Files
revenue-fe/src/pages/members/agent-balance/AgentBalance.tsx
2025-06-03 11:03:43 +07:00

325 lines
9.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { DataTable } from '@/components/ui/DataTable';
import { getColumns } from './Column';
import { apiConfig } from '@/config/api.config';
import axios, { AxiosResponse } from 'axios';
import html2canvas from 'html2canvas';
import { Helmet } from 'react-helmet';
import {
DialogContent,
MenuItem,
Radio,
RadioGroup,
FormControlLabel,
FormControl,
Dialog,
DialogTitle,
Typography,
Button,
Box,
Breadcrumbs,
Link
} from '@mui/material';
import { useState, useEffect, useRef } from 'react';
import { toast } from 'sonner';
import { Container, DataGridLoader, DataGridProvider, LoaderTransparant } from '@/components';
import { ListToolBar } from './ListToolbar';
import { toAbsoluteUrl } from '@/utils';
const BASE_URL = apiConfig.service_customer;
let initBalance = {
id: '',
msisdn: '',
fullname: '',
username: '',
agent_name: '',
balance_emoney: '',
balance_merchant: '',
balance_point: '',
balance_deposit: ''
};
const AgentBalance = () => {
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [loading, setLoading] = useState(false);
const [dataBalance, setDataBalance] = useState([]);
const [formData, setFormData] = useState(initBalance);
const [pageIndex, setPageIndex] = useState(1);
const [currentPage, setCurrentPage] = useState(0);
const [pageSize, setPageSize] = useState(10);
const [dialogType, setDialogType] = useState('');
const [dialogOpen, setDialogOpen] = useState(false);
const [isReloading, setIsReloading] = useState(false);
const [barcode, setBarcode] = useState('');
const [token_legacy, setToken_legacy] = useState('');
// const [selectedMember, setSelectedMember] = useState(initBalance);
useEffect(() => {
// fetchAgentBalance();
}, []);
const fetchAgentBalance = async (
page: number,
limit: number,
sorting: any,
filter: any
) => {
filter = filter.length ? filter : {};
let balances = await axios.get(`${BASE_URL}/customer/agent-balance`, {
params: {
limit: limit,
page: page + 1, // +1 because your API uses 1-based pages
with_deleted: false,
order_field: 'created_at',
order_direction: 'DESC',
filter: JSON.stringify(filter),
specialFilter: true
}
});
let temp = 1;
let resBalance = balances.data.data.list.map((el: any) => {
el.no = temp++;
if (!el.agent_name) el.agent_name = ''
return el;
});
return { data: resBalance, totalCount: balances?.data.data.total_count }
}
const openDialog = () => setIsDialogOpen(true);
const closeDialog = () => {
setIsDialogOpen(false);
setFormData(initBalance);
};
function createGroup() {
setDialogType('create');
openDialog();
}
const handleUpdate = async (data: any) => {
await getQrCode(data.id);
setFormData(data);
setDialogType('update');
setIsDialogOpen(true);
let getTokenLegacy = await axios.get(`${BASE_URL}/token/get-token-legacy`, { params: { id: data.id } });
let temp = getTokenLegacy?.data?.data?.token_legacy || '';
setToken_legacy(temp)
};
const handleReload = async () => {
setIsReloading(true);
await fetchAgentBalance(currentPage, pageSize, '','');
closeDialog()
setIsReloading(false);
// fetchAgentBalance();
};
async function getQrCode(customerId: any): Promise<void> {
try {
setBarcode(``);
let getToken = await axios.get(`${BASE_URL}/token/get`, { params: { id: customerId } });
setBarcode(getToken.data.data.qrCode);
} catch (error: any) {
toast.warning(error.message);
console.log(error);
}
}
if (loading) return <LoaderTransparant />;
return (
<>
<Helmet>
<title>TPAY | Agent Balance</title>
</Helmet>
<Container>
{/* <ConfirmDialog
open={dialogOpen}
onClose={() => setDialogOpen(false)}
title="Confirm Action"
content={''}
onYes={handleYes}
onNo={() => setDialogOpen(false)}
/> */}
<h1 className="text-xl font-medium leading-none text-gray-900 mb-5">Agent Balances</h1>
<Breadcrumbs>
<Link underline="none" color="inherit" href="/">
<span className="text-sm hover:underline">Dashboard</span>
</Link>
<Link underline="none" color="inherit">
<span className="text-sm">Members</span>
</Link>
<Link underline="none" color="inherit">
<span className="text-sm">Agent Balances</span>
</Link>
</Breadcrumbs>
<div className="grid gap-5 lg:gap-7.5 mt-5 relative">
{isReloading && (
<DataGridLoader />
)}
{!isReloading && (<DataGridProvider
// data={dataBalance}
pagination={{ size: pageSize }}
columns={getColumns(handleUpdate)}
layout={{ card: true }}
serverSide={true}
onFetchData={({ pageIndex, pageSize, sorting, columnFilters }) =>
fetchAgentBalance(pageIndex, pageSize, sorting, columnFilters)
}
toolbar={
<ListToolBar
createGroup={createGroup}
onReload={handleReload}
isReloading={isReloading}
/>
}
onRowSelectionChange={(selected, table: any) => {
const selectedRow = table.getSelectedRowModel().rows[0];
if (selectedRow) handleUpdate(selectedRow.original);
}}
/>
)}
</div>
{/* </div> */}
<Dialog open={isDialogOpen} onClose={closeDialog}>
<DialogContent className="w-full flex justify-center items-center">
<div className="relative">
<PaymentCard
barcode={barcode}
token_legacy={token_legacy}
setToken_legacy={setToken_legacy}
customerId={formData.id}
agent_name={formData.agent_name}
handleReload={handleReload}
/>
</div>
</DialogContent>
</Dialog>
</Container>
</>
);
};
// ====================
const PaymentCard = ({ barcode, agent_name, customerId, token_legacy, setToken_legacy, handleReload }: any) => {
const cardRef: any = useRef(null);
const waitForImageLoad = (img: HTMLImageElement): Promise<void> => {
return new Promise((resolve) => {
if (img.complete && img.naturalHeight !== 0) {
resolve();
} else {
toast.warning(`No QR Code`);
img.onload = () => resolve();
}
});
};
const handleDownload = async () => {
if (!cardRef.current) return;
const img = cardRef.current.querySelector('img');
if (img) {
await waitForImageLoad(img);
} else {
return toast.warning(`No QR Code`);
}
const canvas = await html2canvas(cardRef.current, {
useCORS: true,
allowTaint: false,
backgroundColor: 'white',
scale: 2
});
const dataUrl = canvas.toDataURL('image/png');
const link = document.createElement('a');
link.href = dataUrl;
link.download = `${agent_name}_barcode_card.png`;
link.click();
};
const updateTokenLegacy = async () => {
try {
if (!token_legacy) return toast.warning(`Token Legacy can not be empty`);
await axios.post(`${BASE_URL}/token/insert-token-legacy`, {
customerid: customerId,
token_legacy
});
toast.success(`Success Update Token Legacy`);
await handleReload();
} catch (error: any) {
let err_msg = error?.response?.data?.error || error.message
toast.error(err_msg);
}
};
return (
<div className="flex flex-col items-center">
<div
ref={cardRef}
className="relative w-[400px] h-[550px] rounded-xl overflow-hidden shadow-xl bg-white mt-20"
>
<img
src={toAbsoluteUrl('/media/images/fixed-card.png')}
alt="Card Frame"
className="absolute inset-0 w-full h-full object-cover z-0"
/>
<div className="absolute inset-0 z-10 flex flex-col items-center pt-28 px-4 text-center">
<p className="text-[18px] font-semibold text-[#5b0066] mb-4">{agent_name}</p>
{barcode && (
<div className="mb-8">
<img src={barcode} alt="Barcode" className="w-60 h-60 object-contain" />
</div>
)}
<div className="flex-grow"></div>
<div className="absolute bottom-16">
<div className="text-[13px] text-[#47173a] text-left font-medium leading-tight">
<p>Imprime husi : Telin Digital Solution</p>
<p>Imprime : 01062025</p>
</div>
</div>
</div>
</div>
<div className="w-full pt-[20px]">
<div className="flex items-baseline flex-wrap lg:flex-nowrap">
<label className="form-label flex items-center">
Token Legacy<span className="text-red-500"></span>
</label>
<textarea
className="input"
name="token_legacy"
value={token_legacy}
onChange={(e: any) => setToken_legacy(e.target.value)}
/>
</div>
</div>
<div className="flex justify-between w-full mt-4 px-4">
<button
onClick={handleDownload}
className="border border-red-400 text-red-500 px-4 py-1 rounded hover:bg-red-50 text-sm"
>
Print QR
</button>
<button
onClick={updateTokenLegacy}
className="border border-blue-400 text-blue-500 px-4 py-1 rounded hover:bg-blue-50 text-sm"
>
Update to Token Legacy
</button>
</div>
</div>
);
};
export default AgentBalance;