diff --git a/src/pages/disbursement/history-transaction/blocks/DetailTransaction.tsx b/src/pages/disbursement/history-transaction/blocks/DetailTransaction.tsx index 28df134..dfa33ec 100644 --- a/src/pages/disbursement/history-transaction/blocks/DetailTransaction.tsx +++ b/src/pages/disbursement/history-transaction/blocks/DetailTransaction.tsx @@ -1,7 +1,10 @@ +// disbursement/history-transaction/blocks/DetailTransaction.tsx +import { KeenIcon } from '@/components'; import { useTransactionContext } from '../hooks/useTransactionContext'; import { useCallApi } from '@/hooks'; import { apiConfig } from '@/config/api.config'; import { useEffect, useState } from 'react'; +import moment from 'moment'; import { Dialog, DialogBody, @@ -10,10 +13,11 @@ import { DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import TransactionLogViewer from './DetailTransactionLog'; const API_URL = apiConfig.service_disbursement; -type StatusCode = 'W' | 'P' | 'F' | 'D' | 'Y'; +type StatusCode = 'W' | 'O' | 'F' | 'D'; interface StatusInfo { label: string; @@ -22,11 +26,10 @@ interface StatusInfo { } const statusMap: Record = { - W: { label: 'Waiting', bg: 'bg-yellow-100', text: 'text-yellow-600' }, - P: { label: 'Pending', bg: 'bg-blue-100', text: 'text-blue-600' }, + W: { label: 'Waiting Schedule', bg: 'bg-yellow-100', text: 'text-yellow-600' }, + O: { label: 'On Process', bg: 'bg-blue-100', text: 'text-blue-600' }, F: { label: 'Fail', bg: 'bg-red-100', text: 'text-red-600' }, D: { label: 'Done', bg: 'bg-green-100', text: 'text-green-600' }, - Y: { label: 'Active', bg: 'bg-green-100', text: 'text-green-600' }, }; export const renderStatusBadge = (statusRaw: string | null | undefined) => { @@ -49,7 +52,9 @@ const DetailTransaction = () => { const { showDetailDialog, setShowDetailDialog, - selectedTransactionId + selectedTransactionId, + setShowDetailLogDialog, + setDetailLogData } = useTransactionContext(); const [transactionDetails, setTransactionDetails] = useState(null); @@ -92,27 +97,39 @@ const DetailTransaction = () => { Username - Name - Transfer Amount - Description - Invoice Number - Process Date - Response + Fullname + Amount Status + Process Date + Invoice Number + Actions + {transactionDetails?.log && transactionDetails?.log.length > 0 ? ( - transactionDetails.log.map((log: { customer: any, amount: number, remark: string, reference: string, response_date: string, payment_response: string, status: string}, index: number) => ( + transactionDetails.log.map((log: { id: number, customer: any, amount: number, remark: string, reference: string, request_date: string, payment_response: string, status: string}, index: number) => ( {log.customer.username ?? '-'} {log.customer.fullname ?? '-'} {log.amount ?? '-'} - {log.remark ?? '-'} - {log.reference ?? '-'} - {log.response_date ?? '-'} - {log.payment_response ?? '-'} {renderStatusBadge(log.status) ?? '-'} + {log.request_date && moment(log.request_date).isValid() ? moment(log.request_date).format('YYYY-MM-DD HH:mm:ss') : '-'} + {log.reference ?? '-'} + +
+ +
+ + )) ) : ( diff --git a/src/pages/disbursement/history-transaction/blocks/DetailTransactionLog.tsx b/src/pages/disbursement/history-transaction/blocks/DetailTransactionLog.tsx new file mode 100644 index 0000000..7b26b05 --- /dev/null +++ b/src/pages/disbursement/history-transaction/blocks/DetailTransactionLog.tsx @@ -0,0 +1,131 @@ +import React, { useState } from 'react'; +import moment from 'moment'; +import { useTransactionContext } from '../hooks/useTransactionContext'; +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogBody } from '@/components/ui/dialog'; + +interface LogType { + id: string; + amount: number; + remark: string; + reference: string; + response_date: string; + status: string; + customer?: { + username: string; + fullname: string; + }; + payment_response?: string; +} + +type StatusCode = 'W' | 'O' | 'F' | 'D'; + +interface StatusInfo { + label: string; + bg: string; + text: string; +} + +const statusMap: Record = { + W: { label: 'Waiting Schedule', bg: 'bg-yellow-100', text: 'text-yellow-600' }, + O: { label: 'On Process', bg: 'bg-blue-100', text: 'text-blue-600' }, + F: { label: 'Fail', bg: 'bg-red-100', text: 'text-red-600' }, + D: { label: 'Done', bg: 'bg-green-100', text: 'text-green-600' }, +}; + +export const renderStatusBadge = (statusRaw: string | null | undefined) => { + const status = statusRaw as StatusCode; + const { label, bg, text } = statusMap[status] ?? { + label: 'Unknown', + bg: 'bg-gray-100', + text: 'text-gray-600', + }; + + return ( + + {label} + + ); + }; + +const TransactionLogViewer = () => { + const { + showDetailLogDialog, + setShowDetailLogDialog, + detailLogData + } = useTransactionContext(); + + console.log('detailLogData: ', detailLogData) + + + + return ( + + + + Detail Record + + + {/* Tab Content */} + {detailLogData && detailLogData != null ? ( +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID{detailLogData.customer.id}
Username{detailLogData.customer.username}
Name{detailLogData.customer.fullname}
Amount{detailLogData.amount}
Remark{detailLogData.remark}
Payment Request
{detailLogData.payment_request}
Payment Response
{detailLogData.payment_response}
Status{renderStatusBadge(detailLogData.status)}
Prosess Date{detailLogData.request_date && moment(detailLogData.request_date).isValid() ? moment(detailLogData.request_date).format('YYYY-MM-DD HH:mm:ss') : '-'}
Response Date{detailLogData.response_date && moment(detailLogData.response_date).isValid() ? moment(detailLogData.response_date).format('YYYY-MM-DD HH:mm:ss') : '-'}
Reference Number{detailLogData.reference}
+
+
+
+ ) : (
)} +
+
+
+ ); +}; + +export default TransactionLogViewer; diff --git a/src/pages/disbursement/history-transaction/hooks/TransactionContext.tsx b/src/pages/disbursement/history-transaction/hooks/TransactionContext.tsx index 19e2382..b1807a1 100644 --- a/src/pages/disbursement/history-transaction/hooks/TransactionContext.tsx +++ b/src/pages/disbursement/history-transaction/hooks/TransactionContext.tsx @@ -10,6 +10,7 @@ import { Button } from '@/components/ui/button'; import { useNavigate } from 'react-router'; import moment from 'moment'; import DetailTransaction from '../blocks/DetailTransaction'; +import TransactionLogViewer from '../blocks/DetailTransactionLog'; interface TransactionProps { id: number; @@ -31,6 +32,11 @@ interface ContextProps { setSelectedTransactionId: React.Dispatch>; showUploadBatchDialog: boolean; handleUploadBatchDialog: (show: boolean) => void; + showDetailLogDialog: boolean; + // handleDetailLogDialog: (show: boolean) => void; + setShowDetailLogDialog: React.Dispatch>; + setDetailLogData: React.Dispatch>; + detailLogData: any | null } const initialProps: ContextProps = { @@ -41,6 +47,11 @@ const initialProps: ContextProps = { setSelectedTransactionId: () => { }, showUploadBatchDialog: false, handleUploadBatchDialog: (show: boolean) => {}, + showDetailLogDialog: false, + // handleDetailLogDialog: (show: boolean) => {}, + setShowDetailLogDialog: () => { }, + setDetailLogData: () => {}, + detailLogData: null, }; type StatusCode = 'W' | 'P' | 'F' | 'D' | 'Y'; @@ -67,6 +78,8 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { const [showDetailDialog, setShowDetailDialog] = useState(false); const [selectedTransactionId, setSelectedTransactionId] = useState(null); const [showUploadBatchDialog, setShowUploadBatchDialog] = useState(false); + const [showDetailLogDialog, setShowDetailLogDialog] = useState(false); + const [detailLogData, setDetailLogData] = useState(null); const [transaction, setTransaction] = useState([]); const { GetData } = useCallApi(); const navigate = useNavigate(); @@ -74,6 +87,9 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { const handleUploadBatchDialog = useCallback((show: boolean) => { setShowUploadBatchDialog(show); }, []); + // const handleDetailLogDialog = useCallback((show: boolean) => { + // setShowDetailLogDialog(show); + // }, []); const columns = useMemo[]>( () => [ @@ -262,11 +278,17 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { selectedTransactionId, setSelectedTransactionId, handleUploadBatchDialog, - showUploadBatchDialog + showUploadBatchDialog, + // handleDetailLogDialog, + showDetailLogDialog, + setShowDetailLogDialog, + setDetailLogData, + detailLogData }} > + void; + setSelectedLog: (log: LogDetail | null) => void; +} + +const TransactionDialogContext = createContext(undefined); + +export const TransactionDialogProvider = ({ children }: { children: React.ReactNode }) => { + const [showLogDialog, setShowLogDialog] = useState(false); + const [selectedLog, setSelectedLog] = useState(null); + + return ( + + {children} + + ); +}; + +export const useTransactionDialog = () => { + const context = useContext(TransactionDialogContext); + if (!context) throw new Error("useTransactionDialog must be used within TransactionDialogProvider"); + return context; +}; diff --git a/src/pages/master/wallet/blocks/ListToolbar.tsx b/src/pages/master/wallet/blocks/ListToolbar.tsx index 11b5767..1b35ce4 100644 --- a/src/pages/master/wallet/blocks/ListToolbar.tsx +++ b/src/pages/master/wallet/blocks/ListToolbar.tsx @@ -16,8 +16,10 @@ const ListToolbar = () => { table.getColumn('name')?.setFilterValue(event.target.value)} + value={(table.getColumn('wallets.name')?.getFilterValue() as string) ?? ''} + onChange={(event) => + table.getColumn('wallets.name')?.setFilterValue(event.target.value) + } /> {/* diff --git a/src/pages/master/wallet/hooks/ManageWalletContext.tsx b/src/pages/master/wallet/hooks/ManageWalletContext.tsx index 28a5a96..823d6eb 100644 --- a/src/pages/master/wallet/hooks/ManageWalletContext.tsx +++ b/src/pages/master/wallet/hooks/ManageWalletContext.tsx @@ -74,7 +74,7 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } () => [ { accessorFn: (row) => row.name, - id: 'name', + id: 'wallets.name', header: ({ column }) => , enableSorting: true, enableHiding: false, @@ -86,7 +86,7 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } accessorFn: (row) => row.description, id: 'description', header: ({ column }) => , - enableSorting: true, + enableSorting: false, enableHiding: false, meta: { headerClassName: 'w-[250px]' @@ -94,7 +94,7 @@ const ManageWalletContextProvider = ({ children }: { children: React.ReactNode } }, { accessorFn: (row) => row.status, - id: 'status', + id: 'wallets.status', header: ({ column }) => , enableSorting: true, enableHiding: false, diff --git a/src/pages/menu/manage-menu/blocks/ListToolbar.tsx b/src/pages/menu/manage-menu/blocks/ListToolbar.tsx index 9ed6b64..8d1915c 100644 --- a/src/pages/menu/manage-menu/blocks/ListToolbar.tsx +++ b/src/pages/menu/manage-menu/blocks/ListToolbar.tsx @@ -1,10 +1,22 @@ import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; import { useManageMenusContext } from '../hooks/useManageMenusContext'; import { Button } from '@/components/ui/button'; +import React, { useState } from 'react'; const ListToolbar = () => { const { table, reload } = useDataGrid(); const { handleAddDialog } = useManageMenusContext(); + const [searchValue, setSearchValue] = useState(''); + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter') { + handleSearch(); + } + }; + + const handleSearch = () => { + table.getColumn('name')?.setFilterValue(searchValue); + }; return (
@@ -16,10 +28,16 @@ const ListToolbar = () => { table.getColumn('name')?.setFilterValue(event.target.value)} + value={searchValue} + onChange={(event) => setSearchValue(event.target.value)} + onKeyDown={handleKeyDown} /> + + + {/*
handleEditFeeDialog(false, null)} + onClick={handleCloseDialog} >
@@ -654,13 +655,6 @@ const EditFeeDialog = () => {
- diff --git a/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx b/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx index 6f6bee5..df14f82 100644 --- a/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx +++ b/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx @@ -181,7 +181,30 @@ const ManageTransferFeeContextProvider = ({ children }: { children: React.ReactN meta: { headerClassName: 'w-[250px]' } }, { - accessorFn: (row) => row.credit_destination?.fullname, + accessorFn: (row: { credit_to: string }) => { + const mapping: Record = { + D: 'Destination Member', + S: 'Source Member', + I: 'Input Customer' + }; + + return mapping[row.credit_to] || 'Unknown'; + }, + id: 'credit_to', + header: ({ column }) => ( + + ), + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => { + if (row.credit_to === 'S' || row.credit_to === 'D' || !row.credit_destination) { + return 'N/A'; + } + return row.credit_destination?.fullname; + }, id: 'credit_destination', header: ({ column }) => , enableSorting: true, @@ -196,37 +219,102 @@ const ManageTransferFeeContextProvider = ({ children }: { children: React.ReactN enableHiding: false, meta: { headerClassName: 'w-[250px]' } }, + { + accessorFn: (row: { deduct_from: string }) => { + const mapping: Record = { + D: 'Destination Member', + S: 'Source Member', + }; + + return mapping[row.deduct_from]; + }, + id: 'deduct_from', + header: ({ column }) => ( + + ), + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, { accessorFn: (row) => row.deduct_from_account?.description, id: 'deduct_from_account', - header: ({ column }) => , + header: ({ column }) => , enableSorting: true, enableHiding: false, meta: { headerClassName: 'w-[250px]' } }, + { + accessorFn: (row) => row.priority, + id: 'priority', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + cell: ({ row }) => { + const isActive = row.original.priority === 'Y'; + + return ( + + {isActive ? 'Yes' : 'No'} + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + }, { - accessorFn: (row) => (row.priority === 'Y' ? 'Yes' : 'No'), - id: 'priority', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { headerClassName: 'w-[100px]' } - }, - { - accessorFn: (row) => (row.status === 'Y' ? 'Active' : 'Inactive'), + accessorFn: (row) => row.status, id: 'status', header: ({ column }) => , enableSorting: true, enableHiding: false, - meta: { headerClassName: 'w-[150px]' } + cell: ({ row }) => { + const isActive = row.original.status === 'Y'; + + return ( + + {isActive ? 'Active' : 'Inactive'} + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } }, { - accessorFn: (row) => (row.status_include === 'Y' ? 'Yes' : 'No'), + accessorFn: (row) => row.status_include, id: 'status_include', header: ({ column }) => , enableSorting: true, enableHiding: false, - meta: { headerClassName: 'w-[150px]' } + cell: ({ row }) => { + const isActive = row.original.status_include === 'Y'; + + return ( + + {isActive ? 'Yes' : 'No'} + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } }, { id: 'actions', diff --git a/src/pages/transfer/transfertype/blocks/EditDialog.tsx b/src/pages/transfer/transfertype/blocks/EditDialog.tsx index d646905..0039649 100644 --- a/src/pages/transfer/transfertype/blocks/EditDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/EditDialog.tsx @@ -701,15 +701,6 @@ const EditDialog = () => {
- @@ -724,7 +715,7 @@ const EditDialog = () => {
- {/* */} +