From 1f962e445197db3f2634f79248f3abe15b2c57c2 Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Mon, 14 Apr 2025 16:47:59 +0700 Subject: [PATCH] fixing transaction type + transaction fee --- .../transfer/transferfee/blocks/AddDialog.tsx | 262 +++--- .../transferfee/blocks/EditDialog.tsx | 5 + .../hooks/ManageTransferFeeContext.tsx | 755 +++++++++--------- .../transfertype/blocks/AddDialog.tsx | 24 +- .../transfertype/blocks/DeleteDialog.tsx | 7 + .../transfertype/blocks/EditDialog.tsx | 119 ++- .../hooks/ManageTransferTypeContext.tsx | 26 +- 7 files changed, 642 insertions(+), 556 deletions(-) diff --git a/src/pages/transfer/transferfee/blocks/AddDialog.tsx b/src/pages/transfer/transferfee/blocks/AddDialog.tsx index 271f4fe..45df2a9 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,11 +40,7 @@ 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; @@ -62,12 +58,19 @@ interface CustomerProps { 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: '' @@ -75,8 +78,16 @@ const AddFeeDialog = () => { const [transactionTypes, setTransactionTypes] = useState([]); const [wallets, setWallets] = useState([]); const [customers, setCustomers] = useState([]); - const [defaultCustomer, setDefaultCustomer] = 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: '', @@ -104,54 +115,57 @@ const AddFeeDialog = () => { 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, - fee_amount: formField.fee_amount, - transaction_type: formField.transaction_type, - status: formField.status, - status_include: formField.status_include, - priority: formField.priority, - deduct_from: formField.deduct_from, - deduct_from_account: formField.deduct_from_account, - credit_to: formField.credit_to, - credit_destination: formField.credit_destination, - credit_destination_account: formField.credit_destination_account - }; - }; + 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`, { @@ -164,13 +178,16 @@ const AddFeeDialog = () => { setTransactionTypes(response?.data.list || []); } catch (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, @@ -188,6 +205,8 @@ const AddFeeDialog = () => { } catch (error) { console.error('Error fetching wallets', error); setWallets([]); + } finally { + setIsLoadingWallets(false); } }, [GetData]); @@ -199,6 +218,7 @@ const AddFeeDialog = () => { useEffect(() => { if (!showAddFeeDialog) return; const getCustomerList = async (sorting: any) => { + setIsLoadingCustomers(true); try { sorting = sorting.length === 0 ? [{ id: 'name', desc: false }] : sorting; @@ -218,6 +238,8 @@ const AddFeeDialog = () => { } catch (error) { console.error('Error fetching customers', error); setCustomers([]); + } finally { + setIsLoadingCustomers(false); } }; @@ -254,7 +276,7 @@ const AddFeeDialog = () => { return; } } - + if (formField.credit_to === 'I' && !formField.credit_destination) { setAlert({ show: true, @@ -280,6 +302,13 @@ const AddFeeDialog = () => { 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' }); } @@ -293,6 +322,40 @@ const AddFeeDialog = () => { [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)}> @@ -325,6 +388,35 @@ const AddFeeDialog = () => {
+
+ + {transactionTypeId ? ( +
+ + {isLoadingTransactionType && ( +
+
+
+ Loading transaction type... +
+
+ )} +
+ ) : ( + renderSelectWithLoading( + formField.transaction_type, + (transaction_type) => setFormField((prev) => ({ ...prev, transaction_type })), + transactionTypes, + "Select Transaction Type", + isLoadingTransactionType + ) + )} +
{
- + {renderSelectWithLoading( + formField.deduct_from_account, + (value) => setFormField({ ...formField, deduct_from_account: value }), + wallets, + "Select Wallet", + isLoadingWallets + )}
@@ -514,60 +598,24 @@ const AddFeeDialog = () => { {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 + )}
@@ -624,7 +672,11 @@ const AddFeeDialog = () => { > Reset -
diff --git a/src/pages/transfer/transferfee/blocks/EditDialog.tsx b/src/pages/transfer/transferfee/blocks/EditDialog.tsx index 13ccfe2..6123f3f 100644 --- a/src/pages/transfer/transferfee/blocks/EditDialog.tsx +++ b/src/pages/transfer/transferfee/blocks/EditDialog.tsx @@ -167,6 +167,11 @@ const EditFeeDialog = () => { toast.success('Successfully updated transfer fee'); reload(); handleEditFeeDialog(false, null); + const createActivity = { + module: 'Manage Transfer Type', + description: `Edit Transfer Type => ${selectedTransferFee}`, + action: 'U' + }; } else { setAlert({ show: true, message: response?.message || 'Failed to update transfer fee' }); } diff --git a/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx b/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx index df14f82..15b650f 100644 --- a/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx +++ b/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx @@ -1,388 +1,391 @@ -import { DataGridColumnHeader, DataGridProvider, KeenIcon } from '@/components'; -import { Toaster } from '@/components/ui/sonner'; -import { apiConfig } from '@/config/api.config'; -import { useCallApi } from '@/hooks'; -import { ColumnDef } from '@tanstack/react-table'; -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'; + import { DataGridColumnHeader, DataGridProvider, KeenIcon } from '@/components'; + import { Toaster } from '@/components/ui/sonner'; + import { apiConfig } from '@/config/api.config'; + import { useCallApi } from '@/hooks'; + import { ColumnDef } from '@tanstack/react-table'; + 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; - handleEditFeeDialog: (show: boolean, selected_TransferFee: string | null) => void; - showAddFeeDialog: boolean; - handleAddFeeDialog: (show: boolean) => void; - handleDeleteFeeDialog: (show: boolean, selected_TransferFee: string | null) => void; - showDeleteFeeDialog: boolean; - selectedTransferFee: string | null; -} + interface ContextProps { + showEditFeeDialog: boolean; + handleEditFeeDialog: (show: boolean, selected_TransferFee: string | null) => void; + showAddFeeDialog: boolean; + handleAddFeeDialog: (show: boolean) => void; + handleDeleteFeeDialog: (show: boolean, selected_TransferFee: string | null) => void; + showDeleteFeeDialog: boolean; + selectedTransferFee: string | null; + transactionTypeId: string | null; -const initialProps: ContextProps = { - showEditFeeDialog: false, - handleEditFeeDialog: () => {}, - showAddFeeDialog: false, - handleAddFeeDialog: () => {}, - showDeleteFeeDialog: false, - handleDeleteFeeDialog: () => {}, - selectedTransferFee: 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 initialProps: ContextProps = { + showEditFeeDialog: false, + handleEditFeeDialog: () => {}, + showAddFeeDialog: false, + handleAddFeeDialog: () => {}, + showDeleteFeeDialog: false, + handleDeleteFeeDialog: () => {}, + selectedTransferFee: null, + transactionTypeId: null, -const ManageTransferFeeContext = createContext(initialProps); -const API_URL = apiConfig.service_transaction; - -const ManageTransferFeeContextProvider = ({ children }: { children: React.ReactNode }) => { - 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); - }, []); - - const handleAddFeeDialog = useCallback((show: boolean) => { - setShowAddFeeDialog(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 - ) => { - 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[]>( - () => [ - { - accessorFn: (row) => row.name, - id: 'name', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { headerClassName: 'w-[200px]' } - }, - { - accessorFn: (row) => row.description, - id: 'description', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { headerClassName: 'w-[250px]' } - }, - { - accessorFn: (row) => row.minimum_amount, - id: 'minimum_amount', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { headerClassName: 'w-[150px]' } - }, - { - accessorFn: (row) => row.maximum_amount, - id: 'maximum_amount', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { headerClassName: 'w-[150px]' } - }, - { - accessorFn: (row) => row.fee_amount, - id: 'fee_amount', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { headerClassName: 'w-[150px]' } - }, - { - accessorFn: (row) => row.deduct_amount, - id: 'deduct_amount', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { headerClassName: 'w-[150px]' } - }, - { - accessorFn: (row) => row.deduct_percentage, - id: 'deduct_percentage', - header: ({ column }) => , - enableSorting: true, - 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', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { headerClassName: 'w-[250px]' } - }, - { - 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, - cell: ({ row }) => { - const isActive = row.original.priority === 'Y'; - - return ( - - {isActive ? 'Yes' : 'No'} - - ); - }, - meta: { - headerClassName: 'w-[100px]', - cellClassName: 'text-center' - } - }, - { - accessorFn: (row) => row.status, - id: 'status', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - cell: ({ row }) => { - const isActive = row.original.status === 'Y'; - return ( - - {isActive ? 'Active' : 'Inactive'} - - ); - }, - meta: { - headerClassName: 'w-[100px]', - cellClassName: 'text-center' - } - }, - { - accessorFn: (row) => row.status_include, - id: 'status_include', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - cell: ({ row }) => { - const isActive = row.original.status_include === 'Y'; + 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; + } - return ( - - {isActive ? 'Yes' : 'No'} - - ); - }, - meta: { - headerClassName: 'w-[100px]', - cellClassName: 'text-center' - } - }, - { - id: 'actions', - header: ({ column }) => , - enableSorting: false, - enableHiding: false, - cell: (data) => { - const row = data.row.original; - return ( - <> - - - - ); - }, - meta: { - headerClassName: 'w-[100px]', - cellClassName: 'text-center' - } + const ManageTransferFeeContext = createContext(initialProps); + const API_URL = apiConfig.service_transaction; + + 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); + }, []); + + const handleAddFeeDialog = useCallback((show: boolean) => { + setShowAddFeeDialog(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 + ) => { + if (!selectedTransferType) { + return { data: [], totalCount: 0 }; } - ], - [handleEditFeeDialog, handleDeleteFeeDialog] - ); - - return ( -
-
-

Manage Transaction Fee

-
- - - } - sorting={[{ id: 'id', desc: true }]} - serverSide={true} - onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => - doGetTransferFeeListData(pageIndex, pageSize, sorting, columnFilters) + + 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[]>( + () => [ + { + accessorFn: (row) => row.name, + id: 'name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[200px]' } + }, + { + accessorFn: (row) => row.description, + id: 'description', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.minimum_amount, + id: 'minimum_amount', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[150px]' } + }, + { + accessorFn: (row) => row.maximum_amount, + id: 'maximum_amount', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[150px]' } + }, + { + accessorFn: (row) => row.fee_amount, + id: 'fee_amount', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[150px]' } + }, + { + accessorFn: (row) => row.deduct_amount, + id: 'deduct_amount', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[150px]' } + }, + { + accessorFn: (row) => row.deduct_percentage, + id: 'deduct_percentage', + header: ({ column }) => , + enableSorting: true, + 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', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + 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, + cell: ({ row }) => { + const isActive = row.original.priority === 'Y'; + + return ( + + {isActive ? 'Yes' : 'No'} + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' } + }, + { + accessorFn: (row) => row.status, + id: 'status', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + cell: ({ row }) => { + const isActive = row.original.status === 'Y'; + + return ( + + {isActive ? 'Active' : 'Inactive'} + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + }, + { + accessorFn: (row) => row.status_include, + id: 'status_include', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + cell: ({ row }) => { + const isActive = row.original.status_include === 'Y'; + + return ( + + {isActive ? 'Yes' : 'No'} + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + }, + { + id: 'actions', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + cell: (data) => { + const row = data.row.original; + return ( + <> + + + + ); + }, + meta: { + headerClassName: 'w-[100px]', + cellClassName: 'text-center' + } + } + ], + [handleEditFeeDialog, handleDeleteFeeDialog] + ); + + return ( +
+
+

Manage Transaction Fee

+
+ - {children} + + } + sorting={[{ id: 'id', desc: true }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + doGetTransferFeeListData(pageIndex, pageSize, sorting, columnFilters) + } + > + {children} - - -
- ); -}; +
+
+
+ ); + }; -export { ManageTransferFeeContext, ManageTransferFeeContextProvider }; + export { ManageTransferFeeContext, ManageTransferFeeContextProvider }; diff --git a/src/pages/transfer/transfertype/blocks/AddDialog.tsx b/src/pages/transfer/transfertype/blocks/AddDialog.tsx index bff4222..6d35adc 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; @@ -95,7 +96,6 @@ const AddDialog = () => { const parsedUser = getAuth()?.user; - // Updated validation function to make only certain fields required const validateForm = () => { const requiredFields = [ 'name', @@ -141,6 +141,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(() => { @@ -218,7 +225,7 @@ const AddDialog = () => { 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 +237,7 @@ const AddDialog = () => { if (!showAddDialog) return; fetchWallets(); }, [showAddDialog]); - console.log(formField) + // console.log(formField) return ( handleAddDialog(open)}> @@ -436,7 +443,7 @@ const AddDialog = () => {
@@ -451,14 +458,17 @@ const AddDialog = () => { - Disbursement + 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..e4c51ad 100644 --- a/src/pages/transfer/transfertype/blocks/DeleteDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/DeleteDialog.tsx @@ -7,6 +7,7 @@ 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; @@ -33,6 +34,12 @@ const DeleteDialog = () => { 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 }); diff --git a/src/pages/transfer/transfertype/blocks/EditDialog.tsx b/src/pages/transfer/transfertype/blocks/EditDialog.tsx index 0039649..c4b9e8f 100644 --- a/src/pages/transfer/transfertype/blocks/EditDialog.tsx +++ b/src/pages/transfer/transfertype/blocks/EditDialog.tsx @@ -54,8 +54,7 @@ interface PermissionObject { 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([]); @@ -68,7 +67,7 @@ const EditDialog = () => { show: false, message: '' }); - + const initialState: { name: string; description: string; @@ -98,9 +97,9 @@ const EditDialog = () => { updated_by: '', updated_at: '' }; - + const [formField, setFormField] = useState(initialState); - + const resetForm = () => { setFormField(initialState); setSelectedGroups([]); @@ -112,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] @@ -138,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({ @@ -154,7 +151,6 @@ const EditDialog = () => { return false; } - // Validate that at least one permission is selected if (formField.permission.length === 0) { setAlert({ show: true, @@ -179,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); @@ -200,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}`, @@ -214,17 +210,19 @@ const EditDialog = () => { setIsSubmitting(false); }); }; - + const doUpdateTransferType = useCallback(async () => { try { - // Create a clean copy of the form data with properly formatted permissions const formDataToSend = { ...formField, - permission: formField.permission.filter(id => typeof id === 'string') + permission: formField.permission.filter((id) => typeof id === 'string') }; - - const response = await PutData(`${API_URL}/transactiontype/update/${selectedTransferType}`, formDataToSend); - + + const response = await PutData( + `${API_URL}/transactiontype/update/${selectedTransferType}`, + formDataToSend + ); + if (response?.status) { setAlert({ show: false, message: '' }); return true; @@ -236,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 }]; @@ -258,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); } @@ -270,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`, { @@ -283,7 +277,7 @@ const EditDialog = () => { order_field: 'name', order_direction: 'ASC' }); - + if (response?.status && response?.data) { setGroups(response.data.list); } @@ -295,10 +289,9 @@ const EditDialog = () => { getGroupList(); }, [showEditDialog, GetData]); - // Fetch wallets useEffect(() => { if (!showEditDialog) return; - + const getWalletList = async () => { try { const response = await GetData(`${API_URL_MASTERDATA}/wallet/list`, { @@ -306,9 +299,9 @@ const EditDialog = () => { page: 1, with_deleted: false, order_field: 'Wallets.name', - order_direction: 'ASC', + order_direction: 'ASC' }); - + if (response?.status && response?.data) { setWallets(response.data.list); } @@ -320,28 +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}`, {}); - console.log(response); + const response = await GetData( + `${API_URL}/transactiontype/getdata/${selectedTransferType}`, + {} + ); + // console.log(response); if (response?.status) { - // Process permissions to ensure they're always string IDs let permissionIds: string[] = []; - + if (Array.isArray(response.data.permission)) { permissionIds = response.data.permission.map((perm: any) => { - // Check if permission is an object or string if (typeof perm === 'object' && perm !== null) { return perm.id; } return perm; }); } - + setFormField((prev) => ({ ...prev, name: response.data.name, @@ -354,7 +347,7 @@ const EditDialog = () => { status_approval: response.data.status_approval, type: response.data.type || '', status: response.data.status, - permission: permissionIds + permission: permissionIds })); } } catch (error) { @@ -365,11 +358,11 @@ const EditDialog = () => { }); } }; - + const timer = setTimeout(() => { fetchTransactionType(); }, 150); - + return () => clearTimeout(timer); }, [showEditDialog, selectedTransferType, GetData]); useEffect(() => { @@ -582,7 +575,7 @@ const EditDialog = () => {
@@ -596,14 +589,17 @@ const EditDialog = () => { - Disbursement + 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
@@ -659,8 +655,7 @@ const EditDialog = () => {
- - {/* Group Permission Section - Read Only Display */} +
- +
- {/* Transaction Fee Section */} - +
- - + +
@@ -725,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..84a1287 100644 --- a/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx +++ b/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx @@ -147,15 +147,31 @@ 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]' } - }, + }, { accessorFn: (row) => (row.status === 'Y' ? 'Active' : 'Inactive'), id: 'status', @@ -223,7 +239,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 }; };