contentoh-components-library 21.6.56 → 21.6.57

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 (43) hide show
  1. package/dist/components/atoms/AsignationOption/index.js +1 -0
  2. package/dist/components/atoms/AsignationOption/styles.js +1 -1
  3. package/dist/components/molecules/GalleryAssetElement/styles.js +1 -1
  4. package/dist/components/molecules/RetailerSelector/RetailerSelector.stories.js +23 -2
  5. package/dist/components/molecules/RetailerSelector/index.js +7 -2
  6. package/dist/components/molecules/RetailerSelectorv2/index.js +6 -2
  7. package/dist/components/organisms/DigitalAssetsTray/DigitalAssetsTray.stories.js +73 -9
  8. package/dist/components/organisms/DigitalAssetsTray/index.js +13 -5
  9. package/dist/components/pages/CreatorsProductEdition/CreatorsProductEditionView.js +905 -0
  10. package/dist/components/pages/CreatorsProductEdition/constants.js +19 -0
  11. package/dist/components/pages/CreatorsProductEdition/hooks/useCreatorsProductEdition.js +2967 -0
  12. package/dist/components/pages/CreatorsProductEdition/index.js +33 -0
  13. package/dist/components/pages/CreatorsProductEdition/mocks/api.fixtures.js +537 -0
  14. package/dist/components/pages/CreatorsProductEdition/mocks/mockApi.js +251 -0
  15. package/dist/components/pages/CreatorsProductEdition/sections/CommentBox.js +311 -0
  16. package/dist/components/pages/CreatorsProductEdition/sections/ImagePanel.js +421 -0
  17. package/dist/components/pages/CreatorsProductEdition/sections/ImagesSection.js +473 -0
  18. package/dist/components/pages/CreatorsProductEdition/sections/ProductHeader.js +379 -0
  19. package/dist/components/pages/CreatorsProductEdition/sections/ProductMedia.js +138 -0
  20. package/dist/components/pages/CreatorsProductEdition/sections/RetailerMenu.js +162 -0
  21. package/dist/components/pages/CreatorsProductEdition/sections/ServiceActions.js +542 -0
  22. package/dist/components/pages/CreatorsProductEdition/sections/StatusChip.js +50 -0
  23. package/dist/components/pages/CreatorsProductEdition/sections/TabsBar.js +247 -0
  24. package/dist/components/pages/CreatorsProductEdition/sections/VariantsPanel.js +389 -0
  25. package/dist/components/pages/CreatorsProductEdition/sections/tokens.js +90 -0
  26. package/dist/components/pages/CreatorsProductEdition/stories/CreatorsProductEdition.stories.js +168 -0
  27. package/dist/components/pages/CreatorsProductEdition/stories/CreatorsProductEditionAPI.stories.js +74 -0
  28. package/dist/components/pages/CreatorsProductEdition/styles.js +46 -0
  29. package/dist/global-files/digital-assets/assetTypes.js +49 -12
  30. package/dist/global-files/digital-assets/uploadAssets.js +39 -16
  31. package/dist/global-files/digital-assets/useDigitalAssets.js +38 -25
  32. package/package.json +1 -1
  33. package/src/components/atoms/AsignationOption/index.js +1 -1
  34. package/src/components/atoms/AsignationOption/styles.js +9 -0
  35. package/src/components/molecules/GalleryAssetElement/styles.js +5 -1
  36. package/src/components/molecules/RetailerSelector/RetailerSelector.stories.js +15 -1
  37. package/src/components/molecules/RetailerSelector/index.js +8 -1
  38. package/src/components/molecules/RetailerSelectorv2/index.js +7 -1
  39. package/src/components/organisms/DigitalAssetsTray/DigitalAssetsTray.stories.js +67 -4
  40. package/src/components/organisms/DigitalAssetsTray/index.js +8 -4
  41. package/src/global-files/digital-assets/assetTypes.js +42 -10
  42. package/src/global-files/digital-assets/uploadAssets.js +38 -23
  43. package/src/global-files/digital-assets/useDigitalAssets.js +19 -8
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.statusName = exports.statusColor = exports.retailerImage = exports.retailerId = exports.FONTS = exports.COLORS = void 0;
7
+
8
+ var _variables = require("../../../../global-files/variables");
9
+
10
+ var _statusDictionary = require("../../../../global-files/statusDictionary");
11
+
12
+ /*
13
+ Colores y tipografía de la edición de producto, en un solo lugar para las
14
+ secciones hechas con MUI. Son los mismos de los componentes originales
15
+ (Status, FeatureTag, TabSection, ScreenHeader...): el diseño no cambia.
16
+ */
17
+ var COLORS = _variables.GlobalColors;
18
+ exports.COLORS = COLORS;
19
+ var FONTS = _variables.FontFamily;
20
+ /** Color de fondo de la etiqueta de estatus, como en `atoms/Status/styles.js`. */
21
+
22
+ exports.FONTS = FONTS;
23
+ var STATUS_COLORS = {
24
+ CA: _variables.GlobalColors.in_progress,
25
+ IE: _variables.GlobalColors.in_progress,
26
+ GLD: _variables.GlobalColors.in_progress,
27
+ R: _variables.GlobalColors.reception,
28
+ AS: _variables.GlobalColors.reception,
29
+ SAC: _variables.GlobalColors.reception,
30
+ PA: _variables.GlobalColors.reception,
31
+ AA: _variables.GlobalColors.finished,
32
+ AP: _variables.GlobalColors.finished,
33
+ AC: _variables.GlobalColors.finished,
34
+ AAC: _variables.GlobalColors.finished,
35
+ ACA: _variables.GlobalColors.finished,
36
+ RA: _variables.GlobalColors.rejected_status,
37
+ RC: _variables.GlobalColors.rejected_status,
38
+ RP: _variables.GlobalColors.rejected_status,
39
+ RAC: _variables.GlobalColors.rejected_status,
40
+ RCA: _variables.GlobalColors.rejected_status,
41
+ Dat: _variables.GlobalColors.s4,
42
+ Dsc: _variables.GlobalColors.s4,
43
+ Imgs: _variables.GlobalColors.s4,
44
+ FAP: _variables.GlobalColors.exported,
45
+ Ex: _variables.GlobalColors.exported,
46
+ DDI: _variables.GlobalColors.original_purpura,
47
+ TAB: _variables.GlobalColors.deep_gray,
48
+ Pt: _variables.GlobalColors.s2
49
+ };
50
+ /** "RA/AS" se pinta con el color de la primera parte, igual que el original. */
51
+
52
+ var statusColor = function statusColor(status) {
53
+ var _STATUS_COLORS$String;
54
+
55
+ return (_STATUS_COLORS$String = STATUS_COLORS[String(status !== null && status !== void 0 ? status : "").replace(/\/.*/, "")]) !== null && _STATUS_COLORS$String !== void 0 ? _STATUS_COLORS$String : _variables.GlobalColors.s3;
56
+ };
57
+ /** Nombre legible: "RA/AS" → "Rechazado Auditor / Asignado". */
58
+
59
+
60
+ exports.statusColor = statusColor;
61
+
62
+ var statusName = function statusName(status) {
63
+ if (!status) return null;
64
+ var names = String(status).split("/").map(function (key) {
65
+ var _STATUS_DICTIONARY$ke;
66
+
67
+ return (_STATUS_DICTIONARY$ke = _statusDictionary.STATUS_DICTIONARY[key]) === null || _STATUS_DICTIONARY$ke === void 0 ? void 0 : _STATUS_DICTIONARY$ke.name;
68
+ }).filter(Boolean);
69
+ return names.length > 0 ? names.join(" / ") : null;
70
+ };
71
+
72
+ exports.statusName = statusName;
73
+
74
+ var retailerImage = function retailerImage(retailer) {
75
+ var _retailer$id;
76
+
77
+ return (retailer === null || retailer === void 0 ? void 0 : retailer.image) || "https://content-management-images.s3.amazonaws.com/retailers/".concat((_retailer$id = retailer === null || retailer === void 0 ? void 0 : retailer.id) !== null && _retailer$id !== void 0 ? _retailer$id : retailer === null || retailer === void 0 ? void 0 : retailer.id_retailer, ".png");
78
+ };
79
+ /** El id de una cadena llega como `id` o como `id_retailer` según el origen. */
80
+
81
+
82
+ exports.retailerImage = retailerImage;
83
+
84
+ var retailerId = function retailerId(retailer) {
85
+ var _retailer$id2;
86
+
87
+ return (_retailer$id2 = retailer === null || retailer === void 0 ? void 0 : retailer.id) !== null && _retailer$id2 !== void 0 ? _retailer$id2 : retailer === null || retailer === void 0 ? void 0 : retailer.id_retailer;
88
+ };
89
+
90
+ exports.retailerId = retailerId;
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = exports.SinImagenes = exports.HijoDeOtro = exports.EspecialistaTextosCelular = exports.EspecialistaTextos = exports.EspecialistaImagenesTablet = exports.EspecialistaImagenesCelular = exports.EspecialistaImagenes = exports.ErrorAlCargar = exports.ConVariantesCelular = exports.ConVariantes = exports.AuditorQATablet = exports.AuditorQACelular = exports.AuditorQA = exports.AuditorPorEvaluarCelular = exports.AuditorPorEvaluar = void 0;
9
+
10
+ var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/objectSpread2"));
11
+
12
+ var _index = require("../index");
13
+
14
+ var _mockApi = require("../mocks/mockApi");
15
+
16
+ var _ImageEditor = require("../../RetailerProductEdition/stories/ImageEditor.stories");
17
+
18
+ var _TextEditor = require("../../RetailerProductEdition/stories/TextEditor.stories");
19
+
20
+ var _Auditor = require("../../RetailerProductEdition/stories/Auditor.stories");
21
+
22
+ var _jsxRuntime = require("react/jsx-runtime");
23
+
24
+ /*
25
+ Historias con datos locales: no le pegan a ninguna API, así que funcionan
26
+ siempre, sin token ni producto vivo en dev. Las respuestas están en
27
+ `mocks/api.fixtures.js`. Guardar, aprobar o rechazar se acepta sin hacer
28
+ nada (queda en la consola como `[mock API]`).
29
+
30
+ El producto y los usuarios salen de las historias de RetailerProductEdition
31
+ para que las dos vistas se comparen con lo mismo. El token va solo porque la
32
+ pantalla lo exige: aquí no sale a ningún lado.
33
+ */
34
+ var _default = {
35
+ title: "Components/pages/CreatorsProductEdition",
36
+ component: _index.CreatorsProductEdition,
37
+ decorators: [(0, _mockApi.withMockApi)()],
38
+ parameters: {
39
+ layout: "fullscreen"
40
+ }
41
+ }; // Como en la app: la pantalla vive en una caja de altura fija que no se
42
+ // desplaza. El scroll tiene que darlo la propia pantalla, en todos los tamaños.
43
+
44
+ exports.default = _default;
45
+
46
+ var Template = function Template(args) {
47
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
48
+ style: {
49
+ height: "100vh",
50
+ display: "flex",
51
+ overflow: "hidden"
52
+ },
53
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.CreatorsProductEdition, (0, _objectSpread2.default)({}, args))
54
+ });
55
+ };
56
+
57
+ var base = {
58
+ token: _ImageEditor.ImageEditor.args.token,
59
+ productSelected: _ImageEditor.ImageEditor.args.productSelected,
60
+ enableDigitalAssets: true
61
+ };
62
+ var TODAS_LAS_PESTAÑAS = {
63
+ Descripción: true,
64
+ "Ficha técnica": true,
65
+ Imágenes: true
66
+ };
67
+ var celular = {
68
+ viewport: {
69
+ defaultViewport: "mobile2"
70
+ }
71
+ };
72
+ var tablet = {
73
+ viewport: {
74
+ defaultViewport: "tablet"
75
+ }
76
+ }; // --- Especialista de edición (rol 8): pestaña de imágenes -------------------
77
+
78
+ var EspecialistaImagenes = Template.bind({});
79
+ exports.EspecialistaImagenes = EspecialistaImagenes;
80
+ EspecialistaImagenes.args = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, base), {}, {
81
+ tabsSections: _ImageEditor.ImageEditor.args.tabsSections,
82
+ user: _ImageEditor.ImageEditor.args.user
83
+ });
84
+ var EspecialistaImagenesTablet = Template.bind({});
85
+ exports.EspecialistaImagenesTablet = EspecialistaImagenesTablet;
86
+ EspecialistaImagenesTablet.args = EspecialistaImagenes.args;
87
+ EspecialistaImagenesTablet.parameters = tablet;
88
+ var EspecialistaImagenesCelular = Template.bind({});
89
+ exports.EspecialistaImagenesCelular = EspecialistaImagenesCelular;
90
+ EspecialistaImagenesCelular.args = EspecialistaImagenes.args;
91
+ EspecialistaImagenesCelular.parameters = celular; // --- Especialista de textos (rol 7): descripción ----------------------------
92
+
93
+ var EspecialistaTextos = Template.bind({});
94
+ exports.EspecialistaTextos = EspecialistaTextos;
95
+ EspecialistaTextos.args = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, base), {}, {
96
+ tabsSections: _TextEditor.TextEditor.args.tabsSections,
97
+ user: _TextEditor.TextEditor.args.user
98
+ });
99
+ var EspecialistaTextosCelular = Template.bind({});
100
+ exports.EspecialistaTextosCelular = EspecialistaTextosCelular;
101
+ EspecialistaTextosCelular.args = EspecialistaTextos.args;
102
+ EspecialistaTextosCelular.parameters = celular; // --- Auditor QA (rol 6): las tres pestañas ----------------------------------
103
+
104
+ var AuditorQA = Template.bind({});
105
+ exports.AuditorQA = AuditorQA;
106
+ AuditorQA.args = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, base), {}, {
107
+ tabsSections: TODAS_LAS_PESTAÑAS,
108
+ user: _Auditor.Auditor.args.user
109
+ });
110
+ var AuditorQATablet = Template.bind({});
111
+ exports.AuditorQATablet = AuditorQATablet;
112
+ AuditorQATablet.args = AuditorQA.args;
113
+ AuditorQATablet.parameters = tablet;
114
+ var AuditorQACelular = Template.bind({});
115
+ exports.AuditorQACelular = AuditorQACelular;
116
+ AuditorQACelular.args = AuditorQA.args;
117
+ AuditorQACelular.parameters = celular; // Del Sol en "AC": el auditor asignado ve el botón para validar o rechazar.
118
+
119
+ var AuditorPorEvaluar = Template.bind({});
120
+ exports.AuditorPorEvaluar = AuditorPorEvaluar;
121
+ AuditorPorEvaluar.args = AuditorQA.args;
122
+ AuditorPorEvaluar.decorators = [(0, _mockApi.withMockApi)({
123
+ delSolStatus: "AC"
124
+ })];
125
+ var AuditorPorEvaluarCelular = Template.bind({});
126
+ exports.AuditorPorEvaluarCelular = AuditorPorEvaluarCelular;
127
+ AuditorPorEvaluarCelular.args = AuditorQA.args;
128
+ AuditorPorEvaluarCelular.decorators = [(0, _mockApi.withMockApi)({
129
+ delSolStatus: "AC"
130
+ })];
131
+ AuditorPorEvaluarCelular.parameters = celular; // --- Variantes ---------------------------------------------------------------
132
+ // Padre con dos hijos y en un grupo de variantes.
133
+
134
+ var ConVariantes = Template.bind({});
135
+ exports.ConVariantes = ConVariantes;
136
+ ConVariantes.args = EspecialistaTextos.args;
137
+ ConVariantes.decorators = [(0, _mockApi.withMockApi)({
138
+ familia: "padre",
139
+ grupo: true
140
+ })];
141
+ var ConVariantesCelular = Template.bind({});
142
+ exports.ConVariantesCelular = ConVariantesCelular;
143
+ ConVariantesCelular.args = EspecialistaTextos.args;
144
+ ConVariantesCelular.decorators = [(0, _mockApi.withMockApi)({
145
+ familia: "padre",
146
+ grupo: true
147
+ })];
148
+ ConVariantesCelular.parameters = celular; // Hijo de otro producto: no ofrece ligar ni agrupar.
149
+
150
+ var HijoDeOtro = Template.bind({});
151
+ exports.HijoDeOtro = HijoDeOtro;
152
+ HijoDeOtro.args = EspecialistaTextos.args;
153
+ HijoDeOtro.decorators = [(0, _mockApi.withMockApi)({
154
+ familia: "hijo"
155
+ })]; // --- Casos límite -----------------------------------------------------------
156
+
157
+ var SinImagenes = Template.bind({});
158
+ exports.SinImagenes = SinImagenes;
159
+ SinImagenes.args = EspecialistaImagenes.args;
160
+ SinImagenes.decorators = [(0, _mockApi.withMockApi)({
161
+ images: false
162
+ })];
163
+ var ErrorAlCargar = Template.bind({});
164
+ exports.ErrorAlCargar = ErrorAlCargar;
165
+ ErrorAlCargar.args = EspecialistaImagenes.args;
166
+ ErrorAlCargar.decorators = [(0, _mockApi.withMockApi)({
167
+ failLoad: true
168
+ })];
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = exports.Textos = exports.ImagenesTablet = exports.ImagenesCelular = exports.Imagenes = exports.AuditorQA = void 0;
9
+
10
+ var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/objectSpread2"));
11
+
12
+ var _index = require("../index");
13
+
14
+ var _mockApi = require("../mocks/mockApi");
15
+
16
+ var _ImageEditor = require("../../RetailerProductEdition/stories/ImageEditor.stories");
17
+
18
+ var _Auditor = require("../../RetailerProductEdition/stories/Auditor.stories");
19
+
20
+ var _TextEditor = require("../../RetailerProductEdition/stories/TextEditor.stories");
21
+
22
+ var _jsxRuntime = require("react/jsx-runtime");
23
+
24
+ /*
25
+ Historias contra la API real de dev, con los MISMOS datos que las de
26
+ RetailerProductEdition (se importan de allá para no duplicar el token ni el
27
+ producto). Sirven para comparar las dos vistas lado a lado con datos reales.
28
+
29
+ Dependen de que el token siga sirviendo y el producto exista en dev: si una
30
+ falla al cargar, revisar primero eso. Las historias con datos locales, que no
31
+ dependen de nada, están en `CreatorsProductEdition.stories.js`.
32
+ */
33
+ var _default = {
34
+ title: "Components/pages/CreatorsProductEdition/API real",
35
+ component: _index.CreatorsProductEdition,
36
+ // Por si se llega desde una historia con datos locales: la API real.
37
+ decorators: [_mockApi.withRealApi]
38
+ };
39
+ exports.default = _default;
40
+
41
+ var Template = function Template(args) {
42
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.CreatorsProductEdition, (0, _objectSpread2.default)({}, args));
43
+ };
44
+
45
+ var Imagenes = Template.bind({});
46
+ exports.Imagenes = Imagenes;
47
+ Imagenes.args = (0, _objectSpread2.default)({}, _ImageEditor.ImageEditor.args);
48
+ var ImagenesTablet = Template.bind({});
49
+ exports.ImagenesTablet = ImagenesTablet;
50
+ ImagenesTablet.args = (0, _objectSpread2.default)({}, _ImageEditor.ImageEditor.args);
51
+ ImagenesTablet.parameters = {
52
+ viewport: {
53
+ defaultViewport: "tablet"
54
+ }
55
+ };
56
+ var ImagenesCelular = Template.bind({});
57
+ exports.ImagenesCelular = ImagenesCelular;
58
+ ImagenesCelular.args = (0, _objectSpread2.default)({}, _ImageEditor.ImageEditor.args);
59
+ ImagenesCelular.parameters = {
60
+ viewport: {
61
+ defaultViewport: "mobile2"
62
+ }
63
+ };
64
+ var AuditorQA = Template.bind({});
65
+ exports.AuditorQA = AuditorQA;
66
+ AuditorQA.args = (0, _objectSpread2.default)({}, _Auditor.Auditor.args); // El usuario de textos (rol 7) con el producto de la historia de imágenes: el
67
+ // de TextEditor (150504) no existe en dev y la pantalla no puede cargar.
68
+
69
+ var Textos = Template.bind({});
70
+ exports.Textos = Textos;
71
+ Textos.args = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, _TextEditor.TextEditor.args), {}, {
72
+ token: _ImageEditor.ImageEditor.args.token,
73
+ productSelected: _ImageEditor.ImageEditor.args.productSelected
74
+ });
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.Container = exports.BREAKPOINTS = void 0;
9
+
10
+ var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/taggedTemplateLiteral"));
11
+
12
+ var _styledComponents = _interopRequireDefault(require("styled-components"));
13
+
14
+ var _variables = require("../../../global-files/variables");
15
+
16
+ var _templateObject;
17
+
18
+ /*
19
+ Estilos de la edición de producto de Creators.
20
+
21
+ Parte de `RetailerProductEdition/styles.js` (mismo diseño) y agrega lo que la
22
+ hace responsiva. Tres tamaños, los mismos que usa MUI por omisión:
23
+
24
+ - celular (< 600px): una columna, un solo scroll para toda la pantalla.
25
+ - tablet (600-899px): igual, con más aire.
26
+ - desktop (>= 900px): las dos columnas de siempre, cada una con su scroll.
27
+
28
+ Varios hijos (ImagePreviewer, ImageDataTable, InputGroup...) traen anchos fijos
29
+ y la regla es no tocarlos. Donde estorban se ajustan DESDE AQUÍ, con selectores
30
+ acotados a esta página. Las fases siguientes los van reemplazando por MUI y
31
+ estos ajustes desaparecen con ellos.
32
+ */
33
+ var BREAKPOINTS = {
34
+ tablet: 600,
35
+ desktop: 900
36
+ };
37
+ exports.BREAKPOINTS = BREAKPOINTS;
38
+ var mobile = "@media (max-width: ".concat(BREAKPOINTS.tablet - 1, "px)");
39
+ var belowDesktop = "@media (max-width: ".concat(BREAKPOINTS.desktop - 1, "px)");
40
+
41
+ var Container = _styledComponents.default.div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n flex-direction: column;\n height: 100%;\n flex: 1;\n min-width: 0;\n overflow: auto;\n box-sizing: border-box;\n\n /* El scroll lo lleva SIEMPRE este contenedor, como en la vista original: en\n la app la pantalla vive dentro de un layout de altura fija, y si se dejara\n al documento, en celular no habr\xEDa nada que desplazar. */\n ", " {\n overflow-x: hidden;\n overflow-y: auto;\n -webkit-overflow-scrolling: touch;\n /* Sin overscroll-behavior: contain. Al llegar al final, el scroll tiene\n que poder pasar al contenedor de afuera (el lienzo de Storybook, o la\n p\xE1gina si la app la mete en algo que se desplaza); con contain se queda\n atorado y no hay forma de ver lo que est\xE1 debajo. */\n }\n\n .data-container {\n display: flex;\n flex: 0%;\n gap: 16px;\n min-width: 0;\n height: calc(100% - ", "px);\n padding: 0 12px 12px;\n box-sizing: border-box;\n\n ", " {\n flex-direction: column;\n flex: none;\n height: auto;\n }\n\n ", " {\n padding: 0 8px 12px;\n gap: 12px;\n }\n\n .image-data-panel {\n flex: 0 0 clamp(280px, 30%, 360px);\n min-width: 0;\n\n ", " {\n flex: 0 0 auto;\n width: 100%;\n }\n\n ", " {\n max-width: 480px;\n align-self: center;\n }\n }\n\n .product-information {\n flex: 1;\n min-width: 0;\n height: 100%;\n display: flex;\n flex-direction: column;\n\n ", " {\n height: auto;\n }\n\n /* Cabecera, pesta\xF1as y grupos de inputs: que puedan encogerse en vez de\n empujar la p\xE1gina hacia los lados. */\n & > * {\n min-width: 0;\n max-width: 100%;\n }\n\n .services-information-container {\n height: 100%;\n min-width: 0;\n overflow: auto;\n\n ", " {\n height: auto;\n overflow: visible;\n }\n }\n\n }\n }\n\n #modal-message-box {\n width: min(400px, 80vw);\n height: 100px;\n }\n"])), belowDesktop, function (_ref) {
42
+ var headerTop = _ref.headerTop;
43
+ return headerTop;
44
+ }, belowDesktop, mobile, belowDesktop, mobile, belowDesktop, belowDesktop);
45
+
46
+ exports.Container = Container;
@@ -5,7 +5,7 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.warnAssetFile = exports.validateAssetFile = exports.validateAssetDuration = exports.suggestAssetType = exports.resolvePreviewKind = exports.humanizeDuration = exports.getExtension = exports.getAssetType = exports.formatDuration = exports.formatBytes = exports.buildDropzoneAccept = exports.assetTypeOptions = exports.acceptedMimes = exports.acceptedFormatsLabel = exports.acceptedExtensions = exports.VIDEO_DURATION_SECONDS = exports.PLAYABLE_VIDEO_EXTENSIONS = exports.MAX_ASSETS_PER_PRODUCT = exports.IMAGE_EXTENSIONS = exports.ASSET_TYPE_ORDER = exports.ASSET_TYPES = exports.ASSET_PREVIEW = void 0;
8
+ exports.warnUnreadableVideo = exports.warnAssetFile = exports.validateAssetFile = exports.validateAssetDuration = exports.suggestAssetType = exports.resolvePreviewKind = exports.humanizeDuration = exports.getExtension = exports.getAssetType = exports.formatDuration = exports.formatBytes = exports.buildDropzoneAccept = exports.assetTypeOptions = exports.acceptedMimes = exports.acceptedFormatsLabel = exports.acceptedExtensions = exports.VIDEO_DURATION_SECONDS = exports.PLAYABLE_VIDEO_EXTENSIONS = exports.MAX_ASSETS_PER_PRODUCT = exports.IMAGE_EXTENSIONS = exports.ASSET_TYPE_ORDER = exports.ASSET_TYPES = exports.ASSET_PREVIEW = void 0;
9
9
 
