frontend-plus-react 0.1.11 → 0.1.13

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/dist/index.d.ts CHANGED
@@ -38,25 +38,13 @@ interface AppProps {
38
38
  }
39
39
  declare const App: ({ myRoutes, myWScreens, myClientSides, myResultsOk }: AppProps) => react_jsx_runtime.JSX.Element;
40
40
 
41
- interface GenericDataGridProps$1 {
42
- }
43
- interface FixedField {
44
- fieldName: string;
45
- value: any;
46
- until?: any;
47
- }
48
41
  interface CellFeedback {
49
42
  rowId: string;
50
43
  columnKey: string;
51
44
  type: 'success' | 'error';
52
- message?: 'string';
53
- }
54
- interface ConfirmDialogProps {
55
- open: boolean;
56
- onClose: (confirm: boolean) => void;
57
- title: string;
58
- message: string;
45
+ message?: string;
59
46
  }
47
+ type CellFeedbackMap = Map<string, CellFeedback>;
60
48
  interface InputRendererProps<R extends Record<string, any>, S> {
61
49
  column: Column<R, S>;
62
50
  row: R;
@@ -64,14 +52,27 @@ interface InputRendererProps<R extends Record<string, any>, S> {
64
52
  onRowChange: (row: R, commitChanges?: boolean) => void;
65
53
  onClose: (commitChanges?: boolean, shouldFocusCell?: boolean) => void;
66
54
  tableDefinition: TableDefinition;
67
- cellFeedback: CellFeedback | null;
68
- setCellFeedback: (feedback: CellFeedback | null) => void;
55
+ cellFeedbackMap: CellFeedbackMap;
56
+ setCellFeedbackMap: React.Dispatch<React.SetStateAction<CellFeedbackMap>>;
69
57
  onKeyPress?: (rowIndex: number, columnKey: string, event: React.KeyboardEvent, handleCommit: (currentValue: any, closeEditor: boolean, focusNextCell: boolean) => Promise<void>) => void;
70
58
  setTableData: React.Dispatch<React.SetStateAction<any[]>>;
71
59
  setLocalCellChanges: React.Dispatch<React.SetStateAction<Map<string, Set<string>>>>;
72
60
  localCellChanges: Map<string, Set<string>>;
73
61
  primaryKey: string[];
74
62
  }
63
+ interface GenericDataGridProps$1 {
64
+ }
65
+ interface FixedField {
66
+ fieldName: string;
67
+ value: any;
68
+ until?: any;
69
+ }
70
+ interface ConfirmDialogProps {
71
+ open: boolean;
72
+ onClose: (confirm: boolean) => void;
73
+ title: string;
74
+ message: string;
75
+ }
75
76
  interface FilterRendererProps<R extends Record<string, any>, S> {
76
77
  column: Column<R, S>;
77
78
  filters: Record<string, string>;
@@ -197,4 +198,4 @@ declare const useLogout: () => () => Promise<void>;
197
198
 
198
199
  declare const cambiarGuionesBajosPorEspacios: (texto: string) => string;
199
200
 
200
- export { App, type AppContextType, type AppProps, AppProvider, type AppProviderProps, type CellFeedback, type ClientContextState, ConfirmDialog, type ConfirmDialogProps, type CustomCellProps, type CustomHeaderCellProps, type FetchApiOptions, type FilterRendererProps, type FixedField, FrontendPlusReactRoutes, GenericDataGrid, type GenericDataGridForDetailProps, type GenericDataGridProps$1 as GenericDataGridProps, type InputRendererProps, MainLayout, type MenuListItemProps, type MenuUiState, type PrivateRouteProps, type RouterState, type SideMenuProps, type SnackbarContextType, SnackbarProvider, type SnackbarProviderProps, type SnackbarState, type UseApiCallResult, cambiarGuionesBajosPorEspacios, clientSides, extendClientSides, resultsOk as resultComponents, useApiCall, useApp, useLogout, useSnackbar, wScreens };
201
+ export { App, type AppContextType, type AppProps, AppProvider, type AppProviderProps, type CellFeedback, type CellFeedbackMap, type ClientContextState, ConfirmDialog, type ConfirmDialogProps, type CustomCellProps, type CustomHeaderCellProps, type FetchApiOptions, type FilterRendererProps, type FixedField, FrontendPlusReactRoutes, GenericDataGrid, type GenericDataGridForDetailProps, type GenericDataGridProps$1 as GenericDataGridProps, type InputRendererProps, MainLayout, type MenuListItemProps, type MenuUiState, type PrivateRouteProps, type RouterState, type SideMenuProps, type SnackbarContextType, SnackbarProvider, type SnackbarProviderProps, type SnackbarState, type UseApiCallResult, cambiarGuionesBajosPorEspacios, clientSides, extendClientSides, resultsOk as resultComponents, useApiCall, useApp, useLogout, useSnackbar, wScreens };
package/dist/index.js CHANGED
@@ -1258,8 +1258,10 @@ var allColumnsCellRenderer = (props) => {
1258
1258
  switch (column.customType) {
1259
1259
  case "default": {
1260
1260
  const defaultColumn = column;
1261
- const { fieldDef, tableDefinition, primaryKey, cellFeedback, fixedFields, localCellChanges } = defaultColumn;
1261
+ const { fieldDef, tableDefinition, primaryKey, cellFeedbackMap, fixedFields, localCellChanges } = defaultColumn;
1262
1262
  const rowId = getPrimaryKeyValues(row, primaryKey);
1263
+ const cellKey = `${rowId}-${props.column.key}`;
1264
+ const currentCellFeedback = cellFeedbackMap.get ? cellFeedbackMap.get(cellKey) : cellFeedbackMap[cellKey];
1263
1265
  if (fieldDef?.clientSide) {
1264
1266
  const ClientSideComponent = clientSides[fieldDef.clientSide];
1265
1267
  if (ClientSideComponent) {
@@ -1268,8 +1270,8 @@ var allColumnsCellRenderer = (props) => {
1268
1270
  return /* @__PURE__ */ jsx8(FallbackClientSideRenderer_default, { ...props, fieldDefinition: fieldDef, tableDefinition, primaryKey });
1269
1271
  }
1270
1272
  let cellBackgroundColor = "transparent";
1271
- if (cellFeedback && cellFeedback.rowId === rowId && cellFeedback.columnKey === props.column.key) {
1272
- cellBackgroundColor = cellFeedback.type === "error" ? theme.palette.error.light : theme.palette.success.light;
1273
+ if (currentCellFeedback) {
1274
+ cellBackgroundColor = currentCellFeedback.type === "error" ? theme.palette.error.light : theme.palette.success.light;
1273
1275
  } else {
1274
1276
  const isNewRowLocalCheck = row[NEW_ROW_INDICATOR];
1275
1277
  const isMandatory = tableDefinition.primaryKey.includes(props.column.key) || tableDefinition.fields.find((f) => f.name === props.column.key)?.nullable === false;
@@ -1282,7 +1284,7 @@ var allColumnsCellRenderer = (props) => {
1282
1284
  }
1283
1285
  }
1284
1286
  const value = row[props.column.key];
1285
- return /* @__PURE__ */ jsx8(Tooltip3, { title: cellFeedback && cellFeedback.rowId === rowId && cellFeedback.columnKey === props.column.key ? cellFeedback?.message : "", children: /* @__PURE__ */ jsx8(Box5, { sx: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%", backgroundColor: cellBackgroundColor, transition: "background-color 0.3s ease-in-out", display: "flex", alignItems: "center", paddingLeft: "8px", boxSizing: "border-box" }, children: /* @__PURE__ */ jsx8(Typography4, { variant: "body2", sx: { fontSize: "0.875rem", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", width: "100%" }, children: value === null || value === void 0 ? "" : String(value) }) }) });
1287
+ return /* @__PURE__ */ jsx8(Tooltip3, { title: currentCellFeedback?.message || "", children: /* @__PURE__ */ jsx8(Box5, { sx: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%", backgroundColor: cellBackgroundColor, transition: "background-color 0.3s ease-in-out", display: "flex", alignItems: "center", paddingLeft: "8px", boxSizing: "border-box" }, children: /* @__PURE__ */ jsx8(Typography4, { variant: "body2", sx: { fontSize: "0.875rem", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", width: "100%" }, children: value === null || value === void 0 ? "" : String(value) }) }) });
1286
1288
  }
1287
1289
  case "detail": {
1288
1290
  const detailColumn = column;
@@ -1366,10 +1368,10 @@ import { useCallback as useCallback3, useMemo, useState as useState3 } from "rea
1366
1368
  import InputBase2 from "@mui/material/InputBase";
1367
1369
  import { useTheme as useTheme2 } from "@mui/material";
1368
1370
  import { jsx as jsx9 } from "react/jsx-runtime";
1369
- function findChangedValues(oldRowData, newRowData) {
1371
+ function findChangedValues(oldRowData, newRowData, isNewRow) {
1370
1372
  let changes = [];
1371
1373
  for (const key in newRowData) {
1372
- if (Object.prototype.hasOwnProperty.call(oldRowData, key) && oldRowData[key] !== newRowData[key]) {
1374
+ if (Object.prototype.hasOwnProperty.call(oldRowData, key) && oldRowData[key] !== newRowData[key] || isNewRow) {
1373
1375
  changes.push(key);
1374
1376
  }
1375
1377
  }
@@ -1382,8 +1384,10 @@ function InputRenderer({
1382
1384
  tableDefinition,
1383
1385
  onRowChange,
1384
1386
  onClose,
1385
- cellFeedback,
1386
- setCellFeedback,
1387
+ cellFeedbackMap,
1388
+ // Tipo: CellFeedbackMap
1389
+ setCellFeedbackMap,
1390
+ // Tipo: Dispatch<SetStateAction<CellFeedbackMap>>
1387
1391
  onKeyPress,
1388
1392
  setTableData,
1389
1393
  setLocalCellChanges,
@@ -1394,10 +1398,11 @@ function InputRenderer({
1394
1398
  const [editingValue, setEditingValue] = useState3(row[column.key]);
1395
1399
  const theme = useTheme2();
1396
1400
  const { showSuccess, showError } = useSnackbar();
1397
- const rowId = getPrimaryKeyValues(row, primaryKey);
1401
+ const cellKey = getCellKey(row, column.key, primaryKey);
1402
+ const currentCellFeedback = cellFeedbackMap.get(cellKey);
1398
1403
  let cellBackgroundColor;
1399
- if (cellFeedback && cellFeedback.rowId === rowId && cellFeedback.columnKey === column.key) {
1400
- cellBackgroundColor = cellFeedback.type === "error" ? theme.palette.error.light : theme.palette.success.light;
1404
+ if (currentCellFeedback) {
1405
+ cellBackgroundColor = currentCellFeedback.type === "error" ? theme.palette.error.light : theme.palette.success.light;
1401
1406
  }
1402
1407
  const initialRowId = useMemo(() => getPrimaryKeyValues(row, primaryKey), [row, primaryKey]);
1403
1408
  const { callApi } = useApiCall();
@@ -1496,7 +1501,6 @@ function InputRenderer({
1496
1501
  if (rowIndex !== -1) {
1497
1502
  newData[rowIndex] = persistedRowData;
1498
1503
  } else {
1499
- console.warn("Fila no encontrada para actualizar despu\xE9s de la inserci\xF3n. Podr\xEDa haber un problema de sincronizaci\xF3n.");
1500
1504
  const newPrimaryKeyId = getPrimaryKeyValues(persistedRowData, tableDefinition.primaryKey);
1501
1505
  const newRowIndex = newData.findIndex((r) => getPrimaryKeyValues(r, tableDefinition.primaryKey) === newPrimaryKeyId);
1502
1506
  if (newRowIndex !== -1) {
@@ -1512,12 +1516,28 @@ function InputRenderer({
1512
1516
  finalRowIdForFeedback = isPrimaryKeyColumn ? getPrimaryKeyValues(potentialUpdatedRow, tableDefinition.primaryKey) : currentRowIdBeforeUpdate;
1513
1517
  onRowChange({ ...response.row }, true);
1514
1518
  }
1515
- findChangedValues(oldRowData, response.row).forEach(
1516
- (key) => setCellFeedback({ rowId: finalRowIdForFeedback, columnKey: key, type: "success" })
1517
- );
1519
+ const changes = findChangedValues(oldRowData, response.row, isNewRow);
1520
+ setCellFeedbackMap((prevFeedback) => {
1521
+ const newFeedback = new Map(prevFeedback);
1522
+ changes.forEach((key) => {
1523
+ const keyForMap = `${finalRowIdForFeedback}-${key}`;
1524
+ newFeedback.set(keyForMap, { rowId: finalRowIdForFeedback, columnKey: key, type: "success" });
1525
+ });
1526
+ return newFeedback;
1527
+ });
1518
1528
  } catch (err) {
1519
1529
  console.error("Error al guardar el registro:", err);
1520
- setCellFeedback({ rowId: currentRowIdBeforeUpdate, columnKey: column.key, type: "error", message: err.message });
1530
+ const keyForMap = `${currentRowIdBeforeUpdate}-${column.key}`;
1531
+ setCellFeedbackMap((prevFeedback) => {
1532
+ const newFeedback = new Map(prevFeedback);
1533
+ newFeedback.set(keyForMap, {
1534
+ rowId: currentRowIdBeforeUpdate,
1535
+ columnKey: column.key,
1536
+ type: "error",
1537
+ message: err.message
1538
+ });
1539
+ return newFeedback;
1540
+ });
1521
1541
  }
1522
1542
  }, [
1523
1543
  column,
@@ -1528,7 +1548,7 @@ function InputRenderer({
1528
1548
  tableDefinition.fields,
1529
1549
  showSuccess,
1530
1550
  showError,
1531
- setCellFeedback,
1551
+ setCellFeedbackMap,
1532
1552
  onClose,
1533
1553
  setTableData,
1534
1554
  setLocalCellChanges,
@@ -1587,8 +1607,10 @@ var allColumnsEditCellRenderer = (props, allColumns) => {
1587
1607
  fixedFields,
1588
1608
  primaryKey,
1589
1609
  setTableData,
1590
- cellFeedback,
1591
- setCellFeedback,
1610
+ cellFeedbackMap,
1611
+ // <--- CAMBIADO
1612
+ setCellFeedbackMap,
1613
+ // <--- CAMBIADO
1592
1614
  handleKeyPressInEditor,
1593
1615
  localCellChanges,
1594
1616
  setLocalCellChanges
@@ -1601,20 +1623,25 @@ var allColumnsEditCellRenderer = (props, allColumns) => {
1601
1623
  return void 0;
1602
1624
  }
1603
1625
  const rowId = getPrimaryKeyValues(props.row, primaryKey);
1604
- return /* @__PURE__ */ jsx10(Tooltip4, { title: cellFeedback && cellFeedback.rowId === rowId && cellFeedback.columnKey === props.column.key ? cellFeedback?.message : "", children: /* @__PURE__ */ jsx10(Box6, { children: /* @__PURE__ */ jsx10(
1605
- InputRenderer_default,
1606
- {
1607
- ...props,
1608
- tableDefinition,
1609
- setCellFeedback,
1610
- cellFeedback,
1611
- onKeyPress: (rowIndex, columnKey, event, handleCommit) => handleKeyPressInEditor(rowIndex, columnKey, event, allColumns, handleCommit),
1612
- setTableData,
1613
- setLocalCellChanges,
1614
- localCellChanges,
1615
- primaryKey
1616
- }
1617
- ) }) });
1626
+ const cellKey = `${rowId}-${props.column.key}`;
1627
+ const currentCellFeedback = cellFeedbackMap.get ? cellFeedbackMap.get(cellKey) : cellFeedbackMap[cellKey];
1628
+ return (
1629
+ // --- TOOLTIP ADAPTADO: Lee el mensaje de error desde el Mapa ---
1630
+ /* @__PURE__ */ jsx10(Tooltip4, { title: currentCellFeedback?.message || "", children: /* @__PURE__ */ jsx10(Box6, { children: /* @__PURE__ */ jsx10(
1631
+ InputRenderer_default,
1632
+ {
1633
+ ...props,
1634
+ tableDefinition,
1635
+ setCellFeedbackMap,
1636
+ cellFeedbackMap,
1637
+ onKeyPress: (rowIndex, columnKey, event, handleCommit) => handleKeyPressInEditor(rowIndex, columnKey, event, allColumns, handleCommit),
1638
+ setTableData,
1639
+ setLocalCellChanges,
1640
+ localCellChanges,
1641
+ primaryKey
1642
+ }
1643
+ ) }) })
1644
+ );
1618
1645
  }
1619
1646
  return void 0;
1620
1647
  }
@@ -1652,16 +1679,20 @@ function EmptyRowsRenderer() {
1652
1679
 
1653
1680
  // src/components/grid/GenericDataGrid.tsx
1654
1681
  import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
1682
+ var NEW_ROW_INDICATOR = "$new";
1683
+ var DETAIL_ROW_INDICATOR = "$detail";
1655
1684
  var getPrimaryKeyValues = (row, primaryKey) => {
1685
+ let keys = [...primaryKey];
1656
1686
  if (row[DETAIL_ROW_INDICATOR]) {
1657
- primaryKey = primaryKey.concat(DETAIL_ROW_INDICATOR);
1687
+ keys = keys.concat(DETAIL_ROW_INDICATOR);
1658
1688
  }
1659
- return primaryKey.map((key) => {
1689
+ return keys.map((key) => {
1660
1690
  return row[key] !== void 0 && row[key] !== null ? String(row[key]) : "NULL_OR_UNDEFINED";
1661
1691
  }).join("|");
1662
1692
  };
1663
- var NEW_ROW_INDICATOR = "$new";
1664
- var DETAIL_ROW_INDICATOR = "$detail";
1693
+ var getCellKey = (row, columnKey, primaryKey) => {
1694
+ return `${getPrimaryKeyValues(row, primaryKey)}|${columnKey}`;
1695
+ };
1665
1696
  var GenericDataGrid = ({
1666
1697
  tableName,
1667
1698
  fixedFields,
@@ -1674,7 +1705,7 @@ var GenericDataGrid = ({
1674
1705
  const [filters, setFilters] = useState4({});
1675
1706
  const [selectedRows, setSelectedRows] = useState4(() => /* @__PURE__ */ new Set());
1676
1707
  const [selectedCell, setSelectedCell] = useState4(void 0);
1677
- const [cellFeedback, setCellFeedback] = useState4(null);
1708
+ const [cellFeedbackMap, setCellFeedbackMap] = useState4(/* @__PURE__ */ new Map());
1678
1709
  const [localCellChanges, setLocalCellChanges] = useState4(/* @__PURE__ */ new Map());
1679
1710
  const theme = useTheme3();
1680
1711
  const [openConfirmDialog, setOpenConfirmDialog] = useState4(false);
@@ -1692,7 +1723,7 @@ var GenericDataGrid = ({
1692
1723
  setSelectedRows(/* @__PURE__ */ new Set());
1693
1724
  setTableDefinition(null);
1694
1725
  setTableData([]);
1695
- setCellFeedback(null);
1726
+ setCellFeedbackMap(/* @__PURE__ */ new Map());
1696
1727
  setLocalCellChanges(/* @__PURE__ */ new Map());
1697
1728
  setOpenConfirmDialog(false);
1698
1729
  setRowToDelete(null);
@@ -1721,14 +1752,24 @@ var GenericDataGrid = ({
1721
1752
  fetchDataAndDefinition();
1722
1753
  }, [tableName, fixedFields, showError]);
1723
1754
  useEffect(() => {
1724
- if (cellFeedback) {
1755
+ if (cellFeedbackMap.size > 0) {
1725
1756
  if (feedbackTimerRef.current) {
1726
1757
  clearTimeout(feedbackTimerRef.current);
1727
1758
  }
1728
1759
  const timerDuration = 3e3;
1729
1760
  feedbackTimerRef.current = setTimeout(() => {
1730
- if (cellFeedback.type == "success")
1731
- setCellFeedback(null);
1761
+ setCellFeedbackMap((prevMap) => {
1762
+ const newMap = new Map(prevMap);
1763
+ let mapChanged = false;
1764
+ for (const [cellId, feedback] of prevMap.entries()) {
1765
+ if (feedback.type === "success") {
1766
+ newMap.delete(cellId);
1767
+ mapChanged = true;
1768
+ }
1769
+ }
1770
+ return mapChanged ? newMap : prevMap;
1771
+ });
1772
+ feedbackTimerRef.current = null;
1732
1773
  }, timerDuration);
1733
1774
  }
1734
1775
  return () => {
@@ -1736,7 +1777,7 @@ var GenericDataGrid = ({
1736
1777
  clearTimeout(feedbackTimerRef.current);
1737
1778
  }
1738
1779
  };
1739
- }, [cellFeedback]);
1780
+ }, [cellFeedbackMap]);
1740
1781
  const primaryKey = useMemo2(() => {
1741
1782
  if (!tableDefinition) return ["id"];
1742
1783
  return tableDefinition.primaryKey && tableDefinition.primaryKey.length > 0 ? tableDefinition.primaryKey : ["id"];
@@ -1982,7 +2023,7 @@ var GenericDataGrid = ({
1982
2023
  }
1983
2024
  }
1984
2025
  }
1985
- }, [filteredRows, tableDefinition]);
2026
+ }, [filteredRows, tableDefinition, tableData]);
1986
2027
  const handleSelectedCellChange = useCallback4((args) => {
1987
2028
  setSelectedCell(args);
1988
2029
  }, []);
@@ -2000,13 +2041,14 @@ var GenericDataGrid = ({
2000
2041
  customType: "default",
2001
2042
  tableDefinition,
2002
2043
  fieldDef,
2003
- cellFeedback,
2044
+ // 💥 MULTI-CELL: Se inyecta el mapa y su setter
2045
+ cellFeedbackMap,
2046
+ setCellFeedbackMap,
2004
2047
  primaryKey,
2005
2048
  fixedFields,
2006
2049
  localCellChanges,
2007
2050
  setLocalCellChanges,
2008
2051
  setTableData,
2009
- setCellFeedback,
2010
2052
  name: fieldDef.label || cambiarGuionesBajosPorEspacios(fieldDef.name),
2011
2053
  resizable: true,
2012
2054
  sortable: true,
@@ -2088,7 +2130,8 @@ var GenericDataGrid = ({
2088
2130
  isFilterRowVisible,
2089
2131
  filters,
2090
2132
  toggleFilterVisibility,
2091
- cellFeedback,
2133
+ // 💥 MULTI-CELL: Se usa el mapa en lugar de la variable simple
2134
+ cellFeedbackMap,
2092
2135
  primaryKey,
2093
2136
  theme.palette.success.light,
2094
2137
  theme.palette.error.light,