diff --git a/src/app/finance/page.tsx b/src/app/finance/page.tsx index ec78820c..11a67181 100644 --- a/src/app/finance/page.tsx +++ b/src/app/finance/page.tsx @@ -3,12 +3,7 @@ import FinanceTable from '@/components/pages/finance/FinanceTable'; const Finance = () => { - return ( -
-
- -
- ); + return ; }; export default Finance; diff --git a/src/components/pages/finance/FinanceTable.tsx b/src/components/pages/finance/FinanceTable.tsx index f83fa469..a97d60a9 100644 --- a/src/components/pages/finance/FinanceTable.tsx +++ b/src/components/pages/finance/FinanceTable.tsx @@ -1,10 +1,19 @@ -import { useEffect, useMemo, useRef, useState } from 'react'; -import { CellContext } from '@tanstack/react-table'; +'use client'; + +import React, { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from 'react'; +import { CellContext, ColumnDef } from '@tanstack/react-table'; import useSWR from 'swr'; +import { Icon } from '@iconify/react'; import { useFormik } from 'formik'; +import { cn, formatCurrency, formatDate, formatTitleCase } from '@/lib/helper'; import Button from '@/components/Button'; -import Card from '@/components/Card'; import DateInput from '@/components/input/DateInput'; import DebouncedTextInput from '@/components/input/DebouncedTextInput'; import SelectInput, { @@ -12,7 +21,6 @@ import SelectInput, { useSelect, } from '@/components/input/SelectInput'; import Table from '@/components/Table'; -import { formatCurrency, formatDate, formatTitleCase } from '@/lib/helper'; import { useTableFilter } from '@/services/hooks/useTableFilter'; import { Finance } from '@/types/api/finance/finance'; import { @@ -25,115 +33,149 @@ import { FinanceApi } from '@/services/api/finance'; import { isResponseSuccess } from '@/lib/api-helper'; import { BankApi, CustomerApi, SupplierApi } from '@/services/api/master-data'; import { Bank } from '@/types/api/master-data/bank'; -import { useModal } from '@/components/Modal'; +import Modal, { useModal } from '@/components/Modal'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import toast from 'react-hot-toast'; -import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; import RequirePermission from '@/components/helper/RequirePermission'; -import { Icon } from '@iconify/react'; -import RowDropdownOptions from '@/components/table/RowDropdownOptions'; -import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import { useUiStore } from '@/stores/ui/ui.store'; import { FinanceTableFilterSchema, FinanceTableFilterValues, } from './FinanceTableFilter.schema'; +import SelectInputRadio from '@/components/input/SelectInputRadio'; const RowOptionsMenu = ({ - type = 'dropdown', + popoverPosition = 'bottom', props, deleteClickHandler, }: { - type: 'dropdown' | 'collapse'; + popoverPosition: 'bottom' | 'top'; props: CellContext; deleteClickHandler: () => void; }) => { + const popoverId = `finance#${props.row.original.id}`; + const popoverAnchorName = `--anchor-finance#${props.row.original.id}`; + + const closePopover = () => { + const popover = document.getElementById(popoverId) as + | HTMLDivElement + | undefined; + popover?.hidePopover?.(); + }; + return ( - - + - + + - {FINANCE_TRANSACTION_STATUS.includes( - props.row.original.transaction_type - ) && ( - - - - )} + + - {FINANCE_INITIAL_BALANCE_STATUS.includes( - props.row.original.transaction_type - ) && ( - - - - )} + {FINANCE_TRANSACTION_STATUS.includes( + props.row.original.transaction_type + ) && ( + + + + )} - {FINANCE_INJECTION_STATUS.includes( - props.row.original.transaction_type - ) && ( - - - - )} + {FINANCE_INITIAL_BALANCE_STATUS.includes( + props.row.original.transaction_type + ) && ( + + + + )} - - - - + {FINANCE_INJECTION_STATUS.includes( + props.row.original.transaction_type + ) && ( + + + + )} + + + + + + + ); }; @@ -171,6 +213,9 @@ const FinanceTable = () => { }, }); + // ===== FILTER MODAL STATE ===== + const filterModal = useModal(); + // ===== State ===== const deleteModal = useModal(); const [selectedTransactionType, setSelectedTransactionType] = useState< @@ -214,6 +259,18 @@ const FinanceTable = () => { updateFilter('sortBy', values.sort_by); updateFilter('startDate', values.start_date); updateFilter('endDate', values.end_date); + filterModal.closeModal(); + }, + onReset: () => { + updateFilter('search', ''); + resetSearchValue(); + updateFilter('transactionTypes', ''); + updateFilter('bankIds', ''); + updateFilter('customerIds', ''); + updateFilter('supplierIds', ''); + updateFilter('sortBy', ''); + updateFilter('startDate', ''); + updateFilter('endDate', ''); }, }); @@ -266,10 +323,41 @@ const FinanceTable = () => { }); }, [bankOptions, bankRawData]); + // ===== ACTIVE FILTERS COUNT ===== + const activeFiltersCount = useMemo(() => { + let count = 0; + + if (tableFilterState.transactionTypes) count += 1; + if (tableFilterState.bankIds) count += 1; + if (tableFilterState.customerIds) count += 1; + if (tableFilterState.supplierIds) count += 1; + if (tableFilterState.sortBy) count += 1; + if (tableFilterState.startDate) count += 1; + if (tableFilterState.endDate) count += 1; + + return count; + }, [ + tableFilterState.transactionTypes, + tableFilterState.bankIds, + tableFilterState.customerIds, + tableFilterState.supplierIds, + tableFilterState.sortBy, + tableFilterState.startDate, + tableFilterState.endDate, + ]); + + const hasFilters = activeFiltersCount > 0; + // ===== Handler ===== - const searchChangeHandler = (e: React.ChangeEvent) => { - filterFormik.setFieldValue('search', e.target.value); - }; + const searchChangeHandler = useCallback( + (e: React.ChangeEvent) => { + updateFilter('search', e.target.value); + setSearchValue(e.target.value); + setPage(1); + }, + [updateFilter, setSearchValue, setPage] + ); + const transactionTypeChangeHandler = ( val: OptionType | OptionType[] | null ) => { @@ -387,6 +475,11 @@ const FinanceTable = () => { } }; + const handleFilterModalOpen = () => { + filterModal.openModal(); + filterFormik.validateForm(); + }; + const resetFilterHandler = () => { setSelectedTransactionType(null); setSelectedBank(null); @@ -406,6 +499,7 @@ const FinanceTable = () => { updateFilter('startDate', ''); updateFilter('endDate', ''); }; + const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); @@ -417,8 +511,8 @@ const FinanceTable = () => { setIsDeleteLoading(false); }; - const columns = useMemo(() => { - return [ + const columns: ColumnDef[] = useMemo( + () => [ { header: 'ID', accessorKey: 'payment_code', @@ -498,32 +592,17 @@ const FinanceTable = () => { }; return ( - <> - {currentPageSize > 2 && ( - - - - )} - - {currentPageSize <= 2 && ( - - - - )} - + ); }, }, - ]; - }, []); + ], + [] + ); useEffect(() => { return () => { @@ -555,151 +634,258 @@ const FinanceTable = () => { }, [resetSearchValue, dateErrorShown]); return ( -
-
- - - - - - - - - -
- + <> +
+ {/* Header Section */} +
+ {/* Action Buttons */} +
+ + + + + + + + + +
+ + {/* Search and Filter */} +
+ + } + className={{ + wrapper: 'w-full min-w-24 max-w-3xs', + inputWrapper: 'rounded-xl! shadow-button-soft', + input: + 'placeholder:font-semibold placeholder:text-base-content/50', + }} + /> + -
- } - > -
- - - - - - - -
- - - data={isResponseSuccess(finances) ? finances.data : []} - columns={columns} - pageSize={tableFilterState.pageSize} - page={tableFilterState.page} - onPageChange={setPage} - onPageSizeChange={setPageSize} - totalItems={ - isResponseSuccess(finances) ? finances.meta?.total_results : 0 - } - isLoading={isLoading} - /> + + {/* Table Section */} +
+ {isLoading ? ( +
+ +
+ ) : ( + + data={isResponseSuccess(finances) ? finances.data : []} + columns={columns} + pageSize={tableFilterState.pageSize} + page={tableFilterState.page} + totalItems={ + isResponseSuccess(finances) ? finances.meta?.total_results : 0 + } + onPageChange={setPage} + onPageSizeChange={setPageSize} + isLoading={isLoading} + className={{ + containerClassName: 'p-3 mb-0', + headerColumnClassName: 'text-nowrap', + }} + /> + )} +
+
+ + {/* Filter Modal */} + + {/* Modal Header */} +
+
+ +

Filter Data

+
+ +
+
+
+ {}} + closeMenuOnSelect={false} + isClearable + isMulti + className={{ wrapper: 'w-full' }} + /> + + + + + + +
+ + {/* Modal Footer */} +
+ + +
+
+
+ { onClick: confirmationModalDeleteClickHandler, }} /> -
+ ); };