@pagamio/frontend-commons-lib 0.8.208 → 0.8.209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -4,7 +4,7 @@ import { Checkbox, Label, TextInput } from 'flowbite-react';
|
|
|
4
4
|
import { HiMail } from 'react-icons/hi';
|
|
5
5
|
import { useEffect, useRef, useState } from 'react';
|
|
6
6
|
import { Modal, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components';
|
|
7
|
-
import { exportToCsv, exportToPdf, exportToXlsx,
|
|
7
|
+
import { exportToCsv, exportToPdf, exportToXlsx, generateExportAsFile, sendExportEmail } from './exportUtils';
|
|
8
8
|
const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, extraOptions = [], pdfOptions, xlsxOptions, csvOptions, exportAll = false, fetchData, enableEmailExport = false, emailExportApiUrl, onEmailExportSuccess, onEmailExportError, }) => {
|
|
9
9
|
const [exportType, setExportType] = useState(null);
|
|
10
10
|
const [excludedColumns, setExcludedColumns] = useState(['action']);
|
|
@@ -78,27 +78,18 @@ const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, ex
|
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
80
|
const handleEmailModalSubmit = async () => {
|
|
81
|
-
console.log('handleEmailModalSubmit called');
|
|
82
|
-
console.log('emailAddress:', emailAddress);
|
|
83
|
-
console.log('pendingExportData:', pendingExportData);
|
|
84
|
-
console.log('pendingEmailFormat:', pendingEmailFormat);
|
|
85
81
|
if (!emailAddress.trim() || !validateEmail(emailAddress)) {
|
|
86
82
|
setEmailError(emailAddress.trim() ? 'Please enter a valid email address' : 'Email address is required');
|
|
87
83
|
return;
|
|
88
84
|
}
|
|
89
85
|
if (!pendingExportData || !pendingEmailFormat) {
|
|
90
|
-
console.log('Missing pendingExportData or pendingEmailFormat');
|
|
91
86
|
return;
|
|
92
87
|
}
|
|
93
88
|
setEmailError('');
|
|
94
89
|
setIsExporting(true);
|
|
95
90
|
try {
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
console.log('Base64 file generated, length:', base64File.length);
|
|
99
|
-
console.log('Sending email to:', emailAddress);
|
|
100
|
-
const result = await sendExportEmail(emailAddress, base64File, emailExportApiUrl);
|
|
101
|
-
console.log('Email sent successfully:', result);
|
|
91
|
+
const exportFile = await generateExportAsFile(pendingExportData.data, pendingExportData.columns, pendingEmailFormat, { pdfOptions, xlsxOptions, csvOptions });
|
|
92
|
+
const result = await sendExportEmail(emailAddress, exportFile, emailExportApiUrl);
|
|
102
93
|
onEmailExportSuccess?.(result || 'Export sent successfully to your email');
|
|
103
94
|
setEmailAddress('');
|
|
104
95
|
setShowEmailModal(false);
|
|
@@ -40,18 +40,20 @@ export declare const exportToCsv: <T extends Record<string, any>>(data: T[], col
|
|
|
40
40
|
export declare const exportToXlsx: <T extends Record<string, any>>(data: T[], columns: MRT_ColumnDef<T>[], options?: XlsxExportOptions) => void;
|
|
41
41
|
export declare const exportToPdf: <T extends Record<string, any>>(data: T[], columns: MRT_ColumnDef<T>[], options?: PdfExportOptions) => Promise<void>;
|
|
42
42
|
/**
|
|
43
|
-
* Sends an export file to the user via email
|
|
43
|
+
* Sends an export file to the user via email using multipart/form-data
|
|
44
|
+
* Automatically includes Authorization header from cookies if available
|
|
44
45
|
* @param email - The recipient email address
|
|
45
|
-
* @param file -
|
|
46
|
+
* @param file - The File object to send
|
|
46
47
|
* @param baseUrl - The API base URL (optional, defaults to /api/v1)
|
|
48
|
+
* @param additionalHeaders - Optional additional headers to merge with auth headers
|
|
47
49
|
*/
|
|
48
|
-
export declare const sendExportEmail: (email: string, file:
|
|
50
|
+
export declare const sendExportEmail: (email: string, file: File, baseUrl?: string, additionalHeaders?: HeadersInit) => Promise<string>;
|
|
49
51
|
/**
|
|
50
|
-
* Generates export
|
|
52
|
+
* Generates export as a File object for email sending
|
|
51
53
|
*/
|
|
52
|
-
export declare const
|
|
54
|
+
export declare const generateExportAsFile: <T extends Record<string, any>>(data: T[], columns: MRT_ColumnDef<T>[], format: "csv" | "xlsx" | "pdf", options?: {
|
|
53
55
|
pdfOptions?: PdfExportOptions;
|
|
54
56
|
xlsxOptions?: XlsxExportOptions;
|
|
55
57
|
csvOptions?: CsvExportOptions;
|
|
56
|
-
}) => Promise<
|
|
58
|
+
}) => Promise<File>;
|
|
57
59
|
export {};
|
|
@@ -781,28 +781,55 @@ export const exportToPdf = async (data, columns, options = {}) => {
|
|
|
781
781
|
doc.save(filename);
|
|
782
782
|
};
|
|
783
783
|
/**
|
|
784
|
-
*
|
|
784
|
+
* Helper to get authentication headers from browser cookies
|
|
785
|
+
* This reads the accessToken cookie that's set by TokenManager
|
|
786
|
+
*/
|
|
787
|
+
const getAuthHeaders = () => {
|
|
788
|
+
if (typeof document === 'undefined')
|
|
789
|
+
return {};
|
|
790
|
+
// Read accessToken from cookies (matches TokenManager cookie name)
|
|
791
|
+
const cookies = document.cookie.split(';');
|
|
792
|
+
const accessTokenCookie = cookies.find((cookie) => cookie.trim().startsWith('accessToken='));
|
|
793
|
+
if (!accessTokenCookie)
|
|
794
|
+
return {};
|
|
795
|
+
const token = accessTokenCookie.split('=')[1];
|
|
796
|
+
return {
|
|
797
|
+
Authorization: `Bearer ${token}`,
|
|
798
|
+
};
|
|
799
|
+
};
|
|
800
|
+
/**
|
|
801
|
+
* Sends an export file to the user via email using multipart/form-data
|
|
802
|
+
* Automatically includes Authorization header from cookies if available
|
|
785
803
|
* @param email - The recipient email address
|
|
786
|
-
* @param file -
|
|
804
|
+
* @param file - The File object to send
|
|
787
805
|
* @param baseUrl - The API base URL (optional, defaults to /api/v1)
|
|
806
|
+
* @param additionalHeaders - Optional additional headers to merge with auth headers
|
|
788
807
|
*/
|
|
789
|
-
export const sendExportEmail = async (email, file, baseUrl = '/api/v1') => {
|
|
808
|
+
export const sendExportEmail = async (email, file, baseUrl = '/api/v1', additionalHeaders) => {
|
|
809
|
+
const formData = new FormData();
|
|
810
|
+
formData.append('file', file);
|
|
811
|
+
// Build headers: start with auth, then merge additional headers if provided
|
|
812
|
+
const authHeaders = getAuthHeaders();
|
|
813
|
+
const headers = additionalHeaders ? { ...authHeaders, ...additionalHeaders } : authHeaders;
|
|
814
|
+
// Note: Do NOT set Content-Type here - browser will set it automatically with boundary for multipart/form-data
|
|
790
815
|
const response = await fetch(`${baseUrl}/exports/send-email?email=${encodeURIComponent(email)}`, {
|
|
791
816
|
method: 'POST',
|
|
792
|
-
headers
|
|
793
|
-
|
|
794
|
-
},
|
|
795
|
-
body: JSON.stringify({ file }),
|
|
817
|
+
headers,
|
|
818
|
+
body: formData,
|
|
796
819
|
});
|
|
797
820
|
if (!response.ok) {
|
|
798
|
-
|
|
821
|
+
const errorText = await response.text().catch(() => response.statusText);
|
|
822
|
+
throw new Error(`Failed to send email: ${errorText}`);
|
|
799
823
|
}
|
|
800
824
|
return response.text();
|
|
801
825
|
};
|
|
802
826
|
/**
|
|
803
|
-
* Generates export
|
|
827
|
+
* Generates export as a File object for email sending
|
|
804
828
|
*/
|
|
805
|
-
export const
|
|
829
|
+
export const generateExportAsFile = async (data, columns, format, options) => {
|
|
830
|
+
const timestamp = new Date().toISOString().split('T')[0];
|
|
831
|
+
const title = options?.pdfOptions?.title || options?.xlsxOptions?.title || 'export';
|
|
832
|
+
const baseFilename = `${title.toLowerCase().replaceAll(/\s+/g, '_')}_${timestamp}`;
|
|
806
833
|
if (format === 'csv') {
|
|
807
834
|
const visibleColumns = columns.filter((col) => col.accessorKey !== 'action');
|
|
808
835
|
const headers = visibleColumns.map((col) => String(col.header ?? col.accessorKey));
|
|
@@ -812,7 +839,8 @@ export const generateExportAsBase64 = async (data, columns, format, options) =>
|
|
|
812
839
|
return value !== null && value !== undefined ? String(value) : '';
|
|
813
840
|
}));
|
|
814
841
|
const csvContent = Papa.unparse({ fields: headers, data: rows });
|
|
815
|
-
|
|
842
|
+
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
|
843
|
+
return new File([blob], `${baseFilename}.csv`, { type: 'text/csv' });
|
|
816
844
|
}
|
|
817
845
|
if (format === 'xlsx') {
|
|
818
846
|
const visibleColumns = columns.filter((col) => col.accessorKey !== 'action');
|
|
@@ -824,8 +852,13 @@ export const generateExportAsBase64 = async (data, columns, format, options) =>
|
|
|
824
852
|
const worksheet = XLSX.utils.aoa_to_sheet([headers, ...rows]);
|
|
825
853
|
const workbook = XLSX.utils.book_new();
|
|
826
854
|
XLSX.utils.book_append_sheet(workbook, worksheet, options?.xlsxOptions?.sheetName || 'Data');
|
|
827
|
-
const
|
|
828
|
-
|
|
855
|
+
const xlsxBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
|
|
856
|
+
const blob = new Blob([xlsxBuffer], {
|
|
857
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
858
|
+
});
|
|
859
|
+
return new File([blob], `${baseFilename}.xlsx`, {
|
|
860
|
+
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
861
|
+
});
|
|
829
862
|
}
|
|
830
863
|
if (format === 'pdf') {
|
|
831
864
|
const doc = new jsPDF();
|
|
@@ -841,7 +874,8 @@ export const generateExportAsBase64 = async (data, columns, format, options) =>
|
|
|
841
874
|
body: rows,
|
|
842
875
|
startY: 20,
|
|
843
876
|
});
|
|
844
|
-
|
|
877
|
+
const pdfBlob = doc.output('blob');
|
|
878
|
+
return new File([pdfBlob], `${baseFilename}.pdf`, { type: 'application/pdf' });
|
|
845
879
|
}
|
|
846
880
|
throw new Error(`Unsupported format: ${format}`);
|
|
847
881
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { default } from './data-table/index';
|
|
2
2
|
export * from './data-table/types';
|
|
3
3
|
export * from './data-table/pdfExportUtils';
|
|
4
|
-
export { sendExportEmail,
|
|
4
|
+
export { sendExportEmail, generateExportAsFile } from './data-table/exportUtils';
|
|
5
5
|
export * from './utils';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { default } from './data-table/index';
|
|
2
2
|
export * from './data-table/types';
|
|
3
3
|
export * from './data-table/pdfExportUtils';
|
|
4
|
-
export { sendExportEmail,
|
|
4
|
+
export { sendExportEmail, generateExportAsFile } from './data-table/exportUtils';
|
|
5
5
|
export * from './utils';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pagamio/frontend-commons-lib",
|
|
3
3
|
"description": "Pagamio library for Frontend reusable components like the form engine and table container",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.209",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"provenance": false
|