contentoh-components-library 21.6.24 → 21.6.26
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/molecules/SingleSelect/index.js +198 -0
- package/dist/components/molecules/SingleSelect/styles.js +74 -0
- package/dist/components/organisms/LinkVariantsModal/index.js +193 -154
- package/dist/components/organisms/LinkVariantsModal/styles.js +26 -16
- package/dist/components/pages/ProviderProductEdition/styles.js +4 -1
- package/dist/index.js +43 -30
- package/package.json +1 -1
- package/src/components/molecules/SingleSelect/index.js +183 -0
- package/src/components/molecules/SingleSelect/styles.js +132 -0
- package/src/components/organisms/LinkVariantsModal/index.js +224 -143
- package/src/components/organisms/LinkVariantsModal/styles.js +71 -67
- package/src/components/pages/ProviderProductEdition/styles.js +6 -3
- package/src/index.js +1 -0
|
@@ -2,10 +2,8 @@ import { useCallback, useEffect, useMemo, useState } from "react";
|
|
|
2
2
|
import axios from "axios";
|
|
3
3
|
|
|
4
4
|
import { readPayload, ApiError } from "./api";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
getRetailerPicture,
|
|
8
|
-
} from "../../../_utils/helper";
|
|
5
|
+
import { SingleSelect } from "../../molecules/SingleSelect";
|
|
6
|
+
import { getProductImage, getRetailerPicture } from "../../../_utils/helper";
|
|
9
7
|
|
|
10
8
|
import {
|
|
11
9
|
Overlay,
|
|
@@ -130,11 +128,27 @@ export const LinkVariantsModal = ({
|
|
|
130
128
|
cuatro decisiones por producto. Al desmarcarlo aparecen las pestañas y cada
|
|
131
129
|
producto guarda su propia selección en `perChild`.
|
|
132
130
|
*/
|
|
133
|
-
|
|
131
|
+
// Desmarcado a propósito: aplicar la misma herencia a varios productos es una
|
|
132
|
+
// decisión, no un valor por omisión. Marcado de entrada se ligaban todos igual
|
|
133
|
+
// sin que nadie lo hubiera elegido.
|
|
134
|
+
const [applyToAll, setApplyToAll] = useState(false);
|
|
134
135
|
const [activeChild, setActiveChild] = useState(null);
|
|
135
136
|
const [perChild, setPerChild] = useState({});
|
|
136
137
|
|
|
137
138
|
// Cadenas que el padre NO tiene y el usuario decidió agregar a la variante.
|
|
139
|
+
/*
|
|
140
|
+
Imágenes que la base lista pero cuyo archivo no está en S3.
|
|
141
|
+
|
|
142
|
+
Pasa: hay filas de rel_article_image con un src válido que apunta a un objeto
|
|
143
|
+
que ya no existe —comprobado, CloudFront responde 404—. Sin esto el paso 4
|
|
144
|
+
muestra una tarjeta rota, con el texto alternativo donde debería ir la foto, y
|
|
145
|
+
deja marcar para heredar algo que no se puede heredar.
|
|
146
|
+
|
|
147
|
+
No se puede saber desde el servidor sin ir a S3 por cada imagen, así que se
|
|
148
|
+
detecta al fallar la carga y se descuenta de la lista y del conteo.
|
|
149
|
+
*/
|
|
150
|
+
const [brokenImages, setBrokenImages] = useState([]);
|
|
151
|
+
|
|
138
152
|
const [extraRetailers, setExtraRetailers] = useState([]);
|
|
139
153
|
const [newRetailer, setNewRetailer] = useState("");
|
|
140
154
|
const [newDepartment, setNewDepartment] = useState("");
|
|
@@ -277,8 +291,9 @@ export const LinkVariantsModal = ({
|
|
|
277
291
|
images: null,
|
|
278
292
|
});
|
|
279
293
|
setExtraRetailers([]);
|
|
294
|
+
setBrokenImages([]);
|
|
280
295
|
setPerChild({});
|
|
281
|
-
setApplyToAll(
|
|
296
|
+
setApplyToAll(false);
|
|
282
297
|
setActiveChild(mode === "children" ? selected[0] : null);
|
|
283
298
|
setStep("inherit");
|
|
284
299
|
} catch (err) {
|
|
@@ -315,20 +330,25 @@ export const LinkVariantsModal = ({
|
|
|
315
330
|
setLoadingFilters(true);
|
|
316
331
|
try {
|
|
317
332
|
const res = await axios.get(
|
|
318
|
-
`${filtersEndpoint}?retailerSelected=${
|
|
319
|
-
|
|
320
|
-
}`,
|
|
333
|
+
`${filtersEndpoint}?retailerSelected=${
|
|
334
|
+
retailer ?? ""
|
|
335
|
+
}&departmentSelected=${department ?? ""}`,
|
|
321
336
|
{ headers: { Authorization: token } }
|
|
322
337
|
);
|
|
323
338
|
|
|
324
|
-
|
|
325
|
-
|
|
339
|
+
// readPayload YA devuelve el cuerpo parseado. Volver a buscar `body`
|
|
340
|
+
// dentro dejaba la lista siempre vacía, y por eso el selector de cadenas
|
|
341
|
+
// no mostraba nada.
|
|
342
|
+
const lista = readPayload(res)?.data ?? [];
|
|
326
343
|
|
|
327
344
|
setFilters((current) => {
|
|
328
345
|
if (!retailer) {
|
|
329
346
|
return {
|
|
330
347
|
...current,
|
|
331
|
-
retailers: lista.map((item) => ({
|
|
348
|
+
retailers: lista.map((item) => ({
|
|
349
|
+
value: item.id,
|
|
350
|
+
label: item.name,
|
|
351
|
+
})),
|
|
332
352
|
};
|
|
333
353
|
}
|
|
334
354
|
if (!department) {
|
|
@@ -341,9 +361,16 @@ export const LinkVariantsModal = ({
|
|
|
341
361
|
categories: [],
|
|
342
362
|
};
|
|
343
363
|
}
|
|
364
|
+
// El tercer nivel no viene como {id, name} sino como
|
|
365
|
+
// {category_id, subcategory}: con el mapeo de los otros dos, la
|
|
366
|
+
// categoría salía en la lista pero sin texto. Mismo criterio que usa
|
|
367
|
+
// el alta de productos, incluido el separador legible.
|
|
344
368
|
return {
|
|
345
369
|
...current,
|
|
346
|
-
categories: lista.map((item) => ({
|
|
370
|
+
categories: lista.map((item) => ({
|
|
371
|
+
value: item.category_id,
|
|
372
|
+
label: (item.subcategory ?? "").replace("|", " > "),
|
|
373
|
+
})),
|
|
347
374
|
};
|
|
348
375
|
});
|
|
349
376
|
} catch (error) {
|
|
@@ -412,6 +439,12 @@ export const LinkVariantsModal = ({
|
|
|
412
439
|
Las parejas cadena+categoría viajan como objetos, no como ids, porque pueden
|
|
413
440
|
ser cadenas que el padre no tiene: ahí no hay nada que heredar, se asigna.
|
|
414
441
|
*/
|
|
442
|
+
// Las que de verdad se pueden heredar: la base puede listar filas cuyo archivo
|
|
443
|
+
// ya no existe, y esas no cuentan ni para la lista ni para el "todas".
|
|
444
|
+
const imagenesUtiles = offered.images.filter(
|
|
445
|
+
(image) => !brokenImages.includes(image.id)
|
|
446
|
+
);
|
|
447
|
+
|
|
415
448
|
const buildInherit = (seleccion) => {
|
|
416
449
|
const parejas = [
|
|
417
450
|
...offered.categoryRetailers.map((item) => ({
|
|
@@ -431,7 +464,8 @@ export const LinkVariantsModal = ({
|
|
|
431
464
|
seleccion.modes.descriptions === "all"
|
|
432
465
|
? "all"
|
|
433
466
|
: seleccion.chosen.descriptions,
|
|
434
|
-
images:
|
|
467
|
+
images:
|
|
468
|
+
seleccion.modes.images === "all" ? "all" : seleccion.chosen.images,
|
|
435
469
|
categoryRetailers: parejas
|
|
436
470
|
.filter((par) => seleccion.chosen.categoryRetailers.includes(par.clave))
|
|
437
471
|
.map(({ retailerId, categoryId }) => ({ retailerId, categoryId })),
|
|
@@ -484,7 +518,9 @@ export const LinkVariantsModal = ({
|
|
|
484
518
|
!applyToAll && mode === "children"
|
|
485
519
|
? selected.reduce((acc, id) => {
|
|
486
520
|
const guardado =
|
|
487
|
-
id === activeChild
|
|
521
|
+
id === activeChild
|
|
522
|
+
? { modes, chosen, extraRetailers }
|
|
523
|
+
: perChild[id];
|
|
488
524
|
if (guardado) acc[id] = buildInherit(guardado);
|
|
489
525
|
return acc;
|
|
490
526
|
}, {})
|
|
@@ -521,11 +557,18 @@ export const LinkVariantsModal = ({
|
|
|
521
557
|
|
|
522
558
|
// Una dimensión está decidida si el usuario eligió un modo, o si el padre no
|
|
523
559
|
// ofrece nada en ella —no se puede pedir que decida sobre una lista vacía—.
|
|
524
|
-
const decidida = (dimension) =>
|
|
525
|
-
modes[dimension] !== null
|
|
526
|
-
(dimension === "categoryRetailers"
|
|
527
|
-
|
|
528
|
-
|
|
560
|
+
const decidida = (dimension) => {
|
|
561
|
+
if (modes[dimension] !== null) return true;
|
|
562
|
+
if (dimension === "categoryRetailers") {
|
|
563
|
+
return (
|
|
564
|
+
offered.categoryRetailers.length === 0 && extraRetailers.length === 0
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
// Una imagen cuyo archivo no existe no es algo sobre lo que se pueda decidir.
|
|
568
|
+
return dimension === "images"
|
|
569
|
+
? imagenesUtiles.length === 0
|
|
570
|
+
: offered[dimension].length === 0;
|
|
571
|
+
};
|
|
529
572
|
|
|
530
573
|
const DIMENSIONES = [
|
|
531
574
|
"categoryRetailers",
|
|
@@ -544,9 +587,14 @@ export const LinkVariantsModal = ({
|
|
|
544
587
|
|
|
545
588
|
return DIMENSIONES.every((dimension) => {
|
|
546
589
|
if (guardado.modes[dimension] !== null) return true;
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
590
|
+
if (dimension === "categoryRetailers") {
|
|
591
|
+
return (
|
|
592
|
+
offered.categoryRetailers.length === 0 &&
|
|
593
|
+
(guardado.extraRetailers ?? []).length === 0
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
return dimension === "images"
|
|
597
|
+
? imagenesUtiles.length === 0
|
|
550
598
|
: offered[dimension].length === 0;
|
|
551
599
|
});
|
|
552
600
|
};
|
|
@@ -582,7 +630,12 @@ export const LinkVariantsModal = ({
|
|
|
582
630
|
{articleUpc ? ` · UPC ${articleUpc}` : ""}
|
|
583
631
|
</p>
|
|
584
632
|
</div>
|
|
585
|
-
<button
|
|
633
|
+
<button
|
|
634
|
+
type="button"
|
|
635
|
+
className="close"
|
|
636
|
+
onClick={onClose}
|
|
637
|
+
aria-label="Cerrar"
|
|
638
|
+
>
|
|
586
639
|
×
|
|
587
640
|
</button>
|
|
588
641
|
</Header>
|
|
@@ -654,7 +707,9 @@ export const LinkVariantsModal = ({
|
|
|
654
707
|
{candidate.name || `Producto ${candidate.articleId}`}
|
|
655
708
|
<span className="meta">
|
|
656
709
|
UPC {candidate.upc || "—"}
|
|
657
|
-
{candidate.categoryName
|
|
710
|
+
{candidate.categoryName
|
|
711
|
+
? ` · ${candidate.categoryName}`
|
|
712
|
+
: ""}
|
|
658
713
|
</span>
|
|
659
714
|
</span>
|
|
660
715
|
{candidate.variantsCount > 0 && (
|
|
@@ -677,7 +732,11 @@ export const LinkVariantsModal = ({
|
|
|
677
732
|
Mostrando {candidates.length} de {total}
|
|
678
733
|
</span>
|
|
679
734
|
{hasMore && (
|
|
680
|
-
<button
|
|
735
|
+
<button
|
|
736
|
+
type="button"
|
|
737
|
+
onClick={loadMore}
|
|
738
|
+
disabled={loadingMore}
|
|
739
|
+
>
|
|
681
740
|
{loadingMore ? "Cargando…" : "Cargar más"}
|
|
682
741
|
</button>
|
|
683
742
|
)}
|
|
@@ -748,6 +807,7 @@ export const LinkVariantsModal = ({
|
|
|
748
807
|
<label>
|
|
749
808
|
<input
|
|
750
809
|
type="radio"
|
|
810
|
+
name={`categoryRetailers-${activeChild ?? "todos"}`}
|
|
751
811
|
checked={modes.categoryRetailers === "all"}
|
|
752
812
|
onChange={() =>
|
|
753
813
|
chooseMode(
|
|
@@ -769,8 +829,11 @@ export const LinkVariantsModal = ({
|
|
|
769
829
|
<label>
|
|
770
830
|
<input
|
|
771
831
|
type="radio"
|
|
832
|
+
name={`categoryRetailers-${activeChild ?? "todos"}`}
|
|
772
833
|
checked={modes.categoryRetailers === "some"}
|
|
773
|
-
onChange={() =>
|
|
834
|
+
onChange={() =>
|
|
835
|
+
chooseMode("categoryRetailers", "some", [])
|
|
836
|
+
}
|
|
774
837
|
/>
|
|
775
838
|
<span>
|
|
776
839
|
Elegir cuáles
|
|
@@ -788,14 +851,19 @@ export const LinkVariantsModal = ({
|
|
|
788
851
|
clave: `${item.retailerId}-${item.categoryId}`,
|
|
789
852
|
delPadre: true,
|
|
790
853
|
})),
|
|
791
|
-
...extraRetailers.map((item) => ({
|
|
854
|
+
...extraRetailers.map((item) => ({
|
|
855
|
+
...item,
|
|
856
|
+
delPadre: false,
|
|
857
|
+
})),
|
|
792
858
|
].map((item) => (
|
|
793
859
|
<li key={item.clave}>
|
|
794
860
|
<label>
|
|
795
861
|
<input
|
|
796
862
|
type="checkbox"
|
|
797
863
|
disabled={modes.categoryRetailers === "all"}
|
|
798
|
-
checked={chosen.categoryRetailers.includes(
|
|
864
|
+
checked={chosen.categoryRetailers.includes(
|
|
865
|
+
item.clave
|
|
866
|
+
)}
|
|
799
867
|
onChange={() =>
|
|
800
868
|
toggleChoice("categoryRetailers", item.clave)
|
|
801
869
|
}
|
|
@@ -818,58 +886,47 @@ export const LinkVariantsModal = ({
|
|
|
818
886
|
</List>
|
|
819
887
|
|
|
820
888
|
<AddRetailer>
|
|
821
|
-
<
|
|
889
|
+
<SingleSelect
|
|
890
|
+
id="link-variants-retailer"
|
|
891
|
+
placeholder="Agregar otra cadena…"
|
|
892
|
+
options={filters.retailers}
|
|
822
893
|
value={newRetailer}
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
setNewRetailer(valor);
|
|
894
|
+
loading={loadingFilters && !filters.retailers.length}
|
|
895
|
+
onChange={(valor) => {
|
|
896
|
+
setNewRetailer(valor ?? "");
|
|
826
897
|
setNewDepartment("");
|
|
827
898
|
setNewCategory("");
|
|
828
899
|
if (valor) loadFilters(valor, null);
|
|
829
900
|
}}
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
</option>
|
|
836
|
-
))}
|
|
837
|
-
</select>
|
|
838
|
-
<select
|
|
901
|
+
/>
|
|
902
|
+
<SingleSelect
|
|
903
|
+
id="link-variants-department"
|
|
904
|
+
placeholder="Departamento…"
|
|
905
|
+
options={filters.departments}
|
|
839
906
|
value={newDepartment}
|
|
840
|
-
disabled={!newRetailer
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
setNewDepartment(valor);
|
|
907
|
+
disabled={!newRetailer}
|
|
908
|
+
loading={loadingFilters && !!newRetailer}
|
|
909
|
+
onChange={(valor) => {
|
|
910
|
+
setNewDepartment(valor ?? "");
|
|
844
911
|
setNewCategory("");
|
|
845
912
|
if (valor) loadFilters(newRetailer, valor);
|
|
846
913
|
}}
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
</option>
|
|
853
|
-
))}
|
|
854
|
-
</select>
|
|
855
|
-
<select
|
|
914
|
+
/>
|
|
915
|
+
<SingleSelect
|
|
916
|
+
id="link-variants-category"
|
|
917
|
+
placeholder="Categoría…"
|
|
918
|
+
options={filters.categories}
|
|
856
919
|
value={newCategory}
|
|
857
|
-
disabled={!newDepartment
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
{filters.categories.map((item) => (
|
|
862
|
-
<option key={item.value} value={item.value}>
|
|
863
|
-
{item.label}
|
|
864
|
-
</option>
|
|
865
|
-
))}
|
|
866
|
-
</select>
|
|
920
|
+
disabled={!newDepartment}
|
|
921
|
+
loading={loadingFilters && !!newDepartment}
|
|
922
|
+
onChange={(valor) => setNewCategory(valor ?? "")}
|
|
923
|
+
/>
|
|
867
924
|
<button
|
|
868
925
|
type="button"
|
|
869
926
|
onClick={addRetailer}
|
|
870
927
|
disabled={!newRetailer || !newCategory || loadingFilters}
|
|
871
928
|
>
|
|
872
|
-
|
|
929
|
+
Agregar
|
|
873
930
|
</button>
|
|
874
931
|
</AddRetailer>
|
|
875
932
|
</Block>
|
|
@@ -884,6 +941,7 @@ export const LinkVariantsModal = ({
|
|
|
884
941
|
<label>
|
|
885
942
|
<input
|
|
886
943
|
type="radio"
|
|
944
|
+
name={`descriptions-${activeChild ?? "todos"}`}
|
|
887
945
|
checked={modes.descriptions === "all"}
|
|
888
946
|
onChange={() =>
|
|
889
947
|
chooseMode(
|
|
@@ -904,8 +962,11 @@ export const LinkVariantsModal = ({
|
|
|
904
962
|
<label>
|
|
905
963
|
<input
|
|
906
964
|
type="radio"
|
|
965
|
+
name={`descriptions-${activeChild ?? "todos"}`}
|
|
907
966
|
checked={modes.descriptions === "some"}
|
|
908
|
-
onChange={() =>
|
|
967
|
+
onChange={() =>
|
|
968
|
+
chooseMode("descriptions", "some", [])
|
|
969
|
+
}
|
|
909
970
|
/>
|
|
910
971
|
<span>
|
|
911
972
|
Elegir cuáles
|
|
@@ -925,7 +986,9 @@ export const LinkVariantsModal = ({
|
|
|
925
986
|
type="checkbox"
|
|
926
987
|
disabled={modes.descriptions === "all"}
|
|
927
988
|
checked={chosen.descriptions.includes(item.id)}
|
|
928
|
-
onChange={() =>
|
|
989
|
+
onChange={() =>
|
|
990
|
+
toggleChoice("descriptions", item.id)
|
|
991
|
+
}
|
|
929
992
|
/>
|
|
930
993
|
<span>
|
|
931
994
|
{item.name}
|
|
@@ -961,6 +1024,7 @@ export const LinkVariantsModal = ({
|
|
|
961
1024
|
<label>
|
|
962
1025
|
<input
|
|
963
1026
|
type="radio"
|
|
1027
|
+
name={`attributes-${activeChild ?? "todos"}`}
|
|
964
1028
|
checked={modes.attributes === "all"}
|
|
965
1029
|
onChange={() =>
|
|
966
1030
|
chooseMode(
|
|
@@ -973,14 +1037,15 @@ export const LinkVariantsModal = ({
|
|
|
973
1037
|
<span>
|
|
974
1038
|
Todos los que tienen valor
|
|
975
1039
|
<span className="hint">
|
|
976
|
-
{offered.attributes.length} atributo(s) con
|
|
977
|
-
en el padre.
|
|
1040
|
+
{offered.attributes.length} atributo(s) con
|
|
1041
|
+
información en el padre.
|
|
978
1042
|
</span>
|
|
979
1043
|
</span>
|
|
980
1044
|
</label>
|
|
981
1045
|
<label>
|
|
982
1046
|
<input
|
|
983
1047
|
type="radio"
|
|
1048
|
+
name={`attributes-${activeChild ?? "todos"}`}
|
|
984
1049
|
checked={modes.attributes === "some"}
|
|
985
1050
|
onChange={() => chooseMode("attributes", "some", [])}
|
|
986
1051
|
/>
|
|
@@ -996,8 +1061,9 @@ export const LinkVariantsModal = ({
|
|
|
996
1061
|
|
|
997
1062
|
{activeRetailerId && !nameScope && (
|
|
998
1063
|
<Message>
|
|
999
|
-
El producto padre no comparte la cadena que tienes
|
|
1000
|
-
así que los nombres de abajo son los de otra de
|
|
1064
|
+
El producto padre no comparte la cadena que tienes
|
|
1065
|
+
abierta, así que los nombres de abajo son los de otra de
|
|
1066
|
+
sus cadenas.
|
|
1001
1067
|
</Message>
|
|
1002
1068
|
)}
|
|
1003
1069
|
|
|
@@ -1009,7 +1075,9 @@ export const LinkVariantsModal = ({
|
|
|
1009
1075
|
type="checkbox"
|
|
1010
1076
|
disabled={modes.attributes === "all"}
|
|
1011
1077
|
checked={chosen.attributes.includes(attribute.id)}
|
|
1012
|
-
onChange={() =>
|
|
1078
|
+
onChange={() =>
|
|
1079
|
+
toggleChoice("attributes", attribute.id)
|
|
1080
|
+
}
|
|
1013
1081
|
/>
|
|
1014
1082
|
<span>
|
|
1015
1083
|
{attribute.name}
|
|
@@ -1039,79 +1107,85 @@ export const LinkVariantsModal = ({
|
|
|
1039
1107
|
)}
|
|
1040
1108
|
</Block>
|
|
1041
1109
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
<
|
|
1049
|
-
|
|
1110
|
+
{/* Sin imágenes utilizables el bloque no se dibuja: un paso que
|
|
1111
|
+
solo sirve para decir que no hay nada es ruido, y ademas ya no
|
|
1112
|
+
hay decision que tomar ahi. */}
|
|
1113
|
+
{imagenesUtiles.length > 0 && (
|
|
1114
|
+
<Block>
|
|
1115
|
+
<h3>
|
|
1116
|
+
<span className="paso">4</span> Imágenes
|
|
1117
|
+
</h3>
|
|
1118
|
+
<Choices>
|
|
1119
|
+
<label>
|
|
1120
|
+
<input
|
|
1121
|
+
type="radio"
|
|
1122
|
+
name={`images-${activeChild ?? "todos"}`}
|
|
1123
|
+
checked={modes.images === "all"}
|
|
1124
|
+
onChange={() =>
|
|
1125
|
+
chooseMode(
|
|
1126
|
+
"images",
|
|
1127
|
+
"all",
|
|
1128
|
+
imagenesUtiles.map((item) => item.id)
|
|
1129
|
+
)
|
|
1130
|
+
}
|
|
1131
|
+
/>
|
|
1132
|
+
<span>
|
|
1133
|
+
Todas
|
|
1134
|
+
<span className="hint">
|
|
1135
|
+
{imagenesUtiles.length} imagen(es) en el padre.
|
|
1136
|
+
</span>
|
|
1137
|
+
</span>
|
|
1138
|
+
</label>
|
|
1139
|
+
<label>
|
|
1140
|
+
<input
|
|
1141
|
+
type="radio"
|
|
1142
|
+
name={`images-${activeChild ?? "todos"}`}
|
|
1143
|
+
checked={modes.images === "some"}
|
|
1144
|
+
onChange={() => chooseMode("images", "some", [])}
|
|
1145
|
+
/>
|
|
1146
|
+
<span>
|
|
1147
|
+
Elegir cuáles
|
|
1148
|
+
<span className="hint">
|
|
1149
|
+
Útil cuando la variante cambia de color o de empaque.
|
|
1150
|
+
</span>
|
|
1151
|
+
</span>
|
|
1152
|
+
</label>
|
|
1153
|
+
</Choices>
|
|
1154
|
+
|
|
1155
|
+
<ImageGrid>
|
|
1156
|
+
{imagenesUtiles.map((image) => (
|
|
1157
|
+
<label
|
|
1158
|
+
key={image.id}
|
|
1159
|
+
className={[
|
|
1160
|
+
chosen.images.includes(image.id) ? "picked" : "",
|
|
1161
|
+
modes.images === "all" ? "locked" : "",
|
|
1162
|
+
]
|
|
1163
|
+
.filter(Boolean)
|
|
1164
|
+
.join(" ")}
|
|
1165
|
+
>
|
|
1050
1166
|
<input
|
|
1051
|
-
type="
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1167
|
+
type="checkbox"
|
|
1168
|
+
disabled={modes.images === "all"}
|
|
1169
|
+
checked={chosen.images.includes(image.id)}
|
|
1170
|
+
onChange={() => toggleChoice("images", image.id)}
|
|
1171
|
+
/>
|
|
1172
|
+
<img
|
|
1173
|
+
src={getProductImage(image.src)}
|
|
1174
|
+
alt=""
|
|
1175
|
+
onError={() =>
|
|
1176
|
+
setBrokenImages((current) =>
|
|
1177
|
+
current.includes(image.id)
|
|
1178
|
+
? current
|
|
1179
|
+
: [...current, image.id]
|
|
1058
1180
|
)
|
|
1059
1181
|
}
|
|
1060
1182
|
/>
|
|
1061
|
-
<span>
|
|
1062
|
-
Todas
|
|
1063
|
-
<span className="hint">
|
|
1064
|
-
{offered.images.length} imagen(es) en el padre.
|
|
1065
|
-
</span>
|
|
1066
|
-
</span>
|
|
1067
|
-
</label>
|
|
1068
|
-
<label>
|
|
1069
|
-
<input
|
|
1070
|
-
type="radio"
|
|
1071
|
-
checked={modes.images === "some"}
|
|
1072
|
-
onChange={() => chooseMode("images", "some", [])}
|
|
1073
|
-
/>
|
|
1074
|
-
<span>
|
|
1075
|
-
Elegir cuáles
|
|
1076
|
-
<span className="hint">
|
|
1077
|
-
Útil cuando la variante cambia de color o de empaque.
|
|
1078
|
-
</span>
|
|
1079
|
-
</span>
|
|
1183
|
+
<span>{image.imageType || "Sin tipo de toma"}</span>
|
|
1080
1184
|
</label>
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
<label
|
|
1086
|
-
key={image.id}
|
|
1087
|
-
className={[
|
|
1088
|
-
chosen.images.includes(image.id) ? "picked" : "",
|
|
1089
|
-
modes.images === "all" ? "locked" : "",
|
|
1090
|
-
]
|
|
1091
|
-
.filter(Boolean)
|
|
1092
|
-
.join(" ")}
|
|
1093
|
-
>
|
|
1094
|
-
<input
|
|
1095
|
-
type="checkbox"
|
|
1096
|
-
disabled={modes.images === "all"}
|
|
1097
|
-
checked={chosen.images.includes(image.id)}
|
|
1098
|
-
onChange={() => toggleChoice("images", image.id)}
|
|
1099
|
-
/>
|
|
1100
|
-
<img
|
|
1101
|
-
src={getProductImage(image.src)}
|
|
1102
|
-
alt={image.imageType || "Imagen del producto"}
|
|
1103
|
-
/>
|
|
1104
|
-
<span>{image.imageType || "Sin tipo de toma"}</span>
|
|
1105
|
-
</label>
|
|
1106
|
-
))}
|
|
1107
|
-
</ImageGrid>
|
|
1108
|
-
</>
|
|
1109
|
-
) : (
|
|
1110
|
-
<Message>
|
|
1111
|
-
El producto padre no tiene imágenes que heredar.
|
|
1112
|
-
</Message>
|
|
1113
|
-
)}
|
|
1114
|
-
</Block>
|
|
1185
|
+
))}
|
|
1186
|
+
</ImageGrid>
|
|
1187
|
+
</Block>
|
|
1188
|
+
)}
|
|
1115
1189
|
|
|
1116
1190
|
{/* Es la diferencia entre link y propagate, y es la que sorprende:
|
|
1117
1191
|
aquí lo elegido se escribe encima aunque la variante lo hubiera
|
|
@@ -1131,7 +1205,9 @@ export const LinkVariantsModal = ({
|
|
|
1131
1205
|
: todoDecidido
|
|
1132
1206
|
? "Todo revisado. Puedes ligar."
|
|
1133
1207
|
: !applyToAll && mode === "children"
|
|
1134
|
-
? `Faltan ${
|
|
1208
|
+
? `Faltan ${
|
|
1209
|
+
selected.filter((id) => !decididoPara(id)).length
|
|
1210
|
+
} producto(s) por revisar.`
|
|
1135
1211
|
: `Falta decidir: ${faltantes.join(", ")}.`}
|
|
1136
1212
|
</span>
|
|
1137
1213
|
<div className="actions">
|
|
@@ -1145,7 +1221,12 @@ export const LinkVariantsModal = ({
|
|
|
1145
1221
|
Atrás
|
|
1146
1222
|
</button>
|
|
1147
1223
|
)}
|
|
1148
|
-
<button
|
|
1224
|
+
<button
|
|
1225
|
+
type="button"
|
|
1226
|
+
className="secondary"
|
|
1227
|
+
onClick={onClose}
|
|
1228
|
+
disabled={loading}
|
|
1229
|
+
>
|
|
1149
1230
|
Cancelar
|
|
1150
1231
|
</button>
|
|
1151
1232
|
{step === "search" ? (
|