@pagamio/frontend-commons-lib 0.8.205 → 0.8.207
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.
- package/lib/components/layout/Sidebar.js +1 -1
- package/lib/helpers/validations.d.ts +6 -6
- package/lib/pagamio-table/data-table/ExportButton.d.ts +5 -1
- package/lib/pagamio-table/data-table/ExportButton.js +125 -24
- package/lib/pagamio-table/data-table/TableToolbar.d.ts +1 -1
- package/lib/pagamio-table/data-table/TableToolbar.js +2 -2
- package/lib/pagamio-table/data-table/exportUtils.d.ts +15 -0
- package/lib/pagamio-table/data-table/exportUtils.js +65 -0
- package/lib/pagamio-table/data-table/index.d.ts +1 -1
- package/lib/pagamio-table/data-table/index.js +2 -2
- package/lib/pagamio-table/data-table/types.d.ts +8 -0
- package/lib/pagamio-table/index.d.ts +1 -0
- package/lib/pagamio-table/index.js +1 -0
- package/lib/styles.css +4 -0
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ import { useAppSidebarContext } from '../../context';
|
|
|
6
6
|
import { useLibTranslations, useTranslation } from '../../translations';
|
|
7
7
|
const AppSidebarMenu = () => {
|
|
8
8
|
const { pages } = useAppSidebarContext();
|
|
9
|
-
return (_jsx(Sidebar.Items, { children: _jsx(Sidebar.ItemGroup, { children:
|
|
9
|
+
return (_jsx(Sidebar.Items, { children: pages.map((item) => (_jsx(Sidebar.ItemGroup, { children: _jsx(AppSidebarItem, { ...item }) }, item.label))) }));
|
|
10
10
|
};
|
|
11
11
|
const AppSidebarItem = ({ href, target, icon, label, items, badge, forceDropdown }) => {
|
|
12
12
|
const { pathname, linkComponent: Link } = useAppSidebarContext();
|
|
@@ -27,8 +27,8 @@ export declare const signupFormSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
|
27
27
|
password: string;
|
|
28
28
|
firstName: string;
|
|
29
29
|
lastName: string;
|
|
30
|
-
confirmPassword: string;
|
|
31
30
|
emailAddress: string;
|
|
31
|
+
confirmPassword: string;
|
|
32
32
|
profile: string;
|
|
33
33
|
role?: string | undefined;
|
|
34
34
|
}, {
|
|
@@ -36,8 +36,8 @@ export declare const signupFormSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
|
36
36
|
password: string;
|
|
37
37
|
firstName: string;
|
|
38
38
|
lastName: string;
|
|
39
|
-
confirmPassword: string;
|
|
40
39
|
emailAddress: string;
|
|
40
|
+
confirmPassword: string;
|
|
41
41
|
profile: string;
|
|
42
42
|
role?: string | undefined;
|
|
43
43
|
}>, {
|
|
@@ -45,8 +45,8 @@ export declare const signupFormSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
|
45
45
|
password: string;
|
|
46
46
|
firstName: string;
|
|
47
47
|
lastName: string;
|
|
48
|
-
confirmPassword: string;
|
|
49
48
|
emailAddress: string;
|
|
49
|
+
confirmPassword: string;
|
|
50
50
|
profile: string;
|
|
51
51
|
role?: string | undefined;
|
|
52
52
|
}, {
|
|
@@ -54,8 +54,8 @@ export declare const signupFormSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
|
54
54
|
password: string;
|
|
55
55
|
firstName: string;
|
|
56
56
|
lastName: string;
|
|
57
|
-
confirmPassword: string;
|
|
58
57
|
emailAddress: string;
|
|
58
|
+
confirmPassword: string;
|
|
59
59
|
profile: string;
|
|
60
60
|
role?: string | undefined;
|
|
61
61
|
}>, {
|
|
@@ -63,8 +63,8 @@ export declare const signupFormSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
|
63
63
|
password: string;
|
|
64
64
|
firstName: string;
|
|
65
65
|
lastName: string;
|
|
66
|
-
confirmPassword: string;
|
|
67
66
|
emailAddress: string;
|
|
67
|
+
confirmPassword: string;
|
|
68
68
|
profile: string;
|
|
69
69
|
role?: string | undefined;
|
|
70
70
|
}, {
|
|
@@ -72,8 +72,8 @@ export declare const signupFormSchema: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
|
72
72
|
password: string;
|
|
73
73
|
firstName: string;
|
|
74
74
|
lastName: string;
|
|
75
|
-
confirmPassword: string;
|
|
76
75
|
emailAddress: string;
|
|
76
|
+
confirmPassword: string;
|
|
77
77
|
profile: string;
|
|
78
78
|
role?: string | undefined;
|
|
79
79
|
}>;
|
|
@@ -52,6 +52,10 @@ type ExportDropdownProps<T extends Record<string, any>> = {
|
|
|
52
52
|
csvOptions?: CsvExportOptions;
|
|
53
53
|
exportAll?: boolean;
|
|
54
54
|
fetchData?: (params?: Record<string, string>) => Promise<T[]>;
|
|
55
|
+
enableEmailExport?: boolean;
|
|
56
|
+
emailExportApiUrl?: string;
|
|
57
|
+
onEmailExportSuccess?: (message: string) => void;
|
|
58
|
+
onEmailExportError?: (error: Error) => void;
|
|
55
59
|
};
|
|
56
|
-
declare const ExportDropdown: <T extends Record<string, any>>({ data, columns, containerClassName, buttonClassName, extraOptions, pdfOptions, xlsxOptions, csvOptions, exportAll, fetchData, }: ExportDropdownProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
60
|
+
declare const ExportDropdown: <T extends Record<string, any>>({ data, columns, containerClassName, buttonClassName, extraOptions, pdfOptions, xlsxOptions, csvOptions, exportAll, fetchData, enableEmailExport, emailExportApiUrl, onEmailExportSuccess, onEmailExportError, }: ExportDropdownProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
57
61
|
export default ExportDropdown;
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Stack } from '@mantine/core';
|
|
3
|
-
import { Checkbox, Label } from 'flowbite-react';
|
|
3
|
+
import { Checkbox, Label, TextInput } from 'flowbite-react';
|
|
4
|
+
import { HiMail } from 'react-icons/hi';
|
|
4
5
|
import { useEffect, useRef, useState } from 'react';
|
|
5
|
-
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components';
|
|
6
|
-
import { exportToCsv, exportToPdf, exportToXlsx } from './exportUtils';
|
|
7
|
-
const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, extraOptions = [], pdfOptions, xlsxOptions, csvOptions, exportAll = false, fetchData, }) => {
|
|
6
|
+
import { Modal, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components';
|
|
7
|
+
import { exportToCsv, exportToPdf, exportToXlsx, generateExportAsBase64, sendExportEmail } from './exportUtils';
|
|
8
|
+
const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, extraOptions = [], pdfOptions, xlsxOptions, csvOptions, exportAll = false, fetchData, enableEmailExport = false, emailExportApiUrl, onEmailExportSuccess, onEmailExportError, }) => {
|
|
8
9
|
const [exportType, setExportType] = useState(null);
|
|
9
10
|
const [excludedColumns, setExcludedColumns] = useState(['action']);
|
|
10
11
|
const [isExporting, setIsExporting] = useState(false);
|
|
11
12
|
const [exportAllData, setExportAllData] = useState(false);
|
|
12
13
|
const [selectOpen, setSelectOpen] = useState(false);
|
|
14
|
+
const [emailAddress, setEmailAddress] = useState('');
|
|
15
|
+
const [emailError, setEmailError] = useState('');
|
|
16
|
+
const [showEmailModal, setShowEmailModal] = useState(false);
|
|
17
|
+
const [pendingExportData, setPendingExportData] = useState(null);
|
|
18
|
+
const [pendingEmailFormat, setPendingEmailFormat] = useState(null);
|
|
13
19
|
const popoverRef = useRef(null);
|
|
14
20
|
useEffect(() => {
|
|
15
21
|
const handleClickOutside = (event) => {
|
|
@@ -26,6 +32,22 @@ const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, ex
|
|
|
26
32
|
{ value: 'csv', label: 'Export as CSV' },
|
|
27
33
|
{ value: 'xlsx', label: 'Export as XLSX' },
|
|
28
34
|
{ value: 'pdf', label: 'Export as PDF' },
|
|
35
|
+
...(enableEmailExport
|
|
36
|
+
? [
|
|
37
|
+
{
|
|
38
|
+
value: 'email-csv',
|
|
39
|
+
label: (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx(HiMail, { className: "w-4 h-4" }), " Email as CSV"] })),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
value: 'email-xlsx',
|
|
43
|
+
label: (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx(HiMail, { className: "w-4 h-4" }), " Email as XLSX"] })),
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
value: 'email-pdf',
|
|
47
|
+
label: (_jsxs("span", { className: "flex items-center gap-1", children: [_jsx(HiMail, { className: "w-4 h-4" }), " Email as PDF"] })),
|
|
48
|
+
},
|
|
49
|
+
]
|
|
50
|
+
: []),
|
|
29
51
|
];
|
|
30
52
|
const handleCheckboxChange = (columnKey, checked) => {
|
|
31
53
|
setExcludedColumns((prev) => (checked ? [...prev, columnKey] : prev.filter((key) => key !== columnKey)));
|
|
@@ -33,42 +55,104 @@ const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, ex
|
|
|
33
55
|
const getIncludedColumns = () => {
|
|
34
56
|
return columns.filter((col) => !excludedColumns.includes(col.accessorKey));
|
|
35
57
|
};
|
|
58
|
+
const isEmailExport = exportType?.startsWith('email-');
|
|
59
|
+
const emailFormat = isEmailExport ? exportType?.replace('email-', '') : null;
|
|
60
|
+
const validateEmail = (email) => {
|
|
61
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
62
|
+
return emailRegex.test(email);
|
|
63
|
+
};
|
|
64
|
+
const performExport = async (exportData, includedColumns) => {
|
|
65
|
+
if (exportType === 'csv') {
|
|
66
|
+
exportToCsv(exportData, includedColumns, csvOptions);
|
|
67
|
+
}
|
|
68
|
+
else if (exportType === 'xlsx') {
|
|
69
|
+
exportToXlsx(exportData, includedColumns, xlsxOptions);
|
|
70
|
+
}
|
|
71
|
+
else if (exportType === 'pdf') {
|
|
72
|
+
await exportToPdf(exportData, includedColumns, {
|
|
73
|
+
title: pdfOptions?.title || 'Data Export',
|
|
74
|
+
subtitle: pdfOptions?.subtitle,
|
|
75
|
+
colors: pdfOptions?.colors,
|
|
76
|
+
logo: pdfOptions?.logo,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
};
|
|
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
|
+
if (!emailAddress.trim() || !validateEmail(emailAddress)) {
|
|
86
|
+
setEmailError(emailAddress.trim() ? 'Please enter a valid email address' : 'Email address is required');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (!pendingExportData || !pendingEmailFormat) {
|
|
90
|
+
console.log('Missing pendingExportData or pendingEmailFormat');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
setEmailError('');
|
|
94
|
+
setIsExporting(true);
|
|
95
|
+
try {
|
|
96
|
+
console.log('Generating export as base64...');
|
|
97
|
+
const base64File = await generateExportAsBase64(pendingExportData.data, pendingExportData.columns, pendingEmailFormat, { pdfOptions, xlsxOptions, csvOptions });
|
|
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);
|
|
102
|
+
onEmailExportSuccess?.(result || 'Export sent successfully to your email');
|
|
103
|
+
setEmailAddress('');
|
|
104
|
+
setShowEmailModal(false);
|
|
105
|
+
setPendingExportData(null);
|
|
106
|
+
setPendingEmailFormat(null);
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
console.error('Email export failed:', error);
|
|
110
|
+
onEmailExportError?.(error instanceof Error ? error : new Error('Failed to send email'));
|
|
111
|
+
setEmailError('Failed to send email. Please try again.');
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
setIsExporting(false);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const handleEmailModalClose = () => {
|
|
118
|
+
setShowEmailModal(false);
|
|
119
|
+
setEmailAddress('');
|
|
120
|
+
setEmailError('');
|
|
121
|
+
setPendingExportData(null);
|
|
122
|
+
setPendingEmailFormat(null);
|
|
123
|
+
setIsExporting(false);
|
|
124
|
+
};
|
|
36
125
|
const handleContinue = async () => {
|
|
37
126
|
const includedColumns = getIncludedColumns();
|
|
38
127
|
setIsExporting(true);
|
|
39
128
|
try {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
else if (exportType === 'xlsx') {
|
|
49
|
-
exportToXlsx(exportData, includedColumns, xlsxOptions);
|
|
129
|
+
const exportData = exportAllData && fetchData ? await fetchData({ exportAll: 'true' }) : data;
|
|
130
|
+
if (isEmailExport) {
|
|
131
|
+
// Store data, format and show email modal
|
|
132
|
+
setPendingExportData({ data: exportData, columns: includedColumns });
|
|
133
|
+
setPendingEmailFormat(emailFormat); // Store the format before closing popover
|
|
134
|
+
setShowEmailModal(true);
|
|
135
|
+
setExportType(null); // Close the popover
|
|
50
136
|
}
|
|
51
|
-
else
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
title: pdfOptions?.title || 'Data Export',
|
|
55
|
-
subtitle: pdfOptions?.subtitle,
|
|
56
|
-
colors: pdfOptions?.colors,
|
|
57
|
-
logo: pdfOptions?.logo,
|
|
58
|
-
});
|
|
137
|
+
else {
|
|
138
|
+
await performExport(exportData, includedColumns);
|
|
139
|
+
setExportType(null);
|
|
59
140
|
}
|
|
60
141
|
}
|
|
61
142
|
catch (error) {
|
|
62
143
|
console.error('Export failed:', error);
|
|
144
|
+
if (isEmailExport) {
|
|
145
|
+
onEmailExportError?.(error instanceof Error ? error : new Error('Export failed'));
|
|
146
|
+
}
|
|
63
147
|
}
|
|
64
148
|
finally {
|
|
65
149
|
setIsExporting(false);
|
|
66
|
-
setExportType(null);
|
|
67
150
|
}
|
|
68
151
|
};
|
|
69
152
|
const handleExportChange = (type) => {
|
|
70
153
|
if (!type || type === 'none') {
|
|
71
154
|
setExportType(null);
|
|
155
|
+
setEmailError('');
|
|
72
156
|
return;
|
|
73
157
|
}
|
|
74
158
|
// Check if type is an extraOption
|
|
@@ -89,6 +173,23 @@ const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, ex
|
|
|
89
173
|
}) }), _jsx("button", { className: `w-full mt-4 px-4 py-2 rounded-md text-white flex items-center justify-center
|
|
90
174
|
${getIncludedColumns().length === 0 || isExporting
|
|
91
175
|
? 'bg-gray-300 cursor-not-allowed'
|
|
92
|
-
: 'bg-primary-500 hover:bg-primary-600'}`, onClick: handleContinue, disabled: getIncludedColumns().length === 0 || isExporting, children: isExporting ? (_jsxs(_Fragment, { children: [_jsxs("svg", { className: "animate-spin -ml-1 mr-2 h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }),
|
|
176
|
+
: 'bg-primary-500 hover:bg-primary-600'}`, onClick: handleContinue, disabled: getIncludedColumns().length === 0 || isExporting, children: isExporting ? (_jsxs(_Fragment, { children: [_jsxs("svg", { className: "animate-spin -ml-1 mr-2 h-4 w-4 text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }), isEmailExport ? 'Preparing...' : 'Exporting...'] })) : ('Continue') })] })), _jsx(Modal, { isOpen: showEmailModal, onClose: handleEmailModalClose, title: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(HiMail, { className: "w-5 h-5 text-primary-500" }), _jsx("span", { children: "Send Export via Email" })] }), size: "md", primaryButton: {
|
|
177
|
+
label: 'Send Email',
|
|
178
|
+
onClick: () => {
|
|
179
|
+
handleEmailModalSubmit().catch((error) => {
|
|
180
|
+
console.error('Error in handleEmailModalSubmit:', error);
|
|
181
|
+
});
|
|
182
|
+
},
|
|
183
|
+
loading: isExporting,
|
|
184
|
+
disabled: isExporting || !emailAddress.trim(),
|
|
185
|
+
}, secondaryButton: {
|
|
186
|
+
label: 'Cancel',
|
|
187
|
+
onClick: handleEmailModalClose,
|
|
188
|
+
disabled: isExporting,
|
|
189
|
+
variant: 'outline',
|
|
190
|
+
}, children: _jsxs("div", { className: "space-y-4", children: [_jsx("p", { className: "text-sm text-gray-600", children: "Enter your email address to receive the export file as an attachment." }), _jsxs("div", { children: [_jsxs(Label, { htmlFor: "modal-export-email", className: "mb-2 block", children: ["Email Address ", _jsx("span", { className: "text-red-500", children: "*" })] }), _jsx(TextInput, { id: "modal-export-email", type: "email", placeholder: "your.email@example.com", value: emailAddress, onChange: (e) => {
|
|
191
|
+
setEmailAddress(e.target.value);
|
|
192
|
+
setEmailError('');
|
|
193
|
+
}, color: emailError ? 'failure' : undefined, helperText: emailError || undefined, disabled: isExporting, autoFocus: true })] }), pendingEmailFormat && (_jsx("div", { className: "p-3 bg-blue-50 rounded-md border border-blue-200", children: _jsxs("p", { className: "text-xs text-blue-800", children: [_jsx("strong", { children: "Export Format:" }), " ", pendingEmailFormat.toUpperCase()] }) }))] }) })] }));
|
|
93
194
|
};
|
|
94
195
|
export default ExportDropdown;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { type TableToolbarProps } from './types';
|
|
2
|
-
declare const TableToolbar: <T extends Record<string, any>>({ searchable, searchQuery, onSearch, filters, appliedFilters, exportable, columns, data, onTableFilter, addButton, addText, searctInputPlaceHolder, onAdd, handleSearchTable, handleApplyFilters, onClearFilters, showClearFilters, showApplyFilterButton, isNarrow, extraExportOptions, pdfExportOptions, xlsxExportOptions, csvExportOptions, exportAll, fetchData, }: TableToolbarProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
declare const TableToolbar: <T extends Record<string, any>>({ searchable, searchQuery, onSearch, filters, appliedFilters, exportable, columns, data, onTableFilter, addButton, addText, searctInputPlaceHolder, onAdd, handleSearchTable, handleApplyFilters, onClearFilters, showClearFilters, showApplyFilterButton, isNarrow, extraExportOptions, pdfExportOptions, xlsxExportOptions, csvExportOptions, exportAll, fetchData, enableEmailExport, emailExportApiUrl, onEmailExportSuccess, onEmailExportError, }: TableToolbarProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
export default TableToolbar;
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { HiPlusSm } from 'react-icons/hi';
|
|
3
3
|
import { FilterComponent, IconButton } from '../../components';
|
|
4
4
|
import ExportDropdown from './ExportButton';
|
|
5
|
-
const TableToolbar = ({ searchable, searchQuery, onSearch, filters = [], appliedFilters, exportable, columns, data, onTableFilter = () => { }, addButton, addText, searctInputPlaceHolder, onAdd = () => { }, handleSearchTable, handleApplyFilters, onClearFilters = () => { }, showClearFilters = false, showApplyFilterButton = true, isNarrow, extraExportOptions = [], pdfExportOptions, xlsxExportOptions, csvExportOptions, exportAll, fetchData, }) => {
|
|
5
|
+
const TableToolbar = ({ searchable, searchQuery, onSearch, filters = [], appliedFilters, exportable, columns, data, onTableFilter = () => { }, addButton, addText, searctInputPlaceHolder, onAdd = () => { }, handleSearchTable, handleApplyFilters, onClearFilters = () => { }, showClearFilters = false, showApplyFilterButton = true, isNarrow, extraExportOptions = [], pdfExportOptions, xlsxExportOptions, csvExportOptions, exportAll, fetchData, enableEmailExport, emailExportApiUrl, onEmailExportSuccess, onEmailExportError, }) => {
|
|
6
6
|
const handleFilter = (columnKey, value) => {
|
|
7
7
|
onTableFilter(columnKey, value ?? '');
|
|
8
8
|
};
|
|
@@ -19,6 +19,6 @@ const TableToolbar = ({ searchable, searchQuery, onSearch, filters = [], applied
|
|
|
19
19
|
else {
|
|
20
20
|
handleFilter(name, value);
|
|
21
21
|
}
|
|
22
|
-
}, handleApplyFilters: handleApplyFilters ?? handleSearchTable, resetFilters: onClearFilters, showSearch: searchable, searchQuery: searchQuery, onSearch: onSearch, isNarrow: isNarrow, children: _jsxs("div", { className: isNarrow ? 'flex flex-col items-stretch space-y-2 pt-5' : 'flex items-center flex-wrap gap-2', children: [exportable && (_jsx("div", { className: isNarrow ? 'w-full' : 'flex-grow', children: _jsx(ExportDropdown, { containerClassName: "w-full", columns: columns, data: data, buttonClassName: "h-10", extraOptions: extraExportOptions, pdfOptions: pdfExportOptions, xlsxOptions: xlsxExportOptions, csvOptions: csvExportOptions, exportAll: exportAll, fetchData: fetchData }) })), addButton && (_jsx("div", { className: isNarrow ? 'w-full' : 'flex-grow', children: typeof addButton === 'boolean' ? (_jsx(IconButton, { onClick: onAdd, icon: HiPlusSm, label: "add-new-entry", className: "items-center w-full text-nowrap", children: addText ?? 'Add New Entry' })) : (addButton) }))] }) }));
|
|
22
|
+
}, handleApplyFilters: handleApplyFilters ?? handleSearchTable, resetFilters: onClearFilters, showSearch: searchable, searchQuery: searchQuery, onSearch: onSearch, isNarrow: isNarrow, children: _jsxs("div", { className: isNarrow ? 'flex flex-col items-stretch space-y-2 pt-5' : 'flex items-center flex-wrap gap-2', children: [exportable && (_jsx("div", { className: isNarrow ? 'w-full' : 'flex-grow', children: _jsx(ExportDropdown, { containerClassName: "w-full", columns: columns, data: data, buttonClassName: "h-10", extraOptions: extraExportOptions, pdfOptions: pdfExportOptions, xlsxOptions: xlsxExportOptions, csvOptions: csvExportOptions, exportAll: exportAll, fetchData: fetchData, enableEmailExport: enableEmailExport, emailExportApiUrl: emailExportApiUrl, onEmailExportSuccess: onEmailExportSuccess, onEmailExportError: onEmailExportError }) })), addButton && (_jsx("div", { className: isNarrow ? 'w-full' : 'flex-grow', children: typeof addButton === 'boolean' ? (_jsx(IconButton, { onClick: onAdd, icon: HiPlusSm, label: "add-new-entry", className: "items-center w-full text-nowrap", children: addText ?? 'Add New Entry' })) : (addButton) }))] }) }));
|
|
23
23
|
};
|
|
24
24
|
export default TableToolbar;
|
|
@@ -39,4 +39,19 @@ interface CsvExportOptions {
|
|
|
39
39
|
export declare const exportToCsv: <T extends Record<string, any>>(data: T[], columns: MRT_ColumnDef<T>[], options?: CsvExportOptions) => void;
|
|
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
|
+
/**
|
|
43
|
+
* Sends an export file to the user via email
|
|
44
|
+
* @param email - The recipient email address
|
|
45
|
+
* @param file - Base64 encoded file string
|
|
46
|
+
* @param baseUrl - The API base URL (optional, defaults to /api/v1)
|
|
47
|
+
*/
|
|
48
|
+
export declare const sendExportEmail: (email: string, file: string, baseUrl?: string) => Promise<string>;
|
|
49
|
+
/**
|
|
50
|
+
* Generates export file as base64 string for email sending
|
|
51
|
+
*/
|
|
52
|
+
export declare const generateExportAsBase64: <T extends Record<string, any>>(data: T[], columns: MRT_ColumnDef<T>[], format: "csv" | "xlsx" | "pdf", options?: {
|
|
53
|
+
pdfOptions?: PdfExportOptions;
|
|
54
|
+
xlsxOptions?: XlsxExportOptions;
|
|
55
|
+
csvOptions?: CsvExportOptions;
|
|
56
|
+
}) => Promise<string>;
|
|
42
57
|
export {};
|
|
@@ -780,3 +780,68 @@ export const exportToPdf = async (data, columns, options = {}) => {
|
|
|
780
780
|
const filename = `${title.toLowerCase().replace(/\s+/g, '_')}_${timestamp}.pdf`;
|
|
781
781
|
doc.save(filename);
|
|
782
782
|
};
|
|
783
|
+
/**
|
|
784
|
+
* Sends an export file to the user via email
|
|
785
|
+
* @param email - The recipient email address
|
|
786
|
+
* @param file - Base64 encoded file string
|
|
787
|
+
* @param baseUrl - The API base URL (optional, defaults to /api/v1)
|
|
788
|
+
*/
|
|
789
|
+
export const sendExportEmail = async (email, file, baseUrl = '/api/v1') => {
|
|
790
|
+
const response = await fetch(`${baseUrl}/exports/send-email?email=${encodeURIComponent(email)}`, {
|
|
791
|
+
method: 'POST',
|
|
792
|
+
headers: {
|
|
793
|
+
'Content-Type': 'application/json',
|
|
794
|
+
},
|
|
795
|
+
body: JSON.stringify({ file }),
|
|
796
|
+
});
|
|
797
|
+
if (!response.ok) {
|
|
798
|
+
throw new Error(`Failed to send email: ${response.statusText}`);
|
|
799
|
+
}
|
|
800
|
+
return response.text();
|
|
801
|
+
};
|
|
802
|
+
/**
|
|
803
|
+
* Generates export file as base64 string for email sending
|
|
804
|
+
*/
|
|
805
|
+
export const generateExportAsBase64 = async (data, columns, format, options) => {
|
|
806
|
+
if (format === 'csv') {
|
|
807
|
+
const visibleColumns = columns.filter((col) => col.accessorKey !== 'action');
|
|
808
|
+
const headers = visibleColumns.map((col) => String(col.header ?? col.accessorKey));
|
|
809
|
+
const rows = data.map((row) => visibleColumns.map((col) => {
|
|
810
|
+
const key = col.accessorKey;
|
|
811
|
+
const value = row[key];
|
|
812
|
+
return value !== null && value !== undefined ? String(value) : '';
|
|
813
|
+
}));
|
|
814
|
+
const csvContent = Papa.unparse({ fields: headers, data: rows });
|
|
815
|
+
return btoa(csvContent);
|
|
816
|
+
}
|
|
817
|
+
if (format === 'xlsx') {
|
|
818
|
+
const visibleColumns = columns.filter((col) => col.accessorKey !== 'action');
|
|
819
|
+
const headers = visibleColumns.map((col) => String(col.header ?? col.accessorKey));
|
|
820
|
+
const rows = data.map((row) => visibleColumns.map((col) => {
|
|
821
|
+
const key = col.accessorKey;
|
|
822
|
+
return row[key] ?? '';
|
|
823
|
+
}));
|
|
824
|
+
const worksheet = XLSX.utils.aoa_to_sheet([headers, ...rows]);
|
|
825
|
+
const workbook = XLSX.utils.book_new();
|
|
826
|
+
XLSX.utils.book_append_sheet(workbook, worksheet, options?.xlsxOptions?.sheetName || 'Data');
|
|
827
|
+
const xlsxData = XLSX.write(workbook, { bookType: 'xlsx', type: 'base64' });
|
|
828
|
+
return xlsxData;
|
|
829
|
+
}
|
|
830
|
+
if (format === 'pdf') {
|
|
831
|
+
const doc = new jsPDF();
|
|
832
|
+
const visibleColumns = columns.filter((col) => col.accessorKey !== 'action');
|
|
833
|
+
const headers = visibleColumns.map((col) => String(col.header ?? col.accessorKey));
|
|
834
|
+
const rows = data.map((row) => visibleColumns.map((col) => {
|
|
835
|
+
const key = col.accessorKey;
|
|
836
|
+
const value = row[key];
|
|
837
|
+
return value !== null && value !== undefined ? String(value) : '';
|
|
838
|
+
}));
|
|
839
|
+
doc.autoTable({
|
|
840
|
+
head: [headers],
|
|
841
|
+
body: rows,
|
|
842
|
+
startY: 20,
|
|
843
|
+
});
|
|
844
|
+
return doc.output('datauristring').split(',')[1];
|
|
845
|
+
}
|
|
846
|
+
throw new Error(`Unsupported format: ${format}`);
|
|
847
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type PagamioMantineTableProps } from './types';
|
|
2
2
|
declare const PagamioTable: <T extends {
|
|
3
3
|
id: string | number;
|
|
4
|
-
}>({ columns, data, isLoading, pagination, sorting, filtering, search, exportable, addButton, addText, onAdd, onClearFilters, handleSearchTable, showClearFilters, showApplyFilterButton, searctInputPlaceHolder, expandable, extraExportOptions, pdfExportOptions, xlsxExportOptions, csvExportOptions, renderExpandableComponent, onRowClick, rowClassName, ...props }: PagamioMantineTableProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
}>({ columns, data, isLoading, pagination, sorting, filtering, search, exportable, addButton, addText, onAdd, onClearFilters, handleSearchTable, showClearFilters, showApplyFilterButton, searctInputPlaceHolder, expandable, extraExportOptions, pdfExportOptions, xlsxExportOptions, csvExportOptions, renderExpandableComponent, onRowClick, rowClassName, enableEmailExport, emailExportApiUrl, onEmailExportSuccess, onEmailExportError, ...props }: PagamioMantineTableProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
5
5
|
export default PagamioTable;
|
|
@@ -2,10 +2,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useMediaQueries } from '../../shared';
|
|
3
3
|
import CoreTable from './MantineCoreTable';
|
|
4
4
|
import TableToolbar from './TableToolbar';
|
|
5
|
-
const PagamioTable = ({ columns, data, isLoading, pagination, sorting, filtering, search, exportable = false, addButton = false, addText, onAdd, onClearFilters, handleSearchTable, showClearFilters = false, showApplyFilterButton = true, searctInputPlaceHolder, expandable = false, extraExportOptions, pdfExportOptions, xlsxExportOptions, csvExportOptions, renderExpandableComponent, onRowClick, rowClassName, ...props }) => {
|
|
5
|
+
const PagamioTable = ({ columns, data, isLoading, pagination, sorting, filtering, search, exportable = false, addButton = false, addText, onAdd, onClearFilters, handleSearchTable, showClearFilters = false, showApplyFilterButton = true, searctInputPlaceHolder, expandable = false, extraExportOptions, pdfExportOptions, xlsxExportOptions, csvExportOptions, renderExpandableComponent, onRowClick, rowClassName, enableEmailExport, emailExportApiUrl, onEmailExportSuccess, onEmailExportError, ...props }) => {
|
|
6
6
|
const hasPagination = pagination?.enabled;
|
|
7
7
|
const { isSm, isXs } = useMediaQueries();
|
|
8
8
|
const isNarrow = isXs || isSm;
|
|
9
|
-
return (_jsxs("div", { className: "mt-2", children: [_jsx(TableToolbar, { searchable: search?.enabled ?? false, searchQuery: search?.searchQuery ?? '', onSearch: search?.onSearch ?? (() => { }), filters: filtering?.filters ?? [], appliedFilters: filtering?.appliedFilters ?? {}, onTableFilter: filtering?.onTableFilter ?? (() => { }), exportable: exportable, addButton: addButton, addText: addText, onAdd: onAdd ?? (() => { }), handleSearchTable: handleSearchTable, onClearFilters: onClearFilters, showClearFilters: showClearFilters, showApplyFilterButton: showApplyFilterButton, searctInputPlaceHolder: searctInputPlaceHolder, data: data, columns: columns, isNarrow: isNarrow, extraExportOptions: extraExportOptions, pdfExportOptions: pdfExportOptions, xlsxExportOptions: xlsxExportOptions, csvExportOptions: csvExportOptions, exportAll: props.exportAll, fetchData: props.fetchData }), _jsx("div", { className: "border border-gray-200 rounded-md overflow-hidden", children: _jsx(CoreTable, { columns: columns, data: data, isLoading: isLoading, onSort: sorting?.onSort, sortConfig: sorting?.sortConfig ?? null, multiSorting: sorting?.multiSorting || false, sortable: props.sortable, setSortBy: sorting?.setSortBy, setSortDir: sorting?.setSortDir, enablePagination: hasPagination, pagination: pagination, expandable: expandable, onRowClick: onRowClick, rowClassName: rowClassName, renderExpandableComponent: renderExpandableComponent, ...props }) })] }));
|
|
9
|
+
return (_jsxs("div", { className: "mt-2", children: [_jsx(TableToolbar, { searchable: search?.enabled ?? false, searchQuery: search?.searchQuery ?? '', onSearch: search?.onSearch ?? (() => { }), filters: filtering?.filters ?? [], appliedFilters: filtering?.appliedFilters ?? {}, onTableFilter: filtering?.onTableFilter ?? (() => { }), exportable: exportable, addButton: addButton, addText: addText, onAdd: onAdd ?? (() => { }), handleSearchTable: handleSearchTable, onClearFilters: onClearFilters, showClearFilters: showClearFilters, showApplyFilterButton: showApplyFilterButton, searctInputPlaceHolder: searctInputPlaceHolder, data: data, columns: columns, isNarrow: isNarrow, extraExportOptions: extraExportOptions, pdfExportOptions: pdfExportOptions, xlsxExportOptions: xlsxExportOptions, csvExportOptions: csvExportOptions, exportAll: props.exportAll, fetchData: props.fetchData, enableEmailExport: enableEmailExport, emailExportApiUrl: emailExportApiUrl, onEmailExportSuccess: onEmailExportSuccess, onEmailExportError: onEmailExportError }), _jsx("div", { className: "border border-gray-200 rounded-md overflow-hidden", children: _jsx(CoreTable, { columns: columns, data: data, isLoading: isLoading, onSort: sorting?.onSort, sortConfig: sorting?.sortConfig ?? null, multiSorting: sorting?.multiSorting || false, sortable: props.sortable, setSortBy: sorting?.setSortBy, setSortDir: sorting?.setSortDir, enablePagination: hasPagination, pagination: pagination, expandable: expandable, onRowClick: onRowClick, rowClassName: rowClassName, renderExpandableComponent: renderExpandableComponent, ...props }) })] }));
|
|
10
10
|
};
|
|
11
11
|
export default PagamioTable;
|
|
@@ -114,6 +114,10 @@ export type PagamioMantineTableProps<T extends Record<string, any>> = {
|
|
|
114
114
|
row: MRT_Row<T>;
|
|
115
115
|
table: MRT_TableInstance<T>;
|
|
116
116
|
}) => React.ReactNode;
|
|
117
|
+
enableEmailExport?: boolean;
|
|
118
|
+
emailExportApiUrl?: string;
|
|
119
|
+
onEmailExportSuccess?: (message: string) => void;
|
|
120
|
+
onEmailExportError?: (error: Error) => void;
|
|
117
121
|
};
|
|
118
122
|
export type TableToolbarProps<T extends Record<string, any>> = {
|
|
119
123
|
searchable: boolean;
|
|
@@ -141,6 +145,10 @@ export type TableToolbarProps<T extends Record<string, any>> = {
|
|
|
141
145
|
csvExportOptions?: CsvExportOptions;
|
|
142
146
|
exportAll?: boolean;
|
|
143
147
|
fetchData?: (params?: Record<string, string>) => Promise<T[]>;
|
|
148
|
+
enableEmailExport?: boolean;
|
|
149
|
+
emailExportApiUrl?: string;
|
|
150
|
+
onEmailExportSuccess?: (message: string) => void;
|
|
151
|
+
onEmailExportError?: (error: Error) => void;
|
|
144
152
|
};
|
|
145
153
|
export interface BaseEntity {
|
|
146
154
|
id: number | string;
|
package/lib/styles.css
CHANGED
|
@@ -2211,6 +2211,10 @@ input[type="range"]::-ms-fill-lower {
|
|
|
2211
2211
|
.border-dashed {
|
|
2212
2212
|
border-style: dashed;
|
|
2213
2213
|
}
|
|
2214
|
+
.border-blue-200 {
|
|
2215
|
+
--tw-border-opacity: 1;
|
|
2216
|
+
border-color: rgb(195 221 253 / var(--tw-border-opacity, 1));
|
|
2217
|
+
}
|
|
2214
2218
|
.border-blue-500 {
|
|
2215
2219
|
--tw-border-opacity: 1;
|
|
2216
2220
|
border-color: rgb(63 131 248 / var(--tw-border-opacity, 1));
|
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.207",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"provenance": false
|