refactor(FE): Add tab state management and skeleton for

PurchasesPerSupplierTab
This commit is contained in:
rstubryan
2026-02-11 15:53:32 +07:00
parent b03ef4923e
commit 4e5745d237
4 changed files with 712 additions and 393 deletions
@@ -1,14 +1,19 @@
'use client';
import { useState } from 'react';
import Tabs from '@/components/Tabs';
import PurchasesPerSupplierTab from '@/components/pages/report/logistic-stock/tab/PurchasesPerSupplierTab';
import { useLogisticStockTabStore } from '@/stores/logistic-stock-tab/logistic-stock-tab.store';
const LogisticStockTabs = () => {
const [activeTabId, setActiveTabId] = useState<string>('1');
const tabActions = useLogisticStockTabStore((state) => state.tabActions);
const tabs = [
{
id: '1',
label: 'Rekapitulasi Pembelian Per Supplier',
content: <PurchasesPerSupplierTab />,
content: <PurchasesPerSupplierTab tabId='1' />,
},
// {
// id: '2',
@@ -23,8 +28,20 @@ const LogisticStockTabs = () => {
];
return (
<section className='w-full p-4'>
<Tabs tabs={tabs} variant='lifted' />
<section className='w-full'>
<Tabs
tabs={tabs}
variant='lifted'
activeTabId={activeTabId}
onTabChange={setActiveTabId}
className={{
tabHeaderWrapper:
'justify-between items-center p-3 border-b border-base-content/10',
tab: 'w-fit',
content: 'p-0 m-0',
}}
sideContent={tabActions[activeTabId] || null}
/>
</section>
);
};
@@ -0,0 +1,37 @@
import DataStateSkeleton from '@/components/helper/skeleton/DataStateSkeleton';
import Table from '@/components/Table';
import { LogisticPurchasePerSupplierReport } from '@/types/api/report/logistic-stock';
import { ColumnDef } from '@tanstack/react-table';
const PurchasePerSupplierSkeleton = ({
columns,
icon,
title,
subtitle,
}: {
columns: ColumnDef<LogisticPurchasePerSupplierReport['rows'][0]>[];
icon: React.ReactNode;
title: string;
subtitle: string;
}) => {
return (
<div className='relative size-full'>
<Table
data={[]}
columns={columns}
isLoading={true}
className={{
skeletonCellClassName: 'animate-none w-full h-5 bg-base-content/4',
headerColumnClassName: 'whitespace-nowrap',
containerClassName: 'mb-0 overflow-hidden',
tableWrapperClassName: 'overflow-hidden',
}}
/>
<div className='absolute inset-0 flex items-center justify-center'>
<DataStateSkeleton icon={icon} title={title} description={subtitle} />
</div>
</div>
);
};
export default PurchasePerSupplierSkeleton;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,51 @@
'use client';
import { ReactNode } from 'react';
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';
export type LogisticStockTabActionsSlice = {
// State - actions per tab ID
tabActions: Record<string, ReactNode>;
// Actions
setTabActions: (tabId: string, actions: ReactNode) => void;
clearTabActions: (tabId: string) => void;
clearAllTabActions: () => void;
};
export const useLogisticStockTabStore = create<LogisticStockTabActionsSlice>()(
devtools(
(set) => ({
tabActions: {},
setTabActions: (tabId, actions) =>
set(
(state) => ({
tabActions: {
...state.tabActions,
[tabId]: actions,
},
}),
false,
'setTabActions'
),
clearTabActions: (tabId) =>
set(
(state) => {
const { [tabId]: _, ...rest } = state.tabActions;
return { tabActions: rest };
},
false,
'clearTabActions'
),
clearAllTabActions: () =>
set({ tabActions: {} }, false, 'clearAllTabActions'),
}),
{
name: 'LogisticStockTabStore',
}
)
);