contentoh-components-library 21.6.33 → 21.6.35
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/LinkVariantsModal/styles.js +1 -1
- package/dist/components/pages/ProviderProductEdition/index.js +20 -3
- package/dist/components/pages/RetailerProductEdition/index.js +350 -195
- package/dist/components/pages/RetailerProductEdition/styles.js +2 -2
- package/dist/components/pages/RetailerProductEdition/utils.js +8 -3
- package/package.json +1 -1
- package/src/components/pages/ProviderProductEdition/index.js +13 -0
- package/src/components/pages/RetailerProductEdition/index.js +149 -22
- package/src/components/pages/RetailerProductEdition/styles.js +11 -0
- package/src/components/pages/RetailerProductEdition/utils.js +10 -3
- package/dist/ai/prompts/attribute.prompt.js +0 -28
- package/dist/ai/prompts/description.prompt.js +0 -33
- package/dist/ai/schemas/attribute.schema.js +0 -35
- package/dist/ai/schemas/description.schema.js +0 -27
|
@@ -18,9 +18,9 @@ var _templateObject;
|
|
|
18
18
|
// Rosa ContentOh, el mismo del modal de ligar productos.
|
|
19
19
|
var PINK = "#E13AA8";
|
|
20
20
|
|
|
21
|
-
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 .action-buttons{\n display: flex;\n flex-direction: column;\n gap: 1rem;\n }\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\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-radius: 4px;\n text-align: left;\n font-family: ", ";\n font-size: 12px;\n color: ", ";\n }\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) {
|
|
21
|
+
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 .action-buttons{\n display: flex;\n flex-direction: column;\n gap: 1rem;\n }\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\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) {
|
|
22
22
|
var headerTop = _ref.headerTop;
|
|
23
23
|
return headerTop;
|
|
24
|
-
}, _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, PINK, _variables.FontFamily.Raleway_600, PINK, _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, PINK, _variables.GlobalColors.gray, _variables.GlobalColors.gray);
|
|
24
|
+
}, _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, PINK, _variables.FontFamily.Raleway_600, PINK, _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, PINK, _variables.GlobalColors.gray, _variables.GlobalColors.gray);
|
|
25
25
|
|
|
26
26
|
exports.Container = Container;
|
|
@@ -145,10 +145,15 @@ var normalizeProduct = function normalizeProduct(product) {
|
|
|
145
145
|
|
|
146
146
|
var retailersIdsInOrder = productData.statusByRetailer ? productData.statusByRetailer.map(function (status) {
|
|
147
147
|
return status.retailer_id;
|
|
148
|
-
}) : [];
|
|
149
|
-
|
|
148
|
+
}) : []; // Un producto sin ninguna relación de cadena+categoría activa llega con
|
|
149
|
+
// `categoryRetailer` en null, y filtrar sobre null tumbaba la pantalla entera.
|
|
150
|
+
// Se vuelve alcanzable al saltar entre productos de una familia, que es cuando
|
|
151
|
+
// se abren fichas que nadie eligió desde el listado. Se conserva el null para
|
|
152
|
+
// no cambiar lo que ya leen los consumidores.
|
|
153
|
+
|
|
154
|
+
var categoryRetailerInOrder = categoryRetailerNormalized ? categoryRetailerNormalized.filter(function (rel) {
|
|
150
155
|
return retailersIdsInOrder.includes(rel.id_retailer);
|
|
151
|
-
});
|
|
156
|
+
}) : null;
|
|
152
157
|
return {
|
|
153
158
|
id_article: productData.id_article || article.id_article || 0,
|
|
154
159
|
upc: productData.upc || article.upc || null,
|
package/package.json
CHANGED
|
@@ -207,6 +207,16 @@ const ProviderProductEditionView = ({
|
|
|
207
207
|
setProductData();
|
|
208
208
|
}, []);
|
|
209
209
|
|
|
210
|
+
/*
|
|
211
|
+
Contador que fuerza a releer los servicios tras ligar.
|
|
212
|
+
|
|
213
|
+
El efecto de abajo depende de estatus, versión y cadena activa, y ligar no
|
|
214
|
+
cambia ninguno: cambia la HERENCIA de cada campo en el servidor. Al planchar,
|
|
215
|
+
lo que era propio pasa a heredado, y sin releer los chips siguen diciendo lo
|
|
216
|
+
de antes hasta que alguien cierra y reabre el producto.
|
|
217
|
+
*/
|
|
218
|
+
const [linkNonce, setLinkNonce] = useState(0);
|
|
219
|
+
|
|
210
220
|
// Setter de los servicios y porcentages del producto
|
|
211
221
|
useEffect(() => {
|
|
212
222
|
if (!state.product || !state.active_retailer) return;
|
|
@@ -363,6 +373,7 @@ const ProviderProductEditionView = ({
|
|
|
363
373
|
state.product?.version,
|
|
364
374
|
state.active_retailer,
|
|
365
375
|
token,
|
|
376
|
+
linkNonce,
|
|
366
377
|
]);
|
|
367
378
|
|
|
368
379
|
// Actualizador de campos del ui para que coincidan con el retailer activo
|
|
@@ -941,6 +952,8 @@ const ProviderProductEditionView = ({
|
|
|
941
952
|
dispatch({ type: "SET_PRODUCT", payload: updatedProduct });
|
|
942
953
|
// La lista cacheada quedó vieja: se descarta para que vuelva a pedirse.
|
|
943
954
|
setFamily(null);
|
|
955
|
+
// Y los servicios, para que los chips reflejen la herencia recién creada.
|
|
956
|
+
setLinkNonce((n) => n + 1);
|
|
944
957
|
|
|
945
958
|
// Y en sessionStorage, que es de donde sale el producto al recargar. Sin
|
|
946
959
|
// esto el arreglo dura hasta el siguiente F5 y vuelve el contador viejo,
|
|
@@ -185,6 +185,10 @@ const RetailerProductEditionView = ({
|
|
|
185
185
|
const [showLinkVariants, setShowLinkVariants] = useState(false);
|
|
186
186
|
const [family, setFamily] = useState(null);
|
|
187
187
|
const [showFamily, setShowFamily] = useState(false);
|
|
188
|
+
const [loadingVariant, setLoadingVariant] = useState(null);
|
|
189
|
+
// Por qué un salto no se pudo hacer. Vive aparte de `family.error` porque no
|
|
190
|
+
// es un fallo al leer la familia, sino al abrir uno de sus miembros.
|
|
191
|
+
const [avisoFamilia, setAvisoFamilia] = useState(null);
|
|
188
192
|
const [pendingPropagation, setPendingPropagation] = useState(null);
|
|
189
193
|
const [preparandoPropagacion, setPreparandoPropagacion] = useState(false);
|
|
190
194
|
|
|
@@ -833,24 +837,78 @@ const RetailerProductEditionView = ({
|
|
|
833
837
|
: !!family?.parent;
|
|
834
838
|
|
|
835
839
|
/*
|
|
836
|
-
|
|
840
|
+
Abre otro producto de la familia.
|
|
841
|
+
|
|
842
|
+
Cambiar la URL no basta: esta pantalla no lee el producto de la ruta sino de
|
|
843
|
+
sessionStorage —el router hace JSON.parse(sessionStorage.productSelected) y
|
|
844
|
+
se lo pasa como prop—, así que navegar sin precargar dejaría la URL nueva
|
|
845
|
+
mostrando el producto anterior. Por eso primero se trae el destino y se
|
|
846
|
+
escriben las tres llaves que el listado escribe al hacer clic en una fila
|
|
847
|
+
(productSelected, version, productEdit), y solo entonces se navega.
|
|
848
|
+
|
|
849
|
+
Se pide a /ordered-services y no a read-articles-v2, que es lo que usa la
|
|
850
|
+
aplicación de clientes: aquel filtra por la compañía del usuario y el equipo
|
|
851
|
+
interno es de ContentOh trabajando productos de sus clientes, así que ahí no
|
|
852
|
+
devolvería nada. /ordered-services es el mismo endpoint del listado de esta
|
|
853
|
+
aplicación, así que el objeto llega con la forma exacta que normalizeProduct
|
|
854
|
+
espera —con `article` anidado, `statusByRetailer` y `categoryRetailer`—.
|
|
855
|
+
|
|
856
|
+
Un producto de la familia puede no estar en ninguna orden de trabajo: la
|
|
857
|
+
relación padre/hijo vive en `article` y no exige haber pasado por ContentOh.
|
|
858
|
+
En ese caso no hay nada que abrir aquí, y se dice en vez de navegar a una
|
|
859
|
+
pantalla que mostraría el producto equivocado.
|
|
860
|
+
*/
|
|
861
|
+
const openFamilyMember = async (articleId) => {
|
|
862
|
+
setLoadingVariant(articleId);
|
|
863
|
+
setAvisoFamilia(null);
|
|
864
|
+
try {
|
|
865
|
+
const res = await axios.get(
|
|
866
|
+
`${process.env.REACT_APP_ORDERED_SERVICES_ENDPOINT}`,
|
|
867
|
+
{
|
|
868
|
+
params: { filterByIdArticle: articleId, includeFilters: false },
|
|
869
|
+
headers: { Authorization: token },
|
|
870
|
+
}
|
|
871
|
+
);
|
|
837
872
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
873
|
+
// read-order-services responde { total, data: [...] }. La vista trae una
|
|
874
|
+
// fila por orden, así que puede haber varias del mismo artículo; llegan
|
|
875
|
+
// ordenadas por order_id DESC y la primera es la orden más reciente.
|
|
876
|
+
const { data } = readPayload(res) ?? {};
|
|
877
|
+
const encontrado = (data ?? []).find(
|
|
878
|
+
(item) => Number(item?.article?.id_article) === Number(articleId)
|
|
879
|
+
);
|
|
842
880
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
881
|
+
if (!encontrado) {
|
|
882
|
+
setAvisoFamilia(
|
|
883
|
+
"Ese producto no está en ninguna orden de trabajo, así que no se puede abrir desde aquí."
|
|
884
|
+
);
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
846
887
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
888
|
+
sessionStorage.setItem("productSelected", JSON.stringify(encontrado));
|
|
889
|
+
sessionStorage.setItem("version", JSON.stringify(encontrado.version));
|
|
890
|
+
sessionStorage.setItem(
|
|
891
|
+
"productEdit",
|
|
892
|
+
JSON.stringify({
|
|
893
|
+
ArticleId: encontrado.article.id_article,
|
|
894
|
+
categoryId: encontrado.article.id_article,
|
|
895
|
+
product: [encontrado],
|
|
896
|
+
})
|
|
897
|
+
);
|
|
898
|
+
|
|
899
|
+
window.location.assign("/EditProducts");
|
|
900
|
+
} catch (error) {
|
|
901
|
+
console.error("openFamilyMember: ", error);
|
|
902
|
+
setAvisoFamilia("No se pudo abrir ese producto. Intenta de nuevo.");
|
|
903
|
+
} finally {
|
|
904
|
+
setLoadingVariant(null);
|
|
905
|
+
}
|
|
906
|
+
};
|
|
850
907
|
|
|
851
908
|
/*
|
|
852
|
-
Refresca tras ligar, sin recargar: el producto sale de
|
|
853
|
-
un
|
|
909
|
+
Refresca tras ligar, sin recargar la página: el producto sale de
|
|
910
|
+
sessionStorage, así que un F5 devolvería el mismo objeto y el contador
|
|
911
|
+
seguiría igual.
|
|
854
912
|
*/
|
|
855
913
|
const handleOnLinkedVariants = (result) => {
|
|
856
914
|
if (!result) return;
|
|
@@ -869,13 +927,62 @@ const RetailerProductEditionView = ({
|
|
|
869
927
|
};
|
|
870
928
|
|
|
871
929
|
dispatch({ type: "SET_PRODUCT", payload: updatedProduct });
|
|
872
|
-
setFamily(null);
|
|
873
930
|
|
|
931
|
+
/*
|
|
932
|
+
En sessionStorage se PARCHEA lo guardado; no se reemplaza.
|
|
933
|
+
|
|
934
|
+
Lo que hay ahí es el producto tal como lo devuelve el listado de esta
|
|
935
|
+
aplicación: con `article` anidado, `statusByRetailer`, `categoryRetailer`
|
|
936
|
+
y los servicios. `updatedProduct` es la versión aplanada que usa esta
|
|
937
|
+
pantalla, y escribirla encima tiraba todo eso: al siguiente F5 la ficha se
|
|
938
|
+
reconstruía desde un objeto mutilado —sin relaciones de cadena, sin
|
|
939
|
+
estatus por cadena— aunque en pantalla se viera bien hasta entonces.
|
|
940
|
+
|
|
941
|
+
De ligar solo cambian dos cosas, y son las dos que se copian aquí.
|
|
942
|
+
*/
|
|
874
943
|
try {
|
|
875
|
-
|
|
944
|
+
const guardado = JSON.parse(
|
|
945
|
+
sessionStorage.getItem("productSelected") ?? "null"
|
|
946
|
+
);
|
|
947
|
+
|
|
948
|
+
if (guardado) {
|
|
949
|
+
sessionStorage.setItem(
|
|
950
|
+
"productSelected",
|
|
951
|
+
JSON.stringify({
|
|
952
|
+
...guardado,
|
|
953
|
+
variantsCount: updatedProduct.variantsCount,
|
|
954
|
+
parentArticleId: updatedProduct.parentArticleId ?? null,
|
|
955
|
+
})
|
|
956
|
+
);
|
|
957
|
+
}
|
|
876
958
|
} catch (error) {
|
|
959
|
+
// Un sessionStorage inaccesible no debe tumbar la pantalla: el estado en
|
|
960
|
+
// memoria ya quedó bien y es lo que el usuario está viendo.
|
|
877
961
|
console.error("linkVariants/sessionStorage: ", error);
|
|
878
962
|
}
|
|
963
|
+
|
|
964
|
+
/*
|
|
965
|
+
Volver a preguntar, no vaciar.
|
|
966
|
+
|
|
967
|
+
Antes esto hacía `setFamily(null)` para invalidar la caché, y en esta
|
|
968
|
+
pantalla eso tenía el efecto contrario al buscado: el bloque de parentesco
|
|
969
|
+
se decide con `esHijoDeOtro`, que sale de `family`, no del producto. Con
|
|
970
|
+
`family` en null el bloque desaparecía, así que después de ligar la
|
|
971
|
+
pantalla se quedaba SIN ninguna señal de que el producto ya tenía padre
|
|
972
|
+
—justo lo que el usuario acababa de hacer—.
|
|
973
|
+
*/
|
|
974
|
+
loadFamily(true);
|
|
975
|
+
|
|
976
|
+
/*
|
|
977
|
+
Y se recargan los servicios, porque ligar cambia la herencia de cada campo
|
|
978
|
+
en el servidor: al planchar, lo que era propio pasa a heredado y los chips
|
|
979
|
+
tienen que decirlo. Sin esto la ficha sigue mostrando el estado anterior
|
|
980
|
+
hasta que alguien cierra y vuelve a abrir el producto.
|
|
981
|
+
|
|
982
|
+
Sin `enableLoading` para no parpadear el esqueleto encima de una pantalla
|
|
983
|
+
que ya está pintada.
|
|
984
|
+
*/
|
|
985
|
+
loadData(false);
|
|
879
986
|
};
|
|
880
987
|
|
|
881
988
|
/*
|
|
@@ -2011,29 +2118,49 @@ const RetailerProductEditionView = ({
|
|
|
2011
2118
|
)}
|
|
2012
2119
|
|
|
2013
2120
|
{family?.parent && (
|
|
2014
|
-
<
|
|
2015
|
-
|
|
2121
|
+
<button
|
|
2122
|
+
type="button"
|
|
2123
|
+
className="family-row parent"
|
|
2124
|
+
disabled={loadingVariant !== null}
|
|
2125
|
+
onClick={() => openFamilyMember(family.parent.articleId)}
|
|
2126
|
+
>
|
|
2127
|
+
<span className="role">
|
|
2128
|
+
{loadingVariant === family.parent.articleId
|
|
2129
|
+
? "Abriendo…"
|
|
2130
|
+
: "Producto padre"}
|
|
2131
|
+
</span>
|
|
2016
2132
|
<span className="name">{family.parent.name}</span>
|
|
2017
2133
|
<span className="upc">{family.parent.upc}</span>
|
|
2018
|
-
</
|
|
2134
|
+
</button>
|
|
2019
2135
|
)}
|
|
2020
2136
|
|
|
2021
2137
|
{family?.variants?.map((variant) => (
|
|
2022
|
-
<
|
|
2138
|
+
<button
|
|
2023
2139
|
key={variant.articleId}
|
|
2024
|
-
|
|
2140
|
+
type="button"
|
|
2141
|
+
className={`family-row${
|
|
2142
|
+
variant.isCurrent ? " current" : ""
|
|
2143
|
+
}`}
|
|
2144
|
+
disabled={variant.isCurrent || loadingVariant !== null}
|
|
2145
|
+
onClick={() => openFamilyMember(variant.articleId)}
|
|
2025
2146
|
>
|
|
2026
2147
|
<span className="role">
|
|
2027
|
-
{variant.
|
|
2148
|
+
{loadingVariant === variant.articleId
|
|
2149
|
+
? "Abriendo…"
|
|
2150
|
+
: variant.isCurrent
|
|
2151
|
+
? "Estás aquí"
|
|
2152
|
+
: "Hijo"}
|
|
2028
2153
|
</span>
|
|
2029
2154
|
<span className="name">{variant.name}</span>
|
|
2030
2155
|
<span className="upc">{variant.upc}</span>
|
|
2031
|
-
</
|
|
2156
|
+
</button>
|
|
2032
2157
|
))}
|
|
2033
2158
|
|
|
2034
2159
|
{family && !family.error && !family.variants?.length && (
|
|
2035
2160
|
<p className="loading">Este producto no tiene hijos.</p>
|
|
2036
2161
|
)}
|
|
2162
|
+
|
|
2163
|
+
{avisoFamilia && <p className="loading">{avisoFamilia}</p>}
|
|
2037
2164
|
</div>
|
|
2038
2165
|
)}
|
|
2039
2166
|
|
|
@@ -220,13 +220,24 @@ export const Container = styled.div`
|
|
|
220
220
|
align-items: baseline;
|
|
221
221
|
gap: 8px;
|
|
222
222
|
padding: 6px 8px;
|
|
223
|
+
border: none;
|
|
223
224
|
border-radius: 4px;
|
|
225
|
+
background: none;
|
|
226
|
+
cursor: pointer;
|
|
224
227
|
text-align: left;
|
|
225
228
|
font-family: ${FontFamily.Raleway_500};
|
|
226
229
|
font-size: 12px;
|
|
227
230
|
color: ${GlobalColors.deep_gray};
|
|
228
231
|
}
|
|
229
232
|
|
|
233
|
+
.family-row:hover:not(:disabled) {
|
|
234
|
+
background-color: ${GlobalColors.s2};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.family-row:disabled {
|
|
238
|
+
cursor: default;
|
|
239
|
+
opacity: 0.7;
|
|
240
|
+
}
|
|
230
241
|
|
|
231
242
|
.family-row .role {
|
|
232
243
|
min-width: 96px;
|
|
@@ -96,9 +96,16 @@ export const normalizeProduct = (product) => {
|
|
|
96
96
|
? productData.statusByRetailer.map((status) => status.retailer_id)
|
|
97
97
|
: [];
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
// Un producto sin ninguna relación de cadena+categoría activa llega con
|
|
100
|
+
// `categoryRetailer` en null, y filtrar sobre null tumbaba la pantalla entera.
|
|
101
|
+
// Se vuelve alcanzable al saltar entre productos de una familia, que es cuando
|
|
102
|
+
// se abren fichas que nadie eligió desde el listado. Se conserva el null para
|
|
103
|
+
// no cambiar lo que ya leen los consumidores.
|
|
104
|
+
const categoryRetailerInOrder = categoryRetailerNormalized
|
|
105
|
+
? categoryRetailerNormalized.filter((rel) =>
|
|
106
|
+
retailersIdsInOrder.includes(rel.id_retailer)
|
|
107
|
+
)
|
|
108
|
+
: null;
|
|
102
109
|
|
|
103
110
|
return {
|
|
104
111
|
id_article: productData.id_article || article.id_article || 0,
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.generateAttributePrompt = void 0;
|
|
7
|
-
|
|
8
|
-
var generateAttributePrompt = function generateAttributePrompt(_ref) {
|
|
9
|
-
var _ref$upc = _ref.upc,
|
|
10
|
-
upc = _ref$upc === void 0 ? 0 : _ref$upc,
|
|
11
|
-
_ref$inputName = _ref.inputName,
|
|
12
|
-
inputName = _ref$inputName === void 0 ? "" : _ref$inputName,
|
|
13
|
-
_ref$description = _ref.description,
|
|
14
|
-
description = _ref$description === void 0 ? "" : _ref$description,
|
|
15
|
-
_ref$currentValue = _ref.currentValue,
|
|
16
|
-
currentValue = _ref$currentValue === void 0 ? "" : _ref$currentValue,
|
|
17
|
-
_ref$name = _ref.name,
|
|
18
|
-
name = _ref$name === void 0 ? "" : _ref$name,
|
|
19
|
-
_ref$category = _ref.category,
|
|
20
|
-
category = _ref$category === void 0 ? "" : _ref$category,
|
|
21
|
-
_ref$retailer = _ref.retailer,
|
|
22
|
-
retailer = _ref$retailer === void 0 ? "" : _ref$retailer,
|
|
23
|
-
_ref$maxChar = _ref.maxChar,
|
|
24
|
-
maxChar = _ref$maxChar === void 0 ? 100 : _ref$maxChar;
|
|
25
|
-
return "\n Eres un especialista en la generaci\xF3n, optimizaci\xF3n, mejora y captura de atributos de la ficha t\xE9cnica de productos para cat\xE1logos en l\xEDnea.\n Tu tarea es crear atributos claros, concisos y relevantes que resalten las caracter\xEDsticas y beneficios del producto, utilizando un lenguaje preciso y adaptado al p\xFAblico objetivo.\n\n Datos del producto:\n - UPC: ".concat(upc, "\n - Nombre del producto: ").concat(name, "\n - Categor\xEDa: ").concat(category, "\n - Nombre del atributo: ").concat(inputName, "\n - Requerimiento del atributo: ").concat(description, "\n - Valor actual del atributo: ").concat(currentValue, "\n - Cadena comercial dirigida: ").concat(retailer, "\n\n Instrucciones:\n 1. Analiza el nombre del producto y la categor\xEDa para entender su contexto.\n 2. Analiza la descripci\xF3n del atributo actual del producto.\n 3. Identifica la informaci\xF3n clave del atributo que sean relevantes y \xFAtiles para los clientes potenciales.\n 4. Genera una lista de atributos que:\n - Cumplan con la descripcion del atributo proporcionada, no inventes datos o cambies el contexto de lo que pide la descripci\xF3n del atributo.\n - Sean claros y f\xE1ciles de entender.\n - Destaquen las caracter\xEDsticas y beneficios clave del producto.\n - Utilicen un lenguaje preciso y adaptado al p\xFAblico objetivo.\n - Mantengan un tono profesional y coherente con la marca.\n - Aumenten la probabilidad de compra del producto.\n - No excedan los ").concat(maxChar, " caracteres en total.\n - Si existe ejemplo en la descripci\xF3n del atributo, sigue el mismo formato para generar los atributos.\n 5. No incluyas emojis ni signos especiales (*/+\xB4!\xA1?\xBF)\n 6. No repitas el encabezado: ").concat(inputName, "\n 7. No incluyas call to action, ejemplo: \"!Compra ya!\" \"!Da click!\" \"!Apurate!\"\n\n Aseg\xFArate de que los atributos generados cumplan con todas las instrucciones proporcionadas.\n\n No lo olvides, el objetivo principal es mejorar la captura de atributos para la ficha t\xE9cnica del producto para atraer, convencer y dar la informaci\xF3n completa a los clientes potenciales que puedan realizar una compra.\n ");
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
exports.generateAttributePrompt = generateAttributePrompt;
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.generateDescriptionPrompt = void 0;
|
|
7
|
-
|
|
8
|
-
// Cadena y Proveedor
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* La cadena ${cadena} tiene estas reglas ${reglas} para el tipo de descripcion que es: ${descripcion}
|
|
12
|
-
*/
|
|
13
|
-
var generateDescriptionPrompt = function generateDescriptionPrompt(_ref) {
|
|
14
|
-
var _ref$upc = _ref.upc,
|
|
15
|
-
upc = _ref$upc === void 0 ? 0 : _ref$upc,
|
|
16
|
-
_ref$inputName = _ref.inputName,
|
|
17
|
-
inputName = _ref$inputName === void 0 ? "" : _ref$inputName,
|
|
18
|
-
_ref$description = _ref.description,
|
|
19
|
-
description = _ref$description === void 0 ? "" : _ref$description,
|
|
20
|
-
_ref$currentValue = _ref.currentValue,
|
|
21
|
-
currentValue = _ref$currentValue === void 0 ? "" : _ref$currentValue,
|
|
22
|
-
_ref$name = _ref.name,
|
|
23
|
-
name = _ref$name === void 0 ? "" : _ref$name,
|
|
24
|
-
_ref$category = _ref.category,
|
|
25
|
-
category = _ref$category === void 0 ? "" : _ref$category,
|
|
26
|
-
_ref$retailer = _ref.retailer,
|
|
27
|
-
retailer = _ref$retailer === void 0 ? "" : _ref$retailer,
|
|
28
|
-
_ref$maxChar = _ref.maxChar,
|
|
29
|
-
maxChar = _ref$maxChar === void 0 ? 100 : _ref$maxChar;
|
|
30
|
-
return "\n Eres un especialista en la generaci\xF3n, optimizaci\xF3n y mejora de descripciones de productos para cat\xE1logos en l\xEDnea.\n Tu tarea es crear descripciones claras, concisas y atractivas que resalten las caracter\xEDsticas y beneficios del producto, utilizando un lenguaje persuasivo y adaptado al p\xFAblico objetivo.\n\n Datos del producto:\n - UPC: ".concat(upc, "\n - Nombre del producto: ").concat(name, "\n - Categor\xEDa: ").concat(category, "\n - Encabezado de la descripci\xF3n: ").concat(inputName, "\n - Requerimiento de la descripcion: ").concat(description, "\n - Descripcion actual del producto: ").concat(currentValue, "\n - Cadena comercial dirigida: ").concat(retailer, "\n\n Instrucciones:\n 1. Analiza la descripci\xF3n actual del producto en caso de tenerla.\n 2. Identifica \xE1reas de mejora, como claridad, concisi\xF3n, atractivo y relevancia.\n 3. Genera una descripci\xF3n que:\n - Sea clara y f\xE1cil de entender.\n - Destaque las caracter\xEDsticas y beneficios clave del producto.\n - Utilice un lenguaje persuasivo y adaptado al p\xFAblico objetivo.\n - Mantenga un tono profesional y coherente con la marca.\n - No exceda los ").concat(maxChar, " caracteres.\n - Aumente la probabilidad de compra del producto, utilizando persuasi\xF3n en la necesidad de compra del producto.\n 4. No incluyas emojis ni signos especiales (*/+\xB4!\xA1?\xBF)\n 5. No repitas el encabezado: ").concat(inputName, "\n 6. No incluyas call to action, ejemplo: \"!Compra ya!\" \"!Da click!\" \"!Apurate!\"\n\n\n Aseg\xFArate de que la descripci\xF3n generada cumpla con todas las instrucciones proporcionadas.\n\n No lo olvides, el objetivo principal es mejorar la descripci\xF3n del producto para atraer y convencer a los clientes potenciales de realizar una compra. Eres un experto en marketing y redacci\xF3n persuasiva.\n\n Nota: No estas hablando con los clientes, estas descripciones ir\xE1n en la tienda de E-commerce de la cadena comercial. No realices saludos, despedidas, sugerencias\n ");
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
exports.generateDescriptionPrompt = generateDescriptionPrompt;
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
var schema = {
|
|
8
|
-
type: "object",
|
|
9
|
-
properties: {
|
|
10
|
-
results: {
|
|
11
|
-
type: "array",
|
|
12
|
-
items: {
|
|
13
|
-
type: "object",
|
|
14
|
-
properties: {
|
|
15
|
-
label: {
|
|
16
|
-
type: "string"
|
|
17
|
-
},
|
|
18
|
-
value: {
|
|
19
|
-
type: "string"
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
maxItems: 3
|
|
24
|
-
},
|
|
25
|
-
compliance_warnings: {
|
|
26
|
-
type: "array",
|
|
27
|
-
items: {
|
|
28
|
-
type: "string"
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
required: ["results"]
|
|
33
|
-
};
|
|
34
|
-
var _default = schema;
|
|
35
|
-
exports.default = _default;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
var schema = {
|
|
8
|
-
type: "object",
|
|
9
|
-
properties: {
|
|
10
|
-
results: {
|
|
11
|
-
type: "array",
|
|
12
|
-
items: {
|
|
13
|
-
type: "object",
|
|
14
|
-
properties: {
|
|
15
|
-
value: {
|
|
16
|
-
type: "string"
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
minItems: 1,
|
|
21
|
-
maxItems: 3
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
required: ["results"]
|
|
25
|
-
};
|
|
26
|
-
var _default = schema;
|
|
27
|
-
exports.default = _default;
|