From 03e670ef096c266bb511de4928dd68a393dbd773 Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Tue, 4 Mar 2025 16:16:10 +0700 Subject: [PATCH 1/4] Form transfertype + transactionFee --- .gitignore | 2 + src/pages/transfer/blocks/AddDialog.tsx | 120 +++++++- .../transfer/blocks/TransactionFeeDialog.tsx | 281 ++++++++++++++++++ 3 files changed, 395 insertions(+), 8 deletions(-) create mode 100644 src/pages/transfer/blocks/TransactionFeeDialog.tsx diff --git a/.gitignore b/.gitignore index 4e80c27..5a3db31 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,8 @@ yarn-debug.log* yarn-error.log* pnpm-debug.log* lerna-debug.log* +yarn.lock + node_modules dist diff --git a/src/pages/transfer/blocks/AddDialog.tsx b/src/pages/transfer/blocks/AddDialog.tsx index 300425e..a7abdf1 100644 --- a/src/pages/transfer/blocks/AddDialog.tsx +++ b/src/pages/transfer/blocks/AddDialog.tsx @@ -1,5 +1,5 @@ import { apiConfig } from '@/config/api.config'; -import { useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; import { Alert, KeenIcon, useDataGrid } from '@/components'; import { useCallApi } from '@/hooks'; @@ -20,6 +20,10 @@ import { SelectValue } from '@/components/ui/select'; import { Button } from '@/components/ui/button'; +import TransactionFeeDialog from './TransactionFeeDialog'; +import { toast } from 'sonner'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { getAuth } from '@/auth'; interface CreateTransferTypeParams { transfer_type_name: string; @@ -30,6 +34,9 @@ interface CreateTransferTypeParams { maximum_amount: number; otp_threshold: number; maximum_transaction_perDay: number; + status: string; + created_by: string; + created_at: string; } const API_URL = apiConfig.service_dashboard; @@ -52,14 +59,21 @@ const AddDialog = () => { minimal_amount: 0, maximum_amount: 0, otp_threshold: 0, - maximum_transaction_perDay: 0 + maximum_transaction_perDay: 0, + status: '', + created_by: '', + created_at: '' }; const [formField, setFormField] = useState(initialState); + const resetForm = () => { setFormField(initialState); }; + const [isSubmitting, setIsSubmitting] = useState(false); + const [showTransactionFeeDialog, setShowTransactionFeeDialog] = useState(false); + const parsedUser = getAuth()?.user; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); @@ -76,16 +90,72 @@ const AddDialog = () => { }; console.log(payload); }; + useEffect(() => { + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + + if (showAddDialog) { + setFormField({ + ...formField, + created_by: parsedUser?.username, + created_at: formattedTime + }); + } + }, [showAddDialog]); + const doCreateTransferType = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + console.log(formField); + + for (const key in formField) { + if ( + formField[key as keyof typeof formField] === '' || + formField[key as keyof typeof formField] === 0 + ) { + setAlert({ show: true, message: 'All fields must be filled out' }); + return; + } + } + + setAlert({ show: false, message: '' }); + const response = await PostData(`${API_URL}/transactiontype/create`, formField); + + if (response?.status) { + setAlert({ show: false, message: '' }); + handleAddDialog(false); + toast.success('Success Create Transfer Type'); + reload(); + resetForm(); + + const createActivity = { + module: 'Manage Transfer Type', + description: `Create New Transfer Type => ${formField.transfer_type_name}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); + } else { + setAlert({ show: true, message: response?.message || 'Failed to create transfer type' }); + } + + handleAddDialog(false); + }, + [formField] + ); + const handleTransactionFeeSubmit = (data: any) => { + // console.log('Transaction Fee Data Submitted:', data); + setShowTransactionFeeDialog(false); + }; return ( handleAddDialog(open)}> + +
-

- Create Transfer Type -

+

Transfer Type

{

{alert.message}

)} -
+
@@ -273,17 +343,51 @@ const AddDialog = () => { />
+
+
+ + +
+ +
+
+
+ -
+ setShowTransactionFeeDialog(false)} + onSubmit={handleTransactionFeeSubmit} + />
diff --git a/src/pages/transfer/blocks/TransactionFeeDialog.tsx b/src/pages/transfer/blocks/TransactionFeeDialog.tsx new file mode 100644 index 0000000..cccf165 --- /dev/null +++ b/src/pages/transfer/blocks/TransactionFeeDialog.tsx @@ -0,0 +1,281 @@ +import { useState, useCallback, useEffect } from 'react'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; +import Typography from '@mui/material/Typography'; +import { toast } from 'sonner'; +import { apiConfig } from '@/config/api.config'; +import { useCallApi } from '@/hooks'; +import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; +import { get } from 'http'; +import { getAuth } from '@/auth'; +import { useDataGrid } from '@/components'; +import { set } from 'date-fns'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectItem +} from '@/components/ui/select'; + +interface TransactionFeeDialogProps { + open: boolean; + onClose: () => void; + onSubmit: (data: TransactionFeeForm) => void; +} + +interface TransactionFeeForm { + name: string; + description: string; + minimum_amount: number; + maximum_amount: number; + period_start: string; + period_end: string; + deduct_amount: number; + deduct_percentage: number; + priority: string; + status: string; + transactionTypeId: string; + created_by: string; + created_at: string; +} + +const API_URL = apiConfig.service_dashboard; + +const TransactionFeeDialog: React.FC = ({ open, onClose, onSubmit }) => { + const { showAddDialog, handleAddDialog } = useManageTransferTypeContext(); + const parsedUser = getAuth()?.user; + const [formField, setFormField] = useState({ + name: '', + description: '', + minimum_amount: 0, + maximum_amount: 0, + period_start: '', + period_end: '', + deduct_amount: 0, + deduct_percentage: 0, + priority: '', + status: '', + transactionTypeId: '', + created_by: '', + created_at: '' + }); + const { PostData, PutData } = useCallApi(); + const handleChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + setFormField((prev) => ({ + ...prev, + [name]: value + })); + }; + const [isSubmitting, setIsSubmitting] = useState(false); + const { reload } = useDataGrid(); + const resetForm = () => { + setFormField(formField); + }; + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + useEffect(() => { + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + + if (showAddDialog) { + setFormField({ + ...formField, + created_by: parsedUser?.username, + created_at: formattedTime + }); + } + }, [showAddDialog]); + const doCreateTransactionFee = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + console.log(formField); + const response = await PostData(`${API_URL}/transactionfees/create`, formField); + + if (response?.status) { + setAlert({ show: false, message: '' }); + handleAddDialog(false); + toast.success('Success Create Transfer Type'); + reload(); + resetForm(); + + const createActivity = { + module: 'Manage Transfer Fee', + description: `Create New Transfer Fee => ${formField.name}`, + action: 'C' + }; + + doSaveLogActivity(createActivity); + } else { + setAlert({ show: true, message: response?.message || 'Failed to create transfer fee' }); + } + + onSubmit(formField); + }, + [formField] + ); + + return ( + + + + Transaction Fee + + + +
+
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + { + const value = e.target.value; + if (/^\d*$/.test(value)) { + handleChange(e); + } + }} + required + type="text" + inputMode="numeric" + placeholder="Masukkan angka" + /> +
+
+ + +
+ +
+ + +
+
+
+
+
+
+ ); +}; + +export default TransactionFeeDialog; From 5422ce938172ef70350f02548a0af307f3830652 Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Mon, 24 Mar 2025 09:55:20 +0700 Subject: [PATCH 2/4] butuh install packagee react number format --- .../transfer/transferfee/blocks/AddDialog.tsx | 411 ++++++++++++++ .../transferfee/blocks/DeleteDialog.tsx | 87 +++ .../transferfee/blocks/EditDialog.tsx | 499 +++++++++++++++++ .../transferfee/blocks/ListToolBar.tsx | 44 ++ .../hooks/ManageTransferFeeContext.tsx | 236 ++++++++ .../hooks/useManageTransferFeeContext.tsx | 12 + .../transfer/transfertype/TransferType.tsx | 27 + .../transfertype/blocks/AddDialog.tsx | 490 ++++++++++++++++ .../transfertype/blocks/DeleteDialog.tsx | 92 +++ .../transfertype/blocks/EditDialog.tsx | 525 ++++++++++++++++++ .../transfertype/blocks/ListToolBar.tsx | 44 ++ .../hooks/ManageTransferTypeContext.tsx | 254 +++++++++ .../hooks/useManageTransferTypeContext.tsx | 12 + 13 files changed, 2733 insertions(+) create mode 100644 src/pages/transfer/transferfee/blocks/AddDialog.tsx create mode 100644 src/pages/transfer/transferfee/blocks/DeleteDialog.tsx create mode 100644 src/pages/transfer/transferfee/blocks/EditDialog.tsx create mode 100644 src/pages/transfer/transferfee/blocks/ListToolBar.tsx create mode 100644 src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx create mode 100644 src/pages/transfer/transferfee/hooks/useManageTransferFeeContext.tsx create mode 100644 src/pages/transfer/transfertype/TransferType.tsx create mode 100644 src/pages/transfer/transfertype/blocks/AddDialog.tsx create mode 100644 src/pages/transfer/transfertype/blocks/DeleteDialog.tsx create mode 100644 src/pages/transfer/transfertype/blocks/EditDialog.tsx create mode 100644 src/pages/transfer/transfertype/blocks/ListToolBar.tsx create mode 100644 src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx create mode 100644 src/pages/transfer/transfertype/hooks/useManageTransferTypeContext.tsx diff --git a/src/pages/transfer/transferfee/blocks/AddDialog.tsx b/src/pages/transfer/transferfee/blocks/AddDialog.tsx new file mode 100644 index 0000000..dc7ecd7 --- /dev/null +++ b/src/pages/transfer/transferfee/blocks/AddDialog.tsx @@ -0,0 +1,411 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useManageTransferFeeContext } from '../hooks/useManageTransferFeeContext'; +import { NumericFormat } from 'react-number-format'; +import { + Alert, + Container, + DataGridColumnHeader, + DataGridInner, + KeenIcon, + useDataGrid +} from '@/components'; +import { useCallApi } from '@/hooks'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; +import { Button } from '@/components/ui/button'; +import { toast } from 'sonner'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { getAuth } from '@/auth'; +import { + Table, + TableBody, + TableCaption, + TableCell, + TableFooter, + TableHead, + 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; +} + +const API_URL = apiConfig.service_transaction; + +const AddFeeDialog = () => { + const parentRef = useRef(null); + const { reload } = useDataGrid(); + const { PostData, PutData, GetData } = useCallApi(); + const { showAddFeeDialog, handleAddFeeDialog, handleEditFeeDialog, selectedTransferFee } = + useManageTransferFeeContext(); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const [transactionTypes, setTransactionTypes] = useState([]); + + const initialState = { + name: '', + description: '', + transaction_type: '', + minimum_amount: 0, + maximum_amount: 0, + period_start: '', + period_end: '', + deduct_amount: 0, + deduct_percentage: 0, + priority: false, + status: '', + status_include: '', + created_by: '', + created_at: '' + }; + + const [formField, setFormField] = useState(initialState); + + const resetForm = () => { + setFormField(initialState); + }; + + 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, + priority: formField.priority, + transaction_type: formField.transaction_type, + status: formField.status, + status_include: formField.status_include + }; + console.log(payload); + }; + useEffect(() => { + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + + if (showAddFeeDialog) { + setFormField({ + ...formField, + created_by: parsedUser?.username, + created_at: formattedTime + }); + } + }, [showAddFeeDialog]); + + useEffect(() => { + if (!showAddFeeDialog) return; + + const getTransactionTypeList = async (sorting: any) => { + try { + sorting = sorting.length === 0 ? [{ id: 'name', desc: false }] : sorting; + const response = await GetData(`${API_URL}/transactiontype/list`, { + limit: 100, + page: 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc ? 'DESC' : 'ASC' + }); + console.log('TRANSACTION TYPE LIST: ', response?.data?.list); + + setTransactionTypes(response?.data.list || []); + } catch (error) { + console.error('Error fetching customer', error); + } + }; + + getTransactionTypeList([{ id: 'id', desc: false }]); + }, [showAddFeeDialog]); + + const doCreateTransferType = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + console.log(formField); + for (const key in formField) { + if ( + formField[key as keyof typeof formField] === '' || + formField[key as keyof typeof formField] === 0 + ) { + setAlert({ show: true, message: 'All fields must be filled out' }); + return; + } + } + + setAlert({ show: false, message: '' }); + const response = await PostData(`${API_URL}/transactionfees/create`, { + ...formField, + priority: formField.priority ? 'Y' : 'N' + }); + // console.log("coba coba:",response); + + 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' }); + } + console.log(response); + }, + [formField] + ); + + return ( + handleAddFeeDialog(open)}> + + + + +
+
+

AddTransfer Fee

+
+
{ + handleAddFeeDialog(false); + resetForm(); + }} + > + +
+
+
+ + {alert.show && {alert.message}} +
+
+
+
+ + + setFormField((prev) => ({ ...prev, name: target.value })) + } + /> +
+
+ + + setFormField((prev) => ({ ...prev, description: target.value })) + } + /> +
+
+ + { + setFormField((prev) => ({ + ...prev, + minimum_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Max Transaction Per Day" + /> +
+
+ + { + setFormField((prev) => ({ + ...prev, + maximum_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Max Transaction Per Day" + /> +
+
+ + + setFormField((prev) => ({ ...prev, period_start: target.value })) + } + /> +
+
+ + + setFormField((prev) => ({ ...prev, period_end: target.value })) + } + /> +
+
+ + { + setFormField((prev) => ({ + ...prev, + deduct_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Max Transaction Per Day" + /> +
+
+ + { + setFormField((prev) => ({ + ...prev, + deduct_percentage: values.floatValue || 0 + })); + }} + placeholder="Enter Max Transaction Per Day" + /> +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+
+
+
+ ); +}; + +export default AddFeeDialog; diff --git a/src/pages/transfer/transferfee/blocks/DeleteDialog.tsx b/src/pages/transfer/transferfee/blocks/DeleteDialog.tsx new file mode 100644 index 0000000..bf61c83 --- /dev/null +++ b/src/pages/transfer/transferfee/blocks/DeleteDialog.tsx @@ -0,0 +1,87 @@ +import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { Button } from '@/components/ui/button'; +import { Alert, useDataGrid } from '@/components'; +import { ChangeEvent, useCallback, useState } from 'react'; +import { apiConfig } from '@/config/api.config'; +import { toast } from 'sonner'; +import { useCallApi } from '@/hooks'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { EnforceSwitch } from '@/components/switch'; +import { useContext } from 'react'; +import { useManageTransferFeeContext } from '../hooks/useManageTransferFeeContext'; +import { ManageTransferFeeContext } from '../hooks/ManageTransferFeeContext'; +import { DialogDescription } from '@radix-ui/react-dialog'; +import { useManageAccessTypeContext } from '@/pages/access/access-type/hooks/useManageAccessTypeContext'; + +const API_URL = apiConfig.service_transaction; + +const DeleteDialog = () => { + const { showDeleteFeeDialog, handleDeleteFeeDialog, selectedTransferFee } = useManageTransferFeeContext(); + const { reload } = useDataGrid(); + const { DeleteData } = useCallApi(); + const [enforce, setEnforce] = useState(false); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + const doDeleteTransferFee = useCallback(async () => { + console.log("Selected Transfer Fee:", selectedTransferFee, "Type:", typeof selectedTransferFee); + const response = await DeleteData(`${API_URL}/transactionfees/delete/${selectedTransferFee}/${enforce}`, { + id: selectedTransferFee + }); + + if (response?.status) { + setAlert((prev) => ({ ...prev, show: false, message: '' })); + handleDeleteFeeDialog(false, null); + toast.success('Success Delete Product'); + reload(); + } else { + toast.error('Failed Delete Product'); + setAlert((prev) => ({ ...prev, show: true, message: response?.message })); + } + }, [selectedTransferFee, enforce]); + + // console.log(selectedTransferFee); + + return ( + handleDeleteFeeDialog(open, null)}> + + + Delete Transfer Type + Delete Transfer Type + +

Are you sure?

+ you will delete this data! +
+ + ) => { + setEnforce(e.target.checked); + }} + /> +
+
+ {alert.show && ( + +

{alert.message}

+
+ )} +
+ + + + +
+
+ ); +}; + +export default DeleteDialog; + +export { DeleteDialog }; diff --git a/src/pages/transfer/transferfee/blocks/EditDialog.tsx b/src/pages/transfer/transferfee/blocks/EditDialog.tsx new file mode 100644 index 0000000..89ee86c --- /dev/null +++ b/src/pages/transfer/transferfee/blocks/EditDialog.tsx @@ -0,0 +1,499 @@ +import { useCallback, useEffect, useRef, useState } from 'react'; +import { NumericFormat } from 'react-number-format'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; + +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { useManageTransferFeeContext } from '../hooks/useManageTransferFeeContext'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; +import { apiConfig } from '@/config/api.config'; +import { Alert, Container, DataGridInner, KeenIcon, useDataGrid } from '@/components'; +import { toast } from 'sonner'; +import { useCallApi } from '@/hooks'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { getAuth } from '@/auth'; +import { ManageTransferFeeContextProvider } from '../../transferfee/hooks/ManageTransferFeeContext'; +import AddFeeDialog from '../../transferfee/blocks/AddDialog'; + +const API_URL = apiConfig.service_transaction; +const API_URL_MASTERDATA = apiConfig.service_master_data; +const API_URL_CUSTOMER = apiConfig.service_customer; + +interface WalletProps { + Wallet_id: string; + Wallet_name: string; +} + +interface CustomerProps { + id: string; + username: string; + msisdn: string; +} + +interface TransactionTypeProps { + id: string; + name: string; +} + +const EditFeeDialog = () => { + const parentRef = useRef(null); + const { showEditFeeDialog, handleEditFeeDialog, selectedTransferFee } = + useManageTransferFeeContext(); + const { reload } = useDataGrid(); + const [wallets, setWallets] = useState([]); + const { GetData, PutData } = useCallApi(); + const [isSubmitting, setIsSubmitting] = useState(false); + const [transactionTypes, setTransactionTypes] = useState([]); + const parsedUser = getAuth()?.user; + const [customers, setCustomers] = useState([]); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const [formField, setFormField] = useState({ + name: '', + description: '', + minimum_amount: 0, + maximum_amount: 0, + period_start: '', + period_end: '', + deduct_amount: 0, + deduct_percentage: 0, + priority: '', + status: '', + status_include: '', + transaction_type: '', + updated_by: '', + updated_at: '' + }); + useEffect(() => { + const updated_time = new Date(); + const formattedTime = updated_time.toISOString().slice(0, 19).replace('T', ' '); + + if (showEditFeeDialog) { + setFormField({ + ...formField, + updated_by: parsedUser?.username, + updated_at: formattedTime + }); + } + }, [showEditFeeDialog]); + /* actions */ + const doUpdateTransferFee = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + const response = await PutData(`${API_URL}/transactionfees/update/${selectedTransferFee}`, { + ...formField + }); + if (response?.status) { + handleEditFeeDialog(false, null); + toast.success('Success Update User'); + reload(); + } else { + setAlert((prev) => ({ ...prev, show: true, message: response?.message })); + } + console.log(formField); + }, + [formField, selectedTransferFee] + ); + const fetchWallets = useCallback(async () => { + const params = { + limit: 100, + page: 1, + with_deleted: false, + order_field: 'name', + order_direction: 'ASC', + filter: JSON.stringify({ + status: 'Y' + }) + }; + const response = await GetData(`${API_URL_MASTERDATA}/wallet/list`, params); + if (response?.status && response?.data) { + setWallets(response.data.list); + } else { + setWallets([]); + } + }, []); + + useEffect(() => { + fetchWallets(); + }, [fetchWallets]); + + useEffect(() => { + if (!showEditFeeDialog) return; + + 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 ? 'DESC' : 'ASC' + }); + + // 🟡 Log daftar pelanggan saja (kalau respons pakai struktur {data: {list: [...]}}) + console.log('CUSTOMER LIST: ', response?.data?.list); + + setCustomers(response?.data.list || []); + } catch (error) { + console.error('Error fetching customer', error); + } + }; + + getCustomerList([{ id: 'msisdn', desc: false }]); + }, []); + useEffect(() => { + if (!showEditFeeDialog) return; + + const getTransactionTypeList = async (sorting: any) => { + try { + sorting = sorting.length === 0 ? [{ id: 'name', desc: false }] : sorting; + const response = await GetData(`${API_URL}/transactiontype/list`, { + limit: 100, + page: 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc ? 'DESC' : 'ASC' + }); + + // 🟡 Log daftar pelanggan saja (kalau respons pakai struktur {data: {list: [...]}}) + console.log('TRANSACTION TYPE LIST: ', response?.data?.list); + + setTransactionTypes(response?.data.list || []); + } catch (error) { + console.error('Error fetching customer', error); + } + }; + + getTransactionTypeList([{ id: 'id', desc: false }]); + }, [showEditFeeDialog]); + + const fetchTransactionFee = useCallback(async (id: string) => { + const response = await GetData(`${API_URL}/transactionfees/getdata/${id}`, { id }); + // console.log("API Response:", response); + + if (response?.status) { + setFormField((prev) => ({ + ...prev, + name: response.data.name, + description: response.data.description, + minimum_amount: response.data.minimum_amount, + maximum_amount: response.data.maximum_amount, + period_start: response.data.period_start, + period_end: response.data.period_end, + deduct_amount: response.data.deduct_amount, + deduct_percentage: response.data.deduct_percentage, + priority: response.data.priority, + status: response.data.status, + status_include: response.data.status_include, + transaction_type: response.data.transaction_type.id + + // updated_by: parsedUser?.username , + // updated_at: new Date().toISOString().slice(0, 19).replace('T', ' ') + })); + } else { + setFormField((prev) => ({ + ...prev, + name: '', + description: '', + minimum_amount: 0, + maximum_amount: 0, + period_start: '', + period_end: '', + deduct_amount: 0, + deduct_percentage: 0, + priority: '', + status: '', + status_include: '', + transaction_type: '' + })); + } + }, []); + + useEffect(() => { + if (selectedTransferFee) { + fetchTransactionFee(selectedTransferFee); + } + }, [selectedTransferFee]); + + return ( + handleEditFeeDialog(open, null)}> + + + + +
+
+

+ Update Transaction Fee +

+
+
+
handleEditFeeDialog(false, null)} + > + +
+
+
+ +
+ {alert.show && ( + +

{alert.message}

+
+ )} +
+
+
+
+ + + 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" + /> +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ {/*
+ + +
*/} + + {/*
+ + +
*/} +
+ + +
+
+
+
+
+
+
+
+ ); +}; + +export { EditFeeDialog }; diff --git a/src/pages/transfer/transferfee/blocks/ListToolBar.tsx b/src/pages/transfer/transferfee/blocks/ListToolBar.tsx new file mode 100644 index 0000000..9acdc39 --- /dev/null +++ b/src/pages/transfer/transferfee/blocks/ListToolBar.tsx @@ -0,0 +1,44 @@ + import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; + import { useManageTransferFeeContext } from '../hooks/useManageTransferFeeContext'; + import { Button } from '@/components/ui/button'; + + const ListToolbar = () => { + const { table, reload } = useDataGrid(); + const { handleAddFeeDialog, handleEditFeeDialog, selectedTransferFee} = useManageTransferFeeContext(); + + return ( +
+
+
+
+ +
+
+ + + + +
+
+
+
+ ); + }; + + export default ListToolbar; diff --git a/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx b/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx new file mode 100644 index 0000000..67d08ba --- /dev/null +++ b/src/pages/transfer/transferfee/hooks/ManageTransferFeeContext.tsx @@ -0,0 +1,236 @@ +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'; + +interface ContextProps { + showEditFeeDialog: boolean; + handleEditFeeDialog: (show: boolean, selectedTransferFee: string | null) => void; + showAddFeeDialog: boolean; + handleAddFeeDialog: (show: boolean) => void; + handleDeleteFeeDialog: (show: boolean, selectedTransferFee: string | null) => void; + showDeleteFeeDialog: boolean; + selectedTransferFee: string | null; +} + +const initialProps: ContextProps = { + showEditFeeDialog: false, + handleEditFeeDialog: () => {}, + showAddFeeDialog: false, + handleAddFeeDialog: () => {}, + showDeleteFeeDialog: false, + handleDeleteFeeDialog: () => {}, + selectedTransferFee: 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 [selectedTransferFee, setSelectedTransferFee] = useState(null); + const { GetData } = useCallApi(); + + const handleEditFeeDialog = useCallback((show: boolean, selectedTransferFee: string | null) => { + setSelectedTransferFee(show ? selectedTransferFee : null); + setShowEditFeeDialog(show); + }, []); + + const handleAddFeeDialog = useCallback((show: boolean) => { + setShowAddFeeDialog(show); + }, []); + + const handleDeleteFeeDialog = useCallback((show: boolean, selectedTransferFee: string | null) => { + setSelectedTransferFee(show ? selectedTransferFee : 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: 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc ? 'ASC' : 'DESC', + filter: JSON.stringify(filter) + }); + console.log('hasilnya', response?.data.list); + console.log('transactiontype', response?.data); + + return { data: response?.data.list, totalCount: response?.data.total_count }; + }; + 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.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.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.priority, + id: 'priority', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[100px]' } + }, + { + accessorFn: (row) => row.transaction_type?.name, + id: 'transactionTypeId', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.status_include, + id: 'status_include', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[150px]' } + }, + { + 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

+
+ + + } + sorting={[{ id: 'id', desc: true }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + doGetTransferFeeListData(pageIndex, pageSize, sorting, columnFilters) + } + > + {children} + + + + +
+ ); +}; + +export { ManageTransferFeeContext, ManageTransferFeeContextProvider }; diff --git a/src/pages/transfer/transferfee/hooks/useManageTransferFeeContext.tsx b/src/pages/transfer/transferfee/hooks/useManageTransferFeeContext.tsx new file mode 100644 index 0000000..11873ba --- /dev/null +++ b/src/pages/transfer/transferfee/hooks/useManageTransferFeeContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageTransferFeeContext } from './ManageTransferFeeContext'; + +const useManageTransferFeeContext = () => { + const context = useContext(ManageTransferFeeContext); + + if (!context) throw new Error('useManageAccessTypeContext must be used within AuthProvider'); + + return context; +}; + +export { useManageTransferFeeContext }; diff --git a/src/pages/transfer/transfertype/TransferType.tsx b/src/pages/transfer/transfertype/TransferType.tsx new file mode 100644 index 0000000..de8effe --- /dev/null +++ b/src/pages/transfer/transfertype/TransferType.tsx @@ -0,0 +1,27 @@ +import { Container, DataGridInner } from '@/components'; +import { + ManageTransferTypeContext, + ManageTransferTypeContextProvider +} from './hooks/ManageTransferTypeContext'; +import AddDialog from './blocks/AddDialog'; +import { DeleteDialog } from './blocks/DeleteDialog'; +import { EditDialog } from './blocks/EditDialog'; + +const TransferType = () => { + + return ( + + +
+ +
+ + + + +
+
+ ); +}; + +export default TransferType; diff --git a/src/pages/transfer/transfertype/blocks/AddDialog.tsx b/src/pages/transfer/transfertype/blocks/AddDialog.tsx new file mode 100644 index 0000000..d0afb04 --- /dev/null +++ b/src/pages/transfer/transfertype/blocks/AddDialog.tsx @@ -0,0 +1,490 @@ +import { apiConfig } from '@/config/api.config'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; +import { + Alert, + Container, + DataGridColumnHeader, + DataGridInner, + KeenIcon, + useDataGrid +} from '@/components'; +import { useCallApi } from '@/hooks'; +import { NumericFormat } from 'react-number-format'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; +import { Button } from '@/components/ui/button'; +import { toast } from 'sonner'; +import { getAuth } from '@/auth'; + +interface WalletProps { + Wallet_id: string; + Wallet_name: string; +} + +interface CustomerProps { + id: string; + username: string; + msisdn: string; +} + +const API_URL = apiConfig.service_transaction; +const API_URL_MASTERDATA = apiConfig.service_master_data; +const API_URL3_CUSTOMER = apiConfig.service_customer; + +const AddDialog = () => { + const parentRef = useRef(null); + const { GetData } = useCallApi(); + const { showAddDialog, handleAddDialog, selectedTransferType } = useManageTransferTypeContext(); + const [wallets, setWallets] = useState([]); + const [customers, setCustomers] = useState([]); + const { reload } = useDataGrid(); + const { PostData, PutData } = useCallApi(); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + const initialState = { + name: '', + description: '', + wallet_origin: '', + wallet_destination: '', + wallet_fee_destination: '', + customer_fee_destination: '', + minimum_amount: 0, + maximum_amount: 0, + max_transaction_per_day: 0, + status: '', + status_approval: '', + created_by: '', + created_at: '' + }; + + const [formField, setFormField] = useState(initialState); + + const resetForm = () => { + setFormField(initialState); + }; + const [isSubmitting, setIsSubmitting] = useState(false); + + const parsedUser = getAuth()?.user; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + // setIsSubmitting(true); + const payload = { + name: formField.name, + description: formField.description, + wallet_origin: formField.wallet_origin, + wallet_destination: formField.wallet_destination, + minimum_amount: formField.minimum_amount, + maximum_amount: formField.maximum_amount, + max_transaction_per_day: formField.max_transaction_per_day, + wallet_fee_destination: formField.wallet_fee_destination, + customer_fee_destination: formField.customer_fee_destination, + status_approval: formField.status_approval, + status: formField.status + }; + }; + useEffect(() => { + const created_time = new Date(); + const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); + + if (showAddDialog) { + setFormField({ + ...formField, + created_by: parsedUser?.username, + created_at: formattedTime + }); + } + }, [showAddDialog]); + + useEffect(() => { + if (!showAddDialog) return; + const getCustomerList = async (sorting: any) => { + try { + sorting = sorting.length === 0 ? [{ id: 'name', desc: false }] : sorting; + + const response = await GetData(`${API_URL3_CUSTOMER}/customer/list`, { + limit: 100, + page: 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc ? 'DESC' : 'ASC' + }); + console.log('CUSTOMER LIST: ', response?.data?.list); + + setCustomers(response?.data.list || []); + } catch (error) { + console.error('Error fetching customer', error); + } + }; + + getCustomerList([{ id: 'msisdn', desc: false }]); + }, [showAddDialog]); + + const fetchWallets = useCallback(async () => { + const params = { + limit: 100, + page: 1, + with_deleted: false, + order_field: 'name', + order_direction: 'ASC', + filter: JSON.stringify({ + status: 'Y' + }) + }; + const response = await GetData(`${API_URL_MASTERDATA}/wallet/list`, params); + if (response?.status && response?.data) { + setWallets(response.data.list); + } else { + setWallets([]); + } + console.log('WALLET LIST: ', response?.data?.list); + }, []); + + useEffect(() => { + if (!showAddDialog) return; + fetchWallets(); + }, [showAddDialog]); + + const doCreateTransferType = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + console.log(formField); + for (const key in formField) { + if ( + formField[key as keyof typeof formField] === '' || + formField[key as keyof typeof formField] === 0 + ) { + setAlert({ show: true, message: 'All fields must be filled out' }); + return; + } + } + + setAlert({ show: false, message: '' }); + + const response = await PostData(`${API_URL}/transactiontype/create`, formField); + + if (response?.status) { + setAlert({ show: false, message: '' }); + handleAddDialog(false); + toast.success('Success Create Transfer Type'); + reload(); + resetForm(); + + console.log('Berhasil nih, isinya gini:', formField); + } else { + setAlert({ show: true, message: response?.message || 'Failed to create transfer type' }); + } + handleAddDialog(false); + }, + [formField] + ); + + return ( + handleAddDialog(open)}> + + + + +
+
+

Transaction Type

+
+
+
{ + handleAddDialog(false); + resetForm(); + }} + > + +
+
+
+ +
+ {alert.show && ( + +

{alert.message}

+
+ )} +
+
+
+
+ + + 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, + max_transaction_per_day: values.floatValue || 0 + })); + }} + placeholder="Enter Max Transaction Per Day" + /> +
+
+
+
+ +
+ +
+
+
+ +
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+ +
+
+ + +
+ +
+
+
+ +
+
+ + +
+ +
+
+
+ +
+ + +
+
+
+
+
+
+
+ ); +}; + +export default AddDialog; diff --git a/src/pages/transfer/transfertype/blocks/DeleteDialog.tsx b/src/pages/transfer/transfertype/blocks/DeleteDialog.tsx new file mode 100644 index 0000000..52f9e25 --- /dev/null +++ b/src/pages/transfer/transfertype/blocks/DeleteDialog.tsx @@ -0,0 +1,92 @@ +import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { Button } from '@/components/ui/button'; +import { Alert, useDataGrid } from '@/components'; +import { ChangeEvent, useCallback, useState } from 'react'; +import { apiConfig } from '@/config/api.config'; +import { toast } from 'sonner'; +import { useCallApi } from '@/hooks'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { EnforceSwitch } from '@/components/switch'; +import { useContext } from 'react'; +import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; +import { ManageTransferTypeContext } from '../hooks/ManageTransferTypeContext'; +import TransferType from '../TransferType'; +import { DialogDescription } from '@radix-ui/react-dialog'; +import { useManageAccessTypeContext } from '@/pages/access/access-type/hooks/useManageAccessTypeContext'; + +const API_URL = apiConfig.service_transaction; + +const DeleteDialog = () => { + const { showDeleteDialog, handleDeleteDialog, selectedTransferType } = useManageTransferTypeContext(); + const { reload } = useDataGrid(); + const { DeleteData } = useCallApi(); + const [enforce, setEnforce] = useState(false); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + + const doDeleteTransferType = useCallback(async () => { + if (!selectedTransferType) { + toast.error('No Transfer Type selected'); + return; + } + + const response = await DeleteData(`${API_URL}/transactiontype/delete/${selectedTransferType}/${enforce}`, { + id: selectedTransferType + }); + + if (response?.status) { + setAlert((prev) => ({ ...prev, show: false, message: '' })); + handleDeleteDialog(false, null); + reload(); + setTimeout(() => toast.success('Success Delete Product'), 0); + } else { + setAlert((prev) => ({ ...prev, show: true, message: response?.message })); + setTimeout(() => toast.error('Failed Delete Product'), 0); + } + }, [selectedTransferType, enforce, DeleteData, handleDeleteDialog, reload]); + + // console.log(selectedTransferType); + + return ( + handleDeleteDialog(open, null)}> + + + Delete Transfer Type + Delete Transfer Type + +

Are you sure?

+ you will delete this data! +
+ + ) => { + setEnforce(e.target.checked); + }} + /> +
+
+ {alert.show && ( + +

{alert.message}

+
+ )} +
+ + + + +
+
+ ); +}; + +export default DeleteDialog; + +export { DeleteDialog }; diff --git a/src/pages/transfer/transfertype/blocks/EditDialog.tsx b/src/pages/transfer/transfertype/blocks/EditDialog.tsx new file mode 100644 index 0000000..7a27df0 --- /dev/null +++ b/src/pages/transfer/transfertype/blocks/EditDialog.tsx @@ -0,0 +1,525 @@ +import { useCallback, useEffect, useRef, useState } from 'react'; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue +} from '@/components/ui/select'; +import { NumericFormat } from 'react-number-format'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; +import { apiConfig } from '@/config/api.config'; +import { Alert, Container, DataGridInner, KeenIcon, useDataGrid } from '@/components'; +import { toast } from 'sonner'; +import { useCallApi } from '@/hooks'; +import { doSaveLogActivity } from '@/actions/GlobalActions'; +import { getAuth } from '@/auth'; +import { ManageTransferFeeContextProvider } from '../../transferfee/hooks/ManageTransferFeeContext'; +import AddFeeDialog from '../../transferfee/blocks/AddDialog'; + +const API_URL = apiConfig.service_transaction; +const API_URL_MASTERDATA = apiConfig.service_master_data; +const API_URL_CUSTOMER = apiConfig.service_customer; + +interface WalletProps { + Wallet_id: string; + Wallet_name: string; +} + +interface CustomerProps { + id: string; + username: string; + msisdn: string; +} + +interface TranssactionTypeProps { + name: string; + description: string; + minimum_amount: number; + maximum_amount: number; + max_transaction_per_day: number; + status_approval: string; + status: string; + wallet_origin: WalletProps; + wallet_destination: WalletProps; + wallet_fee_destination: WalletProps; + customer_fee_destination: CustomerProps; +} + +const EditDialog = () => { + const parentRef = useRef(null); + const { showEditDialog, handleEditDialog, selectedTransferType, accounts } = + useManageTransferTypeContext(); + const { reload } = useDataGrid(); + const [wallets, setWallets] = useState([]); + const { GetData, PutData } = useCallApi(); + const [isSubmitting, setIsSubmitting] = useState(false); + const parsedUser = getAuth()?.user; + const [customers, setCustomers] = useState([]); + const [transactiontypes, setTransactionTypes] = useState([]); + const [alert, setAlert] = useState({ + show: false, + message: '' + }); + const resetForm = () => { + setFormField(formField); + }; + const [formField, setFormField] = useState({ + name: '', + description: '', + wallet_origin: '', + wallet_destination: '', + wallet_fee_destination: '', + customer_fee_destination: '', + minimum_amount: 0, + maximum_amount: 0, + max_transaction_per_day: 0, + status_approval: '', + status: '', + updated_by: '', + updated_at: '' + }); + useEffect(() => { + const updated_time = new Date(); + const formattedTime = updated_time.toISOString().slice(0, 19).replace('T', ' '); + + if (showEditDialog) { + setFormField({ + ...formField, + updated_by: parsedUser?.username, + updated_at: formattedTime + }); + } + }, [showEditDialog]); + /* actions */ + const doUpdateTransferType = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + const response = await PutData(`${API_URL}/transactiontype/update/${selectedTransferType}`, { + ...formField + }); + if (response?.status) { + handleEditDialog(false, null); + toast.success('Success Update User'); + reload(); + } else { + setAlert((prev) => ({ ...prev, show: true, message: response?.message })); + } + // console.log(formField); + }, + [formField, selectedTransferType] + ); + useEffect(() => { + 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 ? 'DESC' : 'ASC' + }); + // console.log('CUSTOMER LIST: ', response?.data?.list); + + setCustomers(response?.data.list || []); + } catch (error) { + console.error('Error fetching customer', error); + } + }; + + getCustomerList([{ id: 'id', desc: false }]); + }, [showEditDialog]); + const fetchWallets = useCallback(async () => { + const params = { + limit: 100, + page: 1, + with_deleted: false, + order_field: 'name', + order_direction: 'ASC', + filter: JSON.stringify({ + status: 'Y' + }) + }; + const response = await GetData(`${API_URL_MASTERDATA}/wallet/list`, params); + if (response?.status && response?.data) { + setWallets(response.data.list); + } else { + setWallets([]); + } + }, []); + + useEffect(() => { + fetchWallets(); + }, [fetchWallets]); + + const fetchTransactionType = useCallback(async (id: string) => { + const response = await GetData(`${API_URL}/transactiontype/getdata/${id}`, { id }); + // console.log("API Response:", response); + + if (response?.status) { + const data = response.data; + console.log('Fetched customer_fee_destination:', response.data); + setFormField((prev) => ({ + ...prev, + name: response.data.name, + description: response.data.description, + wallet_origin: response.data.wallet_origin.id, + wallet_destination: response.data.wallet_destination.id, + wallet_fee_destination: response.data.wallet_fee_destination.id, + customer_fee_destination: response.data.customer_fee_destination.id, + minimum_amount: response.data.minimum_amount, + maximum_amount: response.data.maximum_amount, + max_transaction_per_day: response.data.max_transaction_per_day, + status_approval: response.data.status_approval, + status: response.data.status + // updated_by: parsedUser?.username , + // updated_at: new Date().toISOString().slice(0, 19).replace('T', ' ') + })); + } else { + setFormField((prev) => ({ + ...prev, + name: '', + description: '', + wallet_origin: '', + wallet_destination: '', + wallet_fee_destination: '', + customer_fee_destination: '', + maximum_amount: 0, + minimum_amount: 0, + max_transaction_per_day: 0, + status_approval: '', + status: '' + })); + } + }, []); + + useEffect(() => { + if (selectedTransferType) { + fetchTransactionType(selectedTransferType); + } + }, [selectedTransferType]); + // console.log('Form Field Data: ', formField); + // console.log('customer list:', customers); + return ( + handleEditDialog(open, null)}> + + + + +
+
+

+ Update Transaction Type +

+
+
+
{ + handleEditDialog(false, null); + resetForm(); + }} + > + +
+
+
+ +
+ {alert.show && ( + +

{alert.message}

+
+ )} +
+
+
+
+ + + setFormField((prev) => ({ ...prev, name: target.value })) + } + /> +
+
+ +
+
+ + + setFormField((prev) => ({ ...prev, description: target.value })) + } + /> +
+
+ +
+
+ + { + setFormField((prev) => ({ + ...prev, + maximum_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Minimum Amount" + /> +
+
+ +
+
+ + { + setFormField((prev) => ({ + ...prev, + maximum_amount: values.floatValue || 0 + })); + }} + placeholder="Enter Maximum Amount" + /> +
+
+
+
+ + { + setFormField((prev) => ({ + ...prev, + max_transaction_per_day: values.floatValue || 0 + })); + }} + placeholder="Enter Max Transaction Per Day" + /> +
+
+
+
+ +
+ +
+
+
+ +
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ +
+ +
+
+
+
+
+ + +
+ +
+
+
+ +
+
+ + +
+ +
+
+
+ + {/*
+ +
*/} +
+ {/* */} + + + +
+
+
+ {/* Bagian Transaction Fee */} + + +
+ +
+ +
+
+
+
+
+
+ ); +}; + +export { EditDialog }; diff --git a/src/pages/transfer/transfertype/blocks/ListToolBar.tsx b/src/pages/transfer/transfertype/blocks/ListToolBar.tsx new file mode 100644 index 0000000..7325816 --- /dev/null +++ b/src/pages/transfer/transfertype/blocks/ListToolBar.tsx @@ -0,0 +1,44 @@ +import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; +import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; +import { Button } from '@/components/ui/button'; + +const ListToolbar = () => { + const { table, reload } = useDataGrid(); + const { handleAddDialog, handleEditDialog } = useManageTransferTypeContext(); + + return ( +
+
+
+
+ +
+
+ + + + +
+
+
+
+ ); +}; + +export default ListToolbar; diff --git a/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx b/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx new file mode 100644 index 0000000..5759d29 --- /dev/null +++ b/src/pages/transfer/transfertype/hooks/ManageTransferTypeContext.tsx @@ -0,0 +1,254 @@ + 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'; + + + interface AccountProps { + id: string; + name: string; + } + + interface TransferType { + id: string; + name: string; + minimum_amount: number; + maximum_amount: number; + max_transaction_per_day: number; + walletOriginId: string; + walletDestinationId: string; + status: string; + } + + interface ContextProps { + showEditDialog: boolean; + handleEditDialog: (show: boolean, selected_user: string | null) => void; + showAddDialog: boolean; + handleAddDialog: (show: boolean) => void; + showDeleteDialog: boolean; + handleDeleteDialog: (show: boolean, selected_user: string | null) => void; + selectedTransferType: string | null; + transferType: string|null; + accounts: AccountProps[]; + } + + const initialProps: ContextProps = { + showEditDialog: false, + handleEditDialog: () => {}, + showAddDialog: false, + handleAddDialog: () => {}, + showDeleteDialog: false, + handleDeleteDialog: () => {}, + selectedTransferType: null, + accounts: [], + transferType: null + }; + + const ManageTransferTypeContext = createContext(initialProps); + const API_URL = apiConfig.service_transaction; + + const ManageTransferTypeContextProvider = ({ children }: { children: React.ReactNode }) => { + const [showEditDialog, setShowEditDialog] = useState(false); + const [showAddDialog, setShowAddDialog] = useState(false); + const [showDeleteDialog, setShowDeleteDialog] = useState(false); + const [selectedUser, setSelectedUser] = useState(null); + const [accounts, setAccount] = useState([]); + const { GetData } = useCallApi(); + const [selectedTransferType, setSelectedTransferType] = useState(null); + const [transferType, setTransferType] = useState(null); + + + const handleEditDialog = useCallback((show: boolean, selected_transfertype: string | null) => { + setSelectedTransferType(show ? selected_transfertype : null); + setShowEditDialog(show); + }, []); + + const handleAddDialog = useCallback((show: boolean) => { + setShowAddDialog(show); + }, []); + + const handleDeleteDialog = useCallback((show: boolean, selected_transfertype: string | null) => { + setShowDeleteDialog(show); + setSelectedTransferType(show ? selected_transfertype : null); + }, []); + + const columns = useMemo[]>( + () => [ + + { + accessorFn: (row) => row.name, + id: 'name', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.wallet_origin?.name || 'N/A', + id: 'wallet_origin', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.wallet_destination.name || 'N/A', + id: 'wallet_destination', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.maximum_amount, + id: 'maximum_amount', + 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-[250px]' } + }, + { + accessorFn: (row) => row.max_transaction_per_day, + id: 'max_transaction_per_day', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.description, + id: 'description', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.wallet_fee_destination.name , + id: 'wallet_fee_destination', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.customer_fee_destination?.username || 'N/A', + id: 'customer_fee_destination', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[250px]' } + }, + { + accessorFn: (row) => row.status_approval, + id: 'status_approval', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[150px]' } + }, + { + accessorFn: (row) => row.status, + id: 'status', + header: ({ column }) => , + enableSorting: true, + enableHiding: false, + meta: { headerClassName: 'w-[150px]' } + } +, + { + id: 'actions', + header: ({ column }) => , + enableSorting: false, + enableHiding: false, + cell: (data) => { + const row = data.row.original; + return ( + <> + + + + ); + }, + meta: { headerClassName: 'w-[100px]', cellClassName: 'text-center' } + } + ], + [handleEditDialog, handleDeleteDialog] + ); + const doGetTransferTypeListData = 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}/transactiontype/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) + }); + console.log("bismillah:",response?.data.list) + // setTransferType(response?.data.list); + return { data: response?.data.list, totalCount: response?.data.total_count }; + // console.log("test:",response) +   }; + + return ( +
+
+

Manage Transaction Type

+
+ + + + +
+ } + sorting={[{ id: 'id', desc: true }]} + serverSide={true} + onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) => + doGetTransferTypeListData(pageIndex, pageSize, sorting, columnFilters) + } + > + {children} + +
+
+
+ ); + + }; + + export { ManageTransferTypeContext, ManageTransferTypeContextProvider }; + export type { TransferType }; diff --git a/src/pages/transfer/transfertype/hooks/useManageTransferTypeContext.tsx b/src/pages/transfer/transfertype/hooks/useManageTransferTypeContext.tsx new file mode 100644 index 0000000..b726a7c --- /dev/null +++ b/src/pages/transfer/transfertype/hooks/useManageTransferTypeContext.tsx @@ -0,0 +1,12 @@ +import { useContext } from 'react'; +import { ManageTransferTypeContext } from './ManageTransferTypeContext'; + +const useManageTransferTypeContext = () => { + const context = useContext(ManageTransferTypeContext); + + if (!context) throw new Error('useManageAccessTypeContext must be used within AuthProvider'); + + return context; +}; + +export { useManageTransferTypeContext }; From d9843d78487d522e189130c65a4163a7fa90f70b Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Mon, 24 Mar 2025 10:22:43 +0700 Subject: [PATCH 3/4] tambahan --- src/config/api.config.ts | 6 +- src/pages/transfer/TransferType.tsx | 21 - src/pages/transfer/blocks/AddDialog.tsx | 398 ------------------ src/pages/transfer/blocks/ListToolBar.tsx | 49 --- .../transfer/blocks/TransactionFeeDialog.tsx | 281 ------------- .../hooks/ManageTransferTypeContext.tsx | 178 -------- .../hooks/useManageTransferTypeContext.tsx | 12 - src/routing/AppRoutingSetup.tsx | 2 +- 8 files changed, 6 insertions(+), 941 deletions(-) delete mode 100644 src/pages/transfer/TransferType.tsx delete mode 100644 src/pages/transfer/blocks/AddDialog.tsx delete mode 100644 src/pages/transfer/blocks/ListToolBar.tsx delete mode 100644 src/pages/transfer/blocks/TransactionFeeDialog.tsx delete mode 100644 src/pages/transfer/hooks/ManageTransferTypeContext.tsx delete mode 100644 src/pages/transfer/hooks/useManageTransferTypeContext.tsx diff --git a/src/config/api.config.ts b/src/config/api.config.ts index 3087034..8896461 100644 --- a/src/config/api.config.ts +++ b/src/config/api.config.ts @@ -1,6 +1,8 @@ interface apiConfigProps { service_dashboard: string; service_master_data: string; + service_transaction: string; + service_customer: string; } const API_URL = import.meta.env.VITE_APP_API_URL; @@ -8,7 +10,9 @@ const apiConfig: apiConfigProps = { // service_dashboard: `${API_URL}${import.meta.env.VITE_ENV != 'development' ? '/d' : ''}`, service_dashboard: `${API_URL}/d`, // service_master_data: `${API_URL}/m` - service_master_data: `${API_URL}/t` + service_master_data: `${API_URL}/t`, + service_transaction: `${API_URL}/tt`, + service_customer: `${API_URL}/c`, }; export { apiConfig }; diff --git a/src/pages/transfer/TransferType.tsx b/src/pages/transfer/TransferType.tsx deleted file mode 100644 index 2e5d03e..0000000 --- a/src/pages/transfer/TransferType.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Container, DataGridInner } from '@/components'; -import { - ManageTransferTypeContext, - ManageTransferTypeContextProvider -} from './hooks/ManageTransferTypeContext'; -import AddDialog from './blocks/AddDialog'; - -const TransferType = () => { - return ( - - -
- -
- -
-
- ); -}; - -export default TransferType; diff --git a/src/pages/transfer/blocks/AddDialog.tsx b/src/pages/transfer/blocks/AddDialog.tsx deleted file mode 100644 index a7abdf1..0000000 --- a/src/pages/transfer/blocks/AddDialog.tsx +++ /dev/null @@ -1,398 +0,0 @@ -import { apiConfig } from '@/config/api.config'; -import { useCallback, useEffect, useRef, useState } from 'react'; -import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; -import { Alert, KeenIcon, useDataGrid } from '@/components'; -import { useCallApi } from '@/hooks'; -import { - Dialog, - DialogBody, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle -} from '@/components/ui/dialog'; -import { Input } from '@/components/ui/input'; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue -} from '@/components/ui/select'; -import { Button } from '@/components/ui/button'; -import TransactionFeeDialog from './TransactionFeeDialog'; -import { toast } from 'sonner'; -import { doSaveLogActivity } from '@/actions/GlobalActions'; -import { getAuth } from '@/auth'; - -interface CreateTransferTypeParams { - transfer_type_name: string; - description: string; - from_account: string; - to_account: string; - minimal_amount: number; - maximum_amount: number; - otp_threshold: number; - maximum_transaction_perDay: number; - status: string; - created_by: string; - created_at: string; -} - -const API_URL = apiConfig.service_dashboard; - -const AddDialog = () => { - const parentRef = useRef(null); - const { showAddDialog, handleAddDialog, accounts } = useManageTransferTypeContext(); - const { reload } = useDataGrid(); - const { PostData, PutData } = useCallApi(); - const [alert, setAlert] = useState({ - show: false, - message: '' - }); - - const initialState = { - transfer_type_name: '', - description: '', - from_account: '', - to_account: '', - minimal_amount: 0, - maximum_amount: 0, - otp_threshold: 0, - maximum_transaction_perDay: 0, - status: '', - created_by: '', - created_at: '' - }; - - const [formField, setFormField] = useState(initialState); - - const resetForm = () => { - setFormField(initialState); - }; - - 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 = { - transfer_type_name: formField.transfer_type_name, - description: formField.description, - from_account: formField.from_account, - to_account: formField.to_account, - minimal_amount: formField.minimal_amount, - maximum_amount: formField.maximum_amount, - otp_threshold: formField.otp_threshold, - maximum_transaction_perDay: formField.maximum_transaction_perDay - }; - console.log(payload); - }; - useEffect(() => { - const created_time = new Date(); - const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); - - if (showAddDialog) { - setFormField({ - ...formField, - created_by: parsedUser?.username, - created_at: formattedTime - }); - } - }, [showAddDialog]); - const doCreateTransferType = useCallback( - async (e: React.FormEvent) => { - e.preventDefault(); - console.log(formField); - - for (const key in formField) { - if ( - formField[key as keyof typeof formField] === '' || - formField[key as keyof typeof formField] === 0 - ) { - setAlert({ show: true, message: 'All fields must be filled out' }); - return; - } - } - - setAlert({ show: false, message: '' }); - const response = await PostData(`${API_URL}/transactiontype/create`, formField); - - if (response?.status) { - setAlert({ show: false, message: '' }); - handleAddDialog(false); - toast.success('Success Create Transfer Type'); - reload(); - resetForm(); - - const createActivity = { - module: 'Manage Transfer Type', - description: `Create New Transfer Type => ${formField.transfer_type_name}`, - action: 'C' - }; - - doSaveLogActivity(createActivity); - } else { - setAlert({ show: true, message: response?.message || 'Failed to create transfer type' }); - } - - handleAddDialog(false); - }, - [formField] - ); - const handleTransactionFeeSubmit = (data: any) => { - // console.log('Transaction Fee Data Submitted:', data); - setShowTransactionFeeDialog(false); - }; - - return ( - handleAddDialog(open)}> - - - - -
-
-

Transfer Type

-
-
-
{ - handleAddDialog(false); - resetForm(); - }} - > - -
-
-
- -
- {alert.show && ( - -

{alert.message}

-
- )} -
-
-
-
- - - setFormField((prev) => ({ ...prev, transfer_type_name: target.value })) - } - /> -
-
- -
-
- - - setFormField((prev) => ({ ...prev, description: target.value })) - } - /> -
-
- -
-
- - -
- -
-
-
- -
-
- - -
- -
-
-
- -
-
- - - setFormField((prev) => ({ - ...prev, - minimal_amount: Number(target.value) - })) - } - /> -
-
- -
-
- - - setFormField((prev) => ({ - ...prev, - maximum_amount: Number(target.value) - })) - } - /> -
-
- -
-
- - - setFormField((prev) => ({ - ...prev, - otp_threshold: Number(target.value) - })) - } - /> -
-
- -
-
- - - setFormField((prev) => ({ - ...prev, - maximum_transaction_perDay: Number(target.value) - })) - } - /> -
-
-
-
- - -
- -
-
-
- -
- - - -
-
-
- setShowTransactionFeeDialog(false)} - onSubmit={handleTransactionFeeSubmit} - /> -
-
-
-
- ); -}; - -export default AddDialog; diff --git a/src/pages/transfer/blocks/ListToolBar.tsx b/src/pages/transfer/blocks/ListToolBar.tsx deleted file mode 100644 index a3af2c3..0000000 --- a/src/pages/transfer/blocks/ListToolBar.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components'; -import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; -import { Button } from '@/components/ui/button'; - -const ListToolbar = () => { - const { table, reload } = useDataGrid(); - const { handleAddDialog, handleEditDialog } = useManageTransferTypeContext(); - - return ( -
-
-
-
- - - - -
-
- - - - -
-
-
-
- ); -}; - -export default ListToolbar; diff --git a/src/pages/transfer/blocks/TransactionFeeDialog.tsx b/src/pages/transfer/blocks/TransactionFeeDialog.tsx deleted file mode 100644 index cccf165..0000000 --- a/src/pages/transfer/blocks/TransactionFeeDialog.tsx +++ /dev/null @@ -1,281 +0,0 @@ -import { useState, useCallback, useEffect } from 'react'; -import { - Dialog, - DialogBody, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle -} from '@/components/ui/dialog'; -import { Input } from '@/components/ui/input'; -import { Button } from '@/components/ui/button'; -import Typography from '@mui/material/Typography'; -import { toast } from 'sonner'; -import { apiConfig } from '@/config/api.config'; -import { useCallApi } from '@/hooks'; -import { useManageTransferTypeContext } from '../hooks/useManageTransferTypeContext'; -import { get } from 'http'; -import { getAuth } from '@/auth'; -import { useDataGrid } from '@/components'; -import { set } from 'date-fns'; -import { doSaveLogActivity } from '@/actions/GlobalActions'; -import { - Select, - SelectTrigger, - SelectValue, - SelectContent, - SelectItem -} from '@/components/ui/select'; - -interface TransactionFeeDialogProps { - open: boolean; - onClose: () => void; - onSubmit: (data: TransactionFeeForm) => void; -} - -interface TransactionFeeForm { - name: string; - description: string; - minimum_amount: number; - maximum_amount: number; - period_start: string; - period_end: string; - deduct_amount: number; - deduct_percentage: number; - priority: string; - status: string; - transactionTypeId: string; - created_by: string; - created_at: string; -} - -const API_URL = apiConfig.service_dashboard; - -const TransactionFeeDialog: React.FC = ({ open, onClose, onSubmit }) => { - const { showAddDialog, handleAddDialog } = useManageTransferTypeContext(); - const parsedUser = getAuth()?.user; - const [formField, setFormField] = useState({ - name: '', - description: '', - minimum_amount: 0, - maximum_amount: 0, - period_start: '', - period_end: '', - deduct_amount: 0, - deduct_percentage: 0, - priority: '', - status: '', - transactionTypeId: '', - created_by: '', - created_at: '' - }); - const { PostData, PutData } = useCallApi(); - const handleChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; - setFormField((prev) => ({ - ...prev, - [name]: value - })); - }; - const [isSubmitting, setIsSubmitting] = useState(false); - const { reload } = useDataGrid(); - const resetForm = () => { - setFormField(formField); - }; - const [alert, setAlert] = useState({ - show: false, - message: '' - }); - useEffect(() => { - const created_time = new Date(); - const formattedTime = created_time.toISOString().slice(0, 19).replace('T', ' '); - - if (showAddDialog) { - setFormField({ - ...formField, - created_by: parsedUser?.username, - created_at: formattedTime - }); - } - }, [showAddDialog]); - const doCreateTransactionFee = useCallback( - async (e: React.FormEvent) => { - e.preventDefault(); - console.log(formField); - const response = await PostData(`${API_URL}/transactionfees/create`, formField); - - if (response?.status) { - setAlert({ show: false, message: '' }); - handleAddDialog(false); - toast.success('Success Create Transfer Type'); - reload(); - resetForm(); - - const createActivity = { - module: 'Manage Transfer Fee', - description: `Create New Transfer Fee => ${formField.name}`, - action: 'C' - }; - - doSaveLogActivity(createActivity); - } else { - setAlert({ show: true, message: response?.message || 'Failed to create transfer fee' }); - } - - onSubmit(formField); - }, - [formField] - ); - - return ( - - - - Transaction Fee - - - -
-
-
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - { - const value = e.target.value; - if (/^\d*$/.test(value)) { - handleChange(e); - } - }} - required - type="text" - inputMode="numeric" - placeholder="Masukkan angka" - /> -
-
- - -
- -
- - -
-
-
-
-
-
- ); -}; - -export default TransactionFeeDialog; diff --git a/src/pages/transfer/hooks/ManageTransferTypeContext.tsx b/src/pages/transfer/hooks/ManageTransferTypeContext.tsx deleted file mode 100644 index 5a3d5d3..0000000 --- a/src/pages/transfer/hooks/ManageTransferTypeContext.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import { DataGridColumnHeader, DataGridProvider } 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'; - -interface SelectedUser { - id: string; - name: string; - internal_name: string; - description: string; -} - -interface AccountProps { - id: string; - name: string; -} - -const accounts: string[] = [ - 'eMoney Account', - 'Topup Account', - 'Merchant Account', - 'Deposit Account', - 'Cash out/in' -]; - -interface ContextProps { - showEditDialog: boolean; - handleEditDialog: (show: boolean, selected_user: string | null) => void; - showAddDialog: boolean; - handleAddDialog: (show: boolean) => void; - selectedUser: string | null; - accounts: AccountProps[]; -} - -const initialProps: ContextProps = { - showEditDialog: false, - handleEditDialog: () => {}, - showAddDialog: false, - handleAddDialog: () => {}, - selectedUser: null, - accounts: [] -}; - -const ManageTransferTypeContext = createContext(initialProps); -const API_URL = apiConfig.service_dashboard; - -const ManageTransferTypeContextProvider = ({ children }: { children: React.ReactNode }) => { - const [showEditDialog, setShowEditDialog] = useState(false); - const [showAddDialog, setShowAddDialog] = useState(false); - const [selectedUser, setSelectedUser] = useState(null); - const [accounts, setAccount] = useState([]); - const { GetData } = useCallApi(); - - useEffect(() => { - setAccount([ - { id: '1', name: 'eMoney Account' }, - { id: '2', name: 'Topup Account' }, - { id: '3', name: 'Merchant Account' }, - { id: '4', name: 'Deposit Account' }, - { id: '5', name: 'Cash in/out Account' } - ]); - }, []); - - const handleEditDialog = useCallback((show: boolean, selected_user: string | null) => { - setSelectedUser(show ? selected_user : null); - setShowEditDialog(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.name, - id: 'name', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { - headerClassName: 'w-[250px]' - } - }, - { - accessorFn: (row) => row.internal_name, - id: 'internal_name', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { - headerClassName: 'w-[250px]' - } - }, - { - accessorFn: (row) => row.description, - id: 'description', - header: ({ column }) => , - enableSorting: true, - enableHiding: false, - meta: { - headerClassName: 'w-[250px]' - } - }, - { - id: 'actions', - enableSorting: false, - header: ({ column }) => , - cell: ({ row }) => { - return ( - <> - - - - ); - }, - meta: { - headerClassName: 'w-[100px]', - cellClassName: 'text-center' - } - } - ], - [handleAddDialog, handleEditDialog] - ); - - return ( -
-
-

Manage Access Type

-
- - - } - sorting={[{ id: 'id', desc: true }]} - serverSide={true} - > - {children} - - -
- ); -}; - -export { ManageTransferTypeContext, ManageTransferTypeContextProvider }; -export type { SelectedUser }; diff --git a/src/pages/transfer/hooks/useManageTransferTypeContext.tsx b/src/pages/transfer/hooks/useManageTransferTypeContext.tsx deleted file mode 100644 index b726a7c..0000000 --- a/src/pages/transfer/hooks/useManageTransferTypeContext.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { useContext } from 'react'; -import { ManageTransferTypeContext } from './ManageTransferTypeContext'; - -const useManageTransferTypeContext = () => { - const context = useContext(ManageTransferTypeContext); - - if (!context) throw new Error('useManageAccessTypeContext must be used within AuthProvider'); - - return context; -}; - -export { useManageTransferTypeContext }; diff --git a/src/routing/AppRoutingSetup.tsx b/src/routing/AppRoutingSetup.tsx index 971fbaa..1cf83ae 100644 --- a/src/routing/AppRoutingSetup.tsx +++ b/src/routing/AppRoutingSetup.tsx @@ -24,7 +24,7 @@ import ManageMenu from '@/pages/menu/manage-menu/ManageMenu'; import Welcome from '@/pages/menu/welcome/Welcome'; import Inbox from '@/pages/message/Inbox'; import ManageWebServices from '@/pages/webservice/ManageWebServices'; -import TransferType from '@/pages/transfer/TransferType'; +import TransferType from '@/pages/transfer/transfertype/TransferType'; import MasterData from '@/pages/master/MasterData'; import PostoAdmsMaster from '@/pages/master/postoadms/PostoAdmsMaster'; import SucosMaster from '@/pages/master/sucos/SucosMaster'; From 7a62945fd67a495d3e0b2b6fe18d4eb04d45146c Mon Sep 17 00:00:00 2001 From: bagusajisaputroo Date: Mon, 24 Mar 2025 10:46:46 +0700 Subject: [PATCH 4/4] +package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 29c3f8b..41cfe62 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "react-inlinesvg": "^4.1.4", "react-intl": "^6.8.7", "react-leaflet": "^4.2.1", + "react-number-format": "^5.4.3", "react-query": "^3.39.3", "react-router": "^6.28.0", "react-router-dom": "^6.28.0",