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.
Files changed (102) hide show
  1. package/.claude/settings.local.json +7 -0
  2. package/dist/ai/prompts/attribute.prompt.js +28 -0
  3. package/dist/ai/prompts/description.prompt.js +33 -0
  4. package/dist/ai/schemas/attribute.schema.js +35 -0
  5. package/dist/ai/schemas/description.schema.js +27 -0
  6. package/dist/components/atoms/MetricCard/index.js +3 -1
  7. package/dist/components/organisms/DashboardMetric/DashboardMetric.stories.js +12 -2
  8. package/dist/components/organisms/DashboardMetric/index.js +24 -1
  9. package/dist/components/organisms/DashboardMetric/styles.js +1 -1
  10. package/dist/components/pages/CreatorsProductEdition/CreatorsProductEditionView.js +11 -5
  11. package/dist/components/pages/CreatorsProductEdition/hooks/useCreatorsProductEdition.js +58 -31
  12. package/dist/components/pages/CreatorsProductEdition/mocks/api.fixtures.js +5 -1
  13. package/dist/components/pages/CreatorsProductEdition/mocks/mockApi.js +3 -40
  14. package/dist/components/pages/CreatorsProductEdition/sections/ImagesSection.js +18 -3
  15. package/dist/components/pages/CreatorsProductEdition/sections/StatusChip.js +4 -13
  16. package/dist/components/pages/CreatorsProductEdition/sections/TabsBar.js +10 -0
  17. package/dist/components/pages/CreatorsProductEdition/stories/CreatorsProductEdition.stories.js +10 -2
  18. package/dist/components/pages/Dashboard/dashboardUtils.js +3 -3
  19. package/dist/components/pages/Dashboard/index.js +102 -88
  20. package/dist/components/pages/Dashboard/styles.js +1 -1
  21. package/dist/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +2 -15
  22. package/dist/components/pages/RetailerProductEdition/index.js +40 -57
  23. package/dist/components/pages/RetailerProductEdition/utils.js +2 -6
  24. package/dist/index.js +0 -13
  25. package/package.json +1 -1
  26. package/src/components/atoms/MetricCard/index.js +2 -2
  27. package/src/components/organisms/DashboardMetric/DashboardMetric.stories.js +11 -0
  28. package/src/components/organisms/DashboardMetric/index.js +13 -1
  29. package/src/components/organisms/DashboardMetric/styles.js +13 -0
  30. package/src/components/pages/CreatorsProductEdition/CreatorsProductEditionView.jsx +22 -3
  31. package/src/components/pages/CreatorsProductEdition/hooks/useCreatorsProductEdition.js +36 -1
  32. package/src/components/pages/CreatorsProductEdition/mocks/api.fixtures.js +15 -3
  33. package/src/components/pages/CreatorsProductEdition/mocks/mockApi.js +8 -18
  34. package/src/components/pages/CreatorsProductEdition/sections/ImagesSection.jsx +24 -2
  35. package/src/components/pages/CreatorsProductEdition/sections/StatusChip.jsx +4 -8
  36. package/src/components/pages/CreatorsProductEdition/sections/TabsBar.jsx +9 -0
  37. package/src/components/pages/CreatorsProductEdition/stories/CreatorsProductEdition.stories.js +6 -0
  38. package/src/components/pages/Dashboard/dashboardUtils.js +3 -3
  39. package/src/components/pages/Dashboard/index.js +62 -106
  40. package/src/components/pages/Dashboard/styles.js +17 -12
  41. package/src/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +0 -12
  42. package/src/components/pages/RetailerProductEdition/index.js +3 -28
  43. package/src/components/pages/RetailerProductEdition/utils.js +0 -5
  44. package/src/index.js +0 -1
  45. package/dist/components/organisms/ServicesNavigation/ServiceToolbar.js +0 -210
  46. package/dist/components/organisms/ServicesNavigation/ServicesNavigation.stories.js +0 -138
  47. package/dist/components/organisms/ServicesNavigation/ServicesRail.js +0 -705
  48. package/dist/components/organisms/ServicesNavigation/catalog.js +0 -505
  49. package/dist/components/organisms/ServicesNavigation/index.js +0 -337
  50. package/dist/components/organisms/ServicesNavigation/model.js +0 -167
  51. package/dist/components/organisms/ServicesNavigation/ui.js +0 -371
  52. package/dist/components/organisms/ServicesNavigation/views.js +0 -1237
  53. package/dist/components/organisms/ServicesWorkspace/AssigneePicker.js +0 -459
  54. package/dist/components/organisms/ServicesWorkspace/ServicesWorkspace.stories.js +0 -119
  55. package/dist/components/organisms/ServicesWorkspace/demo.js +0 -137
  56. package/dist/components/organisms/ServicesWorkspace/index.js +0 -813
  57. package/dist/components/organisms/ServicesWorkspace/servicesModel.js +0 -351
  58. package/dist/components/organisms/ServicesWorkspace/tooltipStyles.js +0 -37
  59. package/dist/components/pages/CreatorsProductEdition/mocks/productServices.fixtures.js +0 -387
  60. package/dist/components/pages/ProductEdition/ProductEdition.stories.js +0 -148
  61. package/dist/components/pages/ProductEdition/ProductEditionView.js +0 -1355
  62. package/dist/components/pages/ProductEdition/ServiceHeader.js +0 -142
  63. package/dist/components/pages/ProductEdition/api.js +0 -256
  64. package/dist/components/pages/ProductEdition/index.js +0 -37
  65. package/dist/components/pages/ProductEdition/permissions.js +0 -200
  66. package/dist/components/pages/ProductEdition/permissions.test.js +0 -320
  67. package/dist/components/pages/ProductEdition/sections/CatalogServicePanel.js +0 -237
  68. package/dist/components/pages/ProductEdition/sections/EditionTopBar.js +0 -174
  69. package/dist/components/pages/ProductEdition/sections/ImagePanel.js +0 -440
  70. package/dist/components/pages/ProductEdition/sections/ServiceTeam.js +0 -275
  71. package/dist/components/pages/ProductEdition/sections/ServiceTools.js +0 -186
  72. package/dist/components/pages/ProductEdition/services.js +0 -233
  73. package/dist/components/pages/ProductEdition/services.test.js +0 -195
  74. package/src/components/organisms/ServicesNavigation/ServiceToolbar.jsx +0 -143
  75. package/src/components/organisms/ServicesNavigation/ServicesNavigation.stories.js +0 -101
  76. package/src/components/organisms/ServicesNavigation/ServicesRail.jsx +0 -591
  77. package/src/components/organisms/ServicesNavigation/catalog.js +0 -180
  78. package/src/components/organisms/ServicesNavigation/index.jsx +0 -232
  79. package/src/components/organisms/ServicesNavigation/model.js +0 -85
  80. package/src/components/organisms/ServicesNavigation/ui.jsx +0 -229
  81. package/src/components/organisms/ServicesNavigation/views.jsx +0 -705
  82. package/src/components/organisms/ServicesWorkspace/AssigneePicker.js +0 -348
  83. package/src/components/organisms/ServicesWorkspace/ServicesWorkspace.stories.js +0 -61
  84. package/src/components/organisms/ServicesWorkspace/demo.js +0 -58
  85. package/src/components/organisms/ServicesWorkspace/index.js +0 -556
  86. package/src/components/organisms/ServicesWorkspace/servicesModel.js +0 -203
  87. package/src/components/organisms/ServicesWorkspace/tooltipStyles.js +0 -27
  88. package/src/components/pages/CreatorsProductEdition/mocks/productServices.fixtures.js +0 -175
  89. package/src/components/pages/ProductEdition/ProductEdition.stories.js +0 -106
  90. package/src/components/pages/ProductEdition/ProductEditionView.jsx +0 -1142
  91. package/src/components/pages/ProductEdition/ServiceHeader.jsx +0 -104
  92. package/src/components/pages/ProductEdition/api.js +0 -84
  93. package/src/components/pages/ProductEdition/index.js +0 -21
  94. package/src/components/pages/ProductEdition/permissions.js +0 -128
  95. package/src/components/pages/ProductEdition/permissions.test.js +0 -249
  96. package/src/components/pages/ProductEdition/sections/CatalogServicePanel.jsx +0 -123
  97. package/src/components/pages/ProductEdition/sections/EditionTopBar.jsx +0 -134
  98. package/src/components/pages/ProductEdition/sections/ImagePanel.jsx +0 -342
  99. package/src/components/pages/ProductEdition/sections/ServiceTeam.jsx +0 -184
  100. package/src/components/pages/ProductEdition/sections/ServiceTools.jsx +0 -134
  101. package/src/components/pages/ProductEdition/services.js +0 -187
  102. 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({ images, delSolStatus, familia, grupo });
46
- // Servicios del producto (edición unificada): con estado, para que un cambio
47
- // de estatus o de asignación se vea al volver a pedir la lista.
48
- const productServices = buildProductServices({ delSolStatus });
49
- const lambdaReply = (config, statusCode, body) =>
50
- reply(config, { statusCode, body: JSON.stringify(body) });
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 = ({ activeTray, setActiveTray, imagesCount, assetsCount }) => {
41
+ const TrayTabs = ({
42
+ activeTray,
43
+ setActiveTray,
44
+ imagesCount,
45
+ assetsCount,
46
+ hasImagesService = true,
47
+ }) => {
42
48
  const trays = [
43
- { id: TRAYS.IMAGES, label: "Imágenes", count: imagesCount },
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, label: labelProp, color, title }) => {
15
- const label = labelProp ?? status ?? "NS";
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: color ?? statusColor(status),
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 = title ?? statusName(status);
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 = ({
@@ -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}/${month}/${day}`;
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, companyTrades } =
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
- const inProcess = Object.keys(ordersByStatus).reduce(
100
- (prev, curr) =>
101
- !["total", "PA", "R", "Ex", "ACA"].includes(curr)
102
- ? prev + ordersByStatus[curr]
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
- let metricsArray = [
109
- metricsData[0]
110
- ? metricsData[0]
111
- : { label: "Productos totales", value: total },
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
- const today = new Date();
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
- setDatesRange({
175
- startDate: formatDate(
176
- new Date(today.setDate(today.getDate() - today.getDay() - 7))
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
- setDatesRange({
188
- startDate: formatDate(
189
- new Date(`${today.getFullYear()}-${today.getMonth() + 1}-01`)
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
- setDatesRange({
199
- startDate: formatDate(
200
- new Date(`${today.getFullYear()}-${today.getMonth()}-01`)
201
- ),
202
- endDate: formatDate(
203
- new Date(`${today.getFullYear()}-${today.getMonth() + 1}-01`)
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, true);
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={metricsData[0]?.value}
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
- margin-left: 10px;
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: flex;
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
- margin-left: 10px;
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, useMemo, useRef, useState } from "react";
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={tabs}
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
- {/* Comentario y cambio de estatus son de un servicio con editor;
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";