contentoh-components-library 21.5.99 → 21.6.1

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 (64) hide show
  1. package/dist/components/atoms/GeneralButton/styles.js +1 -1
  2. package/dist/components/atoms/GeneralInput/index.js +249 -54
  3. package/dist/components/atoms/GeneralInput/styles.js +7 -3
  4. package/dist/components/atoms/InputFormatter/index.js +223 -68
  5. package/dist/components/atoms/InputFormatter/styles.js +20 -4
  6. package/dist/components/molecules/StatusAsignationInfo/index.js +11 -1
  7. package/dist/components/molecules/TabsMenu/index.js +13 -1
  8. package/dist/components/molecules/TagAndInput/index.js +364 -24
  9. package/dist/components/molecules/TagAndInput/styles.js +2 -2
  10. package/dist/components/organisms/FullProductNameHeader/index.js +6 -22
  11. package/dist/components/organisms/InputGroup/index.js +22 -18
  12. package/dist/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +150 -337
  13. package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.context.js +15 -15
  14. package/dist/components/pages/ProviderProductEdition/index.js +393 -352
  15. package/dist/components/pages/ProviderProductEdition/utils.js +1 -0
  16. package/dist/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +125 -211
  17. package/dist/components/pages/RetailerProductEdition/index.js +1743 -2239
  18. package/dist/components/pages/RetailerProductEdition/styles.js +4 -2
  19. package/dist/components/pages/RetailerProductEdition/utils.js +251 -2
  20. package/dist/contexts/AiProductEdition.js +34 -22
  21. package/package.json +4 -2
  22. package/src/ai/utils/compare-strings.js +45 -0
  23. package/src/assets/images/Icons/arrow.png +0 -0
  24. package/src/assets/images/Icons/cancel.png +0 -0
  25. package/src/assets/images/Icons/ia-icon.png +0 -0
  26. package/src/assets/images/Icons/loading.svg +5 -0
  27. package/src/assets/images/Icons/reload.png +0 -0
  28. package/src/components/atoms/GeneralButton/styles.js +4 -0
  29. package/src/components/atoms/GeneralInput/index.js +241 -60
  30. package/src/components/atoms/GeneralInput/styles.js +81 -0
  31. package/src/components/atoms/InputFormatter/index.js +200 -51
  32. package/src/components/atoms/InputFormatter/styles.js +284 -0
  33. package/src/components/atoms/RetailerSelector/RetailerSelector.stories.js +10 -0
  34. package/src/components/atoms/RetailerSelector/index.js +3 -0
  35. package/src/components/atoms/RetailerSelector/styles.js +0 -0
  36. package/src/components/molecules/StatusAsignationInfo/index.js +9 -1
  37. package/src/components/molecules/TabsMenu/index.js +12 -0
  38. package/src/components/molecules/TagAndInput/index.js +294 -21
  39. package/src/components/molecules/TagAndInput/styles.js +59 -17
  40. package/src/components/organisms/ChangeStatusModal/index.jsx +488 -0
  41. package/src/components/organisms/ChangeStatusModal/styles.js +333 -0
  42. package/src/components/organisms/FullProductNameHeader/index.js +4 -28
  43. package/src/components/organisms/FullTabsMenu/index.js +1 -1
  44. package/src/components/organisms/InputGroup/index.js +12 -4
  45. package/src/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +174 -202
  46. package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx +14 -14
  47. package/src/components/pages/ProviderProductEdition/index.js +486 -417
  48. package/src/components/pages/ProviderProductEdition/utils.js +2 -2
  49. package/src/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +136 -243
  50. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.context.jsx +575 -0
  51. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.reducer.js +62 -0
  52. package/src/components/pages/RetailerProductEdition/context/reducers/active-state.js +344 -0
  53. package/src/components/pages/RetailerProductEdition/context/reducers/inputs.js +155 -0
  54. package/src/components/pages/RetailerProductEdition/context/reducers/product.js +114 -0
  55. package/src/components/pages/RetailerProductEdition/context/reducers/system.js +60 -0
  56. package/src/components/pages/RetailerProductEdition/index.js +1580 -1719
  57. package/src/components/pages/RetailerProductEdition/index_old.js +1979 -0
  58. package/src/components/pages/RetailerProductEdition/stories/Auditor.stories.js +101 -0
  59. package/src/components/pages/RetailerProductEdition/stories/ImageEditor.stories.js +115 -0
  60. package/src/components/pages/RetailerProductEdition/stories/TextEditor.stories.js +174 -0
  61. package/src/components/pages/RetailerProductEdition/styles.js +67 -2
  62. package/src/components/pages/RetailerProductEdition/utils.js +240 -0
  63. package/src/contexts/AiProductEdition.jsx +356 -0
  64. package/src/global-files/statusDictionary.js +103 -0
