import { DataGridColumnHeader, DataGridProvider, KeenIcon } from '@/components'; import { Toaster } from '@/components/ui/sonner'; import { apiConfig } from '@/config/api.config'; import { ColumnDef } from '@tanstack/react-table'; import React, { createContext, useCallback, useMemo, useState } from 'react'; import { useCallApi } from '@/hooks'; import ListToolbar from '../blocks/ListToolbar'; import { useNavigate } from 'react-router'; import DetailTransaction from '../blocks/DetailTransaction'; import ResendTransaction from '../blocks/ResendTransaction'; import RollbackTransaction from '../blocks/RollbackTransaction'; interface TransactionProps { id: number; name: string; } interface ContextProps { getTransactionLists: ( limit: number, page: number, with_deleted: boolean, order_field: any, order_direction: any, filter: any ) => Promise<{ data: TransactionProps[]; totalCount: number } | undefined>; showDetailDialog: boolean; setShowDetailDialog: React.Dispatch>; showRollbackDialog: boolean; setShowRollbackDialog: React.Dispatch>; selectedTransactionId: number | null; setSelectedTransactionId: React.Dispatch>; } const initialProps: ContextProps = { getTransactionLists: async () => ({ data: [], totalCount: 0 }), showDetailDialog: false, setShowDetailDialog: () => { }, showRollbackDialog: false, setShowRollbackDialog: () => { }, selectedTransactionId: null, setSelectedTransactionId: () => { } }; const ManageTransactionContext = createContext(initialProps); const API_URL = apiConfig.transaction; const TransactionProvider = ({ children }: { children: React.ReactNode }) => { const [showDetailDialog, setShowDetailDialog] = useState(false); const [showRollbackDialog, setShowRollbackDialog] = useState(false); const [selectedTransactionId, setSelectedTransactionId] = useState(null); const [transaction, setTransaction] = useState([]); const { GetData } = useCallApi(); const navigate = useNavigate(); const handleNavigate = (path: string) => { const url = navigate(`${API_URL}/transaction/history/${path}`); }; const columns = useMemo[]>( () => [ { accessorKey: 'code', header: ({ column }) => , enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]' } }, { accessorFn: (row) => { switch (row.kind) { 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'; default: return '_'; } }, accessorKey: 'kind', header: ({ column }) => , enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]' } }, { accessorKey: 'transaction_date', header: ({ column }) => , enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]' }, cell: ({ row }) => { // Memformat tanggal dan waktu dari ISO ke format biasa (DD-MM-YYYY HH:MM:SS) const transactionDate = new Date(row.original.transaction_date); const formattedDateTime = transactionDate.toLocaleString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false // Gunakan format 24 jam }); return formattedDateTime; // Format DD-MM-YYYY HH:MM:SS (menggunakan waktu yang sudah ada) } }, { accessorKey: 'origin_customer.fullname', header: ({ column }) => , enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]' } }, { accessorFn: (row) => { const purchase = row?.purchase?.destination_customer.fullname; const transfer = row?.transfer?.destination_customer.fullname; return purchase ?? transfer ?? "-"; }, id: 'destination_customer.fullname', header: ({ column }) => , enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]', }, }, { accessorFn: (row) => { const purchaseAmount = row?.purchase?.amount; const transferAmount = row?.transfer?.amount; return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(purchaseAmount ?? transferAmount ?? 0); }, id: 'amount', header: ({ column }) => , enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]', }, }, { accessorFn: (row) => { const purchaseAmount = row?.purchase?.fee_amount; const transferAmount = row?.transfer?.fee_amount; return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(purchaseAmount ?? transferAmount ?? 0); }, id: 'feeamount', header: ({ column }) => , enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]', }, }, { accessorKey: 'status', header: ({ column }) => , enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]', }, cell: ({ row }) => { const statusCode = row.original.status; let label = ''; let badgeClass = ''; switch (statusCode) { case 'C': label = 'COMPLETE'; badgeClass = 'bg-green-100 text-green-800'; break; case 'F': label = 'FAILED'; badgeClass = 'bg-red-100 text-red-800'; break; case 'O': label = 'ON PROCESS'; badgeClass = 'bg-blue-100 text-blue-800'; break; default: label = 'PENDING'; badgeClass = 'bg-gray-100 text-gray-800'; break; } return ( {label} ); }, }, { accessorKey: 'description', header: ({ column }) => , enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]' } }, { accessorKey: 'type.name', header: ({ column }) => , enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]' } }, { id: 'actions', header: ({ column }) => , enableSorting: false, enableHiding: false, cell: (data) => { const row = data.row.original; const isVisible = (row.status === 'F' ? true : false || row.status === 'P' ? true : false) && row.status_approve !== 'W' ? true : false; return (
); }, meta: { headerClassName: 'w-[100px]', cellClassName: 'text-center' } } ], []); const getTransactionLists = async (page: number, limit: number, sorting: any, filter: any) => { try { const today = new Date(); const firstDayOfMonth = new Date(today.getFullYear(), today.getMonth(), 1); let startdate = firstDayOfMonth.toISOString().split('T')[0]; let enddate = today.toISOString().split('T')[0]; let transactioncode = ''; let type = ''; // ✅ Declare formattedFilter early const formattedFilter: any = { "Transactions.transaction_date": { from: `${startdate} 00:00:00`, to: `${enddate} 23:59:59` } }; if (Array.isArray(filter)) { let searchType = ''; let codeValue = ''; // Ambil code dan searchtype dulu filter.forEach((f: any) => { if (f.id === 'code' && f.value) { codeValue = f.value; } if (f.id === 'searchtype' && f.value) { searchType = f.value; } if (f.id === 'transaction_date' && f.value?.from && f.value?.to) { startdate = f.value.from; enddate = f.value.to; formattedFilter["Transactions.transaction_date"] = { from: `${startdate} 00:00:00`, to: `${enddate} 23:59:59` }; } if (f.id === 'kind' && f.value) { type = f.value; } }); // Terapkan berdasarkan searchtype + code if (searchType && codeValue) { if (searchType === "msisdn") { formattedFilter["origin_customer.msisdn"] = { like: `%${codeValue}%` }; } else if (searchType === "fullname") { formattedFilter["origin_customer.fullname"] = { like: `%${codeValue}%` }; } else if (searchType === "trxid") { formattedFilter["Transactions.code"] = { like: `%${codeValue}%` }; } } } if (type) { formattedFilter["Transactions.kind"] = type; } const response = await GetData(`${API_URL}/transaction/history`, { limit, page: page + 1, with_deleted: false, order_field: "Transactions.created_at", order_direction: 'DESC', filter: JSON.stringify(formattedFilter) }); if (!response || !response.data) { console.warn('No data received:', response); return { data: [], totalCount: 0 }; } setTransaction(response.data.list); return { data: response.data.list, totalCount: response.data.total_count }; } catch (error) { console.error('Error fetching transaction', error); return { data: [], totalCount: 0 }; } }; return ( } layout={{ card: true }} sorting={[{ id: 'id', desc: false }]} serverSide={true} onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => getTransactionLists(pageIndex, pageSize, sorting, columnFilters) } > console.log('Retry Transaction closed')} selectedTransactionForResend={null} /> {children} ); }; export { TransactionProvider, ManageTransactionContext }; export type { TransactionProps };