From 4a56209c58d583a4c5656ee82ab6ad0d28417b97 Mon Sep 17 00:00:00 2001 From: Wikzyy Date: Tue, 10 Jun 2025 13:41:11 +0700 Subject: [PATCH] [skip ci] add manage card on customer detail --- src/config/api.config.ts | 4 +- .../manage-members/blocks/DetailMember.tsx | 6 +- .../manage-members/blocks/ManageCard.tsx | 272 ++++++++++++++++++ 3 files changed, 280 insertions(+), 2 deletions(-) create mode 100644 src/pages/members/manage-members/blocks/ManageCard.tsx diff --git a/src/config/api.config.ts b/src/config/api.config.ts index 56e9c15..c3c693c 100644 --- a/src/config/api.config.ts +++ b/src/config/api.config.ts @@ -10,7 +10,8 @@ interface apiConfigProps { service_disbursement: string; service_notification: string; service_feedback: string; - api_dashboard:string + api_dashboard: string; + service_card: string; } const API_URL = import.meta.env.VITE_APP_API_URL; @@ -27,6 +28,7 @@ const apiConfig: apiConfigProps = { service_disbursement: `${API_URL}/s`, service_notification: `${API_URL}/n`, api_dashboard: `${API_URL}/r`, + service_card: `${API_URL}/a`, nationality: `https://tpay.shiblysolution.id/cms/api/mobile/list-country/` }; diff --git a/src/pages/members/manage-members/blocks/DetailMember.tsx b/src/pages/members/manage-members/blocks/DetailMember.tsx index d8c8e0c..b8f82f9 100644 --- a/src/pages/members/manage-members/blocks/DetailMember.tsx +++ b/src/pages/members/manage-members/blocks/DetailMember.tsx @@ -24,6 +24,7 @@ import { Button } from '@/components/ui/button'; import { initialMember } from "../Columns"; import AdmAccess from './AdmAccess'; import CustomerWallet from './CustomerWallet'; +import ManageCard from './ManageCard'; const BASE_URL_MASTER_DATA = apiConfig.service_master_data; const URL_NATIONALITY = apiConfig.nationality; const BASE_URL_CUSTOMER = apiConfig.service_customer; @@ -203,7 +204,7 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa handleReject(formData); // handleClose(); } - +console.log(formData.id); return ( handleAddDialog(open)}> @@ -284,6 +285,9 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa {(formData.id && page!=='kyc') ? ( ) : ""} + {(formData.id && page!=='kyc') ? ( + + ) : ""}
diff --git a/src/pages/members/manage-members/blocks/ManageCard.tsx b/src/pages/members/manage-members/blocks/ManageCard.tsx new file mode 100644 index 0000000..312aa6d --- /dev/null +++ b/src/pages/members/manage-members/blocks/ManageCard.tsx @@ -0,0 +1,272 @@ +import { getAuth } from '@/auth'; +import { Button } from '@/components/ui/button'; +import { Card } from '@/components/ui/card'; +import { + Dialog, + DialogBody, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle +} from '@/components/ui/dialog'; +import { apiConfig } from '@/config/api.config'; +import { useCallApi } from '@/hooks'; +import { AlertTriangle, RefreshCw } from 'lucide-react'; +import { useEffect, useState } from 'react'; +import { toast } from 'sonner'; + +interface CardProps { + id: string; + serial_number: string; + provisioning_date: string; + created_at: string; + created_by: string; + customer: { + msisdn: string; + fullname: string; + }; +} + +type ManageCardProps = { + customerId: string | null; +}; + +const API_URL = apiConfig.service_card; + +const ManageCard = ({ customerId }: ManageCardProps) => { + const { GetData, PostData } = useCallApi(); + const parsedUser = getAuth()?.user; + const [cardList, setCardList] = useState([]); + const [selectedCardId, setSelectedCardId] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const [isSubmitting, setIsSubmitting] = useState(false); + const [showConfirmation, setShowConfirmation] = useState(false); + + const formatDateToTimorLeste = (isoDateString: string): string => { + const dateUTC = new Date(isoDateString); + + // Tambahkan offset UTC+9 dalam milidetik + const offsetInMs = 9 * 60 * 60 * 1000; + const dateTL = new Date(dateUTC.getTime() + offsetInMs); + + const day = dateTL.getDate().toString().padStart(2, '0'); + const monthNames = [ + 'Januari', + 'Februari', + 'Maret', + 'April', + 'Mei', + 'Juni', + 'Juli', + 'Agustus', + 'September', + 'Oktober', + 'November', + 'Desember' + ]; + const month = monthNames[dateTL.getMonth()]; + const year = dateTL.getFullYear(); + + const hours = dateTL.getHours().toString().padStart(2, '0'); + const minutes = dateTL.getMinutes().toString().padStart(2, '0'); + + return `${day} ${month} ${year}, ${hours}:${minutes}`; + }; + + const fetchCardList = async (page: number, limit: number, sorting: any, filter: any) => { + try { + sorting = sorting.length == 0 ? [{ id: 'provisioning_date', desc: true }] : sorting; + filter = + filter.length === 0 ? { 'customer.id': customerId } : { 'customer.id': filter[0].value }; + // filter = filter.length == 0 ? {} : { 'customer.id': { like: `%${customerId}%` } }; + + const response = await GetData(`${API_URL}/card/list`, { + limit, + page: page + 1, + with_deleted: false, + order_field: sorting[0].id, + order_direction: sorting[0].desc == false ? 'ASC' : 'DESC', + filter: JSON.stringify(filter) + }); + + setCardList(response?.data.list); + } catch (error) { + toast.error('Error fetching Card List'); + } + }; + + const doRevokeCard = async (cardId: string) => { + setIsSubmitting(true); + + try { + const response = await PostData(`${API_URL}/card/revoke`, { + id: cardId + }); + + if (response?.status) { + toast.success('Success revoking card'); + fetchCardList(0, 10, [], []); + } else { + toast.error('Error revoking card'); + } + } catch (error) { + toast.error('Error revoking card'); + } finally { + setIsSubmitting(false); + } + }; + + const handleRevokeButton = (cardId: string) => { + setSelectedCardId(cardId); + setShowConfirmation(true); + }; + + const handleCancelSubmit = () => { + setShowConfirmation(false); + setSelectedCardId(null); + }; + + const handleConfirmRevoke = async () => { + if (!selectedCardId) return; + await doRevokeCard(selectedCardId); + setShowConfirmation(false); + setSelectedCardId(null); + }; + + useEffect(() => { + if (customerId) { + fetchCardList(0, 10, [], []); + } + }, [customerId]); + + return ( + <> +
+

Card Member

+ + {cardList ? ( +
+ + + + + + + + + + + + + {cardList.length > 0 ? ( + <> + {cardList.map((item: CardProps, index) => ( + + + + + + + + + ))} + + ) : ( + + + + )} + +
NoNameMsisdnSerial NumberProvisioning DateAction
{index + 1}{item.customer.fullname}{item.customer.msisdn}{item.serial_number}{formatDateToTimorLeste(item.provisioning_date)} + +
+ Card is empty +
+
+ ) : ( +

No Card Available

+ )} +
+
+ setShowConfirmation(open)}> + + + + + Revoke Card + + + + +
+ {isLoading ? ( +
+
+
+
+
+
+
+
+
+
+

Loading Card Details...

+
+ ) : ( +
+

+ Are you sure you want to revoke this card? This action cannot be undone. +

+

+ Revoking this card will deactivate it permanently. The customer will no longer + be able to use this card for any transactions or services. +

+ + {/* Action Buttons */} +
+ + +
+
+ )} +
+
+
+
+ + ); +}; + +export default ManageCard;