@@ -11,11 +11,13 @@ var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/hel
11
11
 
12
12
  var _styledComponents = _interopRequireDefault(require("styled-components"));
13
13
 
14
+ var _variables = require("../../../global-files/variables");
15
+
14
16
  var _templateObject;
15
17
 
16
- var Container = _styledComponents.default.div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n flex-direction: column;\n height: 100%;\n flex: 1;\n overflow: auto;\n\n .data-container {\n display: flex;\n flex: 0%;\n height: calc(100% - ", "px);\n .image-data-panel {\n width: 340px;\n\n & + * {\n margin-left: 10px;\n }\n }\n\n .product-information {\n width: calc(100% - 341px);\n display: flex;\n flex-direction: column;\n\n .services-information-container {\n height: 100%;\n overflow: auto;\n }\n\n .image-services {\n aside {\n display: grid;\n grid-template-columns: repeat(auto-fill, 179px);\n column-gap: 15px;\n row-gap: 15px;\n padding: 20px;\n }\n }\n\n .commentary-box {\n display: flex;\n justify-content: space-between;\n align-items: flex-end;\n padding: 10px;\n padding-left: 0;\n\n .commentary {\n display: flex;\n align-items: flex-end;\n\n .input-container {\n width: 500px;\n\n .quill {\n height: 100px;\n }\n\n & + * {\n margin-left: 5px;\n }\n }\n\n .buttons-box {\n display: flex;\n width: 210px;\n flex-wrap: wrap;\n\n .general-transparent-button {\n & + * {\n margin-top: 5px;\n }\n }\n\n .general-transparent-button,\n .general-green-button,\n .general-button-disabled {\n width: fit-content;\n min-width: 201px;\n height: 40px;\n }\n }\n }\n }\n\n .feedback-box {\n display: flex;\n }\n }\n }\n #modal-message-box {\n width: 400px;\n height: 100px;\n }\n .container {\n width: 100%;\n height: 100%;\n .dropzone {\n height: 100%;\n width: 100%;\n }\n }\n"])), function (_ref) {
18
+ var Container = _styledComponents.default.div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2.default)(["\n display: flex;\n flex-direction: column;\n height: 100%;\n flex: 1;\n overflow: auto;\n\n .data-container {\n display: flex;\n flex: 0%;\n height: calc(100% - ", "px);\n .image-data-panel {\n width: 340px;\n\n & + * {\n margin-left: 10px;\n }\n }\n\n .product-information {\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n\n .services-information-container {\n height: 100%;\n overflow: auto;\n }\n\n .image-services {\n aside {\n display: grid;\n grid-template-columns: repeat(auto-fill, 179px);\n column-gap: 15px;\n row-gap: 15px;\n padding: 20px;\n }\n }\n\n .commentary-box {\n display: flex;\n justify-content: space-between;\n align-items: flex-end;\n padding: 10px;\n padding-left: 0;\n\n .action-buttons{\n display: flex;\n flex-direction: column;\n gap: 1rem;\n }\n\n .commentary {\n display: flex;\n align-items: flex-end;\n\n .input-container {\n width: 500px;\n\n .quill {\n height: 100px;\n }\n\n & + * {\n margin-left: 5px;\n }\n }\n\n .buttons-box {\n display: flex;\n width: 210px;\n flex-wrap: wrap;\n\n .general-transparent-button {\n & + * {\n margin-top: 5px;\n }\n }\n\n .general-transparent-button,\n .general-green-button,\n .general-button-disabled {\n width: fit-content;\n min-width: 201px;\n height: 40px;\n }\n }\n }\n }\n\n .feedback-box {\n display: flex;\n }\n\n .required-inputs-message {\n font-family: ", ";\n font-size: 13px;\n color: ", ";\n padding: 10px;\n display: flex;\n align-items: center;\n\n p + * {\n margin-top: 10px;\n }\n\n button {\n min-width: fit-content;\n }\n }\n }\n }\n #modal-message-box {\n width: 400px;\n height: 100px;\n }\n .container {\n width: 100%;\n height: 90%;\n .dropzone {\n height: 100%;\n width: 100%;\n position: relative;\n transition: all 0.5s ease;\n\n &.drag-active {\n background-color: rgba(", ", 0.05);\n border: 2px dashed ", ";\n border-radius: 8px;\n\n aside {\n opacity: 0.3;\n pointer-events: none;\n }\n }\n\n .drag-overlay {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(", ", 0.1);\n border-radius: 8px;\n pointer-events: none;\n z-index: 10;\n\n p {\n font-family: ", ";\n font-size: 24px;\n font-weight: 600;\n color: ", ";\n text-align: center;\n padding: 20px;\n background-color: ", ";\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n }\n }\n }\n }\n"])), function (_ref) {
17
19
  var headerTop = _ref.headerTop;
18
20
  return headerTop;
19
- });
21
+ }, _variables.FontFamily.AvenirNext, _variables.GlobalColors.color_gray, _variables.GlobalColors.rgb_color_pink, _variables.GlobalColors.color_pink, _variables.GlobalColors.rgb_color_pink, _variables.FontFamily.AvenirNext, _variables.GlobalColors.color_pink, _variables.GlobalColors.white);
20
22
 
