contentoh-components-library 21.6.50 → 21.6.52

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 (90) hide show
  1. package/.env.test +0 -1
  2. package/dist/components/atoms/IconFile/index.js +2 -85
  3. package/dist/components/atoms/IconFile/styles.js +1 -1
  4. package/dist/components/atoms/ProductImage/ProductImage.stories.js +2 -70
  5. package/dist/components/atoms/ProductImage/index.js +27 -100
  6. package/dist/components/atoms/ProductImage/styles.js +1 -3
  7. package/dist/components/molecules/EditionActiveImage/index.js +2 -4
  8. package/dist/components/molecules/GalleryElement/index.js +4 -13
  9. package/dist/components/molecules/GalleryHeader/index.js +24 -96
  10. package/dist/components/molecules/GalleryHeader/styles.js +1 -4
  11. package/dist/components/molecules/ImageSelector/index.js +0 -1
  12. package/dist/components/organisms/ImagePreviewer/index.js +0 -1
  13. package/dist/components/organisms/ProductImageModal/index.js +2 -3
  14. package/dist/components/organisms/PropagateChangesModal/index.js +6 -1
  15. package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.context.js +10 -8
  16. package/dist/components/pages/ProviderProductEdition/index.js +189 -72
  17. package/dist/components/pages/RetailerProductEdition/context/provider-product-edition.context.js +25 -338
  18. package/dist/components/pages/RetailerProductEdition/context/provider-product-edition.reducer.js +2 -12
  19. package/dist/components/pages/RetailerProductEdition/index.js +579 -631
  20. package/dist/components/pages/RetailerProductEdition/stories/ImageEditor.stories.js +0 -1
  21. package/dist/components/pages/RetailerProductEdition/stories/TextEditor.stories.js +145 -45
  22. package/dist/global-files/data.js +3 -16
  23. package/dist/index.js +90 -142
  24. package/package.json +1 -1
  25. package/src/components/atoms/IconFile/index.js +1 -28
  26. package/src/components/atoms/IconFile/styles.js +0 -8
  27. package/src/components/atoms/ProductImage/ProductImage.stories.js +0 -38
  28. package/src/components/atoms/ProductImage/index.js +20 -95
  29. package/src/components/atoms/ProductImage/styles.js +7 -92
  30. package/src/components/molecules/EditionActiveImage/index.js +2 -2
  31. package/src/components/molecules/GalleryElement/index.js +0 -9
  32. package/src/components/molecules/GalleryHeader/index.js +13 -65
  33. package/src/components/molecules/GalleryHeader/styles.js +1 -2
  34. package/src/components/molecules/ImageSelector/index.js +0 -1
  35. package/src/components/organisms/ImagePreviewer/index.js +0 -1
  36. package/src/components/organisms/ProductImageModal/index.js +0 -1
  37. package/src/components/organisms/PropagateChangesModal/index.js +10 -3
  38. package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx +2 -1
  39. package/src/components/pages/ProviderProductEdition/index.js +111 -6
  40. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.context.jsx +2 -202
  41. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.reducer.js +0 -12
  42. package/src/components/pages/RetailerProductEdition/index.js +258 -363
  43. package/src/components/pages/RetailerProductEdition/stories/ImageEditor.stories.js +0 -1
  44. package/src/components/pages/RetailerProductEdition/stories/TextEditor.stories.js +104 -51
  45. package/src/global-files/data.js +2 -17
  46. package/src/index.js +0 -4
  47. package/.claude/launch.json +0 -14
  48. package/dist/ai/prompts/attribute.prompt.js +0 -28
  49. package/dist/ai/prompts/description.prompt.js +0 -33
  50. package/dist/ai/schemas/attribute.schema.js +0 -35
  51. package/dist/ai/schemas/description.schema.js +0 -27
  52. package/dist/components/atoms/AssetPreview/AssetPreview.stories.js +0 -118
  53. package/dist/components/atoms/AssetPreview/index.js +0 -150
  54. package/dist/components/atoms/AssetPreview/styles.js +0 -28
  55. package/dist/components/molecules/GalleryAssetElement/GalleryAssetElement.stories.js +0 -147
  56. package/dist/components/molecules/GalleryAssetElement/index.js +0 -178
  57. package/dist/components/molecules/GalleryAssetElement/styles.js +0 -26
  58. package/dist/components/molecules/GalleryTrayTabs/GalleryTrayTabs.stories.js +0 -56
  59. package/dist/components/molecules/GalleryTrayTabs/index.js +0 -60
  60. package/dist/components/molecules/GalleryTrayTabs/styles.js +0 -20
  61. package/dist/components/organisms/DigitalAssetsTray/DigitalAssetsTray.stories.js +0 -171
  62. package/dist/components/organisms/DigitalAssetsTray/index.js +0 -211
  63. package/dist/components/organisms/DigitalAssetsTray/styles.js +0 -22
  64. package/dist/global-files/digital-assets/assetTypes.js +0 -480
  65. package/dist/global-files/digital-assets/assets.actions.js +0 -64
  66. package/dist/global-files/digital-assets/assets.adapter.js +0 -304
  67. package/dist/global-files/digital-assets/assets.mock.js +0 -136
  68. package/dist/global-files/digital-assets/assets.reducer.js +0 -220
  69. package/dist/global-files/digital-assets/uploadAssets.js +0 -179
  70. package/dist/global-files/digital-assets/useDigitalAssets.js +0 -522
  71. package/docs/activos-digitales.md +0 -273
  72. package/src/components/atoms/AssetPreview/AssetPreview.stories.js +0 -78
  73. package/src/components/atoms/AssetPreview/index.js +0 -119
  74. package/src/components/atoms/AssetPreview/styles.js +0 -190
  75. package/src/components/molecules/GalleryAssetElement/GalleryAssetElement.stories.js +0 -102
  76. package/src/components/molecules/GalleryAssetElement/index.js +0 -162
  77. package/src/components/molecules/GalleryAssetElement/styles.js +0 -159
  78. package/src/components/molecules/GalleryTrayTabs/GalleryTrayTabs.stories.js +0 -32
  79. package/src/components/molecules/GalleryTrayTabs/index.js +0 -41
  80. package/src/components/molecules/GalleryTrayTabs/styles.js +0 -52
  81. package/src/components/organisms/DigitalAssetsTray/DigitalAssetsTray.stories.js +0 -101
  82. package/src/components/organisms/DigitalAssetsTray/index.js +0 -189
  83. package/src/components/organisms/DigitalAssetsTray/styles.js +0 -183
  84. package/src/global-files/digital-assets/assetTypes.js +0 -419
  85. package/src/global-files/digital-assets/assets.actions.js +0 -50
  86. package/src/global-files/digital-assets/assets.adapter.js +0 -229
  87. package/src/global-files/digital-assets/assets.mock.js +0 -122
  88. package/src/global-files/digital-assets/assets.reducer.js +0 -197
  89. package/src/global-files/digital-assets/uploadAssets.js +0 -109
  90. package/src/global-files/digital-assets/useDigitalAssets.js +0 -329
@@ -1,102 +0,0 @@
1
- import { useState } from "react";
2
-
3
- import { GalleryAssetElement } from "./index";
4
- import { GalleryHeader } from "../GalleryHeader";
5
- import {
6
- fromBackendList,
7
- ASSET_STATUS,
8
- } from "../../../global-files/digital-assets/assets.adapter";
9
- import { backendAssetsMock } from "../../../global-files/digital-assets/assets.mock";
10
-
11
- const SAMPLES = {
12
- mp4: "https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4",
13
- gif: "https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif",
14
- };
15
-
16
- /* Las claves del mock apuntan a S3, que todavía no tiene nada: se sustituyen
17
- por archivos públicos para poder ver el componente. */
18
- const assets = fromBackendList(backendAssetsMock).map((asset) => ({
19
- ...asset,
20
- url:
21
- asset.ext === "mp4" ? SAMPLES.mp4 : asset.ext === "gif" ? SAMPLES.gif : "",
22
- poster: "",
23
- }));
24
-
25
- export default {
26
- title: "Components/molecules/GalleryAssetElement",
27
- component: GalleryAssetElement,
28
- };
29
-
30
- const Template = (args) => <GalleryAssetElement {...args} />;
31
-
32
- export const Fila = Template.bind({});
33
- Fila.args = { asset: assets[0], index: 0 };
34
-
35
- export const Cuadricula = Template.bind({});
36
- Cuadricula.args = { asset: assets[0], index: 0, gridLayout: true };
37
-
38
- export const Subiendo = Template.bind({});
39
- Subiendo.args = {
40
- asset: { ...assets[2], status: ASSET_STATUS.UPLOADING, progress: 42 },
41
- index: 0,
42
- };
43
-
44
- export const ConError = Template.bind({});
45
- ConError.args = {
46
- asset: {
47
- ...assets[3],
48
- status: ASSET_STATUS.ERROR,
49
- error: "No se pudo subir el archivo. Intenta de nuevo.",
50
- },
51
- index: 0,
52
- };
53
-
54
- /** La bandeja completa con su encabezado: es el uso real del componente. */
55
- export const BandejaCompleta = () => {
56
- const [selected, setSelected] = useState([]);
57
-
58
- return (
59
- <div style={{ width: 900 }}>
60
- <GalleryHeader
61
- variant="asset"
62
- checkAllId="check-all-assets"
63
- itemSelector="[id^='gallery-asset-']"
64
- setCheckAll={() => {}}
65
- setSelectedImages={setSelected}
66
- />
67
- {assets.map((asset, index) => (
68
- <GalleryAssetElement
69
- key={asset.id}
70
- asset={asset}
71
- index={index}
72
- selectedAssets={selected}
73
- setSelectedAssets={setSelected}
74
- setCheckAll={() => {}}
75
- changeAsset={({ value }) => console.log("nuevo tipo:", value)}
76
- onRemove={(item) => console.log("quitar:", item.name)}
77
- />
78
- ))}
79
- <p style={{ fontFamily: "Lato", fontSize: 12, marginTop: 12 }}>
80
- Seleccionados: {selected.length}
81
- </p>
82
- </div>
83
- );
84
- };
85
-
86
- /** Comparación de los dos encabezados, para verificar que no se movió el de imágenes. */
87
- export const EncabezadosComparados = () => (
88
- <div style={{ width: 900 }}>
89
- <GalleryHeader
90
- variant="image"
91
- setCheckAll={() => {}}
92
- setSelectedImages={() => {}}
93
- />
94
- <GalleryHeader
95
- variant="asset"
96
- checkAllId="check-all-assets-demo"
97
- itemSelector="[id^='gallery-asset-demo-']"
98
- setCheckAll={() => {}}
99
- setSelectedImages={() => {}}
100
- />
101
- </div>
102
- );
@@ -1,162 +0,0 @@
1
- import { Container } from "./styles";
2
- import { AssetPreview } from "../../atoms/AssetPreview";
3
- import { CheckBox } from "../../atoms/CheckBox";
4
- import Select from "../../atoms/Select";
5
- import {
6
- ASSET_PREVIEW,
7
- assetTypeOptions,
8
- formatBytes,
9
- resolvePreviewKind,
10
- } from "../../../global-files/digital-assets/assetTypes";
11
- import {
12
- ASSET_STATUS,
13
- assetKey,
14
- } from "../../../global-files/digital-assets/assets.adapter";
15
-
16
- /*
17
- Fila de un activo digital en la bandeja.
18
-
19
- Es un componente aparte de `GalleryElement` a propósito, no una bifurcación
20
- dentro de él. Un activo no comparte casi nada con una imagen de producto: no
21
- tiene tipo de toma, ni leyenda, ni panel de validación, ni comparación contra
22
- la versión auditable. Meterlo en el mismo archivo habría partido su render en
23
- dos mitades y puesto en riesgo la bandeja de imágenes, que ya funciona.
24
-
25
- Lo que sí comparte —rejilla, tamaños, colores— vive en los estilos, calcados
26
- de `GalleryElement` para que las dos listas se vean como una sola tabla.
27
- */
28
- export const GalleryAssetElement = ({
29
- asset = {},
30
- index = 0,
31
- gridLayout = false,
32
- id,
33
- label,
34
- selectedAssets = [],
35
- setSelectedAssets,
36
- setCheckAll,
37
- changeAsset,
38
- onRemove,
39
- readOnly = false,
40
- checkAllId = "check-all-assets",
41
- itemSelector = "[id^='gallery-asset-']",
42
- }) => {
43
- const elementId = id || `gallery-asset-${index}`;
44
- const key = assetKey(asset);
45
- const isUploading = asset.status === ASSET_STATUS.UPLOADING;
46
- const hasError = asset.status === ASSET_STATUS.ERROR;
47
-
48
- const checkOnChange = (e) => {
49
- const chkGlobal = document.getElementById(checkAllId);
50
- const checkboxList = document.querySelectorAll(itemSelector);
51
- let temp = selectedAssets.slice();
52
-
53
- // Se compara por `assetKey` y no por `id`: un activo recién soltado todavía
54
- // no tiene id del backend, y comparando por id todos los pendientes serían
55
- // "el mismo" y se quitarían juntos de la selección.
56
- temp = e.target.checked
57
- ? [...temp, asset]
58
- : temp.filter((item) => assetKey(item) !== key);
59
-
60
- let counter = 0;
61
- checkboxList?.forEach((chk) => chk.checked && counter++);
62
- if (chkGlobal) chkGlobal.checked = checkboxList.length === counter;
63
- setCheckAll?.(checkboxList.length === counter);
64
- setSelectedAssets?.(temp);
65
- };
66
-
67
- /*
68
- Abrir el activo en otra pestaña.
69
-
70
- Sirve para TODOS los tipos y por eso se prefiere a un visor propio: un video
71
- se reproduce con el reproductor del navegador, un PDF se abre, y un .psd se
72
- descarga. Sin esto, la bandeja mostraba el archivo pero no había forma de
73
- verlo — un video quedaba como un fotograma fijo sin botón de reproducir.
74
-
75
- Solo cuando ya está en S3: un activo recién soltado apunta al archivo del
76
- disco del usuario y abrirlo no le diría nada nuevo.
77
- */
78
- const abrir = () => {
79
- if (!asset.id || !asset.url) return;
80
- window.open(asset.url, "_blank", "noopener,noreferrer");
81
- };
82
-
83
- const onChangeType = (e) => {
84
- changeAsset?.({
85
- action: "changeAssetInfo",
86
- attribute: "assetType",
87
- value: e.target.value,
88
- index,
89
- });
90
- };
91
-
92
- return (
93
- <Container
94
- className={`${gridLayout ? "grid-gallery" : "row-gallery"} ${
95
- hasError ? "asset-error" : ""
96
- }`.trim()}
97
- >
98
- <div className="buttons-container">
99
- <CheckBox id={elementId} label={label} onChange={checkOnChange} />
100
- </div>
101
- <div className="asset-container">
102
- <AssetPreview
103
- asset={asset}
104
- size={`catalogue-image-${gridLayout ? "big" : "small"}-size`}
105
- /*
106
- En cuadrícula hay sitio para el reproductor; en la fila, de 60px,
107
- los controles no caben y estorban al clic.
108
- */
109
- controls={gridLayout && resolvePreviewKind(asset) === ASSET_PREVIEW.VIDEO}
110
- onClick={abrir}
111
- />
112
- <div className="information-container">
113
- <p
114
- className={asset.id ? "asset-name asset-link" : "asset-name"}
115
- title={asset.id ? `Abrir ${asset.name}` : asset.name}
116
- onClick={abrir}
117
- >
118
- {asset.name}
119
- </p>
120
- {!gridLayout && (
121
- <>
122
- <p className="asset-weight">{formatBytes(asset.sizeBytes)}</p>
123
- <p className="asset-format">{(asset.ext || "").toUpperCase()}</p>
124
- <Select
125
- width="100%"
126
- placeholder="Tipo de activo"
127
- options={assetTypeOptions()}
128
- valueSelected={asset.assetType}
129
- onChange={onChangeType}
130
- className={readOnly ? "disabled" : ""}
131
- />
132
- </>
133
- )}
134
- </div>
135
- </div>
136
-
137
- {isUploading && (
138
- <div className="asset-progress" aria-label="Subiendo activo">
139
- <div
140
- className="asset-progress-fill"
141
- style={{
142
- width: `${Math.min(100, Math.max(0, asset.progress ?? 0))}%`,
143
- }}
144
- />
145
- </div>
146
- )}
147
-
148
- {hasError && <p className="asset-error-message">{asset.error}</p>}
149
-
150
- {onRemove && !readOnly && (
151
- <button
152
- type="button"
153
- className="asset-remove"
154
- onClick={() => onRemove(asset)}
155
- title="Quitar activo"
156
- >
157
- ×
158
- </button>
159
- )}
160
- </Container>
161
- );
162
- };
@@ -1,159 +0,0 @@
1
- import styled from "styled-components";
2
- import { FontFamily, GlobalColors } from "../../../global-files/variables";
3
-
4
- /*
5
- Calcado de `GalleryElement/styles.js` para que imágenes y activos se lean como
6
- una sola tabla. Cambia solo la rejilla de la fila —cuatro columnas en vez de
7
- cinco, porque un activo no tiene leyenda— y lo propio de un archivo que se
8
- está subiendo: barra de progreso, mensaje de error y botón de quitar.
9
- */
10
- export const Container = styled.div`
11
- position: relative;
12
-
13
- &.grid-gallery {
14
- width: 179px;
15
- border-radius: 3px;
16
- overflow: hidden;
17
-
18
- .buttons-container {
19
- position: absolute;
20
- top: 5px;
21
- left: 5px;
22
- z-index: 1;
23
- display: flex;
24
- align-items: center;
25
- justify-content: space-between;
26
- }
27
-
28
- .asset-container {
29
- border: 1px solid #f0eef2;
30
-
31
- .information-container {
32
- background-color: ${GlobalColors.s2};
33
- display: flex;
34
- justify-content: space-between;
35
- padding: 0 2px;
36
-
37
- p {
38
- font-family: ${FontFamily.Lato};
39
- color: ${GlobalColors.s4};
40
- font-size: 11px;
41
- line-height: 17px;
42
- overflow: hidden;
43
- text-overflow: ellipsis;
44
- white-space: nowrap;
45
- }
46
- }
47
- }
48
- }
49
-
50
- &.row-gallery {
51
- width: 100%;
52
- display: grid;
53
- grid-template-columns: 0.05fr 1fr;
54
- align-items: center;
55
- padding-right: 10px;
56
-
57
- .buttons-container {
58
- position: relative;
59
- display: flex;
60
- align-items: center;
61
- justify-content: space-between;
62
- }
63
-
64
- .asset-container {
65
- display: grid;
66
- grid-template-columns: auto 1fr;
67
- align-items: center;
68
- flex: 1;
69
-
70
- .information-container {
71
- display: grid;
72
- grid-template-columns: repeat(4, 1fr);
73
- align-items: center;
74
-
75
- p {
76
- font-family: ${FontFamily.Lato};
77
- color: ${GlobalColors.s4};
78
- font-size: 14px;
79
- line-height: 17px;
80
- text-align: center;
81
- overflow: hidden;
82
- text-overflow: ellipsis;
83
- white-space: nowrap;
84
- }
85
-
86
- & > * {
87
- flex: 1;
88
- padding: 5px;
89
- }
90
- }
91
- }
92
- }
93
-
94
- /* El nombre es el sitio donde uno intenta hacer clic para abrir un archivo. */
95
- .asset-link {
96
- cursor: pointer;
97
- text-decoration: underline;
98
- text-underline-offset: 2px;
99
-
100
- &:hover {
101
- color: ${GlobalColors.color_purple};
102
- }
103
- }
104
-
105
- &.asset-error {
106
- border: 1px solid ${GlobalColors.secondary_magenta};
107
- border-radius: 3px;
108
- }
109
-
110
- /* Progreso de subida. Ocupa el borde inferior de la fila para no empujar el
111
- resto del contenido mientras aparece y desaparece. */
112
- .asset-progress {
113
- position: absolute;
114
- left: 0;
115
- right: 0;
116
- bottom: 0;
117
- height: 3px;
118
- background: ${GlobalColors.s3};
119
- border-radius: 2px;
120
- overflow: hidden;
121
- }
122
-
123
- .asset-progress-fill {
124
- height: 100%;
125
- background: ${GlobalColors.color_purple};
126
- transition: width 0.2s ease-out;
127
- }
128
-
129
- .asset-error-message {
130
- margin: 2px 0 0;
131
- padding: 0 8px;
132
- font-family: ${FontFamily.Lato};
133
- font-size: 11px;
134
- line-height: 15px;
135
- color: ${GlobalColors.secondary_magenta};
136
- }
137
-
138
- .asset-remove {
139
- position: absolute;
140
- top: 4px;
141
- right: 6px;
142
- width: 18px;
143
- height: 18px;
144
- display: grid;
145
- place-items: center;
146
- padding: 0;
147
- border: none;
148
- border-radius: 50%;
149
- background: ${GlobalColors.s2};
150
- color: ${GlobalColors.s5};
151
- font-size: 14px;
152
- line-height: 1;
153
- cursor: pointer;
154
-
155
- &:hover {
156
- background: ${GlobalColors.s3};
157
- }
158
- }
159
- `;
@@ -1,32 +0,0 @@
1
- import { useState } from "react";
2
- import { GalleryTrayTabs, TRAYS } from "./index";
3
-
4
- export default {
5
- title: "Components/molecules/GalleryTrayTabs",
6
- component: GalleryTrayTabs,
7
- };
8
-
9
- export const Interactivo = () => {
10
- const [tray, setTray] = useState(TRAYS.IMAGES);
11
- return (
12
- <GalleryTrayTabs
13
- activeTray={tray}
14
- setActiveTray={setTray}
15
- imagesCount={8}
16
- assetsCount={3}
17
- />
18
- );
19
- };
20
-
21
- /** Estado real hasta que exista el backend: la bandeja de activos en cero. */
22
- export const SinActivos = () => {
23
- const [tray, setTray] = useState(TRAYS.IMAGES);
24
- return (
25
- <GalleryTrayTabs
26
- activeTray={tray}
27
- setActiveTray={setTray}
28
- imagesCount={8}
29
- assetsCount={0}
30
- />
31
- );
32
- };
@@ -1,41 +0,0 @@
1
- import { Container } from "./styles";
2
-
3
- export const TRAYS = {
4
- IMAGES: "images",
5
- ASSETS: "assets",
6
- };
7
-
8
- /**
9
- * Selector entre las dos bandejas de la pestaña Imágenes.
10
- *
11
- * Los activos viven aquí y no en una pestaña propia porque es lo que pide la
12
- * tarea —"dentro de las bandejas de imágenes"— y porque así comparten
13
- * selección, descarga y permisos con las fotos en vez de duplicarlos.
14
- */
15
- export const GalleryTrayTabs = ({
16
- activeTray = TRAYS.IMAGES,
17
- setActiveTray,
18
- imagesCount = 0,
19
- assetsCount = 0,
20
- }) => {
21
- const trays = [
22
- { id: TRAYS.IMAGES, label: "Imágenes", count: imagesCount },
23
- { id: TRAYS.ASSETS, label: "Activos digitales", count: assetsCount },
24
- ];
25
-
26
- return (
27
- <Container>
28
- {trays.map((tray) => (
29
- <button
30
- key={tray.id}
31
- type="button"
32
- className={tray.id === activeTray ? "tray-tab active" : "tray-tab"}
33
- onClick={() => setActiveTray?.(tray.id)}
34
- >
35
- {tray.label}
36
- <span className="tray-count">{tray.count}</span>
37
- </button>
38
- ))}
39
- </Container>
40
- );
41
- };
@@ -1,52 +0,0 @@
1
- import styled from "styled-components";
2
- import { FontFamily, GlobalColors } from "../../../global-files/variables";
3
-
4
- export const Container = styled.div`
5
- display: flex;
6
- align-items: center;
7
- gap: 4px;
8
- padding: 8px 0 0;
9
-
10
- .tray-tab {
11
- display: flex;
12
- align-items: center;
13
- gap: 6px;
14
- padding: 6px 14px;
15
- border: none;
16
- border-bottom: 2px solid transparent;
17
- background: none;
18
- cursor: pointer;
19
- font-family: ${FontFamily.AvenirNext};
20
- font-size: 14px;
21
- line-height: 21px;
22
- letter-spacing: -0.015em;
23
- color: ${GlobalColors.s4};
24
-
25
- &:hover {
26
- color: ${GlobalColors.s5};
27
- }
28
-
29
- &.active {
30
- color: ${GlobalColors.s5};
31
- font-weight: 600;
32
- border-bottom-color: ${GlobalColors.color_purple};
33
- }
34
- }
35
-
36
- .tray-count {
37
- min-width: 20px;
38
- padding: 0 6px;
39
- border-radius: 10px;
40
- background: ${GlobalColors.s2};
41
- color: ${GlobalColors.s5};
42
- font-family: ${FontFamily.Lato};
43
- font-size: 11px;
44
- line-height: 18px;
45
- text-align: center;
46
- }
47
-
48
- .active .tray-count {
49
- background: ${GlobalColors.color_purple};
50
- color: ${GlobalColors.white};
51
- }
52
- `;
@@ -1,101 +0,0 @@
1
- import { useReducer, useState } from "react";
2
-
3
- import { DigitalAssetsTray } from "./index";
4
- import { useDigitalAssets } from "../../../global-files/digital-assets/useDigitalAssets";
5
- import {
6
- assetsInitialState,
7
- assetsReducer,
8
- countUnsavedAssets,
9
- hasUnsavedAssets,
10
- selectAssetsToSave,
11
- } from "../../../global-files/digital-assets/assets.reducer";
12
- import { buildSavePayload } from "../../../global-files/digital-assets/assets.adapter";
13
- import { backendAssetsMock } from "../../../global-files/digital-assets/assets.mock";
14
-
15
- export default {
16
- title: "Components/organisms/DigitalAssetsTray",
17
- component: DigitalAssetsTray,
18
- };
19
-
20
- /*
21
- Las historias usan EL MISMO reducer que la ficha, no un estado de juguete.
22
- Así lo que se ve aquí es el comportamiento real: qué queda marcado para
23
- guardar, qué se anota para borrar y qué payload saldría hacia el backend.
24
- */
25
- const Demo = ({ initialAssets = [], gridLayout = false, readOnly = false, showPayload = false }) => {
26
- const [state, dispatch] = useReducer(assetsReducer, assetsInitialState);
27
- const [notices, setNotices] = useState([]);
28
-
29
- const tray = useDigitalAssets({
30
- assets: state.assets_values,
31
- dispatch,
32
- notices,
33
- setNotices,
34
- });
35
-
36
- // Carga inicial simulando la respuesta del backend, una sola vez.
37
- const [loaded, setLoaded] = useState(false);
38
- if (!loaded && initialAssets.length) {
39
- tray.replaceAll(initialAssets);
40
- setLoaded(true);
41
- }
42
-
43
- const payload = buildSavePayload(selectAssetsToSave(state));
44
-
45
- return (
46
- <div style={{ width: 960 }}>
47
- <DigitalAssetsTray
48
- {...tray}
49
- unsaved={countUnsavedAssets(state)}
50
- gridLayout={gridLayout}
51
- readOnly={readOnly}
52
- selectedAssets={state.selected_assets}
53
- setSelectedAssets={(assets) => dispatch({ type: "SET_SELECTED_ASSETS", payload: assets })}
54
- setCheckAll={(checked) => dispatch({ type: "TOGGLE_CHECK_ALL_ASSETS", payload: checked })}
55
- />
56
-
57
- <p style={{ fontFamily: "Lato", fontSize: 12 }}>
58
- Seleccionados: {state.selected_assets.length} · Sin subir: {tray.pending.length} ·
59
- Marcados para actualizar: {state.updated_assets.length} · Para borrar:{" "}
60
- {state.deleted_assets.length} · ¿Hay cambios sin guardar?{" "}
61
- {hasUnsavedAssets(state) ? "sí" : "no"}
62
- </p>
63
-
64
- {showPayload && (
65
- <pre
66
- style={{
67
- fontSize: 11,
68
- background: "#f7f7fc",
69
- padding: 12,
70
- borderRadius: 6,
71
- maxHeight: 280,
72
- overflow: "auto",
73
- }}
74
- >
75
- {JSON.stringify(payload, null, 2)}
76
- </pre>
77
- )}
78
- </div>
79
- );
80
- };
81
-
82
- /**
83
- * Estado real de hoy: sin backend, la bandeja arranca vacía. Arrastrar un mp4,
84
- * un gif, un PDF, un xlsx o un psd lo valida y lo agrega; cualquier otra cosa se
85
- * rechaza con su motivo. Nada se sube.
86
- */
87
- export const Vacia = () => <Demo />;
88
-
89
- export const ConActivos = () => <Demo initialAssets={backendAssetsMock} />;
90
-
91
- export const Cuadricula = () => <Demo initialAssets={backendAssetsMock} gridLayout />;
92
-
93
- export const SoloLectura = () => <Demo initialAssets={backendAssetsMock} readOnly />;
94
-
95
- /**
96
- * Lo que se le enviaría al backend, actualizándose en vivo. Cambia el tipo de un
97
- * activo y aparece en `updateAssets`; bórralo y su id pasa a `deleteAssets`;
98
- * suelta un archivo nuevo y aparece en `newAssets` sin `key`, porque todavía no
99
- * se ha subido a S3.
100
- */
101
- export const PayloadDeGuardado = () => <Demo initialAssets={backendAssetsMock} showPayload />;