@zauru-sdk/components 2.0.202 → 2.0.204

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.
Files changed (33) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/Containers/ButtonSectionContainer.d.ts +0 -1
  3. package/dist/DynamicTable/DynamicPrintTable.d.ts +0 -1
  4. package/dist/Form/DynamicBaculoForm/index.d.ts +2 -0
  5. package/dist/Form/FileUpload/index.d.ts +2 -1
  6. package/dist/Form/TimePicker/index.d.ts +0 -1
  7. package/dist/Form/YesNo/index.d.ts +0 -1
  8. package/dist/Modal/ItemModal.d.ts +1 -1
  9. package/dist/esm/BlockUI/BlockUI.js +1 -1
  10. package/dist/esm/Buttons/Button.js +7 -8
  11. package/dist/esm/Containers/ButtonSectionContainer.js +2 -2
  12. package/dist/esm/Containers/OutletContainer.js +2 -2
  13. package/dist/esm/DynamicTable/DynamicPrintTable.js +13 -14
  14. package/dist/esm/DynamicTable/GenericDynamicTable.js +1 -1
  15. package/dist/esm/Form/DynamicBaculoForm/index.js +21 -57
  16. package/dist/esm/Form/FileUpload/index.js +197 -103
  17. package/dist/esm/Layouts/errorLayout/index.js +3 -5
  18. package/dist/esm/Modal/ItemModal.js +21 -10
  19. package/dist/esm/Skeletons/LoadingWindow.js +8 -0
  20. package/package.json +6 -6
  21. package/src/BlockUI/BlockUI.tsx +2 -4
  22. package/src/Buttons/Button.tsx +28 -32
  23. package/src/Containers/ButtonSectionContainer.tsx +2 -5
  24. package/src/Containers/OutletContainer.tsx +3 -3
  25. package/src/DynamicTable/DynamicPrintTable.tsx +1 -4
  26. package/src/DynamicTable/GenericDynamicTable.tsx +1 -1
  27. package/src/Form/DynamicBaculoForm/index.tsx +55 -66
  28. package/src/Form/FileUpload/index.tsx +365 -150
  29. package/src/Form/TimePicker/index.tsx +0 -1
  30. package/src/Form/YesNo/index.tsx +0 -1
  31. package/src/Layouts/errorLayout/index.tsx +4 -11
  32. package/src/Modal/ItemModal.tsx +44 -13
  33. package/src/Skeletons/LoadingWindow.tsx +11 -1
@@ -1,15 +1,11 @@
1
1
  import { DownloadIconSVG, IdeaIconSVG } from "@zauru-sdk/icons";
2
2
  import React, { useState, useEffect, useRef } from "react";
3
3
  import { useFormContext } from "react-hook-form";
4
- /*
5
- import imageCompression from "browser-image-compression";
6
- import type { Options } from "browser-image-compression";
7
- */
4
+ //import imageCompression, { Options } from "browser-image-compression";
8
5
 
9
6
  type Props = {
10
7
  id?: string;
11
8
  name: string;
12
- formName?: string;
13
9
  title?: string;
14
10
  helpText?: string;
15
11
  hint?: string;
@@ -23,6 +19,8 @@ type Props = {
23
19
  required?: boolean;
24
20
  optimizeImages?: boolean;
25
21
  zauruBaseURL?: string;
22
+ setProcessing?: (processing: boolean) => void;
23
+ signature?: boolean;
26
24
  };
27
25
 
28
26
  export const FileUploadField = (props: Props) => {
@@ -42,6 +40,8 @@ export const FileUploadField = (props: Props) => {
42
40
  required = false,
43
41
  optimizeImages = true,
44
42
  zauruBaseURL = "https://zauru.herokuapp.com",
43
+ setProcessing,
44
+ signature = false,
45
45
  } = props;
46
46
 
47
47
  const {
@@ -55,11 +55,77 @@ export const FileUploadField = (props: Props) => {
55
55
 
56
56
  const [showTooltip, setShowTooltip] = useState<boolean>(false);
57
57
  const [previewSrc, setPreviewSrc] = useState<string | null>(null);
58
- const [fileDeleted, setFileDeleted] = useState<boolean>(false);
59
58
  const [uploading, setUploading] = useState<boolean>(false);
60
59
  const [uploadProgress, setUploadProgress] = useState<number>(0);
60
+ const [openSignatureModal, setOpenSignatureModal] = useState<boolean>(false);
61
+ // Estados para la optimización de imagen
62
+ const [optimizing, setOptimizing] = useState<boolean>(false);
63
+ const [optimizationProgress, setOptimizationProgress] = useState<number>(0);
61
64
  const fileInputRef = useRef<HTMLInputElement>(null);
62
65
 
66
+ // For signature drawing mode
67
+ const canvasRef = useRef<HTMLCanvasElement>(null);
68
+ const isDrawing = useRef(false);
69
+ const lastX = useRef(0);
70
+ const lastY = useRef(0);
71
+
72
+ const handlePointerDown = (e: React.PointerEvent<HTMLCanvasElement>) => {
73
+ e.preventDefault();
74
+ const canvas = canvasRef.current;
75
+ if (!canvas) return;
76
+ const rect = canvas.getBoundingClientRect();
77
+ lastX.current = e.clientX - rect.left;
78
+ lastY.current = e.clientY - rect.top;
79
+ isDrawing.current = true;
80
+ };
81
+
82
+ const handlePointerMove = (e: React.PointerEvent<HTMLCanvasElement>) => {
83
+ e.preventDefault();
84
+ if (!isDrawing.current) return;
85
+ const canvas = canvasRef.current;
86
+ if (!canvas) return;
87
+ const ctx = canvas.getContext("2d");
88
+ if (!ctx) return;
89
+ const rect = canvas.getBoundingClientRect();
90
+ const currentX = e.clientX - rect.left;
91
+ const currentY = e.clientY - rect.top;
92
+ ctx.beginPath();
93
+ ctx.moveTo(lastX.current, lastY.current);
94
+ ctx.lineTo(currentX, currentY);
95
+ ctx.strokeStyle = "black";
96
+ ctx.lineWidth = 2;
97
+ ctx.stroke();
98
+ lastX.current = currentX;
99
+ lastY.current = currentY;
100
+ };
101
+
102
+ const handlePointerUp = (e?: React.PointerEvent<HTMLCanvasElement>) => {
103
+ e?.preventDefault();
104
+ isDrawing.current = false;
105
+ };
106
+
107
+ const clearCanvas = () => {
108
+ const canvas = canvasRef.current;
109
+ if (!canvas) return;
110
+ const ctx = canvas.getContext("2d");
111
+ if (!ctx) return;
112
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
113
+ };
114
+
115
+ const handleSignatureConfirm = () => {
116
+ const canvas = canvasRef.current;
117
+ if (!canvas) return;
118
+ canvas.toBlob(async (blob) => {
119
+ if (blob) {
120
+ const file = new File([blob], "signature.png", { type: "image/png" });
121
+ const objectUrl = URL.createObjectURL(file);
122
+ setPreviewSrc(objectUrl);
123
+ await processFile(file);
124
+ setOpenSignatureModal(false);
125
+ }
126
+ }, "image/png");
127
+ };
128
+
63
129
  useEffect(() => {
64
130
  return () => {
65
131
  if (previewSrc) {
@@ -79,117 +145,126 @@ export const FileUploadField = (props: Props) => {
79
145
  const textColor = isReadOnly ? "text-gray-700" : `text-${color}-900`;
80
146
  const borderColor = error ? "border-red-500" : `border-${color}-500`;
81
147
 
82
- /**
83
- * Función que se dispara cuando el usuario selecciona un archivo.
84
- * Si optimizeImages está activo y se trata de una imagen, la convierte a WebP
85
- * usando la librería browser-image-compression.
86
- */
87
- const handleInputChange = async (
88
- event: React.ChangeEvent<HTMLInputElement>
148
+ const processFile = async (
149
+ file: File,
150
+ event?: React.ChangeEvent<HTMLInputElement>
89
151
  ) => {
90
- if (event.target.files && event.target.files.length > 0) {
91
- let file = event.target.files[0];
92
-
93
- // Si se activa la optimización y es imagen, se convierte a WebP
94
- if (file && file.type.startsWith("image/") && optimizeImages) {
95
- try {
96
- /*
97
- const options: Options = {
98
- fileType: "image/webp", // Especificamos el formato WebP
99
- initialQuality: 0.7, // Calidad inicial (puedes ajustar este valor)
100
- maxSizeMB: 1, // Tamaño máximo (opcional)
101
- maxWidthOrHeight: 1920, // Dimensión máxima (opcional)
102
- useWebWorker: true,
103
- };
104
- // Después de la compresión, renombramos el archivo:
105
- const compressedFile = await imageCompression(file, options);
106
- const newFile = new File(
107
- [compressedFile],
108
- file.name.replace(/\.[^.]+$/, ".webp"),
109
- {
110
- type: file.type,
111
- }
112
- );
113
- file = newFile;
114
- */
115
- console.log("Archivo convertido:", file.name, file.type);
116
- const objectUrl = URL.createObjectURL(file);
117
- setPreviewSrc(objectUrl);
118
- } catch (error) {
119
- console.error("Error al convertir la imagen a WebP:", error);
120
- const objectUrl = URL.createObjectURL(file);
121
- setPreviewSrc(objectUrl);
122
- }
123
- } else if (file && file.type.startsWith("image/")) {
152
+ let processedFile = file;
153
+
154
+ /*
155
+ if (file && file.type.startsWith("image/") && optimizeImages) {
156
+ try {
157
+ setOptimizing(true);
158
+ setOptimizationProgress(0);
159
+ const options: Options = {
160
+ fileType: "image/webp",
161
+ initialQuality: 0.7,
162
+ maxSizeMB: 1,
163
+ maxWidthOrHeight: 1920,
164
+ useWebWorker: true,
165
+ onProgress: (progress: number) => {
166
+ setOptimizationProgress(progress);
167
+ },
168
+ };
169
+ const compressedFile = await imageCompression(file, options);
170
+ setOptimizing(false);
171
+ processedFile = new File(
172
+ [compressedFile],
173
+ file.name.replace(/\.[^.]+$/, ".webp"),
174
+ { type: "image/webp" }
175
+ );
176
+ const objectUrl = URL.createObjectURL(processedFile);
177
+ setPreviewSrc(objectUrl);
178
+ } catch (error) {
179
+ console.error("Error al convertir la imagen a WebP:", error);
180
+ setOptimizing(false);
124
181
  const objectUrl = URL.createObjectURL(file);
125
182
  setPreviewSrc(objectUrl);
126
- } else {
127
- setPreviewSrc(null);
128
183
  }
184
+ } else
185
+ */
186
+
187
+ if (file && file.type.startsWith("image/")) {
188
+ const objectUrl = URL.createObjectURL(file);
189
+ setPreviewSrc(objectUrl);
190
+ } else {
191
+ setPreviewSrc(null);
192
+ }
129
193
 
130
- // Actualizamos el input para que contenga el archivo convertido
194
+ if (event && event.target) {
131
195
  const dataTransfer = new DataTransfer();
132
- dataTransfer.items.add(file);
196
+ dataTransfer.items.add(processedFile);
133
197
  event.target.files = dataTransfer.files;
198
+ }
134
199
 
135
- // Importamos dinámicamente DirectUpload solo en el cliente
136
- import("@rails/activestorage")
137
- .then(({ DirectUpload }) => {
138
- const uploadUrl = `${zauruBaseURL}/api/direct_uploads`;
139
-
140
- setUploading(true);
141
- setUploadProgress(0);
142
-
143
- const directUpload = new DirectUpload(file, uploadUrl, {
144
- directUploadWillStoreFileWithXHR: (xhr: XMLHttpRequest) => {
145
- xhr.upload.addEventListener("progress", (event) => {
146
- if (event.lengthComputable) {
147
- const progress = Math.round(
148
- (event.loaded / event.total) * 100
149
- );
150
- setUploadProgress(progress);
151
- }
152
- });
153
- },
154
- });
155
-
156
- directUpload.create((error, blob) => {
157
- setUploading(false);
158
- if (error) {
159
- console.error("Error al subir el archivo:", error);
160
- } else {
161
- setValue(name, blob.signed_id);
162
- setValue(`${name}_file_type`, blob.content_type);
163
-
164
- // Input hidden para el signed_id
165
- const hiddenField = document.createElement("input");
166
- hiddenField.setAttribute("type", "hidden");
167
- hiddenField.setAttribute("value", blob.signed_id);
168
- hiddenField.setAttribute("name", name);
169
- // Input hidden para el content_type
170
- const typeHiddenField = document.createElement("input");
171
- typeHiddenField.setAttribute("type", "hidden");
172
- typeHiddenField.setAttribute("value", blob.content_type);
173
- typeHiddenField.setAttribute("name", `${name}_file_type`);
174
-
175
- const formElement = document.querySelector("form");
176
- if (formElement) {
177
- formElement.appendChild(hiddenField);
178
- formElement.appendChild(typeHiddenField);
179
- }
200
+ // Proceso de subida mediante DirectUpload
201
+ import("@rails/activestorage")
202
+ .then(({ DirectUpload }) => {
203
+ const uploadUrl = `${zauruBaseURL}/api/direct_uploads`;
204
+
205
+ setProcessing && setProcessing(true);
206
+ setUploading(true);
207
+ setUploadProgress(0);
180
208
 
181
- // Removemos el atributo "name" del input file para evitar enviar el archivo
182
- if (fileInputRef.current) {
183
- fileInputRef.current.removeAttribute("name");
209
+ const directUpload = new DirectUpload(processedFile, uploadUrl, {
210
+ directUploadWillStoreFileWithXHR: (xhr: XMLHttpRequest) => {
211
+ xhr.upload.addEventListener("progress", (event) => {
212
+ if (event.lengthComputable) {
213
+ const progress = Math.round((event.loaded / event.total) * 100);
214
+ setUploadProgress(progress);
184
215
  }
216
+ });
217
+ },
218
+ });
219
+
220
+ directUpload.create((error, blob) => {
221
+ setUploading(false);
222
+ setProcessing && setProcessing(false);
223
+ if (error) {
224
+ console.error("Error al subir el archivo:", error);
225
+ } else {
226
+ setValue(name, blob.signed_id);
227
+ setValue(`${name}_file_type`, blob.content_type);
228
+
229
+ const hiddenField = document.createElement("input");
230
+ hiddenField.setAttribute("type", "hidden");
231
+ hiddenField.setAttribute("value", blob.signed_id);
232
+ hiddenField.setAttribute("name", name);
233
+ const typeHiddenField = document.createElement("input");
234
+ typeHiddenField.setAttribute("type", "hidden");
235
+ typeHiddenField.setAttribute("value", blob.content_type);
236
+ typeHiddenField.setAttribute("name", `${name}_file_type`);
237
+
238
+ const formElement = document.querySelector("form");
239
+ if (formElement) {
240
+ formElement.appendChild(hiddenField);
241
+ formElement.appendChild(typeHiddenField);
185
242
  }
186
- });
187
- })
188
- .catch((err) => console.error("Error al cargar DirectUpload:", err));
189
- }
190
243
 
244
+ if (fileInputRef.current) {
245
+ fileInputRef.current.removeAttribute("name");
246
+ }
247
+ }
248
+ });
249
+ })
250
+ .catch((err) => {
251
+ setProcessing && setProcessing(false);
252
+ console.error("Error al cargar DirectUpload:", err);
253
+ });
254
+ };
255
+
256
+ /**
257
+ * Función que se dispara cuando el usuario selecciona un archivo.
258
+ * Si optimizeImages está activo y se trata de una imagen, la convierte a WebP
259
+ * usando la librería browser-image-compression.
260
+ */
261
+ const handleInputChange = async (
262
+ event: React.ChangeEvent<HTMLInputElement>
263
+ ) => {
264
+ if (event.target.files && event.target.files.length > 0) {
265
+ await processFile(event.target.files[0], event);
266
+ }
191
267
  onChange && onChange(event);
192
- setFileDeleted(false);
193
268
  };
194
269
 
195
270
  /**
@@ -198,7 +273,6 @@ export const FileUploadField = (props: Props) => {
198
273
  */
199
274
  const deleteFile = () => {
200
275
  setPreviewSrc(null);
201
- setFileDeleted(true);
202
276
  if (fileInputRef.current) {
203
277
  fileInputRef.current.value = "";
204
278
  }
@@ -255,6 +329,117 @@ export const FileUploadField = (props: Props) => {
255
329
  * - Si defaultValue es string, se muestra el preview (descarga/imagen).
256
330
  * - Si no hay defaultValue (o es File), se muestra "Sin archivo".
257
331
  */
332
+ if (signature) {
333
+ if (readOnly) {
334
+ return (
335
+ <div className={`col-span-6 sm:col-span-3 ${className}`}>
336
+ {title && (
337
+ <label
338
+ htmlFor={name}
339
+ className="block mb-1 text-sm font-medium text-gray-700"
340
+ >
341
+ {title}
342
+ </label>
343
+ )}
344
+ {typeof defaultValue === "string" && defaultValue ? (
345
+ renderPreview(defaultValue)
346
+ ) : (
347
+ <div className="text-sm italic text-gray-400">
348
+ No hay firma disponible
349
+ </div>
350
+ )}
351
+ </div>
352
+ );
353
+ } else {
354
+ return (
355
+ <div className={`col-span-6 sm:col-span-3 ${className}`}>
356
+ {title && (
357
+ <label
358
+ htmlFor={name}
359
+ className={`block mb-1 text-sm font-medium text-${color}-700`}
360
+ >
361
+ {title}
362
+ {required && <span className="text-red-500 ml-1">*</span>}
363
+ </label>
364
+ )}
365
+ {previewSrc ? (
366
+ <div>
367
+ {renderPreview(previewSrc)}
368
+ <button
369
+ type="button"
370
+ onClick={() => {
371
+ setPreviewSrc(null);
372
+ }}
373
+ className="ml-2 text-red-600 underline text-sm"
374
+ >
375
+ Eliminar firma
376
+ </button>
377
+ </div>
378
+ ) : (
379
+ <div>
380
+ <button
381
+ type="button"
382
+ onClick={() => setOpenSignatureModal(true)}
383
+ className="px-4 py-2 bg-blue-600 text-white rounded"
384
+ >
385
+ Firmar
386
+ </button>
387
+ </div>
388
+ )}
389
+ {openSignatureModal && (
390
+ <div className="fixed inset-0 z-50 flex flex-col bg-white">
391
+ <div className="flex-grow flex items-center justify-center">
392
+ <canvas
393
+ ref={canvasRef}
394
+ width={400}
395
+ height={200}
396
+ style={{
397
+ border: "1px solid #ccc",
398
+ backgroundColor: "transparent",
399
+ touchAction: "none",
400
+ }}
401
+ onPointerDown={handlePointerDown}
402
+ onPointerMove={handlePointerMove}
403
+ onPointerUp={handlePointerUp}
404
+ onPointerLeave={handlePointerUp}
405
+ ></canvas>
406
+ </div>
407
+ <div className="p-4 flex justify-center space-x-4">
408
+ <button
409
+ type="button"
410
+ onClick={clearCanvas}
411
+ className="text-blue-600 underline text-sm"
412
+ >
413
+ Reset
414
+ </button>
415
+ <button
416
+ type="button"
417
+ onClick={handleSignatureConfirm}
418
+ className="text-blue-600 underline text-sm"
419
+ >
420
+ Ok
421
+ </button>
422
+ <button
423
+ type="button"
424
+ onClick={() => setOpenSignatureModal(false)}
425
+ className="text-gray-600 underline text-sm"
426
+ >
427
+ Cancelar
428
+ </button>
429
+ </div>
430
+ </div>
431
+ )}
432
+ </div>
433
+ );
434
+ }
435
+ }
436
+
437
+ /**
438
+ * 2) Modo editable (readOnly = false):
439
+ * - Se muestra siempre el recuadro de vista previa, ya sea con la imagen cargada o con un placeholder.
440
+ * - Si se ha seleccionado una imagen o existe defaultValue y no se ha eliminado,
441
+ * se muestra la imagen y un botón para eliminar el archivo.
442
+ */
258
443
  if (readOnly) {
259
444
  return (
260
445
  <div className={`col-span-6 sm:col-span-3 ${className}`}>
@@ -277,12 +462,6 @@ export const FileUploadField = (props: Props) => {
277
462
  );
278
463
  }
279
464
 
280
- /**
281
- * 2) Modo editable (readOnly = false):
282
- * - Si se ha seleccionado una imagen o existe defaultValue y no se ha eliminado,
283
- * se muestra la vista previa generada junto con un botón para eliminar el archivo.
284
- * - Si se elimina el archivo o no hay ninguno, se muestra el input para cargar uno.
285
- */
286
465
  return (
287
466
  <div className={`col-span-6 sm:col-span-3 ${className}`}>
288
467
  {title && (
@@ -295,33 +474,49 @@ export const FileUploadField = (props: Props) => {
295
474
  </label>
296
475
  )}
297
476
 
298
- {!fileDeleted &&
299
- (previewSrc ? (
300
- <div className="mb-2 flex items-center">
301
- {renderPreview(previewSrc)}
302
- <button
303
- type="button"
304
- onClick={deleteFile}
305
- className="ml-2 text-red-600 underline text-sm"
306
- >
307
- Eliminar archivo
308
- </button>
309
- </div>
310
- ) : (
311
- typeof defaultValue === "string" &&
312
- defaultValue && (
313
- <div className="mb-2 flex items-center">
314
- {renderPreview(defaultValue)}
315
- <button
316
- type="button"
317
- onClick={deleteFile}
318
- className="ml-2 text-red-600 underline text-sm"
319
- >
320
- Eliminar archivo
321
- </button>
322
- </div>
323
- )
324
- ))}
477
+ <div className="mb-2 flex items-center">
478
+ <div
479
+ role="button"
480
+ tabIndex={0}
481
+ onClick={() => {
482
+ const srcToOpen =
483
+ previewSrc || (typeof defaultValue === "string" && defaultValue);
484
+ if (srcToOpen) window.open(srcToOpen, "_blank");
485
+ }}
486
+ onKeyDown={(event) => {
487
+ const srcToOpen =
488
+ previewSrc || (typeof defaultValue === "string" && defaultValue);
489
+ if (event.key === "Enter" && srcToOpen)
490
+ window.open(srcToOpen, "_blank");
491
+ }}
492
+ className="cursor-pointer border border-gray-300 h-48 w-48 flex items-center justify-center"
493
+ >
494
+ {previewSrc || (typeof defaultValue === "string" && defaultValue) ? (
495
+ <img
496
+ src={
497
+ previewSrc ??
498
+ (typeof defaultValue === "string" && defaultValue
499
+ ? defaultValue
500
+ : undefined)
501
+ }
502
+ alt={name}
503
+ className="h-48 w-48"
504
+ style={{ objectFit: "contain" }}
505
+ />
506
+ ) : (
507
+ <span className="text-gray-400">No image</span>
508
+ )}
509
+ </div>
510
+ {(previewSrc || (typeof defaultValue === "string" && defaultValue)) && (
511
+ <button
512
+ type="button"
513
+ onClick={deleteFile}
514
+ className="ml-2 text-red-600 underline text-sm"
515
+ >
516
+ Eliminar archivo
517
+ </button>
518
+ )}
519
+ </div>
325
520
 
326
521
  <div className="flex relative items-center">
327
522
  <input
@@ -353,18 +548,38 @@ export const FileUploadField = (props: Props) => {
353
548
  )}
354
549
  </div>
355
550
 
356
- {uploading && (
357
- <div className="mt-2">
358
- <progress
359
- value={uploadProgress}
360
- max="100"
361
- className="w-full"
362
- ></progress>
363
- <p className="text-sm text-blue-600 mt-1">
364
- Subiendo archivo: {uploadProgress}%
365
- </p>
366
- </div>
367
- )}
551
+ <div className="mt-2 min-h-[60px] flex items-center justify-center border border-dashed border-gray-200 rounded">
552
+ {optimizing || uploading ? (
553
+ <>
554
+ {optimizing && (
555
+ <div className="w-full">
556
+ <progress
557
+ value={optimizationProgress}
558
+ max="100"
559
+ className="w-full"
560
+ ></progress>
561
+ <p className="text-sm text-blue-600 mt-1 text-center">
562
+ Optimizando imagen a webp: {optimizationProgress}%
563
+ </p>
564
+ </div>
565
+ )}
566
+ {uploading && (
567
+ <div className="w-full">
568
+ <progress
569
+ value={uploadProgress}
570
+ max="100"
571
+ className="w-full"
572
+ ></progress>
573
+ <p className="text-sm text-blue-600 mt-1 text-center">
574
+ Subiendo archivo: {uploadProgress}%
575
+ </p>
576
+ </div>
577
+ )}
578
+ </>
579
+ ) : (
580
+ <span className="text-sm text-gray-500">Información de progreso</span>
581
+ )}
582
+ </div>
368
583
 
369
584
  {error && (
370
585
  <p className="mt-2 text-sm text-red-600">
@@ -5,7 +5,6 @@ import { useFormContext } from "react-hook-form";
5
5
  type Props = {
6
6
  id?: string;
7
7
  name: string;
8
- formName?: string;
9
8
  title?: string;
10
9
  hint?: string;
11
10
  helpText?: string;
@@ -4,7 +4,6 @@ import { useFormContext } from "react-hook-form";
4
4
  type Props = {
5
5
  id?: string;
6
6
  name: string;
7
- formName?: string;
8
7
  title?: string;
9
8
  defaultValue?: boolean;
10
9
  helpText?: string;
@@ -28,21 +28,14 @@ export const ErrorLayout = ({
28
28
  <div className="w-full max-w-2xl flex flex-col items-center">
29
29
  <p className="text-2xl text-gray-300 mb-8 text-center">
30
30
  {isRouteErrorResponse(error)
31
- ? `Error en request: ${error.status}: ${error.statusText} - PATH: ${error.data.path} - MESSAGE: ${error.data.message}`
31
+ ? `Error ${error.status}: ${error.statusText}`
32
32
  : error instanceof Error
33
- ? `Error: ${error.message} - NAME: ${
34
- error.name
35
- } - STACK: ${error.stack?.slice(0, 100)} - CAUSE: ${
36
- error.cause
37
- }`
38
- : `Ha ocurrido un error inesperado: ${error}`}
33
+ ? error.message
34
+ : "Ha ocurrido un error inesperado"}
39
35
  </p>
40
36
  {from && (
41
37
  <p className="text-lg text-gray-400 mb-4 text-center">
42
- {isRootLevel
43
- ? "(*) Error lanzado desde: "
44
- : "Error lanzado desde: "}
45
- {from}
38
+ Error lanzado desde: {from}
46
39
  </p>
47
40
  )}
48
41
  {parentError && (