21
23
  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.translateService = exports.sendMessage = exports.getInputsData = exports.getAuditVersion = exports.createMessage = void 0;
8
+ exports.translateService = exports.translateConcept = exports.sendMessage = exports.normalizeProduct = exports.getStatusArrayByRole = exports.getInputsData = exports.getConceptsByRole = exports.getConceptByTab = exports.getAuditVersion = exports.createMessage = exports.calculateRequiredNull = exports.buildCollaboratorAssignations = void 0;
9
9
 
10
10
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
11
11
 
@@ -123,4 +123,253 @@ var sendMessage = /*#__PURE__*/function () {
123
123
  };
124
124
  }();
125
125
 
126
- exports.sendMessage = sendMessage;
126
+ exports.sendMessage = sendMessage;
127
+
128
+ var normalizeProduct = function normalizeProduct(product) {
129
+ // Handle case where product might be wrapped in a product property
130
+ var productData = product.product || product;
131
+ var article = productData.article || {};
132
+ var categoryRetailer = productData.categoryRetailer || article.categoryRetailer;
133
+ var categoryRetailerNormalized = categoryRetailer ? categoryRetailer.map(function (rel) {
134
+ return {
135
+ id_retailer: rel.id_retailer || rel.retailer_id,
136
+ retailer: rel.retailer_name || rel.retailerName,
137
+ name: rel.retailer_name || rel.retailerName,
138
+ id_category: rel.id_category,
139
+ category: rel.category_name || rel.categoryName,
140
+ image: "https://content-management-images.s3.amazonaws.com/retailers/".concat(rel.id_retailer || rel.retailer_id, ".png")
141
+ };
142
+ }) : null; // extraer los retailer_id de statusByRetailer donde task_group_id no sea nulo
143
+
144
+ var retailersIdsInOrder = productData.statusByRetailer ? productData.statusByRetailer.map(function (status) {
145
+ return status.retailer_id;
146
+ }) : [];
147
+ var categoryRetailerInOrder = categoryRetailerNormalized.filter(function (rel) {
148
+ return retailersIdsInOrder.includes(rel.id_retailer);
149
+ });
150
+ return {
151
+ id_article: productData.id_article || article.id_article || 0,
152
+ upc: productData.upc || article.upc || null,
153
+ sku: productData.sku || article.sku || null,
154
+ name: productData.name || article.name || null,
155
+ timestamp: productData.timestamp || article.timestamp || null,
156
+ id_user: productData.id_user || article.id_user || null,
157
+ categoryName: productData.category || article.category || null,
158
+ id_category: productData.id_category || article.id_category || null,
159
+ retailersAvailable: productData.retailersAvailable || null,
160
+ categoryRetailer: categoryRetailerNormalized || null,
161
+ percentages: productData.percentages || null,
162
+ summary: productData.summary || null,
163
+ version: productData.version || 0,
164
+ id_order: productData.orderId || 0,
165
+ status: productData.status || null,
166
+ datasheet_status: productData.datasheet_status || null,
167
+ description_status: productData.description_status || null,
168
+ images_status: productData.images_status || null,
169
+ brand: productData.brand || null,
170
+ services: productData.services || null,
171
+ country: article.country || null,
172
+ id_company: article.company_id || null,
173
+ company: article.company_name || null,
174
+ id_datasheet_especialist: article.id_datasheet_especialist || 0,
175
+ id_datasheet_facilitator: article.id_datasheet_facilitator || null,
176
+ id_description_especialist: article.id_description_especialist || 0,
177
+ id_description_facilitator: article.id_description_facilitator || null,
178
+ id_images_especialist: article.id_images_especialist || 0,
179
+ id_images_facilitator: article.id_images_facilitator || null,
180
+ id_auditor: article.id_auditor || 0,
181
+ statusByRetailer: productData.statusByRetailer || null,
182
+ categoryRetailerInOrder: categoryRetailerInOrder || null
183
+ };
184
+ };
185
+
186
+ exports.normalizeProduct = normalizeProduct;
187
+ var TAB_TO_CONCEPT = {
188
+ Descripción: "description",
189
+ "Ficha técnica": "datasheet",
190
+ Imágenes: "images"
191
+ };
192
+ var CONCEPT_TO_TAB = {
193
+ description: "Descripción",
194
+ datasheet: "Ficha técnica",
195
+ images: "Imágenes"
196
+ };
197
+
198
+ var getConceptByTab = function getConceptByTab(tab) {
199
+ return TAB_TO_CONCEPT[tab];
200
+ };
201
+
202
+ exports.getConceptByTab = getConceptByTab;
203
+
204
+ var translateConcept = function translateConcept(concept) {
205
+ return CONCEPT_TO_TAB[concept];
206
+ };
207
+
208
+ exports.translateConcept = translateConcept;
209
+
210
+ var getStatusArrayByRole = function getStatusArrayByRole(idRole) {
211
+ switch (idRole) {
212
+ case 7:
213
+ case 8:
214
+ return ["PA", "AS", "CA", "RC", "RA", "RP", "RCA"];
215
+
216
+ case 4:
217
+ case 5:
218
+ return ["RC", "AC", "AA", "AP", "ACA"];
219
+
220
+ case 6:
221
+ return ["RP", "RCA", "AC", "RA"];
222
+
223
+ default:
224
+ return [];
225
+ }
226
+ };
227
+
228
+ exports.getStatusArrayByRole = getStatusArrayByRole;
229
+
230
+ var getConceptsByRole = function getConceptsByRole(idRole) {
231
+ switch (idRole) {
232
+ case 4:
233
+ return ["description", "datasheet"];
234
+
235
+ case 5:
236
+ return ["images"];
237
+
238
+ default:
239
+ return ["description", "datasheet", "images"];
240
+ }
241
+ };
242
+
243
+ exports.getConceptsByRole = getConceptsByRole;
244
+
245
+ var buildCollaboratorAssignations = function buildCollaboratorAssignations(product, users) {
246
+ return {
247
+ Descripción: {
248
+ assignations: [{
249
+ collaboratorType: "especialist",
250
+ id: product.id_description_especialist
251
+ }, {
252
+ collaboratorType: "facilitator",
253
+ id: product.id_description_facilitator
254
+ }],
255
+ collaborators: {
256
+ especialist: users[0] || [],
257
+ facilitator: users[2] || []
258
+ }
259
+ },
260
+ "Ficha técnica": {
261
+ assignations: [{
262
+ collaboratorType: "especialist",
263
+ id: product.id_datasheet_especialist
264
+ }, {
265
+ collaboratorType: "facilitator",
266
+ id: product.id_datasheet_facilitator
267
+ }],
268
+ collaborators: {
269
+ especialist: users[0] || [],
270
+ facilitator: users[2] || []
271
+ }
272
+ },
273
+ Imágenes: {
274
+ assignations: [{
275
+ collaboratorType: "especialist",
276
+ id: product.id_images_especialist
277
+ }, {
278
+ collaboratorType: "facilitator",
279
+ id: product.id_images_facilitator
280
+ }],
281
+ collaborators: {
282
+ especialist: users[1] || [],
283
+ facilitator: users[3] || []
284
+ }
285
+ }
286
+ };
287
+ };
288
+
289
+ exports.buildCollaboratorAssignations = buildCollaboratorAssignations;
290
+
291
+ var calculateRequiredNull = function calculateRequiredNull(services, servicesData, activeRetailerId) {
292
+ var _services$3, _services$4, _services$5, _services$5$retailerM, _services$7, _services$7$values;
293
+
294
+ var result = {
295
+ "Ficha técnica": 0,
296
+ Descripción: 0,
297
+ Imágenes: 0
298
+ };
299
+
300
+ var isServiceRequested = function isServiceRequested(retailerId, concept) {
301
+ return servicesData === null || servicesData === void 0 ? void 0 : servicesData.some(function (srv) {
302
+ return srv.id_retailer === retailerId && srv.service === concept;
303
+ });
304
+ }; // Ficha técnica: contar inputs requeridos sin valor
305
+
306
+
307
+ var datasheetInputs = ((_services$3 = services[0]) === null || _services$3 === void 0 ? void 0 : _services$3.inputs) || {};
308
+ var datasheetsByRetailer = Object.values(services[0]).filter(function (item) {
309
+ var _item$retailer;
310
+
311
+ return (item === null || item === void 0 ? void 0 : (_item$retailer = item.retailer) === null || _item$retailer === void 0 ? void 0 : _item$retailer.id) === activeRetailerId;
312
+ });
313
+ datasheetsByRetailer.forEach(function (datasheet) {
314
+ var _datasheet$retailer;
315
+
316
+ if (!isServiceRequested((_datasheet$retailer = datasheet.retailer) === null || _datasheet$retailer === void 0 ? void 0 : _datasheet$retailer.id, "datasheet")) return;
317
+ Object.values(datasheet.data || {}).forEach(function (dataGroup) {
318
+ var _dataGroup$inputs;
319
+
320
+ (_dataGroup$inputs = dataGroup.inputs) === null || _dataGroup$inputs === void 0 ? void 0 : _dataGroup$inputs.forEach(function (inputId) {
321
+ var input = datasheetInputs[inputId];
322
+
323
+ if (input !== null && input !== void 0 && input.required && (input === null || input === void 0 ? void 0 : input.id_retailer) === activeRetailerId && !(input !== null && input !== void 0 && input.value)) {
324
+ result["Ficha técnica"]++;
325
+ }
326
+ });
327
+ });
328
+ }); // Descripción: contar inputs requeridos sin valor
329
+
330
+ var htmlTagsRegex = /(<\/?p>)|(<\/?strong>)|(<br>)/gm;
331
+ var descriptions = (_services$4 = services[1]) === null || _services$4 === void 0 ? void 0 : _services$4.filter(function (desc) {
332
+ return desc.id === activeRetailerId;
333
+ });
334
+ descriptions === null || descriptions === void 0 ? void 0 : descriptions.forEach(function (description) {
335
+ var _description$inputs;
336
+
337
+ if (!isServiceRequested(description.id, "description")) return;
338
+ (_description$inputs = description.inputs) === null || _description$inputs === void 0 ? void 0 : _description$inputs.forEach(function (input) {
339
+ var _input$value;
340
+
341
+ var valueClean = ((_input$value = input.value) === null || _input$value === void 0 ? void 0 : _input$value.replace(htmlTagsRegex, "")) || "";
342
+
343
+ if (input.required && !valueClean) {
344
+ result["Descripción"]++;
345
+ }
346
+ });
347
+ }); // Imágenes: contar imágenes requeridas sin valor
348
+
349
+ var retailerMandatories = ((_services$5 = services[2]) === null || _services$5 === void 0 ? void 0 : (_services$5$retailerM = _services$5.retailerMandatories) === null || _services$5$retailerM === void 0 ? void 0 : _services$5$retailerM.flat()) || [];
350
+ var requestedRetailers = retailerMandatories.filter(function (rm) {
351
+ return servicesData === null || servicesData === void 0 ? void 0 : servicesData.some(function (srv) {
352
+ return srv.id_retailer === rm.id_retailer;
353
+ });
354
+ });
355
+ var requiredImageIds = new Set(requestedRetailers.filter(function (rm) {
356
+ var _services$6, _services$6$inputs;
357
+
358
+ return (_services$6 = services[2]) === null || _services$6 === void 0 ? void 0 : (_services$6$inputs = _services$6.inputs) === null || _services$6$inputs === void 0 ? void 0 : _services$6$inputs.some(function (input) {
359
+ return input.id === rm.id_image && input.required === 1;
360
+ });
361
+ }).map(function (rm) {
362
+ return rm.id_image;
363
+ }));
364
+ var existingImageIds = new Set(((_services$7 = services[2]) === null || _services$7 === void 0 ? void 0 : (_services$7$values = _services$7.values) === null || _services$7$values === void 0 ? void 0 : _services$7$values.map(function (img) {
365
+ return img.image_id;
366
+ })) || []);
367
+ requiredImageIds.forEach(function (imageId) {
368
+ if (!existingImageIds.has(imageId)) {
369
+ result["Imágenes"]++;
370
+ }
371
+ });
372
+ return result;
373
+ };
374
+
375
+ exports.calculateRequiredNull = calculateRequiredNull;
@@ -91,40 +91,47 @@ var AiProductEditionProvider = function AiProductEditionProvider(_ref) {
91
91
  inputsUsingAi = _useState16[0],
92
92
  setInputsUsingAi = _useState16[1];
93
93
 
94
- var MAX_CREDITS = 10;
95
- var COOLDOWN_MS = 5 * 60 * 1000;
94
+ var AI_MAX_CREDITS = 2;
95
+ var AI_RESET_MS = 24 * 60 * 60 * 1000;
96
96
  var RATE_LIMIT_KEY = "ai_generation_limit_data";
97
97
 
98
- var checkAndManageRateLimit = function checkAndManageRateLimit(currentArticleId) {
98
+ var checkAndManageRateLimit = function checkAndManageRateLimit(_ref2) {
99
+ var articleId = _ref2.articleId,
100
+ descriptionId = _ref2.descriptionId,
101
+ attributeId = _ref2.attributeId,
102
+ type = _ref2.type;
99
103
  var now = Date.now();
100
104
  var storedData = localStorage.getItem(RATE_LIMIT_KEY);
101
105
  var allRateData = storedData ? JSON.parse(storedData) : {};
102
- var productTimestamps = allRateData[currentArticleId] || [];
103
- productTimestamps = productTimestamps.filter(function (timestamp) {
104
- return now - timestamp < COOLDOWN_MS;
106
+ var idPart = descriptionId !== null && descriptionId !== void 0 ? descriptionId : attributeId;
107
+ var key = idPart ? "".concat(articleId, "_").concat(idPart, "_").concat(type) : "".concat(articleId);
108
+ var keyTimestamps = allRateData[key] || [];
109
+ keyTimestamps = keyTimestamps.filter(function (timestamp) {
110
+ return now - timestamp < AI_RESET_MS;
105
111
  });
106
112
 
107
- if (productTimestamps.length >= MAX_CREDITS) {
108
- allRateData[currentArticleId] = productTimestamps;
113
+ if (keyTimestamps.length >= AI_MAX_CREDITS) {
114
+ allRateData[key] = keyTimestamps;
109
115
  localStorage.setItem(RATE_LIMIT_KEY, JSON.stringify(allRateData));
110
116
  return {
111
117
  allowed: false,
112
- message: "Has alcanzado el limite de intentos frecuentes para este producto. Por favor, espera unos minutos."
118
+ message: idPart ? "Has alcanzado el límite de intentos para este atributo. Vuelve a intentarlo en 24 horas." : "Has alcanzado el límite de intentos para este producto. Vuelve a intentarlo en 24 horas."
113
119
  };
114
- }
120
+ } // Registramos el intento
115
121
 
116
- productTimestamps.push(now);
117
- allRateData[currentArticleId] = productTimestamps;
122
+
123
+ keyTimestamps.push(now);
124
+ allRateData[key] = keyTimestamps;
118
125
  localStorage.setItem(RATE_LIMIT_KEY, JSON.stringify(allRateData));
119
126
  return {
120
127
  allowed: true
121
128
  };
122
129
  };
123
130
 
124
- function setCurrentSuggestionValue(_ref2) {
125
- var inputId = _ref2.inputId,
126
- index = _ref2.index,
127
- value = _ref2.value;
131
+ function setCurrentSuggestionValue(_ref3) {
132
+ var inputId = _ref3.inputId,
133
+ index = _ref3.index,
134
+ value = _ref3.value;
128
135
  setCurrentSuggestion(function (prev) {
129
136
  return (0, _objectSpread3.default)((0, _objectSpread3.default)({}, prev), {}, (0, _defineProperty2.default)({}, inputId, {
130
137
  index: index,
@@ -142,13 +149,13 @@ var AiProductEditionProvider = function AiProductEditionProvider(_ref) {
142
149
  }
143
150
 
144
151
  function _regenerateProductSuggestions() {
145
- _regenerateProductSuggestions = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(_ref3) {
152
+ _regenerateProductSuggestions = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(_ref4) {
146
153
  var inputName, currentValue, description, maxChar, type, articleId, versionId, descriptionId, attributeId, newSuggestions;
147
154
  return _regenerator.default.wrap(function _callee$(_context) {
148
155
  while (1) {
149
156
  switch (_context.prev = _context.next) {
150
157
  case 0:
151
- inputName = _ref3.inputName, currentValue = _ref3.currentValue, description = _ref3.description, maxChar = _ref3.maxChar, type = _ref3.type, articleId = _ref3.articleId, versionId = _ref3.versionId, descriptionId = _ref3.descriptionId, attributeId = _ref3.attributeId;
158
+ inputName = _ref4.inputName, currentValue = _ref4.currentValue, description = _ref4.description, maxChar = _ref4.maxChar, type = _ref4.type, articleId = _ref4.articleId, versionId = _ref4.versionId, descriptionId = _ref4.descriptionId, attributeId = _ref4.attributeId;
152
159
 
153
160
  if (!(!description || !maxChar || !type)) {
154
161
  _context.next = 3;
@@ -218,14 +225,14 @@ var AiProductEditionProvider = function AiProductEditionProvider(_ref) {
218
225
 
219
226
 
220
227
  function _generateProductSuggestions() {
221
- _generateProductSuggestions = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(_ref4) {
222
- var _ref4$inputName, inputName, _ref4$currentValue, currentValue, _ref4$description, description, _ref4$maxChar, maxChar, _ref4$type, type, articleId, versionId, descriptionId, attributeId, _state$product, _JSON$parse, _JSON$parse2, _JSON$parse2$error, _JSON$parse$data, _JSON$parse3, rateLimitStatus, upc, productName, retailer, category, version, payload, _yield$axios$post, data, errorsRaw, errorMessage, results, _error$message;
228
+ _generateProductSuggestions = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(_ref5) {
229
+ var _ref5$inputName, inputName, _ref5$currentValue, currentValue, _ref5$description, description, _ref5$maxChar, maxChar, _ref5$type, type, articleId, versionId, descriptionId, attributeId, _state$product, _JSON$parse, _JSON$parse2, _JSON$parse2$error, _JSON$parse$data, _JSON$parse3, rateLimitStatus, upc, productName, retailer, category, version, payload, _yield$axios$post, data, errorsRaw, errorMessage, results, _error$message;
223
230
 
224
231
  return _regenerator.default.wrap(function _callee2$(_context2) {
225
232
  while (1) {
226
233
  switch (_context2.prev = _context2.next) {
227
234
  case 0:
228
- _ref4$inputName = _ref4.inputName, inputName = _ref4$inputName === void 0 ? "" : _ref4$inputName, _ref4$currentValue = _ref4.currentValue, currentValue = _ref4$currentValue === void 0 ? "" : _ref4$currentValue, _ref4$description = _ref4.description, description = _ref4$description === void 0 ? "" : _ref4$description, _ref4$maxChar = _ref4.maxChar, maxChar = _ref4$maxChar === void 0 ? 100 : _ref4$maxChar, _ref4$type = _ref4.type, type = _ref4$type === void 0 ? 'description' : _ref4$type, articleId = _ref4.articleId, versionId = _ref4.versionId, descriptionId = _ref4.descriptionId, attributeId = _ref4.attributeId;
235
+ _ref5$inputName = _ref5.inputName, inputName = _ref5$inputName === void 0 ? "" : _ref5$inputName, _ref5$currentValue = _ref5.currentValue, currentValue = _ref5$currentValue === void 0 ? "" : _ref5$currentValue, _ref5$description = _ref5.description, description = _ref5$description === void 0 ? "" : _ref5$description, _ref5$maxChar = _ref5.maxChar, maxChar = _ref5$maxChar === void 0 ? 100 : _ref5$maxChar, _ref5$type = _ref5.type, type = _ref5$type === void 0 ? 'description' : _ref5$type, articleId = _ref5.articleId, versionId = _ref5.versionId, descriptionId = _ref5.descriptionId, attributeId = _ref5.attributeId;
229
236
  _context2.prev = 1;
230
237
 
231
238
  if (isAiAvailable) {
@@ -236,7 +243,12 @@ var AiProductEditionProvider = function AiProductEditionProvider(_ref) {
236
243
  return _context2.abrupt("return");
237
244
 
238
245
  case 4:
239
- rateLimitStatus = checkAndManageRateLimit(articleId);
246
+ rateLimitStatus = checkAndManageRateLimit({
247
+ articleId: articleId,
248
+ descriptionId: descriptionId,
249
+ attributeId: attributeId,
250
+ type: type
251
+ });
240
252
 
241
253
  if (rateLimitStatus.allowed) {
242
254
  _context2.next = 7;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contentoh-components-library",
3
- "version": "21.5.99",
3
+ "version": "21.6.1",
4
4
  "dependencies": {
5
5
  "@aws-amplify/auth": "^4.5.3",
6
6
  "@aws-amplify/datastore": "^3.11.0",
@@ -12,6 +12,7 @@
12
12
  "@fortawesome/free-regular-svg-icons": "^6.2.0",
13
13
  "@fortawesome/free-solid-svg-icons": "^6.2.0",
14
14
  "@fortawesome/react-fontawesome": "^0.2.0",
15
+ "@google/genai": "^1.35.0",
15
16
  "@mui/icons-material": "^5.11.16",
16
17
  "@mui/material": "^5.12.0",
17
18
  "@mui/styled-engine-sc": "^5.12.0",
@@ -51,7 +52,8 @@
51
52
  "styled-components": "^5.3.9",
52
53
  "swiper": "^8.4.4",
53
54
  "uuid": "^8.3.2",
54
- "web-vitals": "^1.0.1"
55
+ "web-vitals": "^1.0.1",
56
+ "zod": "^4.3.5"
55
57
  },
56
58
  "scripts": {
57
59
  "start": "start-storybook -p 6006",
@@ -0,0 +1,45 @@
1
+
2
+ //Calcula el porcentaje de similitud entre la descripción generada por IA y la versión editada por el usuario.
3
+
4
+ export function getTextSimilarityPercentage(originalText, candidateText) {
5
+
6
+ if(!originalText || !candidateText) return;
7
+
8
+ const normalize = (text) => {
9
+ return text
10
+ .trim()
11
+ .toLowerCase()
12
+ .replace(/\s+/g, ' ');
13
+ };
14
+
15
+ const source = normalize(originalText);
16
+ const target = normalize(candidateText);
17
+
18
+ if (source === target) return 100;
19
+ if (source.length === 0 || target.length === 0) return 0;
20
+
21
+ const sourceLength = source.length;
22
+ const targetLength = target.length;
23
+ const distanceMatrix = Array(targetLength + 1).fill(null).map(() => []);
24
+
25
+ for (let i = 0; i <= sourceLength; i++) distanceMatrix[0][i] = i;
26
+ for (let j = 0; j <= targetLength; j++) distanceMatrix[j][0] = j;
27
+
28
+ for (let j = 1; j <= targetLength; j++) {
29
+ for (let i = 1; i <= sourceLength; i++) {
30
+ const substitutionCost = (source[i - 1] === target[j - 1]) ? 0 : 1;
31
+
32
+ distanceMatrix[j][i] = Math.min(
33
+ distanceMatrix[j - 1][i] + 1,
34
+ distanceMatrix[j][i - 1] + 1,
35
+ distanceMatrix[j - 1][i - 1] + substitutionCost
36
+ );
37
+ }
38
+ }
39
+
40
+ const editDistance = distanceMatrix[targetLength][sourceLength];
41
+ const maxLength = Math.max(sourceLength, targetLength);
42
+ const similarityScore = 1 - (editDistance / maxLength);
43
+
44
+ return similarityScore * 100;
45
+ }
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid" width="283" height="283" style="shape-rendering: auto; display: block; background: transparent;" xmlns:xlink="http://www.w3.org/1999/xlink"><g><g>
2
+ <path stroke-width="10" stroke="#e13aa7" fill="none" d="M50 27A23 23 0 1 0 69.9785248320784 38.604450626054636"></path>
3
+ <path fill="#e13aa7" d="M49 15L49 39L61 27L49 15"></path>
4
+ <animateTransform keyTimes="0;1" values="0 50 50;360 50 50" dur="0.9803921568627451s" repeatCount="indefinite" type="rotate" attributeName="transform"></animateTransform>
5
+ </g><g></g></g><!-- [ldio] generated by https://loading.io --></svg>
@@ -38,6 +38,10 @@ export const Container = styled.button`
38
38
  background-color: #603888;
39
39
  }
40
40
 
41
+ &.general-pink-button {
42
+ background-color: #E33AA9;
43
+ }
44
+
41
45
  &.general-transparent-button {
42
46
  background-color: transparent;
43
47
  border: 1px solid #503d66;