diff --git a/src/components/ui/DataTable.tsx b/src/components/ui/DataTable.tsx index 19cde1c..ff672e5 100644 --- a/src/components/ui/DataTable.tsx +++ b/src/components/ui/DataTable.tsx @@ -36,6 +36,7 @@ import { interface DataTableProps { columns: ColumnDef[]; data: TData[]; + createData: any; onUpdate: any; onDelete: any; } @@ -46,7 +47,7 @@ export function DataTable({ createData, onUpdate, onDelete -}: DataTableProps & { createData?: () => void }) { +}: DataTableProps) { const [columnFilters, setColumnFilters] = useState([]); const [sorting, setSorting] = useState([]); @@ -74,7 +75,7 @@ export function DataTable({ onChange={(event) => table.getColumn('name')?.setFilterValue(event.target.value)} className="max-w-sm" /> - {/* */} + {createData?() : ""}
diff --git a/src/pages/account/manage-account/ManageAccount.tsx b/src/pages/account/manage-account/ManageAccount.tsx index f116edd..402befa 100644 --- a/src/pages/account/manage-account/ManageAccount.tsx +++ b/src/pages/account/manage-account/ManageAccount.tsx @@ -93,6 +93,7 @@ const ManageAccount = () => { console.log('Callback update')} onDelete={() => console.log('Callback delete')} /> diff --git a/src/pages/disbursement/history-transaction/blocks/DetailTransaction.tsx b/src/pages/disbursement/history-transaction/blocks/DetailTransaction.tsx index 28df134..c3ded68 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,34 +26,35 @@ 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) => { - const status = statusRaw as StatusCode; - const { label, bg, text } = statusMap[status] ?? { - label: 'Unknown', - bg: 'bg-gray-100', - text: 'text-gray-600', - }; - - return ( - - {label} - - ); - }; + const status = statusRaw as StatusCode; + const { label, bg, text } = statusMap[status] ?? { + label: 'Unknown', + bg: 'bg-gray-100', + text: 'text-gray-600', + }; + + return ( + + {label} + + ); +}; const DetailTransaction = () => { const { GetData } = useCallApi(); const { showDetailDialog, setShowDetailDialog, - selectedTransactionId + selectedTransactionId, + setShowDetailLogDialog, + setDetailLogData } = useTransactionContext(); const [transactionDetails, setTransactionDetails] = useState(null); @@ -92,27 +97,39 @@ const DetailTransaction = () => { - - - - - - + + + + + + {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) => ( - - - - + + + + )) ) : ( 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..b2a668f --- /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 ? ( +
+
+
+
UsernameNameTransfer AmountDescriptionInvoice NumberProcess DateResponseFullnameAmount StatusProcess DateInvoice NumberActions
{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('DD/MM/YYYY HH:mm:ss') : '-'}{log.reference ?? '-'} +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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('DD/MM/YYYY HH:mm:ss') : '-'}
Response Date{detailLogData.response_date && moment(detailLogData.response_date).isValid() ? moment(detailLogData.response_date).format('DD/MM/YYYY 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..8c4862b 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,18 +87,12 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { const handleUploadBatchDialog = useCallback((show: boolean) => { setShowUploadBatchDialog(show); }, []); + // const handleDetailLogDialog = useCallback((show: boolean) => { + // setShowDetailLogDialog(show); + // }, []); const columns = useMemo[]>( () => [ - // { - // accessorKey: 'transaction_date', - // header: ({ column }) => , - // enableSorting: false, - // enableHiding: false, - // meta: { - // headerClassName: 'w-[250px]' - // } - // }, { accessorKey: 'file_name', header: ({ column }) => , @@ -176,7 +183,7 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { header: ({ column }) => , enableSorting: true, enableHiding: false, - cell: ({ row }) => moment(row.original.execution_date).format('YYYY-MM-DD HH:mm:ss') + cell: ({ row }) => moment(row.original.execution_date).format('DD/MM/YYYY HH:mm:ss') }, { accessorFn: (row) => row.done_date, @@ -184,7 +191,7 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { header: ({ column }) => , enableSorting: true, enableHiding: false, - cell: ({ row }) => row.original.done_date ? moment(row.original.done_date).format('YYYY-MM-DD HH:mm:ss') : '' + cell: ({ row }) => row.original.done_date ? moment(row.original.done_date).format('DD/MM/YYYY HH:mm:ss') : '' }, { id: 'actions', @@ -262,11 +269,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/groups/ManageGroups.tsx b/src/pages/groups/ManageGroups.tsx index 7704ad1..55ae1eb 100644 --- a/src/pages/groups/ManageGroups.tsx +++ b/src/pages/groups/ManageGroups.tsx @@ -89,6 +89,10 @@ const ManageGroups = () => { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); + if (!formData.groupName) return toast.warning(`Group name can not be empty!`) + if (!formData.status) return toast.warning(`Status can not be empty!`) + if (!formData.description) return toast.warning(`Description can not be empty!`) + setIsDialogOpen(false); setDialogOpen(true); }; @@ -198,7 +202,7 @@ const ManageGroups = () => {
- Create New Group + {dialogType==='create'?"Create New Group":"Update Group"} @@ -154,7 +143,7 @@ const ManageRewardContextProvider = ({ children }: { children: React.ReactNode } } } ], - [] + [handleEditDialog, handleDeleteDialog] ); const getRewardList = async (page: number, limit: number, sorting: any, filter: any) => { @@ -162,7 +151,7 @@ const ManageRewardContextProvider = ({ children }: { children: React.ReactNode } sorting = sorting.length == 0 ? [{ id: 'name', desc: false }] : sorting; filter = filter.length == 0 ? {} : { any: filter[0].value?.toLowerCase() }; const response = await GetData(`${API_URL_MASTER_DATA}/reward/list`, { - limit, + limit: limit, page: page + 1, with_deleted: false, order_field: sorting[0].id, @@ -171,7 +160,6 @@ const ManageRewardContextProvider = ({ children }: { children: React.ReactNode } }); // console.log('API Response:', response?.data.list); // console.log('reward list :', response); - setRewards(response?.data.list); return { data: response?.data.list, totalCount: response?.data.total_count }; } catch (error) { console.error('Error fethcing reward', error); @@ -181,7 +169,6 @@ const ManageRewardContextProvider = ({ children }: { children: React.ReactNode } return ( { 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/members/kyc-delete-member/ManageKycDeletion.tsx b/src/pages/members/kyc-delete-member/ManageKycDeletion.tsx new file mode 100644 index 0000000..0d5962e --- /dev/null +++ b/src/pages/members/kyc-delete-member/ManageKycDeletion.tsx @@ -0,0 +1,37 @@ +import { Container, DataGridInner } from '@/components'; +import { ManageKycDeletionContextProvider } from './hooks/ManageKycDeletionContext'; +import { Breadcrumbs, Link } from '@mui/material'; +import { Helmet } from 'react-helmet'; + +const ManageKycDeletion = () => { + return ( + <> + + TPAY | List Deletion + + + +

MANAGE KYC DELETION

+ + + Dashboard + + + + Member + + + + History Disbursement + + +
+ +
+
+
+ + ); +}; + +export default ManageKycDeletion; diff --git a/src/pages/members/kyc-delete-member/blocks/DetailDialog.tsx b/src/pages/members/kyc-delete-member/blocks/DetailDialog.tsx new file mode 100644 index 0000000..7875949 --- /dev/null +++ b/src/pages/members/kyc-delete-member/blocks/DetailDialog.tsx @@ -0,0 +1,98 @@ +import { + Dialog, + DialogBody, + DialogContent, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; +import { useManageKycDeletionContext } from '../hooks'; +import { apiConfig } from '@/config/api.config'; +import axios from 'axios'; + +const API_URL = apiConfig.service_customer; +const DetailDialog = () => { + const { showDetailDialog, setShowDetailDialog, detailKyc } = useManageKycDeletionContext(); + + return ( + + + + Customer Deletion Details + + + {/* Tab Content */} + {detailKyc && detailKyc != null ? ( +
+ {generateInput(detailKyc, null, 'Group', 'group_name', 'text', false, true)} + {generateInput(detailKyc, null, 'Username', 'username', 'text', false, true)} + {generateInput(detailKyc, null, 'Full Name', 'fullname', 'text', false, true)} + {generateInput(detailKyc, null, 'Gender', 'customers_gender', 'text', false, true)} + {generateInput(detailKyc, null, 'Date of Birth', 'birthdate', 'date', false, true)} + {generateInput(detailKyc, null, 'Mother Name', 'registered_mother_fullname', 'text', false, true)} + {generateInput(detailKyc, null, 'MSISDN', 'registered_msisdn', 'text', false, true)} + {generateInput(detailKyc, null, 'Reason Deletion', 'reason_deletion', 'text', false, true)} + {generateInput(detailKyc, null, 'Reason Note', 'reason_note', 'text', false, true)} + {generateInput(detailKyc, null, 'Status Approval', 'status_approve', 'text', false, true)} + +
+ + + +
+
+ ) : (
)} +
+
+
+ ); +}; + +export default DetailDialog; + +function generateInput(formData:any, handleChange:any, label:string, name:string, type: string, required: boolean, disabled: boolean) { + function generateDate(isoString: string) { + return isoString.slice(0, 10); // "2000-01-18" + } + + type Code = 'W' | 'Y' | 'N' | 'T' | 'P' | 'D' | 'L'; + interface Reason { + label: string; + } + + const statusMap: Record = { + W: {label: 'Waiting Approval'}, + Y: {label: 'Approve'}, + N: {label: 'Reject'}, + T: {label: 'Tidak lagi menggunakan layanan'}, + P: {label: 'Privasi dan keamanan'}, + D: {label: 'Akun ganda'}, + L: {label: 'Lainnya'} + }; + if (name == 'reason_deletion' || name == 'status_approve') { + const status = formData[name] as Code + const fixStatus = statusMap[status] ?? {label: formData[name]} + formData[name] = fixStatus.label + } + return ( + <> +
+
+ + +
+
+ + ) +} \ No newline at end of file diff --git a/src/pages/members/kyc-delete-member/blocks/ListToolbar.tsx b/src/pages/members/kyc-delete-member/blocks/ListToolbar.tsx new file mode 100644 index 0000000..013a15c --- /dev/null +++ b/src/pages/members/kyc-delete-member/blocks/ListToolbar.tsx @@ -0,0 +1,61 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { Button } from '@/components/ui/button'; +import { useCallback, useState, useEffect } from 'react'; +import { toast } from 'sonner'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + + // Set the initial state for trxDate + const [trxDate, settrxDate] = useState({ from: '', to: '' }); + + // Function to format date to YYYY-MM-DD + const formatDate = (date: Date): string => { + return date.toISOString().split('T')[0]; + }; + + // useEffect to set the default date values + useEffect(() => { + const today = new Date(); + const nextWeek = new Date(today); + nextWeek.setDate(today.getDate() + 7); + + settrxDate({ + from: formatDate(today), // Set 'from' to today + to: formatDate(nextWeek), // Set 'to' to 7 days later + }); + }, []); + + const handleFilterData = useCallback(() => { + try { + table.getColumn('transaction_date')?.setFilterValue(trxDate); + } catch (error) { + toast.error('Error applying filter'); + console.error('Error applying filter:', error); + } + }, [trxDate, table]); + + useEffect(() => { + if (trxDate.from && trxDate.to) { + handleFilterData(); + } + }, [trxDate]); + + return ( +
+
+
+
+ + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/members/kyc-delete-member/hooks/ManageKycDeletionContext.tsx b/src/pages/members/kyc-delete-member/hooks/ManageKycDeletionContext.tsx new file mode 100644 index 0000000..bf5e46f --- /dev/null +++ b/src/pages/members/kyc-delete-member/hooks/ManageKycDeletionContext.tsx @@ -0,0 +1,269 @@ +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 { createContext, useCallback, useMemo, useState } from 'react'; +import ListToolbar from '../blocks/ListToolbar'; +import { useCallApi } from '@/hooks'; +import moment from 'moment'; +import DetailDialog from '../blocks/DetailDialog'; + +interface ManageKycDeletionProps { + id: string; + customers_id: string; + group_id: string; + username: string; + fullname: string; + email: string; + status: string; + created_at: Date; +} + +interface ContextProps { + getKycDeletionList: ( + limit: number, + page: number, + with_deleted: boolean, + order_field: any, + order_direction: any, + filter: any + ) => Promise<{ data: ManageKycDeletionProps[]; totalCount: number } | undefined>; + showDetailDialog: boolean; + setShowDetailDialog: React.Dispatch>; + handleDetailDialog: (show: boolean, selected_user: string | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + selectedIdCustomer: string | null; + detailKyc: any | null; + setDetailKyc: React.Dispatch>; +} + +const initialProps: ContextProps = { + getKycDeletionList: async () => ({ data: [], totalCount: 0 }), + showDetailDialog: false, + handleDetailDialog: () => {}, + showAddDialog: false, + handleAddDialog: () => {}, + selectedIdCustomer: null, + setShowDetailDialog: () => { }, + detailKyc: async () => {}, + setDetailKyc: () => { }, +}; + +const ManageKycDeletionContext = createContext(initialProps); +const API_URL = apiConfig.service_customer; + +type StatusCode = 'W' | 'Y' | 'N' | 'T'; + +interface StatusInfo { + label: string; + bg: string; + text: string; +} + +const statusMap: Record = { + W: { label: 'Waiting Approval', bg: 'bg-yellow-100', text: 'text-yellow-600' }, + T: { label: 'No Need', bg: 'bg-blue-100', text: 'text-blue-600' }, + N: { label: 'Reject', bg: 'bg-red-100', text: 'text-red-600' }, + Y: { label: 'Approve', 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 ManageKycDeletionContextProvider = ({ children }: { children: React.ReactNode }) => { + const [showDetailDialog, setShowDetailDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [selectedIdCustomer, setSelectedIdCustomer] = useState(null); + const [detailKyc, setDetailKyc] = useState(); + const [manageKyc, setManageKyc] = useState([]); + const { GetData } = useCallApi(); + + const getKycDeletionList = async (page: number, limit: number, sorting: any, filter: any) => { + try { + let startdate; + let enddate; + let formattedFilter; + + if (filter == undefined || filter.length == 0) { + const today = new Date(); + const nextWeek = new Date(); + nextWeek.setDate(today.getDate() + 7); + + startdate = today.toISOString().split('T')[0]; + enddate = nextWeek.toISOString().split('T')[0]; + } else if (filter != undefined || filter.length != 0) { + startdate = filter[0].value.from; + enddate = filter[0].value.to; + } + + formattedFilter = { + + }; + + const response = await GetData(`${API_URL}/customer_deletion/list`, { + limit, + page: page + 1, + with_deleted: false, + order_field: "id", + order_direction: 'DESC', + filter: JSON.stringify(formattedFilter) + }); + + setManageKyc(response?.data.list); + return { data: response?.data.list, totalCount: response?.data.total_count }; + } catch (error) { + console.error('Error fetching transaction', error); + } + }; + + const handleDetailDialog = useCallback(async (show: boolean, selected_id_customer: string | null) => { + setSelectedIdCustomer(show ? selected_id_customer : null); + let detailCustomer = await GetData(`${API_URL}/customer_deletion/detail/${selected_id_customer}`, {}) + setDetailKyc(detailCustomer?.data) + console.log('detailCustomer: ',detailCustomer) + console.log('detailCustomer2: ',detailCustomer?.data) + console.log('detailKyc: ', detailKyc) + setShowDetailDialog(show); + }, []); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const columns = useMemo[]>( + () => [ + { + accessorFn: (row) => row.id, + id: 'id', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[100px]' + }, + }, + { + accessorFn: (row) => row.created_at, + id: 'created_at', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[250px]' + }, + cell: ({ row }) => moment(row.original.created_at).format('DD/MM/YYYY HH:mm:ss') + }, + { + accessorFn: (row) => row.username, + id: 'username', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[350px]' + } + }, + { + accessorFn: (row) => row.fullname, + id: 'fullname', + header: ({ column }) => , + enableSorting: true, + meta: { + headerClassName: 'w-[350px]' + } + }, + { + accessorFn: (row) => row.registered_email, + id: 'email', + header: ({ column }) => , + enableSorting: true, + meta: { + headerClassName: 'w-[350px]' + } + }, + { + accessorFn: (row) => row.status_approve, + id: 'status_approve', + header: ({ column }) => , + enableSorting: true, + meta: { + headerClassName: 'w-[350px]' + }, + cell: ({row}) => renderStatusBadge(row.original.status_approve) + }, + { + id: 'actions', + enableSorting: false, + header: ({ column }) => , + cell: (data: any) => { + const row = data.row.original; + + return ( + <> + + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + } + ], + [handleDetailDialog] + ); + + return ( + + + + + } + layout={{ card: true }} + sorting={[{ id: 'name', desc: false }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + getKycDeletionList(pageIndex, pageSize, sorting, columnFilters) + } + > + {children} + + + ); +}; + +export { ManageKycDeletionContextProvider, ManageKycDeletionContext }; +export type { ManageKycDeletionProps }; diff --git a/src/pages/members/kyc-delete-member/hooks/index.tsx b/src/pages/members/kyc-delete-member/hooks/index.tsx new file mode 100644 index 0000000..0d10e8a --- /dev/null +++ b/src/pages/members/kyc-delete-member/hooks/index.tsx @@ -0,0 +1,2 @@ +export * from './ManageKycDeletionContext'; +export * from './useManageKycDeletionContext'; diff --git a/src/pages/members/kyc-delete-member/hooks/useManageKycDeletionContext.tsx b/src/pages/members/kyc-delete-member/hooks/useManageKycDeletionContext.tsx new file mode 100644 index 0000000..f3a20c9 --- /dev/null +++ b/src/pages/members/kyc-delete-member/hooks/useManageKycDeletionContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageKycDeletionContext } from './ManageKycDeletionContext'; + +const useManageKycDeletionContext = () => { + const context = useContext(ManageKycDeletionContext); + + if (!context) throw new Error('useManageKycDeletionContext must be used within AuthProvider'); + + return context; +}; + +export { useManageKycDeletionContext }; diff --git a/src/pages/members/kyc/Kyc.tsx b/src/pages/members/kyc/Kyc.tsx index ff48332..3245347 100644 --- a/src/pages/members/kyc/Kyc.tsx +++ b/src/pages/members/kyc/Kyc.tsx @@ -109,6 +109,7 @@ const Kyc = () => { const updateData: any = member; const customerId = member.id; const description = member.description; + const destinationGroup = updateData.destinationGroup; updateData.updated_by = userLogin.data ? userLogin.data.id : ''; let today = new Date(); updateData.updated_at = today.toString(); @@ -151,15 +152,13 @@ const Kyc = () => { if (updateData[property]) form.append(property, updateData[property]); } if (dialogType === 'reject') { - await axios.post(`${BASE_URL}/customer/reject`, { customerid: customerId }); + if (destinationGroup === "Premium") await axios.post(`${BASE_URL}/customer/reject`, { customerid: customerId, description: updateData.approval_description_premium }); + if (destinationGroup === "Agent") await axios.post(`${BASE_URL}/customer/reject`, { customerid: customerId, description: updateData.approval_description_agent }); } if (dialogType === 'update') { await axios.put(`${BASE_URL}/customer/update/${customerId}`, form); - if (updateData.isneedapproval == 1) - await axios.post(`${BASE_URL}/customer/approve`, { - customerid: customerId, - description: description - }); + if (updateData.isneedapproval == 1&&destinationGroup === "Premium") await axios.post(`${BASE_URL}/customer/approve`, { customerid: customerId, description: updateData.approval_description_premium}); + if (updateData.isneedapproval == 1&&destinationGroup === "Agent") await axios.post(`${BASE_URL}/customer/approve`, { customerid: customerId, description: updateData.approval_description_agent}); } await fetchCustomers(); setDialogOpen(false); @@ -169,6 +168,7 @@ const Kyc = () => { setDialogOpen(false); setIsDialogOpen(false); toast.error(error.message); + } finally { setLoading(false) } }; @@ -234,6 +234,7 @@ const Kyc = () => {
{ let temp = 1; let resMembers = customers.data.data.list.map((el: any) => { el.no = temp++; + if (el.date_birth) { + const d = new Date(el.date_birth); + el.date_birth = d.toLocaleString("sv-SE"); + } el.name = el.fullname; return el; }); @@ -77,6 +81,7 @@ const ManageMembers = () => { function createMember() { setDialogType('create'); + setSelectedMember('') setMember(initialMember); setIsDialogOpen(true); } @@ -132,13 +137,35 @@ const ManageMembers = () => { if (updateData[property]) form.append(property, updateData[property]); } - if (dialogType === 'update') await axios.put(`${BASE_URL}/customer/update/${selectedMember}`, form, { + if (dialogType === 'update') { + await axios.put(`${BASE_URL}/customer/update/${selectedMember}`, form, { headers: { 'Content-Type': 'multipart/form-data' } }); - // if (dialogType === 'create') await axios.post(`${BASE_URL}/customers/create`, member) - toast.success('Success Update Member'); + toast.success('Success Edit Member'); + } + if (dialogType === 'create') { + const createMember:any = member + createMember.pin = "admin" + delete createMember.password; + delete createMember.try_pin; + delete createMember.license_number; + delete createMember.isneedapproval; + delete createMember.isapproved; + delete createMember.approveddate; + delete createMember.approvedby; + delete createMember.updated_by; + delete createMember.deleted_by; + delete createMember.deleted_at; + delete createMember.group; + delete createMember.point_tier; + delete createMember.approval_description_premium; + delete createMember.approval_description_agent; + delete createMember.language; + await axios.post(`${BASE_URL}/customers/create`, member) + toast.success('Success Create Member. PIN sent to email'); + } } catch (error: any) { toast.error(error.message); } finally { @@ -170,7 +197,7 @@ const ManageMembers = () => { onYes={handleYes} onNo={() => setDialogOpen(false)} /> - { member.id !== '' ? ( + { (member.id!=='' || dialogType==='create') ? ( { initialData={member} fetchCustomers={fetchCustomers} profession={profession} + dialogType={dialogType} /> ): ""}

Manage Members

diff --git a/src/pages/members/manage-members/blocks/AdmAccess.tsx b/src/pages/members/manage-members/blocks/AdmAccess.tsx index 735e832..0c4ceec 100644 --- a/src/pages/members/manage-members/blocks/AdmAccess.tsx +++ b/src/pages/members/manage-members/blocks/AdmAccess.tsx @@ -21,14 +21,7 @@ import ConfirmDialog from '@/components/confirm'; const BASE_URL_CUSTOMER = apiConfig.service_customer; // ACCESS ADM -export default function AdmAccess( - page: string, - data: any, - handleClose: any, - fetchCustomers: any, - viewOnly: any, - setViewOnly: any -) { +export default function AdmAccess({page,formData,handleClose,fetchCustomers,viewOnly,setViewOnly}: any) { const [dialogOpen, setDialogOpen] = useState(false); const [dialogType, setDialogType] = useState(''); const [changeGroup, setChangeGroup] = useState(''); @@ -59,10 +52,10 @@ export default function AdmAccess( const handleYes = async () => { try { if (dialogType === 'update status') { - let statusNext = getPinStatus(data.status).res; + let statusNext = getPinStatus(formData.status).res; if (statusNext) await axios.put(`${BASE_URL_CUSTOMER}/customer/statuspin`, { - customerid: data.id, + customerid: formData.id, status: statusNext }); else toast.error('Handle Active/Suspend only'); @@ -70,8 +63,8 @@ export default function AdmAccess( toast.success('Success Update Status'); } if (dialogType === 'reset pin') { - if (data.id) - await axios.post(`${BASE_URL_CUSTOMER}/customer/resetpin`, { customerid: data.id }); + if (formData.id) + await axios.post(`${BASE_URL_CUSTOMER}/customer/resetpin`, { customerid: formData.id }); else throw { message: 'data.id not found' }; await fetchCustomers(); toast.success('Pin will send to customer MSISDN'); @@ -99,10 +92,10 @@ export default function AdmAccess( async function buttonChangeGroup() { try { let dataObj = { - customerid: data.id, + customerid: formData.id, destination_group: changeGroup }; - if (data.group_id === changeGroup) + if (formData.group_id === changeGroup) throw { message: `You update same group as the exist customer group` }; if (dataObj.customerid && dataObj.destination_group) { await axios.post(`${BASE_URL_CUSTOMER}/customer/change-group`, dataObj); @@ -119,14 +112,14 @@ export default function AdmAccess( function openChangeGroupDialog(e: any) { e.preventDefault(); - setChangeGroup(data.group_id); + setChangeGroup(formData.group_id); setChangeGroupD(true); } function btnConfirmDialog(status: boolean) { setDialogOpen(status); } - + if (!formData.id) return ''; if (page !== 'kyc') { return (
@@ -136,9 +129,9 @@ export default function AdmAccess( {/* Left Side */}
-

Pin Status: {getPinStatus(data.status).msg}

+

Pin Status: {getPinStatus(formData.status).msg}

diff --git a/src/pages/members/manage-members/blocks/CustomerWallet.tsx b/src/pages/members/manage-members/blocks/CustomerWallet.tsx index 11d4bbc..3522cb7 100644 --- a/src/pages/members/manage-members/blocks/CustomerWallet.tsx +++ b/src/pages/members/manage-members/blocks/CustomerWallet.tsx @@ -6,7 +6,7 @@ import { apiConfig } from '@/config/api.config'; import { toast } from 'sonner'; const BASE_URL_CUSTOMER = apiConfig.service_customer; -export default function CustomerWallet(customerid: any) { +export default function CustomerWallet({customerid}: any) { const [customerWallet, setCustomerWallet] = useState([]); if (!customerid) return ''; @@ -21,7 +21,7 @@ export default function CustomerWallet(customerid: any) { }); setCustomerWallet(getCustWallet.data.data.data); } catch (error: any) { - // toast.error(error.message); + setCustomerWallet([]) toast.error(`Wallet Not Found`); } } @@ -30,7 +30,7 @@ export default function CustomerWallet(customerid: any) {

Wallet Member

- {customerWallet.length ? ( + {customerWallet ? (
diff --git a/src/pages/members/manage-members/blocks/DetailMember.tsx b/src/pages/members/manage-members/blocks/DetailMember.tsx index 1980510..85035ad 100644 --- a/src/pages/members/manage-members/blocks/DetailMember.tsx +++ b/src/pages/members/manage-members/blocks/DetailMember.tsx @@ -29,7 +29,7 @@ import AdmAccess from './AdmAccess'; import CustomerWallet from './CustomerWallet'; const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialData, handleReject, page, fetchCustomers, - handleClose, profession + handleClose, profession, dialogType }: any) => { const [formData, setFormData] = useState(initialData || initialMember); const [viewOnly, setViewOnly] = useState(false); @@ -168,9 +168,19 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa function buttonOnSubmit(e:any) { e.preventDefault(); - if (page === 'kyc' && formData.destinationGroup === "Premium" && !formData.approval_description_premium) return toast.warning(`Approval Premium Description needed!`) - if (page === 'kyc' && formData.destinationGroup === "Agent" && !formData.approval_description_premium) return toast.warning(`Approval Agent Description needed!`) - if (page === 'kyc' && !formData.description) return toast.warning(`Description for approval needed!`) + if (dialogType === 'update') { + if (page === 'kyc' && formData.destinationGroup === "Premium" && !formData.approval_description_premium) return toast.warning(`Approval Premium Description needed!`) + if (page === 'kyc' && formData.destinationGroup === "Agent" && !formData.approval_description_premium) return toast.warning(`Approval Agent Description needed!`) + if (!formData.msisdn||!formData.email||!formData.fullname||!formData.username||!formData.mother_fullname||!formData.address||!formData.nationality||!formData.date_birth||!formData.gender) { + return toast.warning(`Required fields cannot be empty: msisdn, email, fullname, username, mother Full Name, Address, Nationality, Date Of Birth, Gender.!`) + } + } + if (dialogType === 'create') { + if (!formData.msisdn||!formData.email||!formData.fullname||!formData.username||!formData.mother_fullname||!formData.address||!formData.nationality||!formData.date_birth||!formData.gender) { + return toast.warning(`Required fields cannot be empty: msisdn, email, fullname, username, mother Full Name, Address, Nationality, Date Of Birth, Gender.!`) + } + } + // if (page === 'kyc' && !formData.description) return toast.warning(`Description for approval needed!`) handleSubmit(formData); } @@ -180,6 +190,8 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa } const onReject = () => { + if (formData.destinationGroup === "Premium" && !formData.approval_description_premium) return toast.warning(`Approval Premium Description needed!`) + if (formData.destinationGroup === "Agent" && !formData.approval_description_premium) return toast.warning(`Approval Agent Description needed!`) handleReject(formData); handleClose(); } @@ -188,7 +200,7 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa handleAddDialog(open)}> - Member - View/Edit + Member - {dialogType ==='create' ? "Create" : "View/Edit"} @@ -199,79 +211,81 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa )} - {/*
*/} - {/* onSubmit={(e) => buttonOnSubmit(e, formData)} */} -
+
- {formData.id ? generateInput(formData, handleChange, 'Group', 'group_name', 'text', true, true): ''} - {formData.id ? generateInput(formData, handleChange, 'Username', 'username', 'text', true, true): ''} - {formData.id ? generateInput(formData, handleChange, 'Full Name', 'fullname', 'text', true, viewOnly): ''} - {formData.id ? generateImage(formData, handleChange, 'Photo', 'photouser'): ''} - {formData.id ? generateList(formData, handleChange, genders, 'gender', 'Gender', null, true): ''} - {formData.id ? generateInput(formData, handleChange, 'Date of Birth', 'date_birth', 'date', true, viewOnly): ''} - {formData.id ? generateInput(formData, handleChange, 'Phone Number', 'msisdn', 'text', true, viewOnly): ''} - {formData.id ? generateInput(formData, handleChange, 'Email', 'email', 'text', true, viewOnly): ''} - {/* {generateList(formData, handleChange, status, 'status', 'Status', null, true)} */} - {formData.id ? generateList(formData, handleChange, profession, 'profession', 'Profession', null, false): ''} - {formData.id ? generateList(formData, handleChange, municipios, 'municipio', 'Municipio', null, false): ''} - {formData.id ? generateList(formData, handleChange, postoAdm, 'posto_adms', 'Posto', 'posto_adms_id', false): ''} - {formData.id ? generateList(formData, handleChange, sucos, 'suco', 'Suco', 'sucos_id', false): ''} - {formData.id ? generateList(formData, handleChange, aldeias, 'aldeia', 'Aldeia', null, false): ''} - {formData.id ? generateInput(formData, handleChange, 'Nationality', 'nationality', 'text', true, viewOnly): ''} -
- -
    - {nationality.map((item: any, index) => ( -
  • handleChange({target:{name: 'nationality', value: item.name }})} - className="bg-gray-100 px-4 py-2 rounded hover:bg-gray-200 cursor-default transition"> - {item.name} -
  • - ))} - {formData.nationality && nationality.length === 0 && ( -
  • No results found.
  • - )} -
-
- {formData.id ? generateInput(formData, handleChange, 'Address', 'address', 'text', true, viewOnly): ''} - {formData.id ? generateInput(formData, handleChange, 'Mother Fullname', 'mother_fullname', 'text', true, viewOnly): ''} - {formData.id ? generateInput(formData, handleChange, 'Identity Number', 'identity_number', 'text', false, viewOnly): ''} - - {formData.id ? generateInput(formData, handleChange, 'License Number', 'license_number', 'text', false, viewOnly): ''} - {formData.id ? generateInput(formData, handleChange, 'Merchant Name', 'agent_name', 'text', false, viewOnly): ''} - {formData.id ? generateInput(formData, handleChange, 'Merchant Address', 'merchantaddress', 'text', false, viewOnly): ''} - {formData.id ? generateInput(formData, handleChange, 'Longitude Merchant', 'longitudemerchant', 'text', false, viewOnly): ''} - {formData.id ? generateInput(formData, handleChange, 'Latitude Merchant', 'latitudemerchant', 'text', false, viewOnly): ''} - {formData.id ? generateImage(formData, handleChange, 'File Selfie', 'file_selfie'): ''} - {formData.id ? generateImage(formData, handleChange, 'File Document', 'file_document_id'): ''} - {formData.id ? generateImage(formData, handleChange, 'File Document & Selfie', 'file_document_id_selfie'): ''} - {formData.id ? generateImage(formData, handleChange, 'File Commercial License', 'file_commercial_license'): ''} - - {formData.id ? generateList(formData, handleChange, banks, 'bank_name', 'Bank Name', null, false): ''} - {formData.id ? generateInput(formData, handleChange, 'Bank Account', 'bank_account', 'text', false, viewOnly): ''} - {formData.id ? generateInput(formData, handleChange, 'iBank Number', 'ibank_number', 'text', false, viewOnly): ''} - - {(formData.id&&(!page||formData.destinationGroup === "Premium")) ? generateInput(formData, handleChange, 'Approval Premium Description', 'approval_description_premium', 'text', false, viewOnly): ''} - {(formData.id&&(!page||formData.destinationGroup === "Agent")) ? generateInput(formData, handleChange, 'Approval Agent Description', 'approval_description_agent', 'text', false, viewOnly): ''} - - {(formData.id && page!=='kyc') ? AdmAccess(page, formData, handleClose,fetchCustomers, viewOnly, setViewOnly): ""} - {(formData.id && page!=='kyc') ? CustomerWallet(formData.id) : ""} - -
- - - {/* */} - { - formData.isneedapproval == 1 && page === 'kyc' ? ( - - ) : ('') - } - -
+ {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Group', 'group_name', 'text', true, true): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Username', 'username', 'text', true, dialogType==='create'?false:true): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Full Name', 'fullname', 'text', true, viewOnly): ''} + {(formData.id || dialogType === "create") ? generateImage(formData, handleChange, 'Photo', 'photouser'): ''} + {(formData.id || dialogType === "create") ? generateList(formData, handleChange, genders, 'gender', 'Gender', null, true): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Date of Birth', 'date_birth', 'date', true, viewOnly): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Phone Number', 'msisdn', 'text', true, viewOnly): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Email', 'email', 'text', true, viewOnly): ''} + {/* {generateList(formData, handleChange, status, 'status', 'Status', null, true)} */} + {(formData.id || dialogType === "create") ? generateList(formData, handleChange, profession, 'profession', 'Profession', null, false): ''} + {(formData.id || dialogType === "create") ? generateList(formData, handleChange, municipios, 'municipio', 'Municipio', null, false): ''} + {(formData.id || dialogType === "create") ? generateList(formData, handleChange, postoAdm, 'posto_adms', 'Posto', 'posto_adms_id', false): ''} + {(formData.id || dialogType === "create") ? generateList(formData, handleChange, sucos, 'suco', 'Suco', 'sucos_id', false): ''} + {(formData.id || dialogType === "create") ? generateList(formData, handleChange, aldeias, 'aldeia', 'Aldeia', null, false): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Nationality', 'nationality', 'text', true, viewOnly): ''} +
+ +
    + {nationality.map((item: any, index) => ( +
  • handleChange({target:{name: 'nationality', value: item.name }})} + className="bg-gray-100 px-4 py-2 rounded hover:bg-gray-200 cursor-default transition"> + {item.name} +
  • + ))} + {formData.nationality && nationality.length === 0 && ( +
  • No results found.
  • + )} +
- {/* */} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Address', 'address', 'text', true, viewOnly): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Mother Fullname', 'mother_fullname', 'text', true, viewOnly): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Identity Number', 'identity_number', 'text', false, viewOnly): ''} + + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'License Number', 'license_number', 'text', false, viewOnly): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Merchant Name', 'agent_name', 'text', false, viewOnly): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Merchant Address', 'merchantaddress', 'text', false, viewOnly): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Longitude Merchant', 'longitudemerchant', 'text', false, viewOnly): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Latitude Merchant', 'latitudemerchant', 'text', false, viewOnly): ''} + {(formData.id || dialogType === "create") ? generateImage(formData, handleChange, 'File Selfie', 'file_selfie'): ''} + {(formData.id || dialogType === "create") ? generateImage(formData, handleChange, 'File Document', 'file_document_id'): ''} + {(formData.id || dialogType === "create") ? generateImage(formData, handleChange, 'File Document & Selfie', 'file_document_id_selfie'): ''} + {(formData.id || dialogType === "create") ? generateImage(formData, handleChange, 'File Commercial License', 'file_commercial_license'): ''} + + {(formData.id || dialogType === "create") ? generateList(formData, handleChange, banks, 'bank_name', 'Bank Name', null, false): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Bank Account', 'bank_account', 'text', false, viewOnly): ''} + {(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'iBank Number', 'ibank_number', 'text', false, viewOnly): ''} + + {(formData.id&&(!page||formData.destinationGroup === "Premium")) ? generateInput(formData, handleChange, 'Approval Premium Description', 'approval_description_premium', 'text', false, viewOnly): ''} + {(formData.id&&(!page||formData.destinationGroup === "Agent")) ? generateInput(formData, handleChange, 'Approval Agent Description', 'approval_description_agent', 'text', false, viewOnly): ''} + + {(formData.id && page!=='kyc') ? ( + + ): ""} + {(formData.id && page!=='kyc') ? ( + + ) : ""} + +
+ + + {/* */} + { + formData.isneedapproval == 1 && page === 'kyc' ? ( + + ) : ('') + } + +
+
+
@@ -284,8 +298,7 @@ export default DetailMember; function generateInput(formData:any, handleChange:any, label:string, name:string, type: string, required: boolean, disabled: boolean) { function generateDate(isoString: string) { - const date = new Date(isoString); - return date.toISOString().slice(0, 10); // "2000-01-18" + return isoString.slice(0, 10); // "2000-01-18" } return ( <> 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} /> + + + {/*
+
+
+ + + + + + + + + { + e.currentTarget.scrollTop += e.deltaY; + }} + > + No Customer found. + + {customers.map((customer) => ( + { + setFormField({ + ...formField, + customerid: customer.id + }); + setOpen(false); + }} + > + {customer.username} + + ))} + + + + + +
+
+
diff --git a/src/pages/settings/user/manage-user/blocks/DeleteDialog.tsx b/src/pages/settings/user/manage-user/blocks/DeleteDialog.tsx index 13a8fc9..c00daba 100644 --- a/src/pages/settings/user/manage-user/blocks/DeleteDialog.tsx +++ b/src/pages/settings/user/manage-user/blocks/DeleteDialog.tsx @@ -34,6 +34,7 @@ const DeleteDialog = () => { const response = await DeleteData(`${API_URL}/user/delete/${selectedUser}/${enforce}`, { id: selectedUser }); + // console.log('Delete Response User:', response); if (response?.status) { setAlert((prev) => ({ ...prev, show: false, message: '' })); handleDeleteDialog(false, null); diff --git a/src/pages/settings/user/manage-user/blocks/EditDialog.tsx b/src/pages/settings/user/manage-user/blocks/EditDialog.tsx index 0d32ca6..a18ec29 100644 --- a/src/pages/settings/user/manage-user/blocks/EditDialog.tsx +++ b/src/pages/settings/user/manage-user/blocks/EditDialog.tsx @@ -6,7 +6,15 @@ import { SelectTrigger, SelectValue } from '@/components/ui/select'; - +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList +} from '@/components/ui/command'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Dialog, DialogBody, @@ -15,7 +23,9 @@ import { DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { CustomerProps } from './AddDialog'; import { useUserContext } from '../hooks'; +import { ChevronDown } from 'lucide-react'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { apiConfig } from '@/config/api.config'; @@ -30,6 +40,7 @@ interface RoleListProps { status: string; } +const API_URL_CUSTOMER = apiConfig.service_customer; const API_URL = apiConfig.service_dashboard; const initialState = { @@ -37,7 +48,8 @@ const initialState = { username: '', email: '', id_role: '', - status: '' + status: '', + customerid: '' }; const EditDialog = () => { @@ -45,7 +57,9 @@ const EditDialog = () => { const { showEditDialog, selectedUser, handleEditDialog } = useUserContext(); const { reload } = useDataGrid(); const { GetData, PutData } = useCallApi(); + const [open, setOpen] = useState(false); const [roles, setRoles] = useState([]); + const [customers, setCustomers] = useState([]); const [alert, setAlert] = useState({ show: false, message: '' @@ -109,9 +123,27 @@ const EditDialog = () => { } }, []); + const getCustomerList = async (sorting: any) => { + try { + sorting = sorting.length == 0 ? [{ id: 'name', desc: false }] : sorting; + const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { + limit: 100, + page: 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc == false ? 'ASC' : 'DESC' + }); + + // console.log('CUSTOMER: ', response?.data); + setCustomers(response?.data.list); + } catch (error) { + console.error('Error fetching customer', error); + } + }; + const doFetchUserData = useCallback(async (id: string) => { const response = await GetData(`${API_URL}/user/detail/${id}`, { id }); - // console.log('User detail response:', response); + // console.log('User detail response:', response?.data); if (response?.status) { setFormField((prev) => ({ @@ -120,8 +152,10 @@ const EditDialog = () => { username: response.data.username, email: response.data.email, id_role: response.data.idRole, - status: response.data.status + status: response.data.status, + customerid: response.data.customer.id })); + // console.log('Customer ID from API:', response?.data.customerid); } else { setFormField((prev) => ({ ...prev, @@ -129,18 +163,13 @@ const EditDialog = () => { username: '', email: '', id_role: '0', - status: '' + status: '', + customerid: '' })); } // console.log('Fetched ID Role:', response?.data.id_role); }, []); - useEffect(() => { - if (selectedUser) { - doFetchUserData(selectedUser); - } - }, [selectedUser]); - useEffect(() => { if (showEditDialog === false) { resetForm(); @@ -149,6 +178,7 @@ const EditDialog = () => { useEffect(() => { const fetchAllData = async () => { + await getCustomerList([{ id: 'id', desc: false }]); await doFetchUserRole([{ id: 'name', desc: false }]); if (selectedUser) { await doFetchUserData(selectedUser); @@ -220,6 +250,58 @@ const EditDialog = () => {
+
+
+ + + + + + + + + { + e.currentTarget.scrollTop += e.deltaY; + }} + > + No Customer found. + + {customers.map((customer) => ( + { + setFormField({ + ...formField, + customerid: customer.id + }); + setOpen(false); + }} + > + {customer.username} + + ))} + + + + + +
+
+
diff --git a/src/pages/settings/user/manage-user/blocks/ListToolBar.tsx b/src/pages/settings/user/manage-user/blocks/ListToolBar.tsx index 70eb5be..2e76deb 100644 --- a/src/pages/settings/user/manage-user/blocks/ListToolBar.tsx +++ b/src/pages/settings/user/manage-user/blocks/ListToolBar.tsx @@ -15,7 +15,7 @@ const ListToolBar = () => { table.getColumn('username')?.setFilterValue(event.target.value) diff --git a/src/pages/settings/user/manage-user/hooks/ManageUserContext.tsx b/src/pages/settings/user/manage-user/hooks/ManageUserContext.tsx index 24cbc41..8b33e36 100644 --- a/src/pages/settings/user/manage-user/hooks/ManageUserContext.tsx +++ b/src/pages/settings/user/manage-user/hooks/ManageUserContext.tsx @@ -27,6 +27,7 @@ interface SelectedUser { role: string; new_password: string; check_new_password: string; + customer: string; } const initialProps: ContextProps = { @@ -77,17 +78,27 @@ const ManageUserContextProvider = ({ children }: { children: React.ReactNode }) const columns = useMemo[]>( () => [ { - accessorFn: (row) => row.username, + accessorKey: 'username', id: 'username', header: ({ column }) => , enableSorting: true, enableHiding: false }, + { + accessorFn: (row) => row.customer?.username, + id: 'customer', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { + headerClassName: 'w-[300px]' + } + }, { accessorFn: (row) => row.email, id: 'email', header: ({ column }) => , - enableSorting: false, + enableSorting: true, enableHiding: false, meta: { headerClassName: 'w-[350px]' @@ -97,17 +108,17 @@ const ManageUserContextProvider = ({ children }: { children: React.ReactNode }) accessorFn: (row) => row.name, id: 'name', header: ({ column }) => , - enableSorting: false, + enableSorting: true, enableHiding: false, meta: { - headerClassName: 'w-[350px]' + headerClassName: 'w-[250px]' } }, { accessorFn: (row) => row.role.name, id: 'role_name', header: ({ column }) => , - enableSorting: false, + enableSorting: true, enableHiding: false, cell: (data: any) => { const { role } = data.row.original; @@ -179,17 +190,30 @@ const ManageUserContextProvider = ({ children }: { children: React.ReactNode }) ); const doGetListData = async (page: number, limit: number, sorting: any, filter: any) => { - sorting = sorting.length == 0 ? [{ id: 'username', desc: false }] : sorting; - filter = filter.length == 0 ? {} : { any: filter[0].value.toLowerCase() }; + const USER_TABLE_COLUMNS = ['username', 'email', 'name', 'status']; + + // âž• Tambahkan prefix ke field dari tabel Users + const mappedSorting = sorting.map((sort: any) => ({ + ...sort, + id: USER_TABLE_COLUMNS.includes(sort.id) ? `Users.${sort.id}` : sort.id + })); + + const orderField = mappedSorting[0]?.id ?? 'Users.username'; + const orderDirection = mappedSorting[0]?.desc === false ? 'DESC' : 'ASC'; + + filter = + filter.length == 0 + ? {} + : { 'Users.username': { like: `%${filter[0].value?.toLowerCase()}%` } }; const response = await GetData(`${API_URL}/user/list`, { limit: limit, page: page + 1, with_deleted: false, - order_field: sorting[0].id, - order_direction: sorting[0].desc == false ? 'ASC' : 'DESC', + order_field: orderField, + order_direction: orderDirection, filter: JSON.stringify(filter) }); - console.log('response api:', response); + // console.log('response api:', response); return { data: response?.data.list, totalCount: response?.data.total_count }; }; @@ -215,7 +239,7 @@ const ManageUserContextProvider = ({ children }: { children: React.ReactNode }) pagination={{ size: 10 }} toolbar={} layout={{ card: true }} - sorting={[{ id: 'username', desc: false }]} + sorting={[{ id: 'Users.username', desc: false }]} serverSide={true} onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => doGetListData(pageIndex, pageSize, sorting, columnFilters) diff --git a/src/pages/transfer/transferfee/blocks/AddDialog.tsx b/src/pages/transfer/transferfee/blocks/AddDialog.tsx index c7c8d64..0860010 100644 --- a/src/pages/transfer/transferfee/blocks/AddDialog.tsx +++ b/src/pages/transfer/transferfee/blocks/AddDialog.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useManageTransferFeeContext } from '../hooks/useManageTransferFeeContext'; import { NumericFormat } from 'react-number-format'; import { @@ -40,31 +40,54 @@ import { TableHeader, TableRow } from '@/components/ui/table'; -import { ManageTransferFeeContext } from '../hooks/ManageTransferFeeContext'; -import { ColumnDef } from '@tanstack/react-table'; -import { ManageTransferFeeContextProvider } from '../../transferfee/hooks/ManageTransferFeeContext'; import { apiConfig } from '@/config/api.config'; -import { get } from 'http'; interface TransactionTypeProps { id: string; name: string; } - +interface WalletProps { + id: string; + name: string; +} +interface CustomerProps { + id: string; + username: string; + msisdn: string; +} const API_URL = apiConfig.service_transaction; +const API_URL_MASTER_DATA = apiConfig.service_master_data; +const API_URL_CUSTOMER = apiConfig.service_customer; const AddFeeDialog = () => { const parentRef = useRef(null); const { reload } = useDataGrid(); const { PostData, PutData, GetData } = useCallApi(); - const { showAddFeeDialog, handleAddFeeDialog, handleEditFeeDialog, selectedTransferFee } = - useManageTransferFeeContext(); + const { + showAddFeeDialog, + handleAddFeeDialog, + handleEditFeeDialog, + selectedTransferFee, + transactionTypeId + } = useManageTransferFeeContext(); + const [alert, setAlert] = useState({ show: false, message: '' }); const [transactionTypes, setTransactionTypes] = useState([]); + const [wallets, setWallets] = useState([]); + const [customers, setCustomers] = useState([]); + const [defaultCustomer, setDefaultCustomer] = useState(''); + const [transactionTypeName, setTransactionTypeName] = useState(''); + const [isLoadingTransactionType, setIsLoadingTransactionType] = useState(false); + const [isLoadingWallets, setIsLoadingWallets] = useState(false); + const [isLoadingCustomers, setIsLoadingCustomers] = useState(false); + const customersWithNames = customers.map((customer) => ({ + id: customer.id, + name: customer.username + })); const initialState = { name: '', description: '', @@ -75,58 +98,77 @@ const AddFeeDialog = () => { period_end: '', deduct_amount: 0, deduct_percentage: 0, + fee_amount: 0, priority: '', status: '', status_include: '', created_by: '', - created_at: '' + created_at: '', + deduct_from: '', + deduct_from_account: '', + credit_to: '', + credit_destination: '00000000-0000-0000-0000-000000000000', + credit_destination_account: '' }; const [formField, setFormField] = useState(initialState); const resetForm = () => { setFormField(initialState); + setTransactionTypeName(''); }; const [isSubmitting, setIsSubmitting] = useState(false); const [showTransactionFeeDialog, setShowTransactionFeeDialog] = useState(false); const parsedUser = getAuth()?.user; - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - // setIsSubmitting(true); - const payload = { - name: formField.name, - description: formField.description, - period_start: formField.period_start, - period_end: formField.period_end, - minimum_amount: formField.minimum_amount, - maximum_amount: formField.maximum_amount, - deduct_amount: formField.deduct_amount, - deduct_percentage: formField.deduct_percentage, - transaction_type: formField.transaction_type, - status: formField.status, - status_include: formField.status_include, - priority: formField.priority - }; - }; + useEffect(() => { + if (showAddFeeDialog && transactionTypeId) { + setIsLoadingTransactionType(true); + + setFormField((prev) => ({ + ...prev, + transaction_type: transactionTypeId + })); + + const getTransactionTypeDetails = async () => { + try { + const response = await GetData( + `${API_URL}/transactiontype/getdata/${transactionTypeId}`, + {} + ); + if (response?.status && response?.data) { + setTransactionTypeName(response.data.name); + } + } catch (error) { + console.error('Error fetching transaction type details', error); + } finally { + setIsLoadingTransactionType(false); + } + }; + + getTransactionTypeDetails(); + } + }, [showAddFeeDialog, transactionTypeId, GetData]); + useEffect(() => { const created_time = new Date(); const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); if (showAddFeeDialog) { - setFormField({ - ...formField, + setFormField((prev) => ({ + ...prev, created_by: parsedUser?.username, created_at: formattedTime - }); + })); } - }, [showAddFeeDialog]); + }, [showAddFeeDialog, parsedUser?.username]); useEffect(() => { if (!showAddFeeDialog) return; const getTransactionTypeList = async (sorting: any) => { + setIsLoadingTransactionType(true); try { sorting = sorting.length === 0 ? [{ id: 'name', desc: false }] : sorting; const response = await GetData(`${API_URL}/transactiontype/list`, { @@ -138,40 +180,182 @@ const AddFeeDialog = () => { }); setTransactionTypes(response?.data.list || []); } catch (error) { - console.error('Error fetching customer', error); + console.error('Error fetching transaction types', error); + } finally { + setIsLoadingTransactionType(false); } }; getTransactionTypeList([{ id: 'id', desc: false }]); - }, [showAddFeeDialog]); + }, [showAddFeeDialog, GetData]); + + const fetchWallets = useCallback(async () => { + setIsLoadingWallets(true); + const params = { + limit: 100, + page: 1, + with_deleted: false, + order_field: 'Wallets.name', + order_direction: 'ASC' + }; + try { + const response = await GetData(`${API_URL_MASTER_DATA}/wallet/list`, params); + if (response?.status && response?.data) { + setWallets(response.data.list); + } else { + setWallets([]); + } + } catch (error) { + console.error('Error fetching wallets', error); + setWallets([]); + } finally { + setIsLoadingWallets(false); + } + }, [GetData]); + + useEffect(() => { + if (!showAddFeeDialog) return; + fetchWallets(); + }, [showAddFeeDialog, fetchWallets]); + + useEffect(() => { + if (!showAddFeeDialog) return; + const getCustomerList = async (sorting: any) => { + setIsLoadingCustomers(true); + try { + sorting = sorting.length === 0 ? [{ id: 'name', desc: false }] : sorting; + + const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { + limit: 100, + page: 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc ? 'DESC' : 'ASC' + }); + const customerList = response?.data.list || []; + setCustomers(customerList); + + if (customerList.length > 0) { + setDefaultCustomer(customerList[0].id); + } + } catch (error) { + console.error('Error fetching customers', error); + setCustomers([]); + } finally { + setIsLoadingCustomers(false); + } + }; + + getCustomerList([{ id: 'id', desc: false }]); + }, [showAddFeeDialog, GetData]); const doCreateTransferType = useCallback( async (e: React.FormEvent) => { e.preventDefault(); - for (const key in formField) { - if ( - formField[key as keyof typeof formField] === '' ) { - setAlert({ show: true, message: 'All fields must be filled out' }); + setIsSubmitting(true); + + const requiredFields = [ + 'name', + 'description', + 'period_start', + 'period_end', + 'transaction_type', + 'status', + 'status_include', + 'priority', + 'deduct_from', + 'deduct_from_account', + 'credit_to', + 'credit_destination_account' + ]; + + for (const field of requiredFields) { + if (formField[field as keyof typeof formField] === '') { + setAlert({ + show: true, + message: `All required fields must be filled out. Missing: ${field.replace(/_/g, ' ')}` + }); + setIsSubmitting(false); return; } } + if (formField.credit_to === 'I' && !formField.credit_destination) { + setAlert({ + show: true, + message: 'Credit destination is required when Input Customer is selected' + }); + setIsSubmitting(false); + return; + } + setAlert({ show: false, message: '' }); - const response = await PostData(`${API_URL}/transactionfees/create`, { - ...formField - }); - if (response?.status) { - // toast.success('Success Create Transfer Fee'); - reload(); - resetForm(); - handleAddFeeDialog(false); - } else { - setAlert({ show: true, message: response?.message || 'Failed to create transfer fee' }); + + const payload = { ...formField }; + + if (formField.credit_to !== 'I') { + payload.credit_destination = '00000000-0000-0000-0000-000000000000'; + } + + try { + const response = await PostData(`${API_URL}/transactionfees/create`, payload); + + if (response?.status) { + toast.success('Successfully created transfer fee'); + reload(); + resetForm(); + handleAddFeeDialog(false); + + const createActivity = { + module: 'Manage Transfer Fee', + description: `Create Transfer Fee => ${formField.name}`, + action: 'C' + }; + doSaveLogActivity(createActivity); + } else { + setAlert({ show: true, message: response?.message || 'Failed to create transfer fee' }); + } + } catch (error) { + console.error('Error creating transfer fee', error); + setAlert({ show: true, message: 'An error occurred while creating the transfer fee' }); + } finally { + setIsSubmitting(false); } }, - [formField] + [formField, PostData, reload, handleAddFeeDialog] ); + const renderSelectWithLoading = ( + value: string, + onChangeHandler: (value: string) => void, + options: { id: string; name: string }[] | null, + placeholder: string, + isLoading: boolean + ) => { + return ( + + ); + }; + return ( handleAddFeeDialog(open)}> @@ -194,12 +378,51 @@ const AddFeeDialog = () => {
- {alert.show && {alert.message}} + {alert.show && ( +
+ +

{alert.message}

+
+
+ )}
- + + {transactionTypeId ? ( +
+ + {isLoadingTransactionType && ( +
+
+
+ Loading transaction type... +
+
+ )} +
+ ) : ( + renderSelectWithLoading( + formField.transaction_type, + (transaction_type) => setFormField((prev) => ({ ...prev, transaction_type })), + transactionTypes, + 'Select Transaction Type', + isLoadingTransactionType + ) + )} +
+
+ { />
- + { minimum_amount: values.floatValue || 0 })); }} - placeholder="Enter Max Transaction Per Day" + placeholder="Enter Minimum Amount" />
@@ -253,11 +478,13 @@ const AddFeeDialog = () => { maximum_amount: values.floatValue || 0 })); }} - placeholder="Enter Max Transaction Per Day" + placeholder="Enter Maximum Amount" />
- + { />
- + { deduct_amount: values.floatValue || 0 })); }} - placeholder="Enter Max Transaction Per Day" + placeholder="Enter Deduct Amount" />
@@ -311,31 +540,110 @@ const AddFeeDialog = () => { deduct_percentage: values.floatValue || 0 })); }} - placeholder="Enter Max Transaction Per Day" + placeholder="Enter Deduct Percentage" />
- + + { + setFormField((prev) => ({ + ...prev, + fee_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Fee Amount" + /> +
+
+
- + + {renderSelectWithLoading( + formField.deduct_from_account, + (value) => setFormField({ ...formField, deduct_from_account: value }), + wallets, + 'Select Wallet', + isLoadingWallets + )} +
+
+ + +
+ {formField.credit_to === 'I' && ( +
+ + {renderSelectWithLoading( + formField.credit_destination, + (value) => setFormField({ ...formField, credit_destination: value }), + customersWithNames, + 'Select Customer', + isLoadingCustomers + )} +
+ )} +
+ + {renderSelectWithLoading( + formField.credit_destination_account, + (value) => setFormField({ ...formField, credit_destination_account: value }), + wallets, + 'Select Wallet', + isLoadingWallets + )} +
+
+
- +
- + + setFormField((prev) => ({ ...prev, name: target.value })) + } + /> +
+ +
+ + + setFormField((prev) => ({ ...prev, description: target.value })) + } + /> +
+ +
+ + { + setFormField((prev) => ({ + ...prev, + minimum_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Minimum Amount" + /> +
+ +
+ + { + setFormField((prev) => ({ + ...prev, + maximum_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Maximum Amount" + /> +
+ +
+ + + setFormField((prev) => ({ ...prev, period_start: target.value })) + } + /> +
+ +
+ + + setFormField((prev) => ({ ...prev, period_end: target.value })) + } + /> +
+ +
+ + { + setFormField((prev) => ({ + ...prev, + deduct_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Deduct Amount" + /> +
+ +
+ + { + setFormField((prev) => ({ + ...prev, + deduct_percentage: values.floatValue || 0 + })); + }} + placeholder="Enter Deduct Percentage" + /> +
+ +
+ + { + setFormField((prev) => ({ + ...prev, + fee_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Fee Amount" + /> +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + {formField.credit_to === 'I' && (
- - setFormField((prev) => ({ ...prev, name: target.value })) - } - /> -
-
- - - setFormField((prev) => ({ ...prev, description: target.value })) - } - /> -
-
- - { - setFormField((prev) => ({ - ...prev, - minimum_amount: values.floatValue || 0 - })); - }} - placeholder="Enter Minimum Amount" - /> -
-
- - { - setFormField((prev) => ({ - ...prev, - maximum_amount: values.floatValue || 0 - })); - }} - placeholder="Enter Minimum Amount" - /> -
-
- - - setFormField((prev) => ({ ...prev, period_start: target.value })) - } - /> -
-
- - - setFormField((prev) => ({ ...prev, period_end: target.value })) - } - /> -
-
- - { - setFormField((prev) => ({ - ...prev, - deduct_amount: values.floatValue || 0 - })); - }} - placeholder="Enter Minimum Amount" - /> -
-
- - { - setFormField((prev) => ({ - ...prev, - deduct_percentage: values.floatValue || 0 - })); - }} - placeholder="Enter Minimum Amount" - /> -
-
-
-
- - -
-
- - -
-
- - -
+ )} - {/*
- +
+ +
+ +
+ + +
+ +
+ + -
*/} +
- {/*
- - -
*/} -
- - -
+
+ + +
+ +
+ + +
+ +
+
- -
+
+
diff --git a/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx b/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx index 2510b2d..9d78802 100644 --- a/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx +++ b/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx @@ -7,6 +7,7 @@ import { createContext, useCallback, useEffect, useMemo, useState } from 'react' import ListToolbar from '../blocks/ListToolBar'; import DeleteDialog from '../blocks/DeleteDialog'; import { EditFeeDialog } from '../blocks/EditDialog'; +import { useManageTransferTypeContext } from '../../transfertype/hooks/useManageTransferTypeContext'; interface ContextProps { showEditFeeDialog: boolean; @@ -16,6 +17,7 @@ interface ContextProps { handleDeleteFeeDialog: (show: boolean, selected_TransferFee: string | null) => void; showDeleteFeeDialog: boolean; selectedTransferFee: string | null; + transactionTypeId: string | null; } const initialProps: ContextProps = { @@ -25,20 +27,41 @@ const initialProps: ContextProps = { handleAddFeeDialog: () => {}, showDeleteFeeDialog: false, handleDeleteFeeDialog: () => {}, - selectedTransferFee: null + selectedTransferFee: null, + transactionTypeId: null }; +interface TransferFeeProps { + name: string; + description: string; + minimum_amount: number; + maximum_amount: number; + period_start: string; + period_end: string; + deduct_amount: number; + deduct_percentage: number; + transaction_type: string; + status: string; + status_include: string; + fee: number; +} + const ManageTransferFeeContext = createContext(initialProps); const API_URL = apiConfig.service_transaction; -const ManageTransferFeeContextProvider = ({ children }: { children: React.ReactNode }) => { +const ManageTransferFeeContextProvider = ({ + children, + transactionTypeId = null +}: { + children: React.ReactNode; + transactionTypeId?: string | null; +}) => { const [showEditFeeDialog, setShowEditFeeDialog] = useState(false); const [showAddFeeDialog, setShowAddFeeDialog] = useState(false); const [showDeleteFeeDialog, setShowDeleteFeeDialog] = useState(false); - + const { showAddDialog, handleAddDialog, selectedTransferType } = useManageTransferTypeContext(); const [selectedTransferFee, setSelectedTransferFee] = useState(null); const { GetData } = useCallApi(); - const handleEditFeeDialog = useCallback((show: boolean, selected_TransferFee: string | null) => { setSelectedTransferFee(show ? selected_TransferFee : null); setShowEditFeeDialog(show); @@ -48,28 +71,44 @@ const ManageTransferFeeContextProvider = ({ children }: { children: React.ReactN setShowAddFeeDialog(show); }, []); - const handleDeleteFeeDialog = useCallback((show: boolean, selected_TransferFee: string | null) => { - setSelectedTransferFee(show ? selected_TransferFee : null); - setShowDeleteFeeDialog(show); - }, []); + const handleDeleteFeeDialog = useCallback( + (show: boolean, selected_TransferFee: string | null) => { + setSelectedTransferFee(show ? selected_TransferFee : null); + setShowDeleteFeeDialog(show); + }, + [] + ); const doGetTransferFeeListData = async ( page: number, limit: number, sorting: any, filter: any ) => { - sorting = sorting.length == 0 ? [{ id: 'id', desc: false }] : sorting; - filter = filter.length == 0 ? {} : { any: filter[0].value.toLowerCase() }; - const response = await GetData(`${API_URL}/transactionfees/list`, { - limit: limit, - page: page+1, - with_deleted: false, - order_field: sorting[0].id, - order_direction: sorting[0].desc ? 'ASC' : 'DESC', - filter: JSON.stringify(filter) - }); - return { data: response?.data.list, totalCount: response?.data.total_count }; + if (!selectedTransferType) { + return { data: [], totalCount: 0 }; + } + + sorting = sorting.length === 0 ? [{ id: 'id', desc: false }] : sorting; + filter = filter.length === 0 ? {} : { any: filter[0].value.toLowerCase() }; + + try { + const response = await GetData( + `${API_URL}/transactionfees/getdatabytransactiontype/${selectedTransferType}`, + {} + ); + + // console.log('API Response:', response?.data); + + return { + data: response?.data, + totalCount: 1 + }; + } catch (error) { + console.error('Error fetching transaction fees by transaction type:', error); + return { data: [], totalCount: 0 }; + } }; + const columns = useMemo[]>( () => [ { @@ -105,20 +144,12 @@ const ManageTransferFeeContextProvider = ({ children }: { children: React.ReactN meta: { headerClassName: 'w-[150px]' } }, { - accessorFn: (row) => row.period_start?.split('T')[0], - id: 'period_start', - header: ({ column }) => , + accessorFn: (row) => row.fee_amount, + id: 'fee_amount', + header: ({ column }) => , enableSorting: true, enableHiding: false, - meta: { headerClassName: 'w-[200px]' } - }, - { - accessorFn: (row) => row.period_end?.split('T')[0], - id: 'period_end', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { headerClassName: 'w-[200px]' } + meta: { headerClassName: 'w-[150px]' } }, { accessorFn: (row) => row.deduct_amount, @@ -136,6 +167,23 @@ const ManageTransferFeeContextProvider = ({ children }: { children: React.ReactN enableHiding: false, meta: { headerClassName: 'w-[150px]' } }, + + { + accessorFn: (row) => row.period_start?.split('T')[0], + id: 'period_start', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[200px]' } + }, + { + accessorFn: (row) => row.period_end?.split('T')[0], + id: 'period_end', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[200px]' } + }, { accessorFn: (row) => row.transaction_type?.name, id: 'transactionTypeId', @@ -145,28 +193,140 @@ const ManageTransferFeeContextProvider = ({ children }: { children: React.ReactN meta: { headerClassName: 'w-[250px]' } }, { - accessorFn: (row) => (row.priority === 'Y' ? 'Yes' : 'No'), + 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, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.credit_destination_account?.description, + id: 'credit_destination_account', + header: ({ column }) => ( + + ), + enableSorting: true, + 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 }) => ( + + ), + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.priority, id: 'priority', header: ({ column }) => , enableSorting: true, enableHiding: false, - meta: { headerClassName: 'w-[100px]' } + cell: ({ row }) => { + const isActive = row.original.priority === 'Y'; + + return ( + + {isActive ? 'Yes' : 'No'} + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } }, { - 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', @@ -204,8 +364,8 @@ const ManageTransferFeeContextProvider = ({ children }: { children: React.ReactN return (
-

Manage Transaction Fee

-
+

Manage Transaction Fee

+
@@ -230,8 +391,6 @@ const ManageTransferFeeContextProvider = ({ children }: { children: React.ReactN } > {children} - - diff --git a/src/pages/transfer/transfertype/TransferType.tsx b/src/pages/transfer/transfertype/TransferType.tsx index ab79eca..903669e 100644 --- a/src/pages/transfer/transfertype/TransferType.tsx +++ b/src/pages/transfer/transfertype/TransferType.tsx @@ -37,7 +37,7 @@ const TransferType = () => { - {/* */} + diff --git a/src/pages/transfer/transfertype/blocks/AddDialog.tsx b/src/pages/transfer/transfertype/blocks/AddDialog.tsx index bff4222..6e5f51f 100644 --- a/src/pages/transfer/transfertype/blocks/AddDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/AddDialog.tsx @@ -39,6 +39,7 @@ import { CommandItem, CommandList } from '@/components/ui/command'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; interface WalletProps { id: string; @@ -75,7 +76,6 @@ const AddDialog = () => { wallet_origin: '', wallet_destination: '', - minimum_amount: 0, maximum_amount: 0, max_transaction_per_day: 0, @@ -95,7 +95,6 @@ const AddDialog = () => { const parsedUser = getAuth()?.user; - // Updated validation function to make only certain fields required const validateForm = () => { const requiredFields = [ 'name', @@ -141,6 +140,13 @@ const AddDialog = () => { toast.success('Success Create Transfer Type'); reload(); resetForm(); + const createActivity = { + module: 'Manage Transfer Type', + description: `Create Transfer Type => ${formField.name}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); } }) .finally(() => { @@ -215,10 +221,10 @@ const AddDialog = () => { page: 1, with_deleted: false, order_field: 'wallets.name', - order_direction: 'ASC', + order_direction: 'ASC' }; const response = await GetData(`${API_URL_MASTERDATA}/wallet/list`, params); - console.log(response) + // console.log(response) if (response?.status && response?.data) { setWallets(response.data.list); } else { @@ -230,7 +236,7 @@ const AddDialog = () => { if (!showAddDialog) return; fetchWallets(); }, [showAddDialog]); - console.log(formField) + // console.log(formField) return ( handleAddDialog(open)}> @@ -258,11 +264,11 @@ const AddDialog = () => {
{alert.show && ( -
- -

{alert.message}

-
-
+
+ +

{alert.message}

+
+
)}
@@ -432,11 +438,10 @@ const AddDialog = () => {
-
@@ -453,12 +458,15 @@ const AddDialog = () => { Disbursement Other - Change Customer to Agent - Change Agent to Customer + Change Group Emoney Customer to Agent + Change Group Emoney Agent to Customer + Change Group Point Agent to Customer + Change Group Point Customer to Agent Return Customer Emoney Return Agent Deposit Return Agent Merchant Return Agent Emoney + Reward Point
diff --git a/src/pages/transfer/transfertype/blocks/DeleteDialog.tsx b/src/pages/transfer/transfertype/blocks/DeleteDialog.tsx index 19e4d78..ec35bf1 100644 --- a/src/pages/transfer/transfertype/blocks/DeleteDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/DeleteDialog.tsx @@ -1,4 +1,10 @@ -import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Alert, useDataGrid } from '@/components'; import { useCallback, useState } from 'react'; @@ -7,11 +13,13 @@ import { toast } from 'sonner'; import { useCallApi } from '@/hooks'; import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; import { DialogDescription } from '@radix-ui/react-dialog'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; const API_URL = apiConfig.service_transaction; const DeleteDialog = () => { - const { showDeleteDialog, handleDeleteDialog, selectedTransferType } = useManageTransferTypeContext(); + const { showDeleteDialog, handleDeleteDialog, selectedTransferType } = + useManageTransferTypeContext(); const { reload } = useDataGrid(); const { DeleteData } = useCallApi(); const [alert, setAlert] = useState({ @@ -25,14 +33,23 @@ const DeleteDialog = () => { return; } - const response = await DeleteData(`${API_URL}/transactiontype/delete/${selectedTransferType}/false`, { - id: selectedTransferType - }); + const response = await DeleteData( + `${API_URL}/transactiontype/delete/${selectedTransferType}/false`, + { + id: selectedTransferType + } + ); if (response?.status) { setAlert({ show: false, message: '' }); handleDeleteDialog(false, null); reload(); + const createActivity = { + module: 'Manage Transfer Type', + description: `Delete Transfer Type => ${selectedTransferType}`, + action: 'D' + }; + doSaveLogActivity(createActivity); // setTimeout(() => toast.success('Success Delete Transaction Type'), 0); } else { setAlert({ show: true, message: response?.message }); @@ -44,7 +61,9 @@ const DeleteDialog = () => { Delete Transfer Type - Are you sure you want to delete this data? + + Are you sure you want to delete this data? +

Are you sure?

You will delete this data! diff --git a/src/pages/transfer/transfertype/blocks/EditDialog.tsx b/src/pages/transfer/transfertype/blocks/EditDialog.tsx index db7e391..1e3ca41 100644 --- a/src/pages/transfer/transfertype/blocks/EditDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/EditDialog.tsx @@ -25,6 +25,8 @@ import { useCallApi } from '@/hooks'; import { getAuth } from '@/auth'; import { ManageTransferFeeContextProvider } from '../../transferfee/hooks/ManageTransferFeeContext'; import AddFeeDialog from '../../transferfee/blocks/AddDialog'; +import { EditFeeDialog } from '../../transferfee/blocks/EditDialog'; +import DeleteFeeDialog from '../../transferfee/blocks/DeleteDialog'; import { Checkbox } from '@/components/ui/checkbox'; import { doSaveLogActivity } from '@/actions/GlobalActions'; @@ -43,7 +45,7 @@ interface CustomerProps { msisdn: string; } -interface GroupProps { +interface PermissionObject { id: string; name: string; description: string; @@ -52,11 +54,10 @@ interface GroupProps { const EditDialog = () => { const parentRef = useRef(null); - const { showEditDialog, handleEditDialog, selectedTransferType } = - useManageTransferTypeContext(); + const { showEditDialog, handleEditDialog, selectedTransferType } = useManageTransferTypeContext(); const { reload } = useDataGrid(); const [wallets, setWallets] = useState([]); - const [groups, setGroups] = useState([]); + const [groups, setGroups] = useState([]); const { GetData, PutData } = useCallApi(); const [isSubmitting, setIsSubmitting] = useState(false); const parsedUser = getAuth()?.user; @@ -66,7 +67,7 @@ const EditDialog = () => { show: false, message: '' }); - + const initialState: { name: string; description: string; @@ -96,9 +97,9 @@ const EditDialog = () => { updated_by: '', updated_at: '' }; - + const [formField, setFormField] = useState(initialState); - + const resetForm = () => { setFormField(initialState); setSelectedGroups([]); @@ -110,13 +111,11 @@ const EditDialog = () => { const isSelected = prevState.permission.includes(groupId); if (isSelected) { - // Remove the permission if already selected return { ...prevState, permission: prevState.permission.filter((id) => id !== groupId) }; } else { - // Add the permission if not selected return { ...prevState, permission: [...prevState.permission, groupId] @@ -136,13 +135,13 @@ const EditDialog = () => { 'type' ]; - const missingFields = requiredFields.filter( - (field) => { - return formField[field as keyof typeof formField] === '' || - formField[field as keyof typeof formField] === null || - formField[field as keyof typeof formField] === undefined; - } - ); + const missingFields = requiredFields.filter((field) => { + return ( + formField[field as keyof typeof formField] === '' || + formField[field as keyof typeof formField] === null || + formField[field as keyof typeof formField] === undefined + ); + }); if (missingFields.length > 0) { setAlert({ @@ -152,7 +151,6 @@ const EditDialog = () => { return false; } - // Validate that at least one permission is selected if (formField.permission.length === 0) { setAlert({ show: true, @@ -177,12 +175,12 @@ const EditDialog = () => { })); } }, [showEditDialog, parsedUser]); - + const selectedPermissionNames = groups .filter((g) => formField.permission.includes(g.id)) .map((g) => g.name) .join(', '); - + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); setIsSubmitting(true); @@ -198,7 +196,7 @@ const EditDialog = () => { handleEditDialog(false, null); toast.success('Success Update Transfer Type'); reload(); - + const createActivity = { module: 'Manage Transfer Type', description: `Edit Transfer Type => ${selectedTransferType}`, @@ -212,13 +210,19 @@ const EditDialog = () => { setIsSubmitting(false); }); }; - + const doUpdateTransferType = useCallback(async () => { try { - const response = await PutData(`${API_URL}/transactiontype/update/${selectedTransferType}`, { - ...formField - }); - + const formDataToSend = { + ...formField, + permission: formField.permission.filter((id) => typeof id === 'string') + }; + + const response = await PutData( + `${API_URL}/transactiontype/update/${selectedTransferType}`, + formDataToSend + ); + if (response?.status) { setAlert({ show: false, message: '' }); return true; @@ -230,18 +234,15 @@ const EditDialog = () => { setAlert({ show: true, message: - error instanceof Error - ? error.message - : 'An error occurred while updating transfer type' + error instanceof Error ? error.message : 'An error occurred while updating transfer type' }); return false; } }, [formField, selectedTransferType, PutData]); - // Fetch customers useEffect(() => { if (!showEditDialog) return; - + const getCustomerList = async () => { try { const sorting = [{ id: 'id', desc: false }]; @@ -252,7 +253,7 @@ const EditDialog = () => { order_field: sorting[0].id, order_direction: sorting[0].desc ? 'DESC' : 'ASC' }); - + if (response?.status && response?.data) { setCustomers(response.data.list); } @@ -264,10 +265,9 @@ const EditDialog = () => { getCustomerList(); }, [showEditDialog, GetData]); - // Fetch groups useEffect(() => { if (!showEditDialog) return; - + const getGroupList = async () => { try { const response = await GetData(`${API_URL_MASTERDATA}/groups/list`, { @@ -277,7 +277,7 @@ const EditDialog = () => { order_field: 'name', order_direction: 'ASC' }); - + if (response?.status && response?.data) { setGroups(response.data.list); } @@ -289,20 +289,19 @@ const EditDialog = () => { getGroupList(); }, [showEditDialog, GetData]); - // Fetch wallets useEffect(() => { if (!showEditDialog) return; - + const getWalletList = async () => { try { const response = await GetData(`${API_URL_MASTERDATA}/wallet/list`, { limit: 100, page: 1, with_deleted: false, - order_field: 'wallets.name', - order_direction: 'ASC', + order_field: 'Wallets.name', + order_direction: 'ASC' }); - + if (response?.status && response?.data) { setWallets(response.data.list); } @@ -314,15 +313,28 @@ const EditDialog = () => { getWalletList(); }, [showEditDialog, GetData]); - // Fetch transaction type data useEffect(() => { if (!showEditDialog || !selectedTransferType) return; - + const fetchTransactionType = async () => { try { - const response = await GetData(`${API_URL}/transactiontype/getdata/${selectedTransferType}`, {}); - + const response = await GetData( + `${API_URL}/transactiontype/getdata/${selectedTransferType}`, + {} + ); + // console.log(response); if (response?.status) { + let permissionIds: string[] = []; + + if (Array.isArray(response.data.permission)) { + permissionIds = response.data.permission.map((perm: any) => { + if (typeof perm === 'object' && perm !== null) { + return perm.id; + } + return perm; + }); + } + setFormField((prev) => ({ ...prev, name: response.data.name, @@ -335,7 +347,7 @@ const EditDialog = () => { status_approval: response.data.status_approval, type: response.data.type || '', status: response.data.status, - permission: response.data.permission || [] + permission: permissionIds })); } } catch (error) { @@ -350,10 +362,9 @@ const EditDialog = () => { const timer = setTimeout(() => { fetchTransactionType(); }, 150); - + return () => clearTimeout(timer); }, [showEditDialog, selectedTransferType, GetData]); - useEffect(() => { if (showEditDialog === false) { resetForm(); @@ -564,7 +575,7 @@ const EditDialog = () => {
@@ -580,12 +591,15 @@ const EditDialog = () => { Disbursement Other - Change Customer to Agent - Change Agent to Customer + Change Group Emoney Customer to Agent + Change Group Emoney Agent to Customer + Change Group Point Agent to Customer + Change Group Point Customer to Agent Return Customer Emoney Return Agent Deposit Return Agent Merchant Return Agent Emoney + Reward Point
@@ -641,8 +655,7 @@ const EditDialog = () => {
- - {/* Group Permission Section - Read Only Display */} +
- +
-
- {/* Transaction Fee Section */} - +
+ +
@@ -714,4 +718,4 @@ const EditDialog = () => { ); }; -export { EditDialog }; \ No newline at end of file +export { EditDialog }; diff --git a/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx b/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx index 2fde89a..942ee8f 100644 --- a/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx +++ b/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx @@ -147,12 +147,28 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React meta: { headerClassName: 'w-[250px]' } }, { - accessorFn: (row) => row.type, + accessorFn: (row: { type: string }) => { + const mapping: Record = { + D: 'Disbursement', + O: 'Other', + CA: 'Change Group Emoney Customer to Agent', + AC: 'Change Group Emoney Agent to Customer', + PC: 'Change Group Point Agent to Customer', + PA: 'Change Group Point Customer to Agent', + CE: 'Return Customer Emoney', + AD: 'Return Agent Deposit', + AM: 'Return Agent Merchant', + AE: 'Return Agent Emoney', + R: 'Reward Point' + }; + + return mapping[row.type] || 'Unknown'; + }, id: 'type', header: ({ column }) => ( - + ), - enableSorting: false, + enableSorting: true, enableHiding: false, meta: { headerClassName: 'w-[250px]' } }, @@ -201,20 +217,19 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React ], [handleEditDialog, handleDeleteDialog] ); - + const doGetTransferTypeListData = async ( page: number, limit: number, sorting: any, filter: any ) => { - const orderField = 'created_at'; const orderDirection = sorting.length > 0 ? (sorting[0].desc ? 'DESC' : 'ASC') : 'DESC'; - + filter = filter.length == 0 ? {} : { any: filter[0].value?.toLowerCase() }; - + const response = await GetData(`${API_URL}/transactiontype/list`, { limit: limit, page: page + 1, @@ -223,7 +238,7 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React order_direction: orderDirection, filter: JSON.stringify(filter) }); - console.log(response?.data.list); + // console.log(response?.data.list); return { data: response?.data.list, totalCount: response?.data.total_count }; }; @@ -250,7 +265,7 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React pagination={{ size: 10 }} layout={{ card: true }} toolbar={} - sorting={[{ id: 'created_at', desc: true }]} // Default sorting + sorting={[{ id: 'created_at', desc: true }]} serverSide={true} onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => doGetTransferTypeListData(pageIndex, pageSize, sorting, columnFilters) @@ -265,4 +280,4 @@ const ManageTransferTypeContextProvider = ({ children }: { children: React.React }; export { ManageTransferTypeContext, ManageTransferTypeContextProvider }; -export type { TransferType }; \ No newline at end of file +export type { TransferType }; diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index b7ce41f..865effb 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -15,6 +15,7 @@ import ManagePositionPage from '@/pages/settings/user/manage-position/ManagePosi import ManageAccount from '@/pages/account/manage-account/ManageAccount'; import ManageGroups from '@/pages/groups/ManageGroups'; import ManageMembers from '@/pages/members/manage-members/ManageMembers'; +import ManageKycDeletion from '@/pages/members/kyc-delete-member/ManageKycDeletion'; import Kyc from '@/pages/members/kyc/Kyc'; import AccessType from '@/pages/access/access-type/AccessType'; import MemberCredential from '@/pages/access/member-credentials/MemberCredentials'; @@ -79,6 +80,7 @@ const AppRoutingSetup = (): ReactElement => { } /> } /> + } /> } /> } />