contentoh-components-library 21.6.61 → 21.6.63
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/atoms/MetricCard/index.js +3 -1
- package/dist/components/organisms/DashboardMetric/DashboardMetric.stories.js +12 -2
- package/dist/components/organisms/DashboardMetric/index.js +24 -1
- package/dist/components/organisms/DashboardMetric/styles.js +1 -1
- 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/Dashboard/dashboardUtils.js +3 -3
- package/dist/components/pages/Dashboard/index.js +102 -88
- package/dist/components/pages/Dashboard/styles.js +1 -1
- 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/atoms/MetricCard/index.js +2 -2
- package/src/components/organisms/DashboardMetric/DashboardMetric.stories.js +11 -0
- package/src/components/organisms/DashboardMetric/index.js +13 -1
- package/src/components/organisms/DashboardMetric/styles.js +13 -0
- 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/Dashboard/dashboardUtils.js +3 -3
- package/src/components/pages/Dashboard/index.js +62 -106
- package/src/components/pages/Dashboard/styles.js +17 -12
- 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
|
@@ -2,7 +2,6 @@ import { useEffect, useState } from "react";
|
|
|
2
2
|
import axios from "axios";
|
|
3
3
|
|
|
4
4
|
import { buildFixtures } from "./api.fixtures";
|
|
5
|
-
import { applyProductServicesChange, assignablesFor, buildProductServices } from "./productServices.fixtures";
|
|
6
5
|
|
|
7
6
|
/*
|
|
8
7
|
API falsa para las historias: reemplaza el adaptador de axios mientras la
|
|
@@ -37,17 +36,19 @@ const ok = { statusCode: 200, body: JSON.stringify({ message: "OK" }) };
|
|
|
37
36
|
|
|
38
37
|
export const createMockAdapter = ({
|
|
39
38
|
images = true,
|
|
39
|
+
imagesService = true,
|
|
40
40
|
failLoad = false,
|
|
41
41
|
delSolStatus,
|
|
42
42
|
familia,
|
|
43
43
|
grupo,
|
|
44
44
|
} = {}) => {
|
|
45
|
-
const fx = buildFixtures({
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
const fx = buildFixtures({
|
|
46
|
+
images,
|
|
47
|
+
imagesService,
|
|
48
|
+
delSolStatus,
|
|
49
|
+
familia,
|
|
50
|
+
grupo,
|
|
51
|
+
});
|
|
51
52
|
|
|
52
53
|
return (config) => {
|
|
53
54
|
const method = (config.method || "get").toUpperCase();
|
|
@@ -69,17 +70,6 @@ export const createMockAdapter = ({
|
|
|
69
70
|
if (path === "variants/group") return reply(config, fx.group);
|
|
70
71
|
if (method === "GET" && path === "services") return reply(config, fx.services);
|
|
71
72
|
if (method === "GET" && path === "versions") return reply(config, fx.versions);
|
|
72
|
-
if (method === "GET" && path === "product-services") return lambdaReply(config, 200, productServices);
|
|
73
|
-
if (method === "PUT" && path.startsWith("product-services/")) {
|
|
74
|
-
const action = path.split("/")[1];
|
|
75
|
-
const data = typeof config.data === "string" ? JSON.parse(config.data) : config.data;
|
|
76
|
-
const { statusCode, message } = applyProductServicesChange(productServices, action, data);
|
|
77
|
-
console.info(`[mock API] PUT ${path}`, data);
|
|
78
|
-
return lambdaReply(config, statusCode, statusCode === 200 ? { action, result: data } : { message });
|
|
79
|
-
}
|
|
80
|
-
if (method === "GET" && path === "service-catalog" && query.view === "assignables") {
|
|
81
|
-
return lambdaReply(config, 200, { users: assignablesFor(query.assignment_role) });
|
|
82
|
-
}
|
|
83
73
|
if (path === "percentages") return reply(config, fx.percentages);
|
|
84
74
|
// Sin versión auditable ni observación: con la API real de dev estas dos
|
|
85
75
|
// fallan por CORS, así que la pantalla ya sabe vivir sin ellas.
|
|
@@ -38,9 +38,22 @@ const LIST_COLUMNS = [
|
|
|
38
38
|
// de lado dentro de su caja en vez de aplastar las columnas.
|
|
39
39
|
const LIST_MIN_WIDTH = 760;
|
|
40
40
|
|
|
41
|
-
const TrayTabs = ({
|
|
41
|
+
const TrayTabs = ({
|
|
42
|
+
activeTray,
|
|
43
|
+
setActiveTray,
|
|
44
|
+
imagesCount,
|
|
45
|
+
assetsCount,
|
|
46
|
+
hasImagesService = true,
|
|
47
|
+
}) => {
|
|
42
48
|
const trays = [
|
|
43
|
-
{
|
|
49
|
+
{
|
|
50
|
+
id: TRAYS.IMAGES,
|
|
51
|
+
label: "Imágenes",
|
|
52
|
+
count: imagesCount,
|
|
53
|
+
// Sin el servicio contratado no hay nada que mostrar en esa bandeja,
|
|
54
|
+
// pero se deja a la vista para que se entienda por qué.
|
|
55
|
+
disabled: !hasImagesService,
|
|
56
|
+
},
|
|
44
57
|
{ id: TRAYS.ASSETS, label: "Activos digitales", count: assetsCount },
|
|
45
58
|
];
|
|
46
59
|
return (
|
|
@@ -58,6 +71,7 @@ const TrayTabs = ({ activeTray, setActiveTray, imagesCount, assetsCount }) => {
|
|
|
58
71
|
<Tab
|
|
59
72
|
key={tray.id}
|
|
60
73
|
value={tray.id}
|
|
74
|
+
disabled={tray.disabled}
|
|
61
75
|
disableRipple
|
|
62
76
|
label={
|
|
63
77
|
<Stack direction="row" alignItems="center" gap="6px">
|
|
@@ -87,6 +101,12 @@ const TrayTabs = ({ activeTray, setActiveTray, imagesCount, assetsCount }) => {
|
|
|
87
101
|
letterSpacing: "-0.015em",
|
|
88
102
|
color: COLORS.s4,
|
|
89
103
|
"&.Mui-selected": { color: COLORS.s5, fontWeight: 600 },
|
|
104
|
+
// Igual que en `TabsBar`: el tema de Creators las pinta de rosa
|
|
105
|
+
// al pasar el ratón y aquí no se quiere.
|
|
106
|
+
"&:hover, &.Mui-selected:hover": {
|
|
107
|
+
color: COLORS.s5,
|
|
108
|
+
backgroundColor: "transparent",
|
|
109
|
+
},
|
|
90
110
|
}}
|
|
91
111
|
/>
|
|
92
112
|
);
|
|
@@ -167,6 +187,7 @@ export const ImagesSection = ({
|
|
|
167
187
|
imageLayout,
|
|
168
188
|
// bandejas
|
|
169
189
|
enableDigitalAssets,
|
|
190
|
+
hasImagesService = true,
|
|
170
191
|
currentTray,
|
|
171
192
|
setActiveTray,
|
|
172
193
|
digitalAssets,
|
|
@@ -230,6 +251,7 @@ export const ImagesSection = ({
|
|
|
230
251
|
setActiveTray={setActiveTray}
|
|
231
252
|
imagesCount={images.length}
|
|
232
253
|
assetsCount={digitalAssets?.assets?.length ?? 0}
|
|
254
|
+
hasImagesService={hasImagesService}
|
|
233
255
|
/>
|
|
234
256
|
)}
|
|
235
257
|
|
|
@@ -6,13 +6,9 @@ import { COLORS, FONTS, statusColor, statusName } from "./tokens";
|
|
|
6
6
|
* Etiqueta de estatus ("RA/AS", "AA"...). Mismo color y tamaño que
|
|
7
7
|
* `atoms/Status`; el nombre completo va en el tooltip. `oval` es la variante
|
|
8
8
|
* redondeada de la barra de pestañas.
|
|
9
|
-
*
|
|
10
|
-
* `label`, `color` y `title` (opcionales) reemplazan el texto, el color y el
|
|
11
|
-
* tooltip: los estatus de los flujos simples del catálogo (Pendiente, Hecho…)
|
|
12
|
-
* traen los suyos desde el backend.
|
|
13
9
|
*/
|
|
14
|
-
export const StatusChip = ({ status, oval = false
|
|
15
|
-
const label =
|
|
10
|
+
export const StatusChip = ({ status, oval = false }) => {
|
|
11
|
+
const label = status ?? "NS";
|
|
16
12
|
const chip = (
|
|
17
13
|
<Chip
|
|
18
14
|
label={label}
|
|
@@ -20,7 +16,7 @@ export const StatusChip = ({ status, oval = false, label: labelProp, color, titl
|
|
|
20
16
|
sx={{
|
|
21
17
|
height: 20,
|
|
22
18
|
borderRadius: oval ? "10px" : "3px",
|
|
23
|
-
backgroundColor:
|
|
19
|
+
backgroundColor: statusColor(status),
|
|
24
20
|
color: COLORS.white,
|
|
25
21
|
fontFamily: FONTS.Lato,
|
|
26
22
|
fontSize: 12,
|
|
@@ -30,7 +26,7 @@ export const StatusChip = ({ status, oval = false, label: labelProp, color, titl
|
|
|
30
26
|
/>
|
|
31
27
|
);
|
|
32
28
|
|
|
33
|
-
const name =
|
|
29
|
+
const name = statusName(status);
|
|
34
30
|
return name ? (
|
|
35
31
|
<Tooltip title={name} arrow placement="top">
|
|
36
32
|
{chip}
|
|
@@ -44,6 +44,15 @@ const tabSx = {
|
|
|
44
44
|
borderBottom: `2px solid ${COLORS.s3}`,
|
|
45
45
|
transition: "font-size 0.1s",
|
|
46
46
|
"&.Mui-selected": { color: COLORS.s5, fontSize: { xs: 14, sm: 18 } },
|
|
47
|
+
/*
|
|
48
|
+
El tema de MUI de Creators pinta las pestañas de rosa al pasar el ratón
|
|
49
|
+
(`MuiTab.styleOverrides.root`). Aquí no se quiere ese realce, y la librería
|
|
50
|
+
no debe depender del tema de quien la consume: se anula explícitamente.
|
|
51
|
+
*/
|
|
52
|
+
"&:hover, &.Mui-selected:hover": {
|
|
53
|
+
color: COLORS.s5,
|
|
54
|
+
backgroundColor: "transparent",
|
|
55
|
+
},
|
|
47
56
|
};
|
|
48
57
|
|
|
49
58
|
export const TabsBar = ({
|
package/src/components/pages/CreatorsProductEdition/stories/CreatorsProductEdition.stories.js
CHANGED
|
@@ -102,6 +102,12 @@ HijoDeOtro.decorators = [withMockApi({ familia: "hijo" })];
|
|
|
102
102
|
|
|
103
103
|
// --- Casos límite -----------------------------------------------------------
|
|
104
104
|
|
|
105
|
+
// Producto sin el servicio de imágenes contratado: la bandeja de imágenes
|
|
106
|
+
// queda deshabilitada y la de activos digitales sigue siendo utilizable.
|
|
107
|
+
export const SinServicioDeImagenes = Template.bind({});
|
|
108
|
+
SinServicioDeImagenes.args = AuditorQA.args;
|
|
109
|
+
SinServicioDeImagenes.decorators = [withMockApi({ imagesService: false })];
|
|
110
|
+
|
|
105
111
|
export const SinImagenes = Template.bind({});
|
|
106
112
|
SinImagenes.args = EspecialistaImagenes.args;
|
|
107
113
|
SinImagenes.decorators = [withMockApi({ images: false })];
|
|
@@ -52,9 +52,9 @@ export const getCategories = async (jwt, user, company) => {
|
|
|
52
52
|
export const formatDate = (date) => {
|
|
53
53
|
const newDate = new Date(date);
|
|
54
54
|
const year = newDate.getFullYear();
|
|
55
|
-
const month = newDate.getMonth() + 1;
|
|
56
|
-
const day = newDate.getDate();
|
|
57
|
-
return `${year}
|
|
55
|
+
const month = `${newDate.getMonth() + 1}`.padStart(2, "0");
|
|
56
|
+
const day = `${newDate.getDate()}`.padStart(2, "0");
|
|
57
|
+
return `${year}-${month}-${day}`;
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
const getCategoriesRecursive = (object) => {
|
|
@@ -39,9 +39,9 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
39
39
|
];
|
|
40
40
|
const [applicantsFilter, setApplicantsFilter] = useState([]);
|
|
41
41
|
const [totalCount, setTotalCount] = useState(0);
|
|
42
|
+
// Total sin filtros, solo para el porcentaje de la dona.
|
|
43
|
+
const [totalUnfiltered, setTotalUnfiltered] = useState(0);
|
|
42
44
|
const [isProviderFinanced] = useState(company?.financedRetailers?.length > 0);
|
|
43
|
-
const [trades, setTrades] = useState([]);
|
|
44
|
-
const [tradesSelected, setTradesSelected] = useState([]);
|
|
45
45
|
|
|
46
46
|
const loadProductVersions = async (queryObject) => {
|
|
47
47
|
const keys = Object.keys(queryObject);
|
|
@@ -82,127 +82,102 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
82
82
|
setRetailers(retailers);
|
|
83
83
|
};
|
|
84
84
|
|
|
85
|
-
const loadProductsByStatus = async (orderByStatus) => {
|
|
85
|
+
const loadProductsByStatus = async (orderByStatus, isBaseline = false) => {
|
|
86
86
|
const isRetailer = user.is_retailer && company.retailers;
|
|
87
87
|
const isProvider = !user.is_retailer && user.id_role === 0;
|
|
88
88
|
const isCollaborator = user.id_role > 0;
|
|
89
|
-
const { ordersBydate, ordersByStatus, ordersByActive
|
|
89
|
+
const { ordersBydate, ordersByStatus = {}, ordersByActive = {} } =
|
|
90
90
|
(await loadProductVersions(orderByStatus)) || {};
|
|
91
91
|
|
|
92
|
-
if (trades.length === 0) setTrades(companyTrades);
|
|
93
92
|
const { total = 0, R = 0, PA = 0, Ex = 0, ACA = 0 } = ordersByStatus;
|
|
94
93
|
let productsFinished = 0;
|
|
95
94
|
if (isRetailer) productsFinished = Ex;
|
|
96
|
-
if (isProvider) productsFinished = ACA;
|
|
95
|
+
if (isProvider) productsFinished = ACA + Ex;
|
|
97
96
|
if (isCollaborator) productsFinished = Ex + ACA;
|
|
98
97
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
: prev,
|
|
104
|
-
0
|
|
105
|
-
);
|
|
98
|
+
// Lo que no está sin asignar ni terminado está en proceso, para que las
|
|
99
|
+
// tres tarjetas siempre sumen el total filtrado.
|
|
100
|
+
const unassigned = PA + R;
|
|
101
|
+
const inProcess = total - unassigned - productsFinished;
|
|
106
102
|
|
|
107
|
-
const registeredProducts = ordersByActive.registered;
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
103
|
+
const registeredProducts = ordersByActive.registered ?? 0;
|
|
104
|
+
const metricsArray = [
|
|
105
|
+
{
|
|
106
|
+
label: "Catálogo activo",
|
|
107
|
+
value: registeredProducts,
|
|
108
|
+
hint: "Productos dados de alta y activos. No depende del filtro de fechas, que aplica a la fecha de la orden.",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
label: "En órdenes de trabajo",
|
|
112
|
+
value: total,
|
|
113
|
+
hint: "Productos con orden de trabajo viva dentro de los filtros. Un producto en dos órdenes cuenta en cada una.",
|
|
114
|
+
},
|
|
115
|
+
{ label: "Sin asignar", value: unassigned },
|
|
116
|
+
{ label: "En proceso", value: inProcess },
|
|
117
|
+
{ label: "Terminados", value: productsFinished },
|
|
112
118
|
];
|
|
113
|
-
|
|
114
|
-
metricsArray.push(
|
|
115
|
-
{ label: "Productos activos", value: registeredProducts },
|
|
116
|
-
{ label: "Productos filtrados", value: total },
|
|
117
|
-
{ label: "Productos sin asignar", value: PA + R },
|
|
118
|
-
{ label: "Productos en proceso", value: inProcess },
|
|
119
|
-
{ label: "Productos terminados", value: productsFinished }
|
|
120
|
-
);
|
|
121
119
|
setMetricsData(metricsArray);
|
|
122
120
|
setTotalCount(total);
|
|
121
|
+
if (isBaseline) setTotalUnfiltered(total);
|
|
123
122
|
delete ordersByStatus.total;
|
|
124
123
|
setRequiredProducts(ordersBydate);
|
|
125
124
|
setProductsByStatus(ordersByStatus);
|
|
126
125
|
};
|
|
127
126
|
|
|
128
127
|
const datesSelect = () => {
|
|
129
|
-
|
|
128
|
+
// Cada rango se calcula al momento de elegirlo y con fechas locales: si se
|
|
129
|
+
// parte de un Date compartido, los options se pisan entre sí, y
|
|
130
|
+
// new Date("2026-11-01") cae en el día anterior al oeste de UTC.
|
|
131
|
+
const applyRange = (startDate, endDate = new Date()) =>
|
|
132
|
+
setDatesRange({
|
|
133
|
+
startDate: formatDate(startDate),
|
|
134
|
+
endDate: formatDate(endDate),
|
|
135
|
+
});
|
|
136
|
+
const daysAgo = (days) => {
|
|
137
|
+
const date = new Date();
|
|
138
|
+
date.setDate(date.getDate() - days);
|
|
139
|
+
return date;
|
|
140
|
+
};
|
|
130
141
|
setDateOptions([
|
|
131
142
|
{ id: 0, name: "Rango de fechas" },
|
|
132
143
|
{
|
|
133
144
|
id: 1,
|
|
134
145
|
name: "Todo el tiempo",
|
|
135
|
-
function: () =>
|
|
136
|
-
setDatesRange({
|
|
137
|
-
startDate: formatDate(new Date("1900-01-01")),
|
|
138
|
-
endDate: formatDate(new Date()),
|
|
139
|
-
}),
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
id: 2,
|
|
143
|
-
name: "Hoy",
|
|
144
|
-
function: () =>
|
|
145
|
-
setDatesRange({
|
|
146
|
-
startDate: formatDate(new Date()),
|
|
147
|
-
endDate: formatDate(new Date()),
|
|
148
|
-
}),
|
|
149
|
-
},
|
|
150
|
-
{
|
|
151
|
-
id: 3,
|
|
152
|
-
name: "Ayer",
|
|
153
|
-
function: () =>
|
|
154
|
-
setDatesRange({
|
|
155
|
-
startDate: formatDate(new Date(today.setDate(today.getDate() - 1))),
|
|
156
|
-
endDate: formatDate(new Date()),
|
|
157
|
-
}),
|
|
146
|
+
function: () => applyRange(new Date(1900, 0, 1)),
|
|
158
147
|
},
|
|
148
|
+
{ id: 2, name: "Hoy", function: () => applyRange(new Date()) },
|
|
149
|
+
{ id: 3, name: "Ayer", function: () => applyRange(daysAgo(1), daysAgo(1)) },
|
|
159
150
|
{
|
|
160
151
|
id: 4,
|
|
161
152
|
name: "Esta semana",
|
|
162
|
-
function: () =>
|
|
163
|
-
setDatesRange({
|
|
164
|
-
startDate: formatDate(
|
|
165
|
-
new Date(today.setDate(today.getDate() - today.getDay()))
|
|
166
|
-
),
|
|
167
|
-
endDate: formatDate(new Date()),
|
|
168
|
-
}),
|
|
153
|
+
function: () => applyRange(daysAgo(new Date().getDay())),
|
|
169
154
|
},
|
|
170
155
|
{
|
|
171
156
|
id: 5,
|
|
172
157
|
name: "La semana pasada",
|
|
173
|
-
function: () =>
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
),
|
|
178
|
-
endDate: formatDate(
|
|
179
|
-
new Date(today.setDate(today.getDate() - today.getDay() + 7))
|
|
180
|
-
),
|
|
181
|
-
}),
|
|
158
|
+
function: () => {
|
|
159
|
+
const weekday = new Date().getDay();
|
|
160
|
+
return applyRange(daysAgo(weekday + 7), daysAgo(weekday + 1));
|
|
161
|
+
},
|
|
182
162
|
},
|
|
183
163
|
{
|
|
184
164
|
id: 6,
|
|
185
165
|
name: "Este mes",
|
|
186
|
-
function: () =>
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
),
|
|
191
|
-
endDate: formatDate(today),
|
|
192
|
-
}),
|
|
166
|
+
function: () => {
|
|
167
|
+
const today = new Date();
|
|
168
|
+
return applyRange(new Date(today.getFullYear(), today.getMonth(), 1));
|
|
169
|
+
},
|
|
193
170
|
},
|
|
194
171
|
{
|
|
195
172
|
id: 7,
|
|
196
173
|
name: "El mes pasado",
|
|
197
|
-
function: () =>
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
),
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
),
|
|
205
|
-
}),
|
|
174
|
+
function: () => {
|
|
175
|
+
const today = new Date();
|
|
176
|
+
return applyRange(
|
|
177
|
+
new Date(today.getFullYear(), today.getMonth() - 1, 1),
|
|
178
|
+
new Date(today.getFullYear(), today.getMonth(), 0)
|
|
179
|
+
);
|
|
180
|
+
},
|
|
206
181
|
},
|
|
207
182
|
]);
|
|
208
183
|
};
|
|
@@ -219,7 +194,7 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
219
194
|
setDatesRange({ startDate, endDate });
|
|
220
195
|
setOrderByStatus(queryObject);
|
|
221
196
|
setOrderByRequired(queryObject);
|
|
222
|
-
loadProductsByStatus(queryObject);
|
|
197
|
+
loadProductsByStatus(queryObject, true);
|
|
223
198
|
}, []);
|
|
224
199
|
|
|
225
200
|
useEffect(() => {
|
|
@@ -241,20 +216,11 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
241
216
|
if (companyId.length > 0) queryObject["companyId"] = companyId.join(",");
|
|
242
217
|
if (retailerId.length > 0) queryObject["retailerId"] = retailerId.join(",");
|
|
243
218
|
if (categoryId.length > 0) queryObject["categoryId"] = categoryId.join(",");
|
|
244
|
-
if (tradesSelected.length > 0)
|
|
245
|
-
queryObject["trades"] = encodeURIComponent(tradesSelected.join(","));
|
|
246
219
|
applicantsFilter.length > 0 &&
|
|
247
220
|
(queryObject["requestedBy"] = applicantsFilter.join(","));
|
|
248
221
|
|
|
249
|
-
await loadProductsByStatus(queryObject
|
|
250
|
-
}, [
|
|
251
|
-
companyId,
|
|
252
|
-
retailerId,
|
|
253
|
-
categoryId,
|
|
254
|
-
datesRange,
|
|
255
|
-
applicantsFilter,
|
|
256
|
-
tradesSelected,
|
|
257
|
-
]);
|
|
222
|
+
await loadProductsByStatus(queryObject);
|
|
223
|
+
}, [companyId, retailerId, categoryId, datesRange, applicantsFilter]);
|
|
258
224
|
|
|
259
225
|
return loading ? (
|
|
260
226
|
<Loading />
|
|
@@ -319,17 +285,6 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
319
285
|
defaultOption="Todos los solicitantes"
|
|
320
286
|
/>
|
|
321
287
|
)}
|
|
322
|
-
{user.id_role === 0 && trades?.length > 0 && (
|
|
323
|
-
<CustomSelect
|
|
324
|
-
showSearchBar={true}
|
|
325
|
-
options={trades}
|
|
326
|
-
selectLabel="Todas las marcas"
|
|
327
|
-
placeHolder="Buscar marca"
|
|
328
|
-
customSelectId="trade-select"
|
|
329
|
-
parameterArray={tradesSelected}
|
|
330
|
-
setParameterArray={setTradesSelected}
|
|
331
|
-
/>
|
|
332
|
-
)}
|
|
333
288
|
</div>
|
|
334
289
|
<div className="metric-cards">
|
|
335
290
|
{metricsData.map((metric, index) => (
|
|
@@ -337,6 +292,7 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
337
292
|
key={`${index}-${metric.value}`}
|
|
338
293
|
label={metric.label}
|
|
339
294
|
number={metric.value}
|
|
295
|
+
hint={metric.hint}
|
|
340
296
|
/>
|
|
341
297
|
))}
|
|
342
298
|
</div>
|
|
@@ -358,7 +314,7 @@ export const Dashboard = ({ jwt, user, company }) => {
|
|
|
358
314
|
showPercent={true}
|
|
359
315
|
displayScale={false}
|
|
360
316
|
totalFiltered={totalCount}
|
|
361
|
-
total={
|
|
317
|
+
total={totalUnfiltered}
|
|
362
318
|
/>
|
|
363
319
|
<DashboardMetric
|
|
364
320
|
label={"Productos solicitados"}
|
|
@@ -5,11 +5,9 @@ export const Container = styled.div`
|
|
|
5
5
|
|
|
6
6
|
.filters {
|
|
7
7
|
display: flex;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
}
|
|
8
|
+
flex-wrap: wrap;
|
|
9
|
+
gap: 10px;
|
|
10
|
+
|
|
13
11
|
& + * {
|
|
14
12
|
margin-top: 20px;
|
|
15
13
|
}
|
|
@@ -17,10 +15,8 @@ export const Container = styled.div`
|
|
|
17
15
|
|
|
18
16
|
.metric-cards {
|
|
19
17
|
display: flex;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
margin-left: 10px;
|
|
23
|
-
}
|
|
18
|
+
flex-wrap: wrap;
|
|
19
|
+
gap: 10px;
|
|
24
20
|
|
|
25
21
|
& + * {
|
|
26
22
|
margin-top: 10px;
|
|
@@ -28,10 +24,19 @@ export const Container = styled.div`
|
|
|
28
24
|
}
|
|
29
25
|
|
|
30
26
|
.metrics-main-container {
|
|
31
|
-
display:
|
|
27
|
+
display: grid;
|
|
28
|
+
/* Dos paneles mientras quepan 320px cada uno; si no, uno debajo del otro.
|
|
29
|
+
El min() evita que la columna siga midiendo 320px en pantallas menores. */
|
|
30
|
+
grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
|
|
31
|
+
gap: 10px;
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
/* Sin esto las gráficas no pueden encogerse por debajo de su ancho. */
|
|
34
|
+
> * {
|
|
35
|
+
min-width: 0;
|
|
35
36
|
}
|
|
36
37
|
}
|
|
38
|
+
|
|
39
|
+
@media (max-width: 600px) {
|
|
40
|
+
padding: 15px;
|
|
41
|
+
}
|
|
37
42
|
`;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { RetailerProductEdition } from "./index";
|
|
2
|
-
import { withDemoServices } from "../../organisms/ServicesWorkspace/demo";
|
|
3
2
|
|
|
4
3
|
export default {
|
|
5
4
|
title: "Components/pages/RetailerProductEdition",
|
|
@@ -218,14 +217,3 @@ user: {
|
|
|
218
217
|
}
|
|
219
218
|
|
|
220
219
|
};
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Con la pestaña "Servicios" (la activa Creators con `showServicesTab`) y
|
|
224
|
-
* servicios de ejemplo además de los tres de siempre.
|
|
225
|
-
*/
|
|
226
|
-
export const ConPestanaServicios = Template.bind({});
|
|
227
|
-
ConPestanaServicios.args = {
|
|
228
|
-
...RetailerProductEditionDefault.args,
|
|
229
|
-
showServicesTab: true,
|
|
230
|
-
productSelected: withDemoServices(RetailerProductEditionDefault.args.productSelected, 14),
|
|
231
|
-
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect,
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
2
|
|
|
3
3
|
import axios from "axios";
|
|
4
4
|
import { useDropzone } from "react-dropzone";
|
|
@@ -74,7 +74,6 @@ import generateThumbnail from "./generateThumnail";
|
|
|
74
74
|
|
|
75
75
|
import { AiProductEditionProvider } from "../../../contexts/AiProductEdition";
|
|
76
76
|
import ChangeStatusModal from "../../organisms/ChangeStatusModal";
|
|
77
|
-
import ServicesWorkspace from "../../organisms/ServicesWorkspace";
|
|
78
77
|
|
|
79
78
|
import { Skeleton, Box, Stack } from "@mui/material";
|
|
80
79
|
|
|
@@ -106,14 +105,8 @@ function obtenerDuracionVideoBase64(base64Data) {
|
|
|
106
105
|
});
|
|
107
106
|
}
|
|
108
107
|
|
|
109
|
-
/** Pestaña con todos los servicios del producto (ver organisms/ServicesWorkspace). */
|
|
110
|
-
const SERVICES_TAB = "Servicios";
|
|
111
|
-
|
|
112
108
|
const RetailerProductEditionView = ({
|
|
113
109
|
tabsSections,
|
|
114
|
-
// Opcional para no cambiar la edición de quien no la pida (aplicación de
|
|
115
|
-
// proveedores). Creators la activa.
|
|
116
|
-
showServicesTab = false,
|
|
117
110
|
productSelected = {},
|
|
118
111
|
user = {},
|
|
119
112
|
token,
|
|
@@ -141,13 +134,6 @@ const RetailerProductEditionView = ({
|
|
|
141
134
|
|
|
142
135
|
const isRetailer = user?.is_retailer;
|
|
143
136
|
|
|
144
|
-
const tabs = useMemo(
|
|
145
|
-
() =>
|
|
146
|
-
showServicesTab ? { ...tabsSections, [SERVICES_TAB]: false } : tabsSections,
|
|
147
|
-
[tabsSections, showServicesTab],
|
|
148
|
-
);
|
|
149
|
-
const isServicesTab = state.active_tab === SERVICES_TAB;
|
|
150
|
-
|
|
151
137
|
const [showVersionSelector, setShowVersionSelector] =
|
|
152
138
|
useCloseModal("version-selector");
|
|
153
139
|
const [auditableVersion, setAuditableVersion] = useState(null);
|
|
@@ -2942,7 +2928,7 @@ const RetailerProductEditionView = ({
|
|
|
2942
2928
|
}
|
|
2943
2929
|
/>
|
|
2944
2930
|
<FullTabsMenu
|
|
2945
|
-
tabsSections={
|
|
2931
|
+
tabsSections={tabsSections}
|
|
2946
2932
|
status={getStatusByCurrentServiceAndRetailer()}
|
|
2947
2933
|
activeTab={state.active_tab}
|
|
2948
2934
|
isRetailer={isRetailer}
|
|
@@ -2989,14 +2975,6 @@ const RetailerProductEditionView = ({
|
|
|
2989
2975
|
<Loading />
|
|
2990
2976
|
) : (
|
|
2991
2977
|
<>
|
|
2992
|
-
{isServicesTab && (
|
|
2993
|
-
<ServicesWorkspace
|
|
2994
|
-
product={state.product}
|
|
2995
|
-
retailers={state.product?.categoryRetailerInOrder ?? []}
|
|
2996
|
-
canAssign={![7, 8].includes(user.id_role)}
|
|
2997
|
-
onOpenEditor={handleOnChangeActiveTab}
|
|
2998
|
-
/>
|
|
2999
|
-
)}
|
|
3000
2978
|
{state.active_tab === "Descripción" &&
|
|
3001
2979
|
(state.product?.description_status !== "NS" ? (
|
|
3002
2980
|
<InputGroup
|
|
@@ -3172,10 +3150,7 @@ const RetailerProductEditionView = ({
|
|
|
3172
3150
|
</>
|
|
3173
3151
|
)}
|
|
3174
3152
|
</div>
|
|
3175
|
-
{
|
|
3176
|
-
en la pestaña Servicios cada servicio lleva su propio detalle. */}
|
|
3177
|
-
{!isServicesTab &&
|
|
3178
|
-
(isUserAssignedToService(state.active_tab) ||
|
|
3153
|
+
{(isUserAssignedToService(state.active_tab) ||
|
|
3179
3154
|
isAuditorAssigned()) &&
|
|
3180
3155
|
state.product[`${getConceptByTab(state.active_tab)}_status`] !==
|
|
3181
3156
|
"NS" && (
|
|
@@ -148,11 +148,6 @@ export const normalizeProduct = (product) => {
|
|
|
148
148
|
id_auditor: article.id_auditor || 0,
|
|
149
149
|
statusByRetailer: productData.statusByRetailer || null,
|
|
150
150
|
categoryRetailerInOrder: categoryRetailerInOrder || null,
|
|
151
|
-
|
|
152
|
-
// Servicios para la pestaña "Servicios": estatus por servicio del listado
|
|
153
|
-
// ligero de Creators (view=summary) y, en modo demo, los de ejemplo.
|
|
154
|
-
serviceStatuses: productData.serviceStatuses ?? null,
|
|
155
|
-
demo_services: productData.demo_services ?? null,
|
|
156
151
|
};
|
|
157
152
|
};
|
|
158
153
|
|
package/src/index.js
CHANGED
|
@@ -116,7 +116,6 @@ export * from "./components/pages/RegistrationLoginSecondStep";
|
|
|
116
116
|
export * from "./components/pages/RegistrationLoginThirdStep";
|
|
117
117
|
export * from "./components/pages/RetailerProductEdition";
|
|
118
118
|
export * from "./components/pages/CreatorsProductEdition";
|
|
119
|
-
export * from "./components/pages/ProductEdition";
|
|
120
119
|
export * from "./components/pages/ProviderProductEdition";
|
|
121
120
|
export * from "./components/pages/VerificationCodeResetPassword";
|
|
122
121
|
export * from "./components/pages/MultipleEdition";
|