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
@@ -0,0 +1,1979 @@
1
+ import { Container } from "./styles";
2
+ import { HeaderTop } from "../../molecules/HeaderTop";
3
+ import { ImagePreviewer } from "../../organisms/ImagePreviewer";
4
+ import { ImageDataTable } from "../../organisms/ImageDataTable";
5
+ import { FullProductNameHeader } from "../../organisms/FullProductNameHeader";
6
+ import { FullTabsMenu } from "../../organisms/FullTabsMenu";
7
+ import { InputGroup } from "../../organisms/InputGroup";
8
+ import { useEffect, useReducer, useState, useCallback } from "react";
9
+ import { GalleryElement } from "../../molecules/GalleryElement";
10
+ import { saveAs } from "file-saver";
11
+ import { Commentary } from "../../atoms/Commentary";
12
+ import {
13
+ getRetailerServices,
14
+ getPercentage,
15
+ fetchUsers,
16
+ } from "../../../global-files/data";
17
+ import { GalleryHeader } from "../../molecules/GalleryHeader";
18
+ import { ProductImageModal } from "../../organisms/ProductImageModal";
19
+ import { useDropzone } from "react-dropzone";
20
+ import axios from "axios";
21
+ import { v4 as uuidv4 } from "uuid";
22
+ import AWS from "aws-sdk";
23
+ import attributesSent from "../../../assets/images/modalsSVGs/attributesSent.svg";
24
+ import descriptionSent from "../../../assets/images/modalsSVGs/descriptionSent.svg";
25
+ import imagesSent from "../../../assets/images/modalsSVGs/uploadingImages.svg";
26
+ import { TagAndInput } from "../../molecules/TagAndInput/index";
27
+ import { Button } from "../../atoms/GeneralButton";
28
+ import { GenericModal } from "../../atoms/GenericModal";
29
+ import { ScreenHeader } from "../../atoms/ScreenHeader";
30
+ import { Loading } from "../../atoms/Loading";
31
+ import succes from "../../../assets/images/genericModal/genericModalCheck.svg";
32
+ import { VersionSelector } from "../../organisms/VersionSelector";
33
+ import { useCloseModal } from "../../../global-files/customHooks";
34
+ import {
35
+ getAuditVersion,
36
+ getInputsData,
37
+ createMessage,
38
+ sendMessage,
39
+ } from "./utils";
40
+ import { Modal } from "../../organisms/Modal";
41
+ import { ButtonV2 } from "../../atoms/ButtonV2";
42
+ import generateThumbnail from "./generateThumnail";
43
+
44
+ const reducerImages = (state, action) => {
45
+ let { values, attrForImgs, inputsByRetailer } = state;
46
+ switch (action.action) {
47
+ case "init":
48
+ const newInputsByRetailer = {};
49
+ action?.init?.inputsByRetailer?.forEach((inputs) => {
50
+ inputs?.forEach((input) => {
51
+ if (!newInputsByRetailer[`${input.id_retailer}`])
52
+ newInputsByRetailer[`${input.id_retailer}`] = [];
53
+ newInputsByRetailer[`${input.id_retailer}`].push(input);
54
+ });
55
+ });
56
+ inputsByRetailer = newInputsByRetailer;
57
+ return {
58
+ ...action.init,
59
+ inputsByRetailer,
60
+ valuesInitial: action.init.values,
61
+ inputsInitial: action.init.inputs,
62
+ };
63
+ case "addImg":
64
+ values = [...values, action.img];
65
+ return { ...state, values };
66
+ case "changeImageInfo":
67
+ values[action.index][action.attribute] = action.value;
68
+ return { ...state, values };
69
+ case "changeShotType":
70
+ values[action.index][action.attribute] = action.value;
71
+ return { ...state, values };
72
+
73
+ case "changeAttrValue":
74
+ const index = attrForImgs.general.findIndex((f) => f.id === action.id);
75
+ if (index !== -1) {
76
+ attrForImgs.general[index].value = action.value;
77
+ }
78
+
79
+ return { ...state, attrForImgs, values };
80
+ case "deleteImage":
81
+ values = values.filter(
82
+ (value) => action.selectedImages.indexOf(value) === -1
83
+ );
84
+ return { ...state, values };
85
+ case "orderImages": {
86
+ let { inputsByRetailer, valuesInitial, inputsInitial, inputs } = state;
87
+ try {
88
+ const orderedImages = [];
89
+ const imageIdArray = [];
90
+ if (action?.retailerId && !inputsByRetailer[action.retailerId]) {
91
+ inputsByRetailer[action.retailerId] = [];
92
+ }
93
+ action.retailerId &&
94
+ inputsByRetailer[action.retailerId]?.filter((input) => {
95
+ imageIdArray.push(input.id_image);
96
+ valuesInitial.forEach(async (value) => {
97
+ if (value.ext == "mp4") {
98
+ convertirVideoABase64(
99
+ "https://" +
100
+ process.env.REACT_APP_IMAGES_BUCKET +
101
+ ".s3.amazonaws.com/" +
102
+ value.srcDB
103
+ )
104
+ .then(async (base64) => {
105
+ const videoSrc =
106
+ "data:video/mp4;base64," + base64.split(",")[1]; // Añade el tipo MIME adecuado
107
+ value.src = await generateThumbnail(videoSrc, 2);
108
+ })
109
+ .catch((error) => {
110
+ console.error("Error:", error);
111
+ });
112
+ }
113
+ if (value.image_id === input.id_image) orderedImages.push(value);
114
+ });
115
+ });
116
+ inputs = inputsInitial?.filter((input) =>
117
+ imageIdArray.includes(input.id)
118
+ );
119
+
120
+ values = orderedImages.length > 0 ? orderedImages : [];
121
+ } catch (error) {
122
+ console.log(error);
123
+ }
124
+ return { ...state, values, inputs };
125
+ }
126
+ default:
127
+ return state;
128
+ }
129
+ };
130
+
131
+ const S3_BUCKET = process.env.REACT_APP_IMAGES_BUCKET;
132
+ const REGION = "us-east-1";
133
+
134
+ function convertirVideoABase64(url) {
135
+ return new Promise((resolve, reject) => {
136
+ const xhr = new XMLHttpRequest();
137
+ xhr.open("GET", url, true);
138
+ xhr.responseType = "blob";
139
+ xhr.onload = function () {
140
+ if (xhr.status === 200) {
141
+ const blob = xhr.response;
142
+ const reader = new FileReader();
143
+ reader.onloadend = function () {
144
+ resolve(reader.result);
145
+ };
146
+ reader.readAsDataURL(blob);
147
+ } else {
148
+ reject(new Error("Error al cargar el video"));
149
+ }
150
+ };
151
+ xhr.onerror = function () {
152
+ reject(new Error("Error de red al cargar el video"));
153
+ };
154
+ xhr.send();
155
+ });
156
+ }
157
+
158
+ function obtenerDuracionVideoBase64(base64Data) {
159
+ return new Promise((resolve, reject) => {
160
+ const video = document.createElement("video");
161
+ video.src = base64Data;
162
+ video.addEventListener("loadedmetadata", () => {
163
+ resolve(video.duration);
164
+ });
165
+ video.addEventListener("error", reject);
166
+ });
167
+ }
168
+
169
+ AWS.config.update({
170
+ accessKeyId: process.env.REACT_APP_KUTS3,
171
+ secretAccessKey: process.env.REACT_APP_AKUTS3,
172
+ });
173
+
174
+ const myBucket = new AWS.S3({
175
+ params: { Bucket: S3_BUCKET },
176
+ region: REGION,
177
+ });
178
+
179
+ export const RetailerProductEdition = ({
180
+ tabsSections,
181
+ productSelected = {},
182
+ user = {},
183
+ token,
184
+ location,
185
+ }) => {
186
+ const [activeTab, setActiveTab] = useState("Descripción");
187
+ const [activeImage, setActiveImage] = useState();
188
+ const [imageLayout, setImageLayout] = useState(false);
189
+ const [headerTop, setHeaderTop] = useState(0);
190
+ const [descriptions, setDescriptions] = useState([]);
191
+ const [datasheets, setDatasheets] = useState([]);
192
+ const [images, setImages] = useReducer(reducerImages, {});
193
+ const [showModal, setShowModal] = useState(false);
194
+ const [showRejectModal, setShowRejectModal] = useState(false);
195
+ const { getRootProps, getInputProps } = useDropzone({
196
+ accept: "image/*, video/mp4",
197
+ noKeyboard: true,
198
+ multiple: true,
199
+ noClick: true,
200
+ onDrop: (acceptedFiles) => {
201
+ const newImages = [];
202
+ acceptedFiles.map((file) => {
203
+ const reader = new FileReader();
204
+ reader.fileName = file.name;
205
+ reader.onload = async function (e) {
206
+ const ext = e.srcElement.fileName.split(".");
207
+ const img = new Image();
208
+ if (ext[ext.length - 1] == "mp4") {
209
+ obtenerDuracionVideoBase64(e.target.result)
210
+ .then(async (duracion) => {
211
+ if (duracion > 15 && duracion < 600) {
212
+ img.src = await generateThumbnail(e.target.result, 2);
213
+ setTimeout(() => {
214
+ const width = img.width;
215
+ const height = img.height;
216
+ const newImg = {
217
+ action: "addImg",
218
+ img: {
219
+ src: img.src, //e.target.result,
220
+ name: e.target.fileName,
221
+ ext: ext[ext.length - 1],
222
+ width: width,
223
+ height: height,
224
+ video_src:
225
+ ext[ext.length - 1] == "mp4" ? e.target.result : "",
226
+ },
227
+ };
228
+ setImages(newImg);
229
+ }, 500);
230
+ } else {
231
+ setModalAlert({
232
+ show: true,
233
+ title: "Hubo un error al subir el video",
234
+ message:
235
+ "Los videos deben durar entre 15 segundos y 10 minutos",
236
+ });
237
+ }
238
+ })
239
+ .catch((error) => {
240
+ console.error("Error al obtener la duración del video:", error);
241
+ });
242
+ } else {
243
+ img.src = e.target.result;
244
+ setTimeout(() => {
245
+ const width = img.width;
246
+ const height = img.height;
247
+ const newImg = {
248
+ action: "addImg",
249
+ img: {
250
+ src: img.src, //e.target.result,
251
+ name: e.target.fileName,
252
+ ext: ext[ext.length - 1],
253
+ width: width,
254
+ height: height,
255
+ video_src:
256
+ ext[ext.length - 1] == "mp4" ? e.target.result : "",
257
+ },
258
+ };
259
+ setImages(newImg);
260
+ }, 500);
261
+ }
262
+ };
263
+ reader.onerror = function (error) {
264
+ console.log("dropzoneError: ", error);
265
+ };
266
+ reader.readAsDataURL(file);
267
+ return file;
268
+ });
269
+ },
270
+ });
271
+ const [updatedDatasheets, setUpdatedDatasheets] = useState([]);
272
+ const [updatedDescriptions, setUpdatedDescriptions] = useState([]);
273
+ const [imagesUploaded, setImagesUploaded] = useState(false);
274
+ const [dataImages, setDataImages] = useState();
275
+ const [percentages, setPercentages] = useState(
276
+ new Array(product?.retailers?.length).fill({ percentage: 0 })
277
+ );
278
+ // const [percentages, setPercentages] = useState([{ retailers: {} }]);
279
+ const [activePercentage, setActivePercentage] = useState(0);
280
+ const [activeRetailer, setActiveRetailer] = useState({});
281
+ const [services, setServices] = useState([]);
282
+ const [servicesData, setServicesData] = useState([]);
283
+ const [message, setMessage] = useState("");
284
+ const [product, setProduct] = useState(
285
+ JSON.parse(sessionStorage.getItem("productSelected"))
286
+ ? JSON.parse(sessionStorage.getItem("productSelected"))
287
+ : productSelected
288
+ );
289
+ const [icon, setIcon] = useState(null);
290
+ const [version, setVersion] = useState(product?.version);
291
+ const [comments, setComments] = useState({});
292
+ const [comment, setComment] = useState("");
293
+ const [requiredNull, setRequiredNull] = useState({
294
+ "Ficha técnica": 0,
295
+ Descripción: 0,
296
+ Imágenes: 0,
297
+ });
298
+ const [crossComment, setCrossComment] = useState(false);
299
+ const [userGroups, setUserGroups] = useState([]);
300
+ const [assig, setAssig] = useState({});
301
+ const [selectedImages, setSelectedImages] = useState([]);
302
+ const [componentsArray, setComponentsArray] = useState([]);
303
+ const [checkAll, setCheckAll] = useState(false);
304
+ const isRetailer = user?.is_retailer;
305
+ const [loading, setLoading] = useState(true);
306
+ const [retailerStatus, setRetailerStatus] = useState("-");
307
+ const [statusArray, setStatusArray] = useState([]);
308
+ const [socketType, setSocketType] = useState(null);
309
+ const [saving, setSaving] = useState(loading);
310
+ const [showVersionSelector, setShowVersionSelector] =
311
+ useCloseModal("version-selector");
312
+ const shotThd = [58, 59, 60, 61].includes(activeRetailer.id);
313
+ const [auditableVersion, setAuditableVersion] = useState(null);
314
+ const [auditServices, setAuditServices] = useState([]);
315
+ const [auditDatasheets, setAuditDatasheets] = useState([]);
316
+ const [auditDescriptions, setAuditDescriptions] = useState([]);
317
+ const [auditImages, setAuditImages] = useState([]);
318
+ const [compare, setCompare] = useState(false);
319
+ const [observation, setObservation] = useState();
320
+ const [valRejAll, setValRejAll] = useState(false);
321
+ const [modalAlert, setModalAlert] = useState({
322
+ show: false,
323
+ title: "",
324
+ message: "",
325
+ errorInputMessage: false,
326
+ });
327
+
328
+ const [desc, setDesc] = useState([]);
329
+ const [fich, setFich] = useState([]);
330
+ const [imag, setImag] = useState([]);
331
+
332
+ const [isObservationVisible, setObservationVisible] = useState(false);
333
+
334
+ const toggleObservation = () => {
335
+ setObservationVisible(!isObservationVisible);
336
+ };
337
+ // const handleClickOutside = (event) => {
338
+ // if (
339
+ // isObservationVisible &&
340
+ // !event.target.closest(".Observation") &&
341
+ // !event.target.closest(".Container")
342
+ // ) {
343
+ // hideObservation();
344
+ // }
345
+ // };
346
+
347
+ // useEffect(() => {
348
+ // document.addEventListener("click", handleClickOutside);
349
+ // return () => {
350
+ // document.removeEventListener("click", handleClickOutside);
351
+ // };
352
+ // }, [isObservationVisible]);
353
+
354
+ const hideObservation = () => {
355
+ setObservationVisible(false);
356
+ };
357
+
358
+ const handleCommentSubmit = (e) => {
359
+ e.preventDefault();
360
+ const commentText = document.querySelector(
361
+ "#commentary-box .ql-container .ql-editor > p"
362
+ ).innerHTML;
363
+ createComment(e, commentText, activeTab);
364
+ };
365
+
366
+ useEffect(async () => {
367
+ const { id_article } = product?.article || {};
368
+ if (id_article)
369
+ await getAuditVersion(id_article, setAuditableVersion, token);
370
+ }, []);
371
+
372
+ const loadAuditableData = async () => {
373
+ if (auditableVersion) {
374
+ const auditServices = await getRetailerServices(
375
+ product?.article?.id_article,
376
+ product?.article?.category,
377
+ parseInt(product?.article?.id_category),
378
+ auditableVersion.version,
379
+ token
380
+ );
381
+ getInputsData(
382
+ auditServices,
383
+ activeRetailer,
384
+ setAuditDatasheets,
385
+ setAuditDescriptions
386
+ );
387
+ setAuditServices(auditServices);
388
+ setAuditImages(auditServices[2]);
389
+ }
390
+ };
391
+
392
+ useEffect(() => {
393
+ if (auditableVersion) {
394
+ loadAuditableData();
395
+ }
396
+ }, [auditableVersion]);
397
+
398
+ useEffect(() => {
399
+ checkAll && setSelectedImages(images.values);
400
+ }, [checkAll]);
401
+
402
+ const loadData = async () => {
403
+ try {
404
+ setLoading(true);
405
+
406
+ const ids =
407
+ product?.statusByRetailer?.map((item) => item.retailer_id) ??
408
+ product?.statusByRetailer?.map((item) => item.id_retailer) ??
409
+ [];
410
+ const uniqueIds = [...new Set(ids)];
411
+
412
+ let activeRetailerId = activeRetailer?.id;
413
+ if (!activeRetailerId) {
414
+ const firstValid = product?.article?.categoryRetailer?.find((item) =>
415
+ uniqueIds.includes(item.id_retailer || item.retailer_id)
416
+ );
417
+ if (firstValid) {
418
+ activeRetailerId = firstValid.id_retailer || firstValid.retailer_id;
419
+ }
420
+ }
421
+
422
+ const categoryRetailer =
423
+ product?.article?.categoryRetailer?.filter(
424
+ (item) =>
425
+ uniqueIds.includes(item.id_retailer) &&
426
+ item.id_retailer === activeRetailerId
427
+ ) ??
428
+ product?.article?.categoryRetailer?.filter(
429
+ (item) =>
430
+ uniqueIds.includes(item.retailer_id) &&
431
+ item.retailer_id === activeRetailerId
432
+ ) ??
433
+ [];
434
+
435
+ const categoryName = categoryRetailer[0]?.category_name;
436
+ const categoryId = categoryRetailer[0]?.id_category;
437
+
438
+ const category_name =
439
+ categoryName ??
440
+ (product?.article?.company_name || product?.categoryName);
441
+ const category_id =
442
+ categoryId ??
443
+ parseInt(product?.article?.id_category || product?.id_category);
444
+
445
+ const retailer_id = activeRetailerId ?? categoryRetailer?.id_retailer;
446
+
447
+ const services = await getRetailerServices(
448
+ product?.id_article || product?.article?.id_article,
449
+ category_name,
450
+ category_id,
451
+ version,
452
+ token,
453
+ retailer_id
454
+ );
455
+
456
+ if (auditableVersion && retailer_id) {
457
+ loadAuditableData();
458
+ }
459
+
460
+ setServices(services);
461
+ const generalServices = await getServices();
462
+
463
+ setImages({ action: "init", init: services[2] });
464
+
465
+ if (services[2]?.values?.length > 0) setActiveImage(0);
466
+
467
+ const data = [
468
+ {
469
+ id_article: product?.article?.id_article,
470
+ relations: [
471
+ {
472
+ id_retailer: retailer_id,
473
+ id_category: category_id,
474
+ },
475
+ ],
476
+ version: product.version,
477
+ },
478
+ ];
479
+
480
+ const headers = { Authorization: token };
481
+ getPercentage({ data, headers }).then((res) => {
482
+ setPercentages(JSON.parse(res?.[0]?.body));
483
+ });
484
+
485
+ setImages({ action: "orderImages", retailerId: activeRetailer.id });
486
+
487
+ setLoading(false);
488
+ } catch (error) {
489
+ setLoading(false);
490
+ console.log(error);
491
+ }
492
+ };
493
+
494
+ useEffect(() => {
495
+ setLoading(true);
496
+ loadData();
497
+ }, [activeRetailer]);
498
+
499
+ const getServices = async () => {
500
+ const servicesResponse = await axios.get(
501
+ `${process.env.REACT_APP_SERVICES_ENDPOINT}?articleId=${
502
+ product?.article?.id_article
503
+ }&orderId=${product?.article?.id_order || product.orderId}&end=true`
504
+ );
505
+ const parsedResponse = JSON.parse(servicesResponse?.data?.body).data;
506
+
507
+ const retailers = product.retailers || product.retailersAvailable;
508
+ const retailerResponse = parsedResponse?.map((srv) => srv.id_retailer);
509
+ const active = retailers?.find((retailer) =>
510
+ retailerResponse.includes(retailer.id)
511
+ );
512
+ !activeRetailer.id && setActiveRetailer(active ? active : retailers[0]);
513
+ setServicesData(parsedResponse);
514
+ };
515
+
516
+ const translateConcept = (concept) => {
517
+ const translation = {
518
+ datasheet: "Ficha técnica",
519
+ description: "Descripción",
520
+ images: "Imágenes",
521
+ };
522
+ return translation[concept];
523
+ };
524
+
525
+ const getComments = async (tab = "Descripción") => {
526
+ const commentsResponse = await Promise.all([
527
+ axios.get(
528
+ `${process.env.REACT_APP_COMMENTS_ENDPOINT}?articleId=${product?.article?.id_article}&concept=description&orderIdColab=${product?.orderId}&version=${version}`
529
+ ),
530
+ axios.get(
531
+ `${process.env.REACT_APP_COMMENTS_ENDPOINT}?articleId=${product?.article?.id_article}&concept=datasheet&orderIdColab=${product?.orderId}&version=${version}`
532
+ ),
533
+ axios.get(
534
+ `${process.env.REACT_APP_COMMENTS_ENDPOINT}?articleId=${product?.article?.id_article}&concept=images&orderIdColab=${product?.orderId}&version=${version}`
535
+ ),
536
+ ]);
537
+
538
+ let comments = {};
539
+ commentsResponse.forEach(
540
+ (comment) =>
541
+ JSON.parse(comment?.data?.body).data[0] &&
542
+ (comments[
543
+ translateConcept(JSON.parse(comment?.data?.body)?.data[0]?.concept)
544
+ ] = JSON.parse(comment?.data?.body).data[0])
545
+ );
546
+ setComment(comments[tab]);
547
+ setComments(comments);
548
+ };
549
+
550
+ useEffect(async () => {
551
+ setLoading(true);
552
+ // loadData();
553
+ getComments();
554
+ setUserGroups(await fetchUsers(token));
555
+ let arr = [];
556
+ switch (user.id_role) {
557
+ case 7:
558
+ case 8:
559
+ arr = ["PA", "AS", "CA", "RC", "RA", "RP", "RCA"];
560
+ break;
561
+ case 4:
562
+ case 5:
563
+ arr = ["RC", "AC", "AA", "AP", "ACA"];
564
+ break;
565
+ case 6:
566
+ arr = ["RP", "RCA", "AC", "RA"];
567
+ break;
568
+ default:
569
+ arr = [];
570
+ break;
571
+ }
572
+ setStatusArray(arr);
573
+ setLoading(false);
574
+ }, [product, version]);
575
+
576
+ const loadAssignations = (currentProduct) => {
577
+ setAssig({
578
+ Descripción: {
579
+ assignations: [
580
+ {
581
+ collaboratorType: "especialist",
582
+ id: currentProduct?.article?.id_description_especialist,
583
+ },
584
+ {
585
+ collaboratorType: "facilitator",
586
+ id: currentProduct?.article?.id_description_facilitator,
587
+ },
588
+ ],
589
+ collaborators: {
590
+ especialist: userGroups[0] || [],
591
+ facilitator: userGroups[2] || [],
592
+ },
593
+ },
594
+ "Ficha técnica": {
595
+ assignations: [
596
+ {
597
+ collaboratorType: "especialist",
598
+ id: currentProduct?.article?.id_datasheet_especialist,
599
+ },
600
+ {
601
+ collaboratorType: "facilitator",
602
+ id: currentProduct?.article?.id_datasheet_facilitator,
603
+ },
604
+ ],
605
+ collaborators: {
606
+ especialist: userGroups[0] || [],
607
+ facilitator: userGroups[2] || [],
608
+ },
609
+ },
610
+ Imágenes: {
611
+ assignations: [
612
+ {
613
+ collaboratorType: "especialist",
614
+ id: currentProduct?.article?.id_images_especialist,
615
+ },
616
+ {
617
+ collaboratorType: "facilitator",
618
+ id: currentProduct?.article?.id_images_facilitator,
619
+ },
620
+ ],
621
+ collaborators: {
622
+ especialist: userGroups[1] || [],
623
+ facilitator: userGroups[3] || [],
624
+ },
625
+ },
626
+ });
627
+ };
628
+
629
+ useEffect(() => {
630
+ loadAssignations(product);
631
+ }, [userGroups]);
632
+
633
+ useEffect(() => {
634
+ const retailerPercentages =
635
+ percentages?.[0]?.relations?.[0]?.percentagesGeneral;
636
+
637
+ const requiredPercentage = retailerPercentages?.required;
638
+
639
+ setActivePercentage(requiredPercentage);
640
+
641
+ // const retailers = product?.retailersAvailable || product?.retailers;
642
+ // if (
643
+ // Object.keys(percentages[product.article.id_article] ?? {})?.length > 0
644
+ // ) {
645
+ // retailers?.forEach((retailer, index) => {
646
+ // retailer["percentage"] = Number(
647
+ // percentages[product.article.id_article][retailer.id]
648
+ // ?.percentageRequired
649
+ // );
650
+ // });
651
+ // }
652
+ // setActivePercentage(retailers[0]?.percentage);
653
+ }, [percentages]);
654
+
655
+ useEffect(() => {
656
+ getInputsData(services, activeRetailer, setDatasheets, setDescriptions);
657
+ auditableVersion && loadAuditableData();
658
+ setActivePercentage(Math.round(activeRetailer?.percentage, 0));
659
+ activeRetailer?.id &&
660
+ setImages({ action: "orderImages", retailerId: activeRetailer.id });
661
+ }, [activeRetailer, services]);
662
+
663
+ const thumbs = () => {
664
+ const imageInputs = socketType?.slice();
665
+ const imageType = images?.imageType?.map((e) => ({
666
+ value: e?.id,
667
+ name: e?.name,
668
+ }));
669
+ const imagePackagingType = images?.imagePackagingType?.map((e) => ({
670
+ value: e?.id,
671
+ name: e?.name,
672
+ }));
673
+ const imageShotType = images?.imageShotType?.map((e) => ({
674
+ value: e?.id,
675
+ name: e?.type_shot,
676
+ }));
677
+ return images?.values?.map((image, index) => (
678
+ <GalleryElement
679
+ setCheckAll={setCheckAll}
680
+ key={index + "-" + image.name}
681
+ image={image}
682
+ gridLayout={imageLayout}
683
+ id={"gallery-element-" + index}
684
+ index={index + "-" + image.name + "-" + compare}
685
+ number={index}
686
+ imageType={imageType}
687
+ imagePackagingType={imagePackagingType}
688
+ imageInputs={imageInputs}
689
+ imageShotType={imageShotType}
690
+ setSocketType={setSocketType}
691
+ changeImage={setImages}
692
+ selectedImages={selectedImages}
693
+ setSelectedImages={setSelectedImages}
694
+ auditImages={auditImages}
695
+ compare={compare}
696
+ />
697
+ ));
698
+ };
699
+
700
+ const saveDescriptions = async () => {
701
+ const dataClean = updatedDescriptions.filter((f) => f.value !== "");
702
+ if (dataClean.length > 0) {
703
+ setLoading(true);
704
+ const productTemp = product;
705
+ const articleId = product?.article?.id_article;
706
+ const dataObject = {
707
+ articleId,
708
+ articleData: dataClean,
709
+ };
710
+ if (product?.orderId) dataObject["orderId"] = product?.orderId;
711
+ try {
712
+ const res = await axios.put(
713
+ `${process.env.REACT_APP_ARTICLE_DATA_ENDPOINT}?description=true&version=${version}`,
714
+ dataObject,
715
+ {
716
+ headers: {
717
+ Authorization: token,
718
+ },
719
+ }
720
+ );
721
+ if (res.data.statusCode === 200) {
722
+ const { newStatus, newArticleStatus } = JSON.parse(res.data.body);
723
+ if (newArticleStatus)
724
+ productTemp.status = newArticleStatus[articleId];
725
+ if (newStatus) productTemp.description_status = newStatus;
726
+ setProduct(productTemp);
727
+ sessionStorage.setItem(
728
+ "productSelected",
729
+ JSON.stringify(productTemp)
730
+ );
731
+
732
+ setUpdatedDescriptions([]);
733
+ setMessage("Descripciones guardadas con éxito");
734
+ await loadData();
735
+ }
736
+ } catch (error) {
737
+ console.log(error);
738
+ } finally {
739
+ setLoading(false);
740
+ }
741
+ }
742
+ };
743
+
744
+ const saveDatasheets = async () => {
745
+ const dataClean = updatedDatasheets.filter((f) => f.value !== "");
746
+ if (dataClean.length > 0) {
747
+ setLoading(true);
748
+ const productTemp = product;
749
+ const articleId = product?.article?.id_article;
750
+ const dataObject = {
751
+ articleId,
752
+ articleData: dataClean,
753
+ };
754
+ if (product?.orderId) dataObject["orderId"] = product?.orderId;
755
+ try {
756
+ const res = await axios.put(
757
+ `${process.env.REACT_APP_ARTICLE_DATA_ENDPOINT}?datasheet=true&version=${version}`,
758
+ dataObject,
759
+ {
760
+ headers: {
761
+ Authorization: token,
762
+ },
763
+ }
764
+ );
765
+ if (res.data.statusCode === 200) {
766
+ const { newStatus, newArticleStatus } = JSON.parse(res.data.body);
767
+ if (newArticleStatus)
768
+ productTemp.status = newArticleStatus[articleId];
769
+ if (newStatus) productTemp.datasheet_status = newStatus;
770
+ setProduct(productTemp);
771
+ sessionStorage.setItem(
772
+ "productSelected",
773
+ JSON.stringify(productTemp)
774
+ );
775
+ setUpdatedDatasheets([]);
776
+ setMessage("Fichas técnicas guardadas");
777
+ await loadData();
778
+ }
779
+ } catch (error) {
780
+ console.log(error);
781
+ } finally {
782
+ setLoading(false);
783
+ }
784
+ }
785
+ };
786
+
787
+ useEffect(() => {
788
+ const imageInputs = images?.inputs?.map((e) => ({
789
+ value: e?.id,
790
+ name: e?.name,
791
+ required: e?.required,
792
+ active: images?.values?.some((value) => value?.image_id === e?.id),
793
+ }));
794
+ setSocketType(imageInputs);
795
+ }, [images]);
796
+
797
+ const updateImages = useCallback(async () => {
798
+ const imagesList = images?.values?.slice();
799
+ const imagesListTemp = imagesList?.reduce((acc, image) => {
800
+ acc[image?.image_id] = ++acc[image?.image_id] || 0;
801
+ return acc;
802
+ }, {});
803
+
804
+ const duplicated = imagesList?.filter((image) => {
805
+ return imagesListTemp[image?.image_id];
806
+ });
807
+
808
+ const attrForImgs = Object.values(images?.attrForImgs ?? {}).pop();
809
+ const data = {
810
+ articleId: product?.article?.id_article,
811
+ attrReqImgs: attrForImgs?.map((e) => ({
812
+ attrId: e.id,
813
+ value: e.value ?? "-",
814
+ })),
815
+ articleData: imagesList?.filter((e) => !e.id),
816
+ updateImages: imagesList?.filter((e) => e.id),
817
+ };
818
+ if (product?.orderId) data["orderId"] = product?.orderId;
819
+ let valid =
820
+ data?.articleData?.length === 0
821
+ ? true
822
+ : data?.articleData?.every((e, i) => {
823
+ // if (e?.image_id && e?.packing_type && e?.image_type) {
824
+ if (e?.image_id) {
825
+ return true;
826
+ }
827
+ return false;
828
+ });
829
+ if (valid && data?.updateImages?.length > 0 && duplicated?.length === 0) {
830
+ valid = data?.updateImages?.every((e, i) => {
831
+ // if (e?.image_id && e?.packing_type && e?.image_type) {
832
+ if (e?.image_id) {
833
+ return true;
834
+ }
835
+ return false;
836
+ });
837
+ }
838
+ if (valid && duplicated?.length === 0) {
839
+ setLoading(true);
840
+ try {
841
+ data?.articleData?.forEach((e) => {
842
+ e.uuid = uuidv4();
843
+ });
844
+ setDataImages(data);
845
+ if (data?.articleData?.length > 0) {
846
+ setImagesUploaded(false);
847
+ const promiseArray = [];
848
+ data?.articleData?.forEach((e) => {
849
+ let file;
850
+ if (e.ext == "mp4") {
851
+ file = Buffer.from(
852
+ e.video_src.replace(/^data:video\/\w+;base64,/, ""),
853
+ "base64"
854
+ );
855
+ e.video_src = "";
856
+ } else {
857
+ file = Buffer.from(
858
+ e.src.replace(/^data:image\/\w+;base64,/, ""),
859
+ "base64"
860
+ );
861
+ }
862
+ const params = {
863
+ ACL: "public-read",
864
+ Body: file,
865
+ Bucket: S3_BUCKET,
866
+ Key: `id-${data.articleId}/${version}/${e?.image_id}-${e?.uuid}.${e?.ext}`,
867
+ };
868
+ promiseArray.push(myBucket.putObject(params).promise());
869
+ });
870
+ await Promise.all(promiseArray);
871
+ setImagesUploaded(true);
872
+ } else {
873
+ setImagesUploaded(true);
874
+ }
875
+ } catch (err) {
876
+ console.log(err);
877
+ // setMainLoading(false);
878
+ } finally {
879
+ setLoading(false);
880
+ }
881
+ } else {
882
+ // setMainLoading(false);
883
+ setMessage(
884
+ "Completa los campos que solicita cada una de la imágenes o hay imágenes con el mismo tipo de toma.\nRecuerda hay campos obligatorios y no podras avanzar si no estan completos."
885
+ );
886
+ }
887
+ // eslint-disable-next-line react-hooks/exhaustive-deps
888
+ }, [images, imagesUploaded]);
889
+
890
+ useEffect(async () => {
891
+ if (imagesUploaded) {
892
+ dataImages.articleData = dataImages?.articleData.map((e) => {
893
+ delete e.src;
894
+ e.imageID = e.image_id;
895
+ // e.packingType = e.packing_type;
896
+ // e.imageType = e.image_type;
897
+ if (product?.orderId) e["orderId"] = product?.orderId;
898
+ return e;
899
+ });
900
+ try {
901
+ const res = await axios.put(
902
+ `${process.env.REACT_APP_ARTICLE_DATA_ENDPOINT}?image=true&version=${version}`,
903
+ dataImages,
904
+ {
905
+ headers: {
906
+ Authorization: token,
907
+ },
908
+ }
909
+ );
910
+ if (res.data.statusCode === 200) {
911
+ let productTemp = product;
912
+ const { newStatus, newArticleStatus } = JSON.parse(res.data.body);
913
+ if (newArticleStatus)
914
+ productTemp.status = newArticleStatus[product?.article?.id_article];
915
+ if (newStatus) productTemp.images_status = newStatus;
916
+ setProduct(productTemp);
917
+ sessionStorage.setItem(
918
+ "productSelected",
919
+ JSON.stringify(productTemp)
920
+ );
921
+ setImages({});
922
+ setMessage("Imágenes guardadas con éxito");
923
+ sessionStorage.removeItem("imagesList");
924
+ }
925
+ await loadData();
926
+ } catch (error) {
927
+ console.log(error);
928
+ }
929
+ }
930
+ }, [dataImages, imagesUploaded]);
931
+
932
+ const evaluationFinished = (userId, tab, statusArray) => {
933
+ const srv = servicesData.filter((serv) => serv.service === getConcept(tab));
934
+ const srvActive = srv
935
+ .find((serv) => serv.id_retailer === activeRetailer?.id)
936
+ ?.status?.replace(/.*\//, "");
937
+ const currStatus = product[`${getConcept(tab)}_status`]?.replace(
938
+ /.*\//,
939
+ ""
940
+ );
941
+ const unvalidated = ["IE", "CA"].includes(currStatus);
942
+
943
+ const auditorUnvalidated = !["RA", "AA", "ACA", "AP"].includes(currStatus);
944
+
945
+ switch (userId) {
946
+ case 7:
947
+ case 8:
948
+ return (
949
+ (statusArray.includes(srvActive) &&
950
+ statusArray.includes(product?.status)) ||
951
+ srv.filter((serv) =>
952
+ statusArray.includes(serv.status?.replace(/.*\//, ""))
953
+ ).length === srv.length
954
+ );
955
+ case 4:
956
+ case 5:
957
+ return (
958
+ unvalidated &&
959
+ ["CA", "IE"].includes(product.status) && // "RC", "AC", "AA", "AP", "ACA"
960
+ srv.filter((serv) => statusArray.includes(serv.status)).length ===
961
+ srv.length
962
+ );
963
+ case 6:
964
+ return (
965
+ statusArray.includes(product.status) && // RP, RCA, AC, RA true
966
+ srv.every((serv) =>
967
+ ["RA", "AA", "AP", "ACA"].includes(serv.status)
968
+ ) &&
969
+ auditorUnvalidated
970
+ );
971
+ default:
972
+ break;
973
+ }
974
+ };
975
+
976
+ const getConcept = (tab) => {
977
+ switch (tab) {
978
+ case "Descripción":
979
+ return "description";
980
+ case "Ficha técnica":
981
+ return "datasheet";
982
+ case "Imágenes":
983
+ return "images";
984
+ }
985
+ };
986
+
987
+ const approveRejectButtons = (action) => {
988
+ let concept = getConcept(action || activeTab);
989
+
990
+ const retailerStatus = servicesData
991
+ .find(
992
+ (srv) =>
993
+ srv.id_retailer === activeRetailer?.id && srv.service === concept
994
+ )
995
+ ?.status?.replace(/.*\//, "");
996
+
997
+ //sessionStorage product
998
+ const adminFacilitatorCanEvaluate =
999
+ retailerStatus === "IE" && [1, 4, 5].includes(user.id_role);
1000
+ const adminAuditorCanEvaluate =
1001
+ ["AC", "RP", "RCA", "SAC"].includes(retailerStatus) &&
1002
+ [1, 6].includes(user.id_role);
1003
+ return adminFacilitatorCanEvaluate || adminAuditorCanEvaluate;
1004
+ };
1005
+
1006
+ const approveRejectAllButtons = () => {
1007
+ let concepts = [];
1008
+ switch (user.id_role) {
1009
+ case 4:
1010
+ concepts = ["description", "datasheet"];
1011
+ break;
1012
+ case 5:
1013
+ concepts = ["images"];
1014
+ break;
1015
+
1016
+ default:
1017
+ concepts = ["description", "datasheet", "images"];
1018
+ break;
1019
+ }
1020
+
1021
+ const services = servicesData.filter(({ service }) =>
1022
+ concepts.includes(service)
1023
+ );
1024
+
1025
+ const adminFacilitatorCanEvaluate =
1026
+ services.every((srv) => srv?.status?.replace(/.*\//, "") === "IE") &&
1027
+ [1, 4, 5].includes(user.id_role);
1028
+
1029
+ //sessionStorage product
1030
+ const adminAuditorCanEvaluate =
1031
+ servicesData.every((srv) =>
1032
+ ["AC", "RP", "RCA"].includes(srv?.status?.replace(/.*\//, ""))
1033
+ ) && [1, 6].includes(user.id_role);
1034
+ return adminFacilitatorCanEvaluate || adminAuditorCanEvaluate;
1035
+ };
1036
+
1037
+ const getSectionIcon = () => {
1038
+ switch (activeTab) {
1039
+ case "Ficha técnica":
1040
+ setIcon(attributesSent);
1041
+ break;
1042
+ case "Descripción":
1043
+ setIcon(descriptionSent);
1044
+ break;
1045
+ case "Imágenes":
1046
+ setIcon(imagesSent);
1047
+ break;
1048
+ default:
1049
+ break;
1050
+ }
1051
+ };
1052
+
1053
+ const sendToFacilitator = async (result) => {
1054
+ if (!loading) setLoading(true);
1055
+ try {
1056
+ let concept = getConcept(activeTab);
1057
+
1058
+ const productTemp = { ...product };
1059
+ const evalStatus = retailerStatus;
1060
+ const articleId = product.article.id_article;
1061
+ const orderId = product.orderId;
1062
+
1063
+ let data = {
1064
+ articleId,
1065
+ orderId,
1066
+ concept,
1067
+ evalStatus,
1068
+ retailerId: activeRetailer.id,
1069
+ };
1070
+ let res;
1071
+ let message;
1072
+ if (result) {
1073
+ data.result = result;
1074
+ res = await axios.put(
1075
+ `${process.env.REACT_APP_EVALUATION_ENDPOINT}`,
1076
+ data,
1077
+ {
1078
+ headers: {
1079
+ Authorization: token,
1080
+ },
1081
+ }
1082
+ );
1083
+ getServices();
1084
+ } else {
1085
+ const specialistDone = ["RC", "RA", "CA"].includes(evalStatus);
1086
+
1087
+ if (specialistDone) {
1088
+ message = `${activeTab} enviada a facilitador`;
1089
+ getSectionIcon();
1090
+ } else if (["IE", "AC", "RP", "RCA"].includes(evalStatus)) {
1091
+ message = "Evaluación enviada";
1092
+ getSectionIcon();
1093
+ }
1094
+ res = await axios.put(`${process.env.REACT_APP_SEND_EVAL}`, data, {
1095
+ headers: {
1096
+ Authorization: token,
1097
+ },
1098
+ });
1099
+ }
1100
+ if (res.data.statusCode === 200) {
1101
+ const { newStatus, newOrderStatus, newArticleStatus } = JSON.parse(
1102
+ res.data.body
1103
+ );
1104
+ const messageToChat = createMessage(
1105
+ product.retailers,
1106
+ activeRetailer.id,
1107
+ evalStatus,
1108
+ newStatus,
1109
+ activeTab
1110
+ );
1111
+
1112
+ const data = {
1113
+ paramsBody: {
1114
+ id: product.article.id_article,
1115
+ version: version,
1116
+ items: [{ type: "status", value: messageToChat }],
1117
+ retailerId: activeRetailer.id,
1118
+ status: product.status,
1119
+ },
1120
+ paramsHeader: { Authorization: token },
1121
+ };
1122
+ await sendMessage(data);
1123
+ if (newOrderStatus) productTemp.status = newArticleStatus[articleId];
1124
+ productTemp[`${concept}_status`] = newStatus;
1125
+ await loadData();
1126
+ if (message) setMessage(message);
1127
+ sessionStorage.setItem("productSelected", JSON.stringify(productTemp));
1128
+ setProduct(productTemp);
1129
+ }
1130
+ } catch (error) {
1131
+ setLoading(false);
1132
+ console.log(error);
1133
+ }
1134
+ };
1135
+
1136
+ const userAssigned = (tab, rol) => {
1137
+ let concept = getConcept(activeTab);
1138
+
1139
+ const allowedRoles = [1, 4, 5, 6, 7, 8];
1140
+ const validUser = allowedRoles.includes(user?.id_role);
1141
+
1142
+ if (!rol) {
1143
+ switch (user.id_role) {
1144
+ case 4:
1145
+ case 5:
1146
+ rol = "facilitator";
1147
+ break;
1148
+ case 7:
1149
+ case 8:
1150
+ rol = "especialist";
1151
+ break;
1152
+ }
1153
+ }
1154
+
1155
+ return (
1156
+ user.id_role === 1 ||
1157
+ (product.article[`id_${concept}_${rol}`] === user.id_user && validUser)
1158
+ );
1159
+ };
1160
+
1161
+ const auditorAssigned = () => {
1162
+ return product?.article[`id_auditor`] === user.id_user;
1163
+ };
1164
+
1165
+ const createComment = async (e, body, tab) => {
1166
+ let concept = "";
1167
+ switch (activeTab) {
1168
+ case "Ficha técnica":
1169
+ concept = "datasheet";
1170
+ break;
1171
+ case "Imágenes":
1172
+ concept = "images";
1173
+ break;
1174
+
1175
+ default:
1176
+ concept = "description";
1177
+ break;
1178
+ }
1179
+ const data = {
1180
+ articleId: product?.article?.id_article,
1181
+ orderId: product?.orderId,
1182
+ message: body?.replace(/<.*?\/?>/gm, ""),
1183
+ concept: concept,
1184
+ version: version,
1185
+ };
1186
+ await axios.post(`${process.env.REACT_APP_COMMENTS_ENDPOINT}`, data, {
1187
+ headers: {
1188
+ Authorization: token,
1189
+ },
1190
+ });
1191
+ await getComments(tab);
1192
+ setMessage("");
1193
+ setComponentsArray([]);
1194
+ };
1195
+
1196
+ const getRequired = (services) => {
1197
+ try {
1198
+ const objetcTemp = {};
1199
+ const datasheetServicesArray = Object.values(services[0]);
1200
+ const allDatasheetInputs = datasheetServicesArray.pop();
1201
+ const descriptionsServicesArray = services[1];
1202
+
1203
+ let dsInputsRequired = [];
1204
+
1205
+ let desInputsRequired = 0;
1206
+ datasheetServicesArray?.forEach((datasheet) => {
1207
+ const [requested] = servicesData?.filter(
1208
+ (srv) =>
1209
+ srv.id_retailer === datasheet.retailer.id &&
1210
+ srv.service === getConcept(activeTab)
1211
+ );
1212
+
1213
+ requested &&
1214
+ datasheet?.data &&
1215
+ Object.values(datasheet?.data).forEach((dataGroup) => {
1216
+ dsInputsRequired.push(
1217
+ ...dataGroup.inputs.filter((input) => {
1218
+ return (
1219
+ allDatasheetInputs[input].required &&
1220
+ allDatasheetInputs[input].id_retailer === activeRetailer.id &&
1221
+ (allDatasheetInputs[input].value === undefined ||
1222
+ !allDatasheetInputs[input].value)
1223
+ );
1224
+ })
1225
+ );
1226
+ });
1227
+ });
1228
+
1229
+ objetcTemp["Ficha técnica"] = dsInputsRequired.length;
1230
+
1231
+ const regex = /(<\/?p>)|(<\/?strong>)|(<br>)/gm;
1232
+ descriptionsServicesArray.forEach((description) => {
1233
+ if (description.id != activeRetailer.id) return;
1234
+
1235
+ const [requested] = servicesData.filter(
1236
+ (srv) =>
1237
+ srv.id_retailer === description.id &&
1238
+ srv.service === getConcept(activeTab)
1239
+ );
1240
+
1241
+ if (requested) {
1242
+ description.inputs.forEach((input) => {
1243
+ if (
1244
+ input.required &&
1245
+ (!input.value || input.value?.replace(regex, "") === "")
1246
+ ) {
1247
+ desInputsRequired++;
1248
+ }
1249
+ });
1250
+ }
1251
+ });
1252
+
1253
+ objetcTemp["Descripción"] = desInputsRequired;
1254
+
1255
+ const retailersRequested = [];
1256
+
1257
+ services[2]?.retailerMandatories?.forEach((retMan) =>
1258
+ retMan.forEach((rm) => retailersRequested.push(rm))
1259
+ );
1260
+
1261
+ const requiredImages = services[2]?.inputs?.filter(
1262
+ (e) =>
1263
+ e.required === 1 &&
1264
+ retailersRequested.filter(
1265
+ (ret) =>
1266
+ ret.id_image === e.id &&
1267
+ servicesData.filter((srv) => srv.id_retailer === ret.id_retailer)
1268
+ .length > 0
1269
+ ).length > 0
1270
+ );
1271
+
1272
+ let requiredCounter = 0;
1273
+ requiredImages?.forEach((req) => {
1274
+ return (
1275
+ services[2].values.filter((img) => img.image_id === req.id).length ===
1276
+ 0 && requiredCounter++
1277
+ );
1278
+ });
1279
+ objetcTemp["Imágenes"] = requiredCounter;
1280
+ setRequiredNull(objetcTemp);
1281
+ } catch (error) {
1282
+ console.log(error);
1283
+ }
1284
+ };
1285
+
1286
+ useEffect(() => {
1287
+ setComment(comments[activeTab]);
1288
+ }, [activeTab]);
1289
+
1290
+ const commentRevised = async () => {
1291
+ const data = {
1292
+ commentId: comment.id,
1293
+ };
1294
+ await axios.put(`${process.env.REACT_APP_COMMENTS_ENDPOINT}`, data, {
1295
+ headers: {
1296
+ Authorization: sessionStorage.getItem("jwt"),
1297
+ },
1298
+ });
1299
+ setCrossComment(false);
1300
+ await getComments();
1301
+ };
1302
+
1303
+ const setAssignation = async (assignationType, assignationId) => {
1304
+ let concept = "";
1305
+ switch (activeTab) {
1306
+ case "Ficha técnica":
1307
+ concept = "datasheet";
1308
+ break;
1309
+ case "Imágenes":
1310
+ concept = "images";
1311
+ break;
1312
+
1313
+ default:
1314
+ concept = "description";
1315
+ break;
1316
+ }
1317
+ const productTemp = product;
1318
+ productTemp.article[`id_${concept}_${assignationType}`] = assignationId;
1319
+ const data = {
1320
+ articleList: [
1321
+ {
1322
+ orderId: product.orderId,
1323
+ articleId: product?.article?.id_article,
1324
+ },
1325
+ ],
1326
+ concept: concept,
1327
+ userId: assignationId,
1328
+ };
1329
+ await axios({
1330
+ method: "post",
1331
+ url: process.env.REACT_APP_ASSIGNATIONS_ENDPOINT,
1332
+ data,
1333
+ headers: {
1334
+ Authorization: token,
1335
+ },
1336
+ });
1337
+ loadAssignations(productTemp);
1338
+ sessionStorage.setItem("productSelected", JSON.stringify(productTemp));
1339
+ };
1340
+
1341
+ const downloadImages = () => {
1342
+ selectedImages.length > 0
1343
+ ? selectedImages.forEach((e) => {
1344
+ if (e.id) {
1345
+ saveAs(
1346
+ `https://${process.env.REACT_APP_IMAGES_BUCKET}.s3.amazonaws.com/${e.srcDB}`,
1347
+ `${product.article.upc}_${e.name}.${e.ext}`
1348
+ );
1349
+ }
1350
+ })
1351
+ : images?.values?.forEach((e) => {
1352
+ if (e.id) {
1353
+ saveAs(
1354
+ `https://${process.env.REACT_APP_IMAGES_BUCKET}.s3.amazonaws.com/${e.srcDB}`,
1355
+ `${product.article.upc}_${e.name}.${e.ext}`
1356
+ );
1357
+ }
1358
+ });
1359
+ };
1360
+
1361
+ const deleteImages = async () => {
1362
+ setLoading(true);
1363
+ const { values } = images;
1364
+ const imgsInBack = [];
1365
+
1366
+ selectedImages.forEach((selectedImg) => {
1367
+ if (selectedImg.id) imgsInBack.push(selectedImg);
1368
+ });
1369
+
1370
+ const imgsLeft = values.filter(
1371
+ (value) => selectedImages.indexOf(value) === -1
1372
+ );
1373
+
1374
+ if (imgsInBack.length > 0) {
1375
+ const data = {
1376
+ articleId: product.article.id_article,
1377
+ deleteImages: imgsInBack,
1378
+ orderId: product.orderId,
1379
+ };
1380
+ try {
1381
+ await axios.put(
1382
+ `${process.env.REACT_APP_ARTICLE_DATA_ENDPOINT}?image=true&version=${version}`,
1383
+ data,
1384
+ {
1385
+ headers: { Authorization: token },
1386
+ }
1387
+ );
1388
+ } catch (err) {
1389
+ console.log(err);
1390
+ }
1391
+ }
1392
+
1393
+ setImages({
1394
+ action: "deleteImage",
1395
+ selectedImages,
1396
+ });
1397
+
1398
+ getRequired([
1399
+ services[0],
1400
+ services[1],
1401
+ { ...services[2], values: imgsLeft },
1402
+ ]);
1403
+
1404
+ setLoading(false);
1405
+
1406
+ setMessage("");
1407
+ setComponentsArray([]);
1408
+ };
1409
+
1410
+ const askToDeleteImages = () => {
1411
+ if (selectedImages.length > 0) {
1412
+ setMessage("¿Está seguro de eliminar las imágenes seleccionadas?");
1413
+ setComponentsArray([
1414
+ <ScreenHeader
1415
+ key={"1"}
1416
+ text={"¿Está seguro de eliminar las imágenes seleccionadas?"}
1417
+ headerType="retailer-name-header"
1418
+ color={"white"}
1419
+ />,
1420
+ <Button
1421
+ key={"2"}
1422
+ buttonType="general-white-button"
1423
+ label={"Cancelar"}
1424
+ onClick={() => setMessage("")}
1425
+ />,
1426
+ <Button
1427
+ key={"3"}
1428
+ buttonType="general-button-default"
1429
+ label={"Aceptar"}
1430
+ onClick={() => {
1431
+ setMessage("");
1432
+ deleteImages();
1433
+ }}
1434
+ />,
1435
+ ]);
1436
+ }
1437
+ };
1438
+
1439
+ const getRetailerStatus = (servicesData, tab) => {
1440
+ const arr = servicesData?.slice();
1441
+ let concept = getConcept(tab);
1442
+
1443
+ let retailerService = {};
1444
+ [retailerService] = arr?.filter(
1445
+ (service) =>
1446
+ service.id_retailer === activeRetailer?.id &&
1447
+ service.service === concept
1448
+ );
1449
+ return retailerService ? retailerService.status : "NS";
1450
+ };
1451
+
1452
+ useEffect(() => {
1453
+ let status = getRetailerStatus(servicesData, activeTab);
1454
+ setRetailerStatus(status);
1455
+ }, [activeTab, servicesData, activeRetailer]);
1456
+
1457
+ useEffect(() => {
1458
+ services.length > 0 && getRequired(services);
1459
+ }, [services, servicesData, activeTab]);
1460
+
1461
+ useEffect(() => {
1462
+ setSaving(loading);
1463
+ }, [loading]);
1464
+
1465
+ const validateAll = async (result) => {
1466
+ try {
1467
+ setLoading(true);
1468
+ const evaluationArray = [];
1469
+ let conceptArray = [];
1470
+ switch (user.id_role) {
1471
+ case 4:
1472
+ conceptArray = ["description", "datasheet"];
1473
+ break;
1474
+ case 5:
1475
+ conceptArray = ["images"];
1476
+ break;
1477
+
1478
+ default:
1479
+ conceptArray = ["description", "datasheet", "images"];
1480
+ break;
1481
+ }
1482
+
1483
+ const messages = [];
1484
+
1485
+ servicesData?.forEach((ret) => {
1486
+ if (conceptArray.includes(ret.service)) {
1487
+ let data = {
1488
+ articleId: product.article.id_article,
1489
+ orderId: product.id_order ?? product.orderId,
1490
+ concept: ret.service,
1491
+ result: result,
1492
+ evalStatus: ret.status,
1493
+ retailerId: ret.id_retailer,
1494
+ };
1495
+ evaluationArray.push(
1496
+ axios.put(`${process.env.REACT_APP_EVALUATION_ENDPOINT}`, data, {
1497
+ headers: {
1498
+ Authorization: token,
1499
+ },
1500
+ })
1501
+ );
1502
+ }
1503
+ });
1504
+ await Promise.all(evaluationArray);
1505
+
1506
+ const productTemp = product;
1507
+ productTemp.status = `${result}A`;
1508
+ productTemp.datasheet_status =
1509
+ productTemp.datasheet_status === "NS" ? "NS" : `${result}A`;
1510
+ productTemp.description_status =
1511
+ productTemp.description_status === "NS" ? "NS" : `${result}A`;
1512
+ productTemp.images_status =
1513
+ productTemp.images_status === "NS" ? "NS" : `${result}A`;
1514
+ sessionStorage.setItem("productSelected", JSON.stringify(productTemp));
1515
+ setProduct(productTemp);
1516
+ const messagesResponse = await Promise.all(messages);
1517
+
1518
+ await loadData();
1519
+ } catch (error) {
1520
+ console.log(error);
1521
+ } finally {
1522
+ setLoading(false);
1523
+ }
1524
+ };
1525
+
1526
+ const getObservation = async () => {
1527
+ const response = await axios.get(
1528
+ `${process.env.REACT_APP_READ_OBSERVATION}?articleId=${product.article.id_article}&orderId=${product?.orderId}`,
1529
+ {
1530
+ headers: {
1531
+ Authorization: sessionStorage.getItem("jwt"),
1532
+ },
1533
+ }
1534
+ );
1535
+ const parseData = JSON.parse(response.data.body).data[0];
1536
+ setObservation(parseData.observations);
1537
+ };
1538
+ useEffect(() => {
1539
+ getObservation();
1540
+ }, []);
1541
+ return (
1542
+ <Container headerTop={headerTop}>
1543
+ <HeaderTop
1544
+ setHeaderTop={setHeaderTop}
1545
+ auditableVersion={auditableVersion}
1546
+ setCompare={setCompare}
1547
+ isAuditor={[1, 6].includes(user.id_role)}
1548
+ withChat={location?.state?.withChat}
1549
+ chatType={location?.state?.chatType}
1550
+ productSelected={product}
1551
+ token={token}
1552
+ activeRetailer={activeRetailer}
1553
+ />
1554
+ <div className="data-container">
1555
+ <div className="image-data-panel">
1556
+ <ImagePreviewer
1557
+ activeImage={images?.values ? images?.values[activeImage] : {}}
1558
+ imagesArray={images}
1559
+ setActiveImage={setActiveImage}
1560
+ setShowModal={setShowModal}
1561
+ />
1562
+ <ImageDataTable
1563
+ lists={images}
1564
+ activeImage={images?.values ? images?.values[activeImage] : {}}
1565
+ retailerSelected={activeRetailer?.id}
1566
+ setImages={setImages}
1567
+ assignationsImages={assig["Imágenes"]}
1568
+ imagesStatus={product?.images_status}
1569
+ setAssignation={setAssignation}
1570
+ isRetailer={isRetailer}
1571
+ onClickSave={() =>
1572
+ product?.services?.images === 1 && updateImages()
1573
+ }
1574
+ showSaveButton={auditorAssigned() || userAssigned()}
1575
+ setShowVersionSelector={setShowVersionSelector}
1576
+ version={version}
1577
+ shotThd={shotThd}
1578
+ />
1579
+ </div>
1580
+ <div className="product-information">
1581
+ <FullProductNameHeader
1582
+ headerData={product}
1583
+ productObservation={observation}
1584
+ percent={activePercentage}
1585
+ activeRetailer={activeRetailer}
1586
+ servicesData={servicesData}
1587
+ setActiveRetailer={setActiveRetailer}
1588
+ sendToFacilitator={sendToFacilitator}
1589
+ approve={() => {
1590
+ sendToFacilitator("A");
1591
+ }}
1592
+ reject={() => {
1593
+ setShowRejectModal(true);
1594
+ }}
1595
+ showApproveRejectAll={
1596
+ approveRejectAllButtons() && (auditorAssigned() || userAssigned())
1597
+ }
1598
+ showValidationButtons={
1599
+ approveRejectButtons() && (auditorAssigned() || userAssigned())
1600
+ }
1601
+ approveAll={() => validateAll("A")}
1602
+ rejectAll={() => {
1603
+ setShowRejectModal(true);
1604
+ setValRejAll(true);
1605
+ }}
1606
+ isObservationVisible={isObservationVisible}
1607
+ toggleObservation={toggleObservation}
1608
+ // handleClickOutside={handleClickOutside}
1609
+ hideObservation={hideObservation}
1610
+ />
1611
+ <FullTabsMenu
1612
+ tabsSections={tabsSections}
1613
+ status={retailerStatus}
1614
+ activeTab={activeTab}
1615
+ setActiveTab={setActiveTab}
1616
+ setImageLayout={setImageLayout}
1617
+ downloadImages={downloadImages}
1618
+ askToDeleteImages={askToDeleteImages}
1619
+ assig={assig[activeTab]}
1620
+ setAssignation={setAssignation}
1621
+ isRetailer={isRetailer}
1622
+ showSaveButton={auditorAssigned() || userAssigned()}
1623
+ version={version}
1624
+ desc={desc}
1625
+ setDesc={setDesc}
1626
+ fich={fich}
1627
+ setFich={setFich}
1628
+ imag={imag}
1629
+ setImag={setImag}
1630
+ updatedDescriptions={updatedDescriptions}
1631
+ setUpdatedDescriptions={setUpdatedDescriptions}
1632
+ updatedDatasheets={updatedDatasheets}
1633
+ setUpdatedDatasheets={setUpdatedDatasheets}
1634
+ images={images}
1635
+ setImages={setImages}
1636
+ selectedImages={selectedImages}
1637
+ setSelectedImages={setSelectedImages}
1638
+ setShowVersionSelector={setShowVersionSelector}
1639
+ onClickSave={() => {
1640
+ switch (activeTab) {
1641
+ case "Descripción":
1642
+ !saving &&
1643
+ product?.description_status !== "NS" &&
1644
+ saveDescriptions();
1645
+ break;
1646
+ case "Ficha técnica":
1647
+ !saving &&
1648
+ product?.datasheet_status !== "NS" &&
1649
+ saveDatasheets();
1650
+ break;
1651
+ case "Imágenes":
1652
+ !saving && product?.images_status !== "NS" && updateImages();
1653
+ break;
1654
+
1655
+ default:
1656
+ break;
1657
+ }
1658
+ }}
1659
+ canAssign={![7, 8].includes(user.id_role)}
1660
+ />
1661
+ <div
1662
+ className={
1663
+ "services-information-container " +
1664
+ (imageLayout && activeTab === "Imágenes" ? "image-services" : "")
1665
+ }
1666
+ >
1667
+ {loading ? (
1668
+ <Loading />
1669
+ ) : (
1670
+ <>
1671
+ {!imageLayout &&
1672
+ activeTab === "Imágenes" &&
1673
+ product?.services?.images === 1 && (
1674
+ <GalleryHeader
1675
+ setSelectedImages={setSelectedImages}
1676
+ checkAll={checkAll}
1677
+ setCheckAll={setCheckAll}
1678
+ shotThd={shotThd}
1679
+ />
1680
+ )}
1681
+
1682
+ {activeTab === "Ficha técnica" &&
1683
+ (product?.datasheet_status !== "NS" ? (
1684
+ datasheets[0]?.data?.map((dataGroup, index) => (
1685
+ <InputGroup
1686
+ key={index + "-" + activeRetailer.name}
1687
+ articleId={product.article.id_article}
1688
+ version={version}
1689
+ activeSection={activeTab}
1690
+ inputGroup={dataGroup}
1691
+ dataInputs={datasheets[1]}
1692
+ auditInputs={auditDatasheets[1]}
1693
+ updatedDatasheets={updatedDatasheets}
1694
+ setUpdatedDatasheets={setUpdatedDatasheets}
1695
+ compare={compare}
1696
+ />
1697
+ ))
1698
+ ) : (
1699
+ <ScreenHeader
1700
+ text={"No cuentas con este servicio"}
1701
+ headerType={"input-name-header"}
1702
+ />
1703
+ ))}
1704
+ {activeTab === "Descripción" &&
1705
+ (product?.description_status !== "NS" ? (
1706
+ <InputGroup
1707
+ activeSection={activeTab}
1708
+ inputGroup={descriptions[0]}
1709
+ auditInputGroup={auditDescriptions[0]}
1710
+ updatedDescriptions={updatedDescriptions}
1711
+ setUpdatedDescriptions={setUpdatedDescriptions}
1712
+ articleId={product?.article?.id_article}
1713
+ version={version}
1714
+ dinamicHeight={true}
1715
+ compare={compare}
1716
+ />
1717
+ ) : (
1718
+ <ScreenHeader
1719
+ text={"No cuentas con este servicio"}
1720
+ headerType={"input-name-header"}
1721
+ />
1722
+ ))}
1723
+
1724
+ {activeTab === "Imágenes" &&
1725
+ (product?.images_status !== "NS" ? (
1726
+ <section className="container">
1727
+ <div {...getRootProps({ className: "dropzone" })}>
1728
+ <input {...getInputProps()} />
1729
+ <aside>{thumbs()}</aside>
1730
+ </div>
1731
+ </section>
1732
+ ) : (
1733
+ <ScreenHeader
1734
+ text={"No cuentas con este servicio"}
1735
+ headerType={"input-name-header"}
1736
+ />
1737
+ ))}
1738
+ </>
1739
+ )}
1740
+ </div>
1741
+ {/* {(userAssigned(activeTab) || auditorAssigned()) &&
1742
+ product[`${getConcept(activeTab)}_status`] !== "NS" && (
1743
+ <div className="commentary-box">
1744
+ {[7, 8].includes(user.id_role) && (
1745
+ <Button
1746
+ buttonType={
1747
+ evaluationFinished(
1748
+ user.id_role,
1749
+ activeTab,
1750
+ statusArray
1751
+ ) && requiredNull[activeTab] === 0
1752
+ ? "general-green-button"
1753
+ : "general-button-disabled"
1754
+ }
1755
+ label={"Enviar evaluación"}
1756
+ onClick={() => sendToFacilitator()}
1757
+ />
1758
+ )}
1759
+ </div>
1760
+ )} */}
1761
+
1762
+ {(userAssigned(activeTab) || auditorAssigned()) &&
1763
+ product[`${getConcept(activeTab)}_status`] !== "NS" && (
1764
+ <div className="commentary-box">
1765
+ {!comment ? (
1766
+ <div className="commentary">
1767
+ <TagAndInput
1768
+ label={"Caja de Comentario"}
1769
+ inputType={"textarea"}
1770
+ inputCols={80}
1771
+ inputRows={4}
1772
+ inputId={"commentary-box"}
1773
+ index={0}
1774
+ />
1775
+ <div className="buttons-box">
1776
+ <Button
1777
+ buttonType={"general-transparent-button"}
1778
+ label={"Enviar comentario"}
1779
+ onClick={handleCommentSubmit}
1780
+ />
1781
+ </div>
1782
+ </div>
1783
+ ) : (
1784
+ <div className="feedback-box">
1785
+ <Commentary
1786
+ comment={comment?.message}
1787
+ reviewed={crossComment}
1788
+ />
1789
+ <Button
1790
+ buttonType={"circular-button accept-button"}
1791
+ onClick={async () => {
1792
+ setCrossComment(true);
1793
+ commentRevised();
1794
+ }}
1795
+ />
1796
+ </div>
1797
+ )}
1798
+ {[7, 8].includes(user.id_role) && (
1799
+ <Button
1800
+ buttonType={
1801
+ evaluationFinished(
1802
+ user.id_role,
1803
+ activeTab,
1804
+ statusArray
1805
+ ) && requiredNull[activeTab] === 0
1806
+ ? "general-green-button"
1807
+ : "general-button-disabled"
1808
+ }
1809
+ label={"Enviar evaluación"}
1810
+ onClick={() => sendToFacilitator()}
1811
+ />
1812
+ )}
1813
+ </div>
1814
+ )}
1815
+ </div>
1816
+ </div>
1817
+ {showModal && (
1818
+ <ProductImageModal
1819
+ images={images}
1820
+ setShowModal={setShowModal}
1821
+ sendToFacilitator={sendToFacilitator}
1822
+ approveRejectButtons={approveRejectButtons()}
1823
+ />
1824
+ )}
1825
+ {message.length > 0 && (
1826
+ <GenericModal
1827
+ buttonType={componentsArray.length > 0 && "delete-product"}
1828
+ componentsArray={
1829
+ componentsArray.length > 0
1830
+ ? componentsArray
1831
+ : [
1832
+ <img key="1" src={succes} alt="success icon" />,
1833
+ <ScreenHeader
1834
+ key="2"
1835
+ headerType={"retailer-name-header"}
1836
+ text={message}
1837
+ color={"white"}
1838
+ />,
1839
+ ]
1840
+ }
1841
+ onClick={() => setMessage("")}
1842
+ />
1843
+ )}
1844
+ {showVersionSelector && (
1845
+ <VersionSelector
1846
+ modalId={"version-selector"}
1847
+ articleId={product.article.id_article}
1848
+ setVersion={setVersion}
1849
+ companyName={product.article.company_name}
1850
+ currentVersion={version}
1851
+ setShowVersionSelector={setShowVersionSelector}
1852
+ jwt={token}
1853
+ />
1854
+ )}
1855
+ {showRejectModal && (
1856
+ <Modal
1857
+ title={`Agregar mensaje de rechazo para ${activeTab?.toLowerCase()}`}
1858
+ show={showRejectModal}
1859
+ customComponent={
1860
+ <TagAndInput
1861
+ inputType={"textarea"}
1862
+ inputId={"modal-message-box"}
1863
+ index={0}
1864
+ color={"white"}
1865
+ />
1866
+ }
1867
+ buttons={[
1868
+ <ButtonV2
1869
+ key={"btn-Cancelar"}
1870
+ type={"white"}
1871
+ label={"Cancelar"}
1872
+ size={12}
1873
+ onClick={() => {
1874
+ setShowRejectModal(false);
1875
+ }}
1876
+ />,
1877
+ <ButtonV2
1878
+ key={"btn-Aceptar"}
1879
+ type={"pink"}
1880
+ label={"Aceptar"}
1881
+ size={12}
1882
+ onClick={async (e) => {
1883
+ const elements = document.querySelectorAll(
1884
+ "#modal-message-box .ql-container .ql-editor > p"
1885
+ );
1886
+
1887
+ if (!elements || elements.length === 0) {
1888
+ console.error("Elemento no encontrado");
1889
+ return;
1890
+ }
1891
+
1892
+ let brCounter = 0;
1893
+
1894
+ elements.forEach((el) => {
1895
+ const body = el.innerHTML;
1896
+
1897
+ if (typeof body !== "string") {
1898
+ console.log("El contenido de body no es una cadena", body);
1899
+ isMessageEmpty = true;
1900
+ return;
1901
+ }
1902
+
1903
+ if (!body || body.replace(/<.*?\/?>/gm, "").trim() === "") {
1904
+ brCounter++;
1905
+ }
1906
+ });
1907
+
1908
+ if (brCounter === elements.length) {
1909
+ const container = document.querySelector(
1910
+ ".container-customComponent"
1911
+ );
1912
+
1913
+ const existingAlert = container.querySelector(".alert-error");
1914
+ if (existingAlert) {
1915
+ return; // Si ya existe, no crear otra
1916
+ }
1917
+
1918
+ // Crear alerta con estilos
1919
+ const alert = document.createElement("div");
1920
+ alert.className = "alert-error";
1921
+ alert.style.cssText = `
1922
+ color: #d32f2f;
1923
+ background-color: #ffebee;
1924
+ border: 1px solid #ef5350;
1925
+ border-radius: 4px;
1926
+ padding: 12px 16px;
1927
+ margin-top: 10px;
1928
+ font-size: 14px;
1929
+ display: flex;
1930
+ align-items: center;
1931
+ gap: 8px;
1932
+ font-family: 'Roboto', sans-serif;
1933
+ text-align: center;
1934
+ `;
1935
+
1936
+ alert.innerHTML = `
1937
+ <span>El mensaje no puede estar vacío.</span>
1938
+ `;
1939
+
1940
+ container.appendChild(alert);
1941
+ return;
1942
+ }
1943
+
1944
+ let fullMessage = "";
1945
+
1946
+ elements.forEach((element) => {
1947
+ const body = element.innerHTML;
1948
+
1949
+ fullMessage += body;
1950
+ });
1951
+
1952
+ fullMessage = fullMessage.replace(/<br\s*\/?>/gi, "\n");
1953
+
1954
+ await createComment(e, fullMessage, activeTab);
1955
+ valRejAll ? validateAll("R") : sendToFacilitator("R");
1956
+ setMessage("Rechazado");
1957
+ setShowRejectModal(false);
1958
+ }}
1959
+ />,
1960
+ ]}
1961
+ />
1962
+ )}
1963
+ <Modal
1964
+ className="container-modalAlert"
1965
+ show={modalAlert.show}
1966
+ title={modalAlert.title}
1967
+ message={modalAlert.message}
1968
+ icon={"info"}
1969
+ onClickBtnDefault={(event) => {
1970
+ setModalAlert((prev) => ({
1971
+ ...prev,
1972
+ show: false,
1973
+ errorInputMessage: false,
1974
+ }));
1975
+ }}
1976
+ />
1977
+ </Container>
1978
+ );
1979
+ };