diff --git a/src/components/Table.tsx b/src/components/Table.tsx index f1466744..9feb33e2 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -14,6 +14,7 @@ import { SortingState, OnChangeFn, Row, + HeaderContext, } from '@tanstack/react-table'; import { rankItem } from '@tanstack/match-sorter-utils'; import { Icon } from '@iconify/react'; @@ -57,8 +58,6 @@ export interface TableProps { setRowSelection?: OnChangeFn>; enableRowSelection?: boolean | ((row: Row) => boolean); renderFooter?: boolean; - footerContent?: ReactNode; - footerData?: TData[]; withCheckbox?: boolean; rowOptions?: number[]; } @@ -73,22 +72,22 @@ const emptyContentDefaultValue = ( ); -const TABLE_DEFAULT_STYLING = { +export const TABLE_DEFAULT_STYLING = { containerClassName: 'w-full mb-20', tableWrapperClassName: 'overflow-x-auto border border-solid border-base-content/10 rounded-lg', tableClassName: 'font-inter w-full table-auto text-sm font-medium', tableHeaderClassName: '', headerRowClassName: '', - headerColumnClassName: 'px-4 py-3 text-base-content/50', + headerColumnClassName: + 'px-4 py-3 border-base-content/10 text-base-content/50', tableBodyClassName: '', - bodyRowClassName: 'border-t border-t-base-content/10', + bodyRowClassName: 'border-t border-base-content/10', bodyColumnClassName: 'px-4 py-3 text-base-content', paginationClassName: '', - - tableFooterClassName: '', - footerRowClassName: '', - footerColumnClassName: '', + tableFooterClassName: 'font-semibold border-base-content/10', + footerRowClassName: 'bg-base-200 border-t-2 border-base-content/10', + footerColumnClassName: 'p-4 text-base-content whitespace-nowrap', }; const Table = ({ @@ -111,8 +110,6 @@ const Table = ({ setRowSelection, enableRowSelection, renderFooter = false, - footerContent, - footerData = [], withCheckbox = false, rowOptions = [10, 20, 50, 100], }: TableProps) => { @@ -187,14 +184,6 @@ const Table = ({ const table = useReactTable(tableOptions); const { setPageSize } = table; - const footerTableOptions: TableOptions = { - columns, - data: footerData, - getCoreRowModel: getCoreRowModel(), - }; - - const footerTable = useReactTable(footerTableOptions); - const prevPageClickHandler = () => { table.previousPage(); @@ -235,58 +224,82 @@ const Table = ({ key={headerGroup.id} className={tableClassNames.headerRowClassName} > - {headerGroup.headers.map((header) => ( - -
- {flexRender( - header.column.columnDef.header, - header.getContext() + {headerGroup.headers.map((header) => { + const columnRelativeDepth = + header.depth - header.column.depth; + if ( + !header.isPlaceholder && + columnRelativeDepth > 1 && + header.id === header.column.id + ) { + return null; + } + let rowSpan = 1; + if (header.isPlaceholder) { + const leafs = header.getLeafHeaders(); + rowSpan = leafs[leafs.length - 1].depth - header.depth; + } + return ( + 1, + }, + tableClassNames.headerColumnClassName )} + > +
1, + })} + > + {flexRender( + header.column.columnDef.header, + header.getContext() + )} - {header.column.getCanSort() && ( -
- - -
- )} -
- - ))} + {header.column.getCanSort() && ( +
+ + +
+ )} +
+ + ); + })} ))} @@ -311,25 +324,27 @@ const Table = ({ ))} - - {renderFooter && - (footerData && footerData.length > 0 - ? footerTable.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - : footerContent)} + + {renderFooter && ( + + {table.getAllLeafColumns().map((column) => ( + + {column.columnDef.footer && + flexRender(column.columnDef.footer, { + column, + header: column.columnDef, + table, + } as HeaderContext)} + + ))} + + )} diff --git a/src/components/helper/RequireAuth.tsx b/src/components/helper/RequireAuth.tsx index 119d74cb..dbd4b6bc 100644 --- a/src/components/helper/RequireAuth.tsx +++ b/src/components/helper/RequireAuth.tsx @@ -6,9 +6,147 @@ import useSWRImmutable from 'swr/immutable'; import { useAuth } from '@/services/hooks/useAuth'; import { httpClientFetcher, SWRHttpKey } from '@/services/http/client'; -import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; -import { BaseApiResponse, GetMeResponse } from '@/types/api/api-general'; -import { AxiosError } from 'axios'; +import { isResponseSuccess } from '@/lib/api-helper'; +import { GetMeResponse } from '@/types/api/api-general'; + +// TODO: delete this later, DONT HARDCODE USER DATA +const DUMMY_USER = { + id: 1, + email: 'admin@mbugroup.id', + npk: '0001', + name: 'Super Admin', + image: null, + created_at: '2025-09-30T03:24:20.899229Z', + updated_at: '2025-09-30T03:24:20.899229Z', + roles: [ + { + id: 1, + key: 'mbu.super_admin', + name: 'MBU Administrator', + client: { + id: 1, + name: 'PT Mitra Berlian Unggas', + alias: 'MBU', + }, + permissions: [ + { + id: 1, + name: 'mbu:purchase:read', + action: 'read', + client: { + id: 1, + name: 'PT Mitra Berlian Unggas', + alias: 'MBU', + }, + }, + { + id: 2, + name: 'mbu:purchase:create', + action: 'create', + client: { + id: 1, + name: 'PT Mitra Berlian Unggas', + alias: 'MBU', + }, + }, + { + id: 3, + name: 'mbu:purchase:approve', + action: 'approve', + client: { + id: 1, + name: 'PT Mitra Berlian Unggas', + alias: 'MBU', + }, + }, + ], + }, + { + id: 2, + key: 'lti.super_admin', + name: 'LTI Administrator', + client: { + id: 2, + name: 'PT Lumbung Telur Indonesia', + alias: 'LTI', + }, + permissions: [ + { + id: 4, + name: 'lti:purchase:read', + action: 'read', + client: { + id: 2, + name: 'PT Lumbung Telur Indonesia', + alias: 'LTI', + }, + }, + { + id: 5, + name: 'lti:purchase:create', + action: 'create', + client: { + id: 2, + name: 'PT Lumbung Telur Indonesia', + alias: 'LTI', + }, + }, + { + id: 6, + name: 'lti:purchase:approve', + action: 'approve', + client: { + id: 2, + name: 'PT Lumbung Telur Indonesia', + alias: 'LTI', + }, + }, + ], + }, + { + id: 3, + key: 'manbu.super_admin', + name: 'MANBU Administrator', + client: { + id: 3, + name: 'PT Mandiri Berlian Unggas', + alias: 'MANBU', + }, + permissions: [ + { + id: 7, + name: 'manbu:purchase:read', + action: 'read', + client: { + id: 3, + name: 'PT Mandiri Berlian Unggas', + alias: 'MANBU', + }, + }, + { + id: 8, + name: 'manbu:purchase:create', + action: 'create', + client: { + id: 3, + name: 'PT Mandiri Berlian Unggas', + alias: 'MANBU', + }, + }, + { + id: 9, + name: 'manbu:purchase:approve', + action: 'approve', + client: { + id: 3, + name: 'PT Mandiri Berlian Unggas', + alias: 'MANBU', + }, + }, + ], + }, + ], +}; interface RequireAuthProps { children?: ReactNode; @@ -18,20 +156,17 @@ const RequireAuth = ({ children }: RequireAuthProps) => { const router = useRouter(); const { setUser, setIsLoadingUser } = useAuth(); - const { - data: userResponse, - isLoading: isLoadingUserResponse, - error: userErrorResponse, - } = useSWRImmutable< - GetMeResponse & { ok?: boolean }, - AxiosError, - SWRHttpKey - >('/sso/userinfo', httpClientFetcher, { - shouldRetryOnError: false, - revalidateOnFocus: false, - revalidateOnReconnect: false, - refreshInterval: 0, - }); + const { data: userResponse, isLoading: isLoadingUserResponse } = + useSWRImmutable( + '/auth/sso/userinfo', + httpClientFetcher, + { + shouldRetryOnError: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshInterval: 0, + } + ); useEffect(() => { setIsLoadingUser(isLoadingUserResponse); @@ -40,25 +175,23 @@ const RequireAuth = ({ children }: RequireAuthProps) => { useEffect(() => { if (isResponseSuccess(userResponse)) { setUser(userResponse.data); - } else if ( - isResponseError(userErrorResponse?.response?.data) && - typeof window !== 'undefined' - ) { - router.replace( - `${process.env.NEXT_PUBLIC_SSO_LOGIN_URL as string}?redirect_url=${window.location.href}` - ); + } else { + // router.replace(process.env.NEXT_PUBLIC_SSO_LOGIN_URL as string); + // TODO: remove this later, DONT HARDCODE USER DATA + setUser(DUMMY_USER); } - }, [userResponse, userErrorResponse, setIsLoadingUser, setUser]); + }, [userResponse, setIsLoadingUser, setUser]); - if (isLoadingUserResponse && !userResponse && !userErrorResponse) { - return ( -
- -
- ); - } + // TODO: uncomment this later + // if (isLoadingUserResponse && !userResponse) { + // return ( + //
+ // + //
+ // ); + // } - return <>{isResponseSuccess(userResponse) && children}; + return <>{children}; }; export default RequireAuth; diff --git a/src/components/pages/closing/ClosingSapronakCalculationTable.tsx b/src/components/pages/closing/ClosingSapronakCalculationTable.tsx index cd2b8c68..73c10331 100644 --- a/src/components/pages/closing/ClosingSapronakCalculationTable.tsx +++ b/src/components/pages/closing/ClosingSapronakCalculationTable.tsx @@ -5,7 +5,6 @@ import Card from '@/components/Card'; import Table from '@/components/Table'; import { cn, formatCurrency, formatNumber } from '@/lib/helper'; import { - ClosingSapronakCalculation, RowSapronakCalculation, TotalSapronakCalculation, } from '@/types/api/closing'; @@ -20,10 +19,6 @@ interface ClosingSapronakCalculationTableProps { projectFlockId: number; } -interface FooterSapronakCalculationRow extends RowSapronakCalculation { - _isFooter: true; -} - const ClosingSapronakCalculationTable = ({ type, projectFlockId, @@ -33,176 +28,124 @@ const ClosingSapronakCalculationTable = ({ () => ClosingApi.getPerhitunganSapronak(projectFlockId) ); - const columns: ColumnDef[] = useMemo( - () => [ - { - header: 'Tanggal', - accessorKey: 'tanggal', - cell: (props) => { - const isFooter = '_isFooter' in props.row.original; - if (isFooter) return null; - const value = props.getValue() as string; - return value || '-'; - }, - }, - { - header: 'No. Referensi', - accessorKey: 'no_referensi', - cell: (props) => { - const isFooter = '_isFooter' in props.row.original; - const value = props.getValue() as string; - if (isFooter) { - return ( -
- {value} -
- ); - } - return value || '-'; - }, - }, - { - header: 'QTY Masuk', - accessorKey: 'qty_masuk', - cell: (props) => { - const value = props.getValue() as number; - const isFooter = '_isFooter' in props.row.original; - return ( -
- {formatNumber(value)} -
- ); - }, - }, - { - header: 'QTY Keluar', - accessorKey: 'qty_keluar', - cell: (props) => { - const value = props.getValue() as number; - const isFooter = '_isFooter' in props.row.original; - return ( -
- {formatNumber(value)} -
- ); - }, - }, - { - header: 'QTY Pakai', - accessorKey: 'qty_pakai', - cell: (props) => { - const value = props.getValue() as number; - const isFooter = '_isFooter' in props.row.original; - return ( -
- {formatNumber(value)} -
- ); - }, - }, - { - header: 'Uraian', - accessorKey: 'uraian', - cell: (props) => { - const isFooter = '_isFooter' in props.row.original; - if (isFooter) return null; - const value = props.getValue() as string; - return value || '-'; - }, - }, - { - header: 'Kategori Produk', - accessorKey: 'kategori_produk', - cell: (props) => { - const isFooter = '_isFooter' in props.row.original; - if (isFooter) return null; - const value = props.getValue() as string; - return value || '-'; - }, - }, - { - header: 'Harga Beli/Qty (Rp)', - accessorKey: 'harga_beli_per_qty', - cell: (props) => { - const value = props.getValue() as number; - const isFooter = '_isFooter' in props.row.original; - return ( -
- {formatCurrency(value)} -
- ); - }, - }, - { - header: 'Total Harga (Rp)', - accessorKey: 'total_harga', - cell: (props) => { - const value = props.getValue() as number; - const isFooter = '_isFooter' in props.row.original; - return ( -
- {formatCurrency(value)} -
- ); - }, - }, - { - header: 'Keterangan', - accessorKey: 'keterangan', - cell: (props) => { - const isFooter = '_isFooter' in props.row.original; - if (isFooter) return null; - const value = props.getValue() as string; - return value || '-'; - }, - }, - ], - [] - ); - - const createFooterRow = ( + // Helper function to create columns with footer support + const createColumns = ( total?: TotalSapronakCalculation - ): FooterSapronakCalculationRow[] => { - if (!total) return []; - return [ - { - id: -999, - tanggal: '', - no_referensi: total.label, - qty_masuk: total.qty_masuk, - qty_keluar: total.qty_keluar, - qty_pakai: total.qty_pakai, - uraian: '', - kategori_produk: '', - harga_beli_per_qty: total.harga_beli_per_qty, - total_harga: total.total_harga, - keterangan: '', - _isFooter: true, - }, - ]; - }; + ): ColumnDef[] => [ + { + header: 'Tanggal', + accessorKey: 'tanggal', + cell: (props) => (props.getValue() as string) || '-', + footer: 'Total', + }, + { + header: 'No. Referensi', + accessorKey: 'no_referensi', + cell: (props) => (props.getValue() as string) || '-', + footer: '', + }, + { + header: 'QTY Masuk', + accessorKey: 'qty_masuk', + cell: (props) => formatNumber(props.getValue() as number), + footer: total + ? () => ( +
+ {formatNumber(total.qty_masuk)} +
+ ) + : '', + }, + { + header: 'QTY Keluar', + accessorKey: 'qty_keluar', + cell: (props) => formatNumber(props.getValue() as number), + footer: total + ? () => ( +
+ {formatNumber(total.qty_keluar)} +
+ ) + : '', + }, + { + header: 'QTY Pakai', + accessorKey: 'qty_pakai', + cell: (props) => formatNumber(props.getValue() as number), + footer: total + ? () => ( +
+ {formatNumber(total.qty_pakai)} +
+ ) + : '', + }, + { + header: 'Uraian', + accessorKey: 'uraian', + cell: (props) => (props.getValue() as string) || '-', + footer: '', + }, + { + header: 'Kategori Produk', + accessorKey: 'kategori_produk', + cell: (props) => (props.getValue() as string) || '-', + footer: '', + }, + { + header: 'Harga Beli/Qty (Rp)', + accessorKey: 'harga_beli_per_qty', + cell: (props) => formatCurrency(props.getValue() as number), + footer: total + ? () => ( +
+ {formatCurrency(total.harga_beli_per_qty)} +
+ ) + : '', + }, + { + header: 'Total Harga (Rp)', + accessorKey: 'total_harga', + cell: (props) => formatCurrency(props.getValue() as number), + footer: total + ? () => ( +
+ {formatCurrency(total.total_harga)} +
+ ) + : '', + }, + { + header: 'Keterangan', + accessorKey: 'keterangan', + cell: (props) => (props.getValue() as string) || '-', + footer: '', + }, + ]; - const docBroilerFooter = useMemo( + // Memoize columns untuk setiap kategori + const docBroilerColumns = useMemo( () => isResponseSuccess(sapronakCalculation) - ? createFooterRow(sapronakCalculation.data?.doc_broiler.total) - : [], + ? createColumns(sapronakCalculation.data?.doc_broiler.total) + : createColumns(), [sapronakCalculation] ); - const ovkFooter = useMemo( + const ovkColumns = useMemo( () => isResponseSuccess(sapronakCalculation) - ? createFooterRow(sapronakCalculation.data?.ovk.total) - : [], + ? createColumns(sapronakCalculation.data?.ovk.total) + : createColumns(), [sapronakCalculation] ); - const pakanFooter = useMemo( + const pakanColumns = useMemo( () => isResponseSuccess(sapronakCalculation) - ? createFooterRow(sapronakCalculation.data?.pakan.total) - : [], + ? createColumns(sapronakCalculation.data?.pakan.total) + : createColumns(), [sapronakCalculation] ); @@ -212,39 +155,20 @@ const ClosingSapronakCalculationTable = ({ <> data={sapronakCalculation.data?.doc_broiler.rows ?? []} - columns={columns} - footerData={docBroilerFooter} - renderFooter={ - (sapronakCalculation.data?.doc_broiler.rows.length ?? 0) > 0 && - !!sapronakCalculation.data?.doc_broiler.total - } + columns={docBroilerColumns} className={{ - containerClassName: cn({ - 'mb-20': - sapronakCalculation.data?.doc_broiler.rows.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', - tableFooterClassName: - 'bg-gray-100 font-semibold border border-gray-200', - footerRowClassName: 'border-t-2 border-gray-300', - footerColumnClassName: 'px-6 py-3 text-xs text-gray-900', + containerClassName: 'my-4', }} + renderFooter /> @@ -259,29 +183,11 @@ const ClosingSapronakCalculationTable = ({ > data={sapronakCalculation.data?.ovk.rows ?? []} - columns={columns} - footerData={ovkFooter} - renderFooter={ - (sapronakCalculation.data?.ovk.rows.length ?? 0) > 0 && - !!sapronakCalculation.data?.ovk.total - } + columns={ovkColumns} className={{ - containerClassName: cn({ - 'mb-20': sapronakCalculation.data?.ovk.rows.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', - tableFooterClassName: - 'bg-gray-100 font-semibold border border-gray-200', - footerRowClassName: 'border-t-2 border-gray-300', - footerColumnClassName: 'px-6 py-3 text-xs text-gray-900', + containerClassName: 'my-4', }} + renderFooter /> @@ -296,29 +202,11 @@ const ClosingSapronakCalculationTable = ({ > data={sapronakCalculation.data?.pakan.rows ?? []} - columns={columns} - footerData={pakanFooter} - renderFooter={ - (sapronakCalculation.data?.pakan.rows.length ?? 0) > 0 && - !!sapronakCalculation.data?.pakan.total - } + columns={pakanColumns} className={{ - containerClassName: cn({ - 'mb-20': sapronakCalculation.data?.pakan.rows.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', - tableFooterClassName: - 'bg-gray-100 font-semibold border border-gray-200', - footerRowClassName: 'border-t-2 border-gray-300', - footerColumnClassName: 'px-6 py-3 text-xs text-gray-900', + containerClassName: 'my-4', }} + renderFooter /> diff --git a/src/dummy/closing.dummy.ts b/src/dummy/closing.dummy.ts new file mode 100644 index 00000000..8ebb0164 --- /dev/null +++ b/src/dummy/closing.dummy.ts @@ -0,0 +1,984 @@ +/** + * Dummy Data untuk Closing API + * + * File ini berisi dummy data untuk testing API Closing sebelum backend siap. + * + * Struktur data mengikuti tipe yang didefinisikan di @/types/api/closing.d.ts + * + * @example + * // 1. Menggunakan getAllFetcher dengan SWR: + * import useSWR from 'swr'; + * import { ClosingApi } from '@/services/api/closing'; + * + * const { data, error, isLoading } = useSWR( + * '/closings', + * ClosingApi.getAllFetcher.bind(ClosingApi) + * ); + * + * if (data?.status === 'success') { + * console.log(data.data); // Array of Closing objects + * } + * + * @example + * // 2. Menggunakan getSingle: + * import { ClosingApi } from '@/services/api/closing'; + * + * const response = await ClosingApi.getSingle(1); + * if (response?.status === 'success') { + * console.log(response.data); // Single Closing object + * } else if (response?.status === 'error') { + * console.error(response.message); // Error message + * } + * + * @example + * // 3. Menggunakan getGeneralInfo dengan SWR: + * import useSWR from 'swr'; + * import { ClosingApi } from '@/services/api/closing'; + * + * const closingId = 1; + * const { data, error, isLoading } = useSWR( + * closingId, + * (id: number) => ClosingApi.getGeneralInfo(id) + * ); + * + * if (data?.status === 'success') { + * console.log(data.data); // ClosingGeneralInformation object + * } + * + * @example + * // 4. Menggunakan getAllIncomingSapronakFetcher dengan SWR: + * import useSWR from 'swr'; + * import { ClosingApi } from '@/services/api/closing'; + * + * const { data, error, isLoading } = useSWR( + * `${ClosingApi.basePath}/1/sapronak/incoming`, + * ClosingApi.getAllIncomingSapronakFetcher.bind(ClosingApi) + * ); + * + * if (data?.status === 'success') { + * console.log(data.data); // Array of ClosingIncomingSapronak + * } + * + * @example + * // 5. Menggunakan getAllOutgoingSapronakFetcher dengan SWR: + * import useSWR from 'swr'; + * import { ClosingApi } from '@/services/api/closing'; + * + * const { data, error, isLoading } = useSWR( + * `${ClosingApi.basePath}/1/sapronak/outgoing`, + * ClosingApi.getAllOutgoingSapronakFetcher.bind(ClosingApi) + * ); + * + * if (data?.status === 'success') { + * console.log(data.data); // Array of ClosingOutgoingSapronak + * } + * + * @see {@link /home/sweetpotet/Documents/projects/lti-web-client/src/types/api/closing.d.ts} + */ + +import { format } from 'date-fns'; +import { + Closing, + ClosingGeneralInformation, + ClosingIncomingSapronak, + ClosingOutgoingSapronak, + ClosingSapronakCalculation, +} from '@/types/api/closing'; +import { CreatedUser, BaseApiResponse } from '@/types/api/api-general'; + +// Waktu saat ini untuk created_at/updated_at +const now = format(new Date(), 'yyyy-MM-dd HH:mm:ss'); +const today = format(new Date(), 'yyyy-MM-dd'); +const yesterday = format( + new Date().setDate(new Date().getDate() - 1), + 'yyyy-MM-dd' +); +const lastWeek = format( + new Date().setDate(new Date().getDate() - 7), + 'yyyy-MM-dd' +); +const lastMonth = format( + new Date().setMonth(new Date().getMonth() - 1), + 'yyyy-MM-dd' +); + +// ====================== +// 👤 Created User +// ====================== +export const createdUser: CreatedUser = { + id: 1, + id_user: 1, + email: 'admin@example.com', + name: 'Admin Utama', +}; + +// ====================== +// 📊 Closing Dummy Data +// ====================== +export const dummyClosings: Closing[] = [ + // 1. Closing dengan status Pengajuan - GROWING + { + id: 1, + location_id: 1, + location_name: 'Farm Sukajadi', + project_category: 'GROWING', + period: 1, + closing_date: today, + shed_label: 'Kandang A1, A2, A3', + shed_count: 3, + sales_paid_amount: 150000000, + sales_remaining_amount: 50000000, + sales_payment_status: 'Sebagian Lunas', + project_status: 'Pengajuan', + created_user: createdUser, + created_at: now, + updated_at: now, + }, + + // 2. Closing dengan status Aktif - LAYING + { + id: 2, + location_id: 2, + location_name: 'Farm Cihampelas', + project_category: 'LAYING', + period: 2, + closing_date: yesterday, + shed_label: 'Kandang B1, B2', + shed_count: 2, + sales_paid_amount: 200000000, + sales_remaining_amount: 0, + sales_payment_status: 'Lunas', + project_status: 'Aktif', + created_user: createdUser, + created_at: lastWeek, + updated_at: yesterday, + }, + + // 3. Closing dengan status Selesai - GROWING + { + id: 3, + location_id: 3, + location_name: 'Farm Pasteur', + project_category: 'GROWING', + period: 3, + closing_date: lastWeek, + shed_label: 'Kandang C1, C2, C3, C4', + shed_count: 4, + sales_paid_amount: 300000000, + sales_remaining_amount: 25000000, + sales_payment_status: 'Sebagian Lunas', + project_status: 'Selesai', + created_user: createdUser, + created_at: lastMonth, + updated_at: lastWeek, + }, + + // 4. Closing dengan status Aktif - LAYING + { + id: 4, + location_id: 4, + location_name: 'Farm Setiabudi', + project_category: 'LAYING', + period: 1, + closing_date: today, + shed_label: 'Kandang D1', + shed_count: 1, + sales_paid_amount: 75000000, + sales_remaining_amount: 75000000, + sales_payment_status: 'Belum Lunas', + project_status: 'Aktif', + created_user: createdUser, + created_at: yesterday, + updated_at: now, + }, + + // 5. Closing dengan status Selesai - GROWING + { + id: 5, + location_id: 5, + location_name: 'Farm Dago', + project_category: 'GROWING', + period: 4, + closing_date: lastMonth, + shed_label: 'Kandang E1, E2, E3, E4, E5', + shed_count: 5, + sales_paid_amount: 500000000, + sales_remaining_amount: 0, + sales_payment_status: 'Lunas', + project_status: 'Selesai', + created_user: createdUser, + created_at: lastMonth, + updated_at: lastMonth, + }, + + // 6. Closing dengan status Pengajuan - LAYING + { + id: 6, + location_id: 6, + location_name: 'Farm Lembang', + project_category: 'LAYING', + period: 2, + closing_date: undefined, // Belum ada tanggal closing + shed_label: 'Kandang F1, F2', + shed_count: 2, + sales_paid_amount: 0, + sales_remaining_amount: 180000000, + sales_payment_status: 'Belum Lunas', + project_status: 'Pengajuan', + created_user: createdUser, + created_at: now, + updated_at: now, + }, + + // 7. Closing dengan status Aktif - GROWING + { + id: 7, + location_id: 7, + location_name: 'Farm Ciwidey', + project_category: 'GROWING', + period: 1, + closing_date: yesterday, + shed_label: 'Kandang G1, G2, G3', + shed_count: 3, + sales_paid_amount: 120000000, + sales_remaining_amount: 30000000, + sales_payment_status: 'Sebagian Lunas', + project_status: 'Aktif', + created_user: createdUser, + created_at: lastWeek, + updated_at: yesterday, + }, + + // 8. Closing dengan status Selesai - LAYING + { + id: 8, + location_id: 8, + location_name: 'Farm Bandung Timur', + project_category: 'LAYING', + period: 3, + closing_date: lastMonth, + shed_label: 'Kandang H1, H2, H3, H4, H5, H6', + shed_count: 6, + sales_paid_amount: 600000000, + sales_remaining_amount: 0, + sales_payment_status: 'Lunas', + project_status: 'Selesai', + created_user: createdUser, + created_at: lastMonth, + updated_at: lastMonth, + }, +]; + +// ====================== +// 📊 Closing General Information Dummy Data +// ====================== +export const dummyClosingGeneralInformations: ClosingGeneralInformation[] = [ + // 1. General Info - GROWING - Pengajuan + { + id: 1, + location_id: 1, + location_name: 'Farm Sukajadi', + project_category: 'GROWING', + period: 1, + closing_date: today, + shed_label: 'Kandang A1, A2, A3', + shed_count: 3, + sales_paid_amount: 150000000, + sales_remaining_amount: 50000000, + sales_payment_status: 'Sebagian Lunas', + project_status: 'Pengajuan', + flock_id: 101, + project_type: 'GROWING', + population: 15000, + active_house_count: 3, + closing_status: 'Draft', + created_user: createdUser, + created_at: now, + updated_at: now, + }, + + // 2. General Info - LAYING - Aktif + { + id: 2, + location_id: 2, + location_name: 'Farm Cihampelas', + project_category: 'LAYING', + period: 2, + closing_date: yesterday, + shed_label: 'Kandang B1, B2', + shed_count: 2, + sales_paid_amount: 200000000, + sales_remaining_amount: 0, + sales_payment_status: 'Lunas', + project_status: 'Aktif', + flock_id: 102, + project_type: 'LAYING', + population: 10000, + active_house_count: 2, + closing_status: 'In Progress', + created_user: createdUser, + created_at: lastWeek, + updated_at: yesterday, + }, + + // 3. General Info - GROWING - Selesai + { + id: 3, + location_id: 3, + location_name: 'Farm Pasteur', + project_category: 'GROWING', + period: 3, + closing_date: lastWeek, + shed_label: 'Kandang C1, C2, C3, C4', + shed_count: 4, + sales_paid_amount: 300000000, + sales_remaining_amount: 25000000, + sales_payment_status: 'Sebagian Lunas', + project_status: 'Selesai', + flock_id: 103, + project_type: 'GROWING', + population: 20000, + active_house_count: 4, + closing_status: 'Completed', + created_user: createdUser, + created_at: lastMonth, + updated_at: lastWeek, + }, + + // 4. General Info - LAYING - Aktif + { + id: 4, + location_id: 4, + location_name: 'Farm Setiabudi', + project_category: 'LAYING', + period: 1, + closing_date: today, + shed_label: 'Kandang D1', + shed_count: 1, + sales_paid_amount: 75000000, + sales_remaining_amount: 75000000, + sales_payment_status: 'Belum Lunas', + project_status: 'Aktif', + flock_id: 104, + project_type: 'LAYING', + population: 5000, + active_house_count: 1, + closing_status: 'In Progress', + created_user: createdUser, + created_at: yesterday, + updated_at: now, + }, + + // 5. General Info - GROWING - Selesai + { + id: 5, + location_id: 5, + location_name: 'Farm Dago', + project_category: 'GROWING', + period: 4, + closing_date: lastMonth, + shed_label: 'Kandang E1, E2, E3, E4, E5', + shed_count: 5, + sales_paid_amount: 500000000, + sales_remaining_amount: 0, + sales_payment_status: 'Lunas', + project_status: 'Selesai', + flock_id: 105, + project_type: 'GROWING', + population: 25000, + active_house_count: 5, + closing_status: 'Completed', + created_user: createdUser, + created_at: lastMonth, + updated_at: lastMonth, + }, + + // 6. General Info - LAYING - Pengajuan + { + id: 6, + location_id: 6, + location_name: 'Farm Lembang', + project_category: 'LAYING', + period: 2, + closing_date: undefined, + shed_label: 'Kandang F1, F2', + shed_count: 2, + sales_paid_amount: 0, + sales_remaining_amount: 180000000, + sales_payment_status: 'Belum Lunas', + project_status: 'Pengajuan', + flock_id: 106, + project_type: 'LAYING', + population: 12000, + active_house_count: 2, + closing_status: 'Draft', + created_user: createdUser, + created_at: now, + updated_at: now, + }, + + // 7. General Info - GROWING - Aktif + { + id: 7, + location_id: 7, + location_name: 'Farm Ciwidey', + project_category: 'GROWING', + period: 1, + closing_date: yesterday, + shed_label: 'Kandang G1, G2, G3', + shed_count: 3, + sales_paid_amount: 120000000, + sales_remaining_amount: 30000000, + sales_payment_status: 'Sebagian Lunas', + project_status: 'Aktif', + flock_id: 107, + project_type: 'GROWING', + population: 18000, + active_house_count: 3, + closing_status: 'In Progress', + created_user: createdUser, + created_at: lastWeek, + updated_at: yesterday, + }, + + // 8. General Info - LAYING - Selesai + { + id: 8, + location_id: 8, + location_name: 'Farm Bandung Timur', + project_category: 'LAYING', + period: 3, + closing_date: lastMonth, + shed_label: 'Kandang H1, H2, H3, H4, H5, H6', + shed_count: 6, + sales_paid_amount: 600000000, + sales_remaining_amount: 0, + sales_payment_status: 'Lunas', + project_status: 'Selesai', + flock_id: 108, + project_type: 'LAYING', + population: 30000, + active_house_count: 6, + closing_status: 'Completed', + created_user: createdUser, + created_at: lastMonth, + updated_at: lastMonth, + }, +]; + +// ====================== +// 📦 Incoming Sapronak Dummy Data +// ====================== +export const dummyIncomingSapronaks: ClosingIncomingSapronak[] = [ + { + id: 1, + date: today, + reference_number: 'IN-2025-001', + transaction_type: 'Pembelian', + product_name: 'DOC Broiler Cobb 500', + product_category: 'DOC', + product_sub_category: 'DOC Broiler', + source_warehouse: 'Gudang Pusat', + destination_warehouse: 'Kandang A1', + quantity: 5000, + unit: 'Ekor', + formatted_quantity: '5,000 Ekor', + notes: 'DOC berkualitas tinggi dari supplier terpercaya', + }, + { + id: 2, + date: yesterday, + reference_number: 'IN-2025-002', + transaction_type: 'Transfer Masuk', + product_name: 'Pakan Starter BR-1', + product_category: 'Pakan', + product_sub_category: 'Starter', + source_warehouse: 'Gudang Area Bandung', + destination_warehouse: 'Kandang B1', + quantity: 100, + unit: 'Sak', + formatted_quantity: '100 Sak (5,000 Kg)', + notes: 'Pakan starter untuk periode awal', + }, + { + id: 3, + date: lastWeek, + reference_number: 'IN-2025-003', + transaction_type: 'Pembelian', + product_name: 'Vitamin B Complex', + product_category: 'OVK', + product_sub_category: 'Vitamin', + source_warehouse: 'Supplier Medion', + destination_warehouse: 'Gudang Farmasi', + quantity: 50, + unit: 'Botol', + formatted_quantity: '50 Botol', + notes: 'Vitamin untuk meningkatkan daya tahan tubuh', + }, + { + id: 4, + date: today, + reference_number: 'IN-2025-004', + transaction_type: 'Pembelian', + product_name: 'Pakan Finisher BR-2', + product_category: 'Pakan', + product_sub_category: 'Finisher', + source_warehouse: 'Gudang Pusat', + destination_warehouse: 'Kandang C1', + quantity: 200, + unit: 'Sak', + formatted_quantity: '200 Sak (10,000 Kg)', + notes: 'Pakan finisher untuk periode akhir', + }, + { + id: 5, + date: yesterday, + reference_number: 'IN-2025-005', + transaction_type: 'Transfer Masuk', + product_name: 'Antibiotik Enrofloxacin', + product_category: 'OVK', + product_sub_category: 'Obat', + source_warehouse: 'Gudang Area Jakarta', + destination_warehouse: 'Gudang Farmasi', + quantity: 30, + unit: 'Box', + formatted_quantity: '30 Box', + notes: 'Antibiotik untuk pencegahan penyakit', + }, +]; + +// ====================== +// 📤 Outgoing Sapronak Dummy Data +// ====================== +export const dummyOutgoingSapronaks: ClosingOutgoingSapronak[] = [ + { + id: 1, + date: today, + reference_number: 'OUT-2025-001', + transaction_type: 'Pemakaian', + product_name: 'Pakan Starter BR-1', + product_category: 'Pakan', + product_sub_category: 'Starter', + source_warehouse: 'Kandang A1', + destination_warehouse: 'Konsumsi Kandang A1', + quantity: 50, + unit: 'Sak', + formatted_quantity: '50 Sak (2,500 Kg)', + notes: 'Pemakaian pakan harian periode starter', + }, + { + id: 2, + date: yesterday, + reference_number: 'OUT-2025-002', + transaction_type: 'Transfer Keluar', + product_name: 'DOC Broiler Cobb 500', + product_category: 'DOC', + product_sub_category: 'DOC Broiler', + source_warehouse: 'Kandang B1', + destination_warehouse: 'Kandang B2', + quantity: 1000, + unit: 'Ekor', + formatted_quantity: '1,000 Ekor', + notes: 'Transfer DOC ke kandang baru', + }, + { + id: 3, + date: lastWeek, + reference_number: 'OUT-2025-003', + transaction_type: 'Pemakaian', + product_name: 'Vitamin B Complex', + product_category: 'OVK', + product_sub_category: 'Vitamin', + source_warehouse: 'Gudang Farmasi', + destination_warehouse: 'Konsumsi Kandang C1', + quantity: 10, + unit: 'Botol', + formatted_quantity: '10 Botol', + notes: 'Pemberian vitamin untuk meningkatkan kesehatan', + }, + { + id: 4, + date: today, + reference_number: 'OUT-2025-004', + transaction_type: 'Pemakaian', + product_name: 'Pakan Finisher BR-2', + product_category: 'Pakan', + product_sub_category: 'Finisher', + source_warehouse: 'Kandang C1', + destination_warehouse: 'Konsumsi Kandang C1', + quantity: 80, + unit: 'Sak', + formatted_quantity: '80 Sak (4,000 Kg)', + notes: 'Pemakaian pakan harian periode finisher', + }, + { + id: 5, + date: yesterday, + reference_number: 'OUT-2025-005', + transaction_type: 'Pemakaian', + product_name: 'Antibiotik Enrofloxacin', + product_category: 'OVK', + product_sub_category: 'Obat', + source_warehouse: 'Gudang Farmasi', + destination_warehouse: 'Konsumsi Kandang D1', + quantity: 5, + unit: 'Box', + formatted_quantity: '5 Box', + notes: 'Pengobatan untuk ayam yang sakit', + }, + { + id: 6, + date: lastWeek, + reference_number: 'OUT-2025-006', + transaction_type: 'Transfer Keluar', + product_name: 'Pakan Starter BR-1', + product_category: 'Pakan', + product_sub_category: 'Starter', + source_warehouse: 'Kandang E1', + destination_warehouse: 'Kandang E2', + quantity: 30, + unit: 'Sak', + formatted_quantity: '30 Sak (1,500 Kg)', + notes: 'Transfer pakan antar kandang', + }, +]; + +// ====================== +// 📊 Perhitungan Sapronak Dummy Data +// ====================== +export const dummySapronakCalculation: ClosingSapronakCalculation = { + // DOC Broiler Calculation + doc_broiler: { + rows: [ + { + id: 1, + tanggal: today, + no_referensi: 'IN-2025-001', + qty_masuk: 5000, + qty_keluar: 0, + qty_pakai: 0, + uraian: 'DOC Broiler Cobb 500', + kategori_produk: 'DOC Broiler', + harga_beli_per_qty: 8000, + total_harga: 40000000, + keterangan: 'Pembelian DOC dari supplier', + }, + { + id: 2, + tanggal: yesterday, + no_referensi: 'OUT-2025-002', + qty_masuk: 0, + qty_keluar: 1000, + qty_pakai: 0, + uraian: 'DOC Broiler Cobb 500', + kategori_produk: 'DOC Broiler', + harga_beli_per_qty: 8000, + total_harga: 8000000, + keterangan: 'Transfer DOC ke kandang lain', + }, + { + id: 3, + tanggal: lastWeek, + no_referensi: 'USE-2025-001', + qty_masuk: 0, + qty_keluar: 0, + qty_pakai: 50, + uraian: 'DOC Broiler Cobb 500', + kategori_produk: 'DOC Broiler', + harga_beli_per_qty: 8000, + total_harga: 400000, + keterangan: 'Mortalitas DOC', + }, + ], + total: { + label: 'Total DOC Broiler', + qty_masuk: 5000, + qty_keluar: 1000, + qty_pakai: 50, + harga_beli_per_qty: 8000, + total_harga: 48400000, + }, + }, + + // OVK Calculation + ovk: { + rows: [ + { + id: 1, + tanggal: today, + no_referensi: 'IN-2025-003', + qty_masuk: 50, + qty_keluar: 0, + qty_pakai: 0, + uraian: 'Vitamin B Complex', + kategori_produk: 'Vitamin', + harga_beli_per_qty: 150000, + total_harga: 7500000, + keterangan: 'Pembelian vitamin', + }, + { + id: 2, + tanggal: yesterday, + no_referensi: 'IN-2025-005', + qty_masuk: 30, + qty_keluar: 0, + qty_pakai: 0, + uraian: 'Antibiotik Enrofloxacin', + kategori_produk: 'Obat', + harga_beli_per_qty: 250000, + total_harga: 7500000, + keterangan: 'Pembelian antibiotik', + }, + { + id: 3, + tanggal: lastWeek, + no_referensi: 'OUT-2025-003', + qty_masuk: 0, + qty_keluar: 0, + qty_pakai: 10, + uraian: 'Vitamin B Complex', + kategori_produk: 'Vitamin', + harga_beli_per_qty: 150000, + total_harga: 1500000, + keterangan: 'Pemakaian vitamin', + }, + { + id: 4, + tanggal: yesterday, + no_referensi: 'OUT-2025-005', + qty_masuk: 0, + qty_keluar: 0, + qty_pakai: 5, + uraian: 'Antibiotik Enrofloxacin', + kategori_produk: 'Obat', + harga_beli_per_qty: 250000, + total_harga: 1250000, + keterangan: 'Pemakaian antibiotik', + }, + ], + total: { + label: 'Total OVK', + qty_masuk: 80, + qty_keluar: 0, + qty_pakai: 15, + harga_beli_per_qty: 200000, + total_harga: 17750000, + }, + }, + + // Pakan Calculation + pakan: { + rows: [ + { + id: 1, + tanggal: yesterday, + no_referensi: 'IN-2025-002', + qty_masuk: 100, + qty_keluar: 0, + qty_pakai: 0, + uraian: 'Pakan Starter BR-1', + kategori_produk: 'Starter', + harga_beli_per_qty: 450000, + total_harga: 45000000, + keterangan: 'Pembelian pakan starter', + }, + { + id: 2, + tanggal: today, + no_referensi: 'IN-2025-004', + qty_masuk: 200, + qty_keluar: 0, + qty_pakai: 0, + uraian: 'Pakan Finisher BR-2', + kategori_produk: 'Finisher', + harga_beli_per_qty: 480000, + total_harga: 96000000, + keterangan: 'Pembelian pakan finisher', + }, + { + id: 3, + tanggal: today, + no_referensi: 'OUT-2025-001', + qty_masuk: 0, + qty_keluar: 0, + qty_pakai: 50, + uraian: 'Pakan Starter BR-1', + kategori_produk: 'Starter', + harga_beli_per_qty: 450000, + total_harga: 22500000, + keterangan: 'Pemakaian pakan starter', + }, + { + id: 4, + tanggal: today, + no_referensi: 'OUT-2025-004', + qty_masuk: 0, + qty_keluar: 0, + qty_pakai: 80, + uraian: 'Pakan Finisher BR-2', + kategori_produk: 'Finisher', + harga_beli_per_qty: 480000, + total_harga: 38400000, + keterangan: 'Pemakaian pakan finisher', + }, + { + id: 5, + tanggal: lastWeek, + no_referensi: 'OUT-2025-006', + qty_masuk: 0, + qty_keluar: 30, + qty_pakai: 0, + uraian: 'Pakan Starter BR-1', + kategori_produk: 'Starter', + harga_beli_per_qty: 450000, + total_harga: 13500000, + keterangan: 'Transfer pakan ke kandang lain', + }, + ], + total: { + label: 'Total Pakan', + qty_masuk: 300, + qty_keluar: 30, + qty_pakai: 130, + harga_beli_per_qty: 465000, + total_harga: 215400000, + }, + }, +}; + +// ====================== +// 🔧 Dummy API Response Functions +// ====================== + +/** + * Dummy implementation for getAllFetcher + * Returns all closing records + */ +export const dummyGetAllFetcher = async (): Promise<{ + code: number; + status: 'success'; + message: string; + data: Closing[]; +}> => { + await new Promise((resolve) => setTimeout(resolve, 500)); + return { + code: 200, + status: 'success', + message: 'Data closing berhasil diambil', + data: dummyClosings, + }; +}; + +/** + * Dummy implementation for getSingle + * Returns a single closing by ID + */ +export const dummyGetSingle = async ( + id: number +): Promise | undefined> => { + await new Promise((resolve) => setTimeout(resolve, 300)); + const closing = dummyClosings.find((c) => c.id === id); + + if (!closing) { + return { + code: 404, + status: 'error', + message: `Closing dengan ID ${id} tidak ditemukan`, + }; + } + + return { + code: 200, + status: 'success', + message: 'Data closing berhasil diambil', + data: closing, + }; +}; + +/** + * Dummy implementation for getAllIncomingSapronakFetcher + * Returns all incoming sapronak records + */ +export const dummyGetAllIncomingSapronakFetcher = async (): Promise<{ + code: number; + status: 'success'; + message: string; + data: ClosingIncomingSapronak[]; +}> => { + await new Promise((resolve) => setTimeout(resolve, 400)); + return { + code: 200, + status: 'success', + message: 'Data sapronak masuk berhasil diambil', + data: dummyIncomingSapronaks, + }; +}; + +/** + * Dummy implementation for getAllOutgoingSapronakFetcher + * Returns all outgoing sapronak records + */ +export const dummyGetAllOutgoingSapronakFetcher = async (): Promise<{ + code: number; + status: 'success'; + message: string; + data: ClosingOutgoingSapronak[]; +}> => { + await new Promise((resolve) => setTimeout(resolve, 400)); + return { + code: 200, + status: 'success', + message: 'Data sapronak keluar berhasil diambil', + data: dummyOutgoingSapronaks, + }; +}; + +/** + * Dummy implementation for getGeneralInfo + * Returns closing general information by ID + */ +export const dummyGetGeneralInfo = async ( + id: number +): Promise | undefined> => { + await new Promise((resolve) => setTimeout(resolve, 300)); + const closingInfo = dummyClosingGeneralInformations.find((c) => c.id == id); + + if (!closingInfo) { + return { + code: 404, + status: 'error', + message: `Closing general information dengan ID ${id} tidak ditemukan`, + }; + } + + return { + code: 200, + status: 'success', + message: 'Data closing general information berhasil diambil', + data: closingInfo, + }; +}; + +/** + * Dummy implementation for getPerhitunganSapronak + * Returns sapronak calculation data + */ +export const dummyGetPerhitunganSapronak = async ( + id: number +): Promise< + | { + code: number; + status: 'success'; + message: string; + data: ClosingSapronakCalculation; + } + | undefined +> => { + await new Promise((resolve) => setTimeout(resolve, 400)); + return { + code: 200, + status: 'success', + message: 'Data perhitungan sapronak berhasil diambil', + data: dummySapronakCalculation, + }; +}; diff --git a/src/services/api/closing.ts b/src/services/api/closing.ts index 9dc5ab30..9514f6a3 100644 --- a/src/services/api/closing.ts +++ b/src/services/api/closing.ts @@ -8,17 +8,62 @@ import { ClosingOutgoingSapronak, ClosingSapronakCalculation, } from '@/types/api/closing'; -import { httpClient, httpClientFetcher } from '@/services/http/client'; import { BaseApiResponse } from '@/types/api/api-general'; +import { + dummyGetAllFetcher, + dummyGetSingle, + dummyGetAllIncomingSapronakFetcher, + dummyGetAllOutgoingSapronakFetcher, + dummyGetGeneralInfo, + dummyGetPerhitunganSapronak, +} from '@/dummy/closing.dummy'; +import { httpClient, httpClientFetcher } from '@/services/http/client'; export class ClosingApiService extends BaseApiService { constructor(basePath: string) { super(basePath); } + async getAllFetcher(endpoint: string): Promise> { + // TODO: Remove this block when backend is ready + // return await dummyGetAllFetcher(); + + // Uncomment this when backend is ready + return await httpClientFetcher>(endpoint); + } + + async getSingle(id: number): Promise | undefined> { + // TODO: Remove this block when backend is ready + // try { + // return await dummyGetSingle(id); + // } catch (error) { + // if (axios.isAxiosError>(error)) { + // return error.response?.data; + // } + // return undefined; + // } + + // Uncomment this when backend is ready + try { + const getSinglePath = `${this.basePath}/${id}`; + const getSingleRes = + await httpClient>(getSinglePath); + return getSingleRes; + } catch (error) { + if (axios.isAxiosError>(error)) { + return error.response?.data; + } + return undefined; + } + } + async getAllIncomingSapronakFetcher( endpoint: string ): Promise> { + // TODO: Remove this block when backend is ready + // return await dummyGetAllIncomingSapronakFetcher(); + + // Uncomment this when backend is ready return await httpClientFetcher>( endpoint ); @@ -27,19 +72,37 @@ export class ClosingApiService extends BaseApiService { async getAllOutgoingSapronakFetcher( endpoint: string ): Promise> { + // TODO: Remove this block when backend is ready + // return await dummyGetAllOutgoingSapronakFetcher(); + + // Uncomment this when backend is ready return await httpClientFetcher>( endpoint ); } - async getGeneralInfo(id: number) { + async getGeneralInfo( + id: number + ): Promise | undefined> { + // TODO: Remove this block when backend is ready + // try { + // return await dummyGetGeneralInfo(id); + // } catch (error) { + // if ( + // axios.isAxiosError>(error) + // ) { + // return error.response?.data; + // } + // return undefined; + // } + + // Uncomment this when backend is ready try { const getGeneralInfoPath = `${this.basePath}/${id}`; const getGeneralInfoRes = await httpClient>( getGeneralInfoPath ); - return getGeneralInfoRes; } catch (error) { if ( @@ -54,9 +117,21 @@ export class ClosingApiService extends BaseApiService { async getPerhitunganSapronak( id: number ): Promise | undefined> { + // TODO: Remove this block when backend is ready + // try { + // return await dummyGetPerhitunganSapronak(id); + // } catch (error) { + // if ( + // axios.isAxiosError>(error) + // ) { + // return error.response?.data; + // } + // return undefined; + // } + + // Uncomment this when backend is ready try { const path = `${this.basePath}/${id}/perhitungan_sapronak`; - return await httpClient>( path, {