member agent
This commit is contained in:
@ -52,6 +52,7 @@
|
|||||||
"date-fns": "^3.0.0",
|
"date-fns": "^3.0.0",
|
||||||
"formik": "^2.4.6",
|
"formik": "^2.4.6",
|
||||||
"helmet": "^8.1.0",
|
"helmet": "^8.1.0",
|
||||||
|
"html2canvas": "^1.4.1",
|
||||||
"https": "^1.0.0",
|
"https": "^1.0.0",
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
"lucide-react": "^0.456.0",
|
"lucide-react": "^0.456.0",
|
||||||
|
|||||||
BIN
public/media/images/card.png
Normal file
BIN
public/media/images/card.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 399 KiB |
@ -2,6 +2,7 @@ import { DataTable } from '@/components/ui/DataTable';
|
|||||||
import { getColumns } from './Column';
|
import { getColumns } from './Column';
|
||||||
import { apiConfig } from '@/config/api.config';
|
import { apiConfig } from '@/config/api.config';
|
||||||
import axios, { AxiosResponse } from 'axios';
|
import axios, { AxiosResponse } from 'axios';
|
||||||
|
import html2canvas from 'html2canvas';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
import {
|
import {
|
||||||
DialogContent,
|
DialogContent,
|
||||||
@ -18,7 +19,7 @@ import {
|
|||||||
Breadcrumbs,
|
Breadcrumbs,
|
||||||
Link
|
Link
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import CloseIcon from '@mui/icons-material/Close';
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
import Divider from '@mui/material/Divider';
|
import Divider from '@mui/material/Divider';
|
||||||
import ConfirmDialog from '@/components/confirm';
|
import ConfirmDialog from '@/components/confirm';
|
||||||
@ -27,6 +28,7 @@ import { Container, DataGridLoader, DataGridProvider, LoaderTransparant } from '
|
|||||||
import { ListToolBar } from './ListToolbar';
|
import { ListToolBar } from './ListToolbar';
|
||||||
import { RefreshCw } from 'lucide-react';
|
import { RefreshCw } from 'lucide-react';
|
||||||
import { setgroups } from 'process';
|
import { setgroups } from 'process';
|
||||||
|
import { toAbsoluteUrl } from '@/utils';
|
||||||
const BASE_URL = apiConfig.service_customer;
|
const BASE_URL = apiConfig.service_customer;
|
||||||
|
|
||||||
let initBalance = {
|
let initBalance = {
|
||||||
@ -51,6 +53,8 @@ const AgentBalance = () => {
|
|||||||
const [dialogType, setDialogType] = useState('');
|
const [dialogType, setDialogType] = useState('');
|
||||||
const [dialogOpen, setDialogOpen] = useState(false);
|
const [dialogOpen, setDialogOpen] = useState(false);
|
||||||
const [isReloading, setIsReloading] = useState(false);
|
const [isReloading, setIsReloading] = useState(false);
|
||||||
|
const [barcode, setBarcode] = useState('');
|
||||||
|
// const [selectedMember, setSelectedMember] = useState(initBalance);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchAgentBalance();
|
fetchAgentBalance();
|
||||||
@ -94,7 +98,9 @@ const AgentBalance = () => {
|
|||||||
openDialog();
|
openDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleUpdate = (group: any) => {
|
const handleUpdate = async (data: any) => {
|
||||||
|
await getQrCode(data.id);
|
||||||
|
setFormData(data)
|
||||||
setDialogType('update');
|
setDialogType('update');
|
||||||
setIsDialogOpen(true);
|
setIsDialogOpen(true);
|
||||||
};
|
};
|
||||||
@ -104,6 +110,18 @@ const AgentBalance = () => {
|
|||||||
fetchAgentBalance();
|
fetchAgentBalance();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function getQrCode(customerId:any): Promise<void> {
|
||||||
|
try {
|
||||||
|
setBarcode(`https://img.freepik.com/free-vector/scan-me-qr-code_78370-2915.jpg?semt=ais_hybrid&w=740`)
|
||||||
|
let getToken = await axios.get(`${BASE_URL}/token/get`, { params: { id: customerId }});
|
||||||
|
console.log(getToken.data.data);
|
||||||
|
// setBarcode(getToken.data.data.qrCode);
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.warning(error.message)
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (loading) return <LoaderTransparant />;
|
if (loading) return <LoaderTransparant />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -160,78 +178,134 @@ const AgentBalance = () => {
|
|||||||
</div>
|
</div>
|
||||||
{/* </div> */}
|
{/* </div> */}
|
||||||
|
|
||||||
{/* <Dialog open={isDialogOpen} onClose={closeDialog}>
|
<Dialog open={isDialogOpen} onClose={closeDialog}>
|
||||||
<DialogContent className="w-full">
|
<DialogContent className="w-full flex justify-center items-center">
|
||||||
<div className="flex justify-between">
|
<div className="relative">
|
||||||
<DialogTitle>
|
<PaymentCard barcode={barcode} customerId={formData.id} agent_name={formData.agent_name}/>
|
||||||
{dialogType === 'create' ? 'Create New Group' : 'Update Group'}
|
|
||||||
</DialogTitle>
|
|
||||||
<Box display="flex" justifyContent="flex-end">
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
sx={{ borderColor: 'white', color: 'grey' }}
|
|
||||||
onClick={closeDialog}
|
|
||||||
>
|
|
||||||
<CloseIcon />
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</div>
|
|
||||||
<Divider />
|
|
||||||
<div className="p-5 mt-5">
|
|
||||||
<form onSubmit={handleSubmit} className="flex flex-col gap-4 w-full">
|
|
||||||
<div className="grid grid-cols-4 items-center gap-4 w-full">
|
|
||||||
<label className="form-label text-sm">
|
|
||||||
<span className="text-red-500">*</span>Group Name:
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="groupName"
|
|
||||||
className="input w-full col-span-3"
|
|
||||||
value={formData.groupName}
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-4 items-center gap-4 w-full">
|
|
||||||
<label className="form-label text-sm">
|
|
||||||
<span className="text-red-500">*</span>Active Status:
|
|
||||||
</label>
|
|
||||||
<FormControl>
|
|
||||||
<RadioGroup name="status" row value={formData.status} onChange={handleChange}>
|
|
||||||
<FormControlLabel
|
|
||||||
value="Y"
|
|
||||||
checked={formData.status === 'Y'}
|
|
||||||
control={<Radio />}
|
|
||||||
label="Yes"
|
|
||||||
/>
|
|
||||||
<FormControlLabel
|
|
||||||
value="N"
|
|
||||||
checked={formData.status === 'N'}
|
|
||||||
control={<Radio />}
|
|
||||||
label="No"
|
|
||||||
/>
|
|
||||||
</RadioGroup>
|
|
||||||
</FormControl>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-4 items-center gap-4 w-full">
|
|
||||||
<label className="form-label text-sm">
|
|
||||||
<span className="text-red-500">*</span>Description:
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="description"
|
|
||||||
className="input w-full col-span-3"
|
|
||||||
value={formData.description}
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<Button type="submit">Submit</Button>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog> */}
|
</Dialog>
|
||||||
</Container>
|
</Container>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PaymentCard = ({ barcode, agent_name, customerId }:any) => {
|
||||||
|
const cardRef:any = useRef(null);
|
||||||
|
// useEffect(() => {
|
||||||
|
// fetchToken();
|
||||||
|
// }, []);
|
||||||
|
|
||||||
|
// async function fetchToken(): Promise<void> {
|
||||||
|
// try {
|
||||||
|
// let getToken = await axios.get(`${BASE_URL}/token/get`, { params: { id: customerId }});
|
||||||
|
// console.log(getToken.data.data);
|
||||||
|
// // setBarcode(getToken.data.data.qrCode);
|
||||||
|
// setBarcode(`https://img.freepik.com/free-vector/scan-me-qr-code_78370-2915.jpg?semt=ais_hybrid&w=740`)
|
||||||
|
// } catch (error: any) {
|
||||||
|
// toast.warning(error.message)
|
||||||
|
// console.log(error);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
const handleDownload = async () => {
|
||||||
|
if (!cardRef.current) return;
|
||||||
|
|
||||||
|
const img = cardRef.current.querySelector('img');
|
||||||
|
if (!img || !img.complete) {
|
||||||
|
// Wait until the barcode image has fully loaded
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
img.onload = resolve;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const canvas = await html2canvas(cardRef.current, {
|
||||||
|
useCORS: true, // Important for external images
|
||||||
|
});
|
||||||
|
|
||||||
|
const dataUrl = canvas.toDataURL('image/png');
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = dataUrl;
|
||||||
|
link.download = `${agent_name}_barcode_card.png`;
|
||||||
|
link.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col items-center">
|
||||||
|
{/* Card content to render */}
|
||||||
|
<div ref={cardRef}
|
||||||
|
className="relative w-[320px] h-[460px] rounded-xl overflow-hidden shadow-xl bg-white"
|
||||||
|
>
|
||||||
|
<div className="absolute inset-0 z-10 flex flex-col items-center justify-start pt-[50px] px-4 text-center">
|
||||||
|
<p className="text-[24px] font-semibold text-[#5b0066] mb-5">
|
||||||
|
{agent_name}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{barcode && (
|
||||||
|
<img
|
||||||
|
src={barcode}
|
||||||
|
alt="Barcode"
|
||||||
|
className="w-56 h-56 object-contain mb-2"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Download Button */}
|
||||||
|
<button
|
||||||
|
onClick={handleDownload}
|
||||||
|
className="mt-4 border border-red-400 text-red-500 px-4 py-1 rounded hover:bg-red-50 text-sm"
|
||||||
|
>
|
||||||
|
Print QR
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="relative w-[320px] h-[460px] rounded-xl overflow-hidden shadow-xl">
|
||||||
|
<div className="absolute inset-0 z-10 flex flex-col items-center justify-start pt-[50px] px-4 text-center">
|
||||||
|
<p className="text-[24px] font-semibold text-[#5b0066] mb-5">
|
||||||
|
{agent_name}
|
||||||
|
</p>
|
||||||
|
{barcode && (
|
||||||
|
<img
|
||||||
|
src={barcode}
|
||||||
|
alt="Barcode"
|
||||||
|
className="w-70 h-70 object-contain mb-2"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <div className="relative w-[320px] h-[460px] rounded-xl overflow-hidden shadow-lg">
|
||||||
|
// {/* Background Card Image */}
|
||||||
|
// <img
|
||||||
|
// src={toAbsoluteUrl("/media/images/card.png")}
|
||||||
|
// alt="Card Template"
|
||||||
|
// className="absolute inset-0 w-full h-full object-cover"
|
||||||
|
// />
|
||||||
|
|
||||||
|
// {/* Content Overlay */}
|
||||||
|
// <div className="absolute inset-0 z-10 flex flex-col items-center justify-start pt-32 px-4 text-center">
|
||||||
|
// {/* Agent Name at Top */}
|
||||||
|
// <p className="text-sm font-semibold text-[#5b0066] mb-4">
|
||||||
|
// {agent_name}
|
||||||
|
// </p>
|
||||||
|
|
||||||
|
// {/* Barcode */}
|
||||||
|
// {barcode && (
|
||||||
|
// <img
|
||||||
|
// src={barcode}
|
||||||
|
// alt="Barcode"
|
||||||
|
// className="w-40 h-40 object-contain mb-4"
|
||||||
|
// />
|
||||||
|
// )}
|
||||||
|
// </div>
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
|
};
|
||||||
|
|
||||||
export default AgentBalance;
|
export default AgentBalance;
|
||||||
|
|||||||
@ -143,4 +143,15 @@ export const getColumns = (handleUpdate: (data: any) => void): ColumnDef<AgentBa
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'actions',
|
||||||
|
cell: ({ row }) => {
|
||||||
|
const dataMembers = row.original;
|
||||||
|
return (
|
||||||
|
<button className="btn btn-sm btn-icon btn-clear btn-light" onClick={() => handleUpdate(dataMembers)}>
|
||||||
|
<KeenIcon icon="notepad-edit" />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
@ -121,22 +121,7 @@ const ManageMembers = () => {
|
|||||||
sorting: any,
|
sorting: any,
|
||||||
filter: any
|
filter: any
|
||||||
) => {
|
) => {
|
||||||
// [ SAMPLE
|
|
||||||
// {
|
|
||||||
// "id": "username",
|
|
||||||
// "value": "d"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "group_name",
|
|
||||||
// "value": "Bank"
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// "id": "msisdn",
|
|
||||||
// "value": "88"
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
sorting = sorting.length == 0 ? [{ id: 'name', desc: true }] : sorting;
|
sorting = sorting.length == 0 ? [{ id: 'name', desc: true }] : sorting;
|
||||||
// filter = filter.length ? { any: filter[0].value?.toLowerCase() } : {};
|
|
||||||
filter = filter.length ? filter : {};
|
filter = filter.length ? filter : {};
|
||||||
|
|
||||||
const res = await axios.get(`${BASE_URL}/customer/list`, {
|
const res = await axios.get(`${BASE_URL}/customer/list`, {
|
||||||
|
|||||||
@ -49,7 +49,7 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa
|
|||||||
img: ''
|
img: ''
|
||||||
});
|
});
|
||||||
const [banks] = useState([
|
const [banks] = useState([
|
||||||
{ name: 'BNCTL',id: 'BNCTL' }, { name: 'BRI',id: 'BRI' }, { name: 'BNU',id: 'BNU' }, { name: 'Mandiri',id: 'Mandiri' }
|
{ name: 'BNCTL',id: 'BNCTL' }, { name: 'BRI',id: 'BRI' }, { name: 'BNU',id: 'BNU' }, { name: 'MANDIRI',id: 'MANDIRI' }
|
||||||
])
|
])
|
||||||
const parentRef = useRef<any | null>(null);
|
const parentRef = useRef<any | null>(null);
|
||||||
const [alert, setAlert] = useState({
|
const [alert, setAlert] = useState({
|
||||||
@ -214,7 +214,7 @@ const DetailMember = ({ showAddDialog, setShowAddDialog, handleSubmit, initialDa
|
|||||||
{(formData.id || dialogType === "create") ? generateImage(formData, handleChange, 'Photo', 'photouser', previewImg, setPreviewImg): ''}
|
{(formData.id || dialogType === "create") ? generateImage(formData, handleChange, 'Photo', 'photouser', previewImg, setPreviewImg): ''}
|
||||||
{(formData.id || dialogType === "create") ? generateList(formData, handleChange, genders, 'gender', 'Gender', true, false): ''}
|
{(formData.id || dialogType === "create") ? generateList(formData, handleChange, genders, 'gender', 'Gender', true, false): ''}
|
||||||
{(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Date of Birth', 'date_birth', 'date', true, viewOnly): ''}
|
{(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Date of Birth', 'date_birth', 'date', true, viewOnly): ''}
|
||||||
{(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Phone Number', 'msisdn', 'text', true, dialogType === "create"||false): ''}
|
{(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Phone Number', 'msisdn', 'text', true, dialogType === "create"?false:true): ''}
|
||||||
{(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Email', 'email', 'text', true, viewOnly): ''}
|
{(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Email', 'email', 'text', true, viewOnly): ''}
|
||||||
{/* {generateList(formData, handleChange, status, 'status', 'Status', null, true)} */}
|
{/* {generateList(formData, handleChange, status, 'status', 'Status', null, true)} */}
|
||||||
{(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Mother Fullname', 'mother_fullname', 'text', true, viewOnly): ''}
|
{(formData.id || dialogType === "create") ? generateInput(formData, handleChange, 'Mother Fullname', 'mother_fullname', 'text', true, viewOnly): ''}
|
||||||
|
|||||||
Reference in New Issue
Block a user