contentoh-components-library 21.6.21 → 21.6.23
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/atoms/InheritanceTag/index.js +7 -0
- package/dist/components/molecules/TagAndInput/index.js +2 -0
- package/dist/components/molecules/TagAndInputv2/index.js +2 -0
- package/dist/components/organisms/InputGroup/index.js +17 -16
- package/dist/components/organisms/LinkVariantsModal/index.js +359 -114
- package/dist/components/organisms/LinkVariantsModal/styles.js +15 -3
- package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.context.js +22 -13
- package/dist/components/pages/ProviderProductEdition/index.js +307 -107
- package/dist/components/pages/ProviderProductEdition/styles.js +2 -2
- package/package.json +1 -1
- package/src/components/atoms/InheritanceTag/index.js +6 -0
- package/src/components/molecules/TagAndInput/index.js +2 -0
- package/src/components/molecules/TagAndInputv2/index.js +2 -0
- package/src/components/organisms/InputGroup/index.js +1 -0
- package/src/components/organisms/LinkVariantsModal/index.js +347 -53
- package/src/components/organisms/LinkVariantsModal/styles.js +120 -0
- package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx +14 -1
- package/src/components/pages/ProviderProductEdition/index.js +161 -3
- package/src/components/pages/ProviderProductEdition/styles.js +68 -0
|
@@ -15,9 +15,9 @@ var _variables = require("../../../global-files/variables");
|
|
|
15
15
|
|
|
16
16
|
var _templateObject;
|
|
17
17
|
|
|
18
|
-
var Container = _styledComponents.default.div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n flex-direction: column;\n height: 100%;\n flex: 1;\n overflow: auto;\n\n .data-container {\n display: flex;\n flex: 0%;\n height: calc(100% - ", "px);\n .image-data-panel {\n width: 340px;\n\n & + * {\n margin-left: 10px;\n }\n }\n\n .product-information {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n\n .services-information-container {\n height: 100%;\n overflow: auto;\n }\n\n .image-services {\n aside {\n display: grid;\n grid-template-columns: repeat(auto-fill, 179px);\n column-gap: 15px;\n row-gap: 15px;\n padding: 20px;\n }\n }\n\n .commentary-box {\n display: flex;\n justify-content: space-between;\n align-items: flex-end;\n padding: 10px;\n padding-left: 0;\n\n .commentary {\n display: flex;\n align-items: flex-end;\n\n .input-container {\n width: 500px;\n\n .quill {\n height: 100px;\n }\n\n & + * {\n margin-left: 5px;\n }\n }\n\n .buttons-box {\n display: flex;\n width: 210px;\n flex-wrap: wrap;\n\n .general-transparent-button {\n & + * {\n margin-top: 5px;\n }\n }\n\n .general-transparent-button,\n .general-green-button,\n .general-button-disabled {\n width: fit-content;\n min-width: 201px;\n height: 40px;\n }\n }\n }\n }\n\n .feedback-box {\n display: flex;\n }\n\n .required-inputs-message {\n font-family: ", ";\n font-size: 13px;\n color: ", ";\n padding: 10px;\n display: flex;\n align-items: center;\n\n p + * {\n margin-top: 10px;\n }\n\n button {\n min-width: fit-content;\n }\n }\n }\n }\n #modal-message-box {\n width: 400px;\n height: 100px;\n }\n .container {\n width: 100%;\n height: 90%;\n .dropzone {\n height: 100%;\n width: 100%;\n position: relative;\n transition: all 0.5s ease;\n\n &.drag-active {\n background-color: rgba(", ", 0.05);\n border: 2px dashed ", ";\n border-radius: 8px;\n\n aside {\n opacity: 0.3;\n pointer-events: none;\n }\n }\n\n .drag-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(", ", 0.1);\n border-radius: 8px;\n pointer-events: none;\n z-index: 10;\n\n p {\n font-family: ", ";\n font-size: 24px;\n font-weight: 600;\n color: ", ";\n text-align: center;\n padding: 20px;\n background-color: ", ";\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n }\n }\n }\n .variants-actions {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 8px;\n\n .link-variants {\n border: 1px solid ", ";\n border-radius: 6px;\n background: none;\n padding: 6px 12px;\n font-family: ", ";\n font-size: 11px;\n color: ", ";\n cursor: pointer;\n }\n\n .variants-count {\n font-family: ", ";\n font-size: 11px;\n color: ", ";\n }\n }\n"])), function (_ref) {
|
|
18
|
+
var Container = _styledComponents.default.div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n flex-direction: column;\n height: 100%;\n flex: 1;\n overflow: auto;\n\n .data-container {\n display: flex;\n flex: 0%;\n height: calc(100% - ", "px);\n .image-data-panel {\n width: 340px;\n\n & + * {\n margin-left: 10px;\n }\n }\n\n .product-information {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n\n .services-information-container {\n height: 100%;\n overflow: auto;\n }\n\n .image-services {\n aside {\n display: grid;\n grid-template-columns: repeat(auto-fill, 179px);\n column-gap: 15px;\n row-gap: 15px;\n padding: 20px;\n }\n }\n\n .commentary-box {\n display: flex;\n justify-content: space-between;\n align-items: flex-end;\n padding: 10px;\n padding-left: 0;\n\n .commentary {\n display: flex;\n align-items: flex-end;\n\n .input-container {\n width: 500px;\n\n .quill {\n height: 100px;\n }\n\n & + * {\n margin-left: 5px;\n }\n }\n\n .buttons-box {\n display: flex;\n width: 210px;\n flex-wrap: wrap;\n\n .general-transparent-button {\n & + * {\n margin-top: 5px;\n }\n }\n\n .general-transparent-button,\n .general-green-button,\n .general-button-disabled {\n width: fit-content;\n min-width: 201px;\n height: 40px;\n }\n }\n }\n }\n\n .feedback-box {\n display: flex;\n }\n\n .required-inputs-message {\n font-family: ", ";\n font-size: 13px;\n color: ", ";\n padding: 10px;\n display: flex;\n align-items: center;\n\n p + * {\n margin-top: 10px;\n }\n\n button {\n min-width: fit-content;\n }\n }\n }\n }\n #modal-message-box {\n width: 400px;\n height: 100px;\n }\n .container {\n width: 100%;\n height: 90%;\n .dropzone {\n height: 100%;\n width: 100%;\n position: relative;\n transition: all 0.5s ease;\n\n &.drag-active {\n background-color: rgba(", ", 0.05);\n border: 2px dashed ", ";\n border-radius: 8px;\n\n aside {\n opacity: 0.3;\n pointer-events: none;\n }\n }\n\n .drag-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(", ", 0.1);\n border-radius: 8px;\n pointer-events: none;\n z-index: 10;\n\n p {\n font-family: ", ";\n font-size: 24px;\n font-weight: 600;\n color: ", ";\n text-align: center;\n padding: 20px;\n background-color: ", ";\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n }\n }\n }\n .variants-actions {\n display: flex;\n align-items: center;\n gap: 10px;\n margin-bottom: 8px;\n\n .link-variants {\n border: 1px solid ", ";\n border-radius: 6px;\n background: none;\n padding: 6px 12px;\n font-family: ", ";\n font-size: 11px;\n color: ", ";\n cursor: pointer;\n }\n\n .variants-count {\n border: none;\n background: none;\n padding: 0;\n cursor: pointer;\n font-family: ", ";\n font-size: 11px;\n color: ", ";\n text-decoration: underline;\n }\n }\n\n .variants-family {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin-bottom: 10px;\n padding: 8px;\n border: 1px solid ", ";\n border-radius: 6px;\n\n .loading {\n margin: 0;\n font-family: ", ";\n font-size: 11px;\n color: ", ";\n }\n\n .family-row {\n display: flex;\n align-items: baseline;\n gap: 8px;\n padding: 6px 8px;\n border: none;\n border-radius: 4px;\n background: none;\n cursor: pointer;\n text-align: left;\n font-family: ", ";\n font-size: 12px;\n color: ", ";\n }\n\n .family-row:hover:not(:disabled) {\n background-color: ", ";\n }\n\n .family-row:disabled {\n cursor: default;\n opacity: 0.7;\n }\n\n .family-row .role {\n min-width: 96px;\n font-size: 10px;\n color: ", ";\n }\n\n .family-row.current .role {\n color: ", ";\n }\n\n .family-row .name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .family-row .upc {\n font-size: 11px;\n color: ", ";\n }\n }\n"])), function (_ref) {
|
|
19
19
|
var headerTop = _ref.headerTop;
|
|
20
20
|
return headerTop;
|
|
21
|
-
}, _variables.FontFamily.AvenirNext, _variables.GlobalColors.color_gray, _variables.GlobalColors.rgb_color_pink, _variables.GlobalColors.color_pink, _variables.GlobalColors.rgb_color_pink, _variables.FontFamily.AvenirNext, _variables.GlobalColors.color_pink, _variables.GlobalColors.white, _variables.GlobalColors.original_magenta, _variables.FontFamily.Raleway_600, _variables.GlobalColors.original_magenta, _variables.FontFamily.Raleway_500, _variables.GlobalColors.gray);
|
|
21
|
+
}, _variables.FontFamily.AvenirNext, _variables.GlobalColors.color_gray, _variables.GlobalColors.rgb_color_pink, _variables.GlobalColors.color_pink, _variables.GlobalColors.rgb_color_pink, _variables.FontFamily.AvenirNext, _variables.GlobalColors.color_pink, _variables.GlobalColors.white, _variables.GlobalColors.original_magenta, _variables.FontFamily.Raleway_600, _variables.GlobalColors.original_magenta, _variables.FontFamily.Raleway_500, _variables.GlobalColors.gray, _variables.GlobalColors.s2, _variables.FontFamily.Raleway_500, _variables.GlobalColors.gray, _variables.FontFamily.Raleway_500, _variables.GlobalColors.deep_gray, _variables.GlobalColors.s2, _variables.GlobalColors.original_magenta, _variables.GlobalColors.gray, _variables.GlobalColors.gray);
|
|
22
22
|
|
|
23
23
|
exports.Container = Container;
|
package/package.json
CHANGED
|
@@ -14,11 +14,16 @@ import { Container } from "./styles";
|
|
|
14
14
|
* que llamarlo "Heredado" es falso además de ruidoso. Sin esto la ficha de una
|
|
15
15
|
* variante sale con el chip repetido en cada campo, incluidos los obligatorios en
|
|
16
16
|
* rojo que están sin capturar, y la marca deja de distinguir nada.
|
|
17
|
+
*
|
|
18
|
+
* Tampoco la lleva un atributo NO heredable. El UPC y el SKU son la identidad del
|
|
19
|
+
* producto: el servidor los excluye de link y propagate, así que pintarlos como
|
|
20
|
+
* "Propio" y ofrecer "Volver a heredar" daría un botón incapaz de hacer nada.
|
|
17
21
|
*/
|
|
18
22
|
export const InheritanceTag = ({
|
|
19
23
|
isVariant = false,
|
|
20
24
|
isOverridden = false,
|
|
21
25
|
hasValue = true,
|
|
26
|
+
inheritable = true,
|
|
22
27
|
parentUpc,
|
|
23
28
|
onRestore,
|
|
24
29
|
restoreLabel = "Volver a heredar",
|
|
@@ -26,6 +31,7 @@ export const InheritanceTag = ({
|
|
|
26
31
|
}) => {
|
|
27
32
|
if (!isVariant) return null;
|
|
28
33
|
if (!hasValue) return null;
|
|
34
|
+
if (!inheritable) return null;
|
|
29
35
|
|
|
30
36
|
const state = isOverridden ? "own" : "inherited";
|
|
31
37
|
|
|
@@ -47,6 +47,7 @@ export const TagAndInput = ({
|
|
|
47
47
|
boxOnboardingData,
|
|
48
48
|
isVariant,
|
|
49
49
|
isOverridden,
|
|
50
|
+
inheritable,
|
|
50
51
|
parentUpc,
|
|
51
52
|
onRestoreInheritance,
|
|
52
53
|
}) => {
|
|
@@ -332,6 +333,7 @@ export const TagAndInput = ({
|
|
|
332
333
|
isVariant={isVariant}
|
|
333
334
|
isOverridden={isOverridden}
|
|
334
335
|
hasValue={`${value ?? ""}`.trim() !== ""}
|
|
336
|
+
inheritable={inheritable}
|
|
335
337
|
parentUpc={parentUpc}
|
|
336
338
|
onRestore={
|
|
337
339
|
onRestoreInheritance
|
|
@@ -36,6 +36,7 @@ export const TagAndInputv2 = ({
|
|
|
36
36
|
showMissingChars,
|
|
37
37
|
isVariant,
|
|
38
38
|
isOverridden,
|
|
39
|
+
inheritable,
|
|
39
40
|
parentUpc,
|
|
40
41
|
onRestoreInheritance,
|
|
41
42
|
}) => {
|
|
@@ -64,6 +65,7 @@ export const TagAndInputv2 = ({
|
|
|
64
65
|
isVariant={isVariant}
|
|
65
66
|
isOverridden={isOverridden}
|
|
66
67
|
hasValue={`${value ?? ""}`.trim() !== ""}
|
|
68
|
+
inheritable={inheritable}
|
|
67
69
|
parentUpc={parentUpc}
|
|
68
70
|
onRestore={
|
|
69
71
|
onRestoreInheritance
|
|
@@ -234,6 +234,7 @@ export const InputGroup = ({
|
|
|
234
234
|
showTooltip={true}
|
|
235
235
|
isVariant={variant?.isVariant}
|
|
236
236
|
isOverridden={dataInputs[input]?.isOverridden}
|
|
237
|
+
inheritable={dataInputs[input]?.inheritable}
|
|
237
238
|
parentUpc={variant?.parent?.upc}
|
|
238
239
|
onRestoreInheritance={onRestoreInheritance}
|
|
239
240
|
auditClass={
|
|
@@ -13,6 +13,9 @@ import {
|
|
|
13
13
|
List,
|
|
14
14
|
AttributeList,
|
|
15
15
|
Section,
|
|
16
|
+
SectionHead,
|
|
17
|
+
ImageGrid,
|
|
18
|
+
AddRetailer,
|
|
16
19
|
Message,
|
|
17
20
|
Footer,
|
|
18
21
|
} from "./styles";
|
|
@@ -66,6 +69,8 @@ export const LinkVariantsModal = ({
|
|
|
66
69
|
articleName,
|
|
67
70
|
articleUpc,
|
|
68
71
|
activeRetailerId,
|
|
72
|
+
retailersAvailable,
|
|
73
|
+
categoriesAvailable,
|
|
69
74
|
token,
|
|
70
75
|
endpoint = process.env.REACT_APP_VARIANTS_ENDPOINT,
|
|
71
76
|
onClose,
|
|
@@ -80,13 +85,29 @@ export const LinkVariantsModal = ({
|
|
|
80
85
|
const [searched, setSearched] = useState(false);
|
|
81
86
|
const [selected, setSelected] = useState([]);
|
|
82
87
|
|
|
83
|
-
|
|
88
|
+
// Lo que el padre ofrece en cada dimensión, y lo que el usuario eligió de
|
|
89
|
+
// cada una. Se guardan por separado porque se eligen por separado: heredar
|
|
90
|
+
// todos los atributos no dice nada sobre qué fotos quiere la variante.
|
|
91
|
+
const [offered, setOffered] = useState({
|
|
92
|
+
attributes: [],
|
|
93
|
+
descriptions: [],
|
|
94
|
+
images: [],
|
|
95
|
+
categoryRetailers: [],
|
|
96
|
+
});
|
|
97
|
+
const [chosen, setChosen] = useState({
|
|
98
|
+
attributes: [],
|
|
99
|
+
descriptions: [],
|
|
100
|
+
images: [],
|
|
101
|
+
categoryRetailers: [],
|
|
102
|
+
});
|
|
84
103
|
const [nameScope, setNameScope] = useState(null);
|
|
85
104
|
const [inheritMode, setInheritMode] = useState("all-filled");
|
|
86
|
-
const [
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const [
|
|
105
|
+
const [openSection, setOpenSection] = useState("attributes");
|
|
106
|
+
|
|
107
|
+
// Cadenas que el padre NO tiene y el usuario decidió agregar a la variante.
|
|
108
|
+
const [extraRetailers, setExtraRetailers] = useState([]);
|
|
109
|
+
const [newRetailer, setNewRetailer] = useState("");
|
|
110
|
+
const [newCategory, setNewCategory] = useState("");
|
|
90
111
|
|
|
91
112
|
const [loading, setLoading] = useState(false);
|
|
92
113
|
const [error, setError] = useState(null);
|
|
@@ -160,9 +181,27 @@ export const LinkVariantsModal = ({
|
|
|
160
181
|
parentArticleId,
|
|
161
182
|
retailerId: activeRetailerId,
|
|
162
183
|
});
|
|
163
|
-
|
|
184
|
+
|
|
185
|
+
const listas = {
|
|
186
|
+
attributes: data.attributes || [],
|
|
187
|
+
descriptions: data.descriptions || [],
|
|
188
|
+
images: data.images || [],
|
|
189
|
+
categoryRetailers: data.categoryRetailers || [],
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
setOffered(listas);
|
|
164
193
|
setNameScope(data.nameScope ?? null);
|
|
165
|
-
|
|
194
|
+
// Todo preseleccionado: heredar es el caso normal, y quitar lo que sobra
|
|
195
|
+
// es menos trabajo que marcar de cero lo que casi siempre se quiere.
|
|
196
|
+
setChosen({
|
|
197
|
+
attributes: listas.attributes.map((item) => item.id),
|
|
198
|
+
descriptions: listas.descriptions.map((item) => item.id),
|
|
199
|
+
images: listas.images.map((item) => item.id),
|
|
200
|
+
categoryRetailers: listas.categoryRetailers.map(
|
|
201
|
+
(item) => `${item.retailerId}-${item.categoryId}`
|
|
202
|
+
),
|
|
203
|
+
});
|
|
204
|
+
setExtraRetailers([]);
|
|
166
205
|
setStep("inherit");
|
|
167
206
|
} catch (err) {
|
|
168
207
|
setError(readError(err));
|
|
@@ -171,23 +210,86 @@ export const LinkVariantsModal = ({
|
|
|
171
210
|
}
|
|
172
211
|
};
|
|
173
212
|
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
current
|
|
177
|
-
|
|
178
|
-
|
|
213
|
+
const toggleChoice = (dimension, id) => {
|
|
214
|
+
setChosen((current) => {
|
|
215
|
+
const lista = current[dimension];
|
|
216
|
+
return {
|
|
217
|
+
...current,
|
|
218
|
+
[dimension]: lista.includes(id)
|
|
219
|
+
? lista.filter((item) => item !== id)
|
|
220
|
+
: [...lista, id],
|
|
221
|
+
};
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const toggleAll = (dimension, ids) => {
|
|
226
|
+
setChosen((current) => ({
|
|
227
|
+
...current,
|
|
228
|
+
[dimension]: current[dimension].length === ids.length ? [] : ids,
|
|
229
|
+
}));
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
const addRetailer = () => {
|
|
233
|
+
const retailerId = Number(newRetailer);
|
|
234
|
+
const categoryId = Number(newCategory);
|
|
235
|
+
if (!retailerId || !categoryId) return;
|
|
236
|
+
|
|
237
|
+
const clave = `${retailerId}-${categoryId}`;
|
|
238
|
+
const yaEsta =
|
|
239
|
+
offered.categoryRetailers.some(
|
|
240
|
+
(item) => `${item.retailerId}-${item.categoryId}` === clave
|
|
241
|
+
) || extraRetailers.some((item) => item.clave === clave);
|
|
242
|
+
|
|
243
|
+
if (yaEsta) return;
|
|
244
|
+
|
|
245
|
+
const retailer = (retailersAvailable || []).find(
|
|
246
|
+
(item) => Number(item.id ?? item.value) === retailerId
|
|
247
|
+
);
|
|
248
|
+
const category = (categoriesAvailable || []).find(
|
|
249
|
+
(item) => Number(item.id ?? item.value) === categoryId
|
|
179
250
|
);
|
|
251
|
+
|
|
252
|
+
setExtraRetailers((current) => [
|
|
253
|
+
...current,
|
|
254
|
+
{
|
|
255
|
+
clave,
|
|
256
|
+
retailerId,
|
|
257
|
+
categoryId,
|
|
258
|
+
retailerName: retailer?.name ?? retailer?.label ?? `Cadena ${retailerId}`,
|
|
259
|
+
categoryName: category?.name ?? category?.label ?? `Categoría ${categoryId}`,
|
|
260
|
+
},
|
|
261
|
+
]);
|
|
262
|
+
setChosen((current) => ({
|
|
263
|
+
...current,
|
|
264
|
+
categoryRetailers: [...current.categoryRetailers, clave],
|
|
265
|
+
}));
|
|
266
|
+
setNewRetailer("");
|
|
267
|
+
setNewCategory("");
|
|
180
268
|
};
|
|
181
269
|
|
|
182
270
|
const submit = async () => {
|
|
183
271
|
setLoading(true);
|
|
184
272
|
setError(null);
|
|
185
273
|
|
|
274
|
+
// Las parejas cadena+categoría viajan como objetos, no como ids: pueden ser
|
|
275
|
+
// cadenas que el padre no tiene, y ahí no hay nada que "heredar" — se asigna.
|
|
276
|
+
const todasLasParejas = [
|
|
277
|
+
...offered.categoryRetailers.map((item) => ({
|
|
278
|
+
clave: `${item.retailerId}-${item.categoryId}`,
|
|
279
|
+
retailerId: item.retailerId,
|
|
280
|
+
categoryId: item.categoryId,
|
|
281
|
+
})),
|
|
282
|
+
...extraRetailers,
|
|
283
|
+
];
|
|
284
|
+
|
|
186
285
|
const inherit = {
|
|
187
|
-
attributes:
|
|
188
|
-
|
|
189
|
-
descriptions:
|
|
190
|
-
|
|
286
|
+
attributes:
|
|
287
|
+
inheritMode === "all-filled" ? "all-filled" : chosen.attributes,
|
|
288
|
+
descriptions: chosen.descriptions,
|
|
289
|
+
images: chosen.images,
|
|
290
|
+
categoryRetailers: todasLasParejas
|
|
291
|
+
.filter((par) => chosen.categoryRetailers.includes(par.clave))
|
|
292
|
+
.map(({ retailerId, categoryId }) => ({ retailerId, categoryId })),
|
|
191
293
|
};
|
|
192
294
|
|
|
193
295
|
const body =
|
|
@@ -197,7 +299,14 @@ export const LinkVariantsModal = ({
|
|
|
197
299
|
|
|
198
300
|
try {
|
|
199
301
|
const data = await request("link", body);
|
|
200
|
-
|
|
302
|
+
// El modo importa para quien escucha: en `children` este producto GANA
|
|
303
|
+
// variantes; en `parent` pasa a SER una. Son efectos opuestos sobre la
|
|
304
|
+
// misma ficha, así que quien refresque el estado necesita distinguirlos.
|
|
305
|
+
onLinked?.({
|
|
306
|
+
...data,
|
|
307
|
+
mode,
|
|
308
|
+
parentArticleId: mode === "parent" ? selected[0] : articleId,
|
|
309
|
+
});
|
|
201
310
|
onClose?.();
|
|
202
311
|
} catch (err) {
|
|
203
312
|
setError(readError(err));
|
|
@@ -314,7 +423,7 @@ export const LinkVariantsModal = ({
|
|
|
314
423
|
{step === "inherit" && (
|
|
315
424
|
<>
|
|
316
425
|
<Section>
|
|
317
|
-
<h3
|
|
426
|
+
<h3>Atributos de la ficha técnica</h3>
|
|
318
427
|
<label className="choice">
|
|
319
428
|
<input
|
|
320
429
|
type="radio"
|
|
@@ -322,9 +431,10 @@ export const LinkVariantsModal = ({
|
|
|
322
431
|
onChange={() => setInheritMode("all-filled")}
|
|
323
432
|
/>
|
|
324
433
|
<span>
|
|
325
|
-
Todos los
|
|
434
|
+
Todos los que tienen valor
|
|
326
435
|
<span className="hint">
|
|
327
|
-
{attributes.length} atributo(s) con información en
|
|
436
|
+
{offered.attributes.length} atributo(s) con información en
|
|
437
|
+
el padre.
|
|
328
438
|
</span>
|
|
329
439
|
</span>
|
|
330
440
|
</label>
|
|
@@ -352,13 +462,13 @@ export const LinkVariantsModal = ({
|
|
|
352
462
|
|
|
353
463
|
{inheritMode === "selected" && (
|
|
354
464
|
<AttributeList>
|
|
355
|
-
{attributes.map((attribute) => (
|
|
465
|
+
{offered.attributes.map((attribute) => (
|
|
356
466
|
<li key={attribute.id}>
|
|
357
467
|
<label>
|
|
358
468
|
<input
|
|
359
469
|
type="checkbox"
|
|
360
|
-
checked={
|
|
361
|
-
onChange={() =>
|
|
470
|
+
checked={chosen.attributes.includes(attribute.id)}
|
|
471
|
+
onChange={() => toggleChoice("attributes", attribute.id)}
|
|
362
472
|
/>
|
|
363
473
|
<span>
|
|
364
474
|
{attribute.name}
|
|
@@ -383,36 +493,220 @@ export const LinkVariantsModal = ({
|
|
|
383
493
|
)}
|
|
384
494
|
|
|
385
495
|
<Section>
|
|
386
|
-
<
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
496
|
+
<SectionHead>
|
|
497
|
+
<button
|
|
498
|
+
type="button"
|
|
499
|
+
className="toggle"
|
|
500
|
+
aria-expanded={openSection === "descriptions"}
|
|
501
|
+
onClick={() =>
|
|
502
|
+
setOpenSection(
|
|
503
|
+
openSection === "descriptions" ? null : "descriptions"
|
|
504
|
+
)
|
|
505
|
+
}
|
|
506
|
+
>
|
|
507
|
+
Descripciones
|
|
508
|
+
<span className="count">
|
|
509
|
+
{chosen.descriptions.length} de{" "}
|
|
510
|
+
{offered.descriptions.length}
|
|
511
|
+
</span>
|
|
512
|
+
</button>
|
|
513
|
+
{offered.descriptions.length > 0 && (
|
|
514
|
+
<button
|
|
515
|
+
type="button"
|
|
516
|
+
className="all"
|
|
517
|
+
onClick={() =>
|
|
518
|
+
toggleAll(
|
|
519
|
+
"descriptions",
|
|
520
|
+
offered.descriptions.map((item) => item.id)
|
|
521
|
+
)
|
|
522
|
+
}
|
|
523
|
+
>
|
|
524
|
+
{chosen.descriptions.length === offered.descriptions.length
|
|
525
|
+
? "Ninguna"
|
|
526
|
+
: "Todas"}
|
|
527
|
+
</button>
|
|
528
|
+
)}
|
|
529
|
+
</SectionHead>
|
|
530
|
+
|
|
531
|
+
{openSection === "descriptions" &&
|
|
532
|
+
(offered.descriptions.length ? (
|
|
533
|
+
<AttributeList>
|
|
534
|
+
{offered.descriptions.map((item) => (
|
|
535
|
+
<li key={item.id}>
|
|
536
|
+
<label>
|
|
537
|
+
<input
|
|
538
|
+
type="checkbox"
|
|
539
|
+
checked={chosen.descriptions.includes(item.id)}
|
|
540
|
+
onChange={() => toggleChoice("descriptions", item.id)}
|
|
541
|
+
/>
|
|
542
|
+
<span>{item.name}</span>
|
|
543
|
+
<span className="value" title={item.value}>
|
|
544
|
+
{item.value}
|
|
545
|
+
</span>
|
|
546
|
+
</label>
|
|
547
|
+
</li>
|
|
548
|
+
))}
|
|
549
|
+
</AttributeList>
|
|
550
|
+
) : (
|
|
551
|
+
<Message>El producto padre no tiene descripciones.</Message>
|
|
552
|
+
))}
|
|
553
|
+
</Section>
|
|
554
|
+
|
|
555
|
+
<Section>
|
|
556
|
+
<SectionHead>
|
|
557
|
+
<button
|
|
558
|
+
type="button"
|
|
559
|
+
className="toggle"
|
|
560
|
+
aria-expanded={openSection === "images"}
|
|
561
|
+
onClick={() =>
|
|
562
|
+
setOpenSection(openSection === "images" ? null : "images")
|
|
563
|
+
}
|
|
564
|
+
>
|
|
565
|
+
Imágenes
|
|
566
|
+
<span className="count">
|
|
567
|
+
{chosen.images.length} de {offered.images.length}
|
|
568
|
+
</span>
|
|
569
|
+
</button>
|
|
570
|
+
{offered.images.length > 0 && (
|
|
571
|
+
<button
|
|
572
|
+
type="button"
|
|
573
|
+
className="all"
|
|
574
|
+
onClick={() =>
|
|
575
|
+
toggleAll(
|
|
576
|
+
"images",
|
|
577
|
+
offered.images.map((item) => item.id)
|
|
578
|
+
)
|
|
579
|
+
}
|
|
580
|
+
>
|
|
581
|
+
{chosen.images.length === offered.images.length
|
|
582
|
+
? "Ninguna"
|
|
583
|
+
: "Todas"}
|
|
584
|
+
</button>
|
|
585
|
+
)}
|
|
586
|
+
</SectionHead>
|
|
587
|
+
|
|
588
|
+
{openSection === "images" &&
|
|
589
|
+
(offered.images.length ? (
|
|
590
|
+
<ImageGrid>
|
|
591
|
+
{offered.images.map((image) => (
|
|
592
|
+
<label
|
|
593
|
+
key={image.id}
|
|
594
|
+
className={
|
|
595
|
+
chosen.images.includes(image.id) ? "picked" : ""
|
|
596
|
+
}
|
|
597
|
+
>
|
|
598
|
+
<input
|
|
599
|
+
type="checkbox"
|
|
600
|
+
checked={chosen.images.includes(image.id)}
|
|
601
|
+
onChange={() => toggleChoice("images", image.id)}
|
|
602
|
+
/>
|
|
603
|
+
<img src={image.src} alt={image.imageType || ""} />
|
|
604
|
+
<span>{image.imageType || "Sin tipo"}</span>
|
|
605
|
+
</label>
|
|
606
|
+
))}
|
|
607
|
+
</ImageGrid>
|
|
608
|
+
) : (
|
|
609
|
+
<Message>El producto padre no tiene imágenes.</Message>
|
|
610
|
+
))}
|
|
611
|
+
</Section>
|
|
612
|
+
|
|
613
|
+
<Section>
|
|
614
|
+
<SectionHead>
|
|
615
|
+
<button
|
|
616
|
+
type="button"
|
|
617
|
+
className="toggle"
|
|
618
|
+
aria-expanded={openSection === "retailers"}
|
|
619
|
+
onClick={() =>
|
|
620
|
+
setOpenSection(
|
|
621
|
+
openSection === "retailers" ? null : "retailers"
|
|
622
|
+
)
|
|
623
|
+
}
|
|
624
|
+
>
|
|
410
625
|
Cadenas y categorías
|
|
411
|
-
<span className="
|
|
412
|
-
|
|
626
|
+
<span className="count">
|
|
627
|
+
{chosen.categoryRetailers.length} seleccionada(s)
|
|
413
628
|
</span>
|
|
414
|
-
</
|
|
415
|
-
</
|
|
629
|
+
</button>
|
|
630
|
+
</SectionHead>
|
|
631
|
+
|
|
632
|
+
{openSection === "retailers" && (
|
|
633
|
+
<>
|
|
634
|
+
<List>
|
|
635
|
+
{[
|
|
636
|
+
...offered.categoryRetailers.map((item) => ({
|
|
637
|
+
...item,
|
|
638
|
+
clave: `${item.retailerId}-${item.categoryId}`,
|
|
639
|
+
delPadre: true,
|
|
640
|
+
})),
|
|
641
|
+
...extraRetailers.map((item) => ({
|
|
642
|
+
...item,
|
|
643
|
+
delPadre: false,
|
|
644
|
+
})),
|
|
645
|
+
].map((item) => (
|
|
646
|
+
<li key={item.clave}>
|
|
647
|
+
<label>
|
|
648
|
+
<input
|
|
649
|
+
type="checkbox"
|
|
650
|
+
checked={chosen.categoryRetailers.includes(
|
|
651
|
+
item.clave
|
|
652
|
+
)}
|
|
653
|
+
onChange={() =>
|
|
654
|
+
toggleChoice("categoryRetailers", item.clave)
|
|
655
|
+
}
|
|
656
|
+
/>
|
|
657
|
+
<span>
|
|
658
|
+
{item.retailerName}
|
|
659
|
+
<span className="meta">
|
|
660
|
+
{item.categoryName || "Sin categoría"}
|
|
661
|
+
{!item.delPadre && " · no la tiene el padre"}
|
|
662
|
+
</span>
|
|
663
|
+
</span>
|
|
664
|
+
</label>
|
|
665
|
+
</li>
|
|
666
|
+
))}
|
|
667
|
+
</List>
|
|
668
|
+
|
|
669
|
+
{/* Agregar una cadena que el padre no tiene. No es herencia:
|
|
670
|
+
la variante entra a esa cadena por su cuenta. */}
|
|
671
|
+
<AddRetailer>
|
|
672
|
+
<select
|
|
673
|
+
value={newRetailer}
|
|
674
|
+
onChange={(event) => setNewRetailer(event.target.value)}
|
|
675
|
+
>
|
|
676
|
+
<option value="">Agregar otra cadena…</option>
|
|
677
|
+
{(retailersAvailable || []).map((item) => (
|
|
678
|
+
<option
|
|
679
|
+
key={item.id ?? item.value}
|
|
680
|
+
value={item.id ?? item.value}
|
|
681
|
+
>
|
|
682
|
+
{item.name ?? item.label}
|
|
683
|
+
</option>
|
|
684
|
+
))}
|
|
685
|
+
</select>
|
|
686
|
+
<select
|
|
687
|
+
value={newCategory}
|
|
688
|
+
onChange={(event) => setNewCategory(event.target.value)}
|
|
689
|
+
>
|
|
690
|
+
<option value="">Categoría…</option>
|
|
691
|
+
{(categoriesAvailable || []).map((item) => (
|
|
692
|
+
<option
|
|
693
|
+
key={item.id ?? item.value}
|
|
694
|
+
value={item.id ?? item.value}
|
|
695
|
+
>
|
|
696
|
+
{item.name ?? item.label}
|
|
697
|
+
</option>
|
|
698
|
+
))}
|
|
699
|
+
</select>
|
|
700
|
+
<button
|
|
701
|
+
type="button"
|
|
702
|
+
onClick={addRetailer}
|
|
703
|
+
disabled={!newRetailer || !newCategory}
|
|
704
|
+
>
|
|
705
|
+
Agregar
|
|
706
|
+
</button>
|
|
707
|
+
</AddRetailer>
|
|
708
|
+
</>
|
|
709
|
+
)}
|
|
416
710
|
</Section>
|
|
417
711
|
|
|
418
712
|
{/* Es la diferencia entre link y propagate, y es la que sorprende:
|
|
@@ -464,8 +758,8 @@ export const LinkVariantsModal = ({
|
|
|
464
758
|
// Con el padre sin atributos heredables, ligar sigue siendo
|
|
465
759
|
// válido: se heredan imágenes, descripciones y cadenas.
|
|
466
760
|
(inheritMode === "selected" &&
|
|
467
|
-
attributes.length > 0 &&
|
|
468
|
-
!
|
|
761
|
+
offered.attributes.length > 0 &&
|
|
762
|
+
!chosen.attributes.length)
|
|
469
763
|
}
|
|
470
764
|
>
|
|
471
765
|
{loading ? "Ligando…" : "Ligar"}
|