contentoh-components-library 21.6.36 → 21.6.37

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.
@@ -16,6 +16,10 @@ var _jsxRuntime = require("react/jsx-runtime");
16
16
  *
17
17
  * El estado "propio" es el que carga información —ese campo se separó del padre—
18
18
  * así que es el que lleva acento y el que ofrece la acción de volver a heredar.
19
+ *
20
+ * OJO: "propio" ya NO significa "a salvo de la propagación". Desde el cambio del
21
+ * 2026-09-01 la propagación sobrescribe también estos valores; el aviso de que va
22
+ * a pasar vive en el diálogo de propagación, no aquí. El tooltip lo dice así.
19
23
  * "Heredado" es el caso normal y se mantiene discreto: si gritara en cada campo,
20
24
  * la ficha entera se volvería ruido.
21
25
  *
@@ -51,9 +55,9 @@ var InheritanceTag = function InheritanceTag(_ref) {
51
55
  className: "inheritance-tag ".concat(state, " ").concat(className),
52
56
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
53
57
  className: "tag-label",
54
- title: isOverridden ? "Valor propio de este producto hijo. La propagación del padre no lo modifica." : "Valor heredado".concat(parentUpc ? " del producto ".concat(parentUpc) : " del producto padre", "."),
58
+ title: isOverridden ? "Valor capturado en este producto hijo, distinto al del padre. Si el padre propaga este atributo, se reemplaza." : "Valor heredado".concat(parentUpc ? " del producto ".concat(parentUpc) : " del producto padre", "."),
55
59
  children: isOverridden ? "Propio" : "Heredado"
56
- }), isOverridden && onRestore && /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
60
+ }), Boolean(isOverridden) && onRestore && /*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
57
61
  type: "button",
58
62
  className: "tag-action",
59
63
  onClick: onRestore,
@@ -420,7 +420,7 @@ var TagAndInput = function TagAndInput(_ref) {
420
420
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Container, {
421
421
  inputType: inputType,
422
422
  className: "input-container",
423
- children: [(label === null || label === void 0 ? void 0 : label.length) && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
423
+ children: [Boolean(label === null || label === void 0 ? void 0 : label.length) && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
424
424
  className: "title-container",
425
425
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
426
426
  className: "titles",
@@ -54,7 +54,7 @@ var TagAndInputv2 = function TagAndInputv2(_ref) {
54
54
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Container, {
55
55
  inputType: inputType,
56
56
  className: "input-container",
57
- children: [(label === null || label === void 0 ? void 0 : label.length) && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
57
+ children: [Boolean(label === null || label === void 0 ? void 0 : label.length) && /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
58
58
  className: "title-container",
59
59
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_ScreenHeaderv.ScreenHeaderv2, {
60
60
  text: label,
@@ -9,6 +9,8 @@ exports.PropagateChangesModal = void 0;
9
9
 
10
10
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/toConsumableArray"));
11
11
 
12
+ var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/objectSpread2"));
13
+
12
14
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/slicedToArray"));
13
15
 
14
16
  var _react = require("react");
@@ -27,7 +29,10 @@ var _jsxRuntime = require("react/jsx-runtime");
27
29
 
28
30
  props (* requerido):
29
31
  - *changedAttributes: [{ id, name, value }] lo que se acaba de editar
30
- - *variants: [{ articleId, name, upc }] los hijos activos del padre
32
+ - *variants: [{ articleId, name, upc, overriddenAttributes }] los hijos
33
+ activos del padre. `overriddenAttributes` son los atributos que ese hijo
34
+ capturó a mano; la propagación los sobrescribe, y este diálogo es el
35
+ único lugar donde el usuario puede enterarse antes de que pase.
31
36
  - *onCancel: cerrar sin guardar nada
32
37
  - *onConfirm: (propagation | null) => void
33
38
  null → guardar solo el padre
@@ -67,6 +72,31 @@ var PropagateChangesModal = function PropagateChangesModal(_ref) {
67
72
  var destinatarios = scope === "all" ? variants.length : chosenChildren.length;
68
73
  var puedePropagar = chosenAttributes.length > 0 && destinatarios > 0;
69
74
  var enSegundoPlano = destinatarios > UMBRAL_SEGUNDO_PLANO;
75
+ /*
76
+ A quién se le va a pisar un valor capturado a mano.
77
+ La propagación sobrescribe: eso se decidió a propósito, porque el usuario ya
78
+ eligió atributo por atributo y hijo por hijo. Pero sobrescribir en silencio
79
+ es otra cosa, y desde que se quitaron las etiquetas de «Heredado» y «Propio»
80
+ este diálogo es el único momento en que alguien puede saberlo.
81
+ Se recalcula con lo que está marcado ahora, no al abrir: si el usuario
82
+ desmarca el atributo conflictivo, el aviso desaparece — que es justo la
83
+ salida que el aviso debería estar ofreciendo.
84
+ */
85
+
86
+ var destinos = scope === "all" ? variants : variants.filter(function (item) {
87
+ return chosenChildren.includes(item.articleId);
88
+ });
89
+ var conValorPropio = destinos.map(function (hijo) {
90
+ var _hijo$overriddenAttri;
91
+
92
+ return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, hijo), {}, {
93
+ pisados: ((_hijo$overriddenAttri = hijo.overriddenAttributes) !== null && _hijo$overriddenAttri !== void 0 ? _hijo$overriddenAttri : []).filter(function (id) {
94
+ return chosenAttributes.includes(Number(id));
95
+ })
96
+ });
97
+ }).filter(function (hijo) {
98
+ return hijo.pisados.length > 0;
99
+ });
70
100
 
71
101
  var toggleAttribute = function toggleAttribute(id) {
72
102
  setChosenAttributes(function (current) {
@@ -173,8 +203,11 @@ var PropagateChangesModal = function PropagateChangesModal(_ref) {
173
203
  })
174
204
  }, variant.articleId);
175
205
  })
176
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_styles.Note, {
177
- children: "Un hijo que haya editado alguno de estos atributos por su cuenta conserva su valor. Para devolverlo al del padre est\xE1 la acci\xF3n \xABVolver a heredar\xBB en la ficha de ese hijo."
206
+ }), conValorPropio.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Note, {
207
+ className: "accent",
208
+ children: [conValorPropio.length === 1 ? "Un hijo tiene un valor propio en lo que elegiste y se va a reemplazar: " : "".concat(conValorPropio.length, " hijos tienen valores propios en lo que elegiste y se van a reemplazar: "), conValorPropio.map(function (hijo) {
209
+ return "".concat(hijo.name || "Producto ".concat(hijo.articleId), " (").concat(hijo.pisados.length, ")");
210
+ }).join(", "), ". Si no quieres pisarlos, desmarca ese atributo o ese hijo."]
178
211
  }), enSegundoPlano && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_styles.Note, {
179
212
  className: "accent",
180
213
  children: ["Son m\xE1s de ", UMBRAL_SEGUNDO_PLANO, " hijos, as\xED que la propagaci\xF3n corre en segundo plano: el guardado termina antes de que todas est\xE9n actualizadas."]
@@ -1597,7 +1597,8 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1597
1597
 
1598
1598
  var handleOnClickSave = /*#__PURE__*/function () {
1599
1599
  var _ref12 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee8() {
1600
- var esPadre, cambios;
1600
+ var _familia$variants, cambios, familia, hijos;
1601
+
1601
1602
  return _regenerator.default.wrap(function _callee8$(_context8) {
1602
1603
  while (1) {
1603
1604
  switch (_context8.prev = _context8.next) {
@@ -1611,7 +1612,7 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1611
1612
 
1612
1613
  case 2:
1613
1614
  _context8.t0 = state.active_tab;
1614
- _context8.next = _context8.t0 === "Descripción" ? 5 : _context8.t0 === "Ficha técnica" ? 8 : _context8.t0 === "Imágenes" ? 17 : 20;
1615
+ _context8.next = _context8.t0 === "Descripción" ? 5 : _context8.t0 === "Ficha técnica" ? 8 : _context8.t0 === "Imágenes" ? 32 : 35;
1615
1616
  break;
1616
1617
 
1617
1618
  case 5:
@@ -1619,57 +1620,134 @@ var RetailerProductEditionView = function RetailerProductEditionView(_ref) {
1619
1620
  return saveDescriptions(token);
1620
1621
 
1621
1622
  case 7:
1622
- return _context8.abrupt("break", 21);
1623
+ return _context8.abrupt("break", 36);
1623
1624
 
1624
1625
  case 8:
1625
- // Guardar un padre con hijos abre la decisión de propagar. Sin este
1626
- // paso el cambio se queda solo en el padre y los hijos se van
1627
- // separando de él sin que nadie lo note.
1628
- esPadre = hijosDelProducto > 0;
1629
1626
  cambios = cambiosDeFichaTecnica();
1630
1627
 
1631
- if (!(esPadre && cambios.length > 0)) {
1632
- _context8.next = 14;
1628
+ if (!(cambios.length === 0)) {
1629
+ _context8.next = 13;
1633
1630
  break;
1634
1631
  }
1635
1632
 
1633
+ _context8.next = 12;
1634
+ return saveDatasheets(token);
1635
+
1636
+ case 12:
1637
+ return _context8.abrupt("break", 36);
1638
+
1639
+ case 13:
1640
+ /*
1641
+ Guardar un padre con hijos abre la decisión de propagar. Sin este paso
1642
+ el cambio se queda solo en el padre y los hijos se van separando de él
1643
+ sin que nadie lo note.
1644
+ Si tiene hijos se resuelve AQUÍ, esperando la respuesta, en vez de
1645
+ mirar la copia en memoria. `family` es una consulta asíncrona: si
1646
+ todavía no llegó, o si falló, `hijosDelProducto` vale 0 — o sea que
1647
+ «todavía no sé» se leía igual que «no tiene hijos», y el padre se
1648
+ guardaba sin ofrecer la propagación. En silencio, que es lo peor: el
1649
+ usuario creía haber bajado el cambio a los hijos.
1650
+ La ficha de la aplicación de clientes no tiene el problema porque ahí
1651
+ `state.product.variantsCount` viene del listado; aquí el producto sale
1652
+ del endpoint de reportes, que no trae el parentesco.
1653
+ */
1636
1654
  setPreparandoPropagacion(true);
1637
- loadFamily().then(function () {
1638
- return setPendingPropagation({
1639
- cambios: cambios
1640
- });
1641
- }).finally(function () {
1642
- return setPreparandoPropagacion(false);
1655
+ familia = null;
1656
+ _context8.prev = 15;
1657
+ _context8.next = 18;
1658
+ return loadFamily(true);
1659
+
1660
+ case 18:
1661
+ familia = _context8.sent;
1662
+
1663
+ case 19:
1664
+ _context8.prev = 19;
1665
+ setPreparandoPropagacion(false);
1666
+ return _context8.finish(19);
1667
+
1668
+ case 22:
1669
+ if (!(!familia || familia.error)) {
1670
+ _context8.next = 25;
1671
+ break;
1672
+ }
1673
+
1674
+ dispatch({
1675
+ type: "SET_MODAL",
1676
+ payload: {
1677
+ show: true,
1678
+ title: "No se pudo consultar la familia",
1679
+ message: "No pudimos saber si este producto tiene hijos, así que no sabemos si hay que bajarles el cambio. Vuelve a intentar el guardado; si sigue fallando, guarda y revisa los hijos a mano.",
1680
+ image: _genericModalWarning.default,
1681
+ buttons: [{
1682
+ text: "Entendido",
1683
+ buttonType: "general-white-button",
1684
+ action: function action() {
1685
+ return dispatch({
1686
+ type: "SET_MODAL",
1687
+ payload: {
1688
+ show: false
1689
+ }
1690
+ });
1691
+ }
1692
+ }, {
1693
+ text: "Guardar solo este producto",
1694
+ buttonType: "general-button-default",
1695
+ action: function action() {
1696
+ dispatch({
1697
+ type: "SET_MODAL",
1698
+ payload: {
1699
+ show: false
1700
+ }
1701
+ });
1702
+ saveDatasheets(token);
1703
+ }
1704
+ }]
1705
+ }
1643
1706
  });
1644
1707
  return _context8.abrupt("return");
1645
1708
 
1646
- case 14:
1647
- _context8.next = 16;
1709
+ case 25:
1710
+ hijos = ((_familia$variants = familia.variants) !== null && _familia$variants !== void 0 ? _familia$variants : []).filter(function (v) {
1711
+ return !v.isCurrent;
1712
+ });
1713
+
1714
+ if (!(hijos.length > 0)) {
1715
+ _context8.next = 29;
1716
+ break;
1717
+ }
1718
+
1719
+ setPendingPropagation({
1720
+ cambios: cambios
1721
+ });
1722
+ return _context8.abrupt("return");
1723
+
1724
+ case 29:
1725
+ _context8.next = 31;
1648
1726
  return saveDatasheets(token);
1649
1727
 
1650
- case 16:
1651
- return _context8.abrupt("break", 21);
1728
+ case 31:
1729
+ return _context8.abrupt("break", 36);
1652
1730
 
1653
- case 17:
1654
- _context8.next = 19;
1731
+ case 32:
1732
+ _context8.next = 34;
1655
1733
  return updateImages(token);
1656
1734
 
1657
- case 19:
1658
- return _context8.abrupt("break", 21);
1735
+ case 34:
1736
+ return _context8.abrupt("break", 36);
1659
1737
 
1660
- case 20:
1661
- return _context8.abrupt("break", 21);
1738
+ case 35:
1739
+ return _context8.abrupt("break", 36);
1662
1740
 
1663
- case 21:
1664
- _context8.next = 23;
1741
+ case 36:
1742
+ _context8.next = 38;
1665
1743
  return loadData(false);
1666
1744
 
1667
- case 23:
1745
+ case 38:
1668
1746
  case "end":
1669
1747
  return _context8.stop();
1670
1748
  }
1671
1749
  }
1672
- }, _callee8);
1750
+ }, _callee8, null, [[15,, 19, 22]]);
1673
1751
  }));
1674
1752
 
1675
1753
  return function handleOnClickSave() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contentoh-components-library",
3
- "version": "21.6.36",
3
+ "version": "21.6.37",
4
4
  "dependencies": {
5
5
  "@aws-amplify/auth": "^4.5.3",
6
6
  "@aws-amplify/datastore": "^3.11.0",
@@ -7,6 +7,10 @@ import { Container } from "./styles";
7
7
  *
8
8
  * El estado "propio" es el que carga información —ese campo se separó del padre—
9
9
  * así que es el que lleva acento y el que ofrece la acción de volver a heredar.
10
+ *
11
+ * OJO: "propio" ya NO significa "a salvo de la propagación". Desde el cambio del
12
+ * 2026-09-01 la propagación sobrescribe también estos valores; el aviso de que va
13
+ * a pasar vive en el diálogo de propagación, no aquí. El tooltip lo dice así.
10
14
  * "Heredado" es el caso normal y se mantiene discreto: si gritara en cada campo,
11
15
  * la ficha entera se volvería ruido.
12
16
  *
@@ -41,14 +45,20 @@ export const InheritanceTag = ({
41
45
  className="tag-label"
42
46
  title={
43
47
  isOverridden
44
- ? "Valor propio de este producto hijo. La propagación del padre no lo modifica."
48
+ ? "Valor capturado en este producto hijo, distinto al del padre. Si el padre propaga este atributo, se reemplaza."
45
49
  : `Valor heredado${parentUpc ? ` del producto ${parentUpc}` : " del producto padre"}.`
46
50
  }
47
51
  >
48
52
  {isOverridden ? "Propio" : "Heredado"}
49
53
  </span>
50
54
 
51
- {isOverridden && onRestore && (
55
+ {/* `Boolean`, no `isOverridden` a secas.
56
+
57
+ `is_overridden` llega como NÚMERO (0/1) desde la API y el reducer. Con
58
+ `{isOverridden && ...}`, un 0 se evalúa a 0 y React IMPRIME el texto
59
+ «0» — ese era el cero que aparecía en el hueco de la acción justo
60
+ después de pulsar «Volver a heredar», que es cuando el valor pasa a 0. */}
61
+ {Boolean(isOverridden) && onRestore && (
52
62
  <button type="button" className="tag-action" onClick={onRestore}>
53
63
  {restoreLabel}
54
64
  </button>
@@ -321,7 +321,9 @@ export const TagAndInput = ({
321
321
  className={"input-container"}
322
322
  key={`generalTagInput-${inputType}`}
323
323
  >
324
- {label?.length && (
324
+ {/* `Boolean`, no `label?.length`: con la etiqueta en cadena vacía la
325
+ expresión valía 0 y React imprimía un «0» en la ficha. */}
326
+ {Boolean(label?.length) && (
325
327
  <div className="title-container">
326
328
  <div className="titles">
327
329
  <ScreenHeader
@@ -46,7 +46,9 @@ export const TagAndInputv2 = ({
46
46
  className={"input-container"}
47
47
  key={`generalTagInput-${inputType}`}
48
48
  >
49
- {label?.length && (
49
+ {/* `Boolean`, no `label?.length`: con la etiqueta en cadena vacía la
50
+ expresión valía 0 y React imprimía un «0» en la ficha. */}
51
+ {Boolean(label?.length) && (
50
52
  <div className="title-container">
51
53
  <ScreenHeaderv2
52
54
  text={label}
@@ -21,7 +21,10 @@ import {
21
21
 
22
22
  props (* requerido):
23
23
  - *changedAttributes: [{ id, name, value }] lo que se acaba de editar
24
- - *variants: [{ articleId, name, upc }] los hijos activos del padre
24
+ - *variants: [{ articleId, name, upc, overriddenAttributes }] los hijos
25
+ activos del padre. `overriddenAttributes` son los atributos que ese hijo
26
+ capturó a mano; la propagación los sobrescribe, y este diálogo es el
27
+ único lugar donde el usuario puede enterarse antes de que pase.
25
28
  - *onCancel: cerrar sin guardar nada
26
29
  - *onConfirm: (propagation | null) => void
27
30
  null → guardar solo el padre
@@ -49,6 +52,31 @@ export const PropagateChangesModal = ({
49
52
  const puedePropagar = chosenAttributes.length > 0 && destinatarios > 0;
50
53
  const enSegundoPlano = destinatarios > UMBRAL_SEGUNDO_PLANO;
51
54
 
55
+ /*
56
+ A quién se le va a pisar un valor capturado a mano.
57
+
58
+ La propagación sobrescribe: eso se decidió a propósito, porque el usuario ya
59
+ eligió atributo por atributo y hijo por hijo. Pero sobrescribir en silencio
60
+ es otra cosa, y desde que se quitaron las etiquetas de «Heredado» y «Propio»
61
+ este diálogo es el único momento en que alguien puede saberlo.
62
+
63
+ Se recalcula con lo que está marcado ahora, no al abrir: si el usuario
64
+ desmarca el atributo conflictivo, el aviso desaparece — que es justo la
65
+ salida que el aviso debería estar ofreciendo.
66
+ */
67
+ const destinos = scope === "all"
68
+ ? variants
69
+ : variants.filter((item) => chosenChildren.includes(item.articleId));
70
+
71
+ const conValorPropio = destinos
72
+ .map((hijo) => ({
73
+ ...hijo,
74
+ pisados: (hijo.overriddenAttributes ?? []).filter((id) =>
75
+ chosenAttributes.includes(Number(id))
76
+ ),
77
+ }))
78
+ .filter((hijo) => hijo.pisados.length > 0);
79
+
52
80
  const toggleAttribute = (id) => {
53
81
  setChosenAttributes((current) =>
54
82
  current.includes(id)
@@ -155,13 +183,20 @@ export const PropagateChangesModal = ({
155
183
  </List>
156
184
  )}
157
185
 
158
- {/* La diferencia con "ligar", y la que sorprende si no se dice: aquí
159
- lo que el hijo editó a mano NO se pisa. */}
160
- <Note>
161
- Un hijo que haya editado alguno de estos atributos por su cuenta
162
- conserva su valor. Para devolverlo al del padre está la acción
163
- «Volver a heredar» en la ficha de ese hijo.
164
- </Note>
186
+ {/* Lo que sorprende si no se dice: aquí se pisa lo que el hijo
187
+ hubiera capturado a mano. Se nombra a quién, no solo cuántos: con
188
+ «2 hijos» nadie sabe si le importa, con los nombres sí. */}
189
+ {conValorPropio.length > 0 && (
190
+ <Note className="accent">
191
+ {conValorPropio.length === 1
192
+ ? "Un hijo tiene un valor propio en lo que elegiste y se va a reemplazar: "
193
+ : `${conValorPropio.length} hijos tienen valores propios en lo que elegiste y se van a reemplazar: `}
194
+ {conValorPropio
195
+ .map((hijo) => `${hijo.name || `Producto ${hijo.articleId}`} (${hijo.pisados.length})`)
196
+ .join(", ")}
197
+ . Si no quieres pisarlos, desmarca ese atributo o ese hijo.
198
+ </Note>
199
+ )}
165
200
 
166
201
  {enSegundoPlano && (
167
202
  <Note className="accent">
@@ -1131,17 +1131,73 @@ const RetailerProductEditionView = ({
1131
1131
  await saveDescriptions(token);
1132
1132
  break;
1133
1133
  case "Ficha técnica": {
1134
- // Guardar un padre con hijos abre la decisión de propagar. Sin este
1135
- // paso el cambio se queda solo en el padre y los hijos se van
1136
- // separando de él sin que nadie lo note.
1137
- const esPadre = hijosDelProducto > 0;
1138
1134
  const cambios = cambiosDeFichaTecnica();
1139
1135
 
1140
- if (esPadre && cambios.length > 0) {
1141
- setPreparandoPropagacion(true);
1142
- loadFamily()
1143
- .then(() => setPendingPropagation({ cambios }))
1144
- .finally(() => setPreparandoPropagacion(false));
1136
+ if (cambios.length === 0) {
1137
+ await saveDatasheets(token);
1138
+ break;
1139
+ }
1140
+
1141
+ /*
1142
+ Guardar un padre con hijos abre la decisión de propagar. Sin este paso
1143
+ el cambio se queda solo en el padre y los hijos se van separando de él
1144
+ sin que nadie lo note.
1145
+
1146
+ Si tiene hijos se resuelve AQUÍ, esperando la respuesta, en vez de
1147
+ mirar la copia en memoria. `family` es una consulta asíncrona: si
1148
+ todavía no llegó, o si falló, `hijosDelProducto` vale 0 — o sea que
1149
+ «todavía no sé» se leía igual que «no tiene hijos», y el padre se
1150
+ guardaba sin ofrecer la propagación. En silencio, que es lo peor: el
1151
+ usuario creía haber bajado el cambio a los hijos.
1152
+
1153
+ La ficha de la aplicación de clientes no tiene el problema porque ahí
1154
+ `state.product.variantsCount` viene del listado; aquí el producto sale
1155
+ del endpoint de reportes, que no trae el parentesco.
1156
+ */
1157
+ setPreparandoPropagacion(true);
1158
+ let familia = null;
1159
+ try {
1160
+ familia = await loadFamily(true);
1161
+ } finally {
1162
+ setPreparandoPropagacion(false);
1163
+ }
1164
+
1165
+ // No se pudo saber si tiene hijos. Guardar de todas formas repetiría el
1166
+ // defecto que se está corrigiendo, así que se dice y se deja la decisión.
1167
+ if (!familia || familia.error) {
1168
+ dispatch({
1169
+ type: "SET_MODAL",
1170
+ payload: {
1171
+ show: true,
1172
+ title: "No se pudo consultar la familia",
1173
+ message:
1174
+ "No pudimos saber si este producto tiene hijos, así que no sabemos si hay que bajarles el cambio. Vuelve a intentar el guardado; si sigue fallando, guarda y revisa los hijos a mano.",
1175
+ image: warningIcon,
1176
+ buttons: [
1177
+ {
1178
+ text: "Entendido",
1179
+ buttonType: "general-white-button",
1180
+ action: () =>
1181
+ dispatch({ type: "SET_MODAL", payload: { show: false } }),
1182
+ },
1183
+ {
1184
+ text: "Guardar solo este producto",
1185
+ buttonType: "general-button-default",
1186
+ action: () => {
1187
+ dispatch({ type: "SET_MODAL", payload: { show: false } });
1188
+ saveDatasheets(token);
1189
+ },
1190
+ },
1191
+ ],
1192
+ },
1193
+ });
1194
+ return;
1195
+ }
1196
+
1197
+ const hijos = (familia.variants ?? []).filter((v) => !v.isCurrent);
1198
+
1199
+ if (hijos.length > 0) {
1200
+ setPendingPropagation({ cambios });
1145
1201
  return;
1146
1202
  }
1147
1203