@@ -299,7 +298,34 @@ const DetailApprovalTransaction = () => {
kind = 'RETURN';
} else if (transactionDetails?.kind === 'E') {
kind = 'REWARD';
+ } else if (transactionDetails?.kind === 'L') {
+ kind = 'PURCHASE LOJA';
+ } else if (transactionDetails?.kind === 'B') {
+ kind = 'TOP UP P24';
+ } else if (transactionDetails?.kind === 'A') {
+ kind = 'TRANSFER AGENT';
+ } else if (transactionDetails?.kind === 'M') {
+ kind = 'WITHDRAWAL AGENT';
+ } else if (transactionDetails?.kind === 'O') {
+ kind = 'TOPUP AGENT';
+ } else if (transactionDetails?.kind === 'S') {
+ kind = 'TOPUP P24';
+ } else if (transactionDetails?.kind === 'I') {
+ kind = 'WITHDRAW MERCHANT';
+ } else if (transactionDetails?.kind === 'D') {
+ kind = 'DONATION';
+ } else if (transactionDetails?.kind === 'F') {
+ kind = 'FEE';
+ } else if (transactionDetails?.kind === 'V') {
+ kind = 'REVERSAL';
+ } else if (transactionDetails?.kind === 'C') {
+ kind = 'CASHBACK CASH';
+ } else if (transactionDetails?.kind === 'H') {
+ kind = 'CASHBACK POINT';
+ } else if (transactionDetails?.kind === 'J') {
+ kind = 'WITHDRAW ADMIN';
}
+
return kind;
})()}
@@ -419,7 +445,7 @@ const DetailApprovalTransaction = () => {
Info
-
+
Transaction Date
{transactionDetails?.transaction_date
@@ -436,9 +462,7 @@ const DetailApprovalTransaction = () => {
Full Name
-
- {transactionDetails?.origin_customer?.fullname ?? transactionDetails?.origin_customer?.origin_name}
-
+
{transactionDetails?.origin_name ?? ""}
Amount
@@ -502,7 +526,34 @@ const DetailApprovalTransaction = () => {
kind = 'RETURN';
} else if (transactionDetails?.kind === 'E') {
kind = 'REWARD';
+ } else if (transactionDetails?.kind === 'L') {
+ kind = 'PURCHASE LOJA';
+ } else if (transactionDetails?.kind === 'B') {
+ kind = 'TOP UP P24';
+ } else if (transactionDetails?.kind === 'A') {
+ kind = 'TRANSFER AGENT';
+ } else if (transactionDetails?.kind === 'M') {
+ kind = 'WITHDRAWAL AGENT';
+ } else if (transactionDetails?.kind === 'O') {
+ kind = 'TOPUP AGENT';
+ } else if (transactionDetails?.kind === 'S') {
+ kind = 'TOPUP P24';
+ } else if (transactionDetails?.kind === 'I') {
+ kind = 'WITHDRAW MERCHANT';
+ } else if (transactionDetails?.kind === 'D') {
+ kind = 'DONATION';
+ } else if (transactionDetails?.kind === 'F') {
+ kind = 'FEE';
+ } else if (transactionDetails?.kind === 'V') {
+ kind = 'REVERSAL';
+ } else if (transactionDetails?.kind === 'C') {
+ kind = 'CASHBACK CASH';
+ } else if (transactionDetails?.kind === 'H') {
+ kind = 'CASHBACK POINT';
+ } else if (transactionDetails?.kind === 'J') {
+ kind = 'WITHDRAW ADMIN';
}
+
return kind;
})()}
@@ -526,6 +577,30 @@ const DetailApprovalTransaction = () => {
{transactionDetails?.transfer.destination_iban}
+
+ Transfer Type
+
+ Transfer Type
+
+
+
+
+
Transfer Type
+
+ {
+ (() => {
+ if (transactionDetails?.transfer.type === "S") {
+ return "SEND";
+ } else if (transactionDetails?.transfer.type === "R") {
+ return "RECEIVE";
+ } else {
+ return "UNKNOWN";
+ }
+ })()
+ }
+
+
+
)}
@@ -535,14 +610,12 @@ const DetailApprovalTransaction = () => {
Full Name
-
- {transactionDetails?.origin_customer?.fullname ?? transactionDetails?.origin_customer?.origin_name}
-
+
{transactionDetails?.origin_name ?? ""}
-
+ {/*
Phone Number
{transactionDetails?.origin_customer?.msisdn ?? transactionDetails?.origin_msisdn}
-
+
*/}
Email
{transactionDetails?.origin_customer?.email ?? "-"}
@@ -801,8 +874,9 @@ const DetailApprovalTransaction = () => {
- {transactionDetails?.log_approve && transactionDetails?.log_approve.length > 0 ? (
- transactionDetails.log_approve.map((log: { created_at: string; status: string; updated_at: string }, index: number) => (
+ {[...transactionDetails.log_approve]
+ .sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime())
+ .map((log: { created_at: string; status: string; updated_at: string }, index: number) => (
|
{(() => {
@@ -815,13 +889,15 @@ const DetailApprovalTransaction = () => {
status = 'REJECT';
} else if (log.status === 'T') {
status = 'NO NEED';
+ } else {
+ status = log.status || 'UNKNOWN';
}
return status;
})()}
|
{new Date(log.created_at).toLocaleString('sv-SE', {
- timeZone: 'Asia/Jakarta', // kalau kamu mau waktu lokal (optional)
+ timeZone: 'Asia/Jakarta',
year: 'numeric',
month: '2-digit',
day: '2-digit',
@@ -829,18 +905,11 @@ const DetailApprovalTransaction = () => {
minute: '2-digit',
second: '2-digit',
hour12: false,
- }).replace(' ', ' ')}
+ })}
|
{/* {log.updated_at} | */}
- ))
- ) : (
-
- |
- No logs available
- |
-
- )}
+ ))}
@@ -848,6 +917,7 @@ const DetailApprovalTransaction = () => {
)}
+
{activeTab === 'p24' && (
P24 Logs
diff --git a/src/pages/transaction/approval-transaction/blocks/ListToolbar.tsx b/src/pages/transaction/approval-transaction/blocks/ListToolbar.tsx
index 559857f..37da31e 100644
--- a/src/pages/transaction/approval-transaction/blocks/ListToolbar.tsx
+++ b/src/pages/transaction/approval-transaction/blocks/ListToolbar.tsx
@@ -14,13 +14,11 @@ import {
const ListToolbar = () => {
const { table, reload } = useDataGrid();
- // State untuk filter
const [trxDate, settrxDate] = useState({ from: '', to: '' });
const [statusApproval, setStatusApproval] = useState('');
const [searchValue, setSearchValue] = useState('');
const [typeSearchValue, setSearchTypeValue] = useState('');
- // Set tanggal default saat pertama mount
useEffect(() => {
const today = new Date();
const formatDate = (date: Date) => date.toISOString().split('T')[0];
@@ -30,28 +28,21 @@ const ListToolbar = () => {
});
}, []);
- // Fungsi untuk apply semua filter sekaligus saat tombol Filter ditekan
const handleFilterData = useCallback(() => {
try {
- if (!trxDate.from || !trxDate.to) {
- toast.error('Please select From and To dates');
- return;
- }
+ // if (!trxDate.from || !trxDate.to) {
+ // toast.error('Please select From and To dates');
+ // return;
+ // }
- // Set filter tanggal
table.getColumn('transaction_date')?.setFilterValue(trxDate);
-
- // Set filter status approval
table.getColumn('status_approve')?.setFilterValue(statusApproval || '');
- // Set filter search type sebagai column filter id 'searchtype'
table.setColumnFilters((prevFilters) => {
- // Hapus dulu filter dengan id 'searchtype' dan 'code' agar gak duplikat
const filtered = prevFilters.filter(
(f) => f.id !== 'searchtype' && f.id !== 'code'
);
- // Tambahkan filter baru jika ada
if (typeSearchValue) {
filtered.push({ id: 'searchtype', value: typeSearchValue });
}
@@ -62,7 +53,6 @@ const ListToolbar = () => {
return filtered;
});
- // Reset ke halaman pertama
table.setPageIndex(0);
} catch (error) {
toast.error('Error applying filter');
@@ -79,7 +69,9 @@ const ListToolbar = () => {
settrxDate({ ...trxDate, from: e.target.value })}
+ onChange={(event) =>
+ settrxDate({ ...trxDate, from: event.target.value })
+ }
name="from"
/>
@@ -89,7 +81,9 @@ const ListToolbar = () => {
settrxDate({ ...trxDate, to: e.target.value })}
+ onChange={(event) =>
+ settrxDate({ ...trxDate, to: event.target.value })
+ }
name="to"
/>
@@ -110,7 +104,10 @@ const ListToolbar = () => {
Full Name
-
{transactionDetails?.origin_customer?.origin_name ?? ""}
+
{transactionDetails?.origin_name ?? ""}
Amount
@@ -456,22 +456,24 @@ const DetailTransaction = () => {
kind = 'TRANSFER AGENT';
} else if (transactionDetails?.kind === 'M') {
kind = 'WITHDRAWAL AGENT';
- }else if( transactionDetails?.kind === 'O') {
+ } else if (transactionDetails?.kind === 'O') {
kind = 'TOPUP AGENT';
- }else if (transactionDetails?.kind === 'S') {
+ } else if (transactionDetails?.kind === 'S') {
kind = 'TOPUP P24';
- }else if (transactionDetails?.kind === 'I') {
+ } else if (transactionDetails?.kind === 'I') {
kind = 'WITHDRAW MERCHANT';
- }else if (transactionDetails?.kind === 'D') {
+ } else if (transactionDetails?.kind === 'D') {
kind = 'DONATION';
- }else if (transactionDetails?.kind === 'F') {
+ } else if (transactionDetails?.kind === 'F') {
kind = 'FEE';
- }else if (transactionDetails?.kind === 'V') {
+ } else if (transactionDetails?.kind === 'V') {
kind = 'REVERSAL';
- }else if( transactionDetails?.kind === 'C') {
+ } else if (transactionDetails?.kind === 'C') {
kind = 'CASHBACK CASH';
- }else if( transactionDetails?.kind === 'H') {
+ } else if (transactionDetails?.kind === 'H') {
kind = 'CASHBACK POINT';
+ } else if (transactionDetails?.kind === 'J') {
+ kind = 'WITHDRAW ADMIN';
}
return kind;
@@ -499,7 +501,7 @@ const DetailTransaction = () => {
Info
-
+
Transaction Date
{transactionDetails?.transaction_date
@@ -516,7 +518,7 @@ const DetailTransaction = () => {
Full Name
-
{transactionDetails?.origin_customer?.origin_name ?? ""}
+
{transactionDetails?.origin_name ?? ""}
Amount
@@ -589,12 +591,39 @@ const DetailTransaction = () => {
kind = 'TOP UP';
} else if (transactionDetails?.kind === 'R') {
kind = 'RETURN';
- } else if (transactionDetails?.kind === 'E') {
} else if (transactionDetails?.kind === 'E') {
kind = 'REWARD';
+ } else if (transactionDetails?.kind === 'L') {
+ kind = 'PURCHASE LOJA';
+ } else if (transactionDetails?.kind === 'B') {
+ kind = 'TOP UP P24';
+ } else if (transactionDetails?.kind === 'A') {
+ kind = 'TRANSFER AGENT';
+ } else if (transactionDetails?.kind === 'M') {
+ kind = 'WITHDRAWAL AGENT';
+ } else if (transactionDetails?.kind === 'O') {
+ kind = 'TOPUP AGENT';
+ } else if (transactionDetails?.kind === 'S') {
+ kind = 'TOPUP P24';
+ } else if (transactionDetails?.kind === 'I') {
+ kind = 'WITHDRAW MERCHANT';
+ } else if (transactionDetails?.kind === 'D') {
+ kind = 'DONATION';
+ } else if (transactionDetails?.kind === 'F') {
+ kind = 'FEE';
+ } else if (transactionDetails?.kind === 'V') {
+ kind = 'REVERSAL';
+ } else if (transactionDetails?.kind === 'C') {
+ kind = 'CASHBACK CASH';
+ } else if (transactionDetails?.kind === 'H') {
+ kind = 'CASHBACK POINT';
+ } else if (transactionDetails?.kind === 'J') {
+ kind = 'WITHDRAW ADMIN';
}
+
return kind;
})()}
+
@@ -614,6 +643,30 @@ const DetailTransaction = () => {
{transactionDetails?.transfer.destination_iban}
+
+ Transfer Type
+
+ Transfer Type
+
+
+
+
+
Transfer Type
+
+ {
+ (() => {
+ if (transactionDetails?.transfer.type === "S") {
+ return "SEND";
+ } else if (transactionDetails?.transfer.type === "R") {
+ return "RECEIVE";
+ } else {
+ return "UNKNOWN";
+ }
+ })()
+ }
+
+
+
)}
@@ -623,13 +676,13 @@ const DetailTransaction = () => {
Full Name
-
{transactionDetails?.origin_customer?.origin_name}
+
{transactionDetails?.origin_name}
-
+ {/*
Phone Number
{transactionDetails?.origin_msisdn}
{transactionDetails?.origin_customer?.origin_name ?? ""}
-
+
*/}
Phone Number
{transactionDetails?.origin_customer?.msisdn ?? transactionDetails?.origin_msisdn}
@@ -893,8 +946,9 @@ const DetailTransaction = () => {
- {transactionDetails?.log_approve && transactionDetails?.log_approve.length > 0 ? (
- transactionDetails.log_approve.map((log: { created_at: string; status: string; updated_at: string }, index: number) => (
+ {[...transactionDetails.log_approve]
+ .sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime())
+ .map((log: { created_at: string; status: string; updated_at: string }, index: number) => (
|
{(() => {
@@ -907,13 +961,15 @@ const DetailTransaction = () => {
status = 'REJECT';
} else if (log.status === 'T') {
status = 'NO NEED';
+ } else {
+ status = log.status || 'UNKNOWN';
}
return status;
})()}
|
{new Date(log.created_at).toLocaleString('sv-SE', {
- timeZone: 'Asia/Jakarta', // kalau kamu mau waktu lokal (optional)
+ timeZone: 'Asia/Jakarta',
year: 'numeric',
month: '2-digit',
day: '2-digit',
@@ -921,18 +977,11 @@ const DetailTransaction = () => {
minute: '2-digit',
second: '2-digit',
hour12: false,
- }).replace(' ', ' ')}
+ })}
|
{/* {log.updated_at} | */}
- ))
- ) : (
-
- |
- No logs available
- |
-
- )}
+ ))}
diff --git a/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx b/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx
index 72987dc..031d62e 100644
--- a/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx
+++ b/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx
@@ -28,31 +28,29 @@ const ListToolbar = () => {
const formatDate = (date: Date): string => date.toISOString().split('T')[0];
- // Set tanggal default hari ini saat mount
useEffect(() => {
const today = new Date();
const formatted = formatDate(today);
settrxDate({ from: formatted, to: formatted });
}, []);
- // **Hilangkan semua useEffect yang auto apply filter saat input berubah**
- // Karena kamu mau filter apply hanya lewat tombol Filter
-
- // Fungsi untuk apply SEMUA filter sekaligus saat tombol Filter diklik
- const handleFilterData = useCallback(() => {
- if (!trxDate.from || !trxDate.to) {
- toast.error('Please select both From and To dates');
- return;
+ // ✅ Reset tanggal jika typeSearchValue dipilih
+ useEffect(() => {
+ if (typeSearchValue) {
+ settrxDate({ from: '', to: '' });
}
+ }, [typeSearchValue]);
+
+ const handleFilterData = useCallback(() => {
+ // if (!trxDate.from || !trxDate.to) {
+ // toast.error('Please select both From and To dates');
+ // return;
+ // }
- // Terapkan filter tanggal
table.getColumn('transaction_date')?.setFilterValue(trxDate);
- // Terapkan filter jenis transaksi (kind)
table.setColumnFilters((prev) => {
- // Hapus filter 'kind' dan 'searchtype' agar bisa set ulang
const others = prev.filter(f => f.id !== 'kind' && f.id !== 'searchtype' && f.id !== 'code');
- // Bangun array baru dengan filter yang diinginkan
const filters: any[] = [...others];
if (typeValue) filters.push({ id: 'kind', value: typeValue });
@@ -146,6 +144,7 @@ const ListToolbar = () => {
name="to"
/>
+
diff --git a/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx b/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx
index 6069da8..dfa0451 100644
--- a/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx
+++ b/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx
@@ -9,6 +9,7 @@ import { useNavigate } from 'react-router';
import DetailTransaction from '../blocks/DetailTransaction';
import ResendTransaction from '../blocks/ResendTransaction';
import RollbackTransaction from '../blocks/RollbackTransaction';
+import { start } from 'repl';
interface TransactionProps {
id: number;
@@ -90,6 +91,7 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => {
case 'V': return 'REVERSAL';
case 'C': return 'CASHBACK CASH';
case 'H': return 'CASHBACK POINT';
+ case 'J': return 'WITHDRAW ADMIN';
default: return '_';
}
},
@@ -298,24 +300,15 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => {
const today = new Date();
const firstDayOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
- let startdate = firstDayOfMonth.toISOString().split('T')[0];
- let enddate = today.toISOString().split('T')[0];
+ let startdate: string | undefined;
+ let enddate: string | undefined;
let transactioncode = '';
let type = '';
-
- // ✅ Declare formattedFilter early
- const formattedFilter: any = {
- "Transactions.transaction_date": {
- from: `${startdate} 00:00:00`,
- to: `${enddate} 23:59:59`
- }
- };
+ let searchType = '';
+ let codeValue = '';
if (Array.isArray(filter)) {
- let searchType = '';
- let codeValue = '';
-
- // Ambil code dan searchtype dulu
+ // Ambil semua value dari filter terlebih dahulu
filter.forEach((f: any) => {
if (f.id === 'code' && f.value) {
codeValue = f.value;
@@ -328,10 +321,6 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => {
if (f.id === 'transaction_date' && f.value?.from && f.value?.to) {
startdate = f.value.from;
enddate = f.value.to;
- formattedFilter["Transactions.transaction_date"] = {
- from: `${startdate} 00:00:00`,
- to: `${enddate} 23:59:59`
- };
}
if (f.id === 'kind' && f.value) {
@@ -339,7 +328,30 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => {
}
});
- // Terapkan berdasarkan searchtype + code
+ // Kalau tidak ada searchType, baru pakai tanggal
+ if (!searchType) {
+ if (!startdate || !enddate) {
+ startdate = firstDayOfMonth.toISOString().split('T')[0];
+ enddate = today.toISOString().split('T')[0];
+ }
+ } else {
+ // Kosongkan supaya tidak digunakan di bawah
+ startdate = undefined;
+ enddate = undefined;
+ }
+
+ // Build formattedFilter setelah semua nilai diketahui
+ const formattedFilter: any = {};
+
+ // Tambahkan filter tanggal HANYA jika tidak ada searchType
+ if (startdate && enddate) {
+ formattedFilter["Transactions.transaction_date"] = {
+ from: `${startdate} 00:00:00`,
+ to: `${enddate} 23:59:59`
+ };
+ }
+
+ // Tambahkan filter berdasarkan searchType
if (searchType && codeValue) {
if (searchType === "msisdn") {
formattedFilter["origin_customer.msisdn"] = { like: `%${codeValue}%` };
@@ -349,29 +361,31 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => {
formattedFilter["Transactions.code"] = { like: `%${codeValue}%` };
}
}
+
+ // Tambahkan filter jenis transaksi jika ada
+ if (type) {
+ formattedFilter["Transactions.kind"] = type;
+ }
+
+ const response = await GetData(`${API_URL}/transaction/history`, {
+ limit,
+ page: page + 1,
+ with_deleted: false,
+ order_field: "Transactions.created_at",
+ order_direction: 'DESC',
+ filter: JSON.stringify(formattedFilter)
+ });
+
+ if (!response || !response.data) {
+ console.warn('No data received:', response);
+ return { data: [], totalCount: 0 };
+ }
+
+ setTransaction(response.data.list);
+ return { data: response.data.list, totalCount: response.data.total_count };
}
-
- if (type) {
- formattedFilter["Transactions.kind"] = type;
- }
-
- const response = await GetData(`${API_URL}/transaction/history`, {
- limit,
- page: page + 1,
- with_deleted: false,
- order_field: "Transactions.created_at",
- order_direction: 'DESC',
- filter: JSON.stringify(formattedFilter)
- });
-
- if (!response || !response.data) {
- console.warn('No data received:', response);
- return { data: [], totalCount: 0 };
- }
-
- setTransaction(response.data.list);
- return { data: response.data.list, totalCount: response.data.total_count };
+ return { data: [], totalCount: 0 };
} catch (error) {
console.error('Error fetching transaction', error);
@@ -380,6 +394,7 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => {
};
+
return (
{
+ return (
+ <>
+
+ TPAY | Withdrawal Emoney
+
+
+
+
+ TRANSACTION WITHDRAWAL EMONEY
+
+
+
+ Dashboard
+
+
+ Transaction
+
+
+ Withdraw Saldo
+
+
+
+
+
+ >
+ );
+};
+
+export default WithdrawalEmoney;
diff --git a/src/pages/transaction/withdrawl-emoney/blocks/WithdrawInput.tsx b/src/pages/transaction/withdrawl-emoney/blocks/WithdrawInput.tsx
new file mode 100644
index 0000000..15b4b7d
--- /dev/null
+++ b/src/pages/transaction/withdrawl-emoney/blocks/WithdrawInput.tsx
@@ -0,0 +1,300 @@
+import { getAuth } from '@/auth';
+import { Alert, Container } from '@/components';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { apiConfig } from '@/config/api.config';
+import { useCallApi } from '@/hooks';
+import { RefreshCw } from 'lucide-react';
+import { useEffect, useRef, useState } from 'react';
+import { toast } from 'sonner';
+
+const WithdrawInput = () => {
+ const initialForm: {
+ id_customer: string;
+ amount: string;
+ pin: string;
+ purpose: string;
+ } = {
+ id_customer: '',
+ amount: '',
+ pin: '',
+ purpose: ''
+ };
+
+ const [form, setForm] = useState(initialForm);
+ const [isLoading, setIsLoading] = useState(false);
+ const [customerMsisdn, setCustomerMsisdn] = useState<{ value: string; label: string }[]>([]);
+ const [searchTerm, setSearchTerm] = useState('');
+ const [dropdownOpen, setDropdownOpen] = useState(false);
+ const { GetData, PostData } = useCallApi();
+ const [isSubmitting, setIsSubmitting] = useState(false);
+ const [showConfirmation, setShowConfirmation] = useState(false);
+ const parsedUser = getAuth()?.user;
+ const API_URL = apiConfig.transaction;
+ const API_URL_WALLET = apiConfig.service_wallet;
+ const API_URL_CUSTOMER = apiConfig.service_customer;
+ const dropdownRef = useRef(null);
+
+ const [alert, setAlert] = useState({
+ show: false,
+ message: ''
+ });
+
+ const ResetForm = () => {
+ setForm(initialForm);
+ setAlert({ show: false, message: '' });
+ setSearchTerm('');
+ };
+
+ const fetchCustomerMsisdn = async (sorting: any, filterValue: string) => {
+ const filter: any =
+ filterValue.trim().length === 0
+ ? {}
+ : {
+ or: [
+ { msisdn: { like: `%${filterValue}%` } },
+ { fullname: { like: `%${filterValue}%` } }
+ ]
+ };
+
+ const query: any = {
+ limit: 100,
+ page: 1,
+ with_deleted: false,
+ order_field: sorting[0].id,
+ order_direction: sorting[0].desc ? 'DESC' : 'ASC'
+ };
+
+ if (filter && Object.keys(filter).length > 0) {
+ query.filter = JSON.stringify(filter);
+ // query.page = page + 1;
+ }
+
+ try {
+ const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, query);
+ setCustomerMsisdn(
+ response?.data.list.map((item: any) => ({
+ value: item.id,
+ label: `${item.msisdn} - ${item.fullname}`
+ }))
+ );
+ } catch (error) {
+ toast.error('Failed to fetch customer msisdn');
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ const doPostData = async (form: typeof initialForm) => {
+ setIsSubmitting(true);
+ // console.log(getAuth()?.user.customer.id);
+
+ try {
+ let response = await PostData(`${API_URL}/transaction/transfer`, {
+ msisdn_destination: '1112007',
+ amount: form.amount,
+ pin: form.pin,
+ purpose: form.purpose,
+ id_transaction_type: '380f270b-1f44-406f-a196-d6f784d68eb4',
+ id_origin_customer: form.id_customer,
+ type: 'S'
+ });
+ if (response?.status == true) {
+ toast.success('Success Request Topup');
+ } else {
+ toast.error(`${response?.message?.message}`);
+ }
+ } catch (error: any) {
+ const errorMessage =
+ error?.response?.data?.message || error?.message || 'Something went wrong';
+ toast.error(errorMessage);
+ setAlert({ show: true, message: errorMessage });
+ } finally {
+ setIsSubmitting(false);
+ setShowConfirmation(false);
+ ResetForm();
+ }
+ };
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ if (form.amount == '' || form.id_customer == '' || form.pin == '') {
+ setAlert({
+ show: true,
+ message: 'Please fill in all required fields.'
+ });
+ return;
+ }
+ setAlert({ show: false, message: '' });
+ setShowConfirmation(true);
+ };
+
+ const handleCancelSubmit = () => {
+ setShowConfirmation(false);
+ };
+
+ const handleMsisdnSearch = (e: React.ChangeEvent) => {
+ setIsLoading(true);
+ setSearchTerm(e.target.value);
+ setDropdownOpen(true);
+ const timer = setTimeout(() => {
+ fetchCustomerMsisdn([{ id: 'msisdn', desc: false }], e.target.value);
+ }, 500);
+ return () => clearTimeout(timer);
+ };
+
+ const handleMsisdnSelect = (item: { value: string; label: string }) => {
+ setForm({ ...form, id_customer: item.value });
+ setDropdownOpen(false);
+ setSearchTerm(item.label);
+ };
+
+ useEffect(() => {
+ fetchCustomerMsisdn([{ id: 'msisdn', desc: false }], '');
+
+ const handleClickOutside = (event: any) => {
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
+ setDropdownOpen(false);
+ }
+ };
+
+ document.addEventListener('mousedown', handleClickOutside);
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside);
+ };
+ }, []);
+
+ const filteredMsisdn = customerMsisdn
+ .filter((item) => item.label.toLowerCase().includes(searchTerm.toLowerCase()))
+ .slice(0, 10);
+
+ return (
+ <>
+
+
+
+ {alert.show && (
+
+ {alert.message}
+
+ )}
+ {/* form */}
+
+
+
+
+
+ {showConfirmation && (
+
+
+
Confirm Transaction
+
+ Are you sure you want to withdraw saldo of{' '}
+
+ {new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(
+ Number(form.amount)
+ )}{' '}
+
+ ?
+
+
+
+
+
+
+
+ )}
+ >
+ );
+};
+
+export default WithdrawInput;
diff --git a/src/pages/transaction/withdrawl-emoney/hooks/TransactionWithdrawalEmoneyContext.tsx b/src/pages/transaction/withdrawl-emoney/hooks/TransactionWithdrawalEmoneyContext.tsx
new file mode 100644
index 0000000..f978f52
--- /dev/null
+++ b/src/pages/transaction/withdrawl-emoney/hooks/TransactionWithdrawalEmoneyContext.tsx
@@ -0,0 +1,58 @@
+import { apiConfig } from '@/config/api.config';
+import { createContext } from 'react';
+
+interface TransactionWithdrawalProps {
+ id: string;
+ customers_id: string;
+ group_id: string;
+ username: string;
+ fullname: string;
+ email: string;
+ status: string;
+ created_at: Date;
+}
+
+interface ContextProps {}
+
+const initialProps: ContextProps = {};
+
+const TransactionWithdrawalEmoneyContext = createContext(initialProps);
+const API_URL = apiConfig.service_customer;
+
+type StatusCode = 'W' | 'Y' | 'N' | 'T';
+
+interface StatusInfo {
+ label: string;
+ bg: string;
+ text: string;
+}
+
+const statusMap: Record = {
+ W: { label: 'Waiting Approval', bg: 'bg-yellow-100', text: 'text-yellow-600' },
+ T: { label: 'No Need', bg: 'bg-blue-100', text: 'text-blue-600' },
+ N: { label: 'Reject', bg: 'bg-red-100', text: 'text-red-600' },
+ Y: { label: 'Approve', bg: 'bg-green-100', text: 'text-green-600' }
+};
+
+export const renderStatusBadge = (statusRaw: string | null | undefined) => {
+ const status = statusRaw as StatusCode;
+ const { label, bg, text } = statusMap[status] ?? {
+ label: 'Unknown',
+ bg: 'bg-gray-100',
+ text: 'text-gray-600'
+ };
+
+ return (
+ {label}
+ );
+};
+
+const TransactionWithdrawalEmoneyProvider = ({ children }: { children: React.ReactNode }) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export { TransactionWithdrawalEmoneyProvider, TransactionWithdrawalEmoneyContext };
diff --git a/src/pages/transaction/withdrawl-emoney/hooks/useTransactionWithdrawalEmoney.tsx b/src/pages/transaction/withdrawl-emoney/hooks/useTransactionWithdrawalEmoney.tsx
new file mode 100644
index 0000000..a86d61e
--- /dev/null
+++ b/src/pages/transaction/withdrawl-emoney/hooks/useTransactionWithdrawalEmoney.tsx
@@ -0,0 +1,12 @@
+import { useContext } from 'react';
+import { TransactionWithdrawalEmoneyContext } from './TransactionWithdrawalEmoneyContext';
+
+const useTransactionWithdrawalEmoneyContext = () => {
+ const context = useContext(TransactionWithdrawalEmoneyContext);
+
+ if (!context) throw new Error('useTransactionWithdrawalEmoney must be used within AuthProvider');
+
+ return context;
+};
+
+export { useTransactionWithdrawalEmoneyContext };
diff --git a/src/pages/transfer/transferfee/blocks/AddDialog.tsx b/src/pages/transfer/transferfee/blocks/AddDialog.tsx
index 13469dc..612ac36 100644
--- a/src/pages/transfer/transferfee/blocks/AddDialog.tsx
+++ b/src/pages/transfer/transferfee/blocks/AddDialog.tsx
@@ -114,7 +114,8 @@ const AddFeeDialog = () => {
deduct_from_account: '',
credit_to: '',
credit_destination: '00000000-0000-0000-0000-000000000000',
- credit_destination_account: ''
+ credit_destination_account: '',
+ deduct_when: 'A'
};
const [formField, setFormField] = useState(initialState);
@@ -389,13 +390,19 @@ const AddFeeDialog = () => {
);
};
+ useEffect(() => {
+ if (formField.status_include === 'N') {
+ setFormField((prev) => ({ ...prev, deduct_when: 'A' }));
+ }
+ }, [formField.status_include]);
+
return (
+ {formField.status_include === 'Y' && (
+
+
+
+
+ )}
-
-
-
{
placeholder="Enter Minimum Amount"
/>
-
{
placeholder="Enter Maximum Amount"
/>
-
-
-
{
placeholder="Enter Deduct Amount"
/>
-
{
placeholder="Enter Deduct Percentage"
/>
-
+ {formField.deduct_from === 'I' && (
+
+
+
+
setOpenDeductOrigin(!openDeductOrigin)}
+ >
+
+ {customers.find((customer) => customer.id === formField.deduct_origin)
+ ?.username || 'Search customer...'}
+
+
-{formField.deduct_from === 'I' && (
-
-
-
-
setOpenDeductOrigin(!openDeductOrigin)}
- >
-
- {customers.find((customer) => customer.id === formField.deduct_origin)?.username || 'Search customer...'}
-
-
-
- {openDeductOrigin && (
-
-
- setCustomerSearchTerm(e.target.value)}
- autoComplete="off"
- onClick={(e) => e.stopPropagation()}
- autoFocus
- />
-
-
- {customers
- .filter(
- (customer) =>
- customer.username.toLowerCase().includes(customerSearchTerm.toLowerCase()) ||
- customer.msisdn.includes(customerSearchTerm)
- )
- .map((customer) => (
-
{
- setFormField({ ...formField, deduct_origin: customer.id });
- setOpenDeductOrigin(false);
- }}
- >
- {customer.username}
-
- ))}
- {customers.filter(
- (customer) =>
- customer.username.toLowerCase().includes(customerSearchTerm.toLowerCase()) ||
- customer.msisdn.includes(customerSearchTerm)
- ).length === 0 && (
-
No customer found
- )}
-
-
- )}
-
-
-)}
-
-
+ {openDeductOrigin && (
+
+
+ setCustomerSearchTerm(e.target.value)}
+ autoComplete="off"
+ onClick={(e) => e.stopPropagation()}
+ autoFocus
+ />
+
+
+ {customers
+ .filter(
+ (customer) =>
+ customer.username
+ .toLowerCase()
+ .includes(customerSearchTerm.toLowerCase()) ||
+ customer.msisdn.includes(customerSearchTerm)
+ )
+ .map((customer) => (
+
{
+ setFormField({ ...formField, deduct_origin: customer.id });
+ setOpenDeductOrigin(false);
+ }}
+ >
+ {customer.username}
+
+ ))}
+ {customers.filter(
+ (customer) =>
+ customer.username
+ .toLowerCase()
+ .includes(customerSearchTerm.toLowerCase()) ||
+ customer.msisdn.includes(customerSearchTerm)
+ ).length === 0 && (
+
+ No customer found
+
+ )}
+
+
+ )}
+
+
+ )}
+ {formField.credit_to === 'I' && (
+
+
+
+
setOpenCreditDestination(!openCreditDestination)}
+ >
+
+ {customers.find(
+ (customer) => customer.id === formField.credit_destination
+ )?.username || 'Search customer...'}
+
+
-{formField.credit_to === 'I' && (
-
-
-
-
setOpenCreditDestination(!openCreditDestination)}
- >
-
- {customers.find((customer) => customer.id === formField.credit_destination)
- ?.username || 'Search customer...'}
-
-
-
- {openCreditDestination && (
-
-
- setCustomerSearchTerm(e.target.value)}
- autoComplete="off"
- onClick={(e) => e.stopPropagation()}
- autoFocus
- />
-
-
- {customers
- .filter(
- (customer) =>
- customer.username
- .toLowerCase()
- .includes(customerSearchTerm.toLowerCase()) ||
- customer.msisdn.includes(customerSearchTerm)
- )
- .map((customer) => (
-
{
- setFormField({
- ...formField,
- credit_destination: customer.id
- });
- setOpenCreditDestination(false);
- }}
- >
- {customer.username}
-
- ))}
- {customers.filter(
- (customer) =>
- customer.username
- .toLowerCase()
- .includes(customerSearchTerm.toLowerCase()) ||
- customer.msisdn.includes(customerSearchTerm)
- ).length === 0 && (
-
No customer found
- )}
-
-
- )}
-
-
-)}
-
-
+ {openCreditDestination && (
+
+
+ setCustomerSearchTerm(e.target.value)}
+ autoComplete="off"
+ onClick={(e) => e.stopPropagation()}
+ autoFocus
+ />
+
+
+ {customers
+ .filter(
+ (customer) =>
+ customer.username
+ .toLowerCase()
+ .includes(customerSearchTerm.toLowerCase()) ||
+ customer.msisdn.includes(customerSearchTerm)
+ )
+ .map((customer) => (
+
{
+ setFormField({
+ ...formField,
+ credit_destination: customer.id
+ });
+ setOpenCreditDestination(false);
+ }}
+ >
+ {customer.username}
+
+ ))}
+ {customers.filter(
+ (customer) =>
+ customer.username
+ .toLowerCase()
+ .includes(customerSearchTerm.toLowerCase()) ||
+ customer.msisdn.includes(customerSearchTerm)
+ ).length === 0 && (
+
+ No customer found
+
+ )}
+
+
+ )}
+
+
+ )}
-
-
-
+ {formField.status_include === 'Y' && (
+
+
+
+
+ )}