diff --git a/src/app/master-data/product-category/add/page.tsx b/src/app/master-data/product-category/add/page.tsx new file mode 100644 index 00000000..0993ba7a --- /dev/null +++ b/src/app/master-data/product-category/add/page.tsx @@ -0,0 +1,11 @@ +import ProductCategoryForm from "@/components/pages/master-data/product-category/form/ProductCategoryForm"; + +const AddProductCategory = () => { + return ( +
+ +
+ ); +}; + +export default AddProductCategory; \ No newline at end of file diff --git a/src/app/master-data/product-category/detail/edit/page.tsx b/src/app/master-data/product-category/detail/edit/page.tsx new file mode 100644 index 00000000..6bc10644 --- /dev/null +++ b/src/app/master-data/product-category/detail/edit/page.tsx @@ -0,0 +1,47 @@ +'use client'; + +import { useRouter, useSearchParams } from 'next/navigation'; +import useSWR from 'swr'; + +import ProductCategoryForm from '@/components/pages/master-data/product-category/form/ProductCategoryForm'; + +import { ProductCategoryApi } from '@/services/api/master-data'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; + +const ProductCategoryEdit = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + + const productCategoryId = searchParams.get('productCategoryId'); + + const { data: productCategory, isLoading: isLoadingProductCategory } = useSWR( + productCategoryId, + (id: number) => ProductCategoryApi.getSingle(id) + ); + + if (!productCategoryId) { + router.back(); + + return ( +
+ +
+ ); + } + + if (!isLoadingProductCategory && (!productCategory || isResponseError(productCategory))) { + router.replace('/404'); + return; + } + + return ( +
+ {isLoadingProductCategory && } + {!isLoadingProductCategory && isResponseSuccess(productCategory) && ( + + )} +
+ ); +} + +export default ProductCategoryEdit; \ No newline at end of file diff --git a/src/app/master-data/product-category/detail/page.tsx b/src/app/master-data/product-category/detail/page.tsx new file mode 100644 index 00000000..cba06fdb --- /dev/null +++ b/src/app/master-data/product-category/detail/page.tsx @@ -0,0 +1,47 @@ +'use client'; + +import { useRouter, useSearchParams } from 'next/navigation'; +import useSWR from 'swr'; + +import ProductCategoryForm from '@/components/pages/master-data/product-category/form/ProductCategoryForm'; + +import { ProductCategoryApi } from '@/services/api/master-data'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; + +const ProductCategoryDetail = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + + const productCategoryId = searchParams.get('productCategoryId'); + + const { data: productCategory, isLoading: isLoadingProductCategory } = useSWR( + productCategoryId, + (id: number) => ProductCategoryApi.getSingle(id) + ); + + if (!productCategoryId) { + router.back(); + + return ( +
+ +
+ ); + } + + if (!isLoadingProductCategory && (!productCategory || isResponseError(productCategory))) { + router.replace('/404'); + return; + } + + return ( +
+ {isLoadingProductCategory && } + {!isLoadingProductCategory && isResponseSuccess(productCategory) && ( + + )} +
+ ); +}; + +export default ProductCategoryDetail; diff --git a/src/app/master-data/product-category/page.tsx b/src/app/master-data/product-category/page.tsx new file mode 100644 index 00000000..5ec6d555 --- /dev/null +++ b/src/app/master-data/product-category/page.tsx @@ -0,0 +1,11 @@ +import ProductCategoryTable from "@/components/pages/master-data/product-category/ProductCategoryTable"; + +const ProductCategory = () => { + return ( +
+ +
+ ); +}; + +export default ProductCategory; \ No newline at end of file diff --git a/src/components/pages/master-data/product-category/form/ProductCategoryForm.tsx b/src/components/pages/master-data/product-category/form/ProductCategoryForm.tsx new file mode 100644 index 00000000..453670f3 --- /dev/null +++ b/src/components/pages/master-data/product-category/form/ProductCategoryForm.tsx @@ -0,0 +1,266 @@ +'use client'; + +import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import { useFormik } from 'formik'; +import { toast } from 'react-hot-toast'; + +import { Icon } from '@iconify/react'; +import Button from '@/components/Button'; +import TextInput from '@/components/input/TextInput'; +import { useModal } from '@/components/Modal'; +import ConfirmationModal from '@/components/modal/ConfirmationModal'; + +import { + ProductCategoryFormSchema, + ProductCategoryFormValues, + UpdateProductCategoryFormSchema, +} from '@/components/pages/master-data/product-category/form/ProductCategoryForm.schema'; +import { isResponseError } from '@/lib/api-helper'; +import { + ProductCategory, + CreateProductCategoryPayload, + UpdateProductCategoryPayload, +} from '@/types/api/master-data/product-category'; +import { ProductCategoryApi } from '@/services/api/master-data'; +import { cn } from '@/lib/helper'; + +interface ProductCategoryFormProps { + type?: 'add' | 'edit' | 'detail'; + initialValues?: ProductCategory; +} + +const ProductCategoryForm = ({ type = 'add', initialValues }: ProductCategoryFormProps) => { + const router = useRouter(); + const deleteModal = useModal(); + + const [formErrorMessage, setFormErrorMessage] = useState(''); + const [isDeleteLoading, setIsDeleteLoading] = useState(false); + + const createProductCategoryHandler = useCallback( + async (payload: CreateProductCategoryPayload) => { + const res = await ProductCategoryApi.create(payload); + + if (isResponseError(res)) { + setFormErrorMessage(res.message); + return; + } + + toast.success(res?.message as string); + router.push('/master-data/product-category'); + }, + [router] + ); + + const updateProductCategoryHandler = useCallback( + async (id: number, payload: UpdateProductCategoryPayload) => { + const res = await ProductCategoryApi.update(id, payload); + + if (res?.status === 'error') { + setFormErrorMessage(res.message); + return; + } + + toast.success(res?.message as string); + router.refresh(); + router.push('/master-data/product-category'); + }, + [router] + ); + + const formikInitialValues = useMemo(() => { + return { + code: initialValues?.code ?? '', + name: initialValues?.name ?? '', + }; + }, [initialValues]); + + const formik = useFormik({ + initialValues: formikInitialValues, + validationSchema: type === 'edit' ? UpdateProductCategoryFormSchema : ProductCategoryFormSchema, + onSubmit: async (values) => { + setFormErrorMessage(''); + + const payload: CreateProductCategoryPayload = { + code: values.code, + name: values.name, + }; + + switch (type) { + case 'add': + await createProductCategoryHandler(payload); + break; + case 'edit': + await updateProductCategoryHandler(initialValues?.id as number, payload); + break; + } + }, + }); + + const { setValues: formikSetValues } = formik; + + const deleteProductCategoryClickHandler = () => { + deleteModal.openModal(); + }; + + const confirmationModalDeleteClickHandler = async () => { + setIsDeleteLoading(true); + + await ProductCategoryApi.delete(initialValues?.id as number); + + deleteModal.closeModal(); + toast.success('Successfully delete Product Category!'); + setIsDeleteLoading(false); + router.push('/master-data/product-category'); + }; + + useEffect(() => { + formikSetValues(formikInitialValues); + }, [formikSetValues, formikInitialValues]); + + return ( + <> +
+
+ + +

+ {type === 'add' && 'Tambah Product Category'} + {type === 'edit' && 'Edit Product Category'} + {type === 'detail' && 'Detail Product Category'} +

+
+ +
+
+ + +
+ +
+ {type !== 'add' && ( +
+ + + {type !== 'edit' && ( + + )} +
+ )} + + {type !== 'detail' && ( +
+ + + +
+ )} +
+ + {formErrorMessage && ( +
+ + {formErrorMessage} +
+ )} +
+
+ + {type !== 'add' && ( + + )} + + ); +}; + +export default ProductCategoryForm; \ No newline at end of file