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,348 +0,0 @@
|
|
|
1
|
-
import { useMemo, useRef, useState } from "react";
|
|
2
|
-
import {
|
|
3
|
-
Avatar,
|
|
4
|
-
Box,
|
|
5
|
-
ButtonBase,
|
|
6
|
-
CircularProgress,
|
|
7
|
-
InputAdornment,
|
|
8
|
-
List,
|
|
9
|
-
ListItemButton,
|
|
10
|
-
Popover,
|
|
11
|
-
TextField,
|
|
12
|
-
Tooltip,
|
|
13
|
-
Typography,
|
|
14
|
-
} from "@mui/material";
|
|
15
|
-
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
|
|
16
|
-
import PersonAddAlt1OutlinedIcon from "@mui/icons-material/PersonAddAlt1Outlined";
|
|
17
|
-
import SearchIcon from "@mui/icons-material/Search";
|
|
18
|
-
import CheckIcon from "@mui/icons-material/Check";
|
|
19
|
-
import { getProfilePicture } from "../../../global-files/data";
|
|
20
|
-
import { whiteTooltipProps } from "./tooltipStyles";
|
|
21
|
-
|
|
22
|
-
/** Roles que ven la asignación pero no pueden cambiarla (igual que AsignationControl). */
|
|
23
|
-
export const READ_ONLY_ROLES = [2, 3, 7, 8];
|
|
24
|
-
|
|
25
|
-
export const canCurrentUserAssign = () => {
|
|
26
|
-
try {
|
|
27
|
-
const user = JSON.parse(sessionStorage.getItem("user"));
|
|
28
|
-
return !READ_ONLY_ROLES.includes(user?.id_role);
|
|
29
|
-
} catch (error) {
|
|
30
|
-
return true;
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* ¿El clic fue dentro de una capa flotante de MUI (selector, tooltip, diálogo)?
|
|
36
|
-
* Esas capas se pintan fuera del panel lateral, así que los "clic afuera para
|
|
37
|
-
* cerrar" deben ignorarlas.
|
|
38
|
-
*/
|
|
39
|
-
export const isFloatingLayerClick = (target) =>
|
|
40
|
-
Boolean(target?.closest?.(".MuiPopover-root, .MuiModal-root, .MuiTooltip-popper"));
|
|
41
|
-
|
|
42
|
-
export const fullName = (user) => [user?.name, user?.last_name].filter(Boolean).join(" ");
|
|
43
|
-
|
|
44
|
-
const initials = (user) =>
|
|
45
|
-
[user?.name, user?.last_name]
|
|
46
|
-
.filter(Boolean)
|
|
47
|
-
.map((part) => part.trim()[0])
|
|
48
|
-
.join("")
|
|
49
|
-
.toUpperCase()
|
|
50
|
-
.slice(0, 2);
|
|
51
|
-
|
|
52
|
-
/** Foto del usuario; si no carga, sus iniciales (MUI muestra `children` cuando falla la imagen). */
|
|
53
|
-
function UserAvatar({ user, size = 28 }) {
|
|
54
|
-
return (
|
|
55
|
-
<Avatar
|
|
56
|
-
src={user?.id_user ? getProfilePicture(user.id_user, 40, 40) : undefined}
|
|
57
|
-
alt={fullName(user)}
|
|
58
|
-
sx={{
|
|
59
|
-
width: size,
|
|
60
|
-
height: size,
|
|
61
|
-
fontSize: size * 0.4,
|
|
62
|
-
fontFamily: "Lato, sans-serif",
|
|
63
|
-
fontWeight: 700,
|
|
64
|
-
bgcolor: "#F0EEF2",
|
|
65
|
-
color: "#503D66",
|
|
66
|
-
}}
|
|
67
|
-
>
|
|
68
|
-
{initials(user)}
|
|
69
|
-
</Avatar>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const pillSx = {
|
|
74
|
-
display: "inline-flex",
|
|
75
|
-
alignItems: "center",
|
|
76
|
-
gap: 0.75,
|
|
77
|
-
height: 34,
|
|
78
|
-
pl: 1.25,
|
|
79
|
-
pr: 0.5,
|
|
80
|
-
borderRadius: "17px",
|
|
81
|
-
backgroundColor: "#F0F0F0",
|
|
82
|
-
border: "1px solid transparent",
|
|
83
|
-
fontFamily: "Lato, sans-serif",
|
|
84
|
-
transition: "background-color 120ms, border-color 120ms",
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const statusSx = {
|
|
88
|
-
fontFamily: "Lato, sans-serif",
|
|
89
|
-
fontSize: 12,
|
|
90
|
-
fontWeight: 600,
|
|
91
|
-
color: "#707070",
|
|
92
|
-
whiteSpace: "nowrap",
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Pastilla "estatus + responsable" y selector de personas.
|
|
97
|
-
*
|
|
98
|
-
* Copia de la de Creators (ServicesCell/AssigneePicker) para que la edición se
|
|
99
|
-
* vea y se comporte igual que la tabla. Colores fijos porque la librería no
|
|
100
|
-
* define las variables CSS de las aplicaciones.
|
|
101
|
-
*
|
|
102
|
-
* - Clic en la pastilla: abre un buscador con la lista de personas asignables.
|
|
103
|
-
* - `lockedReason`: si viene, la pastilla muestra un candado, no abre nada
|
|
104
|
-
* y explica el motivo en el tooltip.
|
|
105
|
-
* - `onAssign(user)`: se llama al elegir a alguien (el padre llama assignUser).
|
|
106
|
-
*/
|
|
107
|
-
export default function AssigneePicker({
|
|
108
|
-
statusLabel,
|
|
109
|
-
statusTitle,
|
|
110
|
-
users = [],
|
|
111
|
-
currentId = null,
|
|
112
|
-
onAssign,
|
|
113
|
-
lockedReason = null,
|
|
114
|
-
roleLabel = "Responsable",
|
|
115
|
-
loading = false,
|
|
116
|
-
}) {
|
|
117
|
-
const pillRef = useRef(null);
|
|
118
|
-
const [open, setOpen] = useState(false);
|
|
119
|
-
const [query, setQuery] = useState("");
|
|
120
|
-
// Asignación optimista: se ve de inmediato aunque la tabla tarde en refrescarse.
|
|
121
|
-
const [pickedId, setPickedId] = useState(null);
|
|
122
|
-
|
|
123
|
-
const selectedId = pickedId ?? currentId;
|
|
124
|
-
const current = useMemo(
|
|
125
|
-
() => users.find((user) => user.id_user === selectedId) || null,
|
|
126
|
-
[users, selectedId]
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
// `statusLabel` puede ser texto fijo o una función del asignado actual (para
|
|
130
|
-
// mostrar el nombre de la persona apenas se elige, sin esperar al padre).
|
|
131
|
-
const label = typeof statusLabel === "function" ? statusLabel(current) : statusLabel;
|
|
132
|
-
|
|
133
|
-
const filtered = useMemo(() => {
|
|
134
|
-
const text = query.trim().toLowerCase();
|
|
135
|
-
if (!text) return users;
|
|
136
|
-
return users.filter((user) => fullName(user).toLowerCase().includes(text));
|
|
137
|
-
}, [users, query]);
|
|
138
|
-
|
|
139
|
-
// Al elegir con Enter, el foco vuelve a la pastilla y el mismo Enter la
|
|
140
|
-
// volvía a abrir. Se ignoran los clics que llegan justo después de cerrar.
|
|
141
|
-
const closedAtRef = useRef(0);
|
|
142
|
-
const close = () => {
|
|
143
|
-
closedAtRef.current = Date.now();
|
|
144
|
-
setOpen(false);
|
|
145
|
-
setQuery("");
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const pick = (user) => {
|
|
149
|
-
if (user.id_user !== selectedId) {
|
|
150
|
-
setPickedId(user.id_user);
|
|
151
|
-
onAssign?.(user);
|
|
152
|
-
}
|
|
153
|
-
close();
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
// Mientras llegan las asignaciones (se piden al desplegar la etapa).
|
|
157
|
-
if (loading) {
|
|
158
|
-
return (
|
|
159
|
-
<Box
|
|
160
|
-
component="span"
|
|
161
|
-
role="status"
|
|
162
|
-
aria-busy="true"
|
|
163
|
-
aria-label={`Cargando ${roleLabel.toLowerCase()}`}
|
|
164
|
-
sx={{ ...pillSx, cursor: "progress", pr: 0.75 }}
|
|
165
|
-
>
|
|
166
|
-
<Typography component="span" title={statusTitle} sx={statusSx}>
|
|
167
|
-
{label}
|
|
168
|
-
</Typography>
|
|
169
|
-
<Box
|
|
170
|
-
component="span"
|
|
171
|
-
sx={{ width: 26, height: 26, display: "inline-flex", alignItems: "center", justifyContent: "center" }}
|
|
172
|
-
>
|
|
173
|
-
<CircularProgress size={16} thickness={5} sx={{ color: "#8A6CAA" }} />
|
|
174
|
-
</Box>
|
|
175
|
-
</Box>
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (lockedReason) {
|
|
180
|
-
return (
|
|
181
|
-
<Tooltip {...whiteTooltipProps} title={lockedReason} arrow placement="left">
|
|
182
|
-
<Box
|
|
183
|
-
component="span"
|
|
184
|
-
role="img"
|
|
185
|
-
aria-label={`No se puede asignar: ${lockedReason}`}
|
|
186
|
-
sx={{ ...pillSx, cursor: "not-allowed", pr: 1, opacity: 0.85 }}
|
|
187
|
-
>
|
|
188
|
-
<Typography component="span" title={statusTitle} sx={statusSx}>
|
|
189
|
-
{label}
|
|
190
|
-
</Typography>
|
|
191
|
-
<LockOutlinedIcon sx={{ fontSize: 18, color: "#707070" }} />
|
|
192
|
-
</Box>
|
|
193
|
-
</Tooltip>
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const tooltip = current ? `${roleLabel}: ${fullName(current)}` : `${roleLabel}: por asignar`;
|
|
198
|
-
|
|
199
|
-
return (
|
|
200
|
-
<>
|
|
201
|
-
<Tooltip {...whiteTooltipProps} title={open ? "" : tooltip} arrow placement="left">
|
|
202
|
-
<ButtonBase
|
|
203
|
-
ref={pillRef}
|
|
204
|
-
onClick={(event) => {
|
|
205
|
-
event.stopPropagation();
|
|
206
|
-
if (Date.now() - closedAtRef.current < 400) return;
|
|
207
|
-
setOpen(true);
|
|
208
|
-
}}
|
|
209
|
-
aria-haspopup="dialog"
|
|
210
|
-
aria-expanded={open}
|
|
211
|
-
aria-label={`${tooltip}. Cambiar`}
|
|
212
|
-
sx={{
|
|
213
|
-
...pillSx,
|
|
214
|
-
cursor: "pointer",
|
|
215
|
-
...(open && { borderColor: "#E33AA9", backgroundColor: "#F0EEF2" }),
|
|
216
|
-
"&:hover": { backgroundColor: "#F0EEF2" },
|
|
217
|
-
"&.Mui-focusVisible": { borderColor: "#E33AA9" },
|
|
218
|
-
}}
|
|
219
|
-
>
|
|
220
|
-
<Typography component="span" title={statusTitle} sx={statusSx}>
|
|
221
|
-
{label}
|
|
222
|
-
</Typography>
|
|
223
|
-
{current ? (
|
|
224
|
-
<UserAvatar user={current} size={26} />
|
|
225
|
-
) : (
|
|
226
|
-
<Box
|
|
227
|
-
component="span"
|
|
228
|
-
sx={{
|
|
229
|
-
width: 26,
|
|
230
|
-
height: 26,
|
|
231
|
-
borderRadius: "50%",
|
|
232
|
-
display: "inline-flex",
|
|
233
|
-
alignItems: "center",
|
|
234
|
-
justifyContent: "center",
|
|
235
|
-
border: "1px dashed #8A6CAA",
|
|
236
|
-
color: "#8A6CAA",
|
|
237
|
-
backgroundColor: "#FFFFFF",
|
|
238
|
-
}}
|
|
239
|
-
>
|
|
240
|
-
<PersonAddAlt1OutlinedIcon sx={{ fontSize: 15 }} />
|
|
241
|
-
</Box>
|
|
242
|
-
)}
|
|
243
|
-
</ButtonBase>
|
|
244
|
-
</Tooltip>
|
|
245
|
-
|
|
246
|
-
<Popover
|
|
247
|
-
open={open}
|
|
248
|
-
anchorEl={pillRef.current}
|
|
249
|
-
onClose={close}
|
|
250
|
-
onClick={(event) => event.stopPropagation()}
|
|
251
|
-
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
|
|
252
|
-
transformOrigin={{ vertical: "top", horizontal: "right" }}
|
|
253
|
-
PaperProps={{
|
|
254
|
-
sx: {
|
|
255
|
-
mt: 0.75,
|
|
256
|
-
width: 300,
|
|
257
|
-
maxWidth: "calc(100vw - 32px)",
|
|
258
|
-
borderRadius: "12px",
|
|
259
|
-
border: "1px solid #F0EEF2",
|
|
260
|
-
boxShadow: 6,
|
|
261
|
-
overflow: "hidden",
|
|
262
|
-
},
|
|
263
|
-
}}
|
|
264
|
-
>
|
|
265
|
-
<Box sx={{ p: 1.5, pb: 1, display: "flex", flexDirection: "column", gap: 1 }}>
|
|
266
|
-
<Typography
|
|
267
|
-
sx={{ fontFamily: "Raleway, sans-serif", fontSize: 13, fontWeight: 600, color: "#503D66" }}
|
|
268
|
-
>
|
|
269
|
-
Asignar {roleLabel.toLowerCase()}
|
|
270
|
-
</Typography>
|
|
271
|
-
<TextField
|
|
272
|
-
autoFocus
|
|
273
|
-
size="small"
|
|
274
|
-
fullWidth
|
|
275
|
-
placeholder="Buscar persona…"
|
|
276
|
-
value={query}
|
|
277
|
-
onChange={(event) => setQuery(event.target.value)}
|
|
278
|
-
onKeyDown={(event) => {
|
|
279
|
-
if (event.key === "Enter" && filtered[0]) {
|
|
280
|
-
event.preventDefault();
|
|
281
|
-
pick(filtered[0]);
|
|
282
|
-
}
|
|
283
|
-
}}
|
|
284
|
-
InputProps={{
|
|
285
|
-
startAdornment: (
|
|
286
|
-
<InputAdornment position="start">
|
|
287
|
-
<SearchIcon sx={{ fontSize: 18, color: "#707070" }} />
|
|
288
|
-
</InputAdornment>
|
|
289
|
-
),
|
|
290
|
-
sx: {
|
|
291
|
-
borderRadius: "8px",
|
|
292
|
-
fontFamily: "Lato, sans-serif",
|
|
293
|
-
fontSize: 13,
|
|
294
|
-
"&.Mui-focused .MuiOutlinedInput-notchedOutline": { borderColor: "#E33AA9" },
|
|
295
|
-
},
|
|
296
|
-
}}
|
|
297
|
-
/>
|
|
298
|
-
</Box>
|
|
299
|
-
|
|
300
|
-
<List dense disablePadding sx={{ maxHeight: 280, overflowY: "auto", px: 0.75, pb: 0.75 }}>
|
|
301
|
-
{filtered.map((user) => {
|
|
302
|
-
const isSelected = user.id_user === selectedId;
|
|
303
|
-
return (
|
|
304
|
-
<ListItemButton
|
|
305
|
-
key={user.id_user}
|
|
306
|
-
selected={isSelected}
|
|
307
|
-
onClick={() => pick(user)}
|
|
308
|
-
sx={{
|
|
309
|
-
gap: 1.25,
|
|
310
|
-
borderRadius: "8px",
|
|
311
|
-
py: 0.75,
|
|
312
|
-
"&:hover": { backgroundColor: "#F0EEF2" },
|
|
313
|
-
"&.Mui-selected, &.Mui-selected:hover": { backgroundColor: "#F0EEF2" },
|
|
314
|
-
}}
|
|
315
|
-
>
|
|
316
|
-
<UserAvatar user={user} size={30} />
|
|
317
|
-
<Typography
|
|
318
|
-
sx={{
|
|
319
|
-
flex: 1,
|
|
320
|
-
minWidth: 0,
|
|
321
|
-
fontFamily: "Lato, sans-serif",
|
|
322
|
-
fontSize: 14,
|
|
323
|
-
fontWeight: isSelected ? 700 : 400,
|
|
324
|
-
color: isSelected ? "#503D66" : "#262626",
|
|
325
|
-
overflow: "hidden",
|
|
326
|
-
textOverflow: "ellipsis",
|
|
327
|
-
whiteSpace: "nowrap",
|
|
328
|
-
}}
|
|
329
|
-
>
|
|
330
|
-
{fullName(user)}
|
|
331
|
-
</Typography>
|
|
332
|
-
{isSelected && <CheckIcon sx={{ fontSize: 18, color: "#E33AA9" }} />}
|
|
333
|
-
</ListItemButton>
|
|
334
|
-
);
|
|
335
|
-
})}
|
|
336
|
-
|
|
337
|
-
{filtered.length === 0 && (
|
|
338
|
-
<Typography
|
|
339
|
-
sx={{ py: 2, textAlign: "center", fontFamily: "Lato, sans-serif", fontSize: 13, color: "#707070" }}
|
|
340
|
-
>
|
|
341
|
-
{users.length === 0 ? "No hay personas asignables" : "Sin coincidencias"}
|
|
342
|
-
</Typography>
|
|
343
|
-
)}
|
|
344
|
-
</List>
|
|
345
|
-
</Popover>
|
|
346
|
-
</>
|
|
347
|
-
);
|
|
348
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import ServicesWorkspace from "./index";
|
|
2
|
-
import { withDemoServices, DEMO_USERS } from "./demo";
|
|
3
|
-
|
|
4
|
-
export default {
|
|
5
|
-
title: "Components/organisms/ServicesWorkspace",
|
|
6
|
-
component: ServicesWorkspace,
|
|
7
|
-
argTypes: { onAssign: { action: "onAssign" }, onOpenEditor: { action: "onOpenEditor" } },
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const retailers = [
|
|
11
|
-
{ id_retailer: 4, retailer: "Walmart" },
|
|
12
|
-
{ id_retailer: 9, retailer: "Soriana" },
|
|
13
|
-
{ id_retailer: 12, retailer: "Alsuper" },
|
|
14
|
-
];
|
|
15
|
-
|
|
16
|
-
// Producto con la forma que deja `normalizeProduct` en la edición.
|
|
17
|
-
const baseProduct = {
|
|
18
|
-
id_article: 11080102,
|
|
19
|
-
id_order: 10478,
|
|
20
|
-
name: "Prueba variantes 2 - hijo de 1",
|
|
21
|
-
datasheet_status: "AS",
|
|
22
|
-
description_status: "RA/AS",
|
|
23
|
-
images_status: "PA",
|
|
24
|
-
id_datasheet_especialist: 9101,
|
|
25
|
-
id_datasheet_facilitator: 9103,
|
|
26
|
-
id_description_especialist: 9102,
|
|
27
|
-
id_images_especialist: 0,
|
|
28
|
-
id_auditor: 9104,
|
|
29
|
-
statusByRetailer: [
|
|
30
|
-
{ service: "datasheet", retailer_id: 4, status: "AS" },
|
|
31
|
-
{ service: "datasheet", retailer_id: 9, status: "CA" },
|
|
32
|
-
{ service: "description", retailer_id: 4, status: "RA/AS" },
|
|
33
|
-
{ service: "description", retailer_id: 12, status: "AC" },
|
|
34
|
-
{ service: "images", retailer_id: 4, status: "PA" },
|
|
35
|
-
],
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
const users = { especialist: DEMO_USERS, facilitator: DEMO_USERS, auditor: DEMO_USERS };
|
|
39
|
-
|
|
40
|
-
const Template = (args) => (
|
|
41
|
-
<div style={{ maxWidth: 1100, padding: 24, background: "#FAFAFA" }}>
|
|
42
|
-
<ServicesWorkspace {...args} />
|
|
43
|
-
</div>
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
/** Producto de hoy: solo Ficha técnica, Descripción e Imágenes. */
|
|
47
|
-
export const TresServicios = Template.bind({});
|
|
48
|
-
TresServicios.args = { product: baseProduct, retailers, users, canAssign: true };
|
|
49
|
-
|
|
50
|
-
/** Con 17 servicios (3 de siempre + 14 de ejemplo). */
|
|
51
|
-
export const DiecisieteServicios = Template.bind({});
|
|
52
|
-
DiecisieteServicios.args = {
|
|
53
|
-
product: withDemoServices(baseProduct, 14),
|
|
54
|
-
retailers,
|
|
55
|
-
users,
|
|
56
|
-
canAssign: true,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
/** Rol que solo consulta (sin asignar). */
|
|
60
|
-
export const SoloConsulta = Template.bind({});
|
|
61
|
-
SoloConsulta.args = { ...DiecisieteServicios.args, canAssign: false };
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Servicios de ejemplo para revisar el diseño mientras la base solo tiene los
|
|
3
|
-
tres servicios de siempre. Mismo catálogo que la demo de la tabla de Creators
|
|
4
|
-
(ServicesCell/demoServices.js), con el tipo de entregable de cada uno.
|
|
5
|
-
|
|
6
|
-
Llegan en `product.demo_services` (los pone Creators con ?demoServicios=1) o
|
|
7
|
-
se generan aquí con `withDemoServices` (historias de Storybook).
|
|
8
|
-
*/
|
|
9
|
-
export const DEMO_CATALOG = [
|
|
10
|
-
{ service_name: "quality", display_name: "Calidad", deliverable_type: "Reporte" },
|
|
11
|
-
{ service_name: "datasheetHeader", display_name: "Header Ficha", deliverable_type: "Texto" },
|
|
12
|
-
{ service_name: "brandstore", display_name: "Brandstore", deliverable_type: "Diseño" },
|
|
13
|
-
{ service_name: "premiumImage", display_name: "Imagen Premium", deliverable_type: "Imágenes" },
|
|
14
|
-
{ service_name: "resize", display_name: "Resize", deliverable_type: "Imágenes" },
|
|
15
|
-
{ service_name: "uploadOnly", display_name: "Solo Carga", deliverable_type: "Carga en cadena" },
|
|
16
|
-
{ service_name: "audit", display_name: "Auditoría", deliverable_type: "Reporte" },
|
|
17
|
-
{ service_name: "photo", display_name: "Foto", deliverable_type: "Imágenes" },
|
|
18
|
-
{ service_name: "edition", display_name: "Edición", deliverable_type: "Imágenes" },
|
|
19
|
-
{ service_name: "aplusPlatinum", display_name: "A+ / Platinum SKU", deliverable_type: "Diseño" },
|
|
20
|
-
{ service_name: "benefitInfographics", display_name: "Infografías Beneficios", deliverable_type: "Diseño" },
|
|
21
|
-
{ service_name: "image360", display_name: "360°", deliverable_type: "Archivos 360" },
|
|
22
|
-
{ service_name: "secodatReview", display_name: "Revisión secodat", deliverable_type: "Reporte" },
|
|
23
|
-
{ service_name: "videos", display_name: "Videos", deliverable_type: "Video" },
|
|
24
|
-
{ service_name: "translation", display_name: "Traducción", deliverable_type: "Texto" },
|
|
25
|
-
{ service_name: "followUp", display_name: "Seguimiento", deliverable_type: "Reporte" },
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
const DEMO_STATUSES = ["PA", "AS", "CA", "AC", "RA/AS", "AA", "AP", "Ex"];
|
|
29
|
-
|
|
30
|
-
export const isServicesDemoEnabled = () => {
|
|
31
|
-
try {
|
|
32
|
-
return new URLSearchParams(window.location.search).has("demoServicios");
|
|
33
|
-
} catch (error) {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/** Copia del producto con `count` servicios de ejemplo (estables por producto). */
|
|
39
|
-
export const withDemoServices = (product, count = 14) => {
|
|
40
|
-
const seed = String(product?.id_article ?? product?.article?.id_article ?? 7)
|
|
41
|
-
.split("")
|
|
42
|
-
.reduce((acc, char) => (acc * 31 + char.charCodeAt(0)) % 9973, 7);
|
|
43
|
-
const demo = Array.from({ length: Math.min(count, DEMO_CATALOG.length) }, (_, index) => {
|
|
44
|
-
const service = DEMO_CATALOG[(seed + index) % DEMO_CATALOG.length];
|
|
45
|
-
return { ...service, status: DEMO_STATUSES[(seed + index * 3) % DEMO_STATUSES.length], has_workflow: true };
|
|
46
|
-
});
|
|
47
|
-
return { ...product, demo_services: demo };
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
/** Usuarios de ejemplo para los selectores. */
|
|
51
|
-
export const DEMO_USERS = [
|
|
52
|
-
["Ana", "López"],
|
|
53
|
-
["Carlos", "Méndez"],
|
|
54
|
-
["Diana", "Ruiz"],
|
|
55
|
-
["Eduardo", "Pérez"],
|
|
56
|
-
["Fernanda", "Soto"],
|
|
57
|
-
["Gabriel", "Torres"],
|
|
58
|
-
].map(([name, lastName], index) => ({ id_user: 9100 + index, name, last_name: lastName }));
|