diff --git a/src/components/pages/report/expense/tab/ReportDepreciationTab.tsx b/src/components/pages/report/expense/tab/ReportDepreciationTab.tsx new file mode 100644 index 00000000..403bc63b --- /dev/null +++ b/src/components/pages/report/expense/tab/ReportDepreciationTab.tsx @@ -0,0 +1,467 @@ +'use client'; + +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import { Icon } from '@iconify/react'; +import { ColumnDef } from '@tanstack/react-table'; +import Button from '@/components/Button'; +import Dropdown from '@/components/dropdown/Dropdown'; +import Modal, { useModal } from '@/components/Modal'; +import Pagination from '@/components/Pagination'; +import Table from '@/components/Table'; +import ButtonFilter from '@/components/helper/ButtonFilter'; +import SelectInput, { OptionType } from '@/components/input/SelectInput'; +import ReportExpenseSkeleton from '@/components/pages/report/expense/skeleton/ReportExpenseSkeleton'; +import { useTabActionsStore } from '@/stores/tab-actions/tab-actions.store'; +import { formatCurrency } from '@/lib/helper'; +import { + ReportDepreciation, + ReportDepreciationSearchParams, +} from '@/types/api/report/report-expense'; +import toast from 'react-hot-toast'; + +interface ReportDepreciationTabProps { + tabId: string; +} + +const DUMMY_DEPRECIATION_DATA: ReportDepreciation[] = [ + { + id: 'DEP-001', + flock: 'Flock A-01', + totalCostPullet: 185000000, + totalDepresiasi: 38500000, + periode: 'Periode 1', + farm: 'Farm Sukamaju', + jumlahKandang: 4, + }, + { + id: 'DEP-002', + flock: 'Flock A-02', + totalCostPullet: 192500000, + totalDepresiasi: 40125000, + periode: 'Periode 1', + farm: 'Farm Sukamaju', + jumlahKandang: 5, + }, + { + id: 'DEP-003', + flock: 'Flock B-01', + totalCostPullet: 176800000, + totalDepresiasi: 36200000, + periode: 'Periode 2', + farm: 'Farm Cibitung', + jumlahKandang: 3, + }, + { + id: 'DEP-004', + flock: 'Flock B-02', + totalCostPullet: 201400000, + totalDepresiasi: 42250000, + periode: 'Periode 2', + farm: 'Farm Cibitung', + jumlahKandang: 4, + }, + { + id: 'DEP-005', + flock: 'Flock C-01', + totalCostPullet: 210900000, + totalDepresiasi: 43950000, + periode: 'Periode 3', + farm: 'Farm Karawang', + jumlahKandang: 6, + }, + { + id: 'DEP-006', + flock: 'Flock C-02', + totalCostPullet: 205750000, + totalDepresiasi: 43100000, + periode: 'Periode 3', + farm: 'Farm Karawang', + jumlahKandang: 5, + }, + { + id: 'DEP-007', + flock: 'Flock D-01', + totalCostPullet: 188300000, + totalDepresiasi: 39000000, + periode: 'Periode 4', + farm: 'Farm Subang', + jumlahKandang: 4, + }, + { + id: 'DEP-008', + flock: 'Flock D-02', + totalCostPullet: 197600000, + totalDepresiasi: 40875000, + periode: 'Periode 4', + farm: 'Farm Subang', + jumlahKandang: 5, + }, +]; + +const INITIAL_FILTERS: ReportDepreciationSearchParams = { + farm: null, + period: null, +}; + +const ReportDepreciationTab = ({ tabId }: ReportDepreciationTabProps) => { + const [filterParams, setFilterParams] = + useState(INITIAL_FILTERS); + const [draftFilters, setDraftFilters] = + useState(INITIAL_FILTERS); + const [page, setPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + + const handleFilterModalOpenRef = useRef(() => {}); + const filterModal = useModal(); + const setTabActions = useTabActionsStore((state) => state.setTabActions); + const clearTabActions = useTabActionsStore((state) => state.clearTabActions); + + const farmOptions = useMemo( + () => + Array.from(new Set(DUMMY_DEPRECIATION_DATA.map((item) => item.farm))).map( + (farm) => ({ + value: farm, + label: farm, + }) + ), + [] + ); + + const periodOptions = useMemo( + () => + Array.from( + new Set(DUMMY_DEPRECIATION_DATA.map((item) => item.periode)) + ).map((period) => ({ + value: period, + label: period, + })), + [] + ); + + const draftFarmValue = useMemo( + () => filterToOption(farmOptions, draftFilters.farm), + [draftFilters.farm, farmOptions] + ); + + const draftPeriodValue = useMemo( + () => filterToOption(periodOptions, draftFilters.period), + [draftFilters.period, periodOptions] + ); + + const filteredData = useMemo(() => { + return DUMMY_DEPRECIATION_DATA.filter((item) => { + const matchFarm = filterParams.farm + ? item.farm === filterParams.farm + : true; + const matchPeriod = filterParams.period + ? item.periode === filterParams.period + : true; + + return matchFarm && matchPeriod; + }); + }, [filterParams]); + + const totalPages = useMemo( + () => Math.max(1, Math.ceil(filteredData.length / pageSize)), + [filteredData.length, pageSize] + ); + + useEffect(() => { + if (page > totalPages) { + setPage(totalPages); + } + }, [page, totalPages]); + + const paginatedData = useMemo(() => { + const startIndex = (page - 1) * pageSize; + return filteredData.slice(startIndex, startIndex + pageSize); + }, [filteredData, page, pageSize]); + + handleFilterModalOpenRef.current = () => { + setDraftFilters(filterParams); + filterModal.openModal(); + }; + + const handleApplyFilters = (e: React.FormEvent) => { + e.preventDefault(); + setFilterParams(draftFilters); + setPage(1); + filterModal.closeModal(); + }; + + const handleResetFilters = () => { + setDraftFilters(INITIAL_FILTERS); + setFilterParams(INITIAL_FILTERS); + setPage(1); + filterModal.closeModal(); + }; + + const handleExport = useCallback((type: 'excel' | 'pdf') => { + toast.success( + `Export ${type.toUpperCase()} belum terhubung API. Saat ini tabel memakai dummy data.` + ); + }, []); + + const tabActionsElement = useMemo( + () => ( +
+ handleFilterModalOpenRef.current()} + variant='outline' + className='px-3 py-2.5' + /> + + +
+ + Export +
+ +
+ + } + > + + + +
+ ), + [filterParams, handleExport] + ); + + useEffect(() => { + setTabActions(tabId, tabActionsElement); + }, [setTabActions, tabActionsElement, tabId]); + + useEffect(() => { + return () => { + clearTabActions(tabId); + }; + }, [clearTabActions, tabId]); + + const columns = useMemo((): ColumnDef[] => { + return [ + { + header: 'Flock', + accessorKey: 'flock', + }, + { + header: 'Total Cost Pullet', + accessorKey: 'totalCostPullet', + cell: ({ row }) => formatCurrency(row.original.totalCostPullet), + }, + { + header: 'Total Depresiasi', + accessorKey: 'totalDepresiasi', + cell: ({ row }) => formatCurrency(row.original.totalDepresiasi), + }, + { + header: 'Periode', + accessorKey: 'periode', + }, + { + header: 'Farm', + accessorKey: 'farm', + }, + { + header: 'Jumlah Kandang', + accessorKey: 'jumlahKandang', + cell: ({ row }) => row.original.jumlahKandang.toLocaleString('id-ID'), + }, + ]; + }, []); + + return ( + <> +
+ {filteredData.length === 0 && ( + + } + title='Data Not Yet Available' + subtitle='Please change your filters to get the data.' + /> + )} + + {filteredData.length > 0 && ( + <> + + +
+ + setPage((currentPage) => + currentPage > 1 ? currentPage - 1 : currentPage + ) + } + onNextPage={() => + setPage((currentPage) => + currentPage < totalPages ? currentPage + 1 : currentPage + ) + } + onPageChange={setPage} + rowOptions={[10, 20, 50, 100]} + onRowChange={(value) => { + setPageSize(value); + setPage(1); + }} + /> +
+ + )} + + + +
+
+ +

Filter Data

+
+ +
+ +
+
+ + setDraftFilters((current) => ({ + ...current, + farm: (val as OptionType | null)?.value?.toString() || null, + })) + } + isClearable + className={{ wrapper: 'w-full' }} + /> + + + setDraftFilters((current) => ({ + ...current, + period: (val as OptionType | null)?.value?.toString() || null, + })) + } + isClearable + className={{ wrapper: 'w-full' }} + /> +
+ +
+ + +
+ +
+ + ); +}; + +const filterToOption = ( + options: OptionType[], + value: string | null +): OptionType | null => { + if (!value) return null; + return options.find((option) => option.value === value) || null; +}; + +export default ReportDepreciationTab;