refactor(FE): Refactor tab actions into a memoized component

This commit is contained in:
rstubryan
2026-03-05 11:40:32 +07:00
parent 94ab48d3f6
commit 96ef6f8496
@@ -1,6 +1,12 @@
'use client'; 'use client';
import React, { useState, useCallback, useEffect, useMemo } from 'react'; import React, {
useState,
useCallback,
useEffect,
useMemo,
useRef,
} from 'react';
import useSWR from 'swr'; import useSWR from 'swr';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import Button from '@/components/Button'; import Button from '@/components/Button';
@@ -68,37 +74,10 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => {
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(10); const [pageSize, setPageSize] = useState(10);
const handleFilterModalOpenRef = useRef(() => {});
const filterModal = useModal(); const filterModal = useModal();
// ===== OPTIONS =====
const {
setInputValue: setLocationInputValue,
options: locationOptions,
isLoadingOptions: isLoadingLocations,
loadMore: loadMoreLocations,
} = useSelect<Kandang>(LocationApi.basePath, 'id', 'name', 'search');
const {
setInputValue: setSupplierInputValue,
options: supplierOptions,
isLoadingOptions: isLoadingSuppliers,
loadMore: loadMoreSuppliers,
} = useSelect<Supplier>(SupplierApi.basePath, 'id', 'name', 'search');
const {
setInputValue: setKandangInputValue,
options: kandangOptions,
isLoadingOptions: isLoadingKandangs,
loadMore: loadMoreKandangs,
} = useSelect<Kandang>(KandangApi.basePath, 'id', 'name', 'search');
const {
setInputValue: setNonstockInputValue,
options: nonstockOptions,
isLoadingOptions: isLoadingNonstocks,
loadMore: loadMoreNonstocks,
} = useSelect<Nonstock>(NonstockApi.basePath, 'id', 'name', 'search');
const categoryOptions = useMemo( const categoryOptions = useMemo(
() => [ () => [
{ value: 'BOP', label: 'BOP' }, { value: 'BOP', label: 'BOP' },
@@ -149,6 +128,48 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => {
}, },
}); });
handleFilterModalOpenRef.current = () => {
filterModal.openModal();
formik.validateForm();
};
// ===== OPTIONS =====
const {
setInputValue: setLocationInputValue,
options: locationOptions,
isLoadingOptions: isLoadingLocations,
loadMore: loadMoreLocations,
} = useSelect<Kandang>(LocationApi.basePath, 'id', 'name', 'search');
const {
setInputValue: setSupplierInputValue,
options: supplierOptions,
isLoadingOptions: isLoadingSuppliers,
loadMore: loadMoreSuppliers,
} = useSelect<Supplier>(SupplierApi.basePath, 'id', 'name', 'search');
const {
setInputValue: setKandangInputValue,
options: kandangOptions,
isLoadingOptions: isLoadingKandangs,
loadMore: loadMoreKandangs,
} = useSelect<Kandang>(
KandangApi.basePath,
'id',
'name',
'search',
formik.values.location_id?.value
? { location_id: String(formik.values.location_id.value) }
: undefined
);
const {
setInputValue: setNonstockInputValue,
options: nonstockOptions,
isLoadingOptions: isLoadingNonstocks,
loadMore: loadMoreNonstocks,
} = useSelect<Nonstock>(NonstockApi.basePath, 'id', 'name', 'search');
// ===== FILTER VALUES ===== // ===== FILTER VALUES =====
const locationValue = useMemo( const locationValue = useMemo(
() => formik.values.location_id, () => formik.values.location_id,
@@ -268,13 +289,7 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => {
return; return;
} }
const pdfParams = { await generateReportExpensePDF(allData);
location_name: locationValue?.label,
supplier_name: supplierValue?.label,
realization_date: formik.values.realization_date || undefined,
};
await generateReportExpensePDF(allData, pdfParams);
toast.success('PDF berhasil dibuat dan diunduh.'); toast.success('PDF berhasil dibuat dan diunduh.');
} catch { } catch {
@@ -282,27 +297,23 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => {
} finally { } finally {
setIsPdfExportLoading(false); setIsPdfExportLoading(false);
} }
}, [ }, [reportExpenseExport]);
reportExpenseExport,
locationValue,
supplierValue,
kandangValue,
nonstockValue,
categoryValue,
formik.values.realization_date,
]);
// ===== REGISTER TAB ACTIONS TO STORE ===== // ===== TAB ACTIONS COMPONENT =====
const TabActions = useMemo(() => {
return function TabActionsComponent() {
const setTabActions = useTabActionsStore((state) => state.setTabActions); const setTabActions = useTabActionsStore((state) => state.setTabActions);
const clearTabActions = useTabActionsStore((state) => state.clearTabActions); const clearTabActions = useTabActionsStore(
(state) => state.clearTabActions
);
useEffect(() => { useEffect(() => {
setTabActions( setTabActions(
tabId, tabId,
<div className='flex flex-row gap-3'> <div className='flex flex-row gap-3'>
<ButtonFilter <ButtonFilter
values={formik.values} values={filterParams}
onClick={() => filterModal.openModal()} onClick={() => handleFilterModalOpenRef.current()}
variant='outline' variant='outline'
className='px-3 py-2.5' className='px-3 py-2.5'
/> />
@@ -332,7 +343,11 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => {
<div className='w-px self-stretch bg-base-content/10' /> <div className='w-px self-stretch bg-base-content/10' />
<Icon icon='heroicons:chevron-down' width={14} height={14} /> <Icon
icon='heroicons:chevron-down'
width={14}
height={14}
/>
</div> </div>
</Button> </Button>
} }
@@ -360,20 +375,27 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => {
</Dropdown> </Dropdown>
</div> </div>
); );
}, [ }, [setTabActions]);
tabId,
formik.values,
isAnyExportLoading,
handleExportExcel,
handleExportPDF,
setTabActions,
]);
useEffect(() => { useEffect(() => {
return () => { return () => {
clearTabActions(tabId); clearTabActions(tabId);
}; };
}, [tabId, clearTabActions]); }, [clearTabActions]);
return null;
};
}, [
tabId,
filterParams,
isAnyExportLoading,
handleExportExcel,
handleExportPDF,
isExcelExportLoading,
isPdfExportLoading,
]);
const TabActionsElement = useMemo(() => <TabActions />, [TabActions]);
// ===== TABLE COLUMNS DEFINITION ===== // ===== TABLE COLUMNS DEFINITION =====
const columns = useMemo((): ColumnDef<ReportExpense>[] => { const columns = useMemo((): ColumnDef<ReportExpense>[] => {
@@ -505,6 +527,7 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => {
return ( return (
<> <>
{TabActionsElement}
<div className='w-full p-0 sm:p-3 flex flex-col gap-3'> <div className='w-full p-0 sm:p-3 flex flex-col gap-3'>
{!isSubmitted ? ( {!isSubmitted ? (
<ReportExpenseSkeleton <ReportExpenseSkeleton