refactor(FE): Refactor tab actions to use memoized components

This commit is contained in:
rstubryan
2026-03-05 11:59:27 +07:00
parent a7951b6c28
commit 2de6636bbf
3 changed files with 306 additions and 254 deletions
@@ -1,6 +1,12 @@
'use client';
import React, { useState, useCallback, useEffect, useMemo } from 'react';
import React, {
useState,
useCallback,
useEffect,
useMemo,
useRef,
} from 'react';
import useSWR from 'swr';
import { generateProductionResultExcel } from '../export/ProductionResultExportXLSX';
import toast from 'react-hot-toast';
@@ -66,6 +72,8 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10);
const handleFilterModalOpenRef = useRef(() => {});
const filterModal = useModal();
// ===== TABLE COLUMNS =====
@@ -242,6 +250,11 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
},
});
handleFilterModalOpenRef.current = () => {
filterModal.openModal();
formik.validateForm();
};
// ===== OPTIONS =====
const {
setInputValue: setAreaInputValue,
@@ -519,91 +532,108 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
setIsPdfExportLoading(false);
}, [filterParams]);
// ===== REGISTER TAB ACTIONS TO STORE =====
const setTabActions = useTabActionsStore((state) => state.setTabActions);
const clearTabActions = useTabActionsStore((state) => state.clearTabActions);
// ===== TAB ACTIONS COMPONENT =====
const TabActions = useMemo(() => {
return function TabActionsComponent() {
const setTabActions = useTabActionsStore((state) => state.setTabActions);
const clearTabActions = useTabActionsStore(
(state) => state.clearTabActions
);
useEffect(() => {
setTabActions(
tabId,
<div className='flex flex-row gap-3'>
<ButtonFilter
values={filterParams}
onClick={() => filterModal.openModal()}
variant='outline'
className='px-3 py-2.5'
/>
<Dropdown
align='end'
direction='bottom'
className={{
content:
'mt-1 rounded-xl border border-base-content/5 shadow-sm overflow-hidden',
}}
trigger={
<Button
useEffect(() => {
setTabActions(
tabId,
<div className='flex flex-row gap-3'>
<ButtonFilter
values={filterParams}
onClick={() => handleFilterModalOpenRef.current()}
variant='outline'
color='none'
isLoading={isAnyExportLoading}
className='px-3 py-2.5 text-sm text-base-content/50 border border-base-content/10 rounded-xl shadow-button-soft'
className='px-3 py-2.5'
/>
<Dropdown
align='end'
direction='bottom'
className={{
content:
'mt-1 rounded-xl border border-base-content/5 shadow-sm overflow-hidden',
}}
trigger={
<Button
variant='outline'
color='none'
isLoading={isAnyExportLoading}
className='px-3 py-2.5 text-sm text-base-content/50 border border-base-content/10 rounded-xl shadow-button-soft'
>
<div className='flex flex-row items-center gap-1.5'>
<Icon
icon='heroicons:cloud-arrow-down'
width={20}
height={20}
/>
<span>Export</span>
<div className='w-px self-stretch bg-base-content/10' />
<Icon
icon='heroicons:chevron-down'
width={14}
height={14}
/>
</div>
</Button>
}
>
<div className='flex flex-row items-center gap-1.5'>
<Icon
icon='heroicons:cloud-arrow-down'
width={20}
height={20}
/>
<Button
variant='ghost'
color='none'
onClick={exportToExcelHandler}
isLoading={isExcelExportLoading}
className='w-full p-3 justify-start text-sm text-base-content/50 font-semibold text-nowrap'
>
<Icon icon='heroicons:table-cells' width={20} height={20} />
Export to Excel
</Button>
<Button
variant='ghost'
color='none'
onClick={exportToPdfHandler}
isLoading={isPdfExportLoading}
className='w-full p-3 justify-start text-sm text-base-content/50 font-semibold text-nowrap'
>
<Icon icon='heroicons:document' width={20} height={20} />
Export to PDF
</Button>
</Dropdown>
</div>
);
}, [setTabActions]);
<span>Export</span>
useEffect(() => {
return () => {
clearTabActions(tabId);
};
}, [clearTabActions]);
<div className='w-px self-stretch bg-base-content/10' />
<Icon icon='heroicons:chevron-down' width={14} height={14} />
</div>
</Button>
}
>
<Button
variant='ghost'
color='none'
onClick={exportToExcelHandler}
isLoading={isExcelExportLoading}
className='w-full p-3 justify-start text-sm text-base-content/50 font-semibold text-nowrap'
>
<Icon icon='heroicons:table-cells' width={20} height={20} />
Export to Excel
</Button>
<Button
variant='ghost'
color='none'
onClick={exportToPdfHandler}
isLoading={isPdfExportLoading}
className='w-full p-3 justify-start text-sm text-base-content/50 font-semibold text-nowrap'
>
<Icon icon='heroicons:document' width={20} height={20} />
Export to PDF
</Button>
</Dropdown>
</div>
);
return null;
};
}, [
tabId,
filterParams,
isAnyExportLoading,
exportToExcelHandler,
exportToPdfHandler,
setTabActions,
isExcelExportLoading,
isPdfExportLoading,
]);
useEffect(() => {
return () => {
clearTabActions(tabId);
};
}, [tabId, clearTabActions]);
// Render the TabActions component
const TabActionsElement = useMemo(() => <TabActions />, [TabActions]);
return (
<>
{TabActionsElement}
<div className='w-full p-0 sm:p-3 flex flex-col gap-3'>
{!isSubmitted ? (
<ProductionResultSkeleton