diff --git a/src/__test__/program/DetailProgram.test.js b/src/__test__/program/DetailProgram.test.js index 8c91a1a82c03aca93e02b08cf0843d893266ec1e..83be0662809ff5a5f2f05b1d7242cde5451730ae 100644 --- a/src/__test__/program/DetailProgram.test.js +++ b/src/__test__/program/DetailProgram.test.js @@ -33,7 +33,7 @@ test("Test detail program renders", async () => { await waitFor(() => getByTestId("program")); const program = getByTestId("program"); expect(program.textContent).toContain("Eddrick"); - expect(fetch.mock.calls.length).toEqual(1); + expect(fetch.mock.calls.length).toEqual(2); }); test("Test mock detail program return error", async () => { @@ -72,7 +72,7 @@ test("Test detail program delete", async () => { await waitFor(() => getByTestId("page")); const produk = getByTestId("page"); expect(produk.textContent).toContain("dummy 2"); - expect(fetch.mock.calls.length).toEqual(1); + expect(fetch.mock.calls.length).toEqual(2); const btnDeleteModal = getByTestId("button-delete-program-modal"); await act(async () => { await fireEvent.click(btnDeleteModal); @@ -81,7 +81,7 @@ test("Test detail program delete", async () => { await act(async () => { await fireEvent.click(btnDelete); }); - expect(fetch.mock.calls.length).toEqual(2); + expect(fetch.mock.calls.length).toEqual(3); }); test("Test detail produk delete error", async () => { @@ -110,7 +110,7 @@ test("Test detail produk delete error", async () => { await waitFor(() => getByTestId("page")); const produk = getByTestId("page"); expect(produk.textContent).toContain("Eddrick"); - expect(fetch.mock.calls.length).toEqual(1); + expect(fetch.mock.calls.length).toEqual(2); const btnDeleteModal = getByTestId("button-delete-program-modal"); await act(async () => { await fireEvent.click(btnDeleteModal); @@ -119,8 +119,68 @@ test("Test detail produk delete error", async () => { await act(async () => { await fireEvent.click(btnDelete); }); - expect(fetch.mock.calls.length).toEqual(2); + expect(fetch.mock.calls.length).toEqual(3); expect(produk.textContent).toContain( "Tidak dapat menghapus program, mohon periksa apakah ada program ini." ); }); +test("Test progress program renders", async () => { + fetch + .once( + JSON.stringify({ + id: "6d7462da-6a85-4e2b-9930-69567090a5d5", + code: "3MXZ9T", + name: "dummy 2", + description: "yeyyy", + start_date_time: null, + end_date_time: null, + location: "Depok", + speaker: "Eddrick", + poster_image: + "https://industripilar-api-staging.s3.amazonaws.com/media/uploads/programs/1_txtcYocQEGtOFN33ZCTDbw.png", + }) + ) + .once( + JSON.stringify([{ + description: "ada progress guys", + date: "2020-04-28", + image: + "https://industripilar-api-staging.s3.amazonaws.com/media/uploads/programs/1_txtcYocQEGtOFN33ZCTDbw.png", + }]) + ) + .once(JSON.stringify({}), { statusCode: 200 }); + ; + + const { getByTestId } = render( + <AuthContext.Provider value={{ profile: { token: "BEBAS" } }}> + <DetailProgram /> + </AuthContext.Provider> + ); + await waitFor(() => getByTestId("program")); + const program = getByTestId("program"); + expect(program.textContent).toContain("Eddrick"); + + await waitFor(() => getByTestId("progress-date")); + const progressDate = getByTestId("progress-date"); + expect(progressDate.textContent).toContain("2020-04-28"); + await act(async () => { + await fireEvent.click(getByTestId("button-see-proof")); + }); + const close = getByTestId("button-close-proof"); + expect(close.textContent).toContain("Close"); + await act(async () => { + await fireEvent.click(close); + }); + expect(fetch.mock.calls.length).toEqual(2); +}); +test("Test mock progress program fail", async () => { + fetch.mockReject(new Error("error message")); + const { getByTestId } = render( + <AuthContext.Provider value={{ profile: { token: "BEBAS" } }}> + <DetailProgram /> + </AuthContext.Provider> + ); + await waitFor(() => getByTestId("progress")); + const progress = getByTestId("progress"); + expect(progress.textContent).toContain("Error, progress not found"); +}); diff --git a/src/__test__/program/EditProgram.test.js b/src/__test__/program/EditProgram.test.js index dbd396b5732d99102c142fc3aef76a47f961168b..a4a68e36eb422cd311a7b1d9fc0274408eaaae1d 100644 --- a/src/__test__/program/EditProgram.test.js +++ b/src/__test__/program/EditProgram.test.js @@ -2,7 +2,8 @@ import { act, cleanup, fireEvent, render } from "@testing-library/react"; import AuthContext from "../../utils/contex"; import { waitFor } from "@testing-library/dom"; import React from "react"; -import EditProduk from "../../page/program/EditProgram"; +import EditProgram from "../../page/program/EditProgram"; +import FormProgress from "../../page/program/FormProgress"; beforeEach(() => { fetch.resetMocks(); @@ -30,7 +31,7 @@ test("Test edit program renders", async () => { const { getByTestId } = render( <AuthContext.Provider value={{ profile: { token: "BEBAS" } }}> - <EditProduk /> + <EditProgram /> </AuthContext.Provider> ); const waitProgram = getByTestId("waiting-edit-program"); @@ -44,8 +45,7 @@ test("Test edit program renders", async () => { await act(async () => { await fireEvent.submit(getByTestId("submit-program")); }); - - expect(fetch.mock.calls.length).toEqual(2); + expect(fetch.mock.calls.length).toEqual(3); }); test("Test edit program renders error", async () => { @@ -72,7 +72,7 @@ test("Test edit program renders error", async () => { const { getByTestId } = render( <AuthContext.Provider value={{ profile: { token: "BEBAS" } }}> - <EditProduk /> + <EditProgram /> </AuthContext.Provider> ); const waitProgram = getByTestId("waiting-edit-program"); @@ -90,8 +90,99 @@ test("Test edit program renders error", async () => { await act(async () => { await fireEvent.submit(getByTestId("submit-program")); }); + expect(fetch.mock.calls.length).toEqual(3); +}); - const produk = getByTestId("edit-program"); - expect(produk.textContent).toContain("Error !, Data tidak dapat disimpan"); +test("Test progress program modal", async () => { + fetch.once( + JSON.stringify({ + id: "6d7462da-6a85-4e2b-9930-69567090a5d5", + code: "3MXZ9T", + name: "dummy 2", + description: "yeyyy", + start_date_time: null, + end_date_time: null, + location: "Depok", + speaker: "Eddrick", + open_donation: true, + program_minutes: null, + poster_image: + "https://industripilar-api-staging.s3.amazonaws.com/media/uploads/programs/1_txtcYocQEGtOFN33ZCTDbw.png", + link: null, + total_donation_amount: "2263691.00", + }) + ); + + const { getByTestId } = render( + <AuthContext.Provider value={{ profile: { token: "BEBAS" } }}> + <EditProgram /> + </AuthContext.Provider> + ); + const waitProgram = getByTestId("waiting-edit-program"); + expect(waitProgram.textContent).toContain("Fetching data.."); + await waitFor(() => getByTestId("edit-program")); + const name_program = getByTestId("name-program-input"); + expect(name_program.value).toEqual("dummy 2"); + + const modalButton = getByTestId("button-progress") + await act(async () => { + await fireEvent.click(modalButton); + }); + const modal = getByTestId("modal-progress"); + expect(modal.textContent).toContain("Tambah Progress"); + expect(modal.textContent).toContain("Tanggal"); + expect(modal.textContent).toContain("Berita"); + expect(modal.textContent).toContain("Gambar"); + + const close = getByTestId("close-button"); + await act(async () => { + await fireEvent.click(close); + }); expect(fetch.mock.calls.length).toEqual(2); }); + +test("Test progress program modal submit", async () => { + fetch.once( + JSON.stringify({ + id: "6d7462da-6a85-4e2b-9930-69567090a5d5", + code: "3MXZ9T", + name: "dummy 2", + description: "yeyyy", + start_date_time: null, + end_date_time: null, + location: "Depok", + speaker: "Eddrick", + open_donation: true, + program_minutes: null, + poster_image: + "https://industripilar-api-staging.s3.amazonaws.com/media/uploads/programs/1_txtcYocQEGtOFN33ZCTDbw.png", + link: null, + total_donation_amount: "2263691.00", + }) + ); + + const { getByTestId } = render( + <AuthContext.Provider value={{ profile: { token: "BEBAS" } }}> + <FormProgress /> + </AuthContext.Provider> + ); + const tanggal_progress = getByTestId("tanggal-progress"); + await act(async () => { + await fireEvent.input(tanggal_progress, { target: { value: "2020-05-12T19:30" } }); + }); + const berita_progress = getByTestId("berita-progress"); + await act(async () => { + await fireEvent.input(berita_progress, { target: { value: "ini berita" } }); + }); + const gambar_progress = getByTestId("gambar-progress"); + await act(async () => { + await fireEvent.input(gambar_progress, { + target: { value: "" }, + }); + }); + await act(async () => { + await fireEvent.submit(getByTestId("save-button")); + }); + expect(fetch.mock.calls.length).toEqual(0); +}); + diff --git a/src/page/donasi-barang/DetailDonasiBarang.jsx b/src/page/donasi-barang/DetailDonasiBarang.jsx index d2c5ed3702a8e1e443252266f749aab7b0231558..bf485aba720e8381239f2c8945c1a32ee6302afb 100644 --- a/src/page/donasi-barang/DetailDonasiBarang.jsx +++ b/src/page/donasi-barang/DetailDonasiBarang.jsx @@ -150,7 +150,7 @@ const DetailDonasiBarang = ({ idDonasi }) => { > <div> {donation.delivery_address === null ? ( - <div>Diantar ke masjid Al-Jabar</div> + <div>Diantar ke Masjid Al-Jabar</div> ) : ( <div>Dijemput di {donation.delivery_address}</div> )} diff --git a/src/page/program/DetailProgram.jsx b/src/page/program/DetailProgram.jsx index 890d0c899f6134beded0b61b73c29e75ec1536a7..b6a291601db22af3facaf4a63b9ba5e155583e14 100644 --- a/src/page/program/DetailProgram.jsx +++ b/src/page/program/DetailProgram.jsx @@ -23,12 +23,27 @@ import { const DetailProgram = ({ idProgram }) => { const url = `${process.env.REACT_APP_BASE_URL}/programs/${idProgram}/`; + const progressUrl = url+"progress"; const [program, error] = useFetchSingleData(url); + const [progress, progressError] = useFetchSingleData(progressUrl); const [deleteProgram, errorDelete] = useDelete(url); const [openModal, setOpenModal] = useState(false); const handleClose = () => setOpenModal(false); + const [dialogOpen, setDialogOpen] = useState(false); + let image; + + const handleClickOpen = (img) => { + image = img; + setDialogOpen(true); + }; + + const handleClickClose = () => { + setDialogOpen(false); + }; const start_date_time = new Date(program.start_date_time).toLocaleString(); const end_date_time = new Date(program.end_date_time).toLocaleString(); + + return ( <div data-testid="page" @@ -352,11 +367,90 @@ const DetailProgram = ({ idProgram }) => { </div> </div> </div> + <div + css={css` + margin-top: 1rem; + margin-bottom: 1rem; + `} + > + <div> + <div + css={css` + margin-top: 1rem; + `} + > + <div + css={css` + margin-top: 2rem; + margin-bottom: 1rem; + font-style: normal; + font-weight: normal; + font-size: 24px; + line-height: 22px; + `} + data-testid="progress" + > + Progress Program + {progressError && <ErrorDiv>Error, progress not found.</ErrorDiv>} + {progress.length > 0 ? + <div> + {progress.map ( p => + <div key={p.id} css={css `margin-top: 1rem; font-size: 18px`}> + <p data-testid="progress-date">{p.date}</p> + <p>{p.description}</p> + {p.image !== null && + <Button + onClick={() => handleClickOpen(p.image)} + variant="contained" + color="primary" + size="medium" + data-testid="button-see-proof" + > + Gambar + </Button> + } + </div> + )} + </div> + :<div css={css `margin-top: 1rem ; font-size: 18px`}>Belum ada progress</div> + } + </div> + </div> </div> </div> </div> </div> </div> + </div> + <Dialog + maxWidth="xl" + open={dialogOpen} + onClose={handleClickClose} + aria-labelledby="max-width-dialog-title" + > + <DialogTitle id="max-width-dialog-title">Bukti Transfer</DialogTitle> + <DialogContent> + <img + css={css` + height: 80vh; + width: 80vw; + object-fit: contain; + `} + src={image} + alt="Foto Progress" + /> + </DialogContent> + <DialogActions> + <Button + data-testid="button-close-proof" + onClick={handleClickClose} + color="primary" + > + Close + </Button> + </DialogActions> + </Dialog> + </div> ); }; diff --git a/src/page/program/EditProgram.jsx b/src/page/program/EditProgram.jsx index 6a36903e524b13243632701cf0924ba32eab10bc..39315dd291510e9da33c6445fe3463c81f47b31e 100644 --- a/src/page/program/EditProgram.jsx +++ b/src/page/program/EditProgram.jsx @@ -1,20 +1,44 @@ -import React from "react"; +import React, {useState} from "react"; import useFetchSingleData from "../../utils/useFetchSingleData"; import { css } from "@emotion/core"; -import { ErrorDiv } from "../../component/html/html"; +import { ErrorDiv, RowInput } from "../../component/html/html"; import FormProgram from "./FormProgram"; import ArrowBackIcon from "@material-ui/icons/ArrowBack"; import ErrorOutlineIcon from "@material-ui/icons/ErrorOutline"; import { navigate } from "@reach/router"; import useSendData from "../../utils/useSendData"; +import Button from "@material-ui/core/Button"; +import Dialog from "@material-ui/core/Dialog"; +import DialogActions from "@material-ui/core/DialogActions"; +import DialogContent from "@material-ui/core/DialogContent"; +import DialogTitle from "@material-ui/core/DialogTitle"; +import FormProgress from "./FormProgress"; const EditProgram = ({ idProgram }) => { const url = `${process.env.REACT_APP_BASE_URL}/programs/${idProgram}/`; const [initialData, errorState] = useFetchSingleData(url); const [send, error] = useSendData({ url, method: "PATCH", redirect: -1 }); + const [dialogOpen, setDialogOpen] = useState(false); const onSubmit = (data) => { send(data); }; + + const urlProgress = `${process.env.REACT_APP_BASE_URL}/programs/${idProgram}/progress`; + const [initialProgressData] = useFetchSingleData(urlProgress); + const [sendProgress] = useSendData({ + url: urlProgress, + method: "POST", + redirect: "/program", + }); + const onSubmitProgress = (data) => { + const formData = new FormData(); + formData.append( "date", data["tanggal_progress"]); + formData.append("description", data["berita_progress"]); + if (data["gambar_progress"].length !== 0) + formData.append("image", data["gambar_progress"][0]); + sendProgress(formData); + }; + if (errorState || Object.keys(initialData).length === 0) return ( <div @@ -29,6 +53,13 @@ const EditProgram = ({ idProgram }) => { Fetching data.. </div> ); + const handleClickOpen = () => { + setDialogOpen(true); + }; + + const handleClose = () => { + setDialogOpen(false); + }; return ( <div data-testid="edit-program" @@ -84,6 +115,51 @@ const EditProgram = ({ idProgram }) => { </div> </div> <FormProgram {...{ onSubmit, initialData }} /> + <RowInput> + <Button + onClick={handleClickOpen} + variant="contained" + size="medium" + data-testid="button-progress" + css={css` + text-transform: none; + width: 100%; + background: #FFFFFF; + border: 1px solid #3c8dbc; + box-sizing: border-box; + border-radius: 50px; + font-size: 14px; + line-height: 17px; + text-align: center; + letter-spacing: 0.2em; + color: #3c8dbc; + height: 2.3rem; + `} + > + Tambah Progress + </Button> + </RowInput> + <Dialog + maxWidth="xl" + open={dialogOpen} + onClose={handleClose} + aria-labelledby="max-width-dialog-title" + data-testid="modal-progress" + > + <DialogTitle id="max-width-dialog-title">Tambah Progress</DialogTitle> + <DialogContent> + <FormProgress {...{ onSubmitProgress, initialProgressData }} /> + </DialogContent> + <DialogActions> + <Button + data-testid="close-button" + onClick={handleClose} + color="primary" + > + Close + </Button> + </DialogActions> + </Dialog> </div> ); }; diff --git a/src/page/program/FormProgram.jsx b/src/page/program/FormProgram.jsx index d37d13af9064f016ebf91dcca99ecf37091a5d45..a36f1cb1f6232af983d862c0eda36fa60eaf5149 100644 --- a/src/page/program/FormProgram.jsx +++ b/src/page/program/FormProgram.jsx @@ -226,4 +226,4 @@ const FormProgram = ({ onSubmit, initialData = null }) => { ); }; -export default FormProgram; +export default FormProgram; \ No newline at end of file diff --git a/src/page/program/FormProgress.jsx b/src/page/program/FormProgress.jsx new file mode 100644 index 0000000000000000000000000000000000000000..75bfc588f7fa2fbbad8f628f63a267d8c1a67f69 --- /dev/null +++ b/src/page/program/FormProgress.jsx @@ -0,0 +1,70 @@ +import React from "react"; +import { + ErrorDiv, + RowInput, + InputForm, + LabelInput, + InputSubmitForm, + } from "../../component/html/html"; +import { useForm } from "react-hook-form"; +import { css } from "@emotion/core"; + +function FormProgress ({ onSubmitProgress, initialProgressData = null }) { + + const {register, handleSubmit, errors} = useForm({ + defaultValues: initialProgressData !== null + ? { + tanggal_progress: initialProgressData["tanggal_progress"], + berita_progress: initialProgressData["berita_progress"], + gambar_progress: initialProgressData["gambar_progress"] + } : {} + }); + + return ( + <form onSubmit={handleSubmit(onSubmitProgress)} css={css` + display: flex; + flex-direction: column; + `}> + <RowInput> + <LabelInput htmlFor="tanggal_progress"> + Tanggal + </LabelInput> + <InputForm + data-testid="tanggal-progress" + type="date" + name="tanggal_progress" + ref={register({ required: true })} + /> + {errors.tanggal_progress && <ErrorDiv>Mohon isi tanggal progress</ErrorDiv>} + </RowInput> + + <RowInput> + <LabelInput htmlFor="berita_progress"> + Berita + </LabelInput> + <InputForm + data-testid="berita-progress" + name="berita_progress" + ref={register({ required: true })} + /> + {errors.berita_progress && <ErrorDiv>Mohon isi berita progress</ErrorDiv>} + </RowInput> + + <RowInput> + <LabelInput htmlFor="gambar_progress"> + Gambar + </LabelInput> + <InputForm + data-testid="gambar-progress" + type="file" + name="gambar_progress" + ref={register({ required: false})} + /> + </RowInput> + <RowInput data-testid="save-button"> + <InputSubmitForm type="submit" value="SIMPAN"/> + </RowInput> + </form> + ) +} +export default FormProgress; \ No newline at end of file