contentoh-components-library 21.6.35 → 21.6.36
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/UnlinkVariantModal/index.js +178 -0
- package/dist/components/organisms/UnlinkVariantModal/styles.js +42 -0
- package/dist/components/pages/ProviderProductEdition/index.js +186 -59
- package/dist/components/pages/ProviderProductEdition/styles.js +2 -2
- package/dist/components/pages/RetailerProductEdition/index.js +183 -68
- package/dist/components/pages/RetailerProductEdition/styles.js +2 -2
- package/dist/index.js +25 -12
- package/package.json +1 -1
- package/src/components/organisms/UnlinkVariantModal/index.js +141 -0
- package/src/components/organisms/UnlinkVariantModal/styles.js +106 -0
- package/src/components/pages/ProviderProductEdition/index.js +166 -37
- package/src/components/pages/ProviderProductEdition/styles.js +30 -0
- package/src/components/pages/RetailerProductEdition/index.js +155 -33
- package/src/components/pages/RetailerProductEdition/styles.js +30 -0
- package/src/index.js +1 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
|
|
4
|
+
import { readPayload, ApiError } from "../LinkVariantsModal/api";
|
|
5
|
+
import { Overlay, Panel, Header, Body, Message, Footer } from "./styles";
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
Confirmación para romper un vínculo padre/hijo.
|
|
9
|
+
|
|
10
|
+
El servidor ya sabía hacerlo desde el principio —POST /variants/unlink—, pero
|
|
11
|
+
no había forma de pedirlo desde ninguna pantalla: la única manera de deshacer
|
|
12
|
+
una liga era DESACTIVAR al padre, que suelta a todos los hijos de golpe y no
|
|
13
|
+
se puede revertir. Esto es la versión de a uno.
|
|
14
|
+
|
|
15
|
+
La acción se pide siempre con el id del HIJO, que es quien tiene el vínculo en
|
|
16
|
+
`article.parent_article_id`. Por eso las dos direcciones —un hijo que se suelta
|
|
17
|
+
y un padre que suelta a un hijo— son la misma llamada; lo único que cambia es
|
|
18
|
+
el texto, porque no es lo mismo lo que el usuario cree estar haciendo.
|
|
19
|
+
|
|
20
|
+
props (* requerido):
|
|
21
|
+
- *childArticleId: el hijo que pierde el vínculo
|
|
22
|
+
- childName / childUpc: para nombrarlo en el diálogo
|
|
23
|
+
- parentName / parentUpc: de quién se desprende
|
|
24
|
+
- mode: "self" (esta ficha deja de ser hija) | "child" (esta ficha suelta a un hijo)
|
|
25
|
+
- *token, endpoint
|
|
26
|
+
- *onClose, onUnlinked
|
|
27
|
+
*/
|
|
28
|
+
export const UnlinkVariantModal = ({
|
|
29
|
+
childArticleId,
|
|
30
|
+
childName,
|
|
31
|
+
childUpc,
|
|
32
|
+
parentName,
|
|
33
|
+
parentUpc,
|
|
34
|
+
mode = "self",
|
|
35
|
+
token,
|
|
36
|
+
endpoint = process.env.REACT_APP_VARIANTS_ENDPOINT,
|
|
37
|
+
onClose,
|
|
38
|
+
onUnlinked,
|
|
39
|
+
}) => {
|
|
40
|
+
const [loading, setLoading] = useState(false);
|
|
41
|
+
const [error, setError] = useState(null);
|
|
42
|
+
|
|
43
|
+
const nombreHijo = childName || `Producto ${childArticleId}`;
|
|
44
|
+
const nombrePadre = parentName || "el producto padre";
|
|
45
|
+
|
|
46
|
+
const submit = async () => {
|
|
47
|
+
setLoading(true);
|
|
48
|
+
setError(null);
|
|
49
|
+
try {
|
|
50
|
+
const res = await axios.post(
|
|
51
|
+
`${endpoint}/unlink`,
|
|
52
|
+
{ articleIds: [childArticleId] },
|
|
53
|
+
{ headers: { Authorization: token } }
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const data = readPayload(res);
|
|
57
|
+
onUnlinked?.({ ...data, mode, childArticleId });
|
|
58
|
+
onClose?.();
|
|
59
|
+
} catch (err) {
|
|
60
|
+
// El transporte siempre responde 200; el error de negocio viaja dentro.
|
|
61
|
+
setError(
|
|
62
|
+
err instanceof ApiError || err?.name === "ApiError"
|
|
63
|
+
? err.message
|
|
64
|
+
: "No se pudo desvincular. Intenta de nuevo."
|
|
65
|
+
);
|
|
66
|
+
setLoading(false);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<Overlay onClick={loading ? undefined : onClose}>
|
|
72
|
+
<Panel onClick={(event) => event.stopPropagation()}>
|
|
73
|
+
<Header>
|
|
74
|
+
<h2>
|
|
75
|
+
{mode === "self"
|
|
76
|
+
? "Dejar de ser hijo de otro producto"
|
|
77
|
+
: "Desvincular este hijo"}
|
|
78
|
+
</h2>
|
|
79
|
+
<p>
|
|
80
|
+
{mode === "self" ? (
|
|
81
|
+
<>
|
|
82
|
+
«{nombreHijo}» dejará de colgar de «{nombrePadre}»
|
|
83
|
+
{parentUpc ? ` (UPC ${parentUpc})` : ""}.
|
|
84
|
+
</>
|
|
85
|
+
) : (
|
|
86
|
+
<>
|
|
87
|
+
«{nombreHijo}»{childUpc ? ` (UPC ${childUpc})` : ""} dejará de
|
|
88
|
+
colgar de este producto.
|
|
89
|
+
</>
|
|
90
|
+
)}
|
|
91
|
+
</p>
|
|
92
|
+
</Header>
|
|
93
|
+
|
|
94
|
+
<Body>
|
|
95
|
+
<ul>
|
|
96
|
+
{/* Lo primero que la gente teme, y no pasa. */}
|
|
97
|
+
<li>
|
|
98
|
+
<strong>No se borra nada.</strong> Todo lo que heredó —atributos,
|
|
99
|
+
descripciones, imágenes y cadenas— se queda como información
|
|
100
|
+
propia del producto.
|
|
101
|
+
</li>
|
|
102
|
+
<li>
|
|
103
|
+
Desaparecen las marcas de «Heredado» y «Propio»: sin padre dejan de
|
|
104
|
+
querer decir algo.
|
|
105
|
+
</li>
|
|
106
|
+
<li>
|
|
107
|
+
Deja de recibir la propagación
|
|
108
|
+
{mode === "self" ? " de su padre" : " de este producto"}: lo que se
|
|
109
|
+
edite de un lado ya no baja al otro.
|
|
110
|
+
</li>
|
|
111
|
+
<li className="aviso">
|
|
112
|
+
Volver a ligarlos es a mano, y hay que elegir otra vez qué hereda.
|
|
113
|
+
Desvincular no se deshace solo.
|
|
114
|
+
</li>
|
|
115
|
+
</ul>
|
|
116
|
+
</Body>
|
|
117
|
+
|
|
118
|
+
{error && <Message>{error}</Message>}
|
|
119
|
+
|
|
120
|
+
<Footer>
|
|
121
|
+
<button
|
|
122
|
+
type="button"
|
|
123
|
+
className="secondary"
|
|
124
|
+
onClick={onClose}
|
|
125
|
+
disabled={loading}
|
|
126
|
+
>
|
|
127
|
+
Cancelar
|
|
128
|
+
</button>
|
|
129
|
+
<button
|
|
130
|
+
type="button"
|
|
131
|
+
className="primary"
|
|
132
|
+
onClick={submit}
|
|
133
|
+
disabled={loading}
|
|
134
|
+
>
|
|
135
|
+
{loading ? "Desvinculando…" : "Desvincular"}
|
|
136
|
+
</button>
|
|
137
|
+
</Footer>
|
|
138
|
+
</Panel>
|
|
139
|
+
</Overlay>
|
|
140
|
+
);
|
|
141
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import styled from "styled-components";
|
|
2
|
+
|
|
3
|
+
import { GlobalColors, FontFamily } from "../../../global-files/variables";
|
|
4
|
+
|
|
5
|
+
const PINK = "#E13AA8";
|
|
6
|
+
|
|
7
|
+
export const Overlay = styled.div`
|
|
8
|
+
position: fixed;
|
|
9
|
+
inset: 0;
|
|
10
|
+
z-index: 1000;
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: center;
|
|
13
|
+
justify-content: center;
|
|
14
|
+
background-color: rgba(40, 31, 51, 0.4);
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
export const Panel = styled.div`
|
|
18
|
+
width: min(460px, 92vw);
|
|
19
|
+
border-radius: 10px;
|
|
20
|
+
background-color: ${GlobalColors.white};
|
|
21
|
+
font-family: ${FontFamily.Raleway};
|
|
22
|
+
overflow: hidden;
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
export const Header = styled.div`
|
|
26
|
+
padding: 18px 22px 10px;
|
|
27
|
+
|
|
28
|
+
h2 {
|
|
29
|
+
margin: 0;
|
|
30
|
+
font-family: ${FontFamily.Raleway_600};
|
|
31
|
+
font-size: 16px;
|
|
32
|
+
color: ${GlobalColors.deep_gray};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
p {
|
|
36
|
+
margin: 6px 0 0;
|
|
37
|
+
font-size: 13px;
|
|
38
|
+
line-height: 1.4;
|
|
39
|
+
color: ${GlobalColors.gray};
|
|
40
|
+
}
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
export const Body = styled.div`
|
|
44
|
+
padding: 4px 22px 8px;
|
|
45
|
+
|
|
46
|
+
ul {
|
|
47
|
+
margin: 0;
|
|
48
|
+
padding-left: 18px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
li {
|
|
52
|
+
margin-bottom: 6px;
|
|
53
|
+
font-size: 13px;
|
|
54
|
+
line-height: 1.4;
|
|
55
|
+
color: ${GlobalColors.deep_gray};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Lo único que no se puede deshacer solo va marcado: el resto son
|
|
59
|
+
consecuencias, esta es una advertencia. */
|
|
60
|
+
li.aviso {
|
|
61
|
+
color: ${PINK};
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
export const Message = styled.p`
|
|
66
|
+
margin: 8px 22px 0;
|
|
67
|
+
padding: 10px 12px;
|
|
68
|
+
border-radius: 6px;
|
|
69
|
+
background-color: rgba(225, 58, 168, 0.1);
|
|
70
|
+
font-size: 13px;
|
|
71
|
+
line-height: 1.4;
|
|
72
|
+
color: ${PINK};
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
export const Footer = styled.div`
|
|
76
|
+
display: flex;
|
|
77
|
+
justify-content: flex-end;
|
|
78
|
+
gap: 10px;
|
|
79
|
+
padding: 16px 22px 20px;
|
|
80
|
+
|
|
81
|
+
button {
|
|
82
|
+
height: 38px;
|
|
83
|
+
padding: 0 16px;
|
|
84
|
+
border-radius: 6px;
|
|
85
|
+
cursor: pointer;
|
|
86
|
+
font-family: ${FontFamily.Raleway_600};
|
|
87
|
+
font-size: 13px;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
button:disabled {
|
|
91
|
+
opacity: 0.5;
|
|
92
|
+
cursor: default;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.secondary {
|
|
96
|
+
border: 1px solid ${GlobalColors.s2};
|
|
97
|
+
background: none;
|
|
98
|
+
color: ${GlobalColors.deep_gray};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.primary {
|
|
102
|
+
border: 1px solid ${PINK};
|
|
103
|
+
background-color: ${PINK};
|
|
104
|
+
color: ${GlobalColors.white};
|
|
105
|
+
}
|
|
106
|
+
`;
|
|
@@ -39,6 +39,7 @@ import { ImageDataTable } from "../../organisms/ImageDataTable";
|
|
|
39
39
|
import { ImagePreviewer } from "../../organisms/ImagePreviewer";
|
|
40
40
|
import { InputGroup } from "../../organisms/InputGroup";
|
|
41
41
|
import { LinkVariantsModal } from "../../organisms/LinkVariantsModal";
|
|
42
|
+
import { UnlinkVariantModal } from "../../organisms/UnlinkVariantModal";
|
|
42
43
|
import { PropagateChangesModal } from "../../organisms/PropagateChangesModal";
|
|
43
44
|
import { readPayload } from "../../organisms/LinkVariantsModal/api";
|
|
44
45
|
import { ProductImageModal } from "../../organisms/ProductImageModal";
|
|
@@ -781,8 +782,8 @@ const ProviderProductEditionView = ({
|
|
|
781
782
|
productos no son familia, y una llamada por ficha para no mostrar nada es
|
|
782
783
|
peso que paga todo el mundo por el caso de unos pocos.
|
|
783
784
|
*/
|
|
784
|
-
const loadFamily = async () => {
|
|
785
|
-
if (family) return family;
|
|
785
|
+
const loadFamily = async (forzar = false) => {
|
|
786
|
+
if (family && !forzar) return family;
|
|
786
787
|
try {
|
|
787
788
|
const res = await axios.post(
|
|
788
789
|
`${process.env.REACT_APP_VARIANTS_ENDPOINT}/family`,
|
|
@@ -875,6 +876,71 @@ const ProviderProductEditionView = ({
|
|
|
875
876
|
}
|
|
876
877
|
};
|
|
877
878
|
|
|
879
|
+
/*
|
|
880
|
+
Qué vínculo se está por romper, o null si no hay diálogo abierto.
|
|
881
|
+
|
|
882
|
+
Guarda al HIJO, porque la relación vive en él (`article.parent_article_id`)
|
|
883
|
+
y es lo que pide la acción `unlink`. `mode` solo cambia el texto: no es lo
|
|
884
|
+
mismo soltarse de un padre que soltar a un hijo, aunque por dentro sea la
|
|
885
|
+
misma llamada.
|
|
886
|
+
*/
|
|
887
|
+
const [porDesvincular, setPorDesvincular] = useState(null);
|
|
888
|
+
|
|
889
|
+
/*
|
|
890
|
+
Después de desvincular, esta ficha cambia de forma.
|
|
891
|
+
|
|
892
|
+
Si el producto se soltó de su padre, deja de ser hijo y vuelve a poder ligar
|
|
893
|
+
—el botón reaparece—. Si soltó a un hijo, pierde uno de la cuenta. En los dos
|
|
894
|
+
casos hay que repreguntar la familia: lo que se ve en la lista ya no es lo
|
|
895
|
+
que hay en el servidor.
|
|
896
|
+
*/
|
|
897
|
+
const handleOnUnlinked = (result) => {
|
|
898
|
+
if (!result) return;
|
|
899
|
+
|
|
900
|
+
const updatedProduct =
|
|
901
|
+
result.mode === "self"
|
|
902
|
+
? { ...state.product, parentArticleId: null, variantsCount: 0 }
|
|
903
|
+
: {
|
|
904
|
+
...state.product,
|
|
905
|
+
variantsCount: Math.max((state.product?.variantsCount ?? 1) - 1, 0),
|
|
906
|
+
};
|
|
907
|
+
|
|
908
|
+
dispatch({ type: "SET_PRODUCT", payload: updatedProduct });
|
|
909
|
+
|
|
910
|
+
try {
|
|
911
|
+
sessionStorage.setItem("productSelected", JSON.stringify(updatedProduct));
|
|
912
|
+
|
|
913
|
+
const productEdit = JSON.parse(sessionStorage.getItem("productEdit"));
|
|
914
|
+
if (productEdit) {
|
|
915
|
+
sessionStorage.setItem(
|
|
916
|
+
"productEdit",
|
|
917
|
+
JSON.stringify({ ...productEdit, product: updatedProduct })
|
|
918
|
+
);
|
|
919
|
+
}
|
|
920
|
+
} catch (error) {
|
|
921
|
+
console.error("unlinkVariant/sessionStorage: ", error);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/*
|
|
925
|
+
Si ya no queda familia, se cierra el desplegable: su botón desaparece con
|
|
926
|
+
el vínculo, y dejarlo abierto pinta una caja que dice «no tiene hijos» y
|
|
927
|
+
que nadie puede cerrar.
|
|
928
|
+
*/
|
|
929
|
+
if (
|
|
930
|
+
!updatedProduct.parentArticleId &&
|
|
931
|
+
(updatedProduct.variantsCount ?? 0) === 0
|
|
932
|
+
) {
|
|
933
|
+
setShowFamily(false);
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
loadFamily(true);
|
|
937
|
+
|
|
938
|
+
// Y los servicios: al desvincular, el servidor pone `is_overridden = 0` en
|
|
939
|
+
// todas las versiones, así que los chips de herencia tienen que dejar de
|
|
940
|
+
// dibujarse. Sin esto la ficha sigue mostrándolos hasta que se recarga.
|
|
941
|
+
setLinkNonce((n) => n + 1);
|
|
942
|
+
};
|
|
943
|
+
|
|
878
944
|
const openVariant = async (articleId) => {
|
|
879
945
|
setLoadingVariant(articleId);
|
|
880
946
|
try {
|
|
@@ -950,8 +1016,14 @@ const ProviderProductEditionView = ({
|
|
|
950
1016
|
};
|
|
951
1017
|
|
|
952
1018
|
dispatch({ type: "SET_PRODUCT", payload: updatedProduct });
|
|
953
|
-
|
|
954
|
-
|
|
1019
|
+
/*
|
|
1020
|
+
Se vuelve a pedir, no se vacía.
|
|
1021
|
+
|
|
1022
|
+
`setFamily(null)` invalidaba la caché, pero la lista solo se pide al pulsar
|
|
1023
|
+
el desplegable: si estaba abierto al ligar, se quedaba en «Cargando
|
|
1024
|
+
familia…» para siempre, porque ya nadie iba a volver a pedirla.
|
|
1025
|
+
*/
|
|
1026
|
+
loadFamily(true);
|
|
955
1027
|
// Y los servicios, para que los chips reflejen la herencia recién creada.
|
|
956
1028
|
setLinkNonce((n) => n + 1);
|
|
957
1029
|
|
|
@@ -1513,6 +1585,14 @@ const ProviderProductEditionView = ({
|
|
|
1513
1585
|
onLinked={handleOnLinkedVariants}
|
|
1514
1586
|
/>
|
|
1515
1587
|
)}
|
|
1588
|
+
{porDesvincular && (
|
|
1589
|
+
<UnlinkVariantModal
|
|
1590
|
+
{...porDesvincular}
|
|
1591
|
+
token={token}
|
|
1592
|
+
onClose={() => setPorDesvincular(null)}
|
|
1593
|
+
onUnlinked={handleOnUnlinked}
|
|
1594
|
+
/>
|
|
1595
|
+
)}
|
|
1516
1596
|
{showModal && (
|
|
1517
1597
|
<ProductImageModal
|
|
1518
1598
|
images={state.images_values}
|
|
@@ -1759,43 +1839,92 @@ const ProviderProductEditionView = ({
|
|
|
1759
1839
|
</p>
|
|
1760
1840
|
)}
|
|
1761
1841
|
|
|
1842
|
+
{/* Desvincular se ofrece donde se ve el vínculo, y solo en
|
|
1843
|
+
la dirección que corresponde a esta ficha: desde un hijo,
|
|
1844
|
+
sobre su padre —«me suelto»—; desde un padre, sobre cada
|
|
1845
|
+
hijo. A un hermano no: para eso se abre su ficha, donde la
|
|
1846
|
+
acción dice lo que de verdad va a pasar. */}
|
|
1762
1847
|
{family?.parent && (
|
|
1763
|
-
<
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1848
|
+
<div className="family-item">
|
|
1849
|
+
<button
|
|
1850
|
+
type="button"
|
|
1851
|
+
className="family-row parent"
|
|
1852
|
+
disabled={loadingVariant !== null}
|
|
1853
|
+
onClick={() => openVariant(family.parent.articleId)}
|
|
1854
|
+
>
|
|
1855
|
+
<span className="role">
|
|
1856
|
+
{loadingVariant === family.parent.articleId
|
|
1857
|
+
? "Abriendo…"
|
|
1858
|
+
: "Producto padre"}
|
|
1859
|
+
</span>
|
|
1860
|
+
<span className="name">{family.parent.name}</span>
|
|
1861
|
+
<span className="upc">{family.parent.upc}</span>
|
|
1862
|
+
</button>
|
|
1863
|
+
|
|
1864
|
+
<button
|
|
1865
|
+
type="button"
|
|
1866
|
+
className="desvincular"
|
|
1867
|
+
title="Dejar de ser hijo de este producto"
|
|
1868
|
+
onClick={() =>
|
|
1869
|
+
setPorDesvincular({
|
|
1870
|
+
mode: "self",
|
|
1871
|
+
childArticleId: state.product?.id_article,
|
|
1872
|
+
childName: state.product?.name,
|
|
1873
|
+
childUpc: state.product?.upc,
|
|
1874
|
+
parentName: family.parent.name,
|
|
1875
|
+
parentUpc: family.parent.upc,
|
|
1876
|
+
})
|
|
1877
|
+
}
|
|
1878
|
+
>
|
|
1879
|
+
Desvincular
|
|
1880
|
+
</button>
|
|
1881
|
+
</div>
|
|
1777
1882
|
)}
|
|
1778
1883
|
|
|
1779
1884
|
{family?.variants?.map((variant) => (
|
|
1780
|
-
<
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1885
|
+
<div className="family-item" key={variant.articleId}>
|
|
1886
|
+
<button
|
|
1887
|
+
type="button"
|
|
1888
|
+
className={`family-row${
|
|
1889
|
+
variant.isCurrent ? " current" : ""
|
|
1890
|
+
}`}
|
|
1891
|
+
disabled={variant.isCurrent || loadingVariant !== null}
|
|
1892
|
+
onClick={() => openVariant(variant.articleId)}
|
|
1893
|
+
>
|
|
1894
|
+
<span className="role">
|
|
1895
|
+
{loadingVariant === variant.articleId
|
|
1896
|
+
? "Abriendo…"
|
|
1897
|
+
: variant.isCurrent
|
|
1898
|
+
? "Estás aquí"
|
|
1899
|
+
: "Hijo"}
|
|
1900
|
+
</span>
|
|
1901
|
+
<span className="name">{variant.name}</span>
|
|
1902
|
+
<span className="upc">{variant.upc}</span>
|
|
1903
|
+
</button>
|
|
1904
|
+
|
|
1905
|
+
{/* Solo cuando esta ficha ES el padre: si hay `parent`, lo
|
|
1906
|
+
que se lista son hermanos y este producto no manda
|
|
1907
|
+
sobre su vínculo. */}
|
|
1908
|
+
{!family.parent && !variant.isCurrent && (
|
|
1909
|
+
<button
|
|
1910
|
+
type="button"
|
|
1911
|
+
className="desvincular"
|
|
1912
|
+
title="Desvincular este hijo"
|
|
1913
|
+
onClick={() =>
|
|
1914
|
+
setPorDesvincular({
|
|
1915
|
+
mode: "child",
|
|
1916
|
+
childArticleId: variant.articleId,
|
|
1917
|
+
childName: variant.name,
|
|
1918
|
+
childUpc: variant.upc,
|
|
1919
|
+
parentName: state.product?.name,
|
|
1920
|
+
parentUpc: state.product?.upc,
|
|
1921
|
+
})
|
|
1922
|
+
}
|
|
1923
|
+
>
|
|
1924
|
+
Desvincular
|
|
1925
|
+
</button>
|
|
1926
|
+
)}
|
|
1927
|
+
</div>
|
|
1799
1928
|
))}
|
|
1800
1929
|
|
|
1801
1930
|
{family && !family.error && !family.variants?.length && (
|
|
@@ -208,6 +208,36 @@ export const Container = styled.div`
|
|
|
208
208
|
color: ${GlobalColors.gray};
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
+
/* La fila es un botón que navega; desvincular tiene que quedar FUERA de
|
|
212
|
+
él —un botón dentro de otro no es HTML válido y el clic se confunde—. */
|
|
213
|
+
.family-item {
|
|
214
|
+
display: flex;
|
|
215
|
+
align-items: center;
|
|
216
|
+
gap: 4px;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.family-item .family-row {
|
|
220
|
+
flex: 1;
|
|
221
|
+
min-width: 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.desvincular {
|
|
225
|
+
flex-shrink: 0;
|
|
226
|
+
border: none;
|
|
227
|
+
background: none;
|
|
228
|
+
padding: 4px 6px;
|
|
229
|
+
cursor: pointer;
|
|
230
|
+
font-family: ${FontFamily.Raleway_500};
|
|
231
|
+
font-size: 10px;
|
|
232
|
+
color: ${GlobalColors.gray};
|
|
233
|
+
text-decoration: underline;
|
|
234
|
+
white-space: nowrap;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.desvincular:hover {
|
|
238
|
+
color: ${PINK};
|
|
239
|
+
}
|
|
240
|
+
|
|
211
241
|
.family-row {
|
|
212
242
|
display: flex;
|
|
213
243
|
align-items: baseline;
|