@widergy/mobile-ui 2.1.0 → 3.4.1
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/FileDownloadManager/README.md +447 -0
- package/lib/components/FileDownloadManager/adapter.js +118 -0
- package/lib/components/FileDownloadManager/index.js +373 -0
- package/lib/components/FileDownloadManager/types.js +81 -0
- package/lib/components/FilePicker/index.js +10 -2
- package/lib/components/ImagePicker/index.js +8 -1
- package/lib/components/MultipleFilePicker/index.js +9 -2
- package/lib/components/UTTopbar/index.js +10 -12
- package/package.json +9 -2
- package/CHANGELOG.md +0 -2235
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
# FileDownloadManager
|
|
2
|
+
|
|
3
|
+
Módulo unificado y abstracto para manejar la descarga, almacenamiento, notificación y apertura de archivos en React Native con Expo.
|
|
4
|
+
|
|
5
|
+
## 🎯 Características
|
|
6
|
+
|
|
7
|
+
- ✅ **Generación de archivos**: PDF, Excel (XLSX), JSON
|
|
8
|
+
- ✅ **Almacenamiento seguro**: Storage Access Framework (Android) y documentDirectory (iOS)
|
|
9
|
+
- ✅ **Notificaciones**: Notificación cuando el archivo está listo con tap-to-open
|
|
10
|
+
- ✅ **Visualización nativa**: Soporte para PDF viewer nativo en la app
|
|
11
|
+
- ✅ **Compartir**: Integración con Expo Sharing para archivos sin visor nativo
|
|
12
|
+
- ✅ **Colisión de nombres**: Agrega timestamp automáticamente si el archivo ya existe
|
|
13
|
+
- ✅ **Traducciones personalizables**: Sistema flexible de i18n por parámetros
|
|
14
|
+
- ✅ **Multiplataforma**: iOS y Android
|
|
15
|
+
|
|
16
|
+
## 📦 Estructura
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
src/services/FileDownloadManager/
|
|
20
|
+
├── index.js # Módulo core (listo para @widergy/mobile-ui)
|
|
21
|
+
├── adapter.js # Adapter específico del proyecto
|
|
22
|
+
├── types.js # Tipos y constantes
|
|
23
|
+
└── README.md # Esta documentación
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 🚀 Uso Básico
|
|
27
|
+
|
|
28
|
+
### Excel (XLSX)
|
|
29
|
+
|
|
30
|
+
```javascript
|
|
31
|
+
import { downloadExcel } from 'services/FileDownloadManager/adapter';
|
|
32
|
+
import * as snackbarActions from 'actions/snackbar';
|
|
33
|
+
|
|
34
|
+
// En tu action o componente
|
|
35
|
+
const exportData = async (data, dispatch) => {
|
|
36
|
+
await downloadExcel(
|
|
37
|
+
data, // Array de objetos
|
|
38
|
+
'Reporte_Facturas', // Nombre base del archivo
|
|
39
|
+
dispatch, // Redux dispatch (opcional)
|
|
40
|
+
snackbarActions, // Snackbar actions del proyecto
|
|
41
|
+
{ // Traducciones personalizadas (opcional)
|
|
42
|
+
successDownload: 'Excel descargado exitosamente',
|
|
43
|
+
errorDownload: 'Error al descargar Excel'
|
|
44
|
+
},
|
|
45
|
+
{ // Opciones adicionales
|
|
46
|
+
successCallback: ({ fileUri, fileName }) => {
|
|
47
|
+
console.log(`Archivo guardado: ${fileName}`);
|
|
48
|
+
},
|
|
49
|
+
failureCallback: (error) => {
|
|
50
|
+
console.error('Error:', error);
|
|
51
|
+
},
|
|
52
|
+
preventAutoOpen: false, // Auto-abrir después de guardar
|
|
53
|
+
hideNotification: false // Mostrar notificación
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### PDF
|
|
60
|
+
|
|
61
|
+
```javascript
|
|
62
|
+
import { downloadPDF } from 'services/FileDownloadManager/adapter';
|
|
63
|
+
import * as snackbarActions from 'actions/snackbar';
|
|
64
|
+
|
|
65
|
+
const savePDF = async (base64Content, dispatch) => {
|
|
66
|
+
await downloadPDF(
|
|
67
|
+
base64Content, // PDF en base64
|
|
68
|
+
'Factura_12345', // Nombre base
|
|
69
|
+
dispatch, // Redux dispatch
|
|
70
|
+
snackbarActions, // Snackbar actions
|
|
71
|
+
{ // Traducciones (opcional)
|
|
72
|
+
downloadReadyTitle: 'PDF listo',
|
|
73
|
+
downloadReadyBody: '{fileName} está listo para ver'
|
|
74
|
+
},
|
|
75
|
+
{ // Opciones
|
|
76
|
+
preventAutoOpen: false // Se abrirá con visor nativo
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### JSON
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
import { downloadJSON } from 'services/FileDownloadManager/adapter';
|
|
86
|
+
import * as snackbarActions from 'actions/snackbar';
|
|
87
|
+
|
|
88
|
+
const exportConfig = async (configData, dispatch) => {
|
|
89
|
+
await downloadJSON(
|
|
90
|
+
configData, // Objeto o array
|
|
91
|
+
'configuracion', // Nombre base
|
|
92
|
+
dispatch, // Redux dispatch
|
|
93
|
+
snackbarActions, // Snackbar actions
|
|
94
|
+
{} // Traducciones (usa defaults si está vacío)
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## 🔧 API del Módulo Core
|
|
100
|
+
|
|
101
|
+
### `downloadFile(config)`
|
|
102
|
+
|
|
103
|
+
Función principal que maneja todo el flujo de descarga.
|
|
104
|
+
|
|
105
|
+
**Parámetros:**
|
|
106
|
+
```typescript
|
|
107
|
+
{
|
|
108
|
+
type: 'pdf' | 'xlsx' | 'json', // Tipo de archivo
|
|
109
|
+
fileName: string, // Nombre base (sin extensión)
|
|
110
|
+
data: any, // Datos del archivo
|
|
111
|
+
dispatch?: Function, // Redux dispatch (opcional)
|
|
112
|
+
translations?: { // Traducciones personalizadas (opcional)
|
|
113
|
+
downloadReadyTitle?: string, // Título notificación
|
|
114
|
+
downloadReadyBody?: string, // Cuerpo notificación (usa {fileName})
|
|
115
|
+
shareFileTitle?: string, // Título diálogo compartir (usa {fileName})
|
|
116
|
+
shareError?: string, // Error al compartir
|
|
117
|
+
successDownload?: string, // Mensaje éxito
|
|
118
|
+
errorDownload?: string // Mensaje error
|
|
119
|
+
},
|
|
120
|
+
options?: {
|
|
121
|
+
hideNotification?: boolean, // Omitir notificación
|
|
122
|
+
preventAutoOpen?: boolean, // No abrir automáticamente
|
|
123
|
+
successCallback?: Function, // Callback de éxito
|
|
124
|
+
failureCallback?: Function, // Callback de error
|
|
125
|
+
showSnackbar?: Function // Función para mostrar snackbar
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Retorna:**
|
|
131
|
+
```typescript
|
|
132
|
+
Promise<{
|
|
133
|
+
success: boolean,
|
|
134
|
+
fileUri: string,
|
|
135
|
+
fileName: string
|
|
136
|
+
}>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### `openFile(fileUri, fileName, fileType, translations?)`
|
|
140
|
+
|
|
141
|
+
Abre un archivo previamente guardado.
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
import { openFile, FILE_TYPES } from 'services/FileDownloadManager/adapter';
|
|
145
|
+
|
|
146
|
+
await openFile(
|
|
147
|
+
'file:///path/to/file.pdf',
|
|
148
|
+
'documento.pdf',
|
|
149
|
+
FILE_TYPES.PDF,
|
|
150
|
+
{ // Traducciones opcionales
|
|
151
|
+
shareFileTitle: 'Compartir {fileName}',
|
|
152
|
+
shareError: 'No se pudo compartir'
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## 🌐 Sistema de Traducciones
|
|
158
|
+
|
|
159
|
+
El módulo utiliza un sistema flexible de traducciones que permite personalizar todos los mensajes sin depender de librerías externas como i18next.
|
|
160
|
+
|
|
161
|
+
### Traducciones Disponibles
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
{
|
|
165
|
+
// Título de notificación cuando el archivo está listo
|
|
166
|
+
// Usado en: Notificación del sistema
|
|
167
|
+
downloadReadyTitle: string;
|
|
168
|
+
|
|
169
|
+
// Cuerpo de notificación con nombre del archivo
|
|
170
|
+
// Parámetros: {fileName} - se reemplaza automáticamente
|
|
171
|
+
// Usado en: Notificación del sistema
|
|
172
|
+
downloadReadyBody: string;
|
|
173
|
+
|
|
174
|
+
// Título del diálogo de compartir
|
|
175
|
+
// Parámetros: {fileName} - se reemplaza automáticamente
|
|
176
|
+
// Usado en: Diálogo nativo de compartir (iOS/Android)
|
|
177
|
+
shareFileTitle: string;
|
|
178
|
+
|
|
179
|
+
// Mensaje de error cuando falla compartir
|
|
180
|
+
// Usado en: Callback de error, snackbar
|
|
181
|
+
shareError: string;
|
|
182
|
+
|
|
183
|
+
// Mensaje de éxito para snackbar/toast
|
|
184
|
+
// Usado en: Snackbar después de descarga exitosa
|
|
185
|
+
successDownload: string;
|
|
186
|
+
|
|
187
|
+
// Mensaje de error para snackbar/toast
|
|
188
|
+
// Usado en: Snackbar cuando falla la descarga
|
|
189
|
+
errorDownload: string;
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Valores por Defecto (Español)
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
{
|
|
197
|
+
downloadReadyTitle: 'Archivo listo',
|
|
198
|
+
downloadReadyBody: '{fileName} está disponible',
|
|
199
|
+
shareFileTitle: 'Compartir {fileName}',
|
|
200
|
+
shareError: 'No se pudo compartir el archivo',
|
|
201
|
+
successDownload: 'Archivo descargado correctamente',
|
|
202
|
+
errorDownload: 'Error al descargar el archivo'
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Ejemplo: Traducciones en Inglés
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
import { downloadPDF } from 'services/FileDownloadManager/adapter';
|
|
210
|
+
|
|
211
|
+
const translations = {
|
|
212
|
+
downloadReadyTitle: 'File ready',
|
|
213
|
+
downloadReadyBody: '{fileName} is available',
|
|
214
|
+
shareFileTitle: 'Share {fileName}',
|
|
215
|
+
shareError: 'Could not share file',
|
|
216
|
+
successDownload: 'File downloaded successfully',
|
|
217
|
+
errorDownload: 'Error downloading file'
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
await downloadPDF(
|
|
221
|
+
pdfBase64,
|
|
222
|
+
'Invoice_2024',
|
|
223
|
+
dispatch,
|
|
224
|
+
snackbarActions,
|
|
225
|
+
translations // Pasa las traducciones personalizadas
|
|
226
|
+
);
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Integración con i18next
|
|
230
|
+
|
|
231
|
+
Si tu proyecto usa i18next, puedes crear un helper:
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
// utils/fileManagerTranslations.js
|
|
235
|
+
import i18next from 'i18next';
|
|
236
|
+
|
|
237
|
+
export const getFileManagerTranslations = () => ({
|
|
238
|
+
downloadReadyTitle: i18next.t('fileManager.downloadReadyTitle'),
|
|
239
|
+
downloadReadyBody: i18next.t('fileManager.downloadReadyBody'),
|
|
240
|
+
shareFileTitle: i18next.t('fileManager.shareFileTitle'),
|
|
241
|
+
shareError: i18next.t('fileManager.shareError'),
|
|
242
|
+
successDownload: i18next.t('fileManager.successDownload'),
|
|
243
|
+
errorDownload: i18next.t('fileManager.errorDownload')
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Uso
|
|
247
|
+
import { getFileManagerTranslations } from 'utils/fileManagerTranslations';
|
|
248
|
+
|
|
249
|
+
await downloadExcel(
|
|
250
|
+
data,
|
|
251
|
+
fileName,
|
|
252
|
+
dispatch,
|
|
253
|
+
snackbarActions,
|
|
254
|
+
getFileManagerTranslations()
|
|
255
|
+
);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Traducciones Parciales
|
|
259
|
+
|
|
260
|
+
No es necesario proveer todas las traducciones. Las que no se envíen usarán los valores por defecto:
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
// Solo personalizar algunos mensajes
|
|
264
|
+
await downloadJSON(
|
|
265
|
+
data,
|
|
266
|
+
'config',
|
|
267
|
+
dispatch,
|
|
268
|
+
snackbarActions,
|
|
269
|
+
{
|
|
270
|
+
successDownload: 'JSON exportado!',
|
|
271
|
+
errorDownload: 'Falló la exportación'
|
|
272
|
+
// Resto usa valores por defecto
|
|
273
|
+
}
|
|
274
|
+
);
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## 📱 Comportamiento por Tipo de Archivo
|
|
278
|
+
|
|
279
|
+
### PDF
|
|
280
|
+
- ✅ **Visor nativo**: Se abre dentro de la app
|
|
281
|
+
- 📁 **Ubicación**: `documentDirectory` (iOS/Android)
|
|
282
|
+
- 🔔 **Notificación**: Sí, con tap-to-open
|
|
283
|
+
- 🔄 **Fallback**: Si falla visor nativo → Expo Sharing
|
|
284
|
+
|
|
285
|
+
### XLSX (Excel)
|
|
286
|
+
- ❌ **Visor nativo**: No soportado
|
|
287
|
+
- 📁 **Ubicación**: `documentDirectory` (iOS/Android)
|
|
288
|
+
- 🔔 **Notificación**: Sí, con tap-to-share
|
|
289
|
+
- 🔄 **Comportamiento**: Siempre usa Expo Sharing para abrir
|
|
290
|
+
|
|
291
|
+
### JSON
|
|
292
|
+
- ❌ **Visor nativo**: No soportado
|
|
293
|
+
- 📁 **Ubicación**: `documentDirectory` (iOS/Android)
|
|
294
|
+
- 🔔 **Notificación**: Sí, con tap-to-share
|
|
295
|
+
- 🔄 **Comportamiento**: Siempre usa Expo Sharing para abrir
|
|
296
|
+
|
|
297
|
+
## 🔄 Migración desde Código Legacy
|
|
298
|
+
|
|
299
|
+
### Antes (xlsDownload.js)
|
|
300
|
+
```javascript
|
|
301
|
+
import { generateExcel } from 'utils/xlsDownload';
|
|
302
|
+
|
|
303
|
+
await generateExcel(data, 'Reporte', dispatch);
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Ahora (FileDownloadManager)
|
|
307
|
+
```javascript
|
|
308
|
+
import { downloadExcel } from 'services/FileDownloadManager/adapter';
|
|
309
|
+
|
|
310
|
+
await downloadExcel(data, 'Reporte', dispatch);
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Antes (DownloadFileService.js para PDF)
|
|
314
|
+
```javascript
|
|
315
|
+
import { download, downloadBase64, openDocument } from 'services/DownloadFileService';
|
|
316
|
+
|
|
317
|
+
const path = await download(base64Data, fileName, downloadBase64);
|
|
318
|
+
await openDocument(path);
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
### Ahora (FileDownloadManager)
|
|
322
|
+
```javascript
|
|
323
|
+
import { downloadPDF } from 'services/FileDownloadManager/adapter';
|
|
324
|
+
|
|
325
|
+
await downloadPDF(base64Data, fileName, dispatch);
|
|
326
|
+
// Auto-abre con visor nativo
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## 🛠️ Configuración Requerida
|
|
330
|
+
|
|
331
|
+
### App.tsx
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import * as Notifications from 'expo-notifications';
|
|
335
|
+
|
|
336
|
+
Notifications.setNotificationHandler({
|
|
337
|
+
handleNotification: async () => ({
|
|
338
|
+
shouldPlaySound: false,
|
|
339
|
+
shouldSetBadge: false,
|
|
340
|
+
shouldShowBanner: true,
|
|
341
|
+
shouldShowList: true
|
|
342
|
+
})
|
|
343
|
+
});
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### AndroidManifest.xml
|
|
347
|
+
|
|
348
|
+
```xml
|
|
349
|
+
<queries>
|
|
350
|
+
<!-- PDF -->
|
|
351
|
+
<intent>
|
|
352
|
+
<action android:name="android.intent.action.VIEW" />
|
|
353
|
+
<data android:mimeType="application/pdf" />
|
|
354
|
+
</intent>
|
|
355
|
+
|
|
356
|
+
<!-- Excel -->
|
|
357
|
+
<intent>
|
|
358
|
+
<action android:name="android.intent.action.VIEW" />
|
|
359
|
+
<data android:mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" />
|
|
360
|
+
</intent>
|
|
361
|
+
|
|
362
|
+
<!-- JSON -->
|
|
363
|
+
<intent>
|
|
364
|
+
<action android:name="android.intent.action.VIEW" />
|
|
365
|
+
<data android:mimeType="application/json" />
|
|
366
|
+
</intent>
|
|
367
|
+
</queries>
|
|
368
|
+
|
|
369
|
+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
## 📦 Dependencias
|
|
373
|
+
|
|
374
|
+
```json
|
|
375
|
+
{
|
|
376
|
+
"expo-file-system": "^19.0.17",
|
|
377
|
+
"expo-notifications": "^0.32.12",
|
|
378
|
+
"expo-sharing": "^14.0.7",
|
|
379
|
+
"react-native-file-viewer": "^2.1.5",
|
|
380
|
+
"xlsx": "^0.18.5",
|
|
381
|
+
"dayjs": "^1.11.x",
|
|
382
|
+
"base-64": "^1.0.0"
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## 🎨 Personalización para @widergy/mobile-ui
|
|
387
|
+
|
|
388
|
+
El módulo core (`index.js`) está diseñado para ser portable. Para migrarlo a `@widergy/mobile-ui`:
|
|
389
|
+
|
|
390
|
+
1. **Copiar `index.js` y `types.js`** al paquete
|
|
391
|
+
2. **Exportar** desde el index principal
|
|
392
|
+
3. **Documentar** que los consumidores deben pasar `showSnackbar` en options
|
|
393
|
+
4. **Ejemplo de uso** en el README del paquete:
|
|
394
|
+
|
|
395
|
+
```javascript
|
|
396
|
+
import { downloadFile, FILE_TYPES } from '@widergy/mobile-ui';
|
|
397
|
+
|
|
398
|
+
// El consumidor maneja sus propias notificaciones
|
|
399
|
+
const showSnackbar = (dispatch, type, error) => {
|
|
400
|
+
if (type === 'success') {
|
|
401
|
+
dispatch(showSuccess('Archivo descargado'));
|
|
402
|
+
} else {
|
|
403
|
+
dispatch(showError(error.message));
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
await downloadFile({
|
|
408
|
+
type: FILE_TYPES.PDF,
|
|
409
|
+
fileName: 'documento',
|
|
410
|
+
data: base64Content,
|
|
411
|
+
dispatch,
|
|
412
|
+
options: {
|
|
413
|
+
showSnackbar // Inyección de dependencia
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
## 🐛 Troubleshooting
|
|
419
|
+
|
|
420
|
+
### "Unable to open URL: file://..."
|
|
421
|
+
- **Causa**: iOS no puede abrir archivos file:// directamente
|
|
422
|
+
- **Solución**: El módulo automáticamente usa Expo Sharing como fallback
|
|
423
|
+
|
|
424
|
+
### "Expo FileSystem legacy no disponible"
|
|
425
|
+
- **Causa**: Falta dependencia o versión incorrecta
|
|
426
|
+
- **Solución**: `yarn add expo-file-system@^19.0.17`
|
|
427
|
+
|
|
428
|
+
### Notificación se muestra pero no abre archivo
|
|
429
|
+
- **Causa**: Listener de notificaciones no registrado
|
|
430
|
+
- **Solución**: Verificar que `App.tsx` tenga configurado el `NotificationHandler`
|
|
431
|
+
|
|
432
|
+
### PDF no se abre nativamente en Android
|
|
433
|
+
- **Causa**: Falta query en AndroidManifest
|
|
434
|
+
- **Solución**: Agregar los `<queries>` indicados arriba
|
|
435
|
+
|
|
436
|
+
## 📝 TODO / Roadmap
|
|
437
|
+
|
|
438
|
+
- [ ] Soporte para más formatos (DOC, CSV, etc.)
|
|
439
|
+
- [ ] Progress callbacks para archivos grandes
|
|
440
|
+
- [ ] Compresión opcional
|
|
441
|
+
- [ ] Cache de archivos descargados
|
|
442
|
+
- [ ] Tests unitarios
|
|
443
|
+
- [ ] Integración con analytics
|
|
444
|
+
|
|
445
|
+
## 📄 Licencia
|
|
446
|
+
|
|
447
|
+
Parte del proyecto UtilityGO - Widergy
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
// FileDownloadManager - Project adapter
|
|
2
|
+
// Adapts the generic FileDownloadManager to work with this project's specific Redux patterns
|
|
3
|
+
|
|
4
|
+
import { FILE_TYPES } from './types';
|
|
5
|
+
|
|
6
|
+
import { downloadFile as coreDownloadFile, openFile } from './index';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Show snackbar helper factory
|
|
10
|
+
* @param {Object} snackbarActions - Snackbar actions from the project
|
|
11
|
+
* @param {Object} translations - Translations object
|
|
12
|
+
*/
|
|
13
|
+
const createShowSnackbar =
|
|
14
|
+
(snackbarActions, translations) =>
|
|
15
|
+
(dispatch, type, error = null) => {
|
|
16
|
+
if (type === 'success') {
|
|
17
|
+
dispatch(snackbarActions.displayInfo(translations.successDownload));
|
|
18
|
+
} else if (type === 'error') {
|
|
19
|
+
dispatch(snackbarActions.displayError(error?.message || translations.errorDownload));
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Download Excel file from data array
|
|
25
|
+
* @param {Array} data - Array of objects to export
|
|
26
|
+
* @param {string} fileName - Base file name
|
|
27
|
+
* @param {Function} dispatch - Redux dispatch
|
|
28
|
+
* @param {Object} snackbarActions - Snackbar actions from the project
|
|
29
|
+
* @param {Object} translations - Custom translations (optional)
|
|
30
|
+
* @param {Object} options - Additional options
|
|
31
|
+
*/
|
|
32
|
+
export const downloadExcel = async (
|
|
33
|
+
data,
|
|
34
|
+
fileName,
|
|
35
|
+
dispatch,
|
|
36
|
+
snackbarActions,
|
|
37
|
+
translations = {},
|
|
38
|
+
options = {}
|
|
39
|
+
) =>
|
|
40
|
+
coreDownloadFile({
|
|
41
|
+
type: FILE_TYPES.XLS,
|
|
42
|
+
fileName,
|
|
43
|
+
data,
|
|
44
|
+
dispatch,
|
|
45
|
+
translations,
|
|
46
|
+
options: {
|
|
47
|
+
...options,
|
|
48
|
+
showSnackbar: createShowSnackbar(snackbarActions, translations)
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Download PDF from base64
|
|
54
|
+
* @param {string} base64 - PDF content in base64
|
|
55
|
+
* @param {string} fileName - Base file name
|
|
56
|
+
* @param {Function} dispatch - Redux dispatch
|
|
57
|
+
* @param {Object} snackbarActions - Snackbar actions from the project
|
|
58
|
+
* @param {Object} translations - Custom translations (optional)
|
|
59
|
+
* @param {Object} options - Additional options
|
|
60
|
+
*/
|
|
61
|
+
export const downloadPDF = async (
|
|
62
|
+
base64,
|
|
63
|
+
fileName,
|
|
64
|
+
dispatch,
|
|
65
|
+
snackbarActions,
|
|
66
|
+
translations = {},
|
|
67
|
+
options = {}
|
|
68
|
+
) =>
|
|
69
|
+
coreDownloadFile({
|
|
70
|
+
type: FILE_TYPES.PDF,
|
|
71
|
+
fileName,
|
|
72
|
+
data: base64,
|
|
73
|
+
dispatch,
|
|
74
|
+
translations,
|
|
75
|
+
options: {
|
|
76
|
+
...options,
|
|
77
|
+
showSnackbar: createShowSnackbar(snackbarActions, translations)
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Download JSON file from object
|
|
83
|
+
* @param {Object|Array} data - JSON data to export
|
|
84
|
+
* @param {string} fileName - Base file name
|
|
85
|
+
* @param {Function} dispatch - Redux dispatch
|
|
86
|
+
* @param {Object} snackbarActions - Snackbar actions from the project
|
|
87
|
+
* @param {Object} translations - Custom translations (optional)
|
|
88
|
+
* @param {Object} options - Additional options
|
|
89
|
+
*/
|
|
90
|
+
export const downloadJSON = async (
|
|
91
|
+
data,
|
|
92
|
+
fileName,
|
|
93
|
+
dispatch,
|
|
94
|
+
snackbarActions,
|
|
95
|
+
translations = {},
|
|
96
|
+
options = {}
|
|
97
|
+
) =>
|
|
98
|
+
coreDownloadFile({
|
|
99
|
+
type: FILE_TYPES.JSON,
|
|
100
|
+
fileName,
|
|
101
|
+
data,
|
|
102
|
+
dispatch,
|
|
103
|
+
translations,
|
|
104
|
+
options: {
|
|
105
|
+
...options,
|
|
106
|
+
showSnackbar: createShowSnackbar(snackbarActions, translations)
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
export { openFile, FILE_TYPES };
|
|
111
|
+
|
|
112
|
+
export default {
|
|
113
|
+
downloadExcel,
|
|
114
|
+
downloadPDF,
|
|
115
|
+
downloadJSON,
|
|
116
|
+
openFile,
|
|
117
|
+
FILE_TYPES
|
|
118
|
+
};
|