contentoh-components-library 21.6.61 → 21.6.62
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/.claude/settings.local.json +7 -0
- package/dist/ai/prompts/attribute.prompt.js +28 -0
- package/dist/ai/prompts/description.prompt.js +33 -0
- package/dist/ai/schemas/attribute.schema.js +35 -0
- package/dist/ai/schemas/description.schema.js +27 -0
- package/dist/components/pages/CreatorsProductEdition/CreatorsProductEditionView.js +11 -5
- package/dist/components/pages/CreatorsProductEdition/hooks/useCreatorsProductEdition.js +58 -31
- package/dist/components/pages/CreatorsProductEdition/mocks/api.fixtures.js +5 -1
- package/dist/components/pages/CreatorsProductEdition/mocks/mockApi.js +3 -40
- package/dist/components/pages/CreatorsProductEdition/sections/ImagesSection.js +18 -3
- package/dist/components/pages/CreatorsProductEdition/sections/StatusChip.js +4 -13
- package/dist/components/pages/CreatorsProductEdition/sections/TabsBar.js +10 -0
- package/dist/components/pages/CreatorsProductEdition/stories/CreatorsProductEdition.stories.js +10 -2
- package/dist/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +2 -15
- package/dist/components/pages/RetailerProductEdition/index.js +40 -57
- package/dist/components/pages/RetailerProductEdition/utils.js +2 -6
- package/dist/index.js +0 -13
- package/package.json +1 -1
- package/src/components/pages/CreatorsProductEdition/CreatorsProductEditionView.jsx +22 -3
- package/src/components/pages/CreatorsProductEdition/hooks/useCreatorsProductEdition.js +36 -1
- package/src/components/pages/CreatorsProductEdition/mocks/api.fixtures.js +15 -3
- package/src/components/pages/CreatorsProductEdition/mocks/mockApi.js +8 -18
- package/src/components/pages/CreatorsProductEdition/sections/ImagesSection.jsx +24 -2
- package/src/components/pages/CreatorsProductEdition/sections/StatusChip.jsx +4 -8
- package/src/components/pages/CreatorsProductEdition/sections/TabsBar.jsx +9 -0
- package/src/components/pages/CreatorsProductEdition/stories/CreatorsProductEdition.stories.js +6 -0
- package/src/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +0 -12
- package/src/components/pages/RetailerProductEdition/index.js +3 -28
- package/src/components/pages/RetailerProductEdition/utils.js +0 -5
- package/src/index.js +0 -1
- package/dist/components/organisms/ServicesNavigation/ServiceToolbar.js +0 -210
- package/dist/components/organisms/ServicesNavigation/ServicesNavigation.stories.js +0 -138
- package/dist/components/organisms/ServicesNavigation/ServicesRail.js +0 -705
- package/dist/components/organisms/ServicesNavigation/catalog.js +0 -505
- package/dist/components/organisms/ServicesNavigation/index.js +0 -337
- package/dist/components/organisms/ServicesNavigation/model.js +0 -167
- package/dist/components/organisms/ServicesNavigation/ui.js +0 -371
- package/dist/components/organisms/ServicesNavigation/views.js +0 -1237
- package/dist/components/organisms/ServicesWorkspace/AssigneePicker.js +0 -459
- package/dist/components/organisms/ServicesWorkspace/ServicesWorkspace.stories.js +0 -119
- package/dist/components/organisms/ServicesWorkspace/demo.js +0 -137
- package/dist/components/organisms/ServicesWorkspace/index.js +0 -813
- package/dist/components/organisms/ServicesWorkspace/servicesModel.js +0 -351
- package/dist/components/organisms/ServicesWorkspace/tooltipStyles.js +0 -37
- package/dist/components/pages/CreatorsProductEdition/mocks/productServices.fixtures.js +0 -387
- package/dist/components/pages/ProductEdition/ProductEdition.stories.js +0 -148
- package/dist/components/pages/ProductEdition/ProductEditionView.js +0 -1355
- package/dist/components/pages/ProductEdition/ServiceHeader.js +0 -142
- package/dist/components/pages/ProductEdition/api.js +0 -256
- package/dist/components/pages/ProductEdition/index.js +0 -37
- package/dist/components/pages/ProductEdition/permissions.js +0 -200
- package/dist/components/pages/ProductEdition/permissions.test.js +0 -320
- package/dist/components/pages/ProductEdition/sections/CatalogServicePanel.js +0 -237
- package/dist/components/pages/ProductEdition/sections/EditionTopBar.js +0 -174
- package/dist/components/pages/ProductEdition/sections/ImagePanel.js +0 -440
- package/dist/components/pages/ProductEdition/sections/ServiceTeam.js +0 -275
- package/dist/components/pages/ProductEdition/sections/ServiceTools.js +0 -186
- package/dist/components/pages/ProductEdition/services.js +0 -233
- package/dist/components/pages/ProductEdition/services.test.js +0 -195
- package/src/components/organisms/ServicesNavigation/ServiceToolbar.jsx +0 -143
- package/src/components/organisms/ServicesNavigation/ServicesNavigation.stories.js +0 -101
- package/src/components/organisms/ServicesNavigation/ServicesRail.jsx +0 -591
- package/src/components/organisms/ServicesNavigation/catalog.js +0 -180
- package/src/components/organisms/ServicesNavigation/index.jsx +0 -232
- package/src/components/organisms/ServicesNavigation/model.js +0 -85
- package/src/components/organisms/ServicesNavigation/ui.jsx +0 -229
- package/src/components/organisms/ServicesNavigation/views.jsx +0 -705
- package/src/components/organisms/ServicesWorkspace/AssigneePicker.js +0 -348
- package/src/components/organisms/ServicesWorkspace/ServicesWorkspace.stories.js +0 -61
- package/src/components/organisms/ServicesWorkspace/demo.js +0 -58
- package/src/components/organisms/ServicesWorkspace/index.js +0 -556
- package/src/components/organisms/ServicesWorkspace/servicesModel.js +0 -203
- package/src/components/organisms/ServicesWorkspace/tooltipStyles.js +0 -27
- package/src/components/pages/CreatorsProductEdition/mocks/productServices.fixtures.js +0 -175
- package/src/components/pages/ProductEdition/ProductEdition.stories.js +0 -106
- package/src/components/pages/ProductEdition/ProductEditionView.jsx +0 -1142
- package/src/components/pages/ProductEdition/ServiceHeader.jsx +0 -104
- package/src/components/pages/ProductEdition/api.js +0 -84
- package/src/components/pages/ProductEdition/index.js +0 -21
- package/src/components/pages/ProductEdition/permissions.js +0 -128
- package/src/components/pages/ProductEdition/permissions.test.js +0 -249
- package/src/components/pages/ProductEdition/sections/CatalogServicePanel.jsx +0 -123
- package/src/components/pages/ProductEdition/sections/EditionTopBar.jsx +0 -134
- package/src/components/pages/ProductEdition/sections/ImagePanel.jsx +0 -342
- package/src/components/pages/ProductEdition/sections/ServiceTeam.jsx +0 -184
- package/src/components/pages/ProductEdition/sections/ServiceTools.jsx +0 -134
- package/src/components/pages/ProductEdition/services.js +0 -187
- package/src/components/pages/ProductEdition/services.test.js +0 -88
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Modelo de servicios de un producto para la edición.
|
|
3
|
-
|
|
4
|
-
Misma lógica que la tabla de productos de Creators (ServicesCell/rowServices):
|
|
5
|
-
un servicio se identifica por `service_name`, se agrupa en etapas por su
|
|
6
|
-
estatus base y se pinta con los mismos colores, para que el usuario reconozca
|
|
7
|
-
lo que vio en la tabla al entrar a la edición.
|
|
8
|
-
|
|
9
|
-
Fuentes, en orden:
|
|
10
|
-
1. `serviceStatuses` (listado ligero, view=summary): un elemento por servicio.
|
|
11
|
-
2. Los tres estatus de siempre (datasheet/description/images_status).
|
|
12
|
-
3. `demo_services`: servicios de ejemplo para revisar el diseño (ver demo.js).
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/** Servicios que tienen editor propio en esta pantalla, y su pestaña. */
|
|
16
|
-
export const EDITOR_TABS = {
|
|
17
|
-
description: "Descripción",
|
|
18
|
-
datasheet: "Ficha técnica",
|
|
19
|
-
images: "Imágenes",
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const LEGACY = [
|
|
23
|
-
{ service_name: "datasheet", display_name: "Ficha técnica", statusKey: "datasheet_status" },
|
|
24
|
-
{ service_name: "description", display_name: "Descripción", statusKey: "description_status" },
|
|
25
|
-
{ service_name: "images", display_name: "Imágenes", statusKey: "images_status" },
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
const NOT_REQUESTED = [undefined, null, "", "NS", "NULL", "-"];
|
|
29
|
-
|
|
30
|
-
export const STATUS_NAMES = {
|
|
31
|
-
PA: "Por asignar",
|
|
32
|
-
AS: "Asignado",
|
|
33
|
-
R: "Recibido",
|
|
34
|
-
CA: "Capturando",
|
|
35
|
-
IE: "Información enviada",
|
|
36
|
-
RC: "Rechazado coordinador",
|
|
37
|
-
AC: "Aprobado coordinador",
|
|
38
|
-
RA: "Rechazado auditor",
|
|
39
|
-
AA: "Aprobado auditor",
|
|
40
|
-
RP: "Rechazado proveedor",
|
|
41
|
-
AP: "Aprobado proveedor",
|
|
42
|
-
ACA: "Aprobado cadena",
|
|
43
|
-
RCA: "Rechazado cadena",
|
|
44
|
-
SAC: "Solicitud auditoría Content-oh!",
|
|
45
|
-
AAC: "Aprobado auditoría Content-oh!",
|
|
46
|
-
RAC: "Rechazado auditoría Content-oh!",
|
|
47
|
-
FAP: "Finalización auditoría por proveedor",
|
|
48
|
-
Ex: "Exportado",
|
|
49
|
-
REG: "Registrado",
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const baseStatus = (status) => String(status ?? "").split("/")[0];
|
|
53
|
-
|
|
54
|
-
export const getStatusName = (status) =>
|
|
55
|
-
STATUS_NAMES[status] ?? STATUS_NAMES[baseStatus(status)] ?? status ?? "Sin estatus";
|
|
56
|
-
|
|
57
|
-
/** Mismos colores que la tabla de Creators (helper.getStatusColor). */
|
|
58
|
-
export const getStatusColor = (status) => {
|
|
59
|
-
switch (baseStatus(status)) {
|
|
60
|
-
case "R":
|
|
61
|
-
case "PA":
|
|
62
|
-
case "SAC":
|
|
63
|
-
return "#E67432";
|
|
64
|
-
case "ACA":
|
|
65
|
-
case "AC":
|
|
66
|
-
case "AP":
|
|
67
|
-
case "AA":
|
|
68
|
-
case "AAC":
|
|
69
|
-
return "#18A0FB";
|
|
70
|
-
case "RC":
|
|
71
|
-
case "RA":
|
|
72
|
-
case "RCA":
|
|
73
|
-
case "RP":
|
|
74
|
-
case "RAC":
|
|
75
|
-
return "#D74DED";
|
|
76
|
-
case "CA":
|
|
77
|
-
case "AS":
|
|
78
|
-
case "IE":
|
|
79
|
-
return "#ED9A4D";
|
|
80
|
-
case "Ex":
|
|
81
|
-
case "FAP":
|
|
82
|
-
return "#71DE56";
|
|
83
|
-
default:
|
|
84
|
-
return "#D4D1D7";
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
export const SERVICE_STAGES = [
|
|
89
|
-
{ stage_name: "pending", display_name: "Por asignar", singular: "por asignar", plural: "por asignar", statuses: ["R", "PA"] },
|
|
90
|
-
{ stage_name: "in_progress", display_name: "En proceso", singular: "en proceso", plural: "en proceso", statuses: ["AS", "CA", "IE"] },
|
|
91
|
-
{ stage_name: "rejected", display_name: "Rechazados", singular: "rechazado", plural: "rechazados", statuses: ["RC", "RA", "RP", "RCA", "RAC"] },
|
|
92
|
-
{ stage_name: "review", display_name: "En revisión y aprobación", singular: "en revisión", plural: "en revisión", statuses: ["AC", "AA", "AP", "ACA", "SAC", "AAC"] },
|
|
93
|
-
{ stage_name: "done", display_name: "Terminados", singular: "terminado", plural: "terminados", statuses: ["Ex", "FAP"] },
|
|
94
|
-
{ stage_name: "registered", display_name: "Registrados (solo marca)", singular: "registrado", plural: "registrados", statuses: ["REG"] },
|
|
95
|
-
].map((stage) => ({
|
|
96
|
-
...stage,
|
|
97
|
-
color: stage.stage_name === "registered" ? "#CBCBCB" : getStatusColor(stage.statuses[0]),
|
|
98
|
-
}));
|
|
99
|
-
|
|
100
|
-
const STAGE_BY_NAME = Object.fromEntries(SERVICE_STAGES.map((stage) => [stage.stage_name, stage]));
|
|
101
|
-
const ATTENTION_ORDER = ["rejected", "pending", "in_progress", "review", "done", "registered"];
|
|
102
|
-
|
|
103
|
-
export const getServiceStage = (service) => {
|
|
104
|
-
if (!service.has_workflow) return STAGE_BY_NAME.registered;
|
|
105
|
-
const base = baseStatus(service.status);
|
|
106
|
-
return SERVICE_STAGES.find((stage) => stage.statuses.includes(base)) ?? STAGE_BY_NAME.in_progress;
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
export const groupServicesByStage = (services) =>
|
|
110
|
-
SERVICE_STAGES.map((stage) => ({
|
|
111
|
-
stage,
|
|
112
|
-
services: services.filter((service) => getServiceStage(service).stage_name === stage.stage_name),
|
|
113
|
-
})).filter((group) => group.services.length > 0);
|
|
114
|
-
|
|
115
|
-
export const getAttention = (groups) => {
|
|
116
|
-
const workflow = groups.filter((group) => group.stage.stage_name !== "registered");
|
|
117
|
-
if (workflow.length > 0 && workflow.every((group) => group.stage.stage_name === "done")) {
|
|
118
|
-
return { stage: STAGE_BY_NAME.done, label: "Terminado" };
|
|
119
|
-
}
|
|
120
|
-
const first = ATTENTION_ORDER.map((name) => groups.find((group) => group.stage.stage_name === name)).find(Boolean);
|
|
121
|
-
if (!first) return null;
|
|
122
|
-
const count = first.services.length;
|
|
123
|
-
return { stage: first.stage, label: `${count} ${count === 1 ? first.stage.singular : first.stage.plural}` };
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
/** Cuál abrir primero: lo que más pide atención. */
|
|
127
|
-
export const pickInitialService = (services) => {
|
|
128
|
-
const groups = groupServicesByStage(services);
|
|
129
|
-
const first = ATTENTION_ORDER.map((name) => groups.find((group) => group.stage.stage_name === name)).find(Boolean);
|
|
130
|
-
return first?.services[0]?.service_name ?? null;
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
const assigneesOf = (product, serviceName) => ({
|
|
134
|
-
especialist: product?.[`id_${serviceName}_especialist`] || null,
|
|
135
|
-
facilitator: product?.[`id_${serviceName}_facilitator`] || null,
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Servicios del producto (normalizado por la edición o con la forma del
|
|
140
|
-
* listado): [{ service_name, display_name, status, has_workflow,
|
|
141
|
-
* editor_tab, assignees: { especialist, facilitator }, is_demo }]
|
|
142
|
-
*/
|
|
143
|
-
export const getProductServices = (product) => {
|
|
144
|
-
if (!product) return [];
|
|
145
|
-
let base;
|
|
146
|
-
if (Array.isArray(product.serviceStatuses) && product.serviceStatuses.length > 0) {
|
|
147
|
-
base = product.serviceStatuses
|
|
148
|
-
.filter((service) => !NOT_REQUESTED.includes(service.status))
|
|
149
|
-
.map((service) => {
|
|
150
|
-
const legacy = LEGACY.find((def) => def.service_name === service.service_name);
|
|
151
|
-
const displayName =
|
|
152
|
-
service.display_name && service.display_name !== service.service_name
|
|
153
|
-
? service.display_name
|
|
154
|
-
: legacy?.display_name ?? service.service_name;
|
|
155
|
-
return {
|
|
156
|
-
service_name: service.service_name,
|
|
157
|
-
display_name: displayName,
|
|
158
|
-
status: service.status,
|
|
159
|
-
has_workflow: service.has_workflow !== false,
|
|
160
|
-
};
|
|
161
|
-
});
|
|
162
|
-
} else {
|
|
163
|
-
base = LEGACY.filter((def) => !NOT_REQUESTED.includes(product[def.statusKey])).map((def) => ({
|
|
164
|
-
service_name: def.service_name,
|
|
165
|
-
display_name: def.display_name,
|
|
166
|
-
status: product[def.statusKey],
|
|
167
|
-
has_workflow: true,
|
|
168
|
-
}));
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const demo = (product.demo_services ?? []).map((service) => ({
|
|
172
|
-
service_name: service.service_name,
|
|
173
|
-
display_name: service.display_name,
|
|
174
|
-
status: service.status,
|
|
175
|
-
has_workflow: service.has_workflow !== false,
|
|
176
|
-
deliverable_type: service.deliverable_type,
|
|
177
|
-
is_demo: true,
|
|
178
|
-
}));
|
|
179
|
-
|
|
180
|
-
return [...base, ...demo].map((service) => ({
|
|
181
|
-
...service,
|
|
182
|
-
editor_tab: EDITOR_TABS[service.service_name] ?? null,
|
|
183
|
-
assignees: service.is_demo ? {} : assigneesOf(product, service.service_name),
|
|
184
|
-
}));
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Estatus del servicio en cada cadena. Sale de `statusByRetailer` (detalle del
|
|
189
|
-
* producto); los servicios de ejemplo lo inventan a partir del suyo.
|
|
190
|
-
*/
|
|
191
|
-
export const getRetailerStatuses = (product, service, retailers = []) => {
|
|
192
|
-
const nameOf = (id) => retailers.find((retailer) => retailer.id_retailer === id)?.retailer ?? `Cadena ${id}`;
|
|
193
|
-
if (service.is_demo) {
|
|
194
|
-
return retailers.map((retailer, index) => ({
|
|
195
|
-
id_retailer: retailer.id_retailer,
|
|
196
|
-
retailer: retailer.retailer,
|
|
197
|
-
status: index === 0 ? service.status : baseStatus(service.status),
|
|
198
|
-
}));
|
|
199
|
-
}
|
|
200
|
-
return (product?.statusByRetailer ?? [])
|
|
201
|
-
.filter((item) => item.service === service.service_name)
|
|
202
|
-
.map((item) => ({ id_retailer: item.retailer_id, retailer: nameOf(item.retailer_id), status: item.status }));
|
|
203
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tooltip blanco con la paleta de la plataforma (en lugar del gris oscuro de
|
|
3
|
-
* MUI). Se pasa a <Tooltip {...whiteTooltipProps}>.
|
|
4
|
-
*/
|
|
5
|
-
export const whiteTooltipProps = {
|
|
6
|
-
componentsProps: {
|
|
7
|
-
tooltip: {
|
|
8
|
-
sx: {
|
|
9
|
-
backgroundColor: "#FFFFFF",
|
|
10
|
-
color: "#262626",
|
|
11
|
-
border: "1px solid #F0EEF2",
|
|
12
|
-
borderRadius: "10px",
|
|
13
|
-
boxShadow: 4,
|
|
14
|
-
p: 1.5,
|
|
15
|
-
maxWidth: 340,
|
|
16
|
-
fontFamily: "Lato, sans-serif",
|
|
17
|
-
fontSize: 12,
|
|
18
|
-
},
|
|
19
|
-
},
|
|
20
|
-
arrow: {
|
|
21
|
-
sx: {
|
|
22
|
-
color: "#FFFFFF",
|
|
23
|
-
"&::before": { border: "1px solid #F0EEF2" },
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
};
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
GET /product-services para las historias de la edición unificada
|
|
3
|
-
(ProductEdition): el mismo producto de api.fixtures.js (144814, orden 10421)
|
|
4
|
-
con sus tres servicios de siempre en Oxxo (36) y Del Sol (38), más tres del
|
|
5
|
-
catálogo: A+ (flujo completo, por cadena), Compra de producto en tienda
|
|
6
|
-
(casilla) y Levantamiento y recolección (avance), los dos últimos por
|
|
7
|
-
producto (cadena 0). Nombres, colores e íconos como en cat_service y
|
|
8
|
-
cat_status (docs/sql/catalog 002, 003 y 006 del backend).
|
|
9
|
-
|
|
10
|
-
`applyProductServicesChange` simula PUT /product-services/{action} sobre una
|
|
11
|
-
copia, para que la historia muestre el cambio al volver a pedir la lista.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const ARTICLE_ID = 144814;
|
|
15
|
-
const ORDER_ID = 10421;
|
|
16
|
-
|
|
17
|
-
const STATUS = {
|
|
18
|
-
PA: { status_name: "PA", display_name: "Por asignar", color: "#E57432", flow_name: "workflow", is_final: false, progress_percent: null },
|
|
19
|
-
AA: { status_name: "AA", display_name: "Aprobado auditor", color: "#18A0FB", flow_name: "workflow", is_final: false, progress_percent: null },
|
|
20
|
-
"RA/AS": { status_name: "RA/AS", display_name: "Rechazado auditor / Asignado", color: "#D74DED", flow_name: "workflow", is_final: false, progress_percent: null },
|
|
21
|
-
PE: { status_name: "PE", display_name: "Pendiente", color: "#E57432", flow_name: "checkbox", is_final: false, progress_percent: 0 },
|
|
22
|
-
HE: { status_name: "HE", display_name: "Hecho", color: "#71DE56", flow_name: "checkbox", is_final: true, progress_percent: 100 },
|
|
23
|
-
SE: { status_name: "SE", display_name: "Sin empezar", color: "#E57432", flow_name: "progress", is_final: false, progress_percent: 0 },
|
|
24
|
-
EP: { status_name: "EP", display_name: "En proceso", color: "#ED9A4D", flow_name: "progress", is_final: false, progress_percent: 50 },
|
|
25
|
-
TE: { status_name: "TE", display_name: "Terminado", color: "#71DE56", flow_name: "progress", is_final: true, progress_percent: 100 },
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const OPTIONS = { checkbox: ["PE", "HE"], progress: ["SE", "EP", "TE"] };
|
|
29
|
-
|
|
30
|
-
const WEIGHT = { PA: 1, "RA/AS": 7, AA: 10, PE: 2, SE: 2, EP: 3, HE: 99, TE: 99 };
|
|
31
|
-
|
|
32
|
-
export const PEOPLE = {
|
|
33
|
-
423: { id_user: 423, name: "Coordinador Textos", last_name: null, id_role: 4 },
|
|
34
|
-
424: { id_user: 424, name: "Coordinador Imágenes", last_name: null, id_role: 5 },
|
|
35
|
-
425: { id_user: 425, name: "Auditor QA", last_name: null, id_role: 6 },
|
|
36
|
-
426: { id_user: 426, name: "Especialista Textos", last_name: null, id_role: 7 },
|
|
37
|
-
427: { id_user: 427, name: "Especialista Edición", last_name: null, id_role: 8 },
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const RETAILER_NAMES = { 0: "Sin cadena", 36: "Oxxo", 38: "Del Sol" };
|
|
41
|
-
|
|
42
|
-
const retailer = (id, statusName) => ({
|
|
43
|
-
id_retailer: id,
|
|
44
|
-
retailer_name: RETAILER_NAMES[id],
|
|
45
|
-
quantity: 1,
|
|
46
|
-
status: STATUS[statusName] ?? null,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
const generalOf = (retailers) =>
|
|
50
|
-
retailers
|
|
51
|
-
.filter((item) => item.status)
|
|
52
|
-
.reduce((low, item) => (!low || WEIGHT[item.status.status_name] < WEIGHT[low.status_name] ? item.status : low), null);
|
|
53
|
-
|
|
54
|
-
const service = ({ legacy = false, flow, retailers, roles, assignees, actions, ...rest }) => ({
|
|
55
|
-
icon_name: null,
|
|
56
|
-
deliverable_type: null,
|
|
57
|
-
has_workflow: flow !== "flag",
|
|
58
|
-
requires_qa: roles.includes("auditor"),
|
|
59
|
-
per_retailer: !retailers.some((item) => item.id_retailer === 0),
|
|
60
|
-
is_legacy: legacy,
|
|
61
|
-
status_flow: { flow_name: flow, flow_type: flow === "workflow" || flow === "flag" ? flow : "simple" },
|
|
62
|
-
status: generalOf(retailers),
|
|
63
|
-
status_options: OPTIONS[flow]?.map((name) => STATUS[name]) ?? [],
|
|
64
|
-
retailers,
|
|
65
|
-
roles,
|
|
66
|
-
assignees: { especialist: null, facilitator: null, auditor: null, ...assignees },
|
|
67
|
-
actions,
|
|
68
|
-
...rest,
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
const category = (category_name, display_name) => ({ category_name, display_name });
|
|
72
|
-
|
|
73
|
-
/** Respuesta de GET /product-services (el cuerpo, sin la envoltura de la lambda). */
|
|
74
|
-
export const buildProductServices = ({ delSolStatus } = {}) => ({
|
|
75
|
-
article_id: ARTICLE_ID,
|
|
76
|
-
order_id: ORDER_ID,
|
|
77
|
-
auditor: PEOPLE[425],
|
|
78
|
-
services: [
|
|
79
|
-
service({
|
|
80
|
-
service_name: "datasheet",
|
|
81
|
-
display_name: "Ficha técnica",
|
|
82
|
-
icon_name: "datasheet",
|
|
83
|
-
category: category("texts", "Textos"),
|
|
84
|
-
legacy: true,
|
|
85
|
-
flow: "workflow",
|
|
86
|
-
retailers: [retailer(36, "RA/AS"), retailer(38, delSolStatus ?? "RA/AS")],
|
|
87
|
-
roles: ["especialist", "facilitator", "auditor"],
|
|
88
|
-
assignees: { especialist: PEOPLE[426], facilitator: PEOPLE[423], auditor: PEOPLE[425] },
|
|
89
|
-
actions: { set_status: false, assign: false },
|
|
90
|
-
}),
|
|
91
|
-
service({
|
|
92
|
-
service_name: "description",
|
|
93
|
-
display_name: "Descripción",
|
|
94
|
-
icon_name: "description",
|
|
95
|
-
category: category("texts", "Textos"),
|
|
96
|
-
legacy: true,
|
|
97
|
-
flow: "workflow",
|
|
98
|
-
retailers: [retailer(36, "RA/AS"), retailer(38, delSolStatus ?? "RA/AS")],
|
|
99
|
-
roles: ["especialist", "facilitator", "auditor"],
|
|
100
|
-
assignees: { especialist: PEOPLE[426], facilitator: PEOPLE[423], auditor: PEOPLE[425] },
|
|
101
|
-
actions: { set_status: false, assign: false },
|
|
102
|
-
}),
|
|
103
|
-
service({
|
|
104
|
-
service_name: "images",
|
|
105
|
-
display_name: "Imágenes",
|
|
106
|
-
icon_name: "images",
|
|
107
|
-
category: category("images", "Imágenes"),
|
|
108
|
-
legacy: true,
|
|
109
|
-
flow: "workflow",
|
|
110
|
-
retailers: [retailer(36, "AA"), retailer(38, delSolStatus ?? "AA")],
|
|
111
|
-
roles: ["especialist", "facilitator", "auditor"],
|
|
112
|
-
assignees: { especialist: PEOPLE[427], facilitator: PEOPLE[424], auditor: PEOPLE[425] },
|
|
113
|
-
actions: { set_status: false, assign: false },
|
|
114
|
-
}),
|
|
115
|
-
service({
|
|
116
|
-
service_name: "aplusPlatinum",
|
|
117
|
-
display_name: "A+ / Platinum SKU",
|
|
118
|
-
icon_name: "aplus",
|
|
119
|
-
category: category("media", "Multimedia y diseño"),
|
|
120
|
-
flow: "workflow",
|
|
121
|
-
retailers: [retailer(36, "PA"), retailer(38, "PA")],
|
|
122
|
-
roles: ["especialist", "facilitator", "auditor"],
|
|
123
|
-
assignees: { auditor: PEOPLE[425] },
|
|
124
|
-
actions: { set_status: false, assign: true },
|
|
125
|
-
}),
|
|
126
|
-
service({
|
|
127
|
-
service_name: "productPurchase",
|
|
128
|
-
display_name: "Compra de producto en tienda",
|
|
129
|
-
icon_name: "purchase",
|
|
130
|
-
category: category("logistics", "Logística"),
|
|
131
|
-
flow: "checkbox",
|
|
132
|
-
retailers: [retailer(0, "PE")],
|
|
133
|
-
roles: ["especialist"],
|
|
134
|
-
assignees: { especialist: PEOPLE[427] },
|
|
135
|
-
actions: { set_status: true, assign: true },
|
|
136
|
-
}),
|
|
137
|
-
service({
|
|
138
|
-
service_name: "productPickup",
|
|
139
|
-
display_name: "Levantamiento y recolección",
|
|
140
|
-
icon_name: "pickup",
|
|
141
|
-
category: category("logistics", "Logística"),
|
|
142
|
-
flow: "progress",
|
|
143
|
-
retailers: [retailer(0, "SE")],
|
|
144
|
-
roles: ["especialist"],
|
|
145
|
-
assignees: {},
|
|
146
|
-
actions: { set_status: true, assign: true },
|
|
147
|
-
}),
|
|
148
|
-
],
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
/** Personas que se pueden asignar (GET /service-catalog?view=assignables). */
|
|
152
|
-
export const assignablesFor = (role) =>
|
|
153
|
-
Object.values(PEOPLE)
|
|
154
|
-
.filter((person) => (role === "facilitator" ? [4, 5] : [7, 8]).includes(person.id_role))
|
|
155
|
-
.map((person) => ({ id_user: person.id_user, name: person.name, email: null, id_role: person.id_role }));
|
|
156
|
-
|
|
157
|
-
/** Aplica PUT /product-services/{action} sobre `body` (se modifica en su lugar). */
|
|
158
|
-
export const applyProductServicesChange = (body, action, data) => {
|
|
159
|
-
const target = body.services.find((item) => item.service_name === data?.serviceName);
|
|
160
|
-
if (!target) return { statusCode: 404, message: "El producto no tiene ese servicio en esta orden." };
|
|
161
|
-
if (action === "set-status") {
|
|
162
|
-
const status = STATUS[data.statusName];
|
|
163
|
-
if (!status) return { statusCode: 400, message: "Estatus no válido." };
|
|
164
|
-
target.retailers.forEach((item) => {
|
|
165
|
-
if (!data.retailerIds || data.retailerIds.includes(item.id_retailer)) item.status = status;
|
|
166
|
-
});
|
|
167
|
-
target.status = generalOf(target.retailers);
|
|
168
|
-
return { statusCode: 200 };
|
|
169
|
-
}
|
|
170
|
-
if (action === "assign") {
|
|
171
|
-
target.assignees[data.role] = data.userId ? PEOPLE[data.userId] ?? { id_user: data.userId } : null;
|
|
172
|
-
return { statusCode: 200 };
|
|
173
|
-
}
|
|
174
|
-
return { statusCode: 400, message: `Acción no válida: ${action}.` };
|
|
175
|
-
};
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { ProductEdition } from "./index";
|
|
2
|
-
import { withMockApi } from "../CreatorsProductEdition/mocks/mockApi";
|
|
3
|
-
import { allCatalogServices } from "../../organisms/ServicesNavigation/catalog";
|
|
4
|
-
|
|
5
|
-
/*
|
|
6
|
-
Edición de producto unificada con datos locales: no le pega a ninguna API
|
|
7
|
-
(la simula `CreatorsProductEdition/mocks`). Guardar, aprobar o rechazar se
|
|
8
|
-
acepta sin hacer nada y queda en la consola como `[mock API]`.
|
|
9
|
-
|
|
10
|
-
El producto y los usuarios son los mismos de las historias de
|
|
11
|
-
CreatorsProductEdition, para comparar las dos pantallas con lo mismo.
|
|
12
|
-
*/
|
|
13
|
-
import { ImageEditor } from "../RetailerProductEdition/stories/ImageEditor.stories";
|
|
14
|
-
import { TextEditor } from "../RetailerProductEdition/stories/TextEditor.stories";
|
|
15
|
-
import { Auditor } from "../RetailerProductEdition/stories/Auditor.stories";
|
|
16
|
-
|
|
17
|
-
export default {
|
|
18
|
-
title: "Components/pages/ProductEdition",
|
|
19
|
-
component: ProductEdition,
|
|
20
|
-
decorators: [withMockApi()],
|
|
21
|
-
parameters: { layout: "fullscreen" },
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
// Como en la app: la pantalla vive en una caja de altura fija.
|
|
25
|
-
const Template = (args) => (
|
|
26
|
-
<div style={{ height: "100vh", display: "flex", overflow: "hidden" }}>
|
|
27
|
-
<ProductEdition {...args} />
|
|
28
|
-
</div>
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const base = {
|
|
32
|
-
app: "creators",
|
|
33
|
-
token: ImageEditor.args.token,
|
|
34
|
-
productSelected: ImageEditor.args.productSelected,
|
|
35
|
-
enableDigitalAssets: true,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const TODAS_LAS_PESTAÑAS = {
|
|
39
|
-
Descripción: true,
|
|
40
|
-
"Ficha técnica": true,
|
|
41
|
-
Imágenes: true,
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
/** Servicios del catálogo que todavía no tienen editor (vista de muestra). */
|
|
45
|
-
const SERVICIOS_DE_EJEMPLO = [
|
|
46
|
-
{ service_name: "translation", status: "CA" },
|
|
47
|
-
{ service_name: "seo", status: "AS" },
|
|
48
|
-
{ service_name: "photo", status: "Ex" },
|
|
49
|
-
{ service_name: "videos", status: "IE" },
|
|
50
|
-
{ service_name: "brandstore", status: "AC" },
|
|
51
|
-
{ service_name: "quality", status: "PA" },
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
/** Especialista de imágenes (rol 8): «Míos» le muestra solo Imágenes. */
|
|
55
|
-
export const EspecialistaImagenes = Template.bind({});
|
|
56
|
-
EspecialistaImagenes.storyName = "Especialista de imágenes";
|
|
57
|
-
EspecialistaImagenes.args = {
|
|
58
|
-
...base,
|
|
59
|
-
tabsSections: ImageEditor.args.tabsSections,
|
|
60
|
-
user: ImageEditor.args.user,
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
/** Especialista de textos (rol 7): Ficha técnica y Descripción. */
|
|
64
|
-
export const EspecialistaTextos = Template.bind({});
|
|
65
|
-
EspecialistaTextos.storyName = "Especialista de textos";
|
|
66
|
-
EspecialistaTextos.args = {
|
|
67
|
-
...base,
|
|
68
|
-
tabsSections: TextEditor.args.tabsSections,
|
|
69
|
-
user: TextEditor.args.user,
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
/** Auditor QA (rol 6): asignado a todo el producto, ve los tres servicios. */
|
|
73
|
-
export const AuditorQA = Template.bind({});
|
|
74
|
-
AuditorQA.storyName = "Auditor QA";
|
|
75
|
-
AuditorQA.args = {
|
|
76
|
-
...base,
|
|
77
|
-
tabsSections: TODAS_LAS_PESTAÑAS,
|
|
78
|
-
user: Auditor.args.user,
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
/** Auditor con servicios de ejemplo: así se ve con más de los tres de siempre. */
|
|
82
|
-
export const ConServiciosDeEjemplo = Template.bind({});
|
|
83
|
-
ConServiciosDeEjemplo.storyName = "Con servicios de ejemplo";
|
|
84
|
-
ConServiciosDeEjemplo.args = {
|
|
85
|
-
...AuditorQA.args,
|
|
86
|
-
demoServices: SERVICIOS_DE_EJEMPLO,
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Auditor con todos los servicios activos de la plataforma (los de
|
|
91
|
-
* `cat_service`): los tres con editor salen del producto y el resto son de
|
|
92
|
-
* ejemplo, con estatus variados. Sirve para ver la lista lateral llena: los
|
|
93
|
-
* cinco bloques (con Mantenimiento), el buscador y el Resumen.
|
|
94
|
-
*/
|
|
95
|
-
export const TodosLosServicios = Template.bind({});
|
|
96
|
-
TodosLosServicios.storyName = "Todos los servicios";
|
|
97
|
-
TodosLosServicios.args = {
|
|
98
|
-
...AuditorQA.args,
|
|
99
|
-
demoServices: allCatalogServices({ exclude: ["datasheet", "description", "images"] }),
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
/** En celular la lista se abre como panel con el botón «Servicios». */
|
|
103
|
-
export const EspecialistaImagenesCelular = Template.bind({});
|
|
104
|
-
EspecialistaImagenesCelular.storyName = "Especialista de imágenes · celular";
|
|
105
|
-
EspecialistaImagenesCelular.args = EspecialistaImagenes.args;
|
|
106
|
-
EspecialistaImagenesCelular.parameters = { viewport: { defaultViewport: "mobile2" } };
|