contentoh-components-library 21.6.51 → 21.6.53

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.
@@ -742,14 +742,64 @@ const ProviderProductEditionView = ({
742
742
  return soloPropagables(cambios);
743
743
  };
744
744
 
745
+ /*
746
+ Lo que se acaba de editar en la pestaña de descripciones.
747
+
748
+ Va aparte de `cambiosDeFichaTecnica` porque son tablas distintas y el
749
+ endpoint recibe una lista o la otra. Aquí NO se filtran UPC ni SKU: esos son
750
+ atributos de ficha técnica y no aparecen en esta pestaña.
751
+ */
752
+ const cambiosDeDescripciones = () => {
753
+ const retailerId = state.active_retailer?.id_retailer;
754
+ const inputs = state.services?.descriptions?.inputs ?? {};
755
+
756
+ return (state.updated_descriptions_inputs ?? []).map((item) => {
757
+ const input = inputs[`${item.attributeId}_${retailerId}`];
758
+ return {
759
+ id: Number(item.attributeId),
760
+ name: input?.name ?? `Descripción ${item.attributeId}`,
761
+ value: item.value,
762
+ };
763
+ });
764
+ };
765
+
766
+ /*
767
+ Destinos posibles para lo que se guarde en este producto: sus hijos y sus
768
+ compañeras de grupo. Un hijo no propaga a nadie.
769
+ */
770
+ const destinosPosibles = () => {
771
+ if (state.product?.parentArticleId) return 0;
772
+ const companeras = (variantGroup?.members ?? []).filter((m) => !m.isCurrent);
773
+ return (state.product?.variantsCount ?? 0) + companeras.length;
774
+ };
775
+
745
776
  const handleOnClickSave = () => {
746
777
  // `preparandoPropagacion` cubre la ventana entre el clic y la apertura del
747
778
  // diálogo: sin esto, dos clics seguidos lanzan dos consultas de familia.
748
779
  if (state.saving || preparandoPropagacion) return;
749
780
  switch (state.active_tab) {
750
- case "Descripción":
781
+ case "Descripción": {
782
+ /*
783
+ Guardar una descripción en un padre también abre la decisión de
784
+ propagar. Sin esto, el hijo heredaba la descripción al ligarse y se
785
+ quedaba con la versión vieja en cuanto el padre la corregía, sin que
786
+ nadie lo notara.
787
+ */
788
+ const cambiosDesc = cambiosDeDescripciones();
789
+
790
+ if (destinosPosibles() > 0 && cambiosDesc.length > 0) {
791
+ setPreparandoPropagacion(true);
792
+ loadFamily()
793
+ .then(() =>
794
+ setPendingPropagation({ cambios: cambiosDesc, kind: "description" })
795
+ )
796
+ .finally(() => setPreparandoPropagacion(false));
797
+ return;
798
+ }
799
+
751
800
  saveDescriptions(token);
752
801
  break;
802
+ }
753
803
  case "Ficha técnica": {
754
804
  // Guardar un padre con hijos abre la decisión de propagar. Sin este
755
805
  // paso el cambio se queda solo en el padre y los hijos se van
@@ -788,7 +838,7 @@ const ProviderProductEditionView = ({
788
838
  // justo lo contrario de lo que va a preguntar.
789
839
  setPreparandoPropagacion(true);
790
840
  loadFamily()
791
- .then(() => setPendingPropagation({ cambios }))
841
+ .then(() => setPendingPropagation({ cambios, kind: "datasheet" }))
792
842
  .finally(() => setPreparandoPropagacion(false));
793
843
  return;
794
844
  }
@@ -1686,6 +1736,7 @@ const ProviderProductEditionView = ({
1686
1736
  {pendingPropagation && (
1687
1737
  <PropagateChangesModal
1688
1738
  changedAttributes={pendingPropagation.cambios}
1739
+ kind={pendingPropagation.kind ?? "datasheet"}
1689
1740
  variants={
1690
1741
  state.product?.parentArticleId
1691
1742
  ? []
@@ -1698,8 +1749,29 @@ const ProviderProductEditionView = ({
1698
1749
  saving={state.saving}
1699
1750
  onCancel={() => setPendingPropagation(null)}
1700
1751
  onConfirm={(propagation) => {
1752
+ const esDescripcion = pendingPropagation.kind === "description";
1701
1753
  setPendingPropagation(null);
1702
- saveDatasheets(token, propagation ?? undefined);
1754
+
1755
+ if (!propagation) {
1756
+ // Guardar sin propagar: el producto se guarda solo.
1757
+ if (esDescripcion) saveDescriptions(token);
1758
+ else saveDatasheets(token);
1759
+ return;
1760
+ }
1761
+
1762
+ /*
1763
+ El diálogo habla de «atributos» porque es el mismo componente
1764
+ para las dos pestañas. Al guardar hay que ponerlo en la lista
1765
+ que corresponde: el servidor recibe `attributes` o
1766
+ `descriptions`, nunca una por la otra.
1767
+ */
1768
+ const { attributes, ...destinos } = propagation;
1769
+
1770
+ if (esDescripcion) {
1771
+ saveDescriptions(token, { ...destinos, descriptions: attributes });
1772
+ } else {
1773
+ saveDatasheets(token, propagation);
1774
+ }
1703
1775
  }}
1704
1776
  />
1705
1777
  )}
@@ -34,7 +34,7 @@ const ProductEditionContext = createContext();
34
34
  export const ProviderProductEditionProvider = ({ children }) => {
35
35
  const [state, dispatch] = useReducer(productEditionReducer, initialState);
36
36
 
37
- const saveDescriptions = async (token) => {
37
+ const saveDescriptions = async (token, propagation) => {
38
38
  if (state.updated_descriptions_inputs.length === 0) return;
39
39
 
40
40
  dispatch({ type: "SET_SAVING", payload: true });
@@ -42,6 +42,7 @@ export const ProviderProductEditionProvider = ({ children }) => {
42
42
  const dataObject = {
43
43
  articleId: state.product?.id_article,
44
44
  articleData: state.updated_descriptions_inputs,
45
+ ...(propagation ? { propagation } : {}),
45
46
  };
46
47
 
47
48
  // console.log({dataObject});
@@ -1270,13 +1270,68 @@ const RetailerProductEditionView = ({
1270
1270
  return soloPropagables(cambios);
1271
1271
  };
1272
1272
 
1273
+ /*
1274
+ Lo que se acaba de editar en la pestaña de descripciones.
1275
+
1276
+ Va aparte de `cambiosDeFichaTecnica` porque son tablas distintas y el
1277
+ endpoint recibe una lista o la otra. Aquí NO se filtran UPC ni SKU: esos son
1278
+ atributos de ficha técnica y no aparecen en esta pestaña.
1279
+ */
1280
+ const cambiosDeDescripciones = () => {
1281
+ const retailerId = state.active_retailer?.id_retailer;
1282
+ const inputs = state.services?.descriptions?.inputs ?? {};
1283
+
1284
+ return (state.updated_descriptions_inputs ?? []).map((item) => {
1285
+ const input = inputs[`${item.attributeId}_${retailerId}`];
1286
+ return {
1287
+ id: Number(item.attributeId),
1288
+ name: input?.name ?? `Descripción ${item.attributeId}`,
1289
+ value: item.value,
1290
+ };
1291
+ });
1292
+ };
1293
+
1273
1294
  const handleOnClickSave = async () => {
1274
1295
  if (state.saving || preparandoPropagacion) return;
1275
1296
 
1276
1297
  switch (state.active_tab) {
1277
- case "Descripción":
1298
+ case "Descripción": {
1299
+ /*
1300
+ Guardar una descripción en un padre también abre la decisión de
1301
+ propagar. Sin esto, el hijo heredaba la descripción al ligarse y se
1302
+ quedaba con la versión vieja en cuanto el padre la corregía, sin que
1303
+ nadie lo notara.
1304
+ */
1305
+ const cambiosDesc = cambiosDeDescripciones();
1306
+ const companerasDesc = (variantGroup?.members ?? []).filter(
1307
+ (m) => !m.isCurrent
1308
+ );
1309
+
1310
+ if (esHijoDeOtro || cambiosDesc.length === 0) {
1311
+ await saveDescriptions(token);
1312
+ break;
1313
+ }
1314
+
1315
+ setPreparandoPropagacion(true);
1316
+ let familiaDesc = null;
1317
+ try {
1318
+ familiaDesc = await loadFamily(true);
1319
+ } finally {
1320
+ setPreparandoPropagacion(false);
1321
+ }
1322
+
1323
+ const hijosDesc = (familiaDesc?.variants ?? []).filter(
1324
+ (v) => !v.isCurrent
1325
+ );
1326
+
1327
+ if (hijosDesc.length > 0 || companerasDesc.length > 0) {
1328
+ setPendingPropagation({ cambios: cambiosDesc, kind: "description" });
1329
+ return;
1330
+ }
1331
+
1278
1332
  await saveDescriptions(token);
1279
1333
  break;
1334
+ }
1280
1335
  case "Ficha técnica": {
1281
1336
  const cambios = cambiosDeFichaTecnica();
1282
1337
 
@@ -1368,7 +1423,7 @@ const RetailerProductEditionView = ({
1368
1423
  // Un hijo tampoco puede estar agrupado desde 2026-09-25, así que para
1369
1424
  // él no queda ningún destino posible.
1370
1425
  if (!esHijo && (hijos.length > 0 || companeras.length > 0)) {
1371
- setPendingPropagation({ cambios });
1426
+ setPendingPropagation({ cambios, kind: "datasheet" });
1372
1427
  return;
1373
1428
  }
1374
1429
 
@@ -2131,6 +2186,7 @@ const RetailerProductEditionView = ({
2131
2186
  {pendingPropagation && (
2132
2187
  <PropagateChangesModal
2133
2188
  changedAttributes={pendingPropagation.cambios}
2189
+ kind={pendingPropagation.kind ?? "datasheet"}
2134
2190
  variants={
2135
2191
  esHijoDeOtro
2136
2192
  ? []
@@ -2143,8 +2199,28 @@ const RetailerProductEditionView = ({
2143
2199
  saving={state.saving}
2144
2200
  onCancel={() => setPendingPropagation(null)}
2145
2201
  onConfirm={(propagation) => {
2202
+ const esDescripcion = pendingPropagation.kind === "description";
2146
2203
  setPendingPropagation(null);
2147
- saveDatasheets(token, propagation ?? undefined);
2204
+
2205
+ if (!propagation) {
2206
+ if (esDescripcion) saveDescriptions(token);
2207
+ else saveDatasheets(token);
2208
+ return;
2209
+ }
2210
+
2211
+ /*
2212
+ El diálogo habla de «atributos» porque es el mismo componente
2213
+ para las dos pestañas. Al guardar hay que ponerlo en la lista
2214
+ que corresponde: el servidor recibe `attributes` o
2215
+ `descriptions`, nunca una por la otra.
2216
+ */
2217
+ const { attributes, ...destinos } = propagation;
2218
+
2219
+ if (esDescripcion) {
2220
+ saveDescriptions(token, { ...destinos, descriptions: attributes });
2221
+ } else {
2222
+ saveDatasheets(token, propagation);
2223
+ }
2148
2224
  }}
2149
2225
  />
2150
2226
  )}