diff --git a/src/components/pages/closing/ClosingIncomingSapronaksSummaryTable.tsx b/src/components/pages/closing/ClosingIncomingSapronaksSummaryTable.tsx new file mode 100644 index 00000000..49e4f108 --- /dev/null +++ b/src/components/pages/closing/ClosingIncomingSapronaksSummaryTable.tsx @@ -0,0 +1,174 @@ +'use client'; + +import { ChangeEventHandler, useEffect, useState } from 'react'; +import { useSearchParams } from 'next/navigation'; +import useSWR from 'swr'; +import { ColumnDef, SortingState } from '@tanstack/react-table'; + +import { Icon } from '@iconify/react'; +import Table from '@/components/Table'; +import Card from '@/components/Card'; +import Collapse from '@/components/Collapse'; + +import { cn, formatNumber } from '@/lib/helper'; +import { isResponseSuccess } from '@/lib/api-helper'; +import { useTableFilter } from '@/services/hooks/useTableFilter'; +import { ClosingApi } from '@/services/api/closing'; +import { ClosingIncomingSapronakSummary } from '@/types/api/closing'; + +interface ClosingIncomingSapronaksSummaryTableProps { + projectFlockId: number; +} + +const ClosingIncomingSapronaksSummaryTable = ({ + projectFlockId, +}: ClosingIncomingSapronaksSummaryTableProps) => { + const searchParams = useSearchParams(); + const kandangId = searchParams.get('kandangId'); + + const { + state: tableFilterState, + updateFilter, + setPage, + setPageSize, + toQueryString: getTableFilterQueryString, + } = useTableFilter({ + initial: { + search: '', + nameSort: '', + }, + paramMap: { + page: 'page', + pageSize: 'limit', + nameSort: 'sort_name', + }, + }); + + const { + data: incomingSapronakSummaries, + isLoading: isLoadingIncomingSapronakSummaries, + } = useSWR( + `${ClosingApi.basePath}/${projectFlockId}/sapronak/summary${getTableFilterQueryString()}&type=incoming&kandang_id=${kandangId ? `${kandangId}` : ''}`, + ClosingApi.getAllIncomingSapronakSummaryFetcher, + { + keepPreviousData: true, + } + ); + + const [open, setOpen] = useState(true); + + const [sorting, setSorting] = useState([]); + const [rowSelection, setRowSelection] = useState>({}); + + const incomingSapronaksColumns: ColumnDef[] = + [ + { + header: '#', + cell: (props) => props.row.index + 1, + }, + { + accessorKey: 'category', + header: 'Kategori', + }, + { + accessorKey: 'total_qty', + header: 'Total Kuantitas', + cell: (props) => + `${formatNumber(props.row.original.total_qty)} ${props.row.original.uom.name}`, + }, + ]; + + const searchChangeHandler: ChangeEventHandler = (e) => { + updateFilter('search', e.target.value); + }; + + // track sorting + useEffect(() => { + const isNameSorted = sorting.find((sortItem) => sortItem.id === 'name'); + + if (!isNameSorted) { + updateFilter('nameSort', ''); + } else { + updateFilter('nameSort', isNameSorted.desc ? 'desc' : 'asc'); + } + }, [sorting, updateFilter]); + + useEffect(() => { + if (!open) { + setOpen( + isResponseSuccess(incomingSapronakSummaries) + ? incomingSapronakSummaries.data.length > 0 + : false + ); + } + }, [incomingSapronakSummaries, isResponseSuccess]); + + return ( + + +
Ringkasan Sapronak Masuk
+ + + + } + className='w-full!' + titleClassName='w-full p-0!' + > +
+ + data={ + isResponseSuccess(incomingSapronakSummaries) + ? incomingSapronakSummaries?.data + : [] + } + columns={incomingSapronaksColumns} + pageSize={tableFilterState.pageSize} + onPageSizeChange={setPageSize} + rowOptions={[10, 20, 50, 100]} + page={ + isResponseSuccess(incomingSapronakSummaries) + ? incomingSapronakSummaries?.meta?.page + : 0 + } + totalItems={ + isResponseSuccess(incomingSapronakSummaries) + ? incomingSapronakSummaries?.meta?.total_results + : 0 + } + onPageChange={setPage} + isLoading={isLoadingIncomingSapronakSummaries} + sorting={sorting} + setSorting={setSorting} + rowSelection={rowSelection} + setRowSelection={setRowSelection} + className={{ + containerClassName: cn({ + 'w-full mb-20': + isResponseSuccess(incomingSapronakSummaries) && + incomingSapronakSummaries?.data?.length === 0, + }), + }} + /> +
+
+
+ ); +}; + +export default ClosingIncomingSapronaksSummaryTable; diff --git a/src/components/pages/closing/ClosingOutgoingSapronaksSummaryTable.tsx b/src/components/pages/closing/ClosingOutgoingSapronaksSummaryTable.tsx new file mode 100644 index 00000000..42fcb588 --- /dev/null +++ b/src/components/pages/closing/ClosingOutgoingSapronaksSummaryTable.tsx @@ -0,0 +1,174 @@ +'use client'; + +import { ChangeEventHandler, useEffect, useState } from 'react'; +import { useSearchParams } from 'next/navigation'; +import useSWR from 'swr'; +import { ColumnDef, SortingState } from '@tanstack/react-table'; + +import { Icon } from '@iconify/react'; +import Table from '@/components/Table'; +import Card from '@/components/Card'; +import Collapse from '@/components/Collapse'; + +import { cn, formatNumber } from '@/lib/helper'; +import { isResponseSuccess } from '@/lib/api-helper'; +import { useTableFilter } from '@/services/hooks/useTableFilter'; +import { ClosingApi } from '@/services/api/closing'; +import { ClosingOutgoingSapronakSummary } from '@/types/api/closing'; + +interface ClosingOutgoingSapronaksSummaryTableProps { + projectFlockId: number; +} + +const ClosingOutgoingSapronaksSummaryTable = ({ + projectFlockId, +}: ClosingOutgoingSapronaksSummaryTableProps) => { + const searchParams = useSearchParams(); + const kandangId = searchParams.get('kandangId'); + + const { + state: tableFilterState, + updateFilter, + setPage, + setPageSize, + toQueryString: getTableFilterQueryString, + } = useTableFilter({ + initial: { + search: '', + nameSort: '', + }, + paramMap: { + page: 'page', + pageSize: 'limit', + nameSort: 'sort_name', + }, + }); + + const { + data: outgoingSapronakSummaries, + isLoading: isLoadingOutgoingSapronakSummaries, + } = useSWR( + `${ClosingApi.basePath}/${projectFlockId}/sapronak/summary${getTableFilterQueryString()}&type=outgoing&kandang_id=${kandangId ? `${kandangId}` : ''}`, + ClosingApi.getAllIncomingSapronakSummaryFetcher, + { + keepPreviousData: true, + } + ); + + const [open, setOpen] = useState(true); + + const [sorting, setSorting] = useState([]); + const [rowSelection, setRowSelection] = useState>({}); + + const outgoingSapronaksColumns: ColumnDef[] = + [ + { + header: '#', + cell: (props) => props.row.index + 1, + }, + { + accessorKey: 'category', + header: 'Kategori', + }, + { + accessorKey: 'total_qty', + header: 'Total Kuantitas', + cell: (props) => + `${formatNumber(props.row.original.total_qty)} ${props.row.original.uom.name}`, + }, + ]; + + const searchChangeHandler: ChangeEventHandler = (e) => { + updateFilter('search', e.target.value); + }; + + // track sorting + useEffect(() => { + const isNameSorted = sorting.find((sortItem) => sortItem.id === 'name'); + + if (!isNameSorted) { + updateFilter('nameSort', ''); + } else { + updateFilter('nameSort', isNameSorted.desc ? 'desc' : 'asc'); + } + }, [sorting, updateFilter]); + + useEffect(() => { + if (!open) { + setOpen( + isResponseSuccess(outgoingSapronakSummaries) + ? outgoingSapronakSummaries.data.length > 0 + : false + ); + } + }, [outgoingSapronakSummaries, isResponseSuccess]); + + return ( + + +
Ringkasan Sapronak Keluar
+ + + + } + className='w-full!' + titleClassName='w-full p-0!' + > +
+ + data={ + isResponseSuccess(outgoingSapronakSummaries) + ? outgoingSapronakSummaries?.data + : [] + } + columns={outgoingSapronaksColumns} + pageSize={tableFilterState.pageSize} + onPageSizeChange={setPageSize} + rowOptions={[10, 20, 50, 100]} + page={ + isResponseSuccess(outgoingSapronakSummaries) + ? outgoingSapronakSummaries?.meta?.page + : 0 + } + totalItems={ + isResponseSuccess(outgoingSapronakSummaries) + ? outgoingSapronakSummaries?.meta?.total_results + : 0 + } + onPageChange={setPage} + isLoading={isLoadingOutgoingSapronakSummaries} + sorting={sorting} + setSorting={setSorting} + rowSelection={rowSelection} + setRowSelection={setRowSelection} + className={{ + containerClassName: cn({ + 'w-full mb-20': + isResponseSuccess(outgoingSapronakSummaries) && + outgoingSapronakSummaries?.data?.length === 0, + }), + }} + /> +
+
+
+ ); +}; + +export default ClosingOutgoingSapronaksSummaryTable; diff --git a/src/components/pages/closing/ClosingSapronakTabContent.tsx b/src/components/pages/closing/ClosingSapronakTabContent.tsx index 41c7aa05..03c3c984 100644 --- a/src/components/pages/closing/ClosingSapronakTabContent.tsx +++ b/src/components/pages/closing/ClosingSapronakTabContent.tsx @@ -2,6 +2,8 @@ import ClosingIncomingSapronaksTable from '@/components/pages/closing/ClosingIncomingSapronaksTable'; import ClosingOutgoingSapronaksTable from '@/components/pages/closing/ClosingOutgoingSapronaksTable'; +import ClosingIncomingSapronaksSummaryTable from '@/components/pages/closing/ClosingIncomingSapronaksSummaryTable'; +import ClosingOutgoingSapronaksSummaryTable from './ClosingOutgoingSapronaksSummaryTable'; interface ClosingSapronakTableProps { projectFlockId?: number; @@ -16,7 +18,15 @@ const ClosingSapronakTabContent = ({ <> + + + + )} diff --git a/src/services/api/closing.ts b/src/services/api/closing.ts index 323e09e8..7462e41a 100644 --- a/src/services/api/closing.ts +++ b/src/services/api/closing.ts @@ -11,6 +11,8 @@ import { ClosingSapronakCalculation, ClosingProductionData, ClosingHppExpedition, + ClosingIncomingSapronakSummary, + ClosingOutgoingSapronakSummary, } from '@/types/api/closing'; import { BaseApiResponse } from '@/types/api/api-general'; import { httpClient, httpClientFetcher } from '@/services/http/client'; @@ -62,6 +64,14 @@ export class ClosingApiService extends BaseApiService { ); } + async getAllIncomingSapronakSummaryFetcher( + endpoint: string + ): Promise> { + return await httpClientFetcher< + BaseApiResponse + >(endpoint); + } + async getAllOutgoingSapronakFetcher( endpoint: string ): Promise> { @@ -70,6 +80,14 @@ export class ClosingApiService extends BaseApiService { ); } + async getAllOutgoingSapronakSummaryFetcher( + endpoint: string + ): Promise> { + return await httpClientFetcher< + BaseApiResponse + >(endpoint); + } + async getGeneralInfo( id: number ): Promise | undefined> { diff --git a/src/types/api/closing.d.ts b/src/types/api/closing.d.ts index ff35fd28..ec256a45 100644 --- a/src/types/api/closing.d.ts +++ b/src/types/api/closing.d.ts @@ -11,6 +11,7 @@ import { Product } from '@type/api/master-data/product'; import { Customer } from '@type/api/master-data/customer'; import { BaseMetadata } from '@/types/api/api-general'; import { ProjectFlock } from '@/types/api/production/project-flock'; +import { BaseUom } from '@/types/api/master-data/uom'; export type BaseSales = { id: number; @@ -104,8 +105,16 @@ export type ClosingIncomingSapronak = { notes: string; }; +export type ClosingIncomingSapronakSummary = { + category: string; + total_qty: number; + uom: BaseUom; +}; + export type ClosingOutgoingSapronak = ClosingIncomingSapronak; +export type ClosingOutgoingSapronakSummary = ClosingIncomingSapronakSummary; + export type ClosingProductionData = { purchase: { initial_population: number;