@pagamio/frontend-commons-lib 0.8.356 → 0.8.357

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.
@@ -51,7 +51,7 @@ type ExportDropdownProps<T extends Record<string, any>> = {
51
51
  xlsxOptions?: XlsxExportOptions;
52
52
  csvOptions?: CsvExportOptions;
53
53
  exportAll?: boolean;
54
- fetchData?: (params?: Record<string, string>) => Promise<T[]>;
54
+ fetchData?: (params?: Record<string, string>, onProgress?: (fetched: number, total: number) => void) => Promise<T[]>;
55
55
  enableEmailExport?: boolean;
56
56
  emailExportApiUrl?: string;
57
57
  onEmailExportSuccess?: (message: string) => void;
@@ -9,6 +9,7 @@ const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, ex
9
9
  const [exportType, setExportType] = useState(null);
10
10
  const [excludedColumns, setExcludedColumns] = useState(['action']);
11
11
  const [isExporting, setIsExporting] = useState(false);
12
+ const [exportProgress, setExportProgress] = useState(null);
12
13
  const [exportAllData, setExportAllData] = useState(false);
13
14
  const [selectOpen, setSelectOpen] = useState(false);
14
15
  const [emailAddress, setEmailAddress] = useState('');
@@ -116,8 +117,11 @@ const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, ex
116
117
  const handleContinue = async () => {
117
118
  const includedColumns = getIncludedColumns();
118
119
  setIsExporting(true);
120
+ setExportProgress(null);
119
121
  try {
120
- const exportData = exportAllData && fetchData ? await fetchData({ exportAll: 'true' }) : data;
122
+ const exportData = exportAllData && fetchData
123
+ ? await fetchData({ exportAll: 'true' }, (fetched, total) => setExportProgress({ fetched, total }))
124
+ : data;
121
125
  if (isEmailExport) {
122
126
  // Store data, format and show email modal
123
127
  setPendingExportData({ data: exportData, columns: includedColumns });
@@ -138,6 +142,7 @@ const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, ex
138
142
  }
139
143
  finally {
140
144
  setIsExporting(false);
145
+ setExportProgress(null);
141
146
  }
142
147
  };
143
148
  const handleExportChange = (type) => {
@@ -164,7 +169,11 @@ const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, ex
164
169
  }) }), _jsx(Button, { variant: "primary", className: `w-full mt-4 px-4 py-2 rounded-md text-white flex items-center justify-center
165
170
  ${getIncludedColumns().length === 0 || isExporting
166
171
  ? 'bg-gray-300 cursor-not-allowed'
167
- : 'bg-primary hover:bg-primary/90'}`, 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" }), _jsx("span", { children: "Send Export via Email" })] }), size: "md", primaryButton: {
172
+ : 'bg-primary hover:bg-primary/90'}`, 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" })] }), exportProgress && exportProgress.total > exportProgress.fetched
173
+ ? `Fetching ${exportProgress.fetched}/${exportProgress.total}...`
174
+ : isEmailExport
175
+ ? 'Preparing...'
176
+ : '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" }), _jsx("span", { children: "Send Export via Email" })] }), size: "md", primaryButton: {
168
177
  label: 'Send Email',
169
178
  onClick: () => {
170
179
  handleEmailModalSubmit().catch((error) => {
@@ -82,7 +82,14 @@ export interface ExportConfig<T extends Record<string, any>> {
82
82
  xlsx?: XlsxExportOptions;
83
83
  csv?: CsvExportOptions;
84
84
  extraOptions?: ExtraOption[];
85
- fetchAllData?: (params?: Record<string, string>) => Promise<T[]>;
85
+ /**
86
+ * Fetch the full dataset for "Export all data" (not just the current page).
87
+ * `onProgress(fetched, total)` is invoked after each page so the UI can show
88
+ * progress on long, multi-request exports. `usePagamioTable` auto-wires this
89
+ * for server-paginated tables; a consumer may override (e.g. a dedicated
90
+ * export endpoint).
91
+ */
92
+ fetchAllData?: (params?: Record<string, string>, onProgress?: (fetched: number, total: number) => void) => Promise<T[]>;
86
93
  email?: {
87
94
  apiUrl: string;
88
95
  onSuccess?: (message: string) => void;
@@ -274,9 +274,10 @@ export const usePagamioTable = ({ queryKey, queryFn, enabled: queryEnabled = tru
274
274
  // Pages through the same `queryFn` at the backend's max `limit`, preserving
275
275
  // the user's current sort/filters/search so the export matches what they see.
276
276
  // Returns the full flattened dataset for the client-side export utils.
277
- const fetchAllPages = useCallback(async () => {
277
+ const fetchAllPages = useCallback(async (_params, onProgress) => {
278
278
  if (!isServerMode || !queryFn) {
279
279
  // Client-mode tables already hold the whole filtered/sorted set.
280
+ onProgress?.(processedData.length, processedData.length);
280
281
  return processedData;
281
282
  }
282
283
  const buildPageParams = (page) => buildQueryParams(queryParamConfig, { mode: paginationConfig.mode, page, size: MAX_EXPORT_PAGE_SIZE }, { mode: sortingConfig.mode, sortConfig }, { mode: filteringConfig.mode, searchMode, filters: appliedFilters });
@@ -288,6 +289,7 @@ export const usePagamioTable = ({ queryKey, queryFn, enabled: queryEnabled = tru
288
289
  const all = [...first.data];
289
290
  const total = first.total || serverTotal;
290
291
  const totalPages = Math.max(1, Math.ceil(total / MAX_EXPORT_PAGE_SIZE));
292
+ onProgress?.(all.length, total);
291
293
  // Pages are zero/one-based per the consumer's `queryParamConfig.transform`;
292
294
  // `buildQueryParams` already applies that transform, so we just feed it the
293
295
  // hook's internal zero-based index and let the config bump it.
@@ -297,6 +299,7 @@ export const usePagamioTable = ({ queryKey, queryFn, enabled: queryEnabled = tru
297
299
  if (pageData.length === 0)
298
300
  break; // defensive: stop if a page comes back empty
299
301
  all.push(...pageData);
302
+ onProgress?.(all.length, total);
300
303
  }
301
304
  return all;
302
305
  }, [
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.356",
4
+ "version": "0.8.357",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "provenance": false