diff --git a/src/app/globals.css b/src/app/globals.css index 0fb52327..d2351a24 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -2,7 +2,7 @@ @plugin "daisyui"; @plugin "daisyui/theme" { - name: "corporate"; + name: "lti"; default: false; prefersdark: false; color-scheme: "light"; diff --git a/src/app/master-data/flock/detail/edit/page.tsx b/src/app/master-data/flock/detail/edit/page.tsx index c3903555..c9651727 100644 --- a/src/app/master-data/flock/detail/edit/page.tsx +++ b/src/app/master-data/flock/detail/edit/page.tsx @@ -1,3 +1,5 @@ +'use client' + import FlockForm from "@/components/pages/master-data/flock/form/FlockForm"; import { isResponseError, isResponseSuccess } from "@/lib/api-helper"; import { FlockApi } from "@/services/api/master-data"; diff --git a/src/app/master-data/flock/detail/page.tsx b/src/app/master-data/flock/detail/page.tsx index cedc3243..8a805911 100644 --- a/src/app/master-data/flock/detail/page.tsx +++ b/src/app/master-data/flock/detail/page.tsx @@ -1,3 +1,5 @@ +'use client' + import FlockForm from "@/components/pages/master-data/flock/form/FlockForm"; import { isResponseError, isResponseSuccess } from "@/lib/api-helper"; import { FlockApi } from "@/services/api/master-data"; diff --git a/src/app/production/project-flock/add/page.tsx b/src/app/production/project-flock/add/page.tsx new file mode 100644 index 00000000..60141d80 --- /dev/null +++ b/src/app/production/project-flock/add/page.tsx @@ -0,0 +1,13 @@ +'use client' + +import ProjectFlockForm from "@/components/pages/production/project-flock/form/ProjectFlockForm"; + +const AddProjectFlock = () => { + return ( +
+ +
+ ); +} + +export default AddProjectFlock; \ No newline at end of file diff --git a/src/app/production/project-flock/detail/edit/page.tsx b/src/app/production/project-flock/detail/edit/page.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/app/production/project-flock/detail/page.tsx b/src/app/production/project-flock/detail/page.tsx new file mode 100644 index 00000000..5efe83d8 --- /dev/null +++ b/src/app/production/project-flock/detail/page.tsx @@ -0,0 +1,46 @@ +'use client' + + +import ProjectFlockForm from "@/components/pages/production/project-flock/form/ProjectFlockForm"; +import { isResponseError, isResponseSuccess } from "@/lib/api-helper"; +import { ProjectFlockApi } from "@/services/api/production"; +import { useRouter, useSearchParams } from "next/navigation"; +import useSWR from "swr"; + +const ProjectFlockDetail = () => { + const router = useRouter(); + const searchParams = useSearchParams(); + + const projectFlockId = searchParams.get("projectFlockId"); + + const { data: projectFlock, isLoading: isLoadingCostumer } = useSWR( + projectFlockId, + (id: number) => ProjectFlockApi.getSingle(id) + ); + + if(!projectFlockId){ + router.back(); + + return ( +
+ +
+ ); + } + + if(!isLoadingCostumer && (!projectFlock || isResponseError(projectFlock))){ + router.replace("/404"); + return; + } + + return ( +
+ {isLoadingCostumer && } + {!isLoadingCostumer && isResponseSuccess(projectFlock) && ( + + )} +
+ ) +} + +export default ProjectFlockDetail; \ No newline at end of file diff --git a/src/app/production/project-flock/page.tsx b/src/app/production/project-flock/page.tsx new file mode 100644 index 00000000..fdb8775d --- /dev/null +++ b/src/app/production/project-flock/page.tsx @@ -0,0 +1,12 @@ +import ProjectFlockForm from "@/components/pages/production/project-flock/form/ProjectFlockForm" +import ProjectFlockTable from "@/components/pages/production/project-flock/ProjectFlockTable"; + +const ProjectFlock = () => { + return ( +
+ +
+ ); +} + +export default ProjectFlock; diff --git a/src/components/pages/master-data/flock/FlocksTable.tsx b/src/components/pages/master-data/flock/FlocksTable.tsx index 817eff40..60b392de 100644 --- a/src/components/pages/master-data/flock/FlocksTable.tsx +++ b/src/components/pages/master-data/flock/FlocksTable.tsx @@ -41,7 +41,7 @@ const RowsOptions = ({ )} > + + + + ); +}; + +const ProjectFlockTable = () => { + const { + state: tableFilterState, + updateFilter, + setPage, + setPageSize, + toQueryString: getTableFilterQueryString, + } = useTableFilter({ + initial: { + search: '', + }, + paramMap: { + page: 'page', + pageSize: 'limit', + }, + }); + + // Fetch Data + const { + data: projectFlocks, + isLoading, + mutate: refreshProjectFlocks, + } = useSWR( + `${ProjectFlockApi.basePath}${getTableFilterQueryString()}`, + ProjectFlockApi.getAllFetcher + ); + + // State + const [sorting, setSorting] = useState([]); + const [selectedProjectFlock, setSelectedProjectFlock] = + useState(); + const deleteModal = useModal(); + const [isDeleteLoading, setIsDeleteLoading] = useState(false); + + // Columns + const projectFlocksColumns: ColumnDef[] = [ + { + header: '#', + cell: (props) => + tableFilterState.pageSize * (tableFilterState.page - 1) + + props.row.index + + 1, + }, + { + accessorKey: 'flock.name', + header: 'Flock', + }, + { + accessorKey: 'area.name', + header: 'Area', + }, + { + accessorKey: 'location.name', + header: 'Lokasi', + }, + { + accessorKey: 'fcr.name', + header: 'FCR', + }, + { + accessorKey: 'product_category.name', + header: 'Kategori Produk', + }, + { + header: 'Kandang', + cell: (props) => { + const kandang = props.row.original.kandangs; + const kandangNames = kandang.map((k: Kandang) => k.name); + console.log('kandang'); + console.log(kandang); + return ( +
+ {kandangNames.length > 0 ? kandangNames.join(', ') : 'Tidak ada'} +
+ ); + }, + }, + { + accessorKey: 'period', + header: 'Periode', + }, + { + accessorKey: 'created_at', + header: 'Dibuat pada', + cell: (props) => + new Date(props.row.original.created_at).toLocaleDateString(), + }, + { + header: 'Aksi', + cell: (props) => { + const currentPageSize = props.table.getPaginationRowModel().rows.length; + const currentPageRows = props.table.getPaginationRowModel().flatRows; + const currentRowRelativeIndex = + currentPageRows.findIndex((r) => r.id === props.row.id) + 1; + + const isLast2Rows = currentRowRelativeIndex > currentPageSize - 2; + + const deleteClickHandler = () => { + setSelectedProjectFlock(props.row.original); + deleteModal.openModal(); + }; + + return ( + <> + {currentPageSize > 2 && ( + + + + )} + + {currentPageSize <= 2 && ( + + + + )} + + ); + }, + }, + ]; + + // Handler + const pageSizeChangeHandler = (val: OptionType | OptionType[] | null) => { + const newVal = val as OptionType; + setPageSize(newVal.value as number); + }; + const confirmationModalDeleteClickHandler = async () => { + setIsDeleteLoading(true); + + await ProjectFlockApi.delete(selectedProjectFlock?.id as number); + refreshProjectFlocks(); + + deleteModal.closeModal(); + toast.success('Successfully delete Project Flock!'); + setIsDeleteLoading(false); + }; + + const updateSortingFilter = useCallback( + ( + sortName: Exclude, + sortFilter: ColumnSort | undefined + ) => { + if (!sortFilter) { + updateFilter(sortName, ''); + } else { + updateFilter(sortName, sortFilter.desc ? 'desc' : 'asc'); + } + }, + [updateFilter] + ); + + return ( + <> +
+
+
+
+ +
+
+ +
+
+ + + data={isResponseSuccess(projectFlocks) ? projectFlocks?.data : []} + columns={projectFlocksColumns} + pageSize={tableFilterState.pageSize} + page={ + isResponseSuccess(projectFlocks) ? projectFlocks?.meta?.page : 0 + } + totalItems={ + isResponseSuccess(projectFlocks) + ? projectFlocks?.meta?.total_results + : 0 + } + onPageChange={setPage} + isLoading={isLoading} + sorting={sorting} + setSorting={setSorting} + className={{ + containerClassName: cn({ + 'mb-20': + isResponseSuccess(projectFlocks) && + projectFlocks?.data?.length === 0, + }), + tableWrapperClassName: 'overflow-x-auto min-h-full!', + tableClassName: 'font-inter w-full table-auto min-h-full!', + headerRowClassName: 'border-b border-b-gray-200', + headerColumnClassName: + 'px-6 py-3 text-xs font-semibold text-gray-500 last:flex last:flex-row last:justify-end', + bodyRowClassName: 'border-b border-b-gray-200', + bodyColumnClassName: + 'px-6 py-3 last:flex last:flex-row last:justify-end', + }} + /> +
+
+ + + + ); +}; + +export default ProjectFlockTable; diff --git a/src/components/pages/production/project-flock/form/ProjectFlockForm.schema.ts b/src/components/pages/production/project-flock/form/ProjectFlockForm.schema.ts new file mode 100644 index 00000000..2c00e6ef --- /dev/null +++ b/src/components/pages/production/project-flock/form/ProjectFlockForm.schema.ts @@ -0,0 +1,57 @@ +import * as Yup from 'yup'; + +export const ProjectFlockFormSchema = Yup.object({ + name: Yup.string().required('Nama Proyek wajib diisi!'), + + // Flock + flock: Yup.object({ + value: Yup.number().required('ID Flock wajib diisi!'), + label: Yup.string().required('Nama Flock wajib diisi!'), + }).nullable(), + flock_id: Yup.number().required('Flock wajib diisi!'), + + // Area + area: Yup.object({ + value: Yup.number().required('ID Area wajib diisi!'), + label: Yup.string().required('Nama Area wajib diisi!'), + }).nullable(), + area_id: Yup.number().required('Area wajib diisi!'), + + //Product Category + product_category: Yup.object({ + value: Yup.number().required('ID Kategori Produk wajib diisi!'), + label: Yup.string().required('Nama Kategori Produk wajib diisi!'), + }).nullable(), + product_category_id: Yup.number().required('Kategori Produk wajib diisi!'), + + // FCR + fcr: Yup.object({ + value: Yup.number().required('ID FCR wajib diisi!'), + label: Yup.string().required('Nama FCR wajib diisi!'), + }).nullable(), + fcr_id: Yup.number().required('FCR wajib diisi!'), + + // Location + location: Yup.object({ + value: Yup.number().required('ID Lokasi wajib diisi!'), + label: Yup.string().required('Nama Lokasi wajib diisi!'), + }).nullable(), + location_id: Yup.number().required('Lokasi wajib diisi!'), + + period: Yup.number() + .required('Periode wajib diisi!') + .typeError('Periode harus berupa angka') + .min(1, 'Minimal periode adalah 1'), + + kandang_ids: Yup.array() + .of(Yup.number().typeError('Kandang tidak valid!')) + .min(1, 'Minimal harus ada 1 kandang!') + .required('Kandang wajib diisi!'), +}); + +export type ProjectFlockFormValues = Yup.InferType< + typeof ProjectFlockFormSchema +>; + +export const UpdateProjectFlockFormSchema = ProjectFlockFormSchema; + diff --git a/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx b/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx new file mode 100644 index 00000000..5ca4c9b6 --- /dev/null +++ b/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx @@ -0,0 +1,646 @@ +'use client'; + +import Button from '@/components/Button'; +import SelectInput, { OptionType } from '@/components/input/SelectInput'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; +import { + AreaApi, + FcrApi, + FlockApi, + KandangApi, + LocationApi, + ProductCategoryApi, +} from '@/services/api/master-data'; +import { Icon } from '@iconify/react'; +import { useFormik } from 'formik'; +import { useRouter } from 'next/navigation'; +import { useEffect, useMemo, useRef, useState } from 'react'; +import useSWR from 'swr'; +import { + ProjectFlockFormSchema, + ProjectFlockFormValues, + UpdateProjectFlockFormSchema, +} from './ProjectFlockForm.schema'; +import { + CreateProjectFlockPayload, + ProjectFlock, +} from '@/types/api/production/project-flock'; +import toast from 'react-hot-toast'; +import TextInput from '@/components/input/TextInput'; +import Table from '@/components/Table'; +import { Kandang } from '@/types/api/master-data/kandang'; +import Collapse from '@/components/Collapse'; +import { ProjectFlockApi } from '@/services/api/production'; + +interface ProjectFlockFormProps { + formType?: 'add' | 'edit' | 'detail'; + initialValues?: ProjectFlock; +} + +const ProjectFlockForm = ({ + formType = 'add', + initialValues, +}: ProjectFlockFormProps) => { + // State + const router = useRouter(); + const [projectFlockFormErrorMessage, setProjectFlockFormErrorMessage] = + useState(''); + const [selectedArea, setSelectedArea] = useState(''); + + const [selectedLocation, setSelectedLocation] = useState(''); + const [disabledLocation, setDisabledLocation] = useState(true); + const [optionsLocation, setOptionsLocation] = useState([]); + + const [openSelectKandangs, setOpenSelectKandangs] = useState( + initialValues?.kandangs?.length > 0 + ); + const [optionsKandang, setOptionsKandang] = useState( + initialValues?.kandangs ?? [] + ); + + // Fetch Data + const flockUrl = `${FlockApi.basePath}?${new URLSearchParams({ + search: '', + }).toString()}`; + const { data: flocks, isLoading: isLoadingFlocks } = useSWR( + flockUrl, + FlockApi.getAllFetcher + ); + + const areaUrl = `${AreaApi.basePath}?${new URLSearchParams({ + search: '', + }).toString()}`; + const { data: areas, isLoading: isLoadingAreas } = useSWR( + areaUrl, + AreaApi.getAllFetcher + ); + + const locationUrl = `${LocationApi.basePath}?${new URLSearchParams({ + search: '', + area_id: selectedArea, + }).toString()}`; + const { data: locations, isLoading: isLoadingLocations } = useSWR( + locationUrl, + LocationApi.getAllFetcher + ); + + const fcrUrl = `${FcrApi.basePath}?${new URLSearchParams({ + search: '', + }).toString()}`; + const { data: fcrs, isLoading: isLoadingFcrs } = useSWR( + fcrUrl, + FcrApi.getAllFetcher + ); + + const productCategoryUrl = `${ + ProductCategoryApi.basePath + }?${new URLSearchParams({ + search: '', + }).toString()}`; + const { data: productCategories, isLoading: isLoadingProductCategories } = + useSWR(productCategoryUrl, ProductCategoryApi.getAllFetcher); + + const kandangUrl = `${KandangApi.basePath}?${new URLSearchParams({ + search: '', + location_id: selectedLocation == '' ? '0' : selectedLocation, + }).toString()}`; + const { data: kandang, isLoading: isLoadingKandang } = useSWR( + kandangUrl, + KandangApi.getAllFetcher + ); + + // Map Data to Options + const optionsArea = isResponseSuccess(areas) + ? areas?.data.map((area) => ({ + value: area.id, + label: area.name, + })) + : []; + const optionsFcr = isResponseSuccess(fcrs) + ? fcrs?.data.map((fcr) => ({ + value: fcr.id, + label: fcr.name, + })) + : []; + const optionsFlock = isResponseSuccess(flocks) + ? flocks?.data.map((flock) => ({ + value: flock.id, + label: flock.name, + })) + : []; + const optionsProductCategory = isResponseSuccess(productCategories) + ? productCategories?.data.map((productCategory) => ({ + value: productCategory.id, + label: productCategory.name, + })) + : []; + + useEffect(() => { + if (isResponseSuccess(locations)) { + const options = locations.data.map((location) => ({ + value: location.id, + label: location.name, + })); + setOptionsLocation(options); + } + }, [locations]); + + useEffect(() => { + if (isResponseSuccess(kandang)) { + if (kandang.data.length > 0 && selectedLocation != '') { + setOptionsKandang(kandang.data); + setOpenSelectKandangs(true); + } else { + setOptionsKandang([]); + setOpenSelectKandangs(false); + } + } + }, [kandang]); + + // Options Handler + const areaChangeHandler = (val: OptionType | OptionType[] | null) => { + formik.setFieldTouched('area_id', true); + formik.setFieldValue('area_id', (val as OptionType)?.value); + + formik.setFieldValue('area', val); + + setSelectedArea((val as OptionType)?.value as string); + const disabled = (val as OptionType)?.value == null; + setDisabledLocation(disabled); + + formik.setFieldValue('location', null); + formik.setFieldValue('location_id', 0); + formik.setFieldTouched('location', false); + formik.setFieldTouched('location_id', false); + }; + + const locationChangeHandler = (val: OptionType | OptionType[] | null) => { + setSelectedLocation((val as OptionType)?.value as string); + optionChangeHandler(val, 'location'); + formik.setFieldValue('kandang_ids', []); + }; + + const optionChangeHandler = ( + val: OptionType | OptionType[] | null, + inputName: string + ) => { + formik.setFieldValue(inputName, val); + + formik.setFieldValue( + `${inputName}_id`, + val ? (val as OptionType)?.value : 0 + ); + formik.setFieldTouched(`${inputName}_id`, true); + }; + + const kandangChangeHandler = (event: React.ChangeEvent) => { + const { value, checked } = event.target; + if (checked) { + formik.setFieldValue( + 'kandang_ids', + formik.values.kandang_ids.concat(parseInt(value)) + ); + } else { + formik.setFieldValue( + 'kandang_ids', + formik.values.kandang_ids.filter((id) => id !== parseInt(value)) + ); + } + }; + const kandangCheckAll = (event: React.ChangeEvent) => { + const { checked } = event.target; + if (checked) { + formik.setFieldValue( + 'kandang_ids', + optionsKandang.map((kandang) => kandang.id) + ); + } else { + formik.setFieldValue('kandang_ids', []); + } + }; + + // Submit Handler + const createProjectFlockHandler = async ( + payload: CreateProjectFlockPayload + ) => { + const createProjectFlockRes = await ProjectFlockApi.create(payload); + + if (isResponseSuccess(createProjectFlockRes)) { + toast.success(createProjectFlockRes?.message as string); + router.push('/production/project-flock'); + } + if (isResponseError(createProjectFlockRes)) { + setProjectFlockFormErrorMessage(createProjectFlockRes?.message as string); + // toast.ersror(createProjectFlockRes?.message as string); + } + }; + + // Formik InitialValue + const formikInitialValues = useMemo(() => { + return { + name: initialValues?.name ?? '', + flock: initialValues?.flock + ? { + value: initialValues.flock.id, + label: initialValues.flock.name, + } + : null, + area: initialValues?.area + ? { + value: initialValues.area.id, + label: initialValues.area.name, + } + : null, + product_category: initialValues?.product_category + ? { + value: initialValues.product_category.id, + label: initialValues.product_category.name, + } + : null, + fcr: initialValues?.fcr + ? { + value: initialValues.fcr.id, + label: initialValues.fcr.name, + } + : null, + location: initialValues?.location + ? { + value: initialValues.location.id, + label: initialValues.location.name, + } + : null, + flock_id: initialValues?.flock_id ?? 0, + area_id: 0, + product_category_id: 0, + fcr_id: 0, + location_id: 0, + period: initialValues?.period ?? 0, + kandang_ids: [], + }; + }, [initialValues]); + + // Formik + const formik = useFormik({ + initialValues: formikInitialValues, + validationSchema: + formType == 'add' ? ProjectFlockFormSchema : UpdateProjectFlockFormSchema, + validateOnBlur: true, + validateOnChange: true, + validateOnMount: true, + onSubmit: async (values) => { + setProjectFlockFormErrorMessage(''); + const payload: CreateProjectFlockPayload = { + name: values.name as string, + flock_id: values.flock_id as number, + area_id: values.area_id as number, + product_category_id: values.product_category_id as number, + fcr_id: values.fcr_id as number, + location_id: values.location_id as number, + period: values.period as number, + kandang_ids: values.kandang_ids as number[], + }; + + switch (formType) { + case 'add': + await createProjectFlockHandler(payload); + break; + case 'detail': + break; + default: + break; + } + }, + }); + + const { setValues: formikSetValues } = formik; + // Effect Initial + useEffect(() => { + console.log('Initial Value'); + console.log(initialValues); + if(formType == 'detail'){ + formik.setFieldValue('area', { + value: initialValues.area.id, + label: initialValues.area.name, + }); + formik.setFieldValue('area_id', initialValues.area_id); + setSelectedArea(initialValues.area?.id); + + formik.setFieldValue('period', initialValues.period); + } + }, [initialValues, setSelectedArea, formType]); + useEffect(() => { + formikSetValues(formikInitialValues); + }, [formikSetValues, formikInitialValues]); + // Aktifkan lokasi jika formType = 'detail' + useEffect(() => { + if (formType === 'detail') { + setDisabledLocation(false); + } + }, [formType]); + + // Set lokasi otomatis berdasarkan initialValues saat formType = 'detail' + useEffect(() => { + if (formType === 'detail' && initialValues?.location?.id) { + setSelectedLocation(initialValues.location?.id.toString()); + setDisabledLocation(false); // biar dropdown lokasi aktif juga + } + }, [formType, initialValues]); + + // Setelah data kandang difetch, centang otomatis kandang yang ada di initialValues + useEffect(() => { + if (formType === 'detail' && isResponseSuccess(kandang)) { + setOptionsKandang(kandang.data); + setOpenSelectKandangs(true); + + // Ambil ID dari initialValues.kandangs + const kandangIds = + initialValues?.kandangs?.map((k: Kandang) => k.id) ?? []; + + // Set nilai ke formik + formik.setFieldValue('kandang_ids', kandangIds); + } + }, [formType, kandang, initialValues]); + + return ( + <> +
+
+ + +

+ {formType === 'add' && 'Tambah Project Flock'} + {formType === 'detail' && 'Detail Project Flock'} +

+
+ {projectFlockFormErrorMessage && ( +
+
+ + {projectFlockFormErrorMessage} + +
+
+ )} +
+
+
+
Informasi Umum
+ +
+ {formType != 'detail' && ( +
+ +
+ )} + + { + optionChangeHandler(val, 'flock'); + }} + options={optionsFlock} + isLoading={isLoadingFlocks} + isError={formik.touched.flock && Boolean(formik.errors.flock)} + errorMessage={formik.errors.flock as string} + isClearable + isDisabled={formType === 'detail'} + + /> + + { + optionChangeHandler(val, 'fcr'); + }} + options={optionsFcr} + isLoading={isLoadingFcrs} + isError={formik.touched.fcr && Boolean(formik.errors.fcr)} + errorMessage={formik.errors.fcr as string} + isClearable + isDisabled={formType === 'detail'} + /> + { + optionChangeHandler(val, 'product_category'); + }} + options={optionsProductCategory} + isLoading={isLoadingProductCategories} + isError={ + formik.touched.product_category && + Boolean(formik.errors.product_category) + } + errorMessage={formik.errors.product_category as string} + isClearable + isDisabled={formType === 'detail'} + + /> + +
+
+
+
+
+ +
Pilih Kandang
+ +
+ } + className='w-full size-full' + titleClassName='w-full p-0!' + onOpenChange={setOpenSelectKandangs} + open={openSelectKandangs} + > +
+ + {/* head */} + + + + + + + + + {/* rows */} + {selectedLocation != '' && + optionsKandang.map((kandang) => ( + + + + + + ))} + {selectedLocation == '' && ( + + + + )} + + {/* foot */} + {selectedLocation != '' && ( + + + + + + + + )} +
+ + KandangPenanggung Jawab
+ + {kandang.name}{kandang.pic?.name}
+ Data tidak tersedia +
KandangPenanggung Jawab
+
+ +
+ + +
+ {formType !== 'detail' && ( +
+ + +
+ )} +
+
+
+ + ); +}; + +export default ProjectFlockForm; diff --git a/src/config/constant.ts b/src/config/constant.ts index 97e4c285..2d15c62d 100644 --- a/src/config/constant.ts +++ b/src/config/constant.ts @@ -12,6 +12,52 @@ export const MAIN_DRAWER_LINKS: MAIN_DRAWER_MENU[] = [ icon: 'gg:chart', }, + { + title: 'Flock', + link: '/production', + icon: 'material-symbols:raven-outline-rounded', + submenu: [ + { + title: 'List Flock', + link: '/production/project-flock', + icon: 'material-symbols:list-alt-add-outline-rounded', + }, + { + title: 'Chick In', + link: '/production/chick-in', + icon: 'mdi:home-import-outline', + }, + { + title: 'Recording', + link: '/production/recording', + icon: 'mdi:clipboard-text', + }, + ], + }, + + { + title: 'Persediaan', + link: '/inventory', + icon: 'mdi:warehouse', + submenu: [ + { + title: 'Product', + link: '/inventory/product', + icon: 'mdi:package-variant-closed', + }, + { + title: 'Penyesuaian Stok', + link: '/inventory/adjustment', + icon: 'mdi:database-edit', + }, + { + title: 'Transfer Stok', + link: '/inventory/movement', + icon: 'mdi:swap-horizontal', + }, + ], + }, + { title: 'Master Data', link: '/master-data', @@ -80,24 +126,13 @@ export const MAIN_DRAWER_LINKS: MAIN_DRAWER_MENU[] = [ { title: 'Flock', link: '/master-data/flock', - icon: 'material-symbols:raven-outline-rounded', + icon: 'material-symbols:raven-outline-rounded' }, ], }, - { - title: 'Persediaan', - link: '/inventory', - icon: 'material-symbols:box-outline-rounded', - submenu: [ - { - title: 'Penyesuaian Persediaan', - link: '/inventory/adjustment', - icon: 'material-symbols:box-edit-outline-rounded', - } - ] - }, ] as const; + export const ROWS_OPTIONS = [ { label: '10', diff --git a/src/services/api/production.ts b/src/services/api/production.ts new file mode 100644 index 00000000..16234161 --- /dev/null +++ b/src/services/api/production.ts @@ -0,0 +1,11 @@ +import { + ProjectFlock, + CreateProjectFlockPayload, +} from '@/types/api/production/project-flock'; +import { BaseApiService } from './base'; + +export const ProjectFlockApi = new BaseApiService< + ProjectFlock, + CreateProjectFlockPayload, + unknown +>('/production/project_flocks'); \ No newline at end of file diff --git a/src/types/api/production/project-flock.d.ts b/src/types/api/production/project-flock.d.ts new file mode 100644 index 00000000..fd28ab91 --- /dev/null +++ b/src/types/api/production/project-flock.d.ts @@ -0,0 +1,38 @@ +import { Area } from "../master-data/area"; +import { Fcr } from "../master-data/fcr"; +import { Flock } from "../master-data/flock"; +import { Kandang } from "../master-data/kandang"; +import { Location } from "../master-data/location"; +import { ProductCategory } from "../master-data/product-category"; + +export type BaseProjectFlock = { + name: string; + flock: Flock; + flock_id: number; + area: Area; + area_id: number; + product_category: ProductCategory; + product_category_id: number; + fcr: Fcr; + fcr_id: number; + location: Location; + location_id: number; + period: number; + kandang_ids: number[]; + kandangs: Kandang[]; +} + +export type ProjectFlock = BaseMetadata & BaseProjectFlock + +export type CreateProjectFlockPayload = { + name: string; + flock_id: number; + area_id: number; + product_category_id: number; + fcr_id: number; + location_id: number; + period: number; + kandang_ids: number[]; +} + +export type UpdateProjectFlockPayload = CreateProjectFlockPayload; \ No newline at end of file