diff --git a/src/pages/dashboards/home/blocks/TransactionValue.tsx b/src/pages/dashboards/home/blocks/TransactionValue.tsx index 97f1fc8..d88151e 100644 --- a/src/pages/dashboards/home/blocks/TransactionValue.tsx +++ b/src/pages/dashboards/home/blocks/TransactionValue.tsx @@ -79,29 +79,29 @@ const TransactionValue = ({ startdate, enddate }: Props) => { case "M": type = "Withdrawal Agent"; break; - case 'O': - type = 'TOP UP AGENT'; + case 'O': + type = 'Top Up Agent'; break; - case 'S': - type = 'TRANSFER P24'; + case 'S': + type = 'Transfer P24'; break; - case 'I': - type = 'WIJTDRAW MERCHANT'; + case 'I': + type = 'Withdraw Merchant'; break; - case 'D': - type = 'DONATION'; + case 'D': + type = 'Donation'; break; - case 'F': - type = 'FEE'; + case 'F': + type = 'Fee'; break; - case 'V': - type = 'REVERSAL'; + case 'V': + type = 'Reversal'; break; - case 'C': - type = 'CASHBACK CASH'; + case 'C': + type = 'Cashback Cash'; break; - case 'H': - type = 'CASHBACK POINT'; + case 'H': + type = 'Cashback Point'; break; default: type = "Unknown"; @@ -136,7 +136,8 @@ const TransactionValue = ({ startdate, enddate }: Props) => { > - {new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(item.value)}{item.unit} + + {new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(item.value)}{item.unit} ))} diff --git a/src/pages/wallet/wallet-statement/blocks/FilterSection.tsx b/src/pages/wallet/wallet-statement/blocks/FilterSection.tsx new file mode 100644 index 0000000..e2b4084 --- /dev/null +++ b/src/pages/wallet/wallet-statement/blocks/FilterSection.tsx @@ -0,0 +1,219 @@ +import React, { useCallback, useState, useEffect } from 'react'; +import { Button } from '@/components/ui/button'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; +import { DefaultTooltip, KeenIcon } from '@/components'; +import { toAbsoluteUrl } from '@/utils'; +import { useCallApi } from '@/hooks'; +import { apiConfig } from '@/config/api.config'; + +interface TransferType { + id: string; + name: string; +} + +interface FilterSectionProps { + filters: any; + setFilters: (filters: any) => void; + transaction: any[]; + categoryMap: Record; +} + +const FilterSection: React.FC = ({ + filters, + setFilters, + transaction, + categoryMap +}) => { + const { GetData } = useCallApi(); + const [dateRange, setDateRange] = useState({ + from: new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000).toLocaleDateString('sv-SE'), + to: new Date().toLocaleDateString('sv-SE') + }); + const [selectedTransferType, setSelectedTransferType] = useState(null); + const [transferType, setTransferType] = useState([]); + const [selectedCategory, setSelectedCategory] = useState(null); + const [category, setCategory] = useState([]); + const [searchValue, setSearchValue] = useState(''); + + const fetchTransferType = useCallback(async () => { + try { + const response = await GetData(`${apiConfig.service_transaction}/transactiontype/list`, { + limit: 100, + page: 1, + with_deleted: false, + order_field: 'created_at', + order_direction: 'ASC' + }); + + const sortedData = (response?.data?.list || []) + .sort((a: any, b: any) => a.name.localeCompare(b.name)); + setTransferType(sortedData); + } catch (error) { + console.error('Error fetching transfer types', error); + } +}, [GetData]); + + useEffect(() => { + fetchTransferType(); + }, [fetchTransferType]); + + const categories = Array.from( + new Set( + transaction.map((tx) => categoryMap[tx.category] || '_').filter((cat) => !!cat && cat !== '_') + ) + ); + + useEffect(() => { + setCategory(categories); +}, [transaction, categoryMap]); + + const reverseCategoryMap = Object.fromEntries( + Object.entries(categoryMap).map(([key, value]) => [value, key]) + ); + + const handleTransferTypeChange = (value: string) => { + setSelectedTransferType(value === 'all' ? null : value); + }; + + const handleCategoryChange = (value: string) => { + setSelectedCategory(value === '' ? null : value); + }; + + const handleClearAllFilters = () => { + setDateRange({ + from: new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000).toLocaleDateString('sv-SE'), + to: new Date().toLocaleDateString('sv-SE') + }); + setSelectedTransferType(null); + setSelectedCategory(null); + setSearchValue(''); + setFilters({}); + }; + + const handleApplyFilters = () => { + const appliedFilters: any = {}; + + if (dateRange.from && dateRange.to) { + const fromDate = new Date(`${dateRange.from}T00:00:00Z`); + const toDate = new Date(`${dateRange.to}T23:59:59Z`); + appliedFilters.date = { + from: fromDate.toISOString(), + to: toDate.toISOString() + }; + } + + if (selectedTransferType) { + appliedFilters.id_transaction_type = selectedTransferType; + } + + if (selectedCategory) { + appliedFilters.category = selectedCategory; + } + + if (searchValue) { + appliedFilters.transaction_code = searchValue; + } + + setFilters(appliedFilters); + }; + + return ( + + + + From + setDateRange({ ...dateRange, from: e.target.value })} + /> + + + + To + setDateRange({ ...dateRange, to: e.target.value })} + /> + + + + + + + + + Select Transaction + {transferType.map((transfer) => ( + + {transfer.name} + + ))} + + + + + + + + + + + {category.length === 0 ? ( + No data + ) : ( + category.map((cat) => ( + + {cat} + + )) + )} + + + + + + + setSearchValue(e.target.value)} + /> + + + + + + + + + + Filter Data + + + + + + + + + + + + + + + + ); +}; + +export default FilterSection; \ No newline at end of file diff --git a/src/pages/wallet/wallet-statement/blocks/ListToolbar.tsx b/src/pages/wallet/wallet-statement/blocks/ListToolbar.tsx index 0a77d7c..f9a21b0 100644 --- a/src/pages/wallet/wallet-statement/blocks/ListToolbar.tsx +++ b/src/pages/wallet/wallet-statement/blocks/ListToolbar.tsx @@ -111,8 +111,8 @@ const ListToolbar = ({ }; useEffect(() => { - table.setPageIndex(0); // reset ke halaman pertama kalau mau - reload(); // ini yang akan trigger data fetch ulang + table.setPageIndex(0); + reload(); }, [filters]); return ( @@ -171,7 +171,7 @@ const ListToolbar = ({ - + Filter Data diff --git a/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx b/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx index 107100d..de37075 100644 --- a/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx +++ b/src/pages/wallet/wallet-statement/blocks/ShowDetailDialog.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import React, { createContext, useCallback, useEffect, useState } from 'react'; import { Dialog, DialogBody, @@ -10,63 +10,26 @@ import { import { useCallApi } from '@/hooks'; import { apiConfig } from '@/config/api.config'; import { DataGridColumnHeader, DataGridProvider } from '@/components'; -import { Button } from '@/components/ui/button'; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue -} from '@/components/ui/select'; -import { DefaultTooltip, KeenIcon } from '@/components'; import { useManageStatementContext } from '../hooks/useManageWalletStatementContext'; +import { Toaster } from 'sonner'; +import { format } from 'date-fns'; +import FilterSection from './FilterSection'; -interface TransferType { - id: string; - name: string; +interface ContextProps { + doExportData: (sorting: any, filter: any) => Promise; } -const formatDate = (date: Date) => date.toLocaleDateString('sv-SE'); -const getDefaultDateRange = () => { - const today = new Date(); - const sevenDaysAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000); - return { - from: formatDate(sevenDaysAgo), - to: formatDate(today) - }; +const initialProps: ContextProps = { + doExportData: async () => ({ data: [], totalCount: 0 }) }; +export const showDetailWalletContext = createContext(initialProps); + const ShowDetailWalletDialog = () => { - const { GetData } = useCallApi(); - + const { GetData, GetExportData } = useCallApi(); const { showDetailDialog, setShowDetailDialog, selectedWallet } = useManageStatementContext(); - const [dateRange, setDateRange] = useState(getDefaultDateRange()); - const [selectedTransferType, setSelectedTransferType] = useState(null); - const [transferType, setTransferType] = useState([]); - const [selectedCategory, setSelectedCategory] = useState(null); - const [searchValue, setSearchValue] = useState(''); - const [category, setCategory] = useState([]); - const [transaction, setTransaction] = useState([]); const [filters, setFilters] = useState({}); - - const fetchTransferType = useCallback(async () => { - try { - const response = await GetData(`${apiConfig.service_transaction}/transactiontype/list`, { - limit: 100, - page: 1, - with_deleted: false, - order_field: 'created_at', - order_direction: 'ASC' - }); - (response?.data?.list || []).sort((a: any, b: any) => a.name.localeCompare(b.name)); - } catch (error) { - console.error('Error fetching transfer types', error); - } - }, [GetData]); - - useEffect(() => { - fetchTransferType(); - }, [fetchTransferType]); + const [transaction, setTransaction] = useState([]); const categoryMap: Record = { T: 'TRANSFER', @@ -90,65 +53,6 @@ const ShowDetailWalletDialog = () => { H: 'CASHBACK POINT' }; - useEffect(() => { - const uniqueCategories = Array.from( - new Set( - transaction - .map((tx) => categoryMap[tx.category] || '_') - .filter((cat) => !!cat && cat !== '_') - ) - ); - - setCategory(uniqueCategories); - }, [transaction]); - - const reverseCategoryMap = Object.fromEntries( - Object.entries(categoryMap).map(([key, value]) => [value, key]) - ); - - const handleTransferTypeChange = (value: string) => { - setSelectedTransferType(value === 'all' ? null : value); - }; - - const handleCategoryChange = (value: string) => { - setSelectedCategory(value === '' ? null : value); - }; - - const handleClearAllFilters = () => { - setDateRange(getDefaultDateRange()); - setSelectedTransferType(null); - setSelectedCategory(null); - setSearchValue(''); - setFilters({}); - }; - - const handleApplyFilters = () => { - const appliedFilters: any = {}; - - if (dateRange.from && dateRange.to) { - const fromDate = new Date(`${dateRange.from}T00:00:00Z`); - const toDate = new Date(`${dateRange.to}T23:59:59Z`); - appliedFilters.date = { - from: fromDate.toISOString(), - to: toDate.toISOString() - }; - } - - if (selectedTransferType) { - appliedFilters.transaction_type_id = selectedTransferType; - } - - if (selectedCategory) { - appliedFilters.category = selectedCategory; - } - - if (searchValue) { - appliedFilters.transaction_code = searchValue; - } - - setFilters(appliedFilters); - }; - const columns = [ { accessorKey: 'transaction_code', @@ -188,7 +92,7 @@ const ShowDetailWalletDialog = () => { { accessorKey: 'amount', header: ({ column }: any) => , - enableSorting: false, + enableSorting: true, cell: (info: any) => info.getValue()?.toFixed(2), meta: { headerClassName: 'min-w-[100px]' } }, @@ -200,57 +104,12 @@ const ShowDetailWalletDialog = () => { meta: { headerClassName: 'min-w-[100px]' } }, { - accessorFn: (row: any) => { - switch (row.category) { - case 'T': - return 'TRANSFER'; - case 'P': - return 'PURCHASE'; - case 'W': - return 'WITHDRAW'; - case 'U': - return 'TOP UP'; - case 'R': - return 'RETURN'; - case 'N': - return 'TOP UP PARTNER'; - case 'E': - return 'REWARD'; - case 'L': - return 'PURCHASE LOJA'; - case 'B': - return 'TOP UP P24'; - case 'A': - return 'TRANSFER AGENT'; - case 'M': - return 'WITHDRAWAL AGENT'; - case 'O': - return 'TOP UP AGENT'; - case 'S': - return 'TRANSFER P24'; - case 'I': - return 'WIJTDRAW MERCHANT'; - case 'D': - return 'DONATION'; - case 'F': - return 'FEE'; - case 'V': - return 'REVERSAL'; - case 'C': - return 'CASHBACK CASH'; - case 'H': - return 'CASHBACK POINT'; - default: - return '_'; - } - }, + accessorFn: (row: any) => categoryMap[row.category] || '_', accessorKey: 'category', header: ({ column }: any) => , enableSorting: false, enableHiding: false, - meta: { - headerClassName: 'w-[250px]' - } + meta: { headerClassName: 'w-[250px]' } }, { accessorKey: 'date', @@ -294,14 +153,12 @@ const ShowDetailWalletDialog = () => { limit, page: page + 1, with_deleted: false, - order_field: 'created_at', - order_direction: 'DESC', + order_field: sorting?.[0]?.id ?? 'amount', + order_direction: sorting?.[0]?.desc ? 'ASC' : 'DESC', filter: JSON.stringify(filters) } ); - // console.log(response); - if (!response || !response.data) { console.warn('No data received:', response); return { data: [], totalCount: 0 }; @@ -317,112 +174,85 @@ const ShowDetailWalletDialog = () => { [GetData, filters, selectedWallet] ); + const doExportData = async (sorting: any, filter: any) => { + const user = localStorage.getItem( + `${import.meta.env.VITE_APP_NAME}-auth-v${import.meta.env.VITE_APP_VERSION}` + ); + + const parsedUser = user ? JSON.parse(user) : null; + sorting = sorting.length === 0 ? [{ id: 'created_at', desc: false }] : sorting; + filter = filter && filter.length > 0 ? filter : []; + + let dataFilter: any = {}; + + if (filter && filter.length > 0) { + filter.forEach((f: any) => { + if (f.id === 'username') { + dataFilter['username'] = { like: f.value }; + } else if (f.id === 'created_at') { + dataFilter['created_at'] = f.value; + } + }); + } + + if (!dataFilter['created_at']) { + const defaultFrom = new Date(new Date().setMonth(new Date().getMonth() - 1)); + const defaultTo = new Date(); + + dataFilter['created_at'] = { + from: `${format(defaultFrom, 'yyyy-MM-dd')} 00:00:00`, + to: `${format(defaultTo, 'yyyy-MM-dd')} 23:59:59` + }; + } + + let param = { + order_field: sorting[0].id || 'created_at', + order_direction: sorting[0].desc ? 'DESC' : 'ASC', + with_deleted: false, + filter: JSON.stringify(dataFilter), + token: parsedUser?.access_token + }; + + let url = `${apiConfig.service_wallet}/dashboard/balance/list-balance-download/${selectedWallet?.ID}`; + + GetExportData(url, param, 'user_activity_export_'); + }; + return ( - - - - Details Wallet Statement - - + + + + + + Details Wallet Statement + + - - - - - From - setDateRange({ ...dateRange, from: e.target.value })} - /> - - - - To - setDateRange({ ...dateRange, to: e.target.value })} - /> - - - - - - - - - Select Transaction - {transferType.map((transfer) => ( - - {transfer.name} - - ))} - - - - - - - - - - - {category.length === 0 ? ( - No data - ) : ( - category.map((cat) => ( - - {cat} - - )) - )} - - - - - - - setSearchValue(e.target.value)} - /> - - - - - - - - - - Filter Data - - - - - - - getTransactionLists(pageIndex, pageSize, sorting, columnFilters) - } + + - - - - + + + + getTransactionLists(pageIndex, pageSize, sorting, columnFilters) + } + /> + + + + + ); }; diff --git a/src/pages/wallet/wallet-statement/hooks/ManageWalletStatementContext.tsx b/src/pages/wallet/wallet-statement/hooks/ManageWalletStatementContext.tsx index 42fea90..c461931 100644 --- a/src/pages/wallet/wallet-statement/hooks/ManageWalletStatementContext.tsx +++ b/src/pages/wallet/wallet-statement/hooks/ManageWalletStatementContext.tsx @@ -108,7 +108,7 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } accessorKey: 'amount', header: ({ column }) => , cell: ({ row }) => formatNumber(row.original.amount), - enableSorting: false, + enableSorting: true, enableHiding: false, meta: { headerClassName: 'w-[200px]' @@ -242,7 +242,7 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } const getWalletLists = async (page: number, limit: number, sorting: any, filter: any) => { try { - const sortField = sorting.length > 0 ? sorting[0].id : 'created_at'; + const sortField = sorting.length > 0 ? sorting[0].id : 'amount'; const sortDirection = sorting.length > 0 ? (sorting[0].desc ? 'ASC' : 'DESC') : 'DESC'; let filterParams: any = {}; @@ -383,10 +383,11 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } pagination={{ size: 10 }} toolbar={} layout={{ card: true }} + sorting={[{ id: 'amount', desc: false}]} serverSide={true} onFetchData={ ({ pageIndex, pageSize, sorting }) => - getWalletLists(pageIndex, pageSize, sorting, filters) // gunakan filters dari state, bukan columnFilters + getWalletLists(pageIndex, pageSize, sorting, filters) } > {children}