refactor(FE): refactor chickin views and adjust approval logic in project flocks

This commit is contained in:
randy-ar
2025-12-06 00:15:30 +07:00
parent 885e4250fd
commit 85fdb4f7dd
8 changed files with 440 additions and 307 deletions
@@ -10,8 +10,6 @@ import { useModal } from '@/components/Modal';
import ConfirmationModal from '@/components/modal/ConfirmationModal';
import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes';
import Table from '@/components/Table';
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, formatDate } from '@/lib/helper';
@@ -23,7 +21,7 @@ import { ProjectFlock } from '@/types/api/production/project-flock';
import { Icon } from '@iconify/react';
import { CellContext, SortingState } from '@tanstack/react-table';
import { useRouter } from 'next/navigation';
import { ChangeEventHandler, useEffect, useState } from 'react';
import { ChangeEventHandler, useEffect, useMemo, useState } from 'react';
import toast from 'react-hot-toast';
import useSWR from 'swr';
@@ -124,7 +122,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
});
const router = useRouter();
// State
// ===== State =====
const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});
const selectedRowIds = Object.keys(rowSelection)
.filter((id) => rowSelection[id])
@@ -151,7 +149,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
const [isApproveLoading, setIsApproveLoading] = useState(false);
// Fetch Data
// ===== Fetch Data =====
const {
data: projectFlocks,
isLoading,
@@ -192,7 +190,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
KandangApi.getAllFetcher
);
// Data to Options Mapping
// ===== Data to Options Mapping ======
const optionsArea = isResponseSuccess(areas)
? areas?.data.map((area) => ({
value: area.id,
@@ -212,7 +210,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
}))
: [];
// Handler
// ====== HANDLER ======
const pageSizeChangeHandler = (val: OptionType | OptionType[] | null) => {
const newVal = val as OptionType;
setPageSize(newVal.value as number);
@@ -220,17 +218,17 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
const confirmationModalDeleteClickHandler = async () => {
setIsDeleteLoading(true);
await ProjectFlockApi.delete(selectedProjectFlock?.id as number);
await ProjectFlockApi.delete(selectedSingleRow?.id as number);
refreshProjectFlocks();
deleteModal.closeModal();
toast.success('Successfully delete Project Flock!');
setIsDeleteLoading(false);
setRowSelection({});
};
const searchChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
updateFilter('search', e.target.value);
};
const confirmApprovalHandler = async (
notes: string,
approvalAction: 'APPROVED' | 'REJECTED'
@@ -260,10 +258,29 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
setIsApproveLoading(false);
};
// ====== EFFECT ======
useEffect(() => {
refreshProjectFlocks();
}, [refresh]);
// ====== MEMO ======
const selectedSingleRow: ProjectFlock | null | undefined = useMemo(() => {
return selectedRowIds.length === 1
? isResponseSuccess(projectFlocks)
? projectFlocks?.data.find((row) => row.id === selectedRowIds[0])
: null
: null;
}, [rowSelection]);
const canApprove = useMemo(() => {
if (!selectedSingleRow || isApproveLoading) return false;
const isPengajuan = selectedSingleRow.approval.step_number == 1;
const isNotRejected = selectedSingleRow.approval.action != 'REJECTED';
return isPengajuan && isNotRejected;
}, [selectedSingleRow, isApproveLoading]);
return (
<>
<div className='min-h-screen w-full p-0 sm:p-4'>
@@ -617,9 +634,10 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
{
action: 'DELETE',
icon: 'material-symbols:delete-outline-rounded',
label: `Hapus ${selectedRowIds.length} data`,
label: `Hapus data`,
hidden: selectedRowIds.length !== 1,
onClick: () => {
toast.error(`Konfirmasi hapus ${selectedRowIds.length} data.`);
deleteModal.openModal();
},
},
]}
@@ -632,6 +650,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => {
setApprovalAction('APPROVED');
confirmModal.openModal();
},
disabled: !canApprove,
},
{
icon: 'mdi:times',
@@ -102,7 +102,7 @@ const ProjectFlockClosingForm = ({
className={{ badge: 'rounded-lg px-2' }}
>
<Icon icon='mdi:home' width={12} height={12} />
{` Kapasitas ${formatNumber(projectFlockKandang.kandang.capacity)} Ekor`}
{` Kapasitas ${formatNumber(projectFlockKandang.kandang?.capacity)} Ekor`}
</Badge>
</div>
@@ -34,6 +34,10 @@ const ProjectFlockDetail = ({
null
);
const selectedKandang = projectFlock.kandangs.find(
(kandang) => kandang.id === Number(selectedKandangId)
);
const confirmationModalDeleteClickHandler = async () => {
setIsDeleteLoading(true);
const deleteProjectFlockRes = await ProjectFlockApi.delete(
@@ -328,16 +332,21 @@ const ProjectFlockDetail = ({
value={selectedKandangId?.toString()}
size='md'
color='neutral'
disabled={projectFlock.approval.step_number == 1}
>
{projectFlock.kandangs.map((kandang) => (
<div
key={kandang.id}
className={`grid grid-cols-2 gap-6 cursor-pointer hover:text-gray-800`}
onClick={() => setSelectedKamdangId(kandang.id.toString())}
onClick={() =>
projectFlock.approval.step_number > 1 &&
setSelectedKamdangId(kandang.id.toString())
}
>
<RadioGroupItem
value={kandang.id.toString()}
label={kandang.name}
disabled={projectFlock.approval.step_number == 1}
/>
<div className='text-end'>
<Badge
@@ -354,14 +363,16 @@ const ProjectFlockDetail = ({
</Card>
<div className='grid grid-cols-4 gap-3'>
<Link
href={`/production/project-flock/chickin/add/kandang?projectFlockKandangId=${selectedKandangId}&projectFlockId=${projectFlock.id}`}
href={`/production/project-flock/chickin/add/kandang?projectFlockKandangId=${selectedKandang?.project_flock_kandang_id}&projectFlockId=${projectFlock.id}`}
className='m-0 p-0'
>
<Button
className='w-full px-2 py-1 text-sm'
variant='outline'
color='success'
disabled={!selectedKandangId}
disabled={
!selectedKandangId || projectFlock.approval.step_number == 1
}
>
Chickin <Icon icon='mdi:checkbox-marked-outline' />
</Button>
@@ -374,7 +385,9 @@ const ProjectFlockDetail = ({
className='w-full px-2 py-1 text-sm'
variant='outline'
color='error'
disabled={!selectedKandangId}
disabled={
!selectedKandangId || projectFlock.approval.step_number == 1
}
>
Close <Icon icon='mdi:checkbox-marked-circle-outline' />
</Button>