diff --git a/src/pages/account/home/user-profile/hooks/AccountUserProfileContext.tsx b/src/pages/account/home/user-profile/hooks/AccountUserProfileContext.tsx index 30fc219..58e2e9b 100644 --- a/src/pages/account/home/user-profile/hooks/AccountUserProfileContext.tsx +++ b/src/pages/account/home/user-profile/hooks/AccountUserProfileContext.tsx @@ -109,7 +109,8 @@ const AccountUserProfileContextProvider = ({ children }: { children: React.React const handleSetPinCode = async (newPinCode: PinCodePayload) => { try { setPincodeState(newPinCode); - const customerid = getAuth()?.user?.customer?.id; + // const customerid = getAuth()?.user?.customer?.id; + const customerid = getAuth()?.user?.id; const response = await PutData(`${API_URL2}/customer/pin/${customerid}`, { old_pin: newPinCode.currentpincode, new_pin: newPinCode.newpincode, diff --git a/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx b/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx index f66ae91..b263725 100644 --- a/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx +++ b/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx @@ -292,7 +292,7 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { setSelectedTransactionId(row.id); setShowRollbackDialog(true); }} - disabled={row.status !== 'C'} + disabled={!['C', 'O'].includes(row.status)} > @@ -360,7 +360,7 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => { // Build formattedFilter setelah semua nilai diketahui const formattedFilter: any = {}; - if( status) { + if (status) { formattedFilter["Transactions.status"] = status; } diff --git a/src/pages/transfer/transferfee/blocks/AddDialog.tsx b/src/pages/transfer/transferfee/blocks/AddDialog.tsx index 612ac36..3c45db1 100644 --- a/src/pages/transfer/transferfee/blocks/AddDialog.tsx +++ b/src/pages/transfer/transferfee/blocks/AddDialog.tsx @@ -9,7 +9,7 @@ import { KeenIcon, useDataGrid } from '@/components'; -import { useCallApi } from '@/hooks'; +import { useCallApi } from '@/hooks';3 import { Dialog, DialogBody, @@ -41,6 +41,7 @@ import { TableRow } from '@/components/ui/table'; import { apiConfig } from '@/config/api.config'; +import { set } from 'date-fns'; interface TransactionTypeProps { id: string; @@ -52,7 +53,7 @@ interface WalletProps { } interface CustomerProps { id: string; - username: string; + fullname: string; msisdn: string; } const API_URL = apiConfig.service_transaction; @@ -70,7 +71,9 @@ const AddFeeDialog = () => { selectedTransferFee, transactionTypeId } = useManageTransferFeeContext(); - const [customerSearchTerm, setCustomerSearchTerm] = useState(''); + const [deductSearchTerm, setDeductSearchTerm] = useState(''); + const [creditSearchTerm, setCreditSearchTerm] = useState(''); + const [open, setOpen] = useState(false); const [alert, setAlert] = useState({ @@ -79,17 +82,14 @@ const AddFeeDialog = () => { }); const [transactionTypes, setTransactionTypes] = useState([]); const [wallets, setWallets] = useState([]); - const [customers, setCustomers] = useState([]); - const [defaultCustomer, setDefaultCustomer] = useState(''); + const [deductFilteredCustomers, setDeductFilteredCustomers] = useState([]); + const [creditFilteredCustomers, setCreditFilteredCustomers] = useState([]); +const [isSearchingDeductCustomers, setIsSearchingDeductCustomers] = useState(false); +const [isSearchingCreditCustomers, setIsSearchingCreditCustomers] = useState(false); 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 [openDeductOrigin, setOpenDeductOrigin] = useState(false); const [openCreditDestination, setOpenCreditDestination] = useState(false); @@ -120,15 +120,20 @@ const AddFeeDialog = () => { const [formField, setFormField] = useState(initialState); - const resetForm = () => { - setFormField(initialState); - setTransactionTypeName(''); - }; +const resetForm = () => { + setFormField(initialState); + setTransactionTypeName(''); + setDeductFilteredCustomers([]); + setCreditFilteredCustomers([]); + setDeductSearchTerm(''); + setCreditSearchTerm(''); +}; const handleCloseDialog = () => { setFormField(initialState); setAlert({ show: false, message: '' }); - setCustomerSearchTerm(''); + setDeductSearchTerm(''); + setCreditSearchTerm(''); setOpenCreditDestination(false); setOpenDeductOrigin(false); setOpen(false); @@ -139,6 +144,24 @@ const AddFeeDialog = () => { const [showTransactionFeeDialog, setShowTransactionFeeDialog] = useState(false); const parsedUser = getAuth()?.user; + + const useDebounce = (value: string, delay: number) => { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const handler = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + return () => { + clearTimeout(handler); + }; + }, [value, delay]); + + return debouncedValue; +}; + const debouncedDeductSearchTerm = useDebounce(deductSearchTerm, 500); +const debouncedCreditSearchTerm = useDebounce(creditSearchTerm, 500); useEffect(() => { if (showAddFeeDialog && transactionTypeId) { setIsLoadingTransactionType(true); @@ -170,7 +193,8 @@ const AddFeeDialog = () => { useEffect(() => { if (!showAddFeeDialog) { - setCustomerSearchTerm(''); + setDeductSearchTerm(''); + setCreditSearchTerm(''); setOpen(false); } }, [showAddFeeDialog]); @@ -241,37 +265,89 @@ const AddFeeDialog = () => { if (!showAddFeeDialog) return; fetchWallets(); }, [showAddFeeDialog, fetchWallets]); - - useEffect(() => { - if (!showAddFeeDialog) return; - const getCustomerList = async (sorting: any) => { - setIsLoadingCustomers(true); + + const searchDeductCustomers = useCallback( + async (searchTerm: string) => { + setIsSearchingDeductCustomers(true); try { - sorting = sorting.length === 0 ? [{ id: 'name', desc: false }] : sorting; - - const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { - limit: 100, - page: 1, - with_deleted: false, - order_field: sorting[0].id, - order_direction: sorting[0].desc ? 'DESC' : 'ASC' - }); - const customerList = response?.data.list || []; - setCustomers(customerList); - - if (customerList.length > 0) { - setDefaultCustomer(customerList[0].id); + let response; + if (!searchTerm.trim()) { + response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { + limit: 20, + page: 1, + with_deleted: false, + order_field: 'username', + order_direction: 'ASC' + }); + } else { + const filters = [{ id: 'fullname', value: searchTerm.trim() }]; + response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { + limit: 20, + page: 1, + with_deleted: false, + order_field: 'username', + order_direction: 'ASC', + filter: JSON.stringify(filters), + specialFilter: true + }); } + setDeductFilteredCustomers(response?.data?.list || []); } catch (error) { - console.error('Error fetching customers', error); - setCustomers([]); + console.error('Error searching deduct customers', error); + setDeductFilteredCustomers([]); } finally { - setIsLoadingCustomers(false); + setIsSearchingDeductCustomers(false); } - }; + }, + [GetData] + ); + useEffect(() => { + if (openDeductOrigin && formField.deduct_from === 'I') { + searchDeductCustomers(debouncedDeductSearchTerm); + } +}, [debouncedDeductSearchTerm, openDeductOrigin, formField.deduct_from, searchDeductCustomers]); - getCustomerList([{ id: 'id', desc: false }]); - }, [showAddFeeDialog, GetData]); + + const searchCreditCustomers = useCallback( + async (searchTerm: string) => { + setIsSearchingCreditCustomers(true); + try { + let response; + if (!searchTerm.trim()) { + response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { + limit: 20, + page: 1, + with_deleted: false, + order_field: 'username', + order_direction: 'ASC' + }); + } else { + const filters = [{ id: 'fullname', value: searchTerm.trim() }]; + response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { + limit: 20, + page: 1, + with_deleted: false, + order_field: 'username', + order_direction: 'ASC', + filter: JSON.stringify(filters), + specialFilter: true + }); + } + setCreditFilteredCustomers(response?.data?.list || []); + } catch (error) { + console.error('Error searching credit customers', error); + setCreditFilteredCustomers([]); + } finally { + setIsSearchingCreditCustomers(false); + } + }, + [GetData] + ); + useEffect(() => { + if (openCreditDestination && formField.credit_to === 'I') { + searchCreditCustomers(debouncedCreditSearchTerm); + } +}, [debouncedCreditSearchTerm, openCreditDestination, formField.credit_to, searchCreditCustomers]); const doCreateTransferType = useCallback( async (e: React.FormEvent) => { @@ -624,11 +700,17 @@ const AddFeeDialog = () => {
setOpenDeductOrigin(!openDeductOrigin)} + onClick={() => { + setOpenDeductOrigin(!openDeductOrigin); + if (!openDeductOrigin && deductSearchTerm.trim() === '') { + searchDeductCustomers(''); + } + }} > - {customers.find((customer) => customer.id === formField.deduct_origin) - ?.username || 'Search customer...'} + {deductFilteredCustomers.find( + (customer) => customer.id === formField.deduct_origin + )?.fullname || 'Search customer...'}
@@ -639,45 +721,41 @@ const AddFeeDialog = () => { className="h-8 text-sm" type="text" placeholder="Search customer..." - value={customerSearchTerm} - onChange={(e) => setCustomerSearchTerm(e.target.value)} + value={deductSearchTerm} + onChange={(e) => { + const value = e.target.value; + setDeductSearchTerm(value); + }} autoComplete="off" onClick={(e) => e.stopPropagation()} autoFocus />
- {customers - .filter( - (customer) => - customer.username - .toLowerCase() - .includes(customerSearchTerm.toLowerCase()) || - customer.msisdn.includes(customerSearchTerm) - ) - .map((customer) => ( + {isSearchingDeductCustomers ? ( +
Searching...
+ ) : ( + deductFilteredCustomers.map((customer) => (
{ - setFormField({ ...formField, deduct_origin: customer.id }); - setOpenDeductOrigin(false); + setFormField({ ...formField, deduct_origin: customer.id }); + setOpenDeductOrigin(false); }} > - {customer.username} + {customer.fullname}
- ))} - {customers.filter( - (customer) => - customer.username - .toLowerCase() - .includes(customerSearchTerm.toLowerCase()) || - customer.msisdn.includes(customerSearchTerm) - ).length === 0 && ( -
- No customer found -
+ )) )} + + {!isSearchingDeductCustomers && + deductFilteredCustomers.length === 0 && + deductSearchTerm.trim() && ( +
+ No customer found +
+ )}
)} @@ -723,7 +801,7 @@ const AddFeeDialog = () => { - {formField.credit_to === 'I' && ( + {formField.credit_to === 'I' && (
)} @@ -875,12 +951,7 @@ const AddFeeDialog = () => { diff --git a/src/pages/transfer/transferfee/blocks/EditDialog.tsx b/src/pages/transfer/transferfee/blocks/EditDialog.tsx index c8685d5..16ab108 100644 --- a/src/pages/transfer/transferfee/blocks/EditDialog.tsx +++ b/src/pages/transfer/transferfee/blocks/EditDialog.tsx @@ -45,7 +45,7 @@ interface WalletProps { interface CustomerProps { id: string; - username: string; + fullname: string; msisdn: string; } @@ -59,6 +59,12 @@ const EditFeeDialog = () => { const { showEditFeeDialog, handleEditFeeDialog, selectedTransferFee } = useManageTransferFeeContext(); const { reload } = useDataGrid(); + const [deductSearchTerm, setDeductSearchTerm] = useState(''); + const [creditSearchTerm, setCreditSearchTerm] = useState(''); + const [deductFilteredCustomers, setDeductFilteredCustomers] = useState([]); + const [creditFilteredCustomers, setCreditFilteredCustomers] = useState([]); + const [isSearchingCustomers, setIsSearchingCustomers] = useState(false); + const { GetData, PutData } = useCallApi(); const parsedUser = getAuth()?.user; const [openDeductOrigin, setOpenDeductOrigin] = useState(false); @@ -70,7 +76,7 @@ const EditFeeDialog = () => { const [transactionTypeName, setTransactionTypeName] = useState(''); const customersWithNames = customers.map((customer) => ({ id: customer.id, - name: customer.username + name: customer.fullname })); const [customerSearchTerm, setCustomerSearchTerm] = useState(''); const [showCustomerSearch, setShowCustomerSearch] = useState(false); @@ -80,6 +86,8 @@ const EditFeeDialog = () => { show: false, message: '' }); + const [selectedDeductCustomer, setSelectedDeductCustomer] = useState(null); + const [selectedCreditCustomer, setSelectedCreditCustomer] = useState(null); const [isLoadingTransferFee, setIsLoadingTransferFee] = useState(false); const [isLoadingTransactionType, setIsLoadingTransactionType] = useState(false); @@ -110,7 +118,24 @@ const EditFeeDialog = () => { }; const [formField, setFormField] = useState(initialState); + const useDebounce = (value:string, delay:number) => { + const [debouncedValue, setDebouncedValue] = useState(value); + useEffect(() => { + const handler = setTimeout(() => { + setDebouncedValue(value); + }, delay); + + return () => { + clearTimeout(handler); + }; + }, [value, delay]); + + return debouncedValue; +}; + +const debouncedDeductSearch = useDebounce(deductSearchTerm, 300); +const debouncedCreditSearch = useDebounce(creditSearchTerm, 300); useEffect(() => { const updated_time = new Date(); const formattedTime = updated_time.toISOString().slice(0, 19).replace('T', ' '); @@ -204,7 +229,6 @@ const EditFeeDialog = () => { payload.deduct_origin = '00000000-0000-0000-0000-000000000000'; } - // console.log(payload); try { const response = await PutData( `${API_URL}/transactionfees/update/${selectedTransferFee}`, @@ -262,31 +286,89 @@ const EditFeeDialog = () => { if (!showEditFeeDialog) return; fetchWallets(); }, [showEditFeeDialog, fetchWallets]); - - useEffect(() => { - if (!showEditFeeDialog) return; - - const getCustomerList = async (sorting: any) => { - setIsLoadingCustomers(true); + const searchDeductCustomers = useCallback( + async (searchTerm: string) => { + setIsSearchingCustomers(true); try { - sorting = sorting.length === 0 ? [{ id: 'name', desc: false }] : sorting; - const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { - limit: 100, - page: 1, - with_deleted: false, - order_field: sorting[0].id, - order_direction: sorting[0].desc ? 'DESC' : 'ASC' - }); - setCustomers(response?.data.list || []); + let response; + if (!searchTerm.trim()) { + response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { + limit: 20, + page: 1, + with_deleted: false, + order_field: 'username', + order_direction: 'ASC' + }); + } else { + const filters = [{ id: 'fullname', value: searchTerm.trim() }]; + response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { + limit: 20, + page: 1, + with_deleted: false, + order_field: 'username', + order_direction: 'ASC', + filter: JSON.stringify(filters), + specialFilter: true + }); + } + setDeductFilteredCustomers(response?.data?.list || []); } catch (error) { - console.error('Error fetching customers', error); + console.error('Error searching deduct customers', error); + setDeductFilteredCustomers([]); } finally { - setIsLoadingCustomers(false); + setIsSearchingCustomers(false); } - }; + }, + [GetData] + ); - getCustomerList([{ id: 'id', desc: false }]); - }, [showEditFeeDialog, GetData]); + const searchCreditCustomers = useCallback( + async (searchTerm: string) => { + setIsSearchingCustomers(true); + try { + let response; + if (!searchTerm.trim()) { + response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { + limit: 20, + page: 1, + with_deleted: false, + order_field: 'username', + order_direction: 'ASC' + }); + } else { + const filters = [{ id: 'fullname', value: searchTerm.trim() }]; + response = await GetData(`${API_URL_CUSTOMER}/customer/list`, { + limit: 20, + page: 1, + with_deleted: false, + order_field: 'username', + order_direction: 'ASC', + filter: JSON.stringify(filters), + specialFilter: true + }); + } + setCreditFilteredCustomers(response?.data?.list || []); + } catch (error) { + console.error('Error searching credit customers', error); + setCreditFilteredCustomers([]); + } finally { + setIsSearchingCustomers(false); + } + }, + [GetData] + ); + +useEffect(() => { + if (openDeductOrigin) { + searchDeductCustomers(debouncedDeductSearch); + } +}, [debouncedDeductSearch, openDeductOrigin, searchDeductCustomers]); + +useEffect(() => { + if (openCreditDestination) { + searchCreditCustomers(debouncedCreditSearch); + } +}, [debouncedCreditSearch, openCreditDestination, searchCreditCustomers]); useEffect(() => { if (!showEditFeeDialog) return; @@ -323,7 +405,7 @@ const EditFeeDialog = () => { setIsLoadingTransferFee(true); try { const response = await GetData(`${API_URL}/transactionfees/getdata/${id}`, {}); - // console.log(response); + if (response?.status) { setFormField({ ...initialState, @@ -354,6 +436,32 @@ const EditFeeDialog = () => { if (response.data.transaction_type?.name) { setTransactionTypeName(response.data.transaction_type.name); } + + if ( + response.data.deduct_origin && + response.data.deduct_origin.id !== '00000000-0000-0000-0000-000000000000' + ) { + setSelectedDeductCustomer({ + id: response.data.deduct_origin.id, + fullname: response.data.deduct_origin.fullname || '', + msisdn: response.data.deduct_origin.msisdn || '' + }); + } else { + setSelectedDeductCustomer(null); + } + + if ( + response.data.credit_destination && + response.data.credit_destination.id !== '00000000-0000-0000-0000-000000000000' + ) { + setSelectedCreditCustomer({ + id: response.data.credit_destination.id, + fullname: response.data.credit_destination.fullname || '', + msisdn: response.data.credit_destination.msisdn || '' + }); + } else { + setSelectedCreditCustomer(null); + } } } catch (error) { console.error('Error fetching transaction fee details', error); @@ -658,11 +766,19 @@ const EditFeeDialog = () => {
setOpenDeductOrigin(!openDeductOrigin)} + onClick={() => { + setOpenDeductOrigin(!openDeductOrigin); + if (!openDeductOrigin && deductSearchTerm.trim() === '') { + searchDeductCustomers(''); + } + }} > - {customers.find((customer) => customer.id === formField.deduct_origin) - ?.username || 'Search customer...'} + {selectedDeductCustomer + ? selectedDeductCustomer.fullname + : deductFilteredCustomers.find( + (customer) => customer.id === formField.deduct_origin + )?.fullname || 'Search customer...'}
@@ -673,45 +789,44 @@ const EditFeeDialog = () => { className="h-8 text-sm" type="text" placeholder="Search customer..." - value={customerSearchTerm} - onChange={(e) => setCustomerSearchTerm(e.target.value)} + value={deductSearchTerm} + onChange={(e) => { + const value = e.target.value; + setDeductSearchTerm(value); + + }} autoComplete="off" onClick={(e) => e.stopPropagation()} autoFocus />
- {customers - .filter( - (customer) => - customer.username - .toLowerCase() - .includes(customerSearchTerm.toLowerCase()) || - customer.msisdn.includes(customerSearchTerm) - ) - .map((customer) => ( + {isSearchingCustomers ? ( +
Searching...
+ ) : ( + deductFilteredCustomers.map((customer) => (
{ setFormField({ ...formField, deduct_origin: customer.id }); + setSelectedDeductCustomer(customer); + setDeductSearchTerm(''); setOpenDeductOrigin(false); }} > - {customer.username} + {customer.fullname}
- ))} - {customers.filter( - (customer) => - customer.username - .toLowerCase() - .includes(customerSearchTerm.toLowerCase()) || - customer.msisdn.includes(customerSearchTerm) - ).length === 0 && ( -
- No customer found -
+ )) )} + + {!isSearchingCustomers && + deductFilteredCustomers.length === 0 && + deductSearchTerm.trim() && ( +
+ No customer found +
+ )}
)} @@ -763,12 +878,19 @@ const EditFeeDialog = () => {
setOpenCreditDestination(!openCreditDestination)} + onClick={() => { + setOpenCreditDestination(!openCreditDestination); + if (!openCreditDestination && creditSearchTerm.trim() === '') { + searchCreditCustomers(''); + } + }} > - {customers.find( - (customer) => customer.id === formField.credit_destination - )?.username || 'Search customer...'} + {selectedCreditCustomer + ? selectedCreditCustomer.fullname + : creditFilteredCustomers.find( + (customer) => customer.id === formField.credit_destination + )?.fullname || 'Search customer...'}
@@ -779,23 +901,21 @@ const EditFeeDialog = () => { className="h-8 text-sm" type="text" placeholder="Search customer..." - value={customerSearchTerm} - onChange={(e) => setCustomerSearchTerm(e.target.value)} + value={creditSearchTerm} + onChange={(e) => { + const value = e.target.value; + setCreditSearchTerm(value); + }} autoComplete="off" onClick={(e) => e.stopPropagation()} autoFocus />
- {customers - .filter( - (customer) => - customer.username - .toLowerCase() - .includes(customerSearchTerm.toLowerCase()) || - customer.msisdn.includes(customerSearchTerm) - ) - .map((customer) => ( + {isSearchingCustomers ? ( +
Searching...
+ ) : ( + creditFilteredCustomers.map((customer) => (
{ setFormField({ ...formField, credit_destination: customer.id - }); - setOpenCreditDestination(false); + }); + setOpenCreditDestination(false); }} > - {customer.username} + {customer.fullname}
- ))} - {customers.filter( - (customer) => - customer.username - .toLowerCase() - .includes(customerSearchTerm.toLowerCase()) || - customer.msisdn.includes(customerSearchTerm) - ).length === 0 && ( -
- No customer found -
+ )) )} + + {!isSearchingCustomers && + creditFilteredCustomers.length === 0 && + creditSearchTerm.trim() && ( +
+ No customer found +
+ )}
)}