diff --git a/src/page/kategori/DetailKategori.jsx b/src/page/kategori/DetailKategori.jsx new file mode 100644 index 0000000000000000000000000000000000000000..cbbabeac2c97fb7f1cdb86e3607a5c9fd3629e4a --- /dev/null +++ b/src/page/kategori/DetailKategori.jsx @@ -0,0 +1,131 @@ +import React, { useCallback, useState } from "react"; +import useFetchSingleData from "../../utils/useFetchSingleData"; +import { css } from "@emotion/core"; +import { ButtonDelete, ErrorDiv } from "../../component/html/html"; +import Table from "../../component/Table"; +import LinkYellow from "../../component/LinkYellow"; +import { navigate } from "@reach/router"; +import { ArrowBack } from "@material-ui/icons"; +import { useAuthContext } from "../../utils/contex"; + +const DetailKategori = ({ idKategori }) => { + const url = `${process.env.REACT_APP_BASE_URL}/categories/${idKategori}/`; + const { profile } = useAuthContext(); + const [errorDelete, setErrorDelete] = useState(false); + const [category, error] = useFetchSingleData(url); + const deleteProduct = useCallback(() => { + fetch(url, { + method: "DELETE", + headers: { + Authorization: `Token ${profile.token}`, + }, + }) + .then((response) => { + if (response.ok) { + setErrorDelete(false); + navigate("./"); + } else { + throw new Error("Error"); + } + }) + .catch(() => setErrorDelete(true)); + }, [url, profile.token, setErrorDelete]); + const data = { + url: `${process.env.REACT_APP_BASE_URL}/products/`, + pageDefault: 1, + pageSize: 5, + searchDefault: "", + pageNeighbours: 1, + title: "", + keyValuePairs: [ + ["id", "id"], + ["name", "Nama"], + ["price", "Harga"], + ["stock", "Stok"], + ["subcategory_name", "Subcategory"], + ], + argument: `&subcategory__category=${idKategori}`, + }; + return ( + <div + data-testid="page-detail-kategori" + css={css` + display: flex; + margin: 2rem 3rem 3rem 3rem; + flex-direction: column; + `} + > + {error && <ErrorDiv>Error !, Please relogin..</ErrorDiv>} + {errorDelete && ( + <ErrorDiv> + Tidak dapat menghapus kategori, mohon periksa apakah ada produk + didalam kategori ini. + </ErrorDiv> + )} + <div + css={css` + display: flex; + flex-direction: column; + `} + > + <button + css={css` + align-self: start; + background-color: Transparent; + background-repeat: no-repeat; + border: none; + cursor: pointer; + overflow: hidden; + outline: none; + `} + onClick={() => navigate(-1)} + > + <ArrowBack fontSize="large" /> + </button> + <div + css={css` + font-size: 2rem; + display: flex; + flex-direction: row; + align-items: baseline; + `} + > + <div + css={css` + flex-grow: 2; + `} + > + Kategori: {category.name} + </div> + <div + css={css` + flex-grow: 1; + `} + > + <LinkYellow to="ubah">EDIT</LinkYellow> + </div> + <div + css={css` + flex-grow: 1; + `} + > + <ButtonDelete + data-testid="button-delete-category" + onClick={deleteProduct} + > + HAPUS + </ButtonDelete> + </div> + </div> + <div + css={css` + font-size: 1.5rem; + `} + ></div> + </div> + <Table {...data} /> + </div> + ); +}; + +export default DetailKategori; diff --git a/src/page/kategori/EditKategori.jsx b/src/page/kategori/EditKategori.jsx new file mode 100644 index 0000000000000000000000000000000000000000..fc9945328a16526d446aa524645e4c3e83e4b3af --- /dev/null +++ b/src/page/kategori/EditKategori.jsx @@ -0,0 +1,109 @@ +import React, { useState } from "react"; +import useFetchSingleData from "../../utils/useFetchSingleData"; +import { css } from "@emotion/core"; +import { ErrorDiv } from "../../component/html/html"; +import FormKategori from "./FormKategori"; +import { useAuthContext } from "../../utils/contex"; +import { ArrowBack, ErrorOutline } from "@material-ui/icons"; +import { navigate } from "@reach/router"; + +const EditKategori = ({ idKategori }) => { + const url = `${process.env.REACT_APP_BASE_URL}/categories/${idKategori}/`; + const { profile } = useAuthContext(); + const [error, setError] = useState(false); + const [initialData, errorState] = useFetchSingleData(url); + const onSubmit = (data) => { + const formData = new FormData(); + formData.append("name", data["name"]); + if (data["image"].length !== 0) formData.append("image", data["image"][0]); + fetch(url, { + method: "PATCH", + headers: { + Authorization: `Token ${profile.token}`, + }, + body: formData, + }) + .then((response) => { + if (response.ok) { + setError(false); + navigate("./"); + } else { + throw new Error("Error"); + } + }) + .catch(() => setError(true)); + }; + if (errorState || Object.keys(initialData).length === 0) + return ( + <div + data-testid="waiting-edit-kategori" + css={css` + display: flex; + margin: 2rem 3rem 3rem 3rem; + flex-direction: column; + font-size: 25px; + `} + > + Fetching data.. + </div> + ); + return ( + <div + data-testid="edit-kategori" + css={css` + display: flex; + margin: 2rem 3rem 3rem 3rem; + flex-direction: column; + `} + > + {error && <ErrorDiv>Error !, Data tidak dapat disimpan</ErrorDiv>} + <div + css={css` + display: flex; + flex-direction: row; + `} + > + <button + css={css` + background-color: Transparent; + background-repeat: no-repeat; + border: none; + cursor: pointer; + overflow: hidden; + outline: none; + `} + onClick={() => navigate(-1)} + > + <ArrowBack fontSize="large" /> + </button> + <div + css={css` + font-size: 36px; + `} + > + Edit {initialData.name} + </div> + </div> + <div + css={css` + margin-top: 2.5rem; + display: flex; + `} + > + <ErrorOutline style={{ fontSize: 28, color: "FFC80A" }} /> + <div + css={css` + font-weight: 600; + font-size: 24px; + line-height: 29px; + `} + > + Informasi Kategori + </div> + </div> + <FormKategori {...{ onSubmit, initialData }} /> + </div> + ); +}; + +export default EditKategori; diff --git a/src/page/kategori/FormKategori.jsx b/src/page/kategori/FormKategori.jsx new file mode 100644 index 0000000000000000000000000000000000000000..fc0eb42f9677a5032ebcf7f6d2880780af8ec7b9 --- /dev/null +++ b/src/page/kategori/FormKategori.jsx @@ -0,0 +1,55 @@ +import React from "react"; +import { useForm } from "react-hook-form"; +import { + ErrorDiv, + RowInput, + InputForm, + LabelInput, + InputSubmitForm, +} from "../../component/html/html"; +import { css } from "@emotion/core"; + +const FormKategori = ({ onSubmit, initialData = null }) => { + const { register, handleSubmit, errors } = useForm({ + defaultValues: initialData !== null ? { name: initialData["name"] } : {}, + }); + return ( + <form + data-testid="form-category" + onSubmit={handleSubmit(onSubmit)} + css={css` + display: flex; + flex-direction: column; + `} + > + <RowInput> + <LabelInput htmlFor="name">Nama kategori: </LabelInput> + <InputForm + data-testid="name-kategori-input" + name="name" + ref={register({ required: true })} + /> + {errors.name && <ErrorDiv>Nama kategori tidak boleh kosong</ErrorDiv>} + </RowInput> + {initialData !== null && initialData["image"] != null ? ( + <img + css={css` + height: 10rem; + object-fit: contain; + `} + alt={initialData["name"]} + src={initialData["image"]} + /> + ) : null} + <RowInput> + <LabelInput htmlFor="gambar">Foto kategori: </LabelInput> + <InputForm type="file" name="image" ref={register} /> + </RowInput> + <RowInput> + <InputSubmitForm type="submit" data-testid="submit-category" /> + </RowInput> + </form> + ); +}; + +export default FormKategori; diff --git a/src/page/kategori/ListKategori.jsx b/src/page/kategori/ListKategori.jsx new file mode 100644 index 0000000000000000000000000000000000000000..43ff5aa33a10f50d1a9a2c1ff8db90d819ad34bd --- /dev/null +++ b/src/page/kategori/ListKategori.jsx @@ -0,0 +1,52 @@ +import React from "react"; +import Table from "../../component/Table"; +import { css } from "@emotion/core"; +import LinkYellow from "../../component/LinkYellow"; + +const ListKategori = () => { + const data = { + url: `${process.env.REACT_APP_BASE_URL}/categories/`, + pageDefault: 1, + pageSize: 7, + searchDefault: "", + pageNeighbours: 1, + title: "", + keyValuePairs: [ + ["id", "id"], + ["name", "Nama"], + ], + link: "", + }; + return ( + <div + css={css` + display: flex; + flex-direction: column; + margin: 2rem 3rem 3rem 3rem; + `} + > + <div + css={css` + font-size: 35px; + `} + > + Kelola Kategori + </div> + <div + css={css` + width: 35%; + display: flex; + flex-direction: row; + margin-bottom: 2rem; + margin-top: 1rem; + `} + > + <LinkYellow to="/kategori/tambah">Tambah</LinkYellow> + <LinkYellow to="/kategori">Lihat</LinkYellow> + </div> + <Table {...data} /> + </div> + ); +}; + +export default ListKategori; diff --git a/src/page/kategori/TambahKategori.jsx b/src/page/kategori/TambahKategori.jsx new file mode 100644 index 0000000000000000000000000000000000000000..c5db9033d74103fa9207b37be0172aa7cb669f4b --- /dev/null +++ b/src/page/kategori/TambahKategori.jsx @@ -0,0 +1,72 @@ +import React from "react"; +import { useAuthContext } from "../../utils/contex"; +import { useState } from "react"; +import { css } from "@emotion/core"; +import { ErrorDiv } from "../../component/html/html"; +import FormKategori from "./FormKategori"; +import LinkYellow from "../../component/LinkYellow"; +import { navigate } from "@reach/router"; + +const TambahKategori = () => { + const url = `${process.env.REACT_APP_BASE_URL}/categories/`; + const [error, setError] = useState(false); + const { profile } = useAuthContext(); + const onSubmit = (data) => { + const formData = new FormData(); + formData.append("name", data["name"]); + if (data["image"].length !== 0) formData.append("image", data["image"][0]); + fetch(url, { + method: "POST", + headers: { + Authorization: `Token ${profile.token}`, + }, + body: formData, + }) + .then((response) => { + if (response.ok) { + setError(false); + navigate("/kategori"); + } else { + throw new Error("Error"); + } + }) + .catch(() => setError(true)); + }; + return ( + <div + data-testid="tambah-kategori" + css={css` + display: flex; + margin: 2rem 3rem 3rem 3rem; + flex-direction: column; + `} + > + <div> + {error && <ErrorDiv>Error !, Data tidak dapat disimpan</ErrorDiv>} + </div> + + <div + css={css` + font-size: 35px; + `} + > + Tambah Kategori + </div> + <div + css={css` + width: 35%; + display: flex; + flex-direction: row; + margin-bottom: 2rem; + margin-top: 1rem; + `} + > + <LinkYellow to="/kategori/tambah">Tambah</LinkYellow> + <LinkYellow to="/kategori">Lihat</LinkYellow> + </div> + <FormKategori {...{ onSubmit }} /> + </div> + ); +}; + +export default TambahKategori; diff --git a/src/routes.jsx b/src/routes.jsx index 1fe56810fccc1c4373379c0078d8f4abdc0107d6..814aa365ad0b04f75d71750cbf8420b2a7e58c7e 100644 --- a/src/routes.jsx +++ b/src/routes.jsx @@ -10,6 +10,10 @@ import ListSubkategori from "./page/subkategori/ListSubkategori"; import DetailSubkategori from "./page/subkategori/DetailSubkategori"; import TambahSubkategori from "./page/subkategori/TambahSubkategori"; import EditSubkategori from "./page/subkategori/EditSubkategori"; +import ListKategori from "./page/kategori/ListKategori"; +import DetailKategori from "./page/kategori/DetailKategori"; +import TambahKategori from "./page/kategori/TambahKategori"; +import EditKategori from "./page/kategori/EditKategori"; const Placeholder = ({ children }) => children; @@ -34,6 +38,13 @@ const Routes = () => { /> </Placeholder> + <Placeholder path="kategori"> + <ProtectedRoute path="/" component={ListKategori} /> + <ProtectedRoute path="tambah" component={TambahKategori} /> + <ProtectedRoute path=":idKategori" component={DetailKategori} /> + <ProtectedRoute path=":idKategori/ubah" component={EditKategori} /> + </Placeholder> + <UnauthenticatedRoute path="/" component={Login} /> </Router> );