update
This commit is contained in:
@ -50,10 +50,13 @@
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.4",
|
||||
"date-fns": "^3.0.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"formik": "^2.4.6",
|
||||
"helmet": "^8.1.0",
|
||||
"html2canvas": "^1.4.1",
|
||||
"https": "^1.0.0",
|
||||
"jspdf": "^3.0.1",
|
||||
"jspdf-autotable": "^5.0.2",
|
||||
"leaflet": "^1.9.4",
|
||||
"lucide-react": "^0.456.0",
|
||||
"metronic-tailwind-react": "file:",
|
||||
@ -86,10 +89,12 @@
|
||||
"tailwind-merge": "^2.5.4",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"vite-plugin-windicss": "^1.9.3",
|
||||
"xlsx": "^0.18.5",
|
||||
"yup": "^1.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.14.0",
|
||||
"@types/file-saver": "^2.0.7",
|
||||
"@types/leaflet": "^1.9.14",
|
||||
"@types/node": "^22.9.0",
|
||||
"@types/react": "^18.3.12",
|
||||
|
||||
@ -28,6 +28,7 @@ import { doSaveLogActivity } from '@/actions/GlobalActions';
|
||||
import { CustomerProps } from '@/pages/master/provider/blocks/AddDialog';
|
||||
import { Check, ChevronDown } from 'lucide-react';
|
||||
import { initialStateNotification, selectedNotification, validateFormNotification } from './Types';
|
||||
import { useDebounce } from './useDebounce';
|
||||
|
||||
const API_URL_CUSTOMER = apiConfig.service_customer;
|
||||
const API_URL_NOTIFICATION = apiConfig.service_notification;
|
||||
@ -39,6 +40,8 @@ const AddDialog = () => {
|
||||
const [alert, setAlert] = useState({ show: false, message: '' });
|
||||
const isSubmittingRef = useRef(false);
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const debouncedSearchQuery = useDebounce(searchQuery, 500);
|
||||
|
||||
const [formField, setFormField] = useState<selectedNotification>(initialStateNotification);
|
||||
const [open, setOpen] = useState(false);
|
||||
@ -95,7 +98,6 @@ const AddDialog = () => {
|
||||
}
|
||||
} catch (err) {
|
||||
toast.error('Something went wrong');
|
||||
console.log(err);
|
||||
} finally {
|
||||
isSubmittingRef.current = false;
|
||||
setIsSubmitting(false);
|
||||
@ -104,22 +106,35 @@ const AddDialog = () => {
|
||||
[PostData, formField, handleAddDialog, reload]
|
||||
);
|
||||
|
||||
const getCustomerList = async (sorting: any) => {
|
||||
try {
|
||||
sorting = sorting.length == 0 ? [{ id: 'name', desc: false }] : sorting;
|
||||
const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, {
|
||||
limit: 100,
|
||||
page: 1,
|
||||
with_deleted: false,
|
||||
order_field: sorting[0].id,
|
||||
order_direction: sorting[0].desc == false ? 'ASC' : 'DESC'
|
||||
});
|
||||
useEffect(() => {
|
||||
const fetchCustomers = async () => {
|
||||
try {
|
||||
const filters = [];
|
||||
|
||||
setCustomers(response?.data.list);
|
||||
} catch (error) {
|
||||
console.error('Error fetching customer', error);
|
||||
}
|
||||
};
|
||||
if (debouncedSearchQuery) {
|
||||
filters.push({
|
||||
id: 'fullname',
|
||||
value: debouncedSearchQuery
|
||||
});
|
||||
}
|
||||
|
||||
const response = await GetData(`${API_URL_CUSTOMER}/customer/list`, {
|
||||
limit: 100,
|
||||
page: 1,
|
||||
with_deleted: false,
|
||||
order_field: 'fullname',
|
||||
order_direction: 'ASC',
|
||||
filter: JSON.stringify(filters),
|
||||
specialFilter: filters.length > 0
|
||||
});
|
||||
setCustomers(response?.data.list);
|
||||
} catch (error) {
|
||||
console.error('Error fetching customers', error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchCustomers();
|
||||
}, [debouncedSearchQuery]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
@ -127,10 +142,6 @@ const AddDialog = () => {
|
||||
doCreateNotification(e);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getCustomerList([{ id: 'id', desc: false }]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (showAddDialog === false) {
|
||||
resetForm();
|
||||
@ -217,7 +228,11 @@ const AddDialog = () => {
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[400px] p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Search Customer..." />
|
||||
<CommandInput
|
||||
placeholder="Search Customer..."
|
||||
value={searchQuery}
|
||||
onValueChange={setSearchQuery}
|
||||
/>
|
||||
<CommandList
|
||||
className="max-h-[300px] overflow-y-auto"
|
||||
style={{ touchAction: 'pan-y' }}
|
||||
@ -232,24 +247,20 @@ const AddDialog = () => {
|
||||
return (
|
||||
<CommandItem
|
||||
key={customer.id}
|
||||
value={customer.username}
|
||||
value={customer.fullname}
|
||||
onSelect={() => {
|
||||
const customerId = customer.id;
|
||||
setFormField((prev) => {
|
||||
const isSelected = prev.customers.includes(customerId);
|
||||
return {
|
||||
...prev,
|
||||
customers: isSelected
|
||||
? prev.customers.filter((id) => id !== customerId)
|
||||
: [...prev.customers, customerId]
|
||||
};
|
||||
});
|
||||
setFormField((prev) => ({
|
||||
...prev,
|
||||
customers: isSelected
|
||||
? prev.customers.filter((id) => id !== customer.id)
|
||||
: [...prev.customers, customer.id]
|
||||
}));
|
||||
}}
|
||||
className={isSelected ? 'bg-accent font-semibold' : ''}
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
{isSelected && <Check className="w-4 h-4 text-green-600" />}
|
||||
{customer.username}
|
||||
{customer.fullname} ({customer.msisdn})
|
||||
</span>
|
||||
</CommandItem>
|
||||
);
|
||||
|
||||
17
src/pages/notification/blocks/useDebounce.tsx
Normal file
17
src/pages/notification/blocks/useDebounce.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export function useDebounce<T>(value: T, delay: number): T {
|
||||
const [debouncedValue, setDebouncedValue] = useState<T>(value);
|
||||
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedValue(value);
|
||||
}, delay);
|
||||
|
||||
return () => {
|
||||
clearTimeout(handler);
|
||||
};
|
||||
}, [value, delay]);
|
||||
|
||||
return debouncedValue;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useState, useEffect } from 'react';
|
||||
import React, { useCallback, useState, useEffect, useContext } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Select,
|
||||
@ -11,6 +11,7 @@ import { DefaultTooltip, KeenIcon } from '@/components';
|
||||
import { toAbsoluteUrl } from '@/utils';
|
||||
import { useCallApi } from '@/hooks';
|
||||
import { apiConfig } from '@/config/api.config';
|
||||
import { showDetailWalletContext } from './ShowDetailDialog';
|
||||
|
||||
interface TransferType {
|
||||
id: string;
|
||||
@ -40,24 +41,44 @@ const FilterSection: React.FC<FilterSectionProps> = ({
|
||||
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
||||
const [category, setCategory] = useState<string[]>([]);
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const { doExportExcel, doExportPDF } = useContext(showDetailWalletContext);
|
||||
|
||||
const handleExportExcel = async () => {
|
||||
try {
|
||||
await doExportExcel();
|
||||
// console.log('Excel export initiated successfully');
|
||||
} catch (error) {
|
||||
console.error('Error during Excel export:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const handleExportPDF = async () => {
|
||||
try {
|
||||
await doExportPDF();
|
||||
// console.log('PDF export initiated successfully');
|
||||
} catch (error) {
|
||||
console.error('Error during PDF export:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchTransferType = useCallback(async () => {
|
||||
try {
|
||||
const response = await GetData(`${apiConfig.service_transaction}/transactiontype/list`, {
|
||||
limit: 100,
|
||||
page: 1,
|
||||
with_deleted: false,
|
||||
order_field: 'created_at',
|
||||
order_direction: 'ASC'
|
||||
});
|
||||
|
||||
const sortedData = (response?.data?.list || [])
|
||||
.sort((a: any, b: any) => a.name.localeCompare(b.name));
|
||||
setTransferType(sortedData);
|
||||
} catch (error) {
|
||||
console.error('Error fetching transfer types', error);
|
||||
}
|
||||
}, [GetData]);
|
||||
try {
|
||||
const response = await GetData(`${apiConfig.service_transaction}/transactiontype/list`, {
|
||||
limit: 100,
|
||||
page: 1,
|
||||
with_deleted: false,
|
||||
order_field: 'created_at',
|
||||
order_direction: 'ASC'
|
||||
});
|
||||
|
||||
const sortedData = (response?.data?.list || []).sort((a: any, b: any) =>
|
||||
a.name.localeCompare(b.name)
|
||||
);
|
||||
setTransferType(sortedData);
|
||||
} catch (error) {
|
||||
console.error('Error fetching transfer types', error);
|
||||
}
|
||||
}, [GetData]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchTransferType();
|
||||
@ -70,8 +91,8 @@ const FilterSection: React.FC<FilterSectionProps> = ({
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setCategory(categories);
|
||||
}, [transaction, categoryMap]);
|
||||
setCategory(categories);
|
||||
}, [transaction, categoryMap]);
|
||||
|
||||
const reverseCategoryMap = Object.fromEntries(
|
||||
Object.entries(categoryMap).map(([key, value]) => [value, key])
|
||||
@ -108,7 +129,7 @@ const FilterSection: React.FC<FilterSectionProps> = ({
|
||||
};
|
||||
}
|
||||
|
||||
if (selectedTransferType) {
|
||||
if (selectedTransferType) {
|
||||
appliedFilters.id_transaction_type = selectedTransferType;
|
||||
}
|
||||
|
||||
@ -200,20 +221,22 @@ const FilterSection: React.FC<FilterSectionProps> = ({
|
||||
Filter Data
|
||||
</Button>
|
||||
|
||||
<DefaultTooltip title={'Export Data'} placement={'top'}>
|
||||
<Button variant={'outline'} className="h-7.5 min-w-[58px]">
|
||||
<img src={toAbsoluteUrl('/media/file-types/xls.svg')} className="" alt="" />
|
||||
</Button>
|
||||
</DefaultTooltip>
|
||||
<div className="flex gap-2">
|
||||
<DefaultTooltip title={'Export to Excel'} placement={'top'}>
|
||||
<Button variant={'outline'} className="h-7.5 min-w-[58px]" onClick={handleExportExcel}>
|
||||
<img src={toAbsoluteUrl('/media/file-types/xls.svg')} className="" alt="Excel" />
|
||||
</Button>
|
||||
</DefaultTooltip>
|
||||
|
||||
<DefaultTooltip title={'Export Data'} placement={'top'}>
|
||||
<Button variant={'outline'} className="h-7.5 min-w-[58px]">
|
||||
<img src={toAbsoluteUrl('/media/file-types/pdf.svg')} className="" alt="" />
|
||||
</Button>
|
||||
</DefaultTooltip>
|
||||
<DefaultTooltip title={'Export to PDF'} placement={'top'}>
|
||||
<Button variant={'outline'} className="h-7.5 min-w-[58px]" onClick={handleExportPDF}>
|
||||
<img src={toAbsoluteUrl('/media/file-types/pdf.svg')} className="" alt="PDF" />
|
||||
</Button>
|
||||
</DefaultTooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FilterSection;
|
||||
export default FilterSection;
|
||||
|
||||
@ -14,13 +14,20 @@ import { useManageStatementContext } from '../hooks/useManageWalletStatementCont
|
||||
import { Toaster } from 'sonner';
|
||||
import { format } from 'date-fns';
|
||||
import FilterSection from './FilterSection';
|
||||
import * as XLSX from 'xlsx';
|
||||
import jsPDF from 'jspdf';
|
||||
import 'jspdf-autotable';
|
||||
|
||||
interface ContextProps {
|
||||
doExportData: (sorting: any, filter: any) => Promise<any>;
|
||||
doExportExcel: () => Promise<void>;
|
||||
doExportPDF: () => Promise<void>;
|
||||
}
|
||||
|
||||
const initialProps: ContextProps = {
|
||||
doExportData: async () => ({ data: [], totalCount: 0 })
|
||||
doExportData: async () => ({ data: [], totalCount: 0 }),
|
||||
doExportExcel: async () => {},
|
||||
doExportPDF: async () => {}
|
||||
};
|
||||
|
||||
export const showDetailWalletContext = createContext<ContextProps>(initialProps);
|
||||
@ -174,6 +181,297 @@ const ShowDetailWalletDialog = () => {
|
||||
[GetData, filters, selectedWallet]
|
||||
);
|
||||
|
||||
const getAllTransactionData = async () => {
|
||||
try {
|
||||
const response = await GetData(
|
||||
`${apiConfig.service_wallet}/dashboard/balance/list-balance-detail/${selectedWallet?.ID}`,
|
||||
{
|
||||
limit: 10000,
|
||||
page: 1,
|
||||
with_deleted: false,
|
||||
order_field: 'amount',
|
||||
order_direction: 'DESC',
|
||||
filter: JSON.stringify(filters)
|
||||
}
|
||||
);
|
||||
|
||||
return response?.data?.list || [];
|
||||
} catch (error) {
|
||||
console.error('Error fetching all transaction data', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const formatTransactionData = (data: any[]) => {
|
||||
return data.map((item) => ({
|
||||
'Transaction Code': item.transaction_code || '-',
|
||||
'MSISDN Reffer': item.msisdn_reff || '-',
|
||||
'Transaction Type': item.transaction_type?.name || '-',
|
||||
Type: item.type || '-',
|
||||
'Pre Amount': item.pre_amount?.toFixed(2) || '0.00',
|
||||
Amount: item.amount?.toFixed(2) || '0.00',
|
||||
'Post Amount': item.post_amount?.toFixed(2) || '0.00',
|
||||
Category: categoryMap[item.category] || '-',
|
||||
Date: item.date
|
||||
? new Date(item.date).toLocaleString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
})
|
||||
: '-',
|
||||
Purpose: item.purpose || '-',
|
||||
Notes: item.notes || '-'
|
||||
}));
|
||||
};
|
||||
|
||||
const doExportExcel = async () => {
|
||||
try {
|
||||
const allData = await getAllTransactionData();
|
||||
const formattedData = formatTransactionData(allData);
|
||||
|
||||
const wb = XLSX.utils.book_new();
|
||||
|
||||
const ws = XLSX.utils.json_to_sheet([]);
|
||||
|
||||
const companyHeader = [
|
||||
['T•PAY'],
|
||||
['Telin Digital Solution'],
|
||||
['Av. Pres. Nicolau Lobato, Dili'],
|
||||
['Tel: (+670) 74147147 / 147'],
|
||||
['www.t-pay.tl'],
|
||||
[''],
|
||||
['Wallet Statement Details'],
|
||||
[`Export Date: ${format(new Date(), 'dd MMM yyyy HH:mm:ss')}`],
|
||||
[`Wallet ID: ${selectedWallet?.ID || '-'}`],
|
||||
['']
|
||||
];
|
||||
|
||||
const columnHeaders = [
|
||||
[
|
||||
'Transaction Code',
|
||||
'MSISDN Reffer',
|
||||
'Transaction Type',
|
||||
'Type',
|
||||
'Pre Amount',
|
||||
'Amount',
|
||||
'Post Amount',
|
||||
'Category',
|
||||
'Date',
|
||||
'Purpose',
|
||||
'Notes'
|
||||
]
|
||||
];
|
||||
|
||||
const excelData = [
|
||||
...companyHeader,
|
||||
...columnHeaders,
|
||||
...formattedData.map((item) => Object.values(item))
|
||||
];
|
||||
|
||||
XLSX.utils.sheet_add_aoa(ws, excelData);
|
||||
|
||||
const colWidths = [
|
||||
{ wch: 20 },
|
||||
{ wch: 15 },
|
||||
{ wch: 25 },
|
||||
{ wch: 10 },
|
||||
{ wch: 12 },
|
||||
{ wch: 12 },
|
||||
{ wch: 12 },
|
||||
{ wch: 15 },
|
||||
{ wch: 20 },
|
||||
{ wch: 25 },
|
||||
{ wch: 25 }
|
||||
];
|
||||
ws['!cols'] = colWidths;
|
||||
|
||||
const tpayCell = XLSX.utils.encode_cell({ r: 0, c: 0 });
|
||||
if (ws[tpayCell]) {
|
||||
ws[tpayCell].s = {
|
||||
font: { bold: true, sz: 18, color: { rgb: '000000' } },
|
||||
alignment: { horizontal: 'center' },
|
||||
fill: { fgColor: { rgb: 'F4C2C2' } }
|
||||
};
|
||||
}
|
||||
|
||||
for (let i = 1; i < 5; i++) {
|
||||
const cellRef = XLSX.utils.encode_cell({ r: i, c: 0 });
|
||||
if (ws[cellRef]) {
|
||||
ws[cellRef].s = {
|
||||
font: { sz: 12, color: { rgb: '000000' } },
|
||||
alignment: { horizontal: 'center' },
|
||||
fill: { fgColor: { rgb: 'F4C2C2' } }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const titleCell = XLSX.utils.encode_cell({ r: 6, c: 0 });
|
||||
if (ws[titleCell]) {
|
||||
ws[titleCell].s = {
|
||||
font: { bold: true, sz: 14 },
|
||||
alignment: { horizontal: 'center' }
|
||||
};
|
||||
}
|
||||
|
||||
for (let i = 7; i < 9; i++) {
|
||||
const cellRef = XLSX.utils.encode_cell({ r: i, c: 0 });
|
||||
if (ws[cellRef]) {
|
||||
ws[cellRef].s = {
|
||||
font: { sz: 11 },
|
||||
alignment: { horizontal: 'left' }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
const range = XLSX.utils.encode_range({ s: { r: i, c: 0 }, e: { r: i, c: 10 } });
|
||||
if (!ws['!merges']) ws['!merges'] = [];
|
||||
ws['!merges'].push(XLSX.utils.decode_range(range));
|
||||
}
|
||||
|
||||
for (let col = 0; col < columnHeaders[0].length; col++) {
|
||||
const cellRef = XLSX.utils.encode_cell({ r: 10, c: col });
|
||||
if (ws[cellRef]) {
|
||||
ws[cellRef].s = {
|
||||
font: { bold: true, color: { rgb: 'FFFFFF' } },
|
||||
fill: { fgColor: { rgb: '4472C4' } },
|
||||
alignment: { horizontal: 'center' },
|
||||
border: {
|
||||
top: { style: 'thin', color: { rgb: '000000' } },
|
||||
bottom: { style: 'thin', color: { rgb: '000000' } },
|
||||
left: { style: 'thin', color: { rgb: '000000' } },
|
||||
right: { style: 'thin', color: { rgb: '000000' } }
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
for (let row = 11; row < 11 + formattedData.length; row++) {
|
||||
for (let col = 0; col < columnHeaders[0].length; col++) {
|
||||
const cellRef = XLSX.utils.encode_cell({ r: row, c: col });
|
||||
if (ws[cellRef]) {
|
||||
ws[cellRef].s = {
|
||||
border: {
|
||||
top: { style: 'thin', color: { rgb: 'D9D9D9' } },
|
||||
bottom: { style: 'thin', color: { rgb: 'D9D9D9' } },
|
||||
left: { style: 'thin', color: { rgb: 'D9D9D9' } },
|
||||
right: { style: 'thin', color: { rgb: 'D9D9D9' } }
|
||||
}
|
||||
};
|
||||
|
||||
if ([4, 5, 6].includes(col)) {
|
||||
ws[cellRef].s.alignment = { horizontal: 'right' };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'Wallet Statement');
|
||||
|
||||
const fileName = `wallet_statement_${selectedWallet?.ID}_${format(new Date(), 'yyyyMMdd_HHmmss')}.xlsx`;
|
||||
XLSX.writeFile(wb, fileName);
|
||||
|
||||
// console.log('Excel export completed successfully');
|
||||
} catch (error) {
|
||||
console.error('Error exporting to Excel:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const doExportPDF = async () => {
|
||||
try {
|
||||
const allData = await getAllTransactionData();
|
||||
const formattedData = formatTransactionData(allData);
|
||||
|
||||
const pdf = new jsPDF('l', 'mm', 'a4');
|
||||
|
||||
pdf.setFontSize(20);
|
||||
pdf.setFont('helvetica', 'bold');
|
||||
pdf.text('T•PAY', 148, 20, { align: 'center' });
|
||||
|
||||
pdf.setFontSize(12);
|
||||
pdf.setFont('helvetica', 'normal');
|
||||
pdf.text('Telin Digital Solution', 148, 30, { align: 'center' });
|
||||
pdf.text('Av. Pres. Nicolau Lobato, Dili', 148, 36, { align: 'center' });
|
||||
pdf.text('Tel : (+670) 7414747 / 147', 148, 42, { align: 'center' });
|
||||
pdf.text('www.t-pay.tl', 148, 48, { align: 'center' });
|
||||
|
||||
pdf.setFontSize(14);
|
||||
pdf.setFont('helvetica', 'bold');
|
||||
pdf.text('Wallet Statement Details', 148, 60, { align: 'center' });
|
||||
|
||||
pdf.setFontSize(10);
|
||||
pdf.setFont('helvetica', 'normal');
|
||||
pdf.text(`Export Date: ${format(new Date(), 'dd MMM yyyy HH:mm:ss')}`, 20, 70);
|
||||
pdf.text(`Wallet ID: ${selectedWallet?.ID || '-'}`, 20, 76);
|
||||
|
||||
const tableData = formattedData.map((item) => [
|
||||
item['Transaction Code'],
|
||||
item['MSISDN Reffer'],
|
||||
item['Transaction Type'],
|
||||
item['Type'],
|
||||
item['Pre Amount'],
|
||||
item['Amount'],
|
||||
item['Post Amount'],
|
||||
item['Category'],
|
||||
item['Date'],
|
||||
item['Purpose'],
|
||||
item['Notes']
|
||||
]);
|
||||
|
||||
(pdf as any).autoTable({
|
||||
head: [
|
||||
[
|
||||
'Transaction Code',
|
||||
'MSISDN Reffer',
|
||||
'Transaction Type',
|
||||
'Type',
|
||||
'Pre Amount',
|
||||
'Amount',
|
||||
'Post Amount',
|
||||
'Category',
|
||||
'Date',
|
||||
'Purpose',
|
||||
'Notes'
|
||||
]
|
||||
],
|
||||
body: tableData,
|
||||
startY: 85,
|
||||
styles: {
|
||||
fontSize: 8,
|
||||
cellPadding: 2
|
||||
},
|
||||
headStyles: {
|
||||
fillColor: [66, 66, 66],
|
||||
textColor: [255, 255, 255],
|
||||
fontStyle: 'bold'
|
||||
},
|
||||
columnStyles: {
|
||||
0: { cellWidth: 20 },
|
||||
1: { cellWidth: 20 },
|
||||
2: { cellWidth: 25 },
|
||||
3: { cellWidth: 15 },
|
||||
4: { cellWidth: 18 },
|
||||
5: { cellWidth: 18 },
|
||||
6: { cellWidth: 18 },
|
||||
7: { cellWidth: 25 },
|
||||
8: { cellWidth: 25 },
|
||||
9: { cellWidth: 30 },
|
||||
10: { cellWidth: 30 }
|
||||
},
|
||||
margin: { top: 85, left: 10, right: 10 }
|
||||
});
|
||||
|
||||
const fileName = `wallet_statement_${selectedWallet?.ID}_${format(new Date(), 'yyyyMMdd_HHmmss')}.pdf`;
|
||||
pdf.save(fileName);
|
||||
|
||||
// console.log('PDF export completed successfully');
|
||||
} catch (error) {
|
||||
console.error('Error exporting to PDF:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const doExportData = async (sorting: any, filter: any) => {
|
||||
const user = localStorage.getItem(
|
||||
`${import.meta.env.VITE_APP_NAME}-auth-v${import.meta.env.VITE_APP_VERSION}`
|
||||
@ -219,7 +517,7 @@ const ShowDetailWalletDialog = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<showDetailWalletContext.Provider value={{ doExportData }}>
|
||||
<showDetailWalletContext.Provider value={{ doExportData, doExportExcel, doExportPDF }}>
|
||||
<Toaster expand visibleToasts={9} duration={3000} />
|
||||
<Dialog open={showDetailDialog} onOpenChange={setShowDetailDialog}>
|
||||
<DialogContent className="w-screen max-w-screen max-h-screen p-4 overflow-hidden">
|
||||
|
||||
Reference in New Issue
Block a user