From 96ef6f849643fa6d7a8bf36b9e23d51fcbccff56 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Thu, 5 Mar 2026 11:40:32 +0700 Subject: [PATCH] refactor(FE): Refactor tab actions into a memoized component --- .../report/expense/tab/ReportExpenseTab.tsx | 255 ++++++++++-------- 1 file changed, 139 insertions(+), 116 deletions(-) diff --git a/src/components/pages/report/expense/tab/ReportExpenseTab.tsx b/src/components/pages/report/expense/tab/ReportExpenseTab.tsx index 971536c5..03c35958 100644 --- a/src/components/pages/report/expense/tab/ReportExpenseTab.tsx +++ b/src/components/pages/report/expense/tab/ReportExpenseTab.tsx @@ -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 { Icon } from '@iconify/react'; import Button from '@/components/Button'; @@ -68,37 +74,10 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => { const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(10); + const handleFilterModalOpenRef = useRef(() => {}); + const filterModal = useModal(); - // ===== OPTIONS ===== - const { - setInputValue: setLocationInputValue, - options: locationOptions, - isLoadingOptions: isLoadingLocations, - loadMore: loadMoreLocations, - } = useSelect(LocationApi.basePath, 'id', 'name', 'search'); - - const { - setInputValue: setSupplierInputValue, - options: supplierOptions, - isLoadingOptions: isLoadingSuppliers, - loadMore: loadMoreSuppliers, - } = useSelect(SupplierApi.basePath, 'id', 'name', 'search'); - - const { - setInputValue: setKandangInputValue, - options: kandangOptions, - isLoadingOptions: isLoadingKandangs, - loadMore: loadMoreKandangs, - } = useSelect(KandangApi.basePath, 'id', 'name', 'search'); - - const { - setInputValue: setNonstockInputValue, - options: nonstockOptions, - isLoadingOptions: isLoadingNonstocks, - loadMore: loadMoreNonstocks, - } = useSelect(NonstockApi.basePath, 'id', 'name', 'search'); - const categoryOptions = useMemo( () => [ { 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(LocationApi.basePath, 'id', 'name', 'search'); + + const { + setInputValue: setSupplierInputValue, + options: supplierOptions, + isLoadingOptions: isLoadingSuppliers, + loadMore: loadMoreSuppliers, + } = useSelect(SupplierApi.basePath, 'id', 'name', 'search'); + + const { + setInputValue: setKandangInputValue, + options: kandangOptions, + isLoadingOptions: isLoadingKandangs, + loadMore: loadMoreKandangs, + } = useSelect( + 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(NonstockApi.basePath, 'id', 'name', 'search'); + // ===== FILTER VALUES ===== const locationValue = useMemo( () => formik.values.location_id, @@ -268,13 +289,7 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => { return; } - const pdfParams = { - location_name: locationValue?.label, - supplier_name: supplierValue?.label, - realization_date: formik.values.realization_date || undefined, - }; - - await generateReportExpensePDF(allData, pdfParams); + await generateReportExpensePDF(allData); toast.success('PDF berhasil dibuat dan diunduh.'); } catch { @@ -282,98 +297,105 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => { } finally { setIsPdfExportLoading(false); } - }, [ - reportExpenseExport, - locationValue, - supplierValue, - kandangValue, - nonstockValue, - categoryValue, - formik.values.realization_date, - ]); + }, [reportExpenseExport]); - // ===== 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, -
- filterModal.openModal()} - variant='outline' - className='px-3 py-2.5' - /> - - { + setTabActions( + tabId, +
+ 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' + /> + + +
+ + + Export + +
+ + +
+ + } > -
- + + + +
+ ); + }, [setTabActions]); - Export + useEffect(() => { + return () => { + clearTabActions(tabId); + }; + }, [clearTabActions]); -
- - -
- - } - > - - - -
- ); + return null; + }; }, [ tabId, - formik.values, + filterParams, isAnyExportLoading, handleExportExcel, handleExportPDF, - setTabActions, + isExcelExportLoading, + isPdfExportLoading, ]); - useEffect(() => { - return () => { - clearTabActions(tabId); - }; - }, [tabId, clearTabActions]); + const TabActionsElement = useMemo(() => , [TabActions]); // ===== TABLE COLUMNS DEFINITION ===== const columns = useMemo((): ColumnDef[] => { @@ -505,6 +527,7 @@ const ReportExpenseTab = ({ tabId }: ReportExpenseTabProps) => { return ( <> + {TabActionsElement}
{!isSubmitted ? (