@grafosoft/excel-validator 1.0.4 → 1.0.6

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.
@@ -1,2 +1,2 @@
1
1
  import { ExcelFileProps } from "../types/excelTypes";
2
- export declare const ExcelFile: ({ initData, fileContent, matrix, error, onFileSelected, onReset, validationErrors, onSelectError, hasBalanceDifference, }: ExcelFileProps) => import("react").JSX.Element;
2
+ export declare const ExcelFile: ({ initData, fileContent, matrix, error, onFileSelected, onReset, validationErrors, onSelectError, hasBalanceDifference, onApplyStringEmptyFilter, onDownloadFilteredExcel, isStringEmptyFilterApplied, hasStringEmptyDuplicateErrors, }: ExcelFileProps) => import("react").JSX.Element;
@@ -6,7 +6,7 @@ const react_1 = require("@heroui/react");
6
6
  const react_2 = require("react");
7
7
  const tb_1 = require("react-icons/tb");
8
8
  const ExcelValidator_1 = require("./ExcelValidator");
9
- const ExcelFile = ({ initData, fileContent, matrix, error, onFileSelected, onReset, validationErrors, onSelectError, hasBalanceDifference = false, }) => {
9
+ const ExcelFile = ({ initData, fileContent, matrix, error, onFileSelected, onReset, validationErrors, onSelectError, hasBalanceDifference = false, onApplyStringEmptyFilter, onDownloadFilteredExcel, isStringEmptyFilterApplied, hasStringEmptyDuplicateErrors, }) => {
10
10
  var _a;
11
11
  const [isVisible, setIsVisible] = (0, react_2.useState)(false);
12
12
  const inputRef = (0, react_2.useRef)(null);
@@ -28,7 +28,9 @@ const ExcelFile = ({ initData, fileContent, matrix, error, onFileSelected, onRes
28
28
  }
29
29
  return (bytes / KB).toFixed(2) + " KB";
30
30
  };
31
- return ((0, jsx_runtime_1.jsxs)("section", { className: "h-full bg-content1 p-4 border-r border-default-200", children: [(0, jsx_runtime_1.jsxs)("h2", { className: "text-xl font-semibold text-default-700", children: ["Importa ", initData.title] }), error ? ((0, jsx_runtime_1.jsx)(react_1.Alert, { color: "danger", title: error, className: "mt-3", radius: "sm", hideIconWrapper: true })) : isVisible ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_1.Alert, { radius: "sm", hideIconWrapper: true, hideIcon: true, isVisible: isVisible, className: "mt-4", variant: "bordered", onClose: handleReset, children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-default-700", children: [(0, jsx_runtime_1.jsx)(tb_1.TbFile, { size: 28 }), " ", (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm", children: fileContent === null || fileContent === void 0 ? void 0 : fileContent.name }), (0, jsx_runtime_1.jsx)("small", { className: "text-default-500", children: bytesFormat((_a = fileContent === null || fileContent === void 0 ? void 0 : fileContent.size) !== null && _a !== void 0 ? _a : 0) })] })] }) }), (0, jsx_runtime_1.jsx)(ExcelValidator_1.ExcelValidator, { initData: initData, fileContent: fileContent, matrix: matrix, validationErrors: validationErrors, onSelectError: onSelectError, hasBalanceDifference: hasBalanceDifference })] })) : ((0, jsx_runtime_1.jsx)("label", { className: "mt-4 flex cursor-pointer items-center justify-center rounded-lg border border-dashed border-default-300 px-4 py-8 text-sm font-medium text-default-600 transition hover:border-primary hover:text-primary", htmlFor: "excel-upload", children: (0, jsx_runtime_1.jsxs)("div", { className: "text-center flex flex-col items-center gap-2", children: [(0, jsx_runtime_1.jsx)(tb_1.TbUpload, { size: 28 }), (0, jsx_runtime_1.jsx)("p", { className: "font-semibold text-lg", children: "Seleccionar plantilla" }), (0, jsx_runtime_1.jsx)("small", { className: "text-default-500", children: "Adjunta un archivo .xlsx o .xls para validar y previsualizar." })] }) })), (0, jsx_runtime_1.jsx)("input", { id: "excel-upload", ref: inputRef, className: "hidden", type: "file", accept: ".xlsx,.xls", onChange: (event) => {
31
+ return ((0, jsx_runtime_1.jsxs)("section", { className: "h-full bg-content1 p-4 border-r border-default-200", children: [(0, jsx_runtime_1.jsxs)("h2", { className: "text-xl font-semibold text-default-700", children: ["Importa ", initData.title] }), error ? ((0, jsx_runtime_1.jsx)(react_1.Alert, { color: "danger", title: error, className: "mt-3", radius: "sm", hideIconWrapper: true })) : isVisible ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(react_1.Alert, { radius: "sm", hideIconWrapper: true, hideIcon: true, isVisible: isVisible, className: "mt-4", variant: "bordered", onClose: handleReset, children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2 text-default-700", children: [(0, jsx_runtime_1.jsx)(tb_1.TbFile, { size: 28 }), " ", (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm", children: fileContent === null || fileContent === void 0 ? void 0 : fileContent.name }), (0, jsx_runtime_1.jsx)("small", { className: "text-default-500", children: bytesFormat((_a = fileContent === null || fileContent === void 0 ? void 0 : fileContent.size) !== null && _a !== void 0 ? _a : 0) })] })] }) }), initData.type === "accounts" && ((0, jsx_runtime_1.jsxs)("div", { className: "mt-4 space-y-2", children: [(0, jsx_runtime_1.jsx)(react_1.Button, { className: "w-full border-1", color: "warning", variant: "bordered", radius: "sm", startContent: (0, jsx_runtime_1.jsx)(tb_1.TbFilter, { size: 18 }), onPress: onApplyStringEmptyFilter, isDisabled: !hasStringEmptyDuplicateErrors || isStringEmptyFilterApplied, children: isStringEmptyFilterApplied
32
+ ? "Filtro aplicado"
33
+ : "Filtrar cuentas ya registradas" }), (0, jsx_runtime_1.jsx)(react_1.Button, { className: "w-full border-1", color: "success", variant: "bordered", radius: "sm", startContent: (0, jsx_runtime_1.jsx)(tb_1.TbDownload, { size: 18 }), onPress: onDownloadFilteredExcel, isDisabled: !isStringEmptyFilterApplied || !hasStringEmptyDuplicateErrors, children: "Descargar Nuevo Excel" })] })), (0, jsx_runtime_1.jsx)(ExcelValidator_1.ExcelValidator, { initData: initData, fileContent: fileContent, matrix: matrix, validationErrors: validationErrors, onSelectError: onSelectError, hasBalanceDifference: hasBalanceDifference })] })) : ((0, jsx_runtime_1.jsx)("label", { className: "mt-4 flex cursor-pointer items-center justify-center rounded-lg border border-dashed border-default-300 px-4 py-8 text-sm font-medium text-default-600 transition hover:border-primary hover:text-primary", htmlFor: "excel-upload", children: (0, jsx_runtime_1.jsxs)("div", { className: "text-center flex flex-col items-center gap-2", children: [(0, jsx_runtime_1.jsx)(tb_1.TbUpload, { size: 28 }), (0, jsx_runtime_1.jsx)("p", { className: "font-semibold text-lg", children: "Seleccionar plantilla" }), (0, jsx_runtime_1.jsx)("small", { className: "text-default-500", children: "Adjunta un archivo .xlsx o .xls para validar y previsualizar." })] }) })), (0, jsx_runtime_1.jsx)("input", { id: "excel-upload", ref: inputRef, className: "hidden", type: "file", accept: ".xlsx,.xls", onChange: (event) => {
32
34
  void onFileSelected(event);
33
35
  setIsVisible(true);
34
36
  } })] }));
@@ -84,6 +84,7 @@ function ExcelLayout({ initData, jsonValidator, isBalances = false, }) {
84
84
  const [error, setError] = (0, react_1.useState)(null);
85
85
  const [currentPage, setCurrentPage] = (0, react_1.useState)(1);
86
86
  const [focusTarget, setFocusTarget] = (0, react_1.useState)(null);
87
+ const [isStringEmptyFilterApplied, setIsStringEmptyFilterApplied] = (0, react_1.useState)(false);
87
88
  const [fetchCatalogsByUrl, setFetchCatalogsByUrl] = (0, react_1.useState)({});
88
89
  const [stringEmptyCatalogsByUrl, setStringEmptyCatalogsByUrl] = (0, react_1.useState)({});
89
90
  (0, react_1.useEffect)(() => {
@@ -403,6 +404,9 @@ function ExcelLayout({ initData, jsonValidator, isBalances = false, }) {
403
404
  message: alreadyExists
404
405
  ? `El valor '${trimmedValue}' ya existe`
405
406
  : "",
407
+ errorCode: alreadyExists
408
+ ? "string-empty-already-exists"
409
+ : undefined,
406
410
  };
407
411
  }
408
412
  return { valid: true, message: "" };
@@ -418,6 +422,7 @@ function ExcelLayout({ initData, jsonValidator, isBalances = false, }) {
418
422
  message: result.message,
419
423
  value,
420
424
  filteredRowIndex,
425
+ errorCode: result.errorCode,
421
426
  });
422
427
  }
423
428
  });
@@ -429,6 +434,53 @@ function ExcelLayout({ initData, jsonValidator, isBalances = false, }) {
429
434
  fetchCatalogsByUrl,
430
435
  stringEmptyCatalogsByUrl,
431
436
  ]);
437
+ const stringEmptyDuplicateRowIndexes = (0, react_1.useMemo)(() => Array.from(new Set(validationErrors
438
+ .filter((validationError) => validationError.errorCode === "string-empty-already-exists")
439
+ .map((validationError) => validationError.filteredRowIndex))), [validationErrors]);
440
+ const hasStringEmptyDuplicateErrors = stringEmptyDuplicateRowIndexes.length > 0;
441
+ const validationErrorsForPanel = (0, react_1.useMemo)(() => {
442
+ if (!isStringEmptyFilterApplied) {
443
+ return validationErrors;
444
+ }
445
+ const hiddenIndexes = new Set(stringEmptyDuplicateRowIndexes);
446
+ return validationErrors.filter((validationError) => !hiddenIndexes.has(validationError.filteredRowIndex));
447
+ }, [
448
+ isStringEmptyFilterApplied,
449
+ stringEmptyDuplicateRowIndexes,
450
+ validationErrors,
451
+ ]);
452
+ const handleApplyStringEmptyFilter = () => {
453
+ if (!hasStringEmptyDuplicateErrors) {
454
+ return;
455
+ }
456
+ setIsStringEmptyFilterApplied(true);
457
+ setCurrentPage(1);
458
+ setFocusTarget(null);
459
+ };
460
+ const handleDownloadFilteredExcel = () => {
461
+ var _a;
462
+ if (!hasStringEmptyDuplicateErrors) {
463
+ return;
464
+ }
465
+ const headers = (_a = matrix[0]) !== null && _a !== void 0 ? _a : [];
466
+ const dataRows = matrix
467
+ .slice(1)
468
+ .filter((row) => { var _a, _b; return ((_b = (_a = row[0]) === null || _a === void 0 ? void 0 : _a.toString().trim()) !== null && _b !== void 0 ? _b : "") !== ""; });
469
+ const excludedIndexes = new Set(stringEmptyDuplicateRowIndexes);
470
+ const filteredRows = dataRows.filter((_row, rowIndex) => !excludedIndexes.has(rowIndex));
471
+ const workbook = XLSX.utils.book_new();
472
+ const worksheet = XLSX.utils.aoa_to_sheet([headers, ...filteredRows]);
473
+ const totalColumns = Math.max(headers.length, ...filteredRows.map((row) => row.length));
474
+ worksheet["!cols"] = Array.from({ length: totalColumns }, (_, colIndex) => {
475
+ var _a;
476
+ const longestValue = Math.max(String((_a = headers[colIndex]) !== null && _a !== void 0 ? _a : "").length, ...filteredRows.map((row) => { var _a; return String((_a = row[colIndex]) !== null && _a !== void 0 ? _a : "").length; }));
477
+ return {
478
+ wch: Math.min(Math.max(longestValue + 2, 12), 80),
479
+ };
480
+ });
481
+ XLSX.utils.book_append_sheet(workbook, worksheet, "Filtrado");
482
+ XLSX.writeFile(workbook, `${initData.title}-filtrado.xlsx`);
483
+ };
432
484
  const hasBalanceDifference = (0, react_1.useMemo)(() => {
433
485
  var _a;
434
486
  if (!isBalances || matrix.length <= 1) {
@@ -452,6 +504,7 @@ function ExcelLayout({ initData, jsonValidator, isBalances = false, }) {
452
504
  setError(null);
453
505
  setCurrentPage(1);
454
506
  setFocusTarget(null);
507
+ setIsStringEmptyFilterApplied(false);
455
508
  const fileBuffer = await file.arrayBuffer();
456
509
  const workbook = XLSX.read(fileBuffer, { type: "array" });
457
510
  const firstSheetName = workbook.SheetNames[0];
@@ -501,6 +554,7 @@ function ExcelLayout({ initData, jsonValidator, isBalances = false, }) {
501
554
  setError(null);
502
555
  setCurrentPage(1);
503
556
  setFocusTarget(null);
557
+ setIsStringEmptyFilterApplied(false);
504
558
  };
505
- return ((0, jsx_runtime_1.jsxs)("main", { className: "grid min-h-screen grid-cols-1 md:grid-cols-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "space-y-4 md:col-span-1", children: (0, jsx_runtime_1.jsx)(ExcelFile_1.ExcelFile, { initData: initData, fileContent: fileContent, matrix: matrix, error: error, onFileSelected: handleFileSelected, onReset: handleReset, validationErrors: validationErrors, onSelectError: handleSelectError, hasBalanceDifference: hasBalanceDifference }) }), (0, jsx_runtime_1.jsx)("div", { className: "md:col-span-3", children: (0, jsx_runtime_1.jsx)(ExcelPreview_1.ExcelPreview, { initData: initData, fileContent: fileContent, matrix: matrix, error: error, validationErrors: validationErrors, focusTarget: focusTarget, currentPage: currentPage, onPageChange: setCurrentPage, isBalances: isBalances }) })] }));
559
+ return ((0, jsx_runtime_1.jsxs)("main", { className: "grid min-h-screen grid-cols-1 md:grid-cols-4", children: [(0, jsx_runtime_1.jsx)("div", { className: "space-y-4 md:col-span-1", children: (0, jsx_runtime_1.jsx)(ExcelFile_1.ExcelFile, { initData: initData, fileContent: fileContent, matrix: matrix, error: error, onFileSelected: handleFileSelected, onReset: handleReset, validationErrors: validationErrorsForPanel, onSelectError: handleSelectError, hasBalanceDifference: hasBalanceDifference, onApplyStringEmptyFilter: handleApplyStringEmptyFilter, onDownloadFilteredExcel: handleDownloadFilteredExcel, isStringEmptyFilterApplied: isStringEmptyFilterApplied, hasStringEmptyDuplicateErrors: hasStringEmptyDuplicateErrors }) }), (0, jsx_runtime_1.jsx)("div", { className: "md:col-span-3", children: (0, jsx_runtime_1.jsx)(ExcelPreview_1.ExcelPreview, { initData: initData, fileContent: fileContent, matrix: matrix, error: error, validationErrors: validationErrors, focusTarget: focusTarget, currentPage: currentPage, onPageChange: setCurrentPage, isBalances: isBalances, hiddenFilteredRowIndexes: isStringEmptyFilterApplied ? stringEmptyDuplicateRowIndexes : [] }) })] }));
506
560
  }
@@ -1,2 +1,2 @@
1
1
  import { ExcelPreviewProps } from "../types/excelTypes";
2
- export declare const ExcelPreview: ({ initData, fileContent, matrix, error, validationErrors, focusTarget, currentPage, onPageChange, isBalances, }: ExcelPreviewProps) => import("react").JSX.Element;
2
+ export declare const ExcelPreview: ({ initData, fileContent, matrix, error, validationErrors, focusTarget, currentPage, onPageChange, isBalances, hiddenFilteredRowIndexes, }: ExcelPreviewProps) => import("react").JSX.Element;
@@ -7,15 +7,21 @@ const react_2 = require("react");
7
7
  const pi_1 = require("react-icons/pi");
8
8
  const tb_1 = require("react-icons/tb");
9
9
  const BalanceTotals_1 = require("./BalanceTotals");
10
- const ExcelPreview = ({ initData, fileContent, matrix, error, validationErrors, focusTarget, currentPage, onPageChange, isBalances = false, }) => {
10
+ const ExcelPreview = ({ initData, fileContent, matrix, error, validationErrors, focusTarget, currentPage, onPageChange, isBalances = false, hiddenFilteredRowIndexes = [], }) => {
11
11
  var _a;
12
12
  const rowsPerPage = 30;
13
13
  const cellRefs = (0, react_2.useRef)({});
14
14
  const maxColumns = (0, react_2.useMemo)(() => matrix.reduce((max, row) => Math.max(max, row.length), 0), [matrix]);
15
15
  const tableHeaders = (_a = matrix[0]) !== null && _a !== void 0 ? _a : [];
16
- const allDataRows = matrix
16
+ const hiddenRowIndexesSet = (0, react_2.useMemo)(() => new Set(hiddenFilteredRowIndexes), [hiddenFilteredRowIndexes]);
17
+ const allDataRows = (0, react_2.useMemo)(() => matrix
17
18
  .slice(1)
18
- .filter((row) => { var _a, _b; return ((_b = (_a = row[0]) === null || _a === void 0 ? void 0 : _a.toString().trim()) !== null && _b !== void 0 ? _b : "") !== ""; });
19
+ .filter((row) => { var _a, _b; return ((_b = (_a = row[0]) === null || _a === void 0 ? void 0 : _a.toString().trim()) !== null && _b !== void 0 ? _b : "") !== ""; })
20
+ .map((row, originalFilteredRowIndex) => ({
21
+ row,
22
+ originalFilteredRowIndex,
23
+ }))
24
+ .filter(({ originalFilteredRowIndex }) => !hiddenRowIndexesSet.has(originalFilteredRowIndex)), [matrix, hiddenRowIndexesSet]);
19
25
  const totalRecords = allDataRows.length;
20
26
  const totalPages = Math.max(1, Math.ceil(totalRecords / rowsPerPage));
21
27
  const effectivePage = Math.min(currentPage, totalPages);
@@ -54,15 +60,16 @@ const ExcelPreview = ({ initData, fileContent, matrix, error, validationErrors,
54
60
  return ((0, jsx_runtime_1.jsxs)("section", { className: "h-full bg-gray-50 dark:bg-content1 border-l border-default-200 px-4 py-2", children: [!fileContent ? ((0, jsx_runtime_1.jsx)(react_1.Alert, { color: "primary", title: `Al importar ${initData.title} verás una previsualización de su contenido.`, className: "my-3", radius: "sm", hideIconWrapper: true, variant: "faded" })) : null, fileContent && matrix.length === 0 && !error ? ((0, jsx_runtime_1.jsx)(react_1.Alert, { color: "danger", title: `No se encontraron datos en el archivo seleccionado.`, className: "my-3", radius: "sm", hideIconWrapper: true, variant: "faded" })) : null, fileContent && matrix.length > 0 ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: "mt-4 max-h-[85vh] max-w-full overflow-x-auto overflow-y-auto ", children: (0, jsx_runtime_1.jsxs)("table", { className: "min-w-max w-full text-sm", children: [(0, jsx_runtime_1.jsx)("thead", { className: "sticky top-0 bg-default-100", children: (0, jsx_runtime_1.jsx)("tr", { children: Array.from({ length: maxColumns }).map((_, columnIndex) => ((0, jsx_runtime_1.jsx)("th", { className: "border-x border-t border-default-200 p-3 font-semibold text-default-700", children: tableHeaders[columnIndex] ||
55
61
  `Columna ${columnIndex + 1}` }, `header-${columnIndex}`))) }) }), (0, jsx_runtime_1.jsx)("tbody", { className: "bg-content1", children: dataRows.map((row, rowIndex) => ((0, jsx_runtime_1.jsx)("tr", { children: Array.from({ length: maxColumns }).map((_, columnIndex) => (() => {
56
62
  var _a, _b;
57
- const absoluteRowIndex = startIndex + rowIndex;
58
- const key = `${absoluteRowIndex}-${columnIndex}`;
63
+ const originalFilteredRowIndex = row.originalFilteredRowIndex;
64
+ const key = `${originalFilteredRowIndex}-${columnIndex}`;
59
65
  const hasError = errorMap.has(key);
60
- const isFocusedTarget = (focusTarget === null || focusTarget === void 0 ? void 0 : focusTarget.filteredRowIndex) === absoluteRowIndex &&
66
+ const isFocusedTarget = (focusTarget === null || focusTarget === void 0 ? void 0 : focusTarget.filteredRowIndex) ===
67
+ originalFilteredRowIndex &&
61
68
  (focusTarget === null || focusTarget === void 0 ? void 0 : focusTarget.columnIndex) === columnIndex;
62
69
  return ((0, jsx_runtime_1.jsx)("td", { ref: (element) => {
63
70
  cellRefs.current[key] = element;
64
71
  }, tabIndex: -1, className: `border border-default-200 p-3 align-top whitespace-nowrap outline-none transition-all duration-200 ease-in-out text-default-700
65
- ${isFocusedTarget ? "ring-[1.7px] ring-danger ring-inset" : ""}`, children: hasError ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between", children: [(0, jsx_runtime_1.jsx)("p", { children: (_a = row[columnIndex]) !== null && _a !== void 0 ? _a : "" }), (0, jsx_runtime_1.jsx)(tb_1.TbAlertCircle, { color: "red", size: 20 })] })) : ((0, jsx_runtime_1.jsx)("p", { children: (_b = row[columnIndex]) !== null && _b !== void 0 ? _b : "" })) }, `cell-${rowIndex}-${columnIndex}`));
66
- })()) }, `row-${rowIndex}`))) })] }) }), totalRecords > rowsPerPage ? ((0, jsx_runtime_1.jsxs)("div", { className: "mt-4 flex items-center justify-between gap-3", children: [(0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-default-600", children: ["Mostrando ", startIndex + 1, "-", Math.min(endIndex, totalRecords), " de", " ", totalRecords, " registros"] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", className: "text-sm border border-default-300 disabled:border-default-200 disabled:bg-default-100 disabled:text-default-500 dark:border-default-400 dark:text-default-700", variant: "bordered", disabled: effectivePage === 1, onPress: () => onPageChange(Math.max(1, effectivePage - 1)), isIconOnly: true, children: (0, jsx_runtime_1.jsx)(pi_1.PiCaretLeftBold, { size: 16 }) }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm text-default-700 mx-1", children: ["Pagina ", effectivePage, " de ", totalPages] }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", className: "text-sm border border-default-300 disabled:border-default-200 disabled:bg-default-100 disabled:text-default-500 dark:border-default-400 dark:text-default-700", variant: "bordered", disabled: effectivePage === totalPages, onPress: () => onPageChange(Math.min(totalPages, effectivePage + 1)), isIconOnly: true, children: (0, jsx_runtime_1.jsx)(pi_1.PiCaretRightBold, { size: 16 }) })] })] })) : null, isBalances ? ((0, jsx_runtime_1.jsx)(BalanceTotals_1.BalanceTotals, { headers: tableHeaders, rows: allDataRows })) : null] })) : null] }));
72
+ ${isFocusedTarget ? "ring-[1.7px] ring-danger ring-inset" : ""}`, children: hasError ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between", children: [(0, jsx_runtime_1.jsx)("p", { children: (_a = row.row[columnIndex]) !== null && _a !== void 0 ? _a : "" }), (0, jsx_runtime_1.jsx)(tb_1.TbAlertCircle, { color: "red", size: 20 })] })) : ((0, jsx_runtime_1.jsx)("p", { children: (_b = row.row[columnIndex]) !== null && _b !== void 0 ? _b : "" })) }, `cell-${rowIndex}-${columnIndex}`));
73
+ })()) }, `row-${rowIndex}`))) })] }) }), totalRecords > rowsPerPage ? ((0, jsx_runtime_1.jsxs)("div", { className: "mt-4 flex items-center justify-between gap-3", children: [(0, jsx_runtime_1.jsxs)("p", { className: "text-sm text-default-600", children: ["Mostrando ", startIndex + 1, "-", Math.min(endIndex, totalRecords), " de", " ", totalRecords, " registros"] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [(0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", className: "text-sm border border-default-300 disabled:border-default-200 disabled:bg-default-100 disabled:text-default-500 dark:border-default-400 dark:text-default-700", variant: "bordered", disabled: effectivePage === 1, onPress: () => onPageChange(Math.max(1, effectivePage - 1)), isIconOnly: true, children: (0, jsx_runtime_1.jsx)(pi_1.PiCaretLeftBold, { size: 16 }) }), (0, jsx_runtime_1.jsxs)("span", { className: "text-sm text-default-700 mx-1", children: ["Pagina ", effectivePage, " de ", totalPages] }), (0, jsx_runtime_1.jsx)(react_1.Button, { size: "sm", className: "text-sm border border-default-300 disabled:border-default-200 disabled:bg-default-100 disabled:text-default-500 dark:border-default-400 dark:text-default-700", variant: "bordered", disabled: effectivePage === totalPages, onPress: () => onPageChange(Math.min(totalPages, effectivePage + 1)), isIconOnly: true, children: (0, jsx_runtime_1.jsx)(pi_1.PiCaretRightBold, { size: 16 }) })] })] })) : null, isBalances ? ((0, jsx_runtime_1.jsx)(BalanceTotals_1.BalanceTotals, { headers: tableHeaders, rows: allDataRows.map((entry) => entry.row) })) : null] })) : null] }));
67
74
  };
68
75
  exports.ExcelPreview = ExcelPreview;
@@ -9,6 +9,7 @@ export type ValidationError = {
9
9
  message: string;
10
10
  value: string;
11
11
  filteredRowIndex: number;
12
+ errorCode?: string;
12
13
  };
13
14
  export type FocusTarget = {
14
15
  filteredRowIndex: number;
@@ -25,6 +26,10 @@ export type ExcelFileProps = {
25
26
  validationErrors: ValidationError[];
26
27
  onSelectError: (error: ValidationError) => void;
27
28
  hasBalanceDifference?: boolean;
29
+ onApplyStringEmptyFilter: () => void;
30
+ onDownloadFilteredExcel: () => void;
31
+ isStringEmptyFilterApplied: boolean;
32
+ hasStringEmptyDuplicateErrors: boolean;
28
33
  };
29
34
  export type ExcelValidatorProps = {
30
35
  initData: SettingsProps;
@@ -44,4 +49,5 @@ export type ExcelPreviewProps = {
44
49
  currentPage: number;
45
50
  onPageChange: (page: number) => void;
46
51
  isBalances?: boolean;
52
+ hiddenFilteredRowIndexes?: number[];
47
53
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafosoft/excel-validator",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "React component to validate Excel files against configurable JSON rules.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",