From 6d7cd839d6999dfed61c859d0fbd74018df323dd Mon Sep 17 00:00:00 2001 From: wayanrivan Date: Mon, 19 May 2025 11:39:10 +0700 Subject: [PATCH 1/7] update page transaction --- .../dashboards/home/blocks/MemberActivity.tsx | 86 ++++--- .../home/blocks/TransactionPieChart.tsx | 6 +- .../home/blocks/TransactionValue.tsx | 12 + .../blocks/DetailApprovalTransaction.tsx | 4 +- .../blocks/DetailTransaction.tsx | 239 +++++++++++------- .../blocks/ListToolbar.tsx | 4 + .../hooks/TransactionContext.tsx | 4 + 7 files changed, 233 insertions(+), 122 deletions(-) diff --git a/src/pages/dashboards/home/blocks/MemberActivity.tsx b/src/pages/dashboards/home/blocks/MemberActivity.tsx index 79c998d..badc8b0 100644 --- a/src/pages/dashboards/home/blocks/MemberActivity.tsx +++ b/src/pages/dashboards/home/blocks/MemberActivity.tsx @@ -10,12 +10,37 @@ interface Props { enddate: string; } +const polarToCartesian = (cx: number, cy: number, radius: number, angleInDegrees: number) => { + const angleInRadians = (angleInDegrees * Math.PI) / 180.0; + return { + x: cx + radius * Math.cos(angleInRadians), + y: cy + radius * Math.sin(angleInRadians), + }; +}; + +const describeArc = ( + x: number, + y: number, + radius: number, + startAngle: number, + endAngle: number +) => { + const start = polarToCartesian(x, y, radius, endAngle); + const end = polarToCartesian(x, y, radius, startAngle); + const largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1"; + + return [ + "M", start.x, start.y, + "A", radius, radius, 0, largeArcFlag, 0, end.x, end.y, + ].join(" "); +}; + const MemberActivity = ({ startdate, enddate }: Props) => { const { GetData } = useCallApi(); const [responseTransactionValue, setResponseTransactionValue] = useState(null); useEffect(() => { - const fetchDataTransactionValue = async () => { + const fetchData = async () => { try { const res = await GetData(`${API_URL}/active-user`, { date_from: startdate, @@ -23,43 +48,33 @@ const MemberActivity = ({ startdate, enddate }: Props) => { }); setResponseTransactionValue(res); } catch (error) { - console.error('Error fetching transaction value:', error); + console.error('Error fetching data:', error); } }; - fetchDataTransactionValue(); + fetchData(); }, [startdate, enddate, GetData]); - const percentage = parseFloat((responseTransactionValue?.data?.total_customer_active_percentage ?? 0).toFixed(2)) ?? 0; + const percentage = parseFloat((responseTransactionValue?.data?.total_customer_active_percentage ?? 0).toFixed(2)); const totalCustomer = responseTransactionValue?.data?.total_customer ?? 0; const activeCustomer = responseTransactionValue?.data?.total_customer_active ?? 0; const reguler = responseTransactionValue?.data?.reguler ?? 0; const premium = responseTransactionValue?.data?.premium ?? 0; const agent = responseTransactionValue?.data?.agent ?? 0; - // Hitung sudut pointer - const angle = (percentage / 100) * 180; // 0° (kiri) ke 180° (kanan) - const radians = (angle * Math.PI) / 180; - const radius = 40; // Radius dari setengah lingkaran - const center = 50; // Titik pusat lingkaran - const pointerLength = 25; // Panjang pointer - - const x = center + pointerLength * Math.cos(radians - Math.PI); // offset agar mulai dari kiri - const y = center + pointerLength * Math.sin(radians - Math.PI); - - // Hitung titik akhir untuk arc aktif - const arcAngle = (Math.PI * percentage) / 100; - const arcX = 50 + radius * Math.cos(Math.PI - arcAngle); - const arcY = 50 - radius * Math.sin(arcAngle); + // Calculate pointer angle + const angle = (percentage / 100) * 180; + const pointerX = 50 + 25 * Math.cos((angle - 180) * Math.PI / 180); + const pointerY = 50 + 25 * Math.sin((angle - 180) * Math.PI / 180); return ( -
-
+
+

Member Activity

- {/* Sidebar */} + {/* Sidebar Info */}
  • @@ -70,15 +85,15 @@ const MemberActivity = ({ startdate, enddate }: Props) => { Active Customer: {activeCustomer}
  • - + Reguler: {reguler}
  • - + Premium: {premium}
  • - + Agent: {agent}
@@ -88,7 +103,7 @@ const MemberActivity = ({ startdate, enddate }: Props) => {

Active User

- + {/* Background arc */} { strokeWidth="10" /> {/* Active arc */} - 50 ? 1 : 0} 1 ${arcX} ${arcY}`} - fill="none" - stroke="#34d399" - strokeWidth="10" - /> + {percentage > 0 && ( + + )} {/* Pointer */} -
+
{percentage}% 100%
diff --git a/src/pages/dashboards/home/blocks/TransactionPieChart.tsx b/src/pages/dashboards/home/blocks/TransactionPieChart.tsx index 904b962..d5b0aae 100644 --- a/src/pages/dashboards/home/blocks/TransactionPieChart.tsx +++ b/src/pages/dashboards/home/blocks/TransactionPieChart.tsx @@ -43,7 +43,11 @@ const TransactionPieChart = ({ startdate, enddate }: Props) => { { name: 'Purchase', value: parseFloat((responseTransactionValue?.data?.P ?? 0).toFixed(2)), color: '#baf7c5' }, { name: 'Withdraw', value: parseFloat((responseTransactionValue?.data?.W ?? 0).toFixed(2)), color: '#f56565' }, { name: 'Top Up Partner', value: parseFloat((responseTransactionValue?.data?.N ?? 0).toFixed(2)), color: '#f7fa52' }, - { name: 'Reward', value: parseFloat((responseTransactionValue?.data?.E ?? 0).toFixed(2)), color: '#f7fa52' }, + { name: 'Reward', value: parseFloat((responseTransactionValue?.data?.E ?? 0).toFixed(2)), color: '#f50a19' }, + { name: 'Purchase Loja', value: parseFloat((responseTransactionValue?.data?.L ?? 0).toFixed(2)), color: '#F0A04B' }, + { name: 'Top Up P24', value: parseFloat((responseTransactionValue?.data?.B ?? 0).toFixed(2)), color: '#FADA7A' }, + { name: 'Transfer Agent', value: parseFloat((responseTransactionValue?.data?.A ?? 0).toFixed(2)), color: '#B1C29E' }, + { name: 'Withdrawal Agent', value: parseFloat((responseTransactionValue?.data?.M ?? 0).toFixed(2)), color: '#FCE7C8' }, ]; return ( diff --git a/src/pages/dashboards/home/blocks/TransactionValue.tsx b/src/pages/dashboards/home/blocks/TransactionValue.tsx index 451decc..3892b15 100644 --- a/src/pages/dashboards/home/blocks/TransactionValue.tsx +++ b/src/pages/dashboards/home/blocks/TransactionValue.tsx @@ -67,6 +67,18 @@ const TransactionValue = ({ startdate, enddate }: Props) => { case "E": type = "Reward"; break; + case "L": + type = "Purchase Loja" + break; + case "B": + type ="Top Up P24"; + break; + case "A": + type = " Transfer Agent"; + break; + case "M": + type = "Withdrawal Agent"; + break; default: type = "Unknown"; break; diff --git a/src/pages/transaction/approval-transaction/blocks/DetailApprovalTransaction.tsx b/src/pages/transaction/approval-transaction/blocks/DetailApprovalTransaction.tsx index 53541be..dd878f6 100644 --- a/src/pages/transaction/approval-transaction/blocks/DetailApprovalTransaction.tsx +++ b/src/pages/transaction/approval-transaction/blocks/DetailApprovalTransaction.tsx @@ -118,12 +118,12 @@ const DetailApprovalTransaction = () => { {/* Tabs Navigation */}
- + */} + {transactionDetails?.kind == 'P' && ( + + )} + - + {transactionDetails?.kind !== 'P' && ( + + )} + - - + {transactionDetails?.kind !== 'P' && ( + + )} + + {transactionDetails?.kind !== 'P' && ( + + )} +
{/* Tab Content */} @@ -281,8 +321,16 @@ 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'; } return kind; })()} @@ -338,59 +386,60 @@ const DetailTransaction = () => {
)} - {activeTab === 'detail' && ( -
-

- Product Information - - Product Info - -

-
-
-

Product Name

-

- {transactionDetails?.purchase?.product?.name ?? "-"} -

-
-
-

Price Cash

-

- {transactionDetails?.purchase?.product?.price_cash != null - ? new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(transactionDetails.purchase.product.price_cash) - : "-"} -

-
-
-

Price Point

-

- {transactionDetails?.purchase?.product?.price_point ?? "-"} -

-
-
-

Product Type

-

- {transactionDetails?.purchase?.product?.type ?? "-"} -

-
-
-

Provider Name

-

- {transactionDetails?.purchase?.product?.provider?.description ?? "-"} -

-
-
-

Provider Type

-

- {transactionDetails?.purchase?.product?.provider?.type === "h2h" - ? "HOST TO HOST" - : transactionDetails?.purchase?.product?.provider?.type === "agent" - ? "AGENT" + + {activeTab === 'detail' && transactionDetails?.kind == 'P' && ( +

+

+ Product Information + + Product Info + +

+
+
+

Product Name

+

+ {transactionDetails?.purchase?.product?.name ?? "-"} +

+
+
+

Price Cash

+

+ {transactionDetails?.purchase?.product?.price_cash != null + ? new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(transactionDetails.purchase.product.price_cash) : "-"} -

+

+
+
+

Price Point

+

+ {transactionDetails?.purchase?.product?.price_point ?? "-"} +

+
+
+

Product Type

+

+ {transactionDetails?.purchase?.product?.type ?? "-"} +

+
+
+

Provider Name

+

+ {transactionDetails?.purchase?.product?.provider?.description ?? "-"} +

+
+
+

Provider Type

+

+ {transactionDetails?.purchase?.product?.provider?.type === "h2h" + ? "HOST TO HOST" + : transactionDetails?.purchase?.product?.provider?.type === "agent" + ? "AGENT" + : "-"} +

+
-
)} {activeTab === 'detail' && transactionDetails?.kind != 'P' && transactionDetails?.transfer != null && ( @@ -463,7 +512,7 @@ const DetailTransaction = () => { kind = 'TOP UP'; } else if (transactionDetails?.kind === 'R') { kind = 'RETURN'; - }else if (transactionDetails?.kind === 'E') { + } else if (transactionDetails?.kind === 'E') { kind = 'REWARD'; } return kind; @@ -592,7 +641,7 @@ const DetailTransaction = () => {
)} - {activeTab === 'destinationwallet' && ( + {activeTab === 'destinationwallet' && transactionDetails?.kind?.trim()?.toUpperCase() !== 'P' && (

Destination Wallet

@@ -651,7 +700,7 @@ const DetailTransaction = () => { Type Request Date Response Date - Response Body + {/* Response Body */} Response Code Request Endpoint @@ -683,8 +732,18 @@ const DetailTransaction = () => { hour12: false }) : ''} - {log.request_body} - {log.response_body} + {/* {log.request_body} */} + +
+                                                        
                                                         {log.request_endpoint}
                                                     
                                                 ))
@@ -701,7 +760,7 @@ const DetailTransaction = () => {
                             
)} - {activeTab === 'approve' && ( + {activeTab === 'approve' && transactionDetails?.kind == "P" && (

Approval Logs

{transactionDetails?.log_approve.length === 0 ? ( @@ -777,7 +836,7 @@ const DetailTransaction = () => { Type Request Date Response Date - Response Body + {/* Response Body */} Response Code Request Endpoint @@ -810,8 +869,18 @@ const DetailTransaction = () => { hour12: false }) : ''} - {log.request_body} - {log.response_body} + {/* {log.request_body} */} + +
+                                                            
                                                             {log.request_endpoint ?? '-'}
                                                         
                                                     ))
diff --git a/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx b/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx
index 342c24e..413b7ef 100644
--- a/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx
+++ b/src/pages/transaction/history-transaction/blocks/ListToolbar.tsx
@@ -178,6 +178,10 @@ const ListToolbar = () => {
               RETURN
               TOP UP PARTNER
               REWARD
+              PURCHASE LOJA
+              TOP UP P24
+              TRANSFER AGENT
+              WITHDRAWAL AGENT
             
           
 
diff --git a/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx b/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx
index bfd2355..61c9de6 100644
--- a/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx
+++ b/src/pages/transaction/history-transaction/hooks/TransactionContext.tsx
@@ -78,6 +78,10 @@ const TransactionProvider = ({ children }: { children: React.ReactNode }) => {
             case 'R': return 'RETURN';
             case 'N': return 'TOP UP PARTNER';
             case 'E': return 'REWARD';
+            case 'L': return 'PURCHASE LOJA';
+            case 'B': return 'TOP UP P24';
+            case 'A': return 'TRANSFER AGENT';
+            case 'M': return 'WITHDRAWAL AGENT'; 
             default: return '_';
           }
         },

From c753fb45f023e44390d85f7b3a4b289d4c083297 Mon Sep 17 00:00:00 2001
From: bagusajisaputroo 
Date: Mon, 19 May 2025 13:36:10 +0700
Subject: [PATCH 2/7] adding deduct origin on transfer fee

---
 .../transfer/transferfee/blocks/AddDialog.tsx |  98 +++++++++++++++-
 .../transferfee/blocks/EditDialog.tsx         | 109 +++++++++++++++++-
 .../hooks/ManageTransferFeeContext.tsx        |  28 ++++-
 3 files changed, 222 insertions(+), 13 deletions(-)

diff --git a/src/pages/transfer/transferfee/blocks/AddDialog.tsx b/src/pages/transfer/transferfee/blocks/AddDialog.tsx
index ff0ff5a..f6a736e 100644
--- a/src/pages/transfer/transferfee/blocks/AddDialog.tsx
+++ b/src/pages/transfer/transferfee/blocks/AddDialog.tsx
@@ -106,6 +106,7 @@ const AddFeeDialog = () => {
     created_by: '',
     created_at: '',
     deduct_from: '',
+    deduct_origin: '00000000-0000-0000-0000-000000000000',
     deduct_from_account: '',
     credit_to: '',
     credit_destination: '00000000-0000-0000-0000-000000000000',
@@ -296,6 +297,14 @@ const AddFeeDialog = () => {
         return;
       }
 
+      if (formField.deduct_from === 'I' && !formField.deduct_origin) {
+        setAlert({
+          show: true,
+          message: 'Deduct Origin is required when Input is selected'
+        });
+        setIsSubmitting(false);
+        return;
+      }
       setAlert({ show: false, message: '' });
 
       const payload = { ...formField };
@@ -304,6 +313,9 @@ const AddFeeDialog = () => {
         payload.credit_destination = '00000000-0000-0000-0000-000000000000';
       }
 
+      if (formField.deduct_from !== 'I') {
+        payload.deduct_origin = '00000000-0000-0000-0000-000000000000';
+      }
       try {
         const response = await PostData(`${API_URL}/transactionfees/create`, payload);
 
@@ -557,7 +569,13 @@ const AddFeeDialog = () => {
                   
                   
                 
+ {formField.deduct_from === 'I' && ( +
+ +
+
setOpen(!open)} + > + + {customers.find((customer) => customer.id === formField.deduct_origin) + ?.username || 'Search customer...'} + + +
+ + {open && ( +
+
+ 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 + }); + setOpen(false); + }} + > + {customer.username} +
+ ))} + {customers.filter( + (customer) => + customer.username + .toLowerCase() + .includes(customerSearchTerm.toLowerCase()) || + customer.msisdn.includes(customerSearchTerm) + ).length === 0 && ( +
+ No customer found +
+ )} +
+
+ )} +
+
+ )} +
{renderSelectWithLoading( formField.deduct_from_account, @@ -580,6 +672,7 @@ const AddFeeDialog = () => { isLoadingWallets )}
+
)} +
+ {formField.deduct_from === 'I' && ( +
+ +
+
setOpen(!open)} + > + + {customers.find((customer) => customer.id === formField.deduct_origin) + ?.username || 'Search customer...'} + + +
+ + {open && ( +
+
+ 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 + }); + setOpen(false); + }} + > + {customer.username} +
+ ))} + {customers.filter( + (customer) => + customer.username + .toLowerCase() + .includes(customerSearchTerm.toLowerCase()) || + customer.msisdn.includes(customerSearchTerm) + ).length === 0 && ( +
+ No customer found +
+ )} +
+
+ )} +
+
+ )} +
{renderSelectWithLoading( formField.deduct_from_account, @@ -630,7 +730,6 @@ const EditFeeDialog = () => { isLoadingWallets )}
-
- -
*/} +