From ba1d462a0a994a7cc7f9260d7a9d89a0dc35c969 Mon Sep 17 00:00:00 2001 From: randy-ar Date: Fri, 30 Jan 2026 11:02:18 +0700 Subject: [PATCH] fix(FE): adding skeleton state data on null or unfiltered --- src/components/Table.tsx | 14 ++++- .../helper/skeleton/DataStateSkeleton.tsx | 26 ++++++++ .../helper/skeleton/IconSkeleton.tsx | 13 ++++ .../pages/dashboard/DashboardProduction.tsx | 1 - .../dashboard/chart/DashboardLineChart.tsx | 19 +++--- .../skeleton/DashboardLineChartSkeleton.tsx | 52 ++++++---------- .../skeleton/CustomerSupplierSkeleton.tsx | 37 +++++++++++ .../finance/skeleton/DebtSupplierSkeleton.tsx | 38 ++++++++++++ .../report/finance/tab/CustomerPaymentTab.tsx | 35 ++++++++--- .../report/finance/tab/DebtSupplierTab.tsx | 61 +++++++++++++------ 10 files changed, 222 insertions(+), 74 deletions(-) create mode 100644 src/components/helper/skeleton/DataStateSkeleton.tsx create mode 100644 src/components/helper/skeleton/IconSkeleton.tsx create mode 100644 src/components/pages/report/finance/skeleton/CustomerSupplierSkeleton.tsx create mode 100644 src/components/pages/report/finance/skeleton/DebtSupplierSkeleton.tsx diff --git a/src/components/Table.tsx b/src/components/Table.tsx index 0be39fb5..b40d9db5 100644 --- a/src/components/Table.tsx +++ b/src/components/Table.tsx @@ -42,6 +42,7 @@ interface TableClassNames { footerRowClassName?: string; footerColumnClassName?: string; paginationClassName?: string; + skeletonCellClassName?: string; } export interface TableProps { @@ -79,7 +80,9 @@ export interface TableProps { getSubRows?: (originalRow: TData, index: number) => TData[] | undefined; } -const DUMMY_SKELETON_DATA = [{}, {}, {}, {}, {}]; +const DUMMY_SKELETON_DATA = Array.from({ length: 10 }, (_, index) => ({ + id: index, +})); const emptyContentDefaultValue = (
@@ -414,7 +417,14 @@ const Table = ({ cell.getContext() )} - {isLoading &&
} + {isLoading && ( +
+ )} ))} diff --git a/src/components/helper/skeleton/DataStateSkeleton.tsx b/src/components/helper/skeleton/DataStateSkeleton.tsx new file mode 100644 index 00000000..cea68b82 --- /dev/null +++ b/src/components/helper/skeleton/DataStateSkeleton.tsx @@ -0,0 +1,26 @@ +import IconSkeleton from '@/components/helper/skeleton/IconSkeleton'; +import { Icon } from '@iconify/react'; + +const DataStateSkeleton = ({ + icon, + title, + description, +}: { + icon: React.ReactNode; + title: string; + description: string; +}) => { + return ( +
+ {icon} +

+ {title} +

+

+ {description} +

+
+ ); +}; + +export default DataStateSkeleton; diff --git a/src/components/helper/skeleton/IconSkeleton.tsx b/src/components/helper/skeleton/IconSkeleton.tsx new file mode 100644 index 00000000..0100f14b --- /dev/null +++ b/src/components/helper/skeleton/IconSkeleton.tsx @@ -0,0 +1,13 @@ +import { ReactNode } from 'react'; + +const IconSkeleton = ({ children }: { children: ReactNode }) => { + return ( +
+
+ {children} +
+
+ ); +}; + +export default IconSkeleton; diff --git a/src/components/pages/dashboard/DashboardProduction.tsx b/src/components/pages/dashboard/DashboardProduction.tsx index 27cc208b..674f3719 100644 --- a/src/components/pages/dashboard/DashboardProduction.tsx +++ b/src/components/pages/dashboard/DashboardProduction.tsx @@ -463,7 +463,6 @@ const DashboardProduction = () => { Boolean(formik.errors.endDate) && Boolean(formik.touched.endDate) } - isRange />
diff --git a/src/components/pages/dashboard/chart/DashboardLineChart.tsx b/src/components/pages/dashboard/chart/DashboardLineChart.tsx index 092e4bca..58749cf2 100644 --- a/src/components/pages/dashboard/chart/DashboardLineChart.tsx +++ b/src/components/pages/dashboard/chart/DashboardLineChart.tsx @@ -1,6 +1,7 @@ import Button from '@/components/Button'; import Card from '@/components/Card'; import Dropdown from '@/components/Dropdown'; +import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton'; import { OptionType } from '@/components/input/SelectInput'; import Menu from '@/components/menu/Menu'; import MenuItem from '@/components/menu/MenuItem'; @@ -721,24 +722,18 @@ const DashboardLineChart = ({ return (
{/* Chart icon */} -
-
+ -
-
- - {/* Empty state text */} -

- Data Not Yet Available -

-

- Please change your filters to get the data. -

+ } + title='Data Not Yet Available' + description='Please change your filters to get the data.' + />
); } diff --git a/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx b/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx index 6e4e4b97..7f19a6d0 100644 --- a/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx +++ b/src/components/pages/dashboard/skeleton/DashboardLineChartSkeleton.tsx @@ -1,5 +1,6 @@ import { Icon } from '@iconify/react'; import { DashboardMeta } from '@/types/api/dashboard/dashboard'; +import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton'; const DashboardLineChartSkeleton = ({ meta }: { meta?: DashboardMeta }) => { return ( @@ -24,50 +25,35 @@ const DashboardLineChartSkeleton = ({ meta }: { meta?: DashboardMeta }) => { {!meta?.filters && ( <> {/* Filter icon */} -
-
-
- -
-
-
- - {/* Empty state text */} -

- No Filters Selected -

-

- Please choose filters to narrow down your results and make - your search easier. -

+ + } + title='No Filters Selected' + description='Please choose filters to narrow down your results and make your search easier.' + /> )} {meta?.filters && ( <> {/* Filter icon */} -
-
+ -
-
- - {/* Empty state text */} -

- Data Not Yet Available -

-

- Please change your filters to get the data. -

+ } + title='Data Not Yet Available' + description='Please change your filters to get the data.' + /> )}
diff --git a/src/components/pages/report/finance/skeleton/CustomerSupplierSkeleton.tsx b/src/components/pages/report/finance/skeleton/CustomerSupplierSkeleton.tsx new file mode 100644 index 00000000..8ab0ffd3 --- /dev/null +++ b/src/components/pages/report/finance/skeleton/CustomerSupplierSkeleton.tsx @@ -0,0 +1,37 @@ +import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton'; +import Table from '@/components/Table'; +import { CustomerPaymentRow } from '@/types/api/report/customer-payment'; +import { ColumnDef } from '@tanstack/react-table'; + +const CustomerSupplierSkeleton = ({ + columns, + icon, + title, + subtitle, +}: { + columns: ColumnDef[]; + icon: React.ReactNode; + title: string; + subtitle: string; +}) => { + return ( +
+ +
+ +
+ + ); +}; + +export default CustomerSupplierSkeleton; diff --git a/src/components/pages/report/finance/skeleton/DebtSupplierSkeleton.tsx b/src/components/pages/report/finance/skeleton/DebtSupplierSkeleton.tsx new file mode 100644 index 00000000..b9397f8f --- /dev/null +++ b/src/components/pages/report/finance/skeleton/DebtSupplierSkeleton.tsx @@ -0,0 +1,38 @@ +import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton'; +import Table from '@/components/Table'; +import { DebtRow } from '@/types/api/report/debt-supplier'; +import { Icon } from '@iconify/react'; +import { ColumnDef } from '@tanstack/react-table'; + +const DebtSupplierSkeleton = ({ + columns, + icon, + title, + subtitle, +}: { + columns: ColumnDef[]; + icon: React.ReactNode; + title: string; + subtitle: string; +}) => { + return ( +
+
+
+ +
+ + ); +}; + +export default DebtSupplierSkeleton; diff --git a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx index 0ce0b904..2987455a 100644 --- a/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx +++ b/src/components/pages/report/finance/tab/CustomerPaymentTab.tsx @@ -14,6 +14,7 @@ import { ColumnDef } from '@tanstack/react-table'; import { formatCurrency, formatDate, formatNumber, cn } from '@/lib/helper'; import { CustomerPaymentReport, + CustomerPaymentRow, CustomerPaymentSummary, } from '@/types/api/report/customer-payment'; import { isResponseSuccess } from '@/lib/api-helper'; @@ -27,6 +28,7 @@ import toast from 'react-hot-toast'; import { generateCustomerPaymentExcel } from '@/components/pages/report/finance/export/CustomerPaymentExportXLSX'; import { generateCustomerPaymentPDF } from '@/components/pages/report/finance/export/CustomerPaymentExportPDF'; import { useFinanceTabStore } from '@/stores/finance-tab/finance-tab.store'; +import CustomerSupplierSkeleton from '@/components/pages/report/finance/skeleton/CustomerSupplierSkeleton'; interface CustomerPaymentTabProps { tabId: string; @@ -650,18 +652,37 @@ const CustomerPaymentTab = ({ tabId }: CustomerPaymentTabProps) => { <>
{!isSubmitted ? ( -
- Silakan klik tombol Filter untuk mengatur filter dan menampilkan - data. -
+ + } + title='No Filters Selected' + subtitle='Please choose filters to narrow down your results and make your search easier.' + /> ) : isLoading ? (
) : data.length === 0 ? ( -
- Tidak ada data yang dapat ditampilkan... -
+ + } + title='Data Not Yet Available' + subtitle='Please change your filters to get the data.' + /> ) : ( data.map((customerReport) => { const summary = customerReport.summary || { diff --git a/src/components/pages/report/finance/tab/DebtSupplierTab.tsx b/src/components/pages/report/finance/tab/DebtSupplierTab.tsx index ac53a7a3..646cfb15 100644 --- a/src/components/pages/report/finance/tab/DebtSupplierTab.tsx +++ b/src/components/pages/report/finance/tab/DebtSupplierTab.tsx @@ -35,6 +35,8 @@ import SelectInputCheckbox from '@/components/input/SelectInputCheckbox'; import SelectInputRadio from '@/components/input/SelectInputRadio'; import { useFinanceTabStore } from '@/stores/finance-tab/finance-tab.store'; import StatusBadge from '@/components/helper/StatusBadge'; +import DebtSupplierSkeleton from '@/components/pages/report/finance/skeleton/DebtSupplierSkeleton'; +import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton'; const dueStatus: Record = { 'Sudah Jatuh Tempo': 'error', @@ -332,7 +334,7 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { }; }, [tabId, clearTabActions]); - const getTableColumns = (supplier: DebtSupplier): ColumnDef[] => [ + const getTableColumns = (supplier?: DebtSupplier): ColumnDef[] => [ { id: 'no', header: 'No', @@ -398,8 +400,10 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { return
{formatNumber(value)} Hari
; }, footer: () => { - const value = supplier.total.aging; - return
{formatNumber(value)} Hari
; + const value = supplier?.total.aging; + return ( +
{formatNumber(value || 0)} Hari
+ ); }, }, { @@ -460,10 +464,10 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { ); }, footer: () => { - const value = supplier.total.total_price; + const value = supplier?.total.total_price; return ( -
- {formatCurrency(value)} +
+ {formatCurrency(value || 0)}
); }, @@ -482,10 +486,10 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { ); }, footer: () => { - const value = supplier.total.payment_price; + const value = supplier?.total.payment_price; return ( -
- {formatCurrency(value)} +
+ {formatCurrency(value || 0)}
); }, @@ -504,10 +508,10 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { ); }, footer: () => { - const value = supplier.total.debt_price; + const value = supplier?.total.debt_price; return ( -
- {formatCurrency(value)} +
+ {formatCurrency(value || 0)}
); }, @@ -541,18 +545,37 @@ const DebtSupplierTab = ({ tabId }: DebtSupplierTabProps) => { <>
{!isSubmitted ? ( -
- Silakan klik tombol Filter untuk mengatur filter dan menampilkan - data. -
+ + } + title='No Filters Selected' + subtitle='Please choose filters to narrow down your results and make your search easier.' + /> ) : isLoading ? (
) : data.length === 0 ? ( -
- Tidak ada data yang dapat ditampilkan... -
+ + } + title='Data Not Yet Available' + subtitle='Please change your filters to get the data.' + /> ) : ( data.map((supplierReport) => { return (