10
10
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/esm/toConsumableArray"));
11
11
 
@@ -68,6 +68,22 @@ var VIDEO_DURATION_SECONDS = {
68
68
  };
69
69
  exports.VIDEO_DURATION_SECONDS = VIDEO_DURATION_SECONDS;
70
70
  var ASSET_TYPES = {
71
+ /*
72
+ Imágenes sueltas: fotos de ambientación, lifestyle, material de campaña.
73
+ No sustituyen a la galería de la pestaña Imágenes, que valida tomas
74
+ contra `image_manager`; aquí no cuentan para el avance ni tienen orden.
75
+ El gif tiene su propio tipo y el svg vive en "editable": se sirve como
76
+ descarga porque un svg abierto en el navegador ejecuta scripts.
77
+ */
78
+ imagen: {
79
+ id: "imagen",
80
+ label: "Imagen",
81
+ description: "Foto o imagen suelta (ambientación, lifestyle, campaña)",
82
+ mimes: ["image/jpeg", "image/png", "image/webp", "image/bmp", "image/avif", "image/tiff"],
83
+ extensions: ["jpg", "jpeg", "png", "webp", "bmp", "avif", "tif", "tiff"],
84
+ maxBytes: 50 * MB,
85
+ validatesDuration: false
86
+ },
71
87
  360: {
72
88
  id: "360",
73
89
  label: "360",
@@ -158,7 +174,7 @@ var ASSET_TYPES = {
158
174
  /** Orden en que se muestran en el selector de tipo. */
159
175
 
160
176
  exports.ASSET_TYPES = ASSET_TYPES;
161
- var ASSET_TYPE_ORDER = ["360", "video", "gif", "documento", "hoja_calculo", "editable", "comprimido", "otro"];
177
+ var ASSET_TYPE_ORDER = ["imagen", "360", "video", "gif", "documento", "hoja_calculo", "editable", "comprimido", "otro"];
162
178
  /** Opciones listas para el componente `Select` (espera `{ value, name }`). */
163
179
 
164
180
  exports.ASSET_TYPE_ORDER = ASSET_TYPE_ORDER;
@@ -384,15 +400,9 @@ var validateAssetFile = function validateAssetFile(file) {
384
400
  code: "NO_FILE",
385
401
  message: "No se recibió ningún archivo."
386
402
  };
387
- }
403
+ } // El cupo se revisa al final: un archivo que no se puede subir de todos modos
404
+ // (formato o peso) debe decir ESA razón, no "ya no hay lugar".
388
405
 
389
- if (currentCount >= MAX_ASSETS_PER_PRODUCT) {
390
- return {
391
- valid: false,
392
- code: "MAX_ASSETS",
393
- message: "Solo puedes almacenar ".concat(MAX_ASSETS_PER_PRODUCT, " activos digitales por producto.")
394
- };
395
- }
396
406
 
397
407
  var assetTypeId = suggestAssetType({
398
408
  mime: file.type,
@@ -416,6 +426,14 @@ var validateAssetFile = function validateAssetFile(file) {
416
426
  };
417
427
  }
418
428
 
429
+ if (currentCount >= MAX_ASSETS_PER_PRODUCT) {
430
+ return {
431
+ valid: false,
432
+ code: "MAX_ASSETS",
433
+ message: "\"".concat(file.name, "\" no se agreg\xF3: solo puedes almacenar ").concat(MAX_ASSETS_PER_PRODUCT, " activos digitales por producto.")
434
+ };
435
+ }
436
+
419
437
  return {
420
438
  valid: true,
421
439
  assetType: assetTypeId,
@@ -443,20 +461,39 @@ var warnAssetFile = function warnAssetFile(file, assetTypeId) {
443
461
  if (PLAYABLE_VIDEO_EXTENSIONS.includes(ext)) return null;
444
462
  return "\"".concat(file === null || file === void 0 ? void 0 : file.name, "\" se guardar\xE1 y se podr\xE1 descargar, pero el navegador no puede reproducir los .").concat(ext, ". Convi\xE9rtelo a MP4 si necesitas verlo aqu\xED.");
445
463
  };
464
+ /**
465
+ * Aviso para un video cuya duración el navegador no pudo leer (códec que no
466
+ * conoce, archivo dañado). No se rechaza: sirve igual para entregarlo, solo que
467
+ * aquí no se podrá ver ni se sabe cuánto dura.
468
+ */
469
+
470
+
471
+ exports.warnAssetFile = warnAssetFile;
472
+
473
+ var warnUnreadableVideo = function warnUnreadableVideo(fileName) {
474
+ return "\"".concat(fileName, "\" se guardar\xE1 y se podr\xE1 descargar, pero el navegador no pudo leerlo: no se podr\xE1 reproducir aqu\xED ni se valid\xF3 su duraci\xF3n.");
475
+ };
446
476
  /**
447
477
  * Valida la duración de un video. Va aparte de `validateAssetFile` porque
448
478
  * obtenerla es asíncrono (hay que cargar el archivo en un <video>) y no se
449
479
  * quiere pagar ese costo en archivos que ya fueron rechazados por peso.
480
+ *
481
+ * `seconds` en null significa "no se pudo medir" y no se rechaza: `Number(null)`
482
+ * es 0 y, sin esta guarda, todo video ilegible salía como "dura menos de 10 s".
450
483
  */
451
484
 
452
485
 
453
- exports.warnAssetFile = warnAssetFile;
486
+ exports.warnUnreadableVideo = warnUnreadableVideo;
454
487
 
455
488
  var validateAssetDuration = function validateAssetDuration(seconds, assetTypeId) {
489
+ var fileName = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "El video";
456
490
  var assetType = getAssetType(assetTypeId);
457
491
  if (!assetType.validatesDuration) return {
458
492
  valid: true
459
493
  };
494
+ if (seconds === null || seconds === undefined) return {
495
+ valid: true
496
+ };
460
497
  var value = Number(seconds);
461
498
  if (!Number.isFinite(value)) return {
462
499
  valid: true
@@ -468,7 +505,7 @@ var validateAssetDuration = function validateAssetDuration(seconds, assetTypeId)
468
505
  return {
469
506
  valid: false,
470
507
  code: "DURATION",
471
- message: "Los videos deben durar entre ".concat(humanizeDuration(min), " y ").concat(humanizeDuration(max), ".")
508
+ message: "\"".concat(fileName, "\" dura ").concat(humanizeDuration(value), "; los videos deben durar entre ").concat(humanizeDuration(min), " y ").concat(humanizeDuration(max), ".")
472
509
  };
473
510
  }
474
511
 
@@ -47,16 +47,17 @@ var _assets = require("./assets.adapter");
47
47
  */
48
48
  var requestPresign = /*#__PURE__*/function () {
49
49
  var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(_ref) {
50
- var _data$body, _body$uploads, _body$rejected;
50
+ var _data, _data$body, _data2, _data3, _body$uploads, _body$rejected;
51
51
 
52
- var articleId, assets, token, _yield$axios$post, data, body;
52
+ var articleId, assets, token, data, _yield$axios$post, body;
53
53
 
54
54
  return _regenerator.default.wrap(function _callee$(_context) {
55
55
  while (1) {
56
56
  switch (_context.prev = _context.next) {
57
57
  case 0:
58
58
  articleId = _ref.articleId, assets = _ref.assets, token = _ref.token;
59
- _context.next = 3;
59
+ _context.prev = 1;
60
+ _context.next = 4;
60
61
  return _axios.default.post(process.env.REACT_APP_ASSETS_PRESIGN_ENDPOINT, {
61
62
  articleId: articleId,
62
63
  files: assets.map(function (asset) {
@@ -73,32 +74,44 @@ var requestPresign = /*#__PURE__*/function () {
73
74
  }
74
75
  });
75
76
 
76
- case 3:
77
+ case 4:
77
78
  _yield$axios$post = _context.sent;
78
79
  data = _yield$axios$post.data;
80
+ _context.next = 12;
81
+ break;
82
+
83
+ case 8:
84
+ _context.prev = 8;
85
+ _context.t0 = _context["catch"](1);
86
+ // "Network Error" o "Request failed with status code 502" no le dicen nada
87
+ // al usuario. El detalle queda en la consola para quien lo diagnostique.
88
+ console.error("Activos digitales: falló la firma de la subida", _context.t0);
89
+ throw new Error("No se pudo preparar la subida. Revisa tu conexión e inténtalo de nuevo.");
90
+
91
+ case 12:
79
92
  // `integration: lambda` de API Gateway devuelve el objeto del handler tal
80
93
  // cual, con el cuerpo como cadena, en vez de traducirlo a una respuesta HTTP.
81
- body = typeof (data === null || data === void 0 ? void 0 : data.body) === "string" ? JSON.parse(data.body) : (_data$body = data === null || data === void 0 ? void 0 : data.body) !== null && _data$body !== void 0 ? _data$body : data;
94
+ body = typeof ((_data = data) === null || _data === void 0 ? void 0 : _data.body) === "string" ? JSON.parse(data.body) : (_data$body = (_data2 = data) === null || _data2 === void 0 ? void 0 : _data2.body) !== null && _data$body !== void 0 ? _data$body : data;
82
95
 
83
- if (!(data !== null && data !== void 0 && data.statusCode && data.statusCode >= 400)) {
84
- _context.next = 8;
96
+ if (!((_data3 = data) !== null && _data3 !== void 0 && _data3.statusCode && data.statusCode >= 400)) {
97
+ _context.next = 15;
85
98
  break;
86
99
  }
87
100
 
88
101
  throw new Error((body === null || body === void 0 ? void 0 : body.message) || "No se pudo preparar la subida");
89
102
 
90
- case 8:
103
+ case 15:
91
104
  return _context.abrupt("return", {
92
105
  uploads: (_body$uploads = body === null || body === void 0 ? void 0 : body.uploads) !== null && _body$uploads !== void 0 ? _body$uploads : [],
93
106
  rejected: (_body$rejected = body === null || body === void 0 ? void 0 : body.rejected) !== null && _body$rejected !== void 0 ? _body$rejected : []
94
107
  });
95
108
 
96
- case 9:
109
+ case 16:
97
110
  case "end":
98
111
  return _context.stop();
99
112
  }
100
113
  }
101
- }, _callee);
114
+ }, _callee, null, [[1, 8]]);
102
115
  }));
103
116
 
104
117
  return function requestPresign(_x) {
@@ -157,15 +170,25 @@ var uploadToS3 = function uploadToS3(_ref3) {
157
170
  */
158
171
 
159
172
 
160
- var code = (_$exec = /<Code>(.*?)<\/Code>/.exec(xhr.responseText)) === null || _$exec === void 0 ? void 0 : _$exec[1];
161
- reject(new Error(code === "EntityTooLarge" ? "El archivo supera el tamaño permitido." : "S3 rechaz\xF3 la subida (".concat(code || xhr.status, ").")));
173
+ var code = (_$exec = /<Code>(.*?)<\/Code>/.exec(xhr.responseText)) === null || _$exec === void 0 ? void 0 : _$exec[1]; // El código técnico va a la consola; al usuario, algo que pueda hacer.
174
+
175
+ console.error("Activos digitales: S3 rechazó la subida", code || xhr.status, xhr.responseText);
176
+
177
+ if (code === "EntityTooLarge") {
178
+ reject(new Error("El archivo supera el tamaño permitido."));
179
+ } else if (code === "AccessDenied") {
180
+ reject(new Error("No se pudo subir el archivo. Avisa a soporte (permiso de almacenamiento)."));
181
+ } else {
182
+ reject(new Error("No se pudo subir el archivo (".concat(code || xhr.status, "). Int\xE9ntalo de nuevo; si sigue fallando, avisa a soporte.")));
183
+ }
162
184
  };
163
185
 
164
186
  xhr.onerror = function () {
165
- return reject(new Error( // Un fallo de red sin estatus casi siempre es CORS: el bucket tiene que
166
- // permitir POST desde el origen de la aplicación. El navegador corta la
167
- // petición antes de mandarla y no deja rastro en ningún log del servidor.
168
- "No se pudo conectar con el almacenamiento. Revisa la configuración CORS del bucket."));
187
+ // Un fallo de red sin estatus casi siempre es CORS (el bucket tiene que
188
+ // permitir POST desde el origen de la aplicación) o una conexión caída. El
189
+ // navegador corta la petición y no deja rastro en ningún log del servidor.
190
+ console.error("Activos digitales: no hubo respuesta de S3 (red o CORS del bucket)");
191
+ reject(new Error("No se pudo conectar para subir el archivo. Revisa tu conexión e inténtalo de nuevo."));
169
192
  };
170
193
 
171
194
  xhr.onabort = function () {