'use client'; import Badge from '@/components/Badge'; import Button from '@/components/Button'; import FloatingActionsButton from '@/components/FloatingActionsButton'; import CheckboxInput from '@/components/input/CheckboxInput'; import DebouncedTextInput from '@/components/input/DebouncedTextInput'; import SelectInput, { OptionType } from '@/components/input/SelectInput'; import { useModal } from '@/components/Modal'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import ConfirmationModalWithNotes from '@/components/modal/ConfirmationModalWithNotes'; import Table from '@/components/Table'; import { ROWS_OPTIONS } from '@/config/constant'; import { isResponseError, isResponseSuccess } from '@/lib/api-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'; import { Kandang } from '@/types/api/master-data/kandang'; 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, useMemo, useState } from 'react'; import toast from 'react-hot-toast'; import useSWR from 'swr'; import RequirePermission from '@/components/helper/RequirePermission'; const RowOptionsMenu = ({ type = 'dropdown', props, deleteClickHandler, }: { type: 'dropdown' | 'collapse'; props: CellContext; deleteClickHandler: () => void; }) => { return (
{props.row.original.approval.step_name === 'Aktif' && ( )} {props.row.original.approval.step_name === 'Pengajuan' && ( )}
); }; const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => { const { state: tableFilterState, updateFilter, setPage, setPageSize, toQueryString: getTableFilterQueryString, } = useTableFilter({ initial: { search: '', areaFilter: '', locationFilter: '', kandangFilter: '', periodFilter: '', }, paramMap: { page: 'page', pageSize: 'limit', search: 'search', areaFilter: 'area_id', locationFilter: 'location_id', kandangFilter: 'kandang_id', periodFilter: 'period', }, }); const router = useRouter(); // ===== State ===== const [rowSelection, setRowSelection] = useState>({}); const selectedRowIds = Object.keys(rowSelection) .filter((id) => rowSelection[id]) .map((id) => parseInt(id)); const [locationSelectInputValue, setLocationSelectInputValue] = useState(''); const [areaSelectInputValue, setAreaSelectInputValue] = useState(''); const [kandangSelectInputValue, setKandangSelectInputValue] = useState(''); const [selectedArea, setSelectedArea] = useState(null); const [selectedLocation, setSelectedLocation] = useState( null ); const [selectedKandang, setSelectedKandang] = useState( null ); const [periodInputValue, setPeriodInputValue] = useState(null); const [sorting, setSorting] = useState([]); const [selectedProjectFlock, setSelectedProjectFlock] = useState(); const deleteModal = useModal(); const confirmModal = useModal(); const [approvalAction, setApprovalAction] = useState<'APPROVED' | 'REJECTED'>( 'APPROVED' ); const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [isApproveLoading, setIsApproveLoading] = useState(false); // ===== Fetch Data ===== const { data: projectFlocks, isLoading, mutate: refreshProjectFlocks, } = useSWR( `${ProjectFlockApi.basePath}${getTableFilterQueryString()}`, ProjectFlockApi.getAllFetcher, { revalidateOnMount: true } ); const areaUrl = `${AreaApi.basePath}?${new URLSearchParams({ search: areaSelectInputValue, limit: '100', }).toString()}`; const { data: areas, isLoading: isLoadingAreas } = useSWR( areaUrl, AreaApi.getAllFetcher ); const locationUrl = `${LocationApi.basePath}?${new URLSearchParams({ search: locationSelectInputValue, area_id: selectedArea != null ? selectedArea.value.toString() : '', limit: '100', }).toString()}`; const { data: locations, isLoading: isLoadingLocations } = useSWR( locationUrl, LocationApi.getAllFetcher ); const kandangUrl = `${KandangApi.basePath}?${new URLSearchParams({ search: kandangSelectInputValue, location_id: selectedLocation != null ? selectedLocation.value.toString() : '', limit: '100', }).toString()}`; const { data: kandangs, isLoading: isLoadingKandang } = useSWR( kandangUrl, KandangApi.getAllFetcher ); // ===== Data to Options Mapping ====== const optionsArea = isResponseSuccess(areas) ? areas?.data.map((area) => ({ value: area.id, label: area.name, })) : []; const optionsKandang = isResponseSuccess(kandangs) ? kandangs?.data.map((kandang) => ({ value: kandang.id, label: kandang.name, })) : []; const optionsLocation = isResponseSuccess(locations) ? locations?.data.map((location) => ({ value: location.id, label: location.name, })) : []; // ====== HANDLER ====== const pageSizeChangeHandler = (val: OptionType | OptionType[] | null) => { const newVal = val as OptionType; setPageSize(newVal.value as number); }; const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); const response = await ProjectFlockApi.delete( selectedSingleRow?.id as number ); if (isResponseSuccess(response)) { toast.success(response?.message as string); } if (isResponseError(response)) { toast.error(response?.message as string); } refreshProjectFlocks(); deleteModal.closeModal(); setIsDeleteLoading(false); setRowSelection({}); }; const searchChangeHandler: ChangeEventHandler = (e) => { updateFilter('search', e.target.value); }; const confirmApprovalHandler = async ( notes: string, approvalAction: 'APPROVED' | 'REJECTED' ) => { setIsApproveLoading(true); const approveProjectFlockRes = approvalAction === 'APPROVED' ? await ProjectFlockApi.bulkApprove( selectedRowIds.map((id) => id), notes ) : await ProjectFlockApi.bulkReject( selectedRowIds.map((id) => id), notes ); if (isResponseSuccess(approveProjectFlockRes)) { toast.success('Project Flock berhasil di-approve!'); confirmModal.closeModal(); } if (isResponseError(approveProjectFlockRes)) { toast.error(approveProjectFlockRes?.message as string); confirmModal.closeModal(); } setRowSelection({}); refreshProjectFlocks(); 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 ( <>
{ setSelectedArea(val as OptionType); updateFilter( 'areaFilter', (val as OptionType)?.value.toString() ); }} onInputChange={setAreaSelectInputValue} isClearable /> { setSelectedLocation(val as OptionType); updateFilter( 'locationFilter', (val as OptionType)?.value.toString() ); }} onInputChange={setLocationSelectInputValue} isClearable /> { setSelectedKandang(val as OptionType); updateFilter( 'kandangFilter', (val as OptionType)?.value.toString() ); }} onInputChange={setKandangSelectInputValue} isClearable /> { setPeriodInputValue(parseInt(e.target.value)); updateFilter('periodFilter', e.target.value); }} />
data={isResponseSuccess(projectFlocks) ? projectFlocks?.data : []} columns={[ { id: 'select', header: ({ table }) => { const allRows = table.getRowModel().rows; const selectableRows = allRows; const allSelected = selectableRows.every((row) => row.getIsSelected()) && selectableRows.length != 0; const someSelected = selectableRows.some((row) => row.getIsSelected()) && !allSelected; const toggleSelectableRows = () => { const shouldSelect = !allSelected; selectableRows.forEach((row) => row.toggleSelected(shouldSelect) ); }; return (
); }, cell: ({ row }) => { return ( ); }, }, { accessorKey: 'flock_name', header: 'Flock', }, { accessorKey: 'area.name', header: 'Area', }, { accessorKey: 'location.name', header: 'Lokasi', }, { accessorKey: 'fcr.name', header: 'FCR', }, { accessorKey: 'category', header: 'Kategori', }, { accessorKey: 'approval.step_name', header: 'Status', cell: (props) => { const approval = props.row.original.approval; return ( {approval.step_name} ); }, }, { header: 'Kandang', cell: (props) => { const kandang = props.row.original.kandangs; if (kandang) { const kandangNames = kandang.map((k: Kandang) => k.name); return (
{kandangNames.length > 0 ? kandangNames.join(', ') : 'Tidak ada'}
); } else { return '-'; } }, }, { accessorKey: 'period', header: 'Periode', }, { accessorKey: 'created_at', header: 'Dibuat pada', cell: (props) => formatDate(props.row.original.created_at, 'MMM DD, YYYY'), }, ]} 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} rowSelection={rowSelection} setRowSelection={setRowSelection} 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', }} />
{ deleteModal.openModal(); }, permissions: 'lti.production.project_flocks.delete', }, ]} approvals={[ { icon: 'material-symbols:check', label: 'Approve', action: 'APPROVED', onClick: () => { setApprovalAction('APPROVED'); confirmModal.openModal(); }, disabled: !canApprove, permissions: 'lti.production.project_flocks.approve', }, { icon: 'mdi:times', label: 'Reject', action: 'REJECTED', onClick: () => { setApprovalAction('REJECTED'); confirmModal.openModal(); }, permissions: 'lti.production.project_flocks.approve', }, ]} selectedRowIds={selectedRowIds} onClose={() => { setRowSelection({}); }} /> { confirmApprovalHandler(notes, approvalAction); }, isLoading: isApproveLoading, }} /> ); }; export default ProjectFlockTable;