contentoh-components-library 21.6.27 → 21.6.28
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/components/organisms/PropagateChangesModal/index.js +213 -0
- package/dist/components/organisms/PropagateChangesModal/styles.js +53 -0
- package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.context.js +16 -7
- package/dist/components/pages/ProviderProductEdition/index.js +132 -56
- package/dist/index.js +25 -12
- package/package.json +1 -1
- package/src/components/organisms/PropagateChangesModal/index.js +209 -0
- package/src/components/organisms/PropagateChangesModal/styles.js +184 -0
- package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx +9 -1
- package/src/components/pages/ProviderProductEdition/index.js +114 -34
- package/src/index.js +1 -0
|
@@ -9,7 +9,11 @@ import {
|
|
|
9
9
|
useProviderProductEdition,
|
|
10
10
|
} from "./context/provider-product-edition.context";
|
|
11
11
|
import { normalizeProduct, getConceptByTab } from "./utils";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
getMinorStatus,
|
|
14
|
+
getMinorStatusFromRetailerMap,
|
|
15
|
+
STATUS_DICTIONARY,
|
|
16
|
+
} from "../../../global-files/statusDictionary";
|
|
13
17
|
|
|
14
18
|
import {
|
|
15
19
|
getPercentage,
|
|
@@ -35,6 +39,7 @@ import { ImageDataTable } from "../../organisms/ImageDataTable";
|
|
|
35
39
|
import { ImagePreviewer } from "../../organisms/ImagePreviewer";
|
|
36
40
|
import { InputGroup } from "../../organisms/InputGroup";
|
|
37
41
|
import { LinkVariantsModal } from "../../organisms/LinkVariantsModal";
|
|
42
|
+
import { PropagateChangesModal } from "../../organisms/PropagateChangesModal";
|
|
38
43
|
import { readPayload } from "../../organisms/LinkVariantsModal/api";
|
|
39
44
|
import { ProductImageModal } from "../../organisms/ProductImageModal";
|
|
40
45
|
import { VersionSelector } from "../../organisms/VersionSelector";
|
|
@@ -79,6 +84,8 @@ const ProviderProductEditionView = ({
|
|
|
79
84
|
const [family, setFamily] = useState(null);
|
|
80
85
|
const [showFamily, setShowFamily] = useState(false);
|
|
81
86
|
const [loadingVariant, setLoadingVariant] = useState(null);
|
|
87
|
+
const [pendingPropagation, setPendingPropagation] = useState(null);
|
|
88
|
+
const [preparandoPropagacion, setPreparandoPropagacion] = useState(false);
|
|
82
89
|
const [showRejectModal, setShowRejectModal] = useState(false);
|
|
83
90
|
const [headerTop, setHeaderTop] = useState(0);
|
|
84
91
|
const [assig, setAssig] = useState({});
|
|
@@ -233,7 +240,7 @@ const ProviderProductEditionView = ({
|
|
|
233
240
|
id_category,
|
|
234
241
|
version,
|
|
235
242
|
token,
|
|
236
|
-
id_retailer
|
|
243
|
+
id_retailer
|
|
237
244
|
),
|
|
238
245
|
getPercentage({ data, headers }),
|
|
239
246
|
getServicesData({
|
|
@@ -245,11 +252,10 @@ const ProviderProductEditionView = ({
|
|
|
245
252
|
]);
|
|
246
253
|
|
|
247
254
|
const percentageRaw = percentageRes?.[0];
|
|
248
|
-
const percentages =
|
|
249
|
-
Array.isArray(percentageRaw)
|
|
255
|
+
const percentages =
|
|
256
|
+
(Array.isArray(percentageRaw)
|
|
250
257
|
? percentageRaw[0]?.relations
|
|
251
|
-
: JSON.parse(percentageRaw?.body ?? "null")?.[0]?.relations
|
|
252
|
-
) ?? [];
|
|
258
|
+
: JSON.parse(percentageRaw?.body ?? "null")?.[0]?.relations) ?? [];
|
|
253
259
|
|
|
254
260
|
const orderMap =
|
|
255
261
|
services[2].inputsByRetailer ??
|
|
@@ -277,12 +283,16 @@ const ProviderProductEditionView = ({
|
|
|
277
283
|
|
|
278
284
|
return acc;
|
|
279
285
|
},
|
|
280
|
-
{}
|
|
286
|
+
{}
|
|
281
287
|
);
|
|
282
288
|
|
|
283
289
|
const getServiceMinorStatus = (serviceName) => {
|
|
284
|
-
const records = servicesDataRes.filter(
|
|
285
|
-
|
|
290
|
+
const records = servicesDataRes.filter(
|
|
291
|
+
(s) => s.service === serviceName
|
|
292
|
+
);
|
|
293
|
+
return records.length > 0
|
|
294
|
+
? getMinorStatus(records.map((s) => s.status))
|
|
295
|
+
: undefined;
|
|
286
296
|
};
|
|
287
297
|
|
|
288
298
|
const imagesMinorStatus = getServiceMinorStatus("images");
|
|
@@ -295,9 +305,15 @@ const ProviderProductEditionView = ({
|
|
|
295
305
|
...state.product,
|
|
296
306
|
statusByRetailer: updatedStatusByRetailer,
|
|
297
307
|
status: getMinorStatusFromRetailerMap(updatedStatusByRetailer),
|
|
298
|
-
...(imagesMinorStatus !== undefined && {
|
|
299
|
-
|
|
300
|
-
|
|
308
|
+
...(imagesMinorStatus !== undefined && {
|
|
309
|
+
images_status: imagesMinorStatus,
|
|
310
|
+
}),
|
|
311
|
+
...(descriptionMinorStatus !== undefined && {
|
|
312
|
+
description_status: descriptionMinorStatus,
|
|
313
|
+
}),
|
|
314
|
+
...(datasheetMinorStatus !== undefined && {
|
|
315
|
+
datasheet_status: datasheetMinorStatus,
|
|
316
|
+
}),
|
|
301
317
|
},
|
|
302
318
|
});
|
|
303
319
|
|
|
@@ -320,7 +336,7 @@ const ProviderProductEditionView = ({
|
|
|
320
336
|
const activePercentage =
|
|
321
337
|
percentages.find(({ id_retailer: rId }) => rId === id_retailer) ||
|
|
322
338
|
state.product.percentages?.find(
|
|
323
|
-
({ id_retailer: rId }) => rId === id_retailer
|
|
339
|
+
({ id_retailer: rId }) => rId === id_retailer
|
|
324
340
|
);
|
|
325
341
|
|
|
326
342
|
dispatch({
|
|
@@ -364,7 +380,10 @@ const ProviderProductEditionView = ({
|
|
|
364
380
|
};
|
|
365
381
|
dispatch({
|
|
366
382
|
type: "SET_DATASHEETS_INPUTS",
|
|
367
|
-
payload: [
|
|
383
|
+
payload: [
|
|
384
|
+
datasheetsActiveRetailer,
|
|
385
|
+
state.services.datasheets.inputs,
|
|
386
|
+
],
|
|
368
387
|
});
|
|
369
388
|
} else {
|
|
370
389
|
dispatch({ type: "SET_DATASHEETS_INPUTS", payload: [] });
|
|
@@ -373,7 +392,7 @@ const ProviderProductEditionView = ({
|
|
|
373
392
|
|
|
374
393
|
if (state.services.descriptions) {
|
|
375
394
|
const descriptionsActiveRetailer = state.services.descriptions.filter(
|
|
376
|
-
(item) => item.id === state.active_retailer.id_retailer
|
|
395
|
+
(item) => item.id === state.active_retailer.id_retailer
|
|
377
396
|
);
|
|
378
397
|
|
|
379
398
|
dispatch({
|
|
@@ -388,8 +407,8 @@ const ProviderProductEditionView = ({
|
|
|
388
407
|
retailerInput.some(
|
|
389
408
|
(input) =>
|
|
390
409
|
input.id_retailer === state.active_retailer.id_retailer &&
|
|
391
|
-
input.id_image === value.image_id
|
|
392
|
-
)
|
|
410
|
+
input.id_image === value.image_id
|
|
411
|
+
)
|
|
393
412
|
);
|
|
394
413
|
});
|
|
395
414
|
|
|
@@ -419,7 +438,7 @@ const ProviderProductEditionView = ({
|
|
|
419
438
|
const { status: currentStatus } = state.services_data.find(
|
|
420
439
|
(service) =>
|
|
421
440
|
service.service === currentService &&
|
|
422
|
-
service.id_retailer === currentRetailer
|
|
441
|
+
service.id_retailer === currentRetailer
|
|
423
442
|
);
|
|
424
443
|
|
|
425
444
|
const originTab = origin[state.active_tab];
|
|
@@ -488,7 +507,7 @@ const ProviderProductEditionView = ({
|
|
|
488
507
|
name: e?.name,
|
|
489
508
|
required: e?.required,
|
|
490
509
|
active: state.images_values?.values?.some(
|
|
491
|
-
(value) => value?.image_id === e?.id
|
|
510
|
+
(value) => value?.image_id === e?.id
|
|
492
511
|
),
|
|
493
512
|
}));
|
|
494
513
|
const imageType = state.images_values?.imageType?.map((e) => ({
|
|
@@ -499,7 +518,7 @@ const ProviderProductEditionView = ({
|
|
|
499
518
|
(e) => ({
|
|
500
519
|
value: e?.id,
|
|
501
520
|
name: e?.name,
|
|
502
|
-
})
|
|
521
|
+
})
|
|
503
522
|
);
|
|
504
523
|
|
|
505
524
|
return state.images_values?.values?.map((image, index) => (
|
|
@@ -658,15 +677,56 @@ const ProviderProductEditionView = ({
|
|
|
658
677
|
});
|
|
659
678
|
};
|
|
660
679
|
|
|
680
|
+
/*
|
|
681
|
+
Los atributos que se acaban de tocar, con el nombre que ve el usuario.
|
|
682
|
+
|
|
683
|
+
`updated_datasheets_inputs` trae { attributeId, value } y nada más, así que el
|
|
684
|
+
nombre se busca en los inputs de la cadena activa: un diálogo que preguntara
|
|
685
|
+
por "el atributo 1023" no serviría para decidir nada.
|
|
686
|
+
*/
|
|
687
|
+
const cambiosDeFichaTecnica = () => {
|
|
688
|
+
const retailerId = state.active_retailer?.id_retailer;
|
|
689
|
+
const inputs = state.services?.datasheets?.inputs ?? {};
|
|
690
|
+
|
|
691
|
+
return (state.updated_datasheets_inputs ?? []).map((item) => {
|
|
692
|
+
const input = inputs[`${item.attributeId}_${retailerId}`];
|
|
693
|
+
return {
|
|
694
|
+
id: Number(item.attributeId),
|
|
695
|
+
name: input?.name ?? `Atributo ${item.attributeId}`,
|
|
696
|
+
value: item.value,
|
|
697
|
+
};
|
|
698
|
+
});
|
|
699
|
+
};
|
|
700
|
+
|
|
661
701
|
const handleOnClickSave = () => {
|
|
662
|
-
|
|
702
|
+
// `preparandoPropagacion` cubre la ventana entre el clic y la apertura del
|
|
703
|
+
// diálogo: sin esto, dos clics seguidos lanzan dos consultas de familia.
|
|
704
|
+
if (state.saving || preparandoPropagacion) return;
|
|
663
705
|
switch (state.active_tab) {
|
|
664
706
|
case "Descripción":
|
|
665
707
|
saveDescriptions(token);
|
|
666
708
|
break;
|
|
667
|
-
case "Ficha técnica":
|
|
709
|
+
case "Ficha técnica": {
|
|
710
|
+
// Guardar un padre con variantes abre la decisión de propagar. Sin este
|
|
711
|
+
// paso el cambio se queda solo en el padre y las variantes se van
|
|
712
|
+
// separando de él sin que nadie lo note.
|
|
713
|
+
const esPadre = state.product?.variantsCount > 0;
|
|
714
|
+
const cambios = cambiosDeFichaTecnica();
|
|
715
|
+
|
|
716
|
+
if (esPadre && cambios.length > 0) {
|
|
717
|
+
// Se espera a tener la familia antes de abrir: si no, el diálogo
|
|
718
|
+
// aparece diciendo "0 variantes" hasta que llega la respuesta, que es
|
|
719
|
+
// justo lo contrario de lo que va a preguntar.
|
|
720
|
+
setPreparandoPropagacion(true);
|
|
721
|
+
loadFamily()
|
|
722
|
+
.then(() => setPendingPropagation({ cambios }))
|
|
723
|
+
.finally(() => setPreparandoPropagacion(false));
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
|
|
668
727
|
saveDatasheets(token);
|
|
669
728
|
break;
|
|
729
|
+
}
|
|
670
730
|
case "Imágenes":
|
|
671
731
|
updateImages(token);
|
|
672
732
|
break;
|
|
@@ -709,7 +769,7 @@ const ProviderProductEditionView = ({
|
|
|
709
769
|
peso que paga todo el mundo por el caso de unos pocos.
|
|
710
770
|
*/
|
|
711
771
|
const loadFamily = async () => {
|
|
712
|
-
if (family) return;
|
|
772
|
+
if (family) return family;
|
|
713
773
|
try {
|
|
714
774
|
const res = await axios.post(
|
|
715
775
|
`${process.env.REACT_APP_VARIANTS_ENDPOINT}/family`,
|
|
@@ -853,7 +913,10 @@ const ProviderProductEditionView = ({
|
|
|
853
913
|
try {
|
|
854
914
|
const res = await axios.post(
|
|
855
915
|
`${process.env.REACT_APP_VARIANTS_ENDPOINT}/restore`,
|
|
856
|
-
{
|
|
916
|
+
{
|
|
917
|
+
articleId: state.product.id_article,
|
|
918
|
+
attributes: [Number(attributeId)],
|
|
919
|
+
},
|
|
857
920
|
{ headers: { Authorization: token } }
|
|
858
921
|
);
|
|
859
922
|
|
|
@@ -929,7 +992,7 @@ const ProviderProductEditionView = ({
|
|
|
929
992
|
headers: {
|
|
930
993
|
Authorization: token,
|
|
931
994
|
},
|
|
932
|
-
}
|
|
995
|
+
}
|
|
933
996
|
);
|
|
934
997
|
|
|
935
998
|
const newStatuses = JSON.parse(res.data.body);
|
|
@@ -1180,10 +1243,13 @@ const ProviderProductEditionView = ({
|
|
|
1180
1243
|
const isProvider = !user.is_retailer;
|
|
1181
1244
|
state.services_data?.forEach((ret) => {
|
|
1182
1245
|
const { service, id_retailer } = ret;
|
|
1183
|
-
const currentEvalStatus =
|
|
1246
|
+
const currentEvalStatus =
|
|
1247
|
+
state.product.statusByRetailer[id_retailer]?.[service];
|
|
1184
1248
|
|
|
1185
|
-
if (isProvider && currentEvalStatus !== STATUS_DICTIONARY.AA.status)
|
|
1186
|
-
|
|
1249
|
+
if (isProvider && currentEvalStatus !== STATUS_DICTIONARY.AA.status)
|
|
1250
|
+
return;
|
|
1251
|
+
if (!isProvider && currentEvalStatus !== STATUS_DICTIONARY.AP.status)
|
|
1252
|
+
return;
|
|
1187
1253
|
|
|
1188
1254
|
const data = {
|
|
1189
1255
|
...dataGeneral,
|
|
@@ -1196,7 +1262,7 @@ const ProviderProductEditionView = ({
|
|
|
1196
1262
|
headers: {
|
|
1197
1263
|
Authorization: token,
|
|
1198
1264
|
},
|
|
1199
|
-
})
|
|
1265
|
+
})
|
|
1200
1266
|
);
|
|
1201
1267
|
});
|
|
1202
1268
|
|
|
@@ -1244,7 +1310,7 @@ const ProviderProductEditionView = ({
|
|
|
1244
1310
|
ArticleId: updatedProduct.id_article,
|
|
1245
1311
|
idCategory: updatedProduct.id_category,
|
|
1246
1312
|
product: updatedProduct,
|
|
1247
|
-
})
|
|
1313
|
+
})
|
|
1248
1314
|
);
|
|
1249
1315
|
|
|
1250
1316
|
// Mostrar modal de éxito
|
|
@@ -1323,6 +1389,18 @@ const ProviderProductEditionView = ({
|
|
|
1323
1389
|
jwt={token}
|
|
1324
1390
|
/>
|
|
1325
1391
|
)}
|
|
1392
|
+
{pendingPropagation && (
|
|
1393
|
+
<PropagateChangesModal
|
|
1394
|
+
changedAttributes={pendingPropagation.cambios}
|
|
1395
|
+
variants={(family?.variants ?? []).filter((v) => !v.isCurrent)}
|
|
1396
|
+
saving={state.saving}
|
|
1397
|
+
onCancel={() => setPendingPropagation(null)}
|
|
1398
|
+
onConfirm={(propagation) => {
|
|
1399
|
+
setPendingPropagation(null);
|
|
1400
|
+
saveDatasheets(token, propagation ?? undefined);
|
|
1401
|
+
}}
|
|
1402
|
+
/>
|
|
1403
|
+
)}
|
|
1326
1404
|
{showLinkVariants && (
|
|
1327
1405
|
<LinkVariantsModal
|
|
1328
1406
|
articleId={state.product?.id_article}
|
|
@@ -1418,7 +1496,7 @@ const ProviderProductEditionView = ({
|
|
|
1418
1496
|
size={12}
|
|
1419
1497
|
onClick={async () => {
|
|
1420
1498
|
const elements = document.querySelectorAll(
|
|
1421
|
-
"#modal-message-box .ql-container .ql-editor > p"
|
|
1499
|
+
"#modal-message-box .ql-container .ql-editor > p"
|
|
1422
1500
|
);
|
|
1423
1501
|
|
|
1424
1502
|
if (!elements || elements.length === 0) {
|
|
@@ -1435,7 +1513,7 @@ const ProviderProductEditionView = ({
|
|
|
1435
1513
|
|
|
1436
1514
|
if (isMessageEmpty) {
|
|
1437
1515
|
const container = document.querySelector(
|
|
1438
|
-
".container-customComponent"
|
|
1516
|
+
".container-customComponent"
|
|
1439
1517
|
);
|
|
1440
1518
|
const existingAlert =
|
|
1441
1519
|
container.querySelector(".alert-error");
|
|
@@ -1601,7 +1679,9 @@ const ProviderProductEditionView = ({
|
|
|
1601
1679
|
<button
|
|
1602
1680
|
key={variant.articleId}
|
|
1603
1681
|
type="button"
|
|
1604
|
-
className={`family-row${
|
|
1682
|
+
className={`family-row${
|
|
1683
|
+
variant.isCurrent ? " current" : ""
|
|
1684
|
+
}`}
|
|
1605
1685
|
disabled={variant.isCurrent || loadingVariant !== null}
|
|
1606
1686
|
onClick={() => openVariant(variant.articleId)}
|
|
1607
1687
|
>
|
|
@@ -1754,7 +1834,7 @@ const ProviderProductEditionView = ({
|
|
|
1754
1834
|
handleOnUpdateApprovedInputs
|
|
1755
1835
|
}
|
|
1756
1836
|
/>
|
|
1757
|
-
)
|
|
1837
|
+
)
|
|
1758
1838
|
)
|
|
1759
1839
|
) : (
|
|
1760
1840
|
<ScreenHeader
|
package/src/index.js
CHANGED
|
@@ -88,6 +88,7 @@ export * from "./components/organisms/ImagePreviewer/index";
|
|
|
88
88
|
export * from "./components/organisms/ImagesGroup/index";
|
|
89
89
|
export * from "./components/organisms/InputGroup/index";
|
|
90
90
|
export * from "./components/organisms/LinkVariantsModal/index";
|
|
91
|
+
export * from "./components/organisms/PropagateChangesModal/index";
|
|
91
92
|
export * from "./components/organisms/ProductImageModal/index";
|
|
92
93
|
export * from "./components/organisms/Chat/index";
|
|
93
94
|
export * from "./components/organisms/Modal/index";
|