contentoh-components-library 21.6.22 → 21.6.24
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/.env.test +1 -0
- package/dist/_utils/helper.js +47 -2
- package/dist/components/organisms/LinkVariantsModal/index.js +891 -186
- package/dist/components/organisms/LinkVariantsModal/styles.js +29 -5
- package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.context.js +22 -13
- package/dist/components/pages/ProviderProductEdition/index.js +393 -110
- package/dist/components/pages/ProviderProductEdition/styles.js +2 -2
- package/package.json +1 -1
- package/src/_utils/helper.js +40 -0
- package/src/components/organisms/LinkVariantsModal/index.js +813 -117
- package/src/components/organisms/LinkVariantsModal/styles.js +256 -0
- package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx +14 -1
- package/src/components/pages/ProviderProductEdition/index.js +223 -3
- package/src/components/pages/ProviderProductEdition/styles.js +68 -0
|
@@ -82,6 +82,25 @@ export const Body = styled.div`
|
|
|
82
82
|
flex: 1;
|
|
83
83
|
overflow-y: auto;
|
|
84
84
|
padding: 0 24px;
|
|
85
|
+
|
|
86
|
+
.apply-all {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: flex-start;
|
|
89
|
+
gap: 8px;
|
|
90
|
+
margin-bottom: 12px;
|
|
91
|
+
padding: 10px 12px;
|
|
92
|
+
border-radius: 6px;
|
|
93
|
+
background-color: ${GlobalColors.s2};
|
|
94
|
+
font-size: 12px;
|
|
95
|
+
color: ${GlobalColors.deep_gray};
|
|
96
|
+
cursor: pointer;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.apply-all .hint {
|
|
100
|
+
display: block;
|
|
101
|
+
font-size: 11px;
|
|
102
|
+
color: ${GlobalColors.gray};
|
|
103
|
+
}
|
|
85
104
|
`;
|
|
86
105
|
|
|
87
106
|
export const SearchRow = styled.form`
|
|
@@ -145,6 +164,14 @@ export const List = styled.ul`
|
|
|
145
164
|
color: ${GlobalColors.gray};
|
|
146
165
|
}
|
|
147
166
|
|
|
167
|
+
.logo {
|
|
168
|
+
width: 24px;
|
|
169
|
+
height: 24px;
|
|
170
|
+
object-fit: contain;
|
|
171
|
+
border-radius: 3px;
|
|
172
|
+
flex-shrink: 0;
|
|
173
|
+
}
|
|
174
|
+
|
|
148
175
|
.count {
|
|
149
176
|
margin-left: auto;
|
|
150
177
|
font-size: 11px;
|
|
@@ -262,3 +289,232 @@ export const Footer = styled.div`
|
|
|
262
289
|
cursor: default;
|
|
263
290
|
}
|
|
264
291
|
`;
|
|
292
|
+
|
|
293
|
+
export const ImageGrid = styled.div`
|
|
294
|
+
display: grid;
|
|
295
|
+
grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
|
|
296
|
+
gap: 8px;
|
|
297
|
+
margin-bottom: 16px;
|
|
298
|
+
|
|
299
|
+
label {
|
|
300
|
+
position: relative;
|
|
301
|
+
display: flex;
|
|
302
|
+
flex-direction: column;
|
|
303
|
+
gap: 4px;
|
|
304
|
+
padding: 6px;
|
|
305
|
+
border: 1px solid ${GlobalColors.s2};
|
|
306
|
+
border-radius: 6px;
|
|
307
|
+
cursor: pointer;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
label.picked {
|
|
311
|
+
border-color: ${GlobalColors.original_magenta};
|
|
312
|
+
background-color: rgba(${GlobalColors.rgb_color_pink}, 0.06);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
label.locked {
|
|
316
|
+
cursor: default;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
label input {
|
|
320
|
+
position: absolute;
|
|
321
|
+
top: 8px;
|
|
322
|
+
left: 8px;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
label img {
|
|
326
|
+
width: 100%;
|
|
327
|
+
height: 72px;
|
|
328
|
+
object-fit: contain;
|
|
329
|
+
background-color: ${GlobalColors.s2};
|
|
330
|
+
border-radius: 4px;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
label span {
|
|
334
|
+
font-size: 10px;
|
|
335
|
+
color: ${GlobalColors.gray};
|
|
336
|
+
text-align: center;
|
|
337
|
+
overflow: hidden;
|
|
338
|
+
text-overflow: ellipsis;
|
|
339
|
+
white-space: nowrap;
|
|
340
|
+
}
|
|
341
|
+
`;
|
|
342
|
+
|
|
343
|
+
export const AddRetailer = styled.div`
|
|
344
|
+
display: flex;
|
|
345
|
+
flex-wrap: wrap;
|
|
346
|
+
gap: 8px;
|
|
347
|
+
margin-bottom: 16px;
|
|
348
|
+
|
|
349
|
+
select {
|
|
350
|
+
flex: 1 1 140px;
|
|
351
|
+
min-width: 0;
|
|
352
|
+
height: 32px;
|
|
353
|
+
padding: 0 8px;
|
|
354
|
+
border: 1px solid ${GlobalColors.s2};
|
|
355
|
+
border-radius: 6px;
|
|
356
|
+
font-family: ${FontFamily.Raleway};
|
|
357
|
+
font-size: 12px;
|
|
358
|
+
color: ${GlobalColors.deep_gray};
|
|
359
|
+
background-color: ${GlobalColors.white};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
button {
|
|
363
|
+
height: 32px;
|
|
364
|
+
padding: 0 14px;
|
|
365
|
+
border: 1px solid ${GlobalColors.original_magenta};
|
|
366
|
+
border-radius: 6px;
|
|
367
|
+
background: none;
|
|
368
|
+
font-family: ${FontFamily.Raleway_600};
|
|
369
|
+
font-size: 12px;
|
|
370
|
+
color: ${GlobalColors.original_magenta};
|
|
371
|
+
cursor: pointer;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
select:disabled {
|
|
375
|
+
opacity: 0.5;
|
|
376
|
+
cursor: default;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
button:disabled {
|
|
380
|
+
opacity: 0.4;
|
|
381
|
+
cursor: default;
|
|
382
|
+
}
|
|
383
|
+
`;
|
|
384
|
+
|
|
385
|
+
export const Block = styled.section`
|
|
386
|
+
margin-bottom: 20px;
|
|
387
|
+
padding-bottom: 16px;
|
|
388
|
+
border-bottom: 1px solid ${GlobalColors.s2};
|
|
389
|
+
|
|
390
|
+
&:last-of-type {
|
|
391
|
+
border-bottom: none;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
h3 {
|
|
395
|
+
display: flex;
|
|
396
|
+
align-items: center;
|
|
397
|
+
gap: 8px;
|
|
398
|
+
margin: 0 0 8px;
|
|
399
|
+
font-family: ${FontFamily.Raleway_600};
|
|
400
|
+
font-size: 13px;
|
|
401
|
+
color: ${GlobalColors.deep_gray};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
h3 .paso {
|
|
405
|
+
display: inline-flex;
|
|
406
|
+
align-items: center;
|
|
407
|
+
justify-content: center;
|
|
408
|
+
width: 18px;
|
|
409
|
+
height: 18px;
|
|
410
|
+
border-radius: 50%;
|
|
411
|
+
background-color: ${GlobalColors.original_magenta};
|
|
412
|
+
color: ${GlobalColors.white};
|
|
413
|
+
font-size: 10px;
|
|
414
|
+
}
|
|
415
|
+
`;
|
|
416
|
+
|
|
417
|
+
export const Choices = styled.div`
|
|
418
|
+
display: flex;
|
|
419
|
+
flex-direction: column;
|
|
420
|
+
gap: 2px;
|
|
421
|
+
margin-bottom: 10px;
|
|
422
|
+
|
|
423
|
+
label {
|
|
424
|
+
display: flex;
|
|
425
|
+
align-items: flex-start;
|
|
426
|
+
gap: 8px;
|
|
427
|
+
padding: 4px 0;
|
|
428
|
+
font-size: 12px;
|
|
429
|
+
color: ${GlobalColors.deep_gray};
|
|
430
|
+
cursor: pointer;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
label .hint {
|
|
434
|
+
display: block;
|
|
435
|
+
font-size: 11px;
|
|
436
|
+
color: ${GlobalColors.gray};
|
|
437
|
+
}
|
|
438
|
+
`;
|
|
439
|
+
|
|
440
|
+
export const Paging = styled.div`
|
|
441
|
+
display: flex;
|
|
442
|
+
align-items: center;
|
|
443
|
+
justify-content: space-between;
|
|
444
|
+
gap: 12px;
|
|
445
|
+
margin: -8px 0 16px;
|
|
446
|
+
font-family: ${FontFamily.Raleway_500};
|
|
447
|
+
font-size: 11px;
|
|
448
|
+
color: ${GlobalColors.gray};
|
|
449
|
+
|
|
450
|
+
button {
|
|
451
|
+
border: 1px solid ${GlobalColors.s2};
|
|
452
|
+
border-radius: 6px;
|
|
453
|
+
background: none;
|
|
454
|
+
padding: 5px 12px;
|
|
455
|
+
cursor: pointer;
|
|
456
|
+
font-family: ${FontFamily.Raleway_600};
|
|
457
|
+
font-size: 11px;
|
|
458
|
+
color: ${GlobalColors.original_magenta};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
button:disabled {
|
|
462
|
+
opacity: 0.5;
|
|
463
|
+
cursor: default;
|
|
464
|
+
}
|
|
465
|
+
`;
|
|
466
|
+
|
|
467
|
+
export const Tabs = styled.div`
|
|
468
|
+
display: flex;
|
|
469
|
+
flex-wrap: wrap;
|
|
470
|
+
gap: 6px;
|
|
471
|
+
margin-bottom: 16px;
|
|
472
|
+
padding-bottom: 12px;
|
|
473
|
+
border-bottom: 1px solid ${GlobalColors.s2};
|
|
474
|
+
|
|
475
|
+
button {
|
|
476
|
+
display: inline-flex;
|
|
477
|
+
align-items: center;
|
|
478
|
+
gap: 6px;
|
|
479
|
+
max-width: 200px;
|
|
480
|
+
padding: 6px 10px;
|
|
481
|
+
border: 1px solid ${GlobalColors.s2};
|
|
482
|
+
border-radius: 6px;
|
|
483
|
+
background-color: ${GlobalColors.white};
|
|
484
|
+
cursor: pointer;
|
|
485
|
+
font-family: ${FontFamily.Raleway_500};
|
|
486
|
+
font-size: 11px;
|
|
487
|
+
color: ${GlobalColors.gray};
|
|
488
|
+
overflow: hidden;
|
|
489
|
+
text-overflow: ellipsis;
|
|
490
|
+
white-space: nowrap;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
button.active {
|
|
494
|
+
border-color: ${GlobalColors.original_magenta};
|
|
495
|
+
color: ${GlobalColors.original_magenta};
|
|
496
|
+
background-color: rgba(${GlobalColors.rgb_color_pink}, 0.08);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
button .orden {
|
|
500
|
+
display: inline-flex;
|
|
501
|
+
align-items: center;
|
|
502
|
+
justify-content: center;
|
|
503
|
+
width: 16px;
|
|
504
|
+
height: 16px;
|
|
505
|
+
border-radius: 50%;
|
|
506
|
+
background-color: ${GlobalColors.s2};
|
|
507
|
+
font-size: 9px;
|
|
508
|
+
flex-shrink: 0;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
button.active .orden {
|
|
512
|
+
background-color: ${GlobalColors.original_magenta};
|
|
513
|
+
color: ${GlobalColors.white};
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
button .listo {
|
|
517
|
+
color: ${GlobalColors.original_magenta};
|
|
518
|
+
flex-shrink: 0;
|
|
519
|
+
}
|
|
520
|
+
`;
|
package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx
CHANGED
|
@@ -159,9 +159,22 @@ export const ProviderProductEditionProvider = ({ children }) => {
|
|
|
159
159
|
type: "SET_UPDATED_DATASHEETS_INPUTS",
|
|
160
160
|
payload: [],
|
|
161
161
|
});
|
|
162
|
+
// En una variante, todo atributo que el hijo toca deja de ser heredado:
|
|
163
|
+
// update-articles-data le pone is_overridden = 1 en la base. Si aquí solo
|
|
164
|
+
// se refresca el valor, el chip sigue diciendo "Heredado" hasta la
|
|
165
|
+
// siguiente carga de la ficha, y el usuario ve una marca que ya es falsa.
|
|
166
|
+
const esVariante =
|
|
167
|
+
state.services?.datasheets?.variant?.isVariant ??
|
|
168
|
+
!!state.product?.parentArticleId;
|
|
169
|
+
|
|
162
170
|
dispatch({
|
|
163
171
|
type: "UPDATE_DATASHEETS_INPUTS",
|
|
164
|
-
payload:
|
|
172
|
+
payload: esVariante
|
|
173
|
+
? state.updated_datasheets_inputs.map((item) => ({
|
|
174
|
+
...item,
|
|
175
|
+
isOverridden: 1,
|
|
176
|
+
}))
|
|
177
|
+
: state.updated_datasheets_inputs,
|
|
165
178
|
});
|
|
166
179
|
|
|
167
180
|
// Mostrar modal de éxito
|
|
@@ -76,6 +76,9 @@ const ProviderProductEditionView = ({
|
|
|
76
76
|
const [boxData, setBoxData] = useState(null);
|
|
77
77
|
const [showModal, setShowModal] = useState(false);
|
|
78
78
|
const [showLinkVariants, setShowLinkVariants] = useState(false);
|
|
79
|
+
const [family, setFamily] = useState(null);
|
|
80
|
+
const [showFamily, setShowFamily] = useState(false);
|
|
81
|
+
const [loadingVariant, setLoadingVariant] = useState(null);
|
|
79
82
|
const [showRejectModal, setShowRejectModal] = useState(false);
|
|
80
83
|
const [headerTop, setHeaderTop] = useState(0);
|
|
81
84
|
const [assig, setAssig] = useState({});
|
|
@@ -697,6 +700,142 @@ const ProviderProductEditionView = ({
|
|
|
697
700
|
});
|
|
698
701
|
};
|
|
699
702
|
|
|
703
|
+
/*
|
|
704
|
+
Trae la familia del producto: sus variantes, o sus hermanas si el abierto es
|
|
705
|
+
una de ellas.
|
|
706
|
+
|
|
707
|
+
Se pide al abrir la sección y no al montar la pantalla: la mayoría de los
|
|
708
|
+
productos no son familia, y una llamada por ficha para no mostrar nada es
|
|
709
|
+
peso que paga todo el mundo por el caso de unos pocos.
|
|
710
|
+
*/
|
|
711
|
+
const loadFamily = async () => {
|
|
712
|
+
if (family) return;
|
|
713
|
+
try {
|
|
714
|
+
const res = await axios.post(
|
|
715
|
+
`${process.env.REACT_APP_VARIANTS_ENDPOINT}/family`,
|
|
716
|
+
{ articleId: state.product?.id_article },
|
|
717
|
+
{ headers: { Authorization: token } }
|
|
718
|
+
);
|
|
719
|
+
setFamily(readPayload(res));
|
|
720
|
+
} catch (error) {
|
|
721
|
+
console.error("loadFamily: ", error);
|
|
722
|
+
setFamily({ variants: [], parent: null, error: true });
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
/*
|
|
727
|
+
Abre otra variante de la familia.
|
|
728
|
+
|
|
729
|
+
Esta pantalla no lee el producto de la URL: lo lee de sessionStorage, donde
|
|
730
|
+
lo dejó el listado al hacer clic. Así que navegar a /products/:id sin más
|
|
731
|
+
cambia la barra de direcciones y deja el producto anterior en pantalla.
|
|
732
|
+
|
|
733
|
+
Por eso primero se trae el producto por su ID —no por su UPC: hay 12,024 UPC
|
|
734
|
+
repetidos entre artículos activos y 5,579 de esos casos caen dentro de la
|
|
735
|
+
misma compañía, así que el UPC no identifica— y se deja en sessionStorage con
|
|
736
|
+
la misma forma que usa el listado. Después se navega.
|
|
737
|
+
|
|
738
|
+
Es un rodeo, y lo es porque el origen del dato está mal puesto. Arreglarlo de
|
|
739
|
+
raíz —que la ficha lea de la URL— toca todas las plataformas y no cabe aquí.
|
|
740
|
+
*/
|
|
741
|
+
const openVariant = async (articleId) => {
|
|
742
|
+
setLoadingVariant(articleId);
|
|
743
|
+
try {
|
|
744
|
+
const res = await axios.get(
|
|
745
|
+
`${process.env.REACT_APP_NEW_ARTICLES_ENDPOINT}`,
|
|
746
|
+
{
|
|
747
|
+
params: { listType: "general", filterByArticleId: articleId },
|
|
748
|
+
headers: { Authorization: token },
|
|
749
|
+
}
|
|
750
|
+
);
|
|
751
|
+
|
|
752
|
+
// read-articles-v2 responde { count, data: [...] }.
|
|
753
|
+
const { data } = readPayload(res);
|
|
754
|
+
const encontrado = (data ?? []).find(
|
|
755
|
+
(item) => Number(item.id_article) === Number(articleId)
|
|
756
|
+
);
|
|
757
|
+
|
|
758
|
+
if (encontrado) {
|
|
759
|
+
sessionStorage.setItem(
|
|
760
|
+
"productSelected",
|
|
761
|
+
JSON.stringify({
|
|
762
|
+
...encontrado,
|
|
763
|
+
article: { id_article: encontrado.id_article },
|
|
764
|
+
})
|
|
765
|
+
);
|
|
766
|
+
sessionStorage.setItem(
|
|
767
|
+
"productEdit",
|
|
768
|
+
JSON.stringify({
|
|
769
|
+
ArticleId: encontrado.id_article,
|
|
770
|
+
idCategory: encontrado.id_category,
|
|
771
|
+
product: encontrado,
|
|
772
|
+
})
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
} catch (error) {
|
|
776
|
+
// Si la consulta falla se navega igual: la pantalla mostrará el producto
|
|
777
|
+
// que hubiera en sessionStorage, que es el comportamiento de siempre.
|
|
778
|
+
// Peor sería dejar el clic sin efecto y que pareciera que no responde.
|
|
779
|
+
console.error("openVariant: ", error);
|
|
780
|
+
} finally {
|
|
781
|
+
setLoadingVariant(null);
|
|
782
|
+
window.location.assign(`/products/${articleId}/datasheet`);
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
/*
|
|
787
|
+
Refresca la ficha después de ligar, sin recargar la página.
|
|
788
|
+
|
|
789
|
+
Recargar no servía: el producto de esta pantalla viene del listado —por
|
|
790
|
+
sessionStorage—, así que tras el refresh volvía el mismo objeto de antes y el
|
|
791
|
+
contador seguía mostrando el número viejo. Además una recarga se lleva lo que
|
|
792
|
+
el usuario tenga sin guardar.
|
|
793
|
+
|
|
794
|
+
Los dos modos tienen efectos opuestos sobre este producto: ligando hijos GANA
|
|
795
|
+
variantes; ligándose a un padre pasa a SER una, y entonces el botón de ligar
|
|
796
|
+
desaparece porque la jerarquía es de un solo nivel.
|
|
797
|
+
*/
|
|
798
|
+
const handleOnLinkedVariants = (result) => {
|
|
799
|
+
if (!result) return;
|
|
800
|
+
|
|
801
|
+
const updatedProduct =
|
|
802
|
+
result.mode === "children"
|
|
803
|
+
? {
|
|
804
|
+
...state.product,
|
|
805
|
+
variantsCount:
|
|
806
|
+
(state.product?.variantsCount ?? 0) +
|
|
807
|
+
(result.linked ?? []).length,
|
|
808
|
+
}
|
|
809
|
+
: {
|
|
810
|
+
...state.product,
|
|
811
|
+
parentArticleId: result.parentArticleId ?? null,
|
|
812
|
+
variantsCount: 0,
|
|
813
|
+
};
|
|
814
|
+
|
|
815
|
+
dispatch({ type: "SET_PRODUCT", payload: updatedProduct });
|
|
816
|
+
// La lista cacheada quedó vieja: se descarta para que vuelva a pedirse.
|
|
817
|
+
setFamily(null);
|
|
818
|
+
|
|
819
|
+
// Y en sessionStorage, que es de donde sale el producto al recargar. Sin
|
|
820
|
+
// esto el arreglo dura hasta el siguiente F5 y vuelve el contador viejo,
|
|
821
|
+
// que es justo el síntoma que se reportó.
|
|
822
|
+
try {
|
|
823
|
+
sessionStorage.setItem("productSelected", JSON.stringify(updatedProduct));
|
|
824
|
+
|
|
825
|
+
const productEdit = JSON.parse(sessionStorage.getItem("productEdit"));
|
|
826
|
+
if (productEdit) {
|
|
827
|
+
sessionStorage.setItem(
|
|
828
|
+
"productEdit",
|
|
829
|
+
JSON.stringify({ ...productEdit, product: updatedProduct })
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
} catch (error) {
|
|
833
|
+
// Un sessionStorage inaccesible no debe tumbar la pantalla: el estado en
|
|
834
|
+
// memoria ya quedó bien y es lo que el usuario está viendo.
|
|
835
|
+
console.error("linkVariants/sessionStorage: ", error);
|
|
836
|
+
}
|
|
837
|
+
};
|
|
838
|
+
|
|
700
839
|
/*
|
|
701
840
|
Acción "Volver a heredar del producto" de los chips de herencia.
|
|
702
841
|
|
|
@@ -1192,7 +1331,7 @@ const ProviderProductEditionView = ({
|
|
|
1192
1331
|
activeRetailerId={state.active_retailer?.id_retailer}
|
|
1193
1332
|
token={token}
|
|
1194
1333
|
onClose={() => setShowLinkVariants(false)}
|
|
1195
|
-
onLinked={
|
|
1334
|
+
onLinked={handleOnLinkedVariants}
|
|
1196
1335
|
/>
|
|
1197
1336
|
)}
|
|
1198
1337
|
{showModal && (
|
|
@@ -1395,10 +1534,91 @@ const ProviderProductEditionView = ({
|
|
|
1395
1534
|
Ligar productos
|
|
1396
1535
|
</button>
|
|
1397
1536
|
{state.product?.variantsCount > 0 && (
|
|
1398
|
-
<
|
|
1537
|
+
<button
|
|
1538
|
+
type="button"
|
|
1539
|
+
className="variants-count"
|
|
1540
|
+
aria-expanded={showFamily}
|
|
1541
|
+
onClick={() => {
|
|
1542
|
+
setShowFamily((abierto) => !abierto);
|
|
1543
|
+
loadFamily();
|
|
1544
|
+
}}
|
|
1545
|
+
>
|
|
1399
1546
|
{state.product.variantsCount} variante
|
|
1400
1547
|
{state.product.variantsCount === 1 ? "" : "s"}
|
|
1401
|
-
|
|
1548
|
+
<span aria-hidden="true">{showFamily ? " ▴" : " ▾"}</span>
|
|
1549
|
+
</button>
|
|
1550
|
+
)}
|
|
1551
|
+
</div>
|
|
1552
|
+
)}
|
|
1553
|
+
|
|
1554
|
+
{/* La ficha de una variante también necesita ver la familia: desde
|
|
1555
|
+
aquí se salta al padre o a una hermana sin pasar por el listado. */}
|
|
1556
|
+
{state.product?.parentArticleId && (
|
|
1557
|
+
<div className="variants-actions">
|
|
1558
|
+
<button
|
|
1559
|
+
type="button"
|
|
1560
|
+
className="variants-count"
|
|
1561
|
+
aria-expanded={showFamily}
|
|
1562
|
+
onClick={() => {
|
|
1563
|
+
setShowFamily((abierto) => !abierto);
|
|
1564
|
+
loadFamily();
|
|
1565
|
+
}}
|
|
1566
|
+
>
|
|
1567
|
+
Variante de otro producto
|
|
1568
|
+
<span aria-hidden="true">{showFamily ? " ▴" : " ▾"}</span>
|
|
1569
|
+
</button>
|
|
1570
|
+
</div>
|
|
1571
|
+
)}
|
|
1572
|
+
|
|
1573
|
+
{showFamily && (
|
|
1574
|
+
<div className="variants-family">
|
|
1575
|
+
{!family && <p className="loading">Cargando familia…</p>}
|
|
1576
|
+
|
|
1577
|
+
{family?.error && (
|
|
1578
|
+
<p className="loading">
|
|
1579
|
+
No se pudo cargar la familia de este producto.
|
|
1580
|
+
</p>
|
|
1581
|
+
)}
|
|
1582
|
+
|
|
1583
|
+
{family?.parent && (
|
|
1584
|
+
<button
|
|
1585
|
+
type="button"
|
|
1586
|
+
className="family-row parent"
|
|
1587
|
+
disabled={loadingVariant !== null}
|
|
1588
|
+
onClick={() => openVariant(family.parent.articleId)}
|
|
1589
|
+
>
|
|
1590
|
+
<span className="role">
|
|
1591
|
+
{loadingVariant === family.parent.articleId
|
|
1592
|
+
? "Abriendo…"
|
|
1593
|
+
: "Producto padre"}
|
|
1594
|
+
</span>
|
|
1595
|
+
<span className="name">{family.parent.name}</span>
|
|
1596
|
+
<span className="upc">{family.parent.upc}</span>
|
|
1597
|
+
</button>
|
|
1598
|
+
)}
|
|
1599
|
+
|
|
1600
|
+
{family?.variants?.map((variant) => (
|
|
1601
|
+
<button
|
|
1602
|
+
key={variant.articleId}
|
|
1603
|
+
type="button"
|
|
1604
|
+
className={`family-row${variant.isCurrent ? " current" : ""}`}
|
|
1605
|
+
disabled={variant.isCurrent || loadingVariant !== null}
|
|
1606
|
+
onClick={() => openVariant(variant.articleId)}
|
|
1607
|
+
>
|
|
1608
|
+
<span className="role">
|
|
1609
|
+
{loadingVariant === variant.articleId
|
|
1610
|
+
? "Abriendo…"
|
|
1611
|
+
: variant.isCurrent
|
|
1612
|
+
? "Estás aquí"
|
|
1613
|
+
: "Variante"}
|
|
1614
|
+
</span>
|
|
1615
|
+
<span className="name">{variant.name}</span>
|
|
1616
|
+
<span className="upc">{variant.upc}</span>
|
|
1617
|
+
</button>
|
|
1618
|
+
))}
|
|
1619
|
+
|
|
1620
|
+
{family && !family.error && !family.variants?.length && (
|
|
1621
|
+
<p className="loading">Este producto no tiene variantes.</p>
|
|
1402
1622
|
)}
|
|
1403
1623
|
</div>
|
|
1404
1624
|
)}
|
|
@@ -178,9 +178,77 @@ export const Container = styled.div`
|
|
|
178
178
|
}
|
|
179
179
|
|
|
180
180
|
.variants-count {
|
|
181
|
+
border: none;
|
|
182
|
+
background: none;
|
|
183
|
+
padding: 0;
|
|
184
|
+
cursor: pointer;
|
|
185
|
+
font-family: ${FontFamily.Raleway_500};
|
|
186
|
+
font-size: 11px;
|
|
187
|
+
color: ${GlobalColors.gray};
|
|
188
|
+
text-decoration: underline;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.variants-family {
|
|
193
|
+
display: flex;
|
|
194
|
+
flex-direction: column;
|
|
195
|
+
gap: 4px;
|
|
196
|
+
margin-bottom: 10px;
|
|
197
|
+
padding: 8px;
|
|
198
|
+
border: 1px solid ${GlobalColors.s2};
|
|
199
|
+
border-radius: 6px;
|
|
200
|
+
|
|
201
|
+
.loading {
|
|
202
|
+
margin: 0;
|
|
181
203
|
font-family: ${FontFamily.Raleway_500};
|
|
182
204
|
font-size: 11px;
|
|
183
205
|
color: ${GlobalColors.gray};
|
|
184
206
|
}
|
|
207
|
+
|
|
208
|
+
.family-row {
|
|
209
|
+
display: flex;
|
|
210
|
+
align-items: baseline;
|
|
211
|
+
gap: 8px;
|
|
212
|
+
padding: 6px 8px;
|
|
213
|
+
border: none;
|
|
214
|
+
border-radius: 4px;
|
|
215
|
+
background: none;
|
|
216
|
+
cursor: pointer;
|
|
217
|
+
text-align: left;
|
|
218
|
+
font-family: ${FontFamily.Raleway_500};
|
|
219
|
+
font-size: 12px;
|
|
220
|
+
color: ${GlobalColors.deep_gray};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.family-row:hover:not(:disabled) {
|
|
224
|
+
background-color: ${GlobalColors.s2};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.family-row:disabled {
|
|
228
|
+
cursor: default;
|
|
229
|
+
opacity: 0.7;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.family-row .role {
|
|
233
|
+
min-width: 96px;
|
|
234
|
+
font-size: 10px;
|
|
235
|
+
color: ${GlobalColors.original_magenta};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.family-row.current .role {
|
|
239
|
+
color: ${GlobalColors.gray};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.family-row .name {
|
|
243
|
+
flex: 1;
|
|
244
|
+
overflow: hidden;
|
|
245
|
+
text-overflow: ellipsis;
|
|
246
|
+
white-space: nowrap;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.family-row .upc {
|
|
250
|
+
font-size: 11px;
|
|
251
|
+
color: ${GlobalColors.gray};
|
|
252
|
+
}
|
|
185
253
|
}
|
|
186
254
|
`;
|