diff --git a/src/app/globals.css b/src/app/globals.css index e50e020d..eee443f7 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -7,26 +7,39 @@ default: false; prefersdark: false; color-scheme: 'light'; - --color-base-100: oklch(98% 0.001 106.423); - --color-base-200: oklch(97% 0.001 106.424); - --color-base-300: oklch(92% 0.003 48.717); - --color-base-content: oklch(22.389% 0.031 278.072); - --color-primary: oklch(60% 0.126 221.723); - --color-primary-content: oklch(100% 0 0); - --color-secondary: oklch(52% 0.105 223.128); - --color-secondary-content: oklch(100% 0 0); - --color-accent: oklch(45% 0.085 224.283); - --color-accent-content: oklch(100% 0 0); - --color-neutral: oklch(39% 0.07 227.392); - --color-neutral-content: oklch(100% 0 0); - --color-info: oklch(58% 0.158 241.966); - --color-info-content: oklch(100% 0 0); - --color-success: oklch(62% 0.194 149.214); - --color-success-content: oklch(100% 0 0); - --color-warning: oklch(85% 0.199 91.936); - --color-warning-content: oklch(0% 0 0); - --color-error: oklch(57% 0.245 27.325); - --color-error-content: oklch(100% 0 0); + + /* Primary Colors */ + --color-primary: oklch(39.4% 0.177 301.9); + --color-primary-content: oklch(87.5% 0.038 274.5); + + /* Secondary Colors */ + --color-secondary: oklch(60.1% 0.258 335.7); + --color-secondary-content: oklch(99.4% 0.007 337.8); + + /* Accent Colors */ + --color-accent: oklch(76.2% 0.155 170.8); + --color-accent-content: oklch(7.2% 0.007 167.6); + + /* Neutral Colors */ + --color-neutral: oklch(22.4% 0.032 258.8); + --color-neutral-content: oklch(87.7% 0.016 257.0); + + /* Base Colors */ + --color-base-100: oklch(100% 0 0); /* #ffffff */ + --color-base-200: oklch(97.2% 0 0); /* #f2f2f2 */ + --color-base-300: oklch(93.1% 0.002 249.7); /* #e5e6e6 */ + --color-base-content: oklch(18.6% 0.024 257.7); /* #1f2937 */ + + /* Status/Utility Colors */ + --color-info: oklch(67.4% 0.176 238.9); + --color-info-content: oklch(0% 0 0); /* #000000 */ + --color-success: oklch(62.3% 0.147 149.0); + --color-success-content: oklch(100% 0 0); /* #ffffff */ + --color-warning: oklch(82.2% 0.165 91.9); + --color-warning-content: oklch(0% 0 0); /* #000000 */ + --color-error: oklch(61.8% 0.203 27.8); + --color-error-content: oklch(100% 0 0); /* #fffffff */ + --radius-selector: 0rem; --radius-field: 0.25rem; --radius-box: 0.25rem; diff --git a/src/app/production/project-flock/add/page.tsx b/src/app/production/project-flock/add/page.tsx index 726c6050..2eb2c090 100644 --- a/src/app/production/project-flock/add/page.tsx +++ b/src/app/production/project-flock/add/page.tsx @@ -12,7 +12,7 @@ const AddProjectFlock = () => { // }, // })); return ( -
+
); diff --git a/src/app/production/project-flock/detail/edit/page.tsx b/src/app/production/project-flock/detail/edit/page.tsx index f55ce601..e5f88f19 100644 --- a/src/app/production/project-flock/detail/edit/page.tsx +++ b/src/app/production/project-flock/detail/edit/page.tsx @@ -37,7 +37,7 @@ const ProjectFlockEdit = () => { } return ( -
+
{isLoadingProjectFlock && ( )} diff --git a/src/components/FloatingActionsButton.tsx b/src/components/FloatingActionsButton.tsx index 8be8669f..1ee5e6c0 100644 --- a/src/components/FloatingActionsButton.tsx +++ b/src/components/FloatingActionsButton.tsx @@ -1,5 +1,6 @@ 'use client'; +import Tooltip from '@/components/Tooltip'; import { cn } from '@/lib/helper'; import { Icon } from '@iconify/react'; @@ -50,7 +51,7 @@ const FloatingActionsButton = ({
@@ -72,14 +73,15 @@ const FloatingActionsButton = ({ key={index} onClick={action.onClick} className='text-white hover:text-gray-400 tooltip tooltip-bottom' - data-tip={action.label} > - + + + ); })} @@ -91,7 +93,9 @@ const FloatingActionsButton = ({ onClick={onClose} className='text-white hover:text-gray-400' > - + + +
diff --git a/src/components/input/CheckboxInput.tsx b/src/components/input/CheckboxInput.tsx index fb0c95c7..f14bc852 100644 --- a/src/components/input/CheckboxInput.tsx +++ b/src/components/input/CheckboxInput.tsx @@ -53,7 +53,7 @@ const CheckboxInput = ({ id={name} name={name} className={cn( - 'checkbox cursor-pointer', + 'checkbox rounded-md cursor-pointer', { 'border-error': isError, 'border-success': isValid, diff --git a/src/components/pages/production/project-flock/ProjectFlockTable.tsx b/src/components/pages/production/project-flock/ProjectFlockTable.tsx index 51ef2ab6..613ea5fc 100644 --- a/src/components/pages/production/project-flock/ProjectFlockTable.tsx +++ b/src/components/pages/production/project-flock/ProjectFlockTable.tsx @@ -1,5 +1,6 @@ 'use client'; +import Badge from '@/components/Badge'; import Button from '@/components/Button'; import FloatingActionsButton from '@/components/FloatingActionsButton'; import CheckboxInput from '@/components/input/CheckboxInput'; @@ -13,7 +14,7 @@ import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowDropdownOptions from '@/components/table/RowDropdownOptions'; import { ROWS_OPTIONS } from '@/config/constant'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; -import { cn } from '@/lib/helper'; +import { cn, formatDate } from '@/lib/helper'; import { AreaApi, KandangApi, LocationApi } from '@/services/api/master-data'; import { ProjectFlockApi } from '@/services/api/production/project-flock'; import { useTableFilter } from '@/services/hooks/useTableFilter'; @@ -270,7 +271,6 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
- + */}
void }) => { id: 'select', header: ({ table }) => { const allRows = table.getRowModel().rows; - const selectableRows = allRows.filter( - (row) => row.original?.approval?.step_number == 1 - ); + const selectableRows = allRows; const allSelected = selectableRows.every((row) => row.getIsSelected()) && @@ -421,12 +419,6 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => { checked={allSelected} indeterminate={someSelected} onChange={toggleSelectableRows} - disabled={ - isResponseSuccess(projectFlocks) && - projectFlocks?.data?.filter( - (flock) => flock.approval.step_number == 1 - ).length == 0 - } />
); @@ -435,14 +427,8 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => { return ( @@ -473,6 +459,40 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => { { accessorKey: 'approval.step_name', header: 'Status', + cell: (props) => { + const approval = props.row.original.approval; + + return ( + + + {approval.step_name} + + ); + }, }, { header: 'Kandang', @@ -500,51 +520,51 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => { accessorKey: 'created_at', header: 'Dibuat pada', cell: (props) => - new Date(props.row.original.created_at).toLocaleDateString(), + formatDate(props.row.original.created_at, 'MMM DD, YYYY'), }, - { - 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; + // { + // 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 isLast2Rows = + // currentRowRelativeIndex > currentPageSize - 2; - const deleteClickHandler = () => { - setSelectedProjectFlock(props.row.original); - deleteModal.openModal(); - }; + // const deleteClickHandler = () => { + // setSelectedProjectFlock(props.row.original); + // deleteModal.openModal(); + // }; - return ( - <> - {currentPageSize > 2 && ( - - - - )} + // return ( + // <> + // {currentPageSize > 2 && ( + // + // + // + // )} - {currentPageSize <= 2 && ( - - - - )} - - ); - }, - }, + // {currentPageSize <= 2 && ( + // + // + // + // )} + // + // ); + // }, + // }, ]} pageSize={tableFilterState.pageSize} page={ @@ -597,7 +617,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => { { action: 'DELETE', icon: 'material-symbols:delete-outline-rounded', - label: 'Hapus Massal', + label: `Hapus ${selectedRowIds.length} data`, onClick: () => { toast.error(`Konfirmasi hapus ${selectedRowIds.length} data.`); }, @@ -611,7 +631,6 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => { onClick: () => { setApprovalAction('APPROVED'); confirmModal.openModal(); - setRowSelection({}); }, }, { @@ -621,7 +640,6 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => { onClick: () => { setApprovalAction('REJECTED'); confirmModal.openModal(); - setRowSelection({}); }, }, ]} diff --git a/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx b/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx index a056ea71..28ab757c 100644 --- a/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx +++ b/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx @@ -1,6 +1,7 @@ import Badge from '@/components/Badge'; import Button from '@/components/Button'; import Card from '@/components/Card'; +import Tooltip from '@/components/Tooltip'; import { formatCurrency, formatDate, @@ -10,6 +11,7 @@ import { import { ProjectFlock } from '@/types/api/production/project-flock'; import { Icon } from '@iconify/react'; import Link from 'next/link'; +import { useRouter } from 'next/navigation'; import { useState } from 'react'; const ProjectFlockDetail = ({ @@ -17,6 +19,7 @@ const ProjectFlockDetail = ({ }: { projectFlock: ProjectFlock; }) => { + const router = useRouter(); const [openBudgets, setOpenBudget] = useState(false); return ( @@ -32,18 +35,37 @@ const ProjectFlockDetail = ({
-
+
Created On {formatDate(projectFlock.created_at, 'MMM DD, YYYY')}
+ {projectFlock?.approval?.step_number == 2 && ( + + + + + + )} - + + +
@@ -58,7 +80,7 @@ const ProjectFlockDetail = ({ variant='soft' color={ projectFlock.approval.step_number == 1 - ? 'secondary' + ? 'neutral' : projectFlock.approval.step_number == 2 ? 'success' : projectFlock.approval.step_number >= 3 @@ -75,7 +97,7 @@ const ProjectFlockDetail = ({ height={12} color={ projectFlock.approval.step_number == 1 - ? 'secondary' + ? 'neutral' : projectFlock.approval.step_number == 2 ? 'success' : projectFlock.approval.step_number >= 3 @@ -87,7 +109,7 @@ const ProjectFlockDetail = ({
@@ -103,7 +125,7 @@ const ProjectFlockDetail = ({
{ diff --git a/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx b/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx index 01157c6f..38a57844 100644 --- a/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx +++ b/src/components/pages/production/project-flock/form/ProjectFlockForm.tsx @@ -17,7 +17,7 @@ import { import { Icon } from '@iconify/react'; import { FormikErrors, useFormik } from 'formik'; import { useRouter } from 'next/navigation'; -import { use, useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import useSWR, { KeyedMutator } from 'swr'; import { ProjectFlockBudgetsSchemaType, @@ -47,6 +47,7 @@ import Card from '@/components/Card'; import ProjectFlockKandangTable from '@/components/pages/production/project-flock/form/ProjectFlockKandangTable'; import { Nonstock } from '@/types/api/master-data/nonstock'; import { useUiStore } from '@/stores/ui/ui.store'; +import Link from 'next/link'; interface ProjectFlockFormProps { formType?: 'add' | 'edit' | 'detail'; @@ -110,19 +111,6 @@ const ProjectFlockForm = ({ ) ); - useEffect(() => { - if (initialValues?.approval?.step_name) { - const pengajuanRejected = - initialValues.approval.step_number == 1 && - initialValues.approval.action == 'REJECTED'; - const approvedDisabled = - initialValues.approval.step_number !== 1 || pengajuanRejected; - setIsApprovedDisabled(approvedDisabled); - setIsRejectedDisabled(!approvedDisabled || pengajuanRejected); - setApprovalAction(!approvedDisabled ? 'APPROVED' : 'REJECTED'); - } - }, [initialValues]); - // Fetch Data const { isLoadingOptions: isLoadingFlocks, options: optionsFlock } = useSelect(FlockApi.basePath, 'id', 'name'); @@ -221,7 +209,12 @@ const ProjectFlockForm = ({ formik.setFieldValue('area_id', (val as OptionType)?.value); formik.setFieldValue('area', val); - formik.setFieldTouched('area_id', true); + if (Boolean(val)) { + formik.setFieldTouched('area_id', false); + formik.setFieldError('area_id', ''); + } else { + formik.setFieldTouched('area_id', true); + } setSelectedArea((val as OptionType)?.value as string); setSelectedLocation(''); @@ -254,7 +247,12 @@ const ProjectFlockForm = ({ val ? (val as OptionType)?.value : 0 ); - formik.setFieldTouched(`${inputName}_id`, true); + if (Boolean(val)) { + formik.setFieldTouched(`${inputName}_id`, false); + formik.setFieldError(`${inputName}_id`, ''); + } else { + formik.setFieldTouched(`${inputName}_id`, true); + } }; const categoryChangeHandler = (val: OptionType | OptionType[] | null) => { @@ -282,7 +280,7 @@ const ProjectFlockForm = ({ const updateProjectFlockHandler = async ( payload: CreateProjectFlockPayload ) => { - const updateProjectFlockRes = await ProjectFlockApi.update( + const updateProjectFlockRes = await ProjectFlockApi.resubmit( initialValues?.id as number, payload ); @@ -314,21 +312,14 @@ const ProjectFlockForm = ({ 0, initialValues?.flock_name?.lastIndexOf(' ') ) ?? ''; + const optionFind = optionsFlock.find((flock) => { + return flock.label == trimFlock; + }) as OptionType; return { - flock: initialValues?.flock_name - ? { - value: - optionsFlock.find((flock) => { - return flock.label == trimFlock; - })?.value ?? 0, - label: - formType != 'detail' - ? (optionsFlock.find((flock) => { - return flock.label == trimFlock; - })?.label ?? '') - : initialValues?.flock_name, - } - : null, + flock: + optionsFlock.find((flock) => { + return flock.label == trimFlock; + }) ?? null, area: initialValues?.area ? { value: initialValues.area?.id, @@ -355,14 +346,8 @@ const ProjectFlockForm = ({ : null, flock_name: optionsFlock.find((flock) => { - return ( - flock.label == - initialValues?.flock_name?.slice( - 0, - initialValues?.flock_name?.lastIndexOf(' ') - ) - ); - })?.label ?? '', + return flock.label == trimFlock; + })?.label ?? trimFlock, area_id: initialValues?.area?.id ?? 0, category: initialValues?.category as NonNullable< 'GROWING' | 'LAYING' | undefined @@ -372,7 +357,18 @@ const ProjectFlockForm = ({ kandang_ids: initialValues?.kandangs?.map( (k: Kandang) => k.id ) as number[], - project_budgets: [ + project_budgets: initialValues?.project_budgets?.map((budget) => { + return { + nonstock: { + value: budget.nonstock?.id ?? '', + label: budget.nonstock?.name ?? '', + }, + nonstock_id: budget.nonstock?.id ?? '', + qty: budget.qty, + price: budget.price, + total_price: budget.qty * budget.price, + }; + }) ?? [ { nonstock: null, nonstock_id: '', @@ -387,94 +383,13 @@ const ProjectFlockForm = ({ // Formik const formik = useFormik({ initialValues: { - flock: initialValues?.flock_name - ? { - value: - optionsFlock.find((flock) => { - return ( - flock.label == - initialValues?.flock_name?.slice( - 0, - initialValues?.flock_name?.lastIndexOf(' ') - ) - ); - })?.value ?? 0, - label: - formType != 'detail' - ? (optionsFlock.find((flock) => { - return ( - flock.label == - initialValues?.flock_name?.slice( - 0, - initialValues?.flock_name?.lastIndexOf(' ') - ) - ); - })?.label ?? '') - : initialValues?.flock_name, - } - : null, - area: initialValues?.area - ? { - value: initialValues.area?.id, - label: initialValues.area.name, - } - : null, - category_option: initialValues?.category - ? { - value: initialValues.category, - label: initialValues.category, - } - : 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_name: - formType != 'detail' - ? optionsFlock.find((flock) => { - return ( - flock.label == - initialValues?.flock_name?.slice( - 0, - initialValues?.flock_name?.lastIndexOf(' ') - ) - ); - })?.label - : (initialValues?.flock_name ?? ''), - area_id: initialValues?.area?.id ?? 0, - category: initialValues?.category as NonNullable< - 'GROWING' | 'LAYING' | undefined - >, - fcr_id: initialValues?.fcr?.id ?? 0, - location_id: initialValues?.location?.id ?? 0, - kandang_ids: initialValues?.kandangs?.map((k: Kandang) => k.id) as ( - | number - | undefined - )[], - project_budgets: [ - { - nonstock: null, - nonstock_id: '', - qty: '', - price: '', - total_price: '', - }, - ], + ...formikInitialValues, } as ProjectFlockFormValues, - enableReinitialize: true, validationSchema: formType == 'add' ? ProjectFlockFormSchema : UpdateProjectFlockFormSchema, validateOnBlur: true, - validateOnChange: true, - validateOnMount: true, + // validateOnChange: true, + // validateOnMount: true, onSubmit: async (values) => { setProjectFlockFormErrorMessage(''); const payload: CreateProjectFlockPayload = { @@ -522,7 +437,18 @@ const ProjectFlockForm = ({ }, [initialValues, setSelectedArea, formType]); useEffect(() => { - formikSetValues(formikInitialValues); + const trimFlock = + initialValues?.flock_name?.slice( + 0, + initialValues?.flock_name?.lastIndexOf(' ') + ) ?? ''; + formikSetValues({ + ...formikInitialValues, + flock: optionsFlock.find((flock) => { + return flock.label == trimFlock; + }) as OptionType, + flock_name: trimFlock ?? '', + }); }, [formikSetValues]); // Aktifkan lokasi jika formType = 'detail' @@ -542,10 +468,6 @@ const ProjectFlockForm = ({ } }, [formType, initialValues]); - useEffect(() => { - formik.validateForm(); - }, [formik.values]); - useEffect(() => { const selectedRowIds = Object.keys(rowSelection) .filter((id) => rowSelection[id]) @@ -583,6 +505,19 @@ const ProjectFlockForm = ({ return unsub; }, []); + useEffect(() => { + if (initialValues?.approval?.step_name) { + const pengajuanRejected = + initialValues.approval.step_number == 1 && + initialValues.approval.action == 'REJECTED'; + const approvedDisabled = + initialValues.approval.step_number !== 1 || pengajuanRejected; + setIsApprovedDisabled(approvedDisabled); + setIsRejectedDisabled(!approvedDisabled || pengajuanRejected); + setApprovalAction(!approvedDisabled ? 'APPROVED' : 'REJECTED'); + } + }, [initialValues]); + // Actions handler const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); @@ -727,31 +662,59 @@ const ProjectFlockForm = ({ : undefined; const inputPeriod = (initialValues?.period ?? selectedPeriod == 0) ? 1 : selectedPeriod; + const filteredNonStockOptions = optionsNonstock.filter((nonstock) => { - return !(formik.values.project_budgets ?? []).some( - (budget) => budget.nonstock_id === nonstock.value - ); + const isNonstockAlreadyInBudgets = ( + formik.values.project_budgets ?? [] + ).some((budget) => budget.nonstock_id === nonstock.value); + + return !isNonstockAlreadyInBudgets; }); return ( <>
-
- - -

- {formType === 'add' && 'Tambah Project Flock'} - {formType === 'edit' && 'Edit Project Flock'} - {formType === 'detail' && 'Detail Project Flock'} -

-
+ {/* Header */} +
+
+ + + +
+
+ {formType == 'add' ? 'Add Flock' : 'Update Flock'} +
+
+
+ +
+
{projectFlockFormErrorMessage && (
@@ -829,15 +792,11 @@ const ProjectFlockForm = ({ onSubmit={formik.handleSubmit} onReset={formik.handleReset} > - {/* Card Informasi Umum */} - -
+ {/* Form Informasi Umum */} +
+
+

Informasi Umum

+
+ -
- +
- {/* Card Pilih Kandang */} - + {/* Form Pilih Kandang */} +
+
+

Pilih Kandang

{isLoadingKandang && ( @@ -964,33 +918,43 @@ const ProjectFlockForm = ({ initialValues={initialValues} />
- +
{/* Card Estimasi Budget */} - - - - - - - - - - - - - {formik.values.project_budgets && - formik.values.project_budgets.length > 0 ? ( - formik.values.project_budgets.map((budget, index) => ( - - - - - - - - )) - ) : ( - - - - )} - -
ProdukKuantitasHarga SatuanHarga TotalAksi
+
+
+

+ Estimasi Aggaran Per Flock +

+
+ {formik.values.project_budgets && + formik.values.project_budgets.length > 0 ? ( + formik.values.project_budgets.map((budget, index) => ( + +
+
+
Anggaran ke-{index + 1}
+ +
+
-
+ +
ns.id === budget.nonstock_id - )?.uom?.name ?? '') - : '' +
+ {isResponseSuccess(nonstocks) + ? (nonstocks.data.find( + (ns) => ns.id === budget.nonstock_id + )?.uom?.name ?? '') + : ''} +
} errorMessage={ ( @@ -1070,8 +1036,8 @@ const ProjectFlockForm = ({ ) } /> -
+ +
+ {`Per ${ + isResponseSuccess(nonstocks) + ? (nonstocks.data.find( + (ns) => ns.id === budget.nonstock_id + )?.uom?.name ?? 'Item') + : 'Item' + }`} +
+ } errorMessage={ ( formik.errors.project_budgets?.[ @@ -1100,8 +1077,8 @@ const ProjectFlockForm = ({ ) } /> -
+ +
Total
+ } errorMessage={ ( formik.errors.project_budgets?.[ @@ -1137,108 +1117,50 @@ const ProjectFlockForm = ({ ) } /> -
- -
- Tidak ada data estimasi anggaran. -
+
+
+ + )) + ) : ( +
+ Tidak ada data estimasi anggaran. +
+ )} + +
+
- - - -
- {formType !== 'detail' && ( -
- - +
+ {/*
+
+ {JSON.stringify(formik.values)}
+
+ {JSON.stringify(formik.errors)} +
+
*/} + {formType !== 'detail' && ( + )}
- {formType != 'add' && ( -
- {formType != 'edit' && ( - - )} - -
- )}
{ - const initialKandangIdSet = useMemo(() => { - return initialValues?.kandangs.map((k) => k.id) ?? []; - }, [initialValues]); - const isRowEnabled = (row: Row) => { - const isDisabled = - !initialKandangIdSet.includes(row.original.id) && - (row.original.status == 'ACTIVE' || - row.original.status == 'PENGAJUAN' || - formType == 'detail'); - return !isDisabled; + // Fungsi untuk menangani perubahan checkbox + const handleCheckboxChange = (kandang: Kandang, isChecked: boolean) => { + // Hanya izinkan perubahan jika tidak dalam mode 'detail' + if (formType === 'detail') return; + + // Pastikan kandang.id ada dan tidak null/undefined + if (kandang.id === undefined) return; + + const kandangIdString = kandang.id.toString(); + + setRowSelection((prev) => { + const newSelection = { ...prev }; + if (isChecked) { + newSelection[kandangIdString] = true; + } else { + delete newSelection[kandangIdString]; + } + return newSelection; + }); }; return ( <> - - data={listKandang} - columns={[ - { - id: 'select', - header: ({ table }) => { - const allRows = table.getRowModel().rows; - // 1. Filter semua baris dengan logika yang sama persis seperti di cell - const selectableRows = allRows.filter(isRowEnabled); + {listKandang.length > 0 ? ( + <> + {/* ... Bagian Badge Status ... */} +
+ + + Tersedia ( + { + listKandang.filter((kandang) => kandang.status == 'NON_ACTIVE') + .length + } + ) + +
+ + + Tidak Tersedia ( + { + listKandang.filter((kandang) => kandang.status != 'NON_ACTIVE') + .length + } + ) + +
+ {/* --- */} + +
+ {listKandang.map((kandang, index) => { + const kandangIdString = + kandang.id?.toString() ?? `temp-${index}`; - // 2. Cek apakah SEMUA baris yang BISA DIPILIH sudah terpilih - const allSelected = - selectableRows.length > 0 && - selectableRows.every((row) => row.getIsSelected()); + const isSelected = + !!rowSelection[kandangIdString] || + (kandang.id !== undefined && + selectedIds.includes(kandang.id)); - // 3. Cek apakah BEBERAPA baris yang BISA DIPILIH sudah terpilih - const someSelected = - selectableRows.some((row) => row.getIsSelected()) && - !allSelected; + const isDisabled = + formType == 'detail' || kandang.status != 'NON_ACTIVE'; - // 4. Fungsi toggle HANYA akan mentoggle baris yang BISA DIPILIH - const toggleSelectableRows = () => { - const shouldSelect = !allSelected; - selectableRows.forEach((row) => - row.toggleSelected(shouldSelect) + return ( +
+ + handleCheckboxChange(kandang, e.currentTarget.checked) + } + /> + + + {kandang.status != 'NON_ACTIVE' && 'Tidak'} Tersedia + +
); - }; - - return ( -
- -
- ); - }, - cell: ({ row }) => { - return ( - - ); - }, - }, - { - accessorFn: (row) => row.name, - header: 'Kandang', - }, - { - accessorFn: (row) => row.status, - header: 'Status', - cell: (props) => { - return ( - { - switch (props.row.original.status) { - case 'ACTIVE': - return 'red'; - case 'PENGAJUAN': - return 'green'; - case 'NON_ACTIVE': - return 'blue'; - default: - return 'gray'; - } - })()} - content={props.row.original.status - .toLowerCase() - .replace(/_/g, ' ') - .replace(/\b\w/g, (char) => char.toUpperCase())} - /> - ); - }, - }, - { - accessorFn: (row) => row.capacity, - header: 'Kapasitas', - }, - { - accessorFn: (row) => row.location?.name, - header: 'Periode', - cell: (props) => { - const period = - listPeriods.length > 0 - ? listPeriods.find((p) => p.id == props.row.original.id) - : undefined; - const calcPeriod = period?.period == 0 ? 1 : period?.period; - const selected = props.row.getIsSelected(); - const initPeriod = initialValues?.period; - return formType == 'detail' - ? selected - ? initPeriod - : '-' - : formType == 'add' - ? (calcPeriod ?? '-') - : selected - ? (initPeriod ?? '-') - : (calcPeriod ?? '-'); - }, - }, - { - accessorFn: (row) => row.pic?.name, - header: 'Penanggung Jawab', - }, - ]} - className={{ - containerClassName: cn({ - 'mb-20': listKandang?.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', - paginationClassName: 'hidden', - }} - rowSelection={rowSelection} - setRowSelection={setRowSelection} - /> + })} +
+
+ + ) : ( +
+ Pilih lokasi terlebih dahulu +
+ )} ); }; diff --git a/src/services/api/production/project-flock.ts b/src/services/api/production/project-flock.ts index ea0ef12e..d92881f6 100644 --- a/src/services/api/production/project-flock.ts +++ b/src/services/api/production/project-flock.ts @@ -141,6 +141,38 @@ export class ProjectFlockService extends BaseApiService< } } + /** + * Resubmit Project Flock + */ + async resubmit( + id: number, + payload: UpdateProjectFlockPayload + ): Promise | undefined> { + try { + const updatePath = `${this.basePath}/${id}/resubmit`; + + const headers = { + 'Content-Type': 'application/json', + ...(this.header ?? {}), + }; + + const updateRes = await httpClient>( + updatePath, + { + method: 'PUT', + body: payload, + headers, + } + ); + return updateRes; + } catch (error: unknown) { + if (axios.isAxiosError>(error)) { + return error.response?.data; + } + return undefined; + } + } + /** * Approve single Project Flock */