contentoh-components-library 21.6.57 → 21.6.59
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/components/pages/CreatorsProductEdition/CreatorsProductEditionView.js +90 -135
- package/dist/components/pages/CreatorsProductEdition/hooks/useCreatorsProductEdition.js +148 -162
- package/dist/components/pages/CreatorsProductEdition/mocks/api.fixtures.js +16 -0
- package/dist/components/pages/CreatorsProductEdition/mocks/mockApi.js +1 -0
- package/dist/components/pages/CreatorsProductEdition/sections/ImageGallery.js +433 -0
- package/dist/components/pages/CreatorsProductEdition/sections/NoticeDialog.js +155 -0
- package/dist/components/pages/CreatorsProductEdition/sections/RejectDialog.js +201 -0
- package/dist/components/pages/CreatorsProductEdition/sections/VersionDrawer.js +615 -0
- package/dist/components/pages/CreatorsProductEdition/stories/CreatorsProductEdition.stories.js +3 -31
- package/dist/components/pages/CreatorsProductEdition/stories/CreatorsProductEditionAPI.stories.js +55 -30
- package/dist/components/pages/CreatorsProductEdition/stories/products.js +923 -0
- package/dist/components/pages/CreatorsProductEdition/styles.js +27 -7
- package/dist/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +2 -1
- package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.context.js +325 -10
- package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.reducer.js +12 -2
- package/dist/components/pages/ProviderProductEdition/index.js +486 -231
- package/dist/index.js +13 -0
- package/package.json +1 -1
- package/src/components/pages/CreatorsProductEdition/CreatorsProductEditionView.jsx +777 -0
- package/src/components/pages/CreatorsProductEdition/constants.js +21 -0
- package/src/components/pages/CreatorsProductEdition/hooks/useCreatorsProductEdition.js +2238 -0
- package/src/components/pages/CreatorsProductEdition/index.js +19 -0
- package/src/components/pages/CreatorsProductEdition/mocks/api.fixtures.js +357 -0
- package/src/components/pages/CreatorsProductEdition/mocks/mockApi.js +144 -0
- package/src/components/pages/CreatorsProductEdition/sections/CommentBox.jsx +183 -0
- package/src/components/pages/CreatorsProductEdition/sections/ImageGallery.jsx +269 -0
- package/src/components/pages/CreatorsProductEdition/sections/ImagePanel.jsx +332 -0
- package/src/components/pages/CreatorsProductEdition/sections/ImagesSection.jsx +385 -0
- package/src/components/pages/CreatorsProductEdition/sections/NoticeDialog.jsx +111 -0
- package/src/components/pages/CreatorsProductEdition/sections/ProductHeader.jsx +305 -0
- package/src/components/pages/CreatorsProductEdition/sections/ProductMedia.jsx +101 -0
- package/src/components/pages/CreatorsProductEdition/sections/RejectDialog.jsx +125 -0
- package/src/components/pages/CreatorsProductEdition/sections/RetailerMenu.jsx +129 -0
- package/src/components/pages/CreatorsProductEdition/sections/ServiceActions.jsx +382 -0
- package/src/components/pages/CreatorsProductEdition/sections/StatusChip.jsx +37 -0
- package/src/components/pages/CreatorsProductEdition/sections/TabsBar.jsx +187 -0
- package/src/components/pages/CreatorsProductEdition/sections/VariantsPanel.jsx +311 -0
- package/src/components/pages/CreatorsProductEdition/sections/VersionDrawer.jsx +357 -0
- package/src/components/pages/CreatorsProductEdition/sections/tokens.js +63 -0
- package/src/components/pages/CreatorsProductEdition/stories/CreatorsProductEdition.stories.js +111 -0
- package/src/components/pages/CreatorsProductEdition/stories/CreatorsProductEditionAPI.stories.js +85 -0
- package/src/components/pages/CreatorsProductEdition/stories/products.js +966 -0
- package/src/components/pages/CreatorsProductEdition/styles.js +178 -0
- package/src/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +1 -0
- package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx +201 -0
- package/src/components/pages/ProviderProductEdition/context/provider-product-edition.reducer.js +12 -0
- package/src/components/pages/ProviderProductEdition/index.js +228 -7
- package/src/index.js +1 -0
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { Box, Checkbox, Chip, Link, Stack, Tab, Tabs, Typography } from "@mui/material";
|
|
2
|
+
|
|
3
|
+
import { GalleryElement } from "../../../molecules/GalleryElement";
|
|
4
|
+
import { TRAYS } from "../../../molecules/GalleryTrayTabs";
|
|
5
|
+
import { DigitalAssetsTray } from "../../../organisms/DigitalAssetsTray";
|
|
6
|
+
|
|
7
|
+
import { COLORS, FONTS } from "./tokens";
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
Pestaña Imágenes: bandejas (imágenes / activos digitales), cabecera de la
|
|
11
|
+
lista con "seleccionar todo", la galería con su zona para soltar archivos, y
|
|
12
|
+
el estado vacío.
|
|
13
|
+
|
|
14
|
+
Reemplaza a GalleryTrayTabs, GalleryHeader y el marcado de la galería de la
|
|
15
|
+
vista original. Se reutilizan tal cual las tarjetas (`GalleryElement`, con sus
|
|
16
|
+
selects de tipo y empaque) y la bandeja de activos (`DigitalAssetsTray`): son
|
|
17
|
+
componentes grandes con lógica propia y rehacerlos sería reinventarlos.
|
|
18
|
+
|
|
19
|
+
Dos cosas que las tarjetas exigen y que por eso se conservan:
|
|
20
|
+
- Una casilla global con id `check-all-images`. Cada tarjeta la busca por
|
|
21
|
+
id al marcarse; si no existe, marcar una imagen lanza un error.
|
|
22
|
+
- "Seleccionar todo" marca las casillas de las tarjetas directamente en el
|
|
23
|
+
DOM (`[id^='gallery-element-']`), igual que GalleryHeader.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
// Columnas de la lista, calcadas de GalleryHeader para que queden alineadas con
|
|
27
|
+
// las filas de GalleryElement.
|
|
28
|
+
const LIST_COLUMNS = [
|
|
29
|
+
{ label: "Imagen", pl: 0 },
|
|
30
|
+
{ label: "Nombre", pl: "1.75rem" },
|
|
31
|
+
{ label: "Tamaño", pl: "2.75rem" },
|
|
32
|
+
{ label: "Formato", pl: "4.5rem" },
|
|
33
|
+
{ label: "¿Tiene leyenda?", ml: "-1rem" },
|
|
34
|
+
{ label: "Tipo de toma" },
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
// La lista es una tabla de columnas fijas: por debajo de este ancho se desplaza
|
|
38
|
+
// de lado dentro de su caja en vez de aplastar las columnas.
|
|
39
|
+
const LIST_MIN_WIDTH = 760;
|
|
40
|
+
|
|
41
|
+
const TrayTabs = ({ activeTray, setActiveTray, imagesCount, assetsCount }) => {
|
|
42
|
+
const trays = [
|
|
43
|
+
{ id: TRAYS.IMAGES, label: "Imágenes", count: imagesCount },
|
|
44
|
+
{ id: TRAYS.ASSETS, label: "Activos digitales", count: assetsCount },
|
|
45
|
+
];
|
|
46
|
+
return (
|
|
47
|
+
<Tabs
|
|
48
|
+
value={activeTray}
|
|
49
|
+
onChange={(_, tray) => setActiveTray?.(tray)}
|
|
50
|
+
variant="scrollable"
|
|
51
|
+
scrollButtons={false}
|
|
52
|
+
TabIndicatorProps={{ sx: { bgcolor: COLORS.color_purple, height: 2 } }}
|
|
53
|
+
sx={{ minHeight: 36, pt: 1 }}
|
|
54
|
+
>
|
|
55
|
+
{trays.map((tray) => {
|
|
56
|
+
const active = tray.id === activeTray;
|
|
57
|
+
return (
|
|
58
|
+
<Tab
|
|
59
|
+
key={tray.id}
|
|
60
|
+
value={tray.id}
|
|
61
|
+
disableRipple
|
|
62
|
+
label={
|
|
63
|
+
<Stack direction="row" alignItems="center" gap="6px">
|
|
64
|
+
{tray.label}
|
|
65
|
+
<Chip
|
|
66
|
+
label={tray.count}
|
|
67
|
+
size="small"
|
|
68
|
+
sx={{
|
|
69
|
+
height: 18,
|
|
70
|
+
minWidth: 20,
|
|
71
|
+
fontFamily: FONTS.Lato,
|
|
72
|
+
fontSize: 11,
|
|
73
|
+
bgcolor: active ? COLORS.color_purple : COLORS.s2,
|
|
74
|
+
color: active ? COLORS.white : COLORS.s5,
|
|
75
|
+
"& .MuiChip-label": { px: "6px" },
|
|
76
|
+
}}
|
|
77
|
+
/>
|
|
78
|
+
</Stack>
|
|
79
|
+
}
|
|
80
|
+
sx={{
|
|
81
|
+
minHeight: 36,
|
|
82
|
+
px: "14px",
|
|
83
|
+
py: "6px",
|
|
84
|
+
textTransform: "none",
|
|
85
|
+
fontFamily: FONTS.AvenirNext,
|
|
86
|
+
fontSize: 14,
|
|
87
|
+
letterSpacing: "-0.015em",
|
|
88
|
+
color: COLORS.s4,
|
|
89
|
+
"&.Mui-selected": { color: COLORS.s5, fontWeight: 600 },
|
|
90
|
+
}}
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
})}
|
|
94
|
+
</Tabs>
|
|
95
|
+
);
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/*
|
|
99
|
+
La casilla global se deriva de la selección real y no de
|
|
100
|
+
`state.all_image_checked`: el reducer nunca pone ese valor en true
|
|
101
|
+
(TOGGLE_CHECK_ALL_IMAGES solo llena `selected_images`). En la vista original no
|
|
102
|
+
se nota porque su casilla no está controlada por React y guarda su estado en
|
|
103
|
+
el DOM; controlada con ese valor, se quedaría siempre desmarcada.
|
|
104
|
+
*/
|
|
105
|
+
const ListHeader = ({ selectedCount, totalCount, setCheckAll, setSelectedImages }) => {
|
|
106
|
+
const allSelected = totalCount > 0 && selectedCount >= totalCount;
|
|
107
|
+
const someSelected = selectedCount > 0 && !allSelected;
|
|
108
|
+
|
|
109
|
+
const toggleAll = (e) => {
|
|
110
|
+
const checked = e.target.checked;
|
|
111
|
+
document
|
|
112
|
+
.querySelectorAll("[id^='gallery-element-']")
|
|
113
|
+
.forEach((chk) => (chk.checked = checked));
|
|
114
|
+
setCheckAll(checked);
|
|
115
|
+
if (!checked) setSelectedImages([]);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<Box sx={{ display: "flex", alignItems: "center", width: "100%", py: "10px" }}>
|
|
120
|
+
<Box sx={{ width: "5.25%", minWidth: 36 }}>
|
|
121
|
+
<Checkbox
|
|
122
|
+
size="small"
|
|
123
|
+
checked={allSelected}
|
|
124
|
+
indeterminate={someSelected}
|
|
125
|
+
onChange={toggleAll}
|
|
126
|
+
inputProps={{ id: "check-all-images", "aria-label": "Seleccionar todas las imágenes" }}
|
|
127
|
+
sx={{
|
|
128
|
+
p: "4px",
|
|
129
|
+
color: COLORS.s3,
|
|
130
|
+
"&.Mui-checked, &.MuiCheckbox-indeterminate": { color: COLORS.magenta_s2 },
|
|
131
|
+
}}
|
|
132
|
+
/>
|
|
133
|
+
</Box>
|
|
134
|
+
<Box
|
|
135
|
+
sx={{
|
|
136
|
+
width: "90%",
|
|
137
|
+
display: "grid",
|
|
138
|
+
gridTemplateColumns: "0.1fr 1fr 1fr 1fr 1fr 1fr",
|
|
139
|
+
}}
|
|
140
|
+
>
|
|
141
|
+
{LIST_COLUMNS.map((column) => (
|
|
142
|
+
<Typography
|
|
143
|
+
key={column.label}
|
|
144
|
+
sx={{
|
|
145
|
+
pl: column.pl,
|
|
146
|
+
ml: column.ml,
|
|
147
|
+
textAlign: "center",
|
|
148
|
+
fontFamily: FONTS.AvenirNext,
|
|
149
|
+
fontWeight: 600,
|
|
150
|
+
fontSize: 14,
|
|
151
|
+
lineHeight: "21px",
|
|
152
|
+
letterSpacing: "-0.015em",
|
|
153
|
+
color: COLORS.s5,
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
{column.label}
|
|
157
|
+
</Typography>
|
|
158
|
+
))}
|
|
159
|
+
</Box>
|
|
160
|
+
</Box>
|
|
161
|
+
);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const ImagesSection = ({
|
|
165
|
+
imagesValues,
|
|
166
|
+
selectedImages,
|
|
167
|
+
imageLayout,
|
|
168
|
+
// bandejas
|
|
169
|
+
enableDigitalAssets,
|
|
170
|
+
currentTray,
|
|
171
|
+
setActiveTray,
|
|
172
|
+
digitalAssets,
|
|
173
|
+
unsavedAssets,
|
|
174
|
+
selectedAssets,
|
|
175
|
+
setSelectedAssets,
|
|
176
|
+
setAllAssetsChecked,
|
|
177
|
+
// permisos
|
|
178
|
+
canEdit,
|
|
179
|
+
// imágenes
|
|
180
|
+
setCheckAll,
|
|
181
|
+
setSelectedImages,
|
|
182
|
+
onChangeCurrentImage,
|
|
183
|
+
onUpdateImage,
|
|
184
|
+
onSelectImage,
|
|
185
|
+
// zona para soltar archivos (react-dropzone, desde el hook)
|
|
186
|
+
getRootProps,
|
|
187
|
+
getInputProps,
|
|
188
|
+
isDragActive,
|
|
189
|
+
openFilePicker,
|
|
190
|
+
}) => {
|
|
191
|
+
const images = imagesValues?.values ?? [];
|
|
192
|
+
|
|
193
|
+
const imageInputs = imagesValues?.inputs?.map((e) => ({
|
|
194
|
+
value: e?.id,
|
|
195
|
+
name: e?.name,
|
|
196
|
+
required: e?.required,
|
|
197
|
+
active: images.some((value) => value?.image_id === e?.id),
|
|
198
|
+
}));
|
|
199
|
+
const imageType = imagesValues?.imageType?.map((e) => ({ value: e?.id, name: e?.name }));
|
|
200
|
+
const imagePackagingType = imagesValues?.imagePackagingType?.map((e) => ({
|
|
201
|
+
value: e?.id,
|
|
202
|
+
name: e?.name,
|
|
203
|
+
}));
|
|
204
|
+
|
|
205
|
+
const cards = images.map((image, index) => (
|
|
206
|
+
<GalleryElement
|
|
207
|
+
id={"gallery-element-" + index}
|
|
208
|
+
index={index + "-" + image.name}
|
|
209
|
+
key={index}
|
|
210
|
+
image={image}
|
|
211
|
+
number={index}
|
|
212
|
+
gridLayout={imageLayout}
|
|
213
|
+
imageType={imageType}
|
|
214
|
+
imagePackagingType={imagePackagingType}
|
|
215
|
+
imageInputs={imageInputs}
|
|
216
|
+
selectedImages={selectedImages}
|
|
217
|
+
setCheckAll={setCheckAll}
|
|
218
|
+
changeImage={onUpdateImage}
|
|
219
|
+
setSelectedImages={onSelectImage}
|
|
220
|
+
updateApprovedInputsImages={(item) => console.log("updateApprovedInputsImages", item)}
|
|
221
|
+
onSelect={() => onChangeCurrentImage(index)}
|
|
222
|
+
/>
|
|
223
|
+
));
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<Box sx={{ minWidth: 0 }}>
|
|
227
|
+
{enableDigitalAssets && (
|
|
228
|
+
<TrayTabs
|
|
229
|
+
activeTray={currentTray}
|
|
230
|
+
setActiveTray={setActiveTray}
|
|
231
|
+
imagesCount={images.length}
|
|
232
|
+
assetsCount={digitalAssets?.assets?.length ?? 0}
|
|
233
|
+
/>
|
|
234
|
+
)}
|
|
235
|
+
|
|
236
|
+
{currentTray === TRAYS.ASSETS && (
|
|
237
|
+
<Box sx={{ position: "relative", minWidth: 0 }}>
|
|
238
|
+
<DigitalAssetsTray
|
|
239
|
+
{...digitalAssets}
|
|
240
|
+
unsaved={unsavedAssets}
|
|
241
|
+
gridLayout={imageLayout}
|
|
242
|
+
readOnly={!canEdit}
|
|
243
|
+
selectedAssets={selectedAssets}
|
|
244
|
+
setSelectedAssets={setSelectedAssets}
|
|
245
|
+
setCheckAll={setAllAssetsChecked}
|
|
246
|
+
/>
|
|
247
|
+
</Box>
|
|
248
|
+
)}
|
|
249
|
+
|
|
250
|
+
{currentTray === TRAYS.IMAGES && (
|
|
251
|
+
<Box sx={{ overflowX: imageLayout ? "visible" : "auto", WebkitOverflowScrolling: "touch" }}>
|
|
252
|
+
<Box sx={{ minWidth: imageLayout || images.length === 0 ? 0 : LIST_MIN_WIDTH }}>
|
|
253
|
+
{!imageLayout && images.length > 0 ? (
|
|
254
|
+
<ListHeader
|
|
255
|
+
selectedCount={selectedImages?.length ?? 0}
|
|
256
|
+
totalCount={images.length}
|
|
257
|
+
setCheckAll={setCheckAll}
|
|
258
|
+
setSelectedImages={setSelectedImages}
|
|
259
|
+
/>
|
|
260
|
+
) : (
|
|
261
|
+
/* Sin cabecera (cuadrícula o sin imágenes) las tarjetas siguen
|
|
262
|
+
buscando `#check-all-images` al marcarse. En la vista original,
|
|
263
|
+
en cuadrícula no existe: marcar una imagen lanza un TypeError y
|
|
264
|
+
la selección no se guarda. Esta casilla oculta lo evita. */
|
|
265
|
+
<input type="checkbox" id="check-all-images" hidden readOnly aria-hidden="true" />
|
|
266
|
+
)}
|
|
267
|
+
|
|
268
|
+
<Box sx={{ position: "relative" }}>
|
|
269
|
+
<Box
|
|
270
|
+
{...getRootProps()}
|
|
271
|
+
sx={{
|
|
272
|
+
position: "relative",
|
|
273
|
+
minHeight: { xs: 160, md: 240 },
|
|
274
|
+
borderRadius: "8px",
|
|
275
|
+
border: "2px dashed transparent",
|
|
276
|
+
transition: "all 0.3s ease",
|
|
277
|
+
...(isDragActive && {
|
|
278
|
+
bgcolor: `rgba(${COLORS.rgb_color_pink}, 0.05)`,
|
|
279
|
+
borderColor: COLORS.color_pink,
|
|
280
|
+
}),
|
|
281
|
+
}}
|
|
282
|
+
>
|
|
283
|
+
<input {...getInputProps()} />
|
|
284
|
+
{isDragActive && (
|
|
285
|
+
<Box
|
|
286
|
+
sx={{
|
|
287
|
+
position: "absolute",
|
|
288
|
+
inset: 0,
|
|
289
|
+
zIndex: 10,
|
|
290
|
+
display: "flex",
|
|
291
|
+
alignItems: "center",
|
|
292
|
+
justifyContent: "center",
|
|
293
|
+
bgcolor: `rgba(${COLORS.rgb_color_pink}, 0.1)`,
|
|
294
|
+
borderRadius: "8px",
|
|
295
|
+
pointerEvents: "none",
|
|
296
|
+
}}
|
|
297
|
+
>
|
|
298
|
+
<Typography
|
|
299
|
+
sx={{
|
|
300
|
+
fontFamily: FONTS.AvenirNext,
|
|
301
|
+
fontSize: { xs: 18, sm: 24 },
|
|
302
|
+
fontWeight: 600,
|
|
303
|
+
color: COLORS.color_pink,
|
|
304
|
+
textAlign: "center",
|
|
305
|
+
p: 2.5,
|
|
306
|
+
bgcolor: COLORS.white,
|
|
307
|
+
borderRadius: "8px",
|
|
308
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
309
|
+
}}
|
|
310
|
+
>
|
|
311
|
+
Suelta las imágenes aquí
|
|
312
|
+
</Typography>
|
|
313
|
+
</Box>
|
|
314
|
+
)}
|
|
315
|
+
|
|
316
|
+
<Box
|
|
317
|
+
component="aside"
|
|
318
|
+
sx={
|
|
319
|
+
imageLayout
|
|
320
|
+
? {
|
|
321
|
+
display: "grid",
|
|
322
|
+
gridTemplateColumns: {
|
|
323
|
+
xs: "repeat(2, minmax(0, 1fr))",
|
|
324
|
+
sm: "repeat(auto-fill, 179px)",
|
|
325
|
+
},
|
|
326
|
+
justifyContent: "center",
|
|
327
|
+
gap: { xs: 1, sm: "15px" },
|
|
328
|
+
p: { xs: "12px 0", sm: "20px" },
|
|
329
|
+
opacity: isDragActive ? 0.3 : 1,
|
|
330
|
+
pointerEvents: isDragActive ? "none" : "auto",
|
|
331
|
+
// En celular dos tarjetas por fila: las de 179px fijos
|
|
332
|
+
// se estiran a su columna.
|
|
333
|
+
"@media (max-width: 599.95px)": {
|
|
334
|
+
// !important: el estilo propio de la tarjeta (dos
|
|
335
|
+
// clases) le gana a este selector.
|
|
336
|
+
"& > *": { width: "100% !important" },
|
|
337
|
+
"& img, & video": {
|
|
338
|
+
width: "100% !important",
|
|
339
|
+
height: "auto !important",
|
|
340
|
+
aspectRatio: "1 / 1",
|
|
341
|
+
},
|
|
342
|
+
},
|
|
343
|
+
}
|
|
344
|
+
: { opacity: isDragActive ? 0.3 : 1 }
|
|
345
|
+
}
|
|
346
|
+
>
|
|
347
|
+
{cards}
|
|
348
|
+
</Box>
|
|
349
|
+
|
|
350
|
+
{images.length === 0 && (
|
|
351
|
+
<Box
|
|
352
|
+
sx={{
|
|
353
|
+
position: { xs: "static", md: "absolute" },
|
|
354
|
+
top: "50%",
|
|
355
|
+
left: "50%",
|
|
356
|
+
transform: { md: "translate(-50%, -50%)" },
|
|
357
|
+
width: { xs: "100%", md: "80%" },
|
|
358
|
+
maxWidth: 500,
|
|
359
|
+
mx: "auto",
|
|
360
|
+
p: { xs: "24px 8px", md: "40px" },
|
|
361
|
+
textAlign: "center",
|
|
362
|
+
boxSizing: "border-box",
|
|
363
|
+
}}
|
|
364
|
+
>
|
|
365
|
+
<Typography sx={{ fontSize: 18, color: "#666", mb: 2 }}>
|
|
366
|
+
Este producto no tiene imágenes
|
|
367
|
+
</Typography>
|
|
368
|
+
{canEdit && (
|
|
369
|
+
<Typography sx={{ fontSize: 14, color: "#999", mb: 2.5 }}>
|
|
370
|
+
Arrastra las imágenes aquí o{" "}
|
|
371
|
+
<Link component="button" type="button" onClick={openFilePicker}>
|
|
372
|
+
haz clic para abrir el explorador de archivos
|
|
373
|
+
</Link>
|
|
374
|
+
</Typography>
|
|
375
|
+
)}
|
|
376
|
+
</Box>
|
|
377
|
+
)}
|
|
378
|
+
</Box>
|
|
379
|
+
</Box>
|
|
380
|
+
</Box>
|
|
381
|
+
</Box>
|
|
382
|
+
)}
|
|
383
|
+
</Box>
|
|
384
|
+
);
|
|
385
|
+
};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Box, Button, Dialog, IconButton, Stack, Typography } from "@mui/material";
|
|
2
|
+
import CloseIcon from "@mui/icons-material/Close";
|
|
3
|
+
|
|
4
|
+
import { COLORS, FONTS } from "./tokens";
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
Aviso de la edición de producto (guardado, error, confirmaciones).
|
|
8
|
+
|
|
9
|
+
Reemplaza a `atoms/GenericModal` + ScreenHeader con el mismo `state.modal`
|
|
10
|
+
(`image`, `title`, `message`, `buttons`) y el mismo diseño oscuro, hecho con
|
|
11
|
+
el Dialog de MUI: en celular no se sale de la pantalla (el original medía
|
|
12
|
+
500px fijos) y se cierra con Escape o tocando fuera.
|
|
13
|
+
|
|
14
|
+
Los botones llegan con los `buttonType` de GeneralButton; se traducen a los
|
|
15
|
+
dos estilos que usa la pantalla: contorno blanco o relleno magenta.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const pill = {
|
|
19
|
+
minWidth: 140,
|
|
20
|
+
height: 40,
|
|
21
|
+
borderRadius: "20px",
|
|
22
|
+
textTransform: "none",
|
|
23
|
+
fontFamily: FONTS.Raleway_500,
|
|
24
|
+
fontSize: 14,
|
|
25
|
+
boxShadow: "none",
|
|
26
|
+
"&:hover": { boxShadow: "none" },
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const buttonSx = (buttonType = "") =>
|
|
30
|
+
buttonType.includes("white")
|
|
31
|
+
? {
|
|
32
|
+
...pill,
|
|
33
|
+
color: COLORS.s2,
|
|
34
|
+
border: `1px solid ${COLORS.white}`,
|
|
35
|
+
"&:hover": { ...pill["&:hover"], bgcolor: "rgba(255,255,255,0.08)" },
|
|
36
|
+
}
|
|
37
|
+
: {
|
|
38
|
+
...pill,
|
|
39
|
+
color: COLORS.white,
|
|
40
|
+
bgcolor: COLORS.magenta_s2,
|
|
41
|
+
"&:hover": { ...pill["&:hover"], bgcolor: COLORS.secondary_magenta },
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const NoticeDialog = ({ modal = {}, onClose }) => {
|
|
45
|
+
const { show, image, title, message, buttons } = modal;
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<Dialog
|
|
49
|
+
open={Boolean(show)}
|
|
50
|
+
onClose={onClose}
|
|
51
|
+
fullWidth
|
|
52
|
+
maxWidth={false}
|
|
53
|
+
PaperProps={{
|
|
54
|
+
sx: {
|
|
55
|
+
width: "min(500px, calc(100% - 32px))",
|
|
56
|
+
m: 2,
|
|
57
|
+
bgcolor: COLORS.deep_gray,
|
|
58
|
+
borderRadius: "15px",
|
|
59
|
+
p: { xs: "40px 20px 30px", sm: "40px" },
|
|
60
|
+
textAlign: "center",
|
|
61
|
+
color: COLORS.white,
|
|
62
|
+
},
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
<IconButton
|
|
66
|
+
aria-label="Cerrar"
|
|
67
|
+
onClick={onClose}
|
|
68
|
+
size="small"
|
|
69
|
+
sx={{ position: "absolute", top: 12, right: 12, color: COLORS.white }}
|
|
70
|
+
>
|
|
71
|
+
<CloseIcon fontSize="small" />
|
|
72
|
+
</IconButton>
|
|
73
|
+
|
|
74
|
+
<Stack alignItems="center" gap={2.5}>
|
|
75
|
+
{image && <Box component="img" src={image} alt="" sx={{ maxWidth: 64, maxHeight: 64 }} />}
|
|
76
|
+
{title && (
|
|
77
|
+
<Typography sx={{ fontFamily: FONTS.Raleway_600, fontSize: 18, lineHeight: 1.3 }}>
|
|
78
|
+
{title}
|
|
79
|
+
</Typography>
|
|
80
|
+
)}
|
|
81
|
+
{message && (
|
|
82
|
+
<Typography
|
|
83
|
+
sx={{
|
|
84
|
+
fontFamily: FONTS.Raleway,
|
|
85
|
+
fontSize: 16,
|
|
86
|
+
lineHeight: 1.4,
|
|
87
|
+
whiteSpace: "pre-wrap",
|
|
88
|
+
overflowWrap: "anywhere",
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
{message}
|
|
92
|
+
</Typography>
|
|
93
|
+
)}
|
|
94
|
+
{buttons?.length > 0 && (
|
|
95
|
+
<Stack
|
|
96
|
+
direction={{ xs: "column", sm: "row" }}
|
|
97
|
+
justifyContent="center"
|
|
98
|
+
gap={2}
|
|
99
|
+
sx={{ mt: 1, width: { xs: "100%", sm: "auto" } }}
|
|
100
|
+
>
|
|
101
|
+
{buttons.map((button, index) => (
|
|
102
|
+
<Button key={index} onClick={button.action} sx={buttonSx(button.buttonType)}>
|
|
103
|
+
{button.text}
|
|
104
|
+
</Button>
|
|
105
|
+
))}
|
|
106
|
+
</Stack>
|
|
107
|
+
)}
|
|
108
|
+
</Stack>
|
|
109
|
+
</Dialog>
|
|
110
|
+
);
|
|
111
|
+
};
|