contentoh-components-library 21.5.94 → 21.5.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/utils/compare-strings.js +45 -0
- package/dist/components/atoms/GeneralButton/styles.js +1 -1
- package/dist/components/atoms/GeneralInput/index.js +245 -54
- package/dist/components/atoms/GeneralInput/styles.js +7 -3
- package/dist/components/atoms/InputFormatter/index.js +223 -68
- package/dist/components/atoms/InputFormatter/styles.js +20 -4
- package/dist/components/molecules/StatusAsignationInfo/index.js +11 -1
- package/dist/components/molecules/TabsMenu/index.js +13 -12
- package/dist/components/molecules/TagAndInput/index.js +361 -24
- package/dist/components/molecules/TagAndInput/styles.js +2 -2
- package/dist/components/organisms/ChangeStatusModal/index.js +531 -0
- package/dist/components/organisms/ChangeStatusModal/styles.js +85 -0
- package/dist/components/organisms/FullProductNameHeader/index.js +6 -22
- package/dist/components/organisms/InputGroup/index.js +22 -18
- package/dist/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +150 -337
- package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.context.js +15 -15
- package/dist/components/pages/ProviderProductEdition/index.js +413 -396
- package/dist/components/pages/ProviderProductEdition/utils.js +1 -0
- package/dist/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +179 -196
- package/dist/components/pages/RetailerProductEdition/context/provider-product-edition.context.js +59 -260
- package/dist/components/pages/RetailerProductEdition/context/reducers/product.js +50 -38
- package/dist/components/pages/RetailerProductEdition/index.js +1719 -2237
- package/dist/components/pages/RetailerProductEdition/styles.js +4 -2
- package/dist/components/pages/RetailerProductEdition/utils.js +251 -2
- package/dist/contexts/AiProductEdition.js +230 -158
- package/dist/global-files/statusDictionary.js +103 -0
- package/package.json +4 -2
- package/src/ai/utils/compare-strings.js +45 -0
- package/src/assets/images/Icons/arrow.png +0 -0
- package/src/assets/images/Icons/cancel.png +0 -0
- package/src/assets/images/Icons/ia-icon.png +0 -0
- package/src/assets/images/Icons/loading.svg +5 -0
- package/src/assets/images/Icons/reload.png +0 -0
- package/src/components/atoms/GeneralButton/styles.js +4 -0
- package/src/components/atoms/GeneralInput/index.js +237 -60
- package/src/components/atoms/GeneralInput/styles.js +81 -0
- package/src/components/atoms/InputFormatter/index.js +200 -51
- package/src/components/atoms/InputFormatter/styles.js +284 -0
- package/src/components/atoms/RetailerSelector/RetailerSelector.stories.js +10 -0
- package/src/components/atoms/RetailerSelector/index.js +3 -0
- package/src/components/atoms/RetailerSelector/styles.js +0 -0
- package/src/components/molecules/StatusAsignationInfo/index.js +9 -1
- package/src/components/molecules/TabsMenu/index.js +12 -11
- package/src/components/molecules/TagAndInput/index.js +286 -21
- package/src/components/molecules/TagAndInput/styles.js +59 -17
- package/src/components/organisms/ChangeStatusModal/index.jsx +488 -0
- package/src/components/organisms/ChangeStatusModal/styles.js +333 -0
- package/src/components/organisms/FullProductNameHeader/index.js +4 -28
- package/src/components/organisms/FullTabsMenu/index.js +1 -1
- package/src/components/organisms/InputGroup/index.js +12 -4
- package/src/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +174 -202
- package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx +14 -14
- package/src/components/pages/ProviderProductEdition/index.js +496 -475
- package/src/components/pages/ProviderProductEdition/utils.js +2 -2
- package/src/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +201 -224
- package/src/components/pages/RetailerProductEdition/context/provider-product-edition.context.jsx +575 -0
- package/src/components/pages/RetailerProductEdition/context/provider-product-edition.reducer.js +62 -0
- package/src/components/pages/RetailerProductEdition/context/reducers/active-state.js +344 -0
- package/src/components/pages/RetailerProductEdition/context/reducers/inputs.js +155 -0
- package/src/components/pages/RetailerProductEdition/context/reducers/product.js +114 -0
- package/src/components/pages/RetailerProductEdition/context/reducers/system.js +60 -0
- package/src/components/pages/RetailerProductEdition/index.js +1545 -1718
- package/src/components/pages/RetailerProductEdition/index_old.js +1979 -0
- package/src/components/pages/RetailerProductEdition/stories/Auditor.stories.js +101 -0
- package/src/components/pages/RetailerProductEdition/stories/ImageEditor.stories.js +115 -0
- package/src/components/pages/RetailerProductEdition/stories/TextEditor.stories.js +174 -0
- package/src/components/pages/RetailerProductEdition/styles.js +67 -2
- package/src/components/pages/RetailerProductEdition/utils.js +240 -0
- package/src/contexts/AiProductEdition.jsx +339 -0
- package/src/global-files/statusDictionary.js +103 -0
|
@@ -1,392 +1,284 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
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";
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import axios from "axios";
|
|
4
|
+
import { useDropzone } from "react-dropzone";
|
|
10
5
|
import { saveAs } from "file-saver";
|
|
11
|
-
|
|
6
|
+
|
|
12
7
|
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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";
|
|
8
|
+
ProviderProductEditionProvider,
|
|
9
|
+
useProviderProductEdition,
|
|
10
|
+
} from "./context/provider-product-edition.context";
|
|
34
11
|
import {
|
|
12
|
+
normalizeProduct,
|
|
13
|
+
getConceptByTab,
|
|
35
14
|
getAuditVersion,
|
|
36
15
|
getInputsData,
|
|
37
16
|
createMessage,
|
|
38
17
|
sendMessage,
|
|
18
|
+
translateConcept,
|
|
19
|
+
getStatusArrayByRole,
|
|
20
|
+
getConceptsByRole,
|
|
21
|
+
buildCollaboratorAssignations,
|
|
22
|
+
calculateRequiredNull,
|
|
39
23
|
} from "./utils";
|
|
40
|
-
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
fetchUsers,
|
|
27
|
+
getPercentage,
|
|
28
|
+
getRetailerServices,
|
|
29
|
+
getServicesData,
|
|
30
|
+
} from "../../../global-files/data";
|
|
31
|
+
import { useCloseModal } from "../../../global-files/customHooks";
|
|
32
|
+
|
|
33
|
+
import { Button } from "../../atoms/GeneralButton";
|
|
34
|
+
import { GenericModal } from "../../atoms/GenericModal";
|
|
35
|
+
import { Loading } from "../../atoms/Loading";
|
|
36
|
+
import { ScreenHeader } from "../../atoms/ScreenHeader";
|
|
41
37
|
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
38
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
);
|
|
39
|
+
import { GalleryElement } from "../../molecules/GalleryElement";
|
|
40
|
+
import { GalleryHeader } from "../../molecules/GalleryHeader";
|
|
41
|
+
import { HeaderTop } from "../../molecules/HeaderTop";
|
|
42
|
+
import { TagAndInput } from "../../molecules/TagAndInput/index";
|
|
119
43
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
};
|
|
44
|
+
import { FullProductNameHeader } from "../../organisms/FullProductNameHeader";
|
|
45
|
+
import { FullTabsMenu } from "../../organisms/FullTabsMenu";
|
|
46
|
+
import { ImageDataTable } from "../../organisms/ImageDataTable";
|
|
47
|
+
import { ImagePreviewer } from "../../organisms/ImagePreviewer";
|
|
48
|
+
import { InputGroup } from "../../organisms/InputGroup";
|
|
49
|
+
import { ProductImageModal } from "../../organisms/ProductImageModal";
|
|
50
|
+
import { VersionSelector } from "../../organisms/VersionSelector";
|
|
51
|
+
import { Modal } from "../../organisms/Modal";
|
|
130
52
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
}
|
|
53
|
+
import successIcon from "../../../assets/images/genericModal/genericModalCheck.svg";
|
|
54
|
+
import errorIcon from "../../../assets/images/genericModal/errorModal.svg";
|
|
55
|
+
import warningIcon from "../../../assets/images/genericModal/genericModalWarning.svg";
|
|
56
|
+
import attributesSent from "../../../assets/images/modalsSVGs/attributesSent.svg";
|
|
57
|
+
import descriptionSent from "../../../assets/images/modalsSVGs/descriptionSent.svg";
|
|
58
|
+
import imagesSent from "../../../assets/images/modalsSVGs/uploadingImages.svg";
|
|
168
59
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
secretAccessKey: process.env.REACT_APP_AKUTS3,
|
|
172
|
-
});
|
|
60
|
+
import { Container } from "./styles";
|
|
61
|
+
import { Commentary } from "../../atoms/Commentary";
|
|
173
62
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
region: REGION,
|
|
177
|
-
});
|
|
63
|
+
import { AiProductEditionProvider } from "../../../contexts/AiProductEdition";
|
|
64
|
+
import ChangeStatusModal from "../../organisms/ChangeStatusModal";
|
|
178
65
|
|
|
179
|
-
|
|
66
|
+
import { Skeleton, Box, Stack } from "@mui/material";
|
|
67
|
+
|
|
68
|
+
const RetailerProductEditionView = ({
|
|
180
69
|
tabsSections,
|
|
181
70
|
productSelected = {},
|
|
182
71
|
user = {},
|
|
183
72
|
token,
|
|
184
73
|
location,
|
|
185
74
|
}) => {
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
75
|
+
const {
|
|
76
|
+
state,
|
|
77
|
+
dispatch,
|
|
78
|
+
saveDatasheets,
|
|
79
|
+
saveDescriptions,
|
|
80
|
+
updateImages,
|
|
81
|
+
saveImageAttrs,
|
|
82
|
+
deleteImages,
|
|
83
|
+
handleOnDownloadImages,
|
|
84
|
+
createComment,
|
|
85
|
+
} = useProviderProductEdition();
|
|
86
|
+
|
|
87
|
+
const isRetailer = user?.is_retailer;
|
|
88
|
+
|
|
89
|
+
const [showVersionSelector, setShowVersionSelector] =
|
|
90
|
+
useCloseModal("version-selector");
|
|
91
|
+
const [auditableVersion, setAuditableVersion] = useState(null);
|
|
189
92
|
const [headerTop, setHeaderTop] = useState(0);
|
|
190
|
-
const [
|
|
191
|
-
const [
|
|
192
|
-
const [images, setImages] = useReducer(reducerImages, {});
|
|
193
|
-
const [showModal, setShowModal] = useState(false);
|
|
93
|
+
const [shotThd, setShotThd] = useState(false);
|
|
94
|
+
const [observation, setObservation] = useState();
|
|
194
95
|
const [showRejectModal, setShowRejectModal] = useState(false);
|
|
195
|
-
const
|
|
196
|
-
|
|
96
|
+
const [isObservationVisible, setObservationVisible] = useState(false);
|
|
97
|
+
const [imageLayout, setImageLayout] = useState(false);
|
|
98
|
+
const [crossComment, setCrossComment] = useState(false);
|
|
99
|
+
const [statusArray, setStatusArray] = useState([]);
|
|
100
|
+
const [rejectAll, setRejectAll] = useState(false);
|
|
101
|
+
|
|
102
|
+
const [auditServices, setAuditServices] = useState([]);
|
|
103
|
+
const [auditDatasheets, setAuditDatasheets] = useState([]);
|
|
104
|
+
const [auditDescriptions, setAuditDescriptions] = useState([]);
|
|
105
|
+
const [showModal, setShowModal] = useState(false);
|
|
106
|
+
|
|
107
|
+
const [compare, setCompare] = useState(false);
|
|
108
|
+
const { getRootProps, getInputProps, isDragActive, open } = useDropzone({
|
|
109
|
+
accept: "image/*",
|
|
197
110
|
noKeyboard: true,
|
|
198
111
|
multiple: true,
|
|
199
112
|
noClick: true,
|
|
200
113
|
onDrop: (acceptedFiles) => {
|
|
201
|
-
const newImages = [];
|
|
202
114
|
acceptedFiles.map((file) => {
|
|
203
115
|
const reader = new FileReader();
|
|
204
116
|
reader.fileName = file.name;
|
|
117
|
+
|
|
205
118
|
reader.onload = async function (e) {
|
|
206
|
-
const
|
|
119
|
+
const fileName = e.target.fileName;
|
|
120
|
+
const fileExtension = fileName.split(".").pop();
|
|
121
|
+
const fileDataURL = e.target.result;
|
|
122
|
+
|
|
207
123
|
const img = new Image();
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
-
}
|
|
124
|
+
img.src = fileDataURL;
|
|
125
|
+
|
|
126
|
+
img.onload = function () {
|
|
127
|
+
const width = img.width;
|
|
128
|
+
const height = img.height;
|
|
129
|
+
const newImg = {
|
|
130
|
+
src: fileDataURL,
|
|
131
|
+
name: fileName,
|
|
132
|
+
ext: fileExtension,
|
|
133
|
+
width: width,
|
|
134
|
+
height: height,
|
|
135
|
+
isApproved: true, // VALIDAR QUE SOLO SEA PARA RADIOSHACK
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
dispatch({
|
|
139
|
+
type: "ADD_IMAGE_VALUE",
|
|
140
|
+
payload: newImg,
|
|
141
|
+
});
|
|
142
|
+
};
|
|
262
143
|
};
|
|
144
|
+
|
|
263
145
|
reader.onerror = function (error) {
|
|
264
146
|
console.log("dropzoneError: ", error);
|
|
265
147
|
};
|
|
148
|
+
|
|
266
149
|
reader.readAsDataURL(file);
|
|
267
150
|
return file;
|
|
268
151
|
});
|
|
269
152
|
},
|
|
270
153
|
});
|
|
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
154
|
|
|
328
|
-
const [
|
|
329
|
-
const [fich, setFich] = useState([]);
|
|
330
|
-
const [imag, setImag] = useState([]);
|
|
155
|
+
const [openChangeStatusModal, setOpenChangeStatusModal] = useState(false);
|
|
331
156
|
|
|
332
|
-
const
|
|
157
|
+
const thumbs = () => {
|
|
158
|
+
const imageInputs = state.images_values?.inputs?.map((e) => ({
|
|
159
|
+
value: e?.id,
|
|
160
|
+
name: e?.name,
|
|
161
|
+
required: e?.required,
|
|
162
|
+
active: state.images_values?.values?.some(
|
|
163
|
+
(value) => value?.image_id === e?.id,
|
|
164
|
+
),
|
|
165
|
+
}));
|
|
166
|
+
const imageType = state.images_values?.imageType?.map((e) => ({
|
|
167
|
+
value: e?.id,
|
|
168
|
+
name: e?.name,
|
|
169
|
+
}));
|
|
170
|
+
const imagePackagingType = state.images_values?.imagePackagingType?.map(
|
|
171
|
+
(e) => ({
|
|
172
|
+
value: e?.id,
|
|
173
|
+
name: e?.name,
|
|
174
|
+
}),
|
|
175
|
+
);
|
|
333
176
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
177
|
+
return state.images_values?.values?.map((image, index) => (
|
|
178
|
+
<GalleryElement
|
|
179
|
+
id={"gallery-element-" + index}
|
|
180
|
+
index={index + "-" + image.name}
|
|
181
|
+
key={index}
|
|
182
|
+
image={image}
|
|
183
|
+
number={index}
|
|
184
|
+
gridLayout={imageLayout}
|
|
185
|
+
imageType={imageType}
|
|
186
|
+
imagePackagingType={imagePackagingType}
|
|
187
|
+
imageInputs={imageInputs}
|
|
188
|
+
selectedImages={state.selected_images}
|
|
189
|
+
setCheckAll={handleOnSetCheckAll}
|
|
190
|
+
changeImage={(item) => {
|
|
191
|
+
dispatch({ type: "UPDATE_IMAGE_VALUE", payload: item });
|
|
192
|
+
}}
|
|
193
|
+
setSelectedImages={(item) =>
|
|
194
|
+
dispatch({ type: "SET_SELECTED_IMAGE", payload: item })
|
|
195
|
+
}
|
|
196
|
+
updateApprovedInputsImages={(item) =>
|
|
197
|
+
console.log("updateApprovedInputsImages", item)
|
|
198
|
+
}
|
|
199
|
+
/>
|
|
200
|
+
));
|
|
356
201
|
};
|
|
357
202
|
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
203
|
+
const initializeProduct = async () => {
|
|
204
|
+
try {
|
|
205
|
+
const product = productSelected ? productSelected : JSON.parse(sessionStorage.getItem("productSelected"));
|
|
206
|
+
|
|
207
|
+
const productNormalized = normalizeProduct(product);
|
|
208
|
+
|
|
209
|
+
dispatch({
|
|
210
|
+
type: "SET_PRODUCT",
|
|
211
|
+
payload: productNormalized,
|
|
212
|
+
});
|
|
213
|
+
dispatch({
|
|
214
|
+
type: "SET_ACTIVE_RETAILER",
|
|
215
|
+
payload: productNormalized.categoryRetailerInOrder[0],
|
|
216
|
+
});
|
|
217
|
+
setShotThd(
|
|
218
|
+
[58, 59, 60, 61].includes(
|
|
219
|
+
productNormalized.categoryRetailerInOrder[0].id_retailer,
|
|
220
|
+
),
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
// Configurar statusArray según el rol del usuario
|
|
224
|
+
setStatusArray(getStatusArrayByRole(user.id_role));
|
|
225
|
+
|
|
226
|
+
// Cargar usuarios y asignaciones
|
|
227
|
+
const users = await fetchUsers(token);
|
|
228
|
+
if (users.length > 0) {
|
|
229
|
+
dispatch({
|
|
230
|
+
type: "SET_COLLABORATOR_ASSIGNATIONS",
|
|
231
|
+
payload: buildCollaboratorAssignations(productNormalized, users),
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const { id_article } = productNormalized;
|
|
236
|
+
if (id_article) {
|
|
237
|
+
await getAuditVersion(id_article, setAuditableVersion, token);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (id_article && productNormalized.id_order) {
|
|
241
|
+
const response = await axios.get(
|
|
242
|
+
process.env.REACT_APP_READ_OBSERVATION,
|
|
243
|
+
{
|
|
244
|
+
params: {
|
|
245
|
+
articleId: id_article,
|
|
246
|
+
orderId: productNormalized.id_order,
|
|
247
|
+
},
|
|
248
|
+
headers: {
|
|
249
|
+
Authorization: sessionStorage.getItem("jwt"),
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
);
|
|
253
|
+
const parseData = JSON.parse(response.data.body).data[0];
|
|
254
|
+
setObservation(parseData.observations);
|
|
255
|
+
}
|
|
256
|
+
} catch (error) {
|
|
257
|
+
console.log("Error setting product data: ", error);
|
|
258
|
+
}
|
|
364
259
|
};
|
|
365
260
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
await getAuditVersion(id_article, setAuditableVersion, token);
|
|
261
|
+
// Setter del producto y carga inicial (optimizado para evitar cascada)
|
|
262
|
+
useEffect(() => {
|
|
263
|
+
initializeProduct();
|
|
370
264
|
}, []);
|
|
371
265
|
|
|
372
266
|
const loadAuditableData = async () => {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
setAuditImages(auditServices[2]);
|
|
389
|
-
}
|
|
267
|
+
const auditServices = await getRetailerServices(
|
|
268
|
+
state.product?.id_article,
|
|
269
|
+
state.product?.categoryName,
|
|
270
|
+
parseInt(state.product?.id_category),
|
|
271
|
+
auditableVersion.version,
|
|
272
|
+
token,
|
|
273
|
+
);
|
|
274
|
+
getInputsData(
|
|
275
|
+
auditServices,
|
|
276
|
+
{ id: state.active_retailer.id_retailer },
|
|
277
|
+
setAuditDatasheets,
|
|
278
|
+
setAuditDescriptions,
|
|
279
|
+
);
|
|
280
|
+
setAuditServices(auditServices);
|
|
281
|
+
setAuditImages(auditServices[2]);
|
|
390
282
|
};
|
|
391
283
|
|
|
392
284
|
useEffect(() => {
|
|
@@ -395,682 +287,438 @@ export const RetailerProductEdition = ({
|
|
|
395
287
|
}
|
|
396
288
|
}, [auditableVersion]);
|
|
397
289
|
|
|
398
|
-
|
|
399
|
-
checkAll && setSelectedImages(images.values);
|
|
400
|
-
}, [checkAll]);
|
|
401
|
-
|
|
402
|
-
const loadData = async () => {
|
|
290
|
+
const loadData = async (enableLoading = true, versionSelected = null) => {
|
|
403
291
|
try {
|
|
404
|
-
|
|
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] });
|
|
292
|
+
if (enableLoading) dispatch({ type: "SET_LOADING", payload: true });
|
|
464
293
|
|
|
465
|
-
|
|
294
|
+
const { id_article, version, id_order } = state.product;
|
|
295
|
+
const { category, id_category, id_retailer } = state.active_retailer;
|
|
466
296
|
|
|
297
|
+
// Payloads y headers
|
|
467
298
|
const data = [
|
|
468
299
|
{
|
|
469
|
-
id_article
|
|
300
|
+
id_article,
|
|
301
|
+
version: versionSelected ? versionSelected : version,
|
|
470
302
|
relations: [
|
|
471
303
|
{
|
|
472
|
-
id_retailer
|
|
473
|
-
id_category
|
|
304
|
+
id_retailer,
|
|
305
|
+
id_category,
|
|
474
306
|
},
|
|
475
307
|
],
|
|
476
|
-
version: product.version,
|
|
477
308
|
},
|
|
478
309
|
];
|
|
479
310
|
|
|
480
311
|
const headers = { Authorization: token };
|
|
481
|
-
|
|
482
|
-
|
|
312
|
+
|
|
313
|
+
const [services, percentagesRes, servicesDataRes, commentsResponse] =
|
|
314
|
+
await Promise.all([
|
|
315
|
+
getRetailerServices(
|
|
316
|
+
id_article,
|
|
317
|
+
category,
|
|
318
|
+
id_category,
|
|
319
|
+
versionSelected ?? version,
|
|
320
|
+
token,
|
|
321
|
+
id_retailer,
|
|
322
|
+
),
|
|
323
|
+
getPercentage({ data, headers }),
|
|
324
|
+
getServicesData({
|
|
325
|
+
articleId: id_article,
|
|
326
|
+
orderId: id_order,
|
|
327
|
+
end: true,
|
|
328
|
+
token,
|
|
329
|
+
}),
|
|
330
|
+
// Obtener comentarios en paralelo
|
|
331
|
+
Promise.all([
|
|
332
|
+
axios.get(process.env.REACT_APP_COMMENTS_ENDPOINT, {
|
|
333
|
+
params: {
|
|
334
|
+
articleId: id_article,
|
|
335
|
+
concept: "description",
|
|
336
|
+
orderIdColab: id_order,
|
|
337
|
+
version: versionSelected ?? version,
|
|
338
|
+
},
|
|
339
|
+
}),
|
|
340
|
+
axios.get(process.env.REACT_APP_COMMENTS_ENDPOINT, {
|
|
341
|
+
params: {
|
|
342
|
+
articleId: id_article,
|
|
343
|
+
concept: "datasheet",
|
|
344
|
+
orderIdColab: id_order,
|
|
345
|
+
version: versionSelected ?? version,
|
|
346
|
+
},
|
|
347
|
+
}),
|
|
348
|
+
axios.get(process.env.REACT_APP_COMMENTS_ENDPOINT, {
|
|
349
|
+
params: {
|
|
350
|
+
articleId: id_article,
|
|
351
|
+
concept: "images",
|
|
352
|
+
orderIdColab: id_order,
|
|
353
|
+
version: versionSelected ?? version,
|
|
354
|
+
},
|
|
355
|
+
}),
|
|
356
|
+
]),
|
|
357
|
+
]);
|
|
358
|
+
|
|
359
|
+
dispatch({
|
|
360
|
+
type: "SET_RETAILER_STATUS",
|
|
361
|
+
payload: servicesDataRes.map((service) => ({
|
|
362
|
+
retailer_id: service?.id_retailer,
|
|
363
|
+
service: service?.service,
|
|
364
|
+
status: service?.status,
|
|
365
|
+
task_user_group_id: service?.task_user_group_id,
|
|
366
|
+
})),
|
|
483
367
|
});
|
|
484
368
|
|
|
485
|
-
|
|
369
|
+
// Extraer relaciones del response
|
|
370
|
+
const percentages =
|
|
371
|
+
JSON.parse(percentagesRes?.[0]?.body)?.[0]?.relations ?? [];
|
|
372
|
+
|
|
373
|
+
// Procesar comentarios
|
|
374
|
+
let commentsMap = {};
|
|
375
|
+
commentsResponse.forEach((commentRes) => {
|
|
376
|
+
const commentData = JSON.parse(commentRes?.data?.body).data[0];
|
|
377
|
+
if (commentData) {
|
|
378
|
+
const tab = translateConcept(commentData.concept);
|
|
379
|
+
commentsMap[tab] = commentData;
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
dispatch({ type: "SET_COMMENTS", payload: commentsMap });
|
|
383
|
+
|
|
384
|
+
// Ordenamiento de imágenes
|
|
385
|
+
const orderMap = services[2].inputsByRetailer
|
|
386
|
+
.flat()
|
|
387
|
+
.reduce((acc, item) => {
|
|
388
|
+
acc[item.id_image] = item.order;
|
|
389
|
+
return acc;
|
|
390
|
+
}, {});
|
|
391
|
+
|
|
392
|
+
const orderedValues = [...services[2].values].sort((a, b) => {
|
|
393
|
+
const orderA = orderMap[a.image_id] ?? Number.MAX_SAFE_INTEGER;
|
|
394
|
+
const orderB = orderMap[b.image_id] ?? Number.MAX_SAFE_INTEGER;
|
|
395
|
+
return orderA - orderB;
|
|
396
|
+
});
|
|
486
397
|
|
|
487
|
-
|
|
398
|
+
// Procesamiento de inputs del retailer activo (evita cascada con state.services)
|
|
399
|
+
const retailerDatasheets = services[0][id_retailer];
|
|
400
|
+
const datasheetsActiveRetailer = {
|
|
401
|
+
...retailerDatasheets,
|
|
402
|
+
data: Object.values(retailerDatasheets.data),
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
const descriptionsActiveRetailer = services[1].filter(
|
|
406
|
+
(item) => item.id === id_retailer,
|
|
407
|
+
);
|
|
408
|
+
|
|
409
|
+
const filteredValues = services[2].values.filter((value) => {
|
|
410
|
+
return services[2].inputsByRetailer.some((retailerInput) =>
|
|
411
|
+
retailerInput.some(
|
|
412
|
+
(input) =>
|
|
413
|
+
input.id_retailer === id_retailer &&
|
|
414
|
+
input.id_image === value.image_id,
|
|
415
|
+
),
|
|
416
|
+
);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Dispatch consolidado
|
|
420
|
+
dispatch({
|
|
421
|
+
type: "SET_SERVICES",
|
|
422
|
+
payload: {
|
|
423
|
+
datasheets: services[0],
|
|
424
|
+
descriptions: services[1],
|
|
425
|
+
images: {
|
|
426
|
+
...services[2],
|
|
427
|
+
values: orderedValues,
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
dispatch({ type: "SET_PERCENTAGES", payload: percentages });
|
|
433
|
+
dispatch({
|
|
434
|
+
type: "SET_ACTIVE_PERCENTAGES",
|
|
435
|
+
payload: percentages.find(
|
|
436
|
+
({ id_retailer: rId }) => rId === id_retailer,
|
|
437
|
+
),
|
|
438
|
+
});
|
|
439
|
+
dispatch({ type: "SET_SERVICES_DATA", payload: servicesDataRes });
|
|
440
|
+
|
|
441
|
+
// Setear inputs del retailer activo directamente (evita cascada)
|
|
442
|
+
dispatch({
|
|
443
|
+
type: "SET_DATASHEETS_INPUTS",
|
|
444
|
+
payload: [datasheetsActiveRetailer, services[0].inputs],
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
dispatch({
|
|
448
|
+
type: "SET_DESCRIPTIONS_INPUTS",
|
|
449
|
+
payload: descriptionsActiveRetailer,
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
dispatch({
|
|
453
|
+
type: "SET_IMAGES_VALUES",
|
|
454
|
+
payload: {
|
|
455
|
+
...services[2],
|
|
456
|
+
values: filteredValues,
|
|
457
|
+
},
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// Calcular campos requeridos sin valor
|
|
461
|
+
dispatch({
|
|
462
|
+
type: "SET_MISSING_REQUIRED_FIELDS",
|
|
463
|
+
payload: calculateRequiredNull(services, servicesDataRes, id_retailer),
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// Auditable
|
|
467
|
+
if (auditableVersion && id_retailer) {
|
|
468
|
+
loadAuditableData();
|
|
469
|
+
}
|
|
488
470
|
} catch (error) {
|
|
489
|
-
|
|
490
|
-
|
|
471
|
+
console.log("Error loading data: ", error);
|
|
472
|
+
dispatch({ type: "SET_ERRORS", payload: [error.message] });
|
|
473
|
+
} finally {
|
|
474
|
+
dispatch({ type: "SET_LOADING", payload: false });
|
|
491
475
|
}
|
|
492
476
|
};
|
|
493
477
|
|
|
494
478
|
useEffect(() => {
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
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;
|
|
479
|
+
if (state.active_retailer) {
|
|
480
|
+
loadData();
|
|
481
|
+
}
|
|
482
|
+
}, [state.active_retailer]);
|
|
506
483
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
setServicesData(parsedResponse);
|
|
484
|
+
const handleOnChangeCurrentImage = (index) => {
|
|
485
|
+
if (typeof index === "number") {
|
|
486
|
+
dispatch({ type: "SET_CURRENT_IMAGE", payload: index });
|
|
487
|
+
} else if (typeof index === "object") {
|
|
488
|
+
dispatch({ type: "CHANGE_ATTR_VALUE", payload: index });
|
|
489
|
+
}
|
|
514
490
|
};
|
|
515
491
|
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
return translation[concept];
|
|
492
|
+
const handleOnShowModalGallery = () => {
|
|
493
|
+
dispatch({
|
|
494
|
+
type: "SET_ACTIVE_TAB",
|
|
495
|
+
payload: "Imágenes",
|
|
496
|
+
});
|
|
497
|
+
setShowModal(true);
|
|
523
498
|
};
|
|
524
499
|
|
|
525
|
-
const
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
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);
|
|
500
|
+
const handleOnChangeActiveRetailer = (retailer) => {
|
|
501
|
+
dispatch({
|
|
502
|
+
type: "SET_ACTIVE_RETAILER",
|
|
503
|
+
payload: retailer,
|
|
504
|
+
});
|
|
548
505
|
};
|
|
549
506
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
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
|
-
},
|
|
507
|
+
const handleOnChangeActiveTab = (tab) => {
|
|
508
|
+
dispatch({
|
|
509
|
+
type: "SET_ACTIVE_TAB",
|
|
510
|
+
payload: tab,
|
|
626
511
|
});
|
|
627
512
|
};
|
|
628
513
|
|
|
629
|
-
|
|
630
|
-
|
|
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
|
-
));
|
|
514
|
+
const handleOnToggleImageLayout = () => {
|
|
515
|
+
setImageLayout(!imageLayout);
|
|
698
516
|
};
|
|
699
517
|
|
|
700
|
-
const
|
|
701
|
-
|
|
702
|
-
|
|
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
|
-
);
|
|
518
|
+
const handleOnToggleObservation = () => {
|
|
519
|
+
setObservationVisible(!isObservationVisible);
|
|
520
|
+
};
|
|
731
521
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
await loadData();
|
|
735
|
-
}
|
|
736
|
-
} catch (error) {
|
|
737
|
-
console.log(error);
|
|
738
|
-
} finally {
|
|
739
|
-
setLoading(false);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
522
|
+
const handleOnHideObservation = () => {
|
|
523
|
+
setObservationVisible(false);
|
|
742
524
|
};
|
|
743
525
|
|
|
744
|
-
const
|
|
745
|
-
|
|
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
|
-
}
|
|
526
|
+
const isAuditorAssigned = () => {
|
|
527
|
+
return state.product?.id_auditor === user?.id_user;
|
|
785
528
|
};
|
|
786
529
|
|
|
787
|
-
|
|
788
|
-
const
|
|
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
|
-
});
|
|
530
|
+
const isUserAssignedToService = (tab, rol) => {
|
|
531
|
+
const concept = getConceptByTab(state.active_tab);
|
|
807
532
|
|
|
808
|
-
const
|
|
809
|
-
const
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
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);
|
|
533
|
+
const allowedRoles = [1, 4, 5, 6, 7, 8];
|
|
534
|
+
const validUser = allowedRoles.includes(user?.id_role);
|
|
535
|
+
|
|
536
|
+
// Determinar rol por defecto si no se pasa
|
|
537
|
+
if (!rol) {
|
|
538
|
+
if (user.id_role === 4 || user.id_role === 5) {
|
|
539
|
+
rol = "facilitator";
|
|
540
|
+
} else if (user.id_role === 7 || user.id_role === 8) {
|
|
541
|
+
rol = "especialist";
|
|
928
542
|
}
|
|
929
543
|
}
|
|
930
|
-
}, [dataImages, imagesUploaded]);
|
|
931
544
|
|
|
932
|
-
|
|
933
|
-
const
|
|
934
|
-
const
|
|
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
|
-
};
|
|
545
|
+
const isAdmin = user.id_role === 1;
|
|
546
|
+
const idUserAssigned = state.product?.[`id_${concept}_${rol}`];
|
|
547
|
+
const isAssigned = idUserAssigned === user.id_user;
|
|
975
548
|
|
|
976
|
-
|
|
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
|
-
}
|
|
549
|
+
return isAdmin || (isAssigned && validUser);
|
|
985
550
|
};
|
|
986
551
|
|
|
987
|
-
const
|
|
988
|
-
let concept =
|
|
552
|
+
const canShowSingleEvaluationButtons = (action) => {
|
|
553
|
+
let concept = getConceptByTab(action || state.active_tab);
|
|
989
554
|
|
|
990
|
-
const retailerStatus =
|
|
991
|
-
|
|
555
|
+
const retailerStatus = state.services_data
|
|
556
|
+
?.find(
|
|
992
557
|
(srv) =>
|
|
993
|
-
srv.id_retailer ===
|
|
558
|
+
srv.id_retailer === state.active_retailer?.id_retailer &&
|
|
559
|
+
srv.service === concept,
|
|
994
560
|
)
|
|
995
561
|
?.status?.replace(/.*\//, "");
|
|
996
562
|
|
|
997
|
-
//sessionStorage product
|
|
998
563
|
const adminFacilitatorCanEvaluate =
|
|
999
564
|
retailerStatus === "IE" && [1, 4, 5].includes(user.id_role);
|
|
1000
565
|
const adminAuditorCanEvaluate =
|
|
1001
566
|
["AC", "RP", "RCA", "SAC"].includes(retailerStatus) &&
|
|
1002
567
|
[1, 6].includes(user.id_role);
|
|
568
|
+
|
|
1003
569
|
return adminFacilitatorCanEvaluate || adminAuditorCanEvaluate;
|
|
1004
570
|
};
|
|
1005
571
|
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1008
|
-
switch (user.id_role) {
|
|
1009
|
-
case 4:
|
|
1010
|
-
concepts = ["description", "datasheet"];
|
|
1011
|
-
break;
|
|
1012
|
-
case 5:
|
|
1013
|
-
concepts = ["images"];
|
|
1014
|
-
break;
|
|
572
|
+
const canShowBulkEvaluationButtons = () => {
|
|
573
|
+
const concepts = getConceptsByRole(user.id_role);
|
|
1015
574
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
break;
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
const services = servicesData.filter(({ service }) =>
|
|
1022
|
-
concepts.includes(service)
|
|
575
|
+
const services = state.services_data.filter(({ service }) =>
|
|
576
|
+
concepts.includes(service),
|
|
1023
577
|
);
|
|
1024
578
|
|
|
1025
579
|
const adminFacilitatorCanEvaluate =
|
|
1026
580
|
services.every((srv) => srv?.status?.replace(/.*\//, "") === "IE") &&
|
|
1027
581
|
[1, 4, 5].includes(user.id_role);
|
|
1028
582
|
|
|
1029
|
-
//sessionStorage product
|
|
1030
583
|
const adminAuditorCanEvaluate =
|
|
1031
|
-
|
|
1032
|
-
["AC", "RP", "RCA"].includes(srv?.status?.replace(/.*\//, ""))
|
|
584
|
+
state.services_data.every((srv) =>
|
|
585
|
+
["AC", "RP", "RCA"].includes(srv?.status?.replace(/.*\//, "")),
|
|
1033
586
|
) && [1, 6].includes(user.id_role);
|
|
1034
587
|
return adminFacilitatorCanEvaluate || adminAuditorCanEvaluate;
|
|
1035
588
|
};
|
|
1036
589
|
|
|
1037
|
-
const
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
590
|
+
const getStatusByCurrentServiceAndRetailer = () => {
|
|
591
|
+
const { statusByRetailer } = state.product;
|
|
592
|
+
if (!statusByRetailer) return "-";
|
|
593
|
+
|
|
594
|
+
const currentService = getConceptByTab(state.active_tab);
|
|
595
|
+
const currentRetailer = state.active_retailer.id_retailer;
|
|
596
|
+
const currentStatus =
|
|
597
|
+
statusByRetailer.filter(
|
|
598
|
+
(item) =>
|
|
599
|
+
item.retailer_id === currentRetailer &&
|
|
600
|
+
item.service === currentService,
|
|
601
|
+
)[0]?.status || "-";
|
|
602
|
+
|
|
603
|
+
return currentStatus;
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
const handleOnClickSaveImages = () => {
|
|
607
|
+
if (state.product?.services?.images === 1) {
|
|
608
|
+
saveImageAttrs(token);
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
|
|
612
|
+
const handleOnClickSave = async () => {
|
|
613
|
+
if (state.saving) return;
|
|
614
|
+
|
|
615
|
+
switch (state.active_tab) {
|
|
1042
616
|
case "Descripción":
|
|
1043
|
-
|
|
617
|
+
await saveDescriptions(token);
|
|
618
|
+
break;
|
|
619
|
+
case "Ficha técnica":
|
|
620
|
+
await saveDatasheets(token);
|
|
1044
621
|
break;
|
|
1045
622
|
case "Imágenes":
|
|
1046
|
-
|
|
623
|
+
await updateImages(token);
|
|
1047
624
|
break;
|
|
1048
625
|
default:
|
|
1049
626
|
break;
|
|
1050
627
|
}
|
|
628
|
+
|
|
629
|
+
await loadData(false);
|
|
630
|
+
};
|
|
631
|
+
|
|
632
|
+
const handleOnSetUpdatedDescriptions = (items) => {
|
|
633
|
+
dispatch({
|
|
634
|
+
type: "SET_UPDATED_DESCRIPTIONS_INPUTS",
|
|
635
|
+
payload: items,
|
|
636
|
+
});
|
|
637
|
+
};
|
|
638
|
+
|
|
639
|
+
const handleOnSetUpdatedDatasheets = (items) => {
|
|
640
|
+
dispatch({
|
|
641
|
+
type: "SET_UPDATED_DATASHEETS_INPUTS",
|
|
642
|
+
payload: items,
|
|
643
|
+
});
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
const handleOnAskToDeleteImages = () => {
|
|
647
|
+
if (state.selected_images.length === 0) {
|
|
648
|
+
dispatch({
|
|
649
|
+
type: "SET_MODAL",
|
|
650
|
+
payload: {
|
|
651
|
+
show: true,
|
|
652
|
+
title: "Eliminar imágenes",
|
|
653
|
+
message: "No has seleccionado ninguna imagen para eliminar.",
|
|
654
|
+
image: warningIcon,
|
|
655
|
+
},
|
|
656
|
+
});
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
dispatch({
|
|
661
|
+
type: "SET_MODAL",
|
|
662
|
+
payload: {
|
|
663
|
+
show: true,
|
|
664
|
+
title: "Eliminar imágenes",
|
|
665
|
+
message:
|
|
666
|
+
"¿Estás seguro de que deseas eliminar las imágenes seleccionadas?",
|
|
667
|
+
image: warningIcon,
|
|
668
|
+
buttons: [
|
|
669
|
+
{
|
|
670
|
+
text: "Cancelar",
|
|
671
|
+
buttonType: "general-white-button",
|
|
672
|
+
action: () =>
|
|
673
|
+
dispatch({ type: "SET_MODAL", payload: { show: false } }),
|
|
674
|
+
},
|
|
675
|
+
{
|
|
676
|
+
text: "Eliminar",
|
|
677
|
+
buttonType: "general-button-default",
|
|
678
|
+
action: () => {
|
|
679
|
+
dispatch({ type: "SET_MODAL", payload: { show: false } });
|
|
680
|
+
deleteImages(token);
|
|
681
|
+
},
|
|
682
|
+
},
|
|
683
|
+
],
|
|
684
|
+
},
|
|
685
|
+
});
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
const handleOnApproveSingleService = async () => {
|
|
689
|
+
await sendSingleEvaluation("A");
|
|
1051
690
|
};
|
|
1052
691
|
|
|
1053
|
-
const
|
|
1054
|
-
|
|
692
|
+
const handleOnRejectSingleService = () => {
|
|
693
|
+
setShowRejectModal(true);
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
const sendSingleEvaluation = async (result) => {
|
|
697
|
+
if (state.saving) return;
|
|
698
|
+
|
|
699
|
+
dispatch({ type: "SET_SAVING", payload: true });
|
|
700
|
+
|
|
701
|
+
const concept = getConceptByTab(state.active_tab);
|
|
702
|
+
|
|
703
|
+
const articleId = state.product.id_article;
|
|
704
|
+
const orderId = state.product.id_order ?? state.product.orderId;
|
|
705
|
+
const sectionStatusKey = `${concept}_status`;
|
|
706
|
+
const evalStatus = state.product[sectionStatusKey];
|
|
707
|
+
const retailerId = state.active_retailer?.id_retailer;
|
|
708
|
+
|
|
709
|
+
let data = { articleId, orderId, concept, evalStatus, retailerId };
|
|
710
|
+
let res;
|
|
711
|
+
let message;
|
|
712
|
+
let icon;
|
|
713
|
+
|
|
714
|
+
const activeTab = state.active_tab;
|
|
715
|
+
|
|
1055
716
|
try {
|
|
1056
|
-
|
|
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;
|
|
717
|
+
//Esto solo se ejecutará cuando se aprueba o rechaza desde el modal superior derecho
|
|
1072
718
|
if (result) {
|
|
1073
719
|
data.result = result;
|
|
720
|
+
data.retailerId = retailerId;
|
|
721
|
+
|
|
1074
722
|
res = await axios.put(
|
|
1075
723
|
`${process.env.REACT_APP_EVALUATION_ENDPOINT}`,
|
|
1076
724
|
data,
|
|
@@ -1078,254 +726,285 @@ export const RetailerProductEdition = ({
|
|
|
1078
726
|
headers: {
|
|
1079
727
|
Authorization: token,
|
|
1080
728
|
},
|
|
1081
|
-
}
|
|
729
|
+
},
|
|
730
|
+
);
|
|
731
|
+
|
|
732
|
+
const newStatuses = JSON.parse(res.data.body);
|
|
733
|
+
const serviceStatus =
|
|
734
|
+
newStatuses.newServiceStatus[articleId][`${concept}Status`];
|
|
735
|
+
|
|
736
|
+
// Actualizar el producto con los nuevos estados
|
|
737
|
+
const updatedStatusByRetailer = state.product.statusByRetailer.map(
|
|
738
|
+
(item) =>
|
|
739
|
+
item.retailer_id === retailerId && item.service === concept
|
|
740
|
+
? { ...item, status: serviceStatus }
|
|
741
|
+
: item,
|
|
1082
742
|
);
|
|
1083
|
-
|
|
1084
|
-
|
|
743
|
+
|
|
744
|
+
const updatedProduct = {
|
|
745
|
+
...state.product,
|
|
746
|
+
statusByRetailer: updatedStatusByRetailer,
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
dispatch({ type: "SET_PRODUCT", payload: updatedProduct });
|
|
750
|
+
|
|
751
|
+
// Mostrar modal de éxito
|
|
752
|
+
dispatch({
|
|
753
|
+
type: "SET_MODAL",
|
|
754
|
+
payload: {
|
|
755
|
+
show: true,
|
|
756
|
+
title: "",
|
|
757
|
+
message:
|
|
758
|
+
result === "A" ? "Aprobado con éxito" : "Rechazado con éxito",
|
|
759
|
+
image: successIcon,
|
|
760
|
+
},
|
|
761
|
+
});
|
|
762
|
+
} else { //Caso del botón "Enviar evaluación"
|
|
763
|
+
|
|
764
|
+
//Se construye el mensaje y se actualiza el estatus
|
|
765
|
+
|
|
1085
766
|
const specialistDone = ["RC", "RA", "CA"].includes(evalStatus);
|
|
1086
767
|
|
|
1087
768
|
if (specialistDone) {
|
|
1088
769
|
message = `${activeTab} enviada a facilitador`;
|
|
1089
|
-
|
|
770
|
+
icon =
|
|
771
|
+
activeTab === "Descripción"
|
|
772
|
+
? descriptionSent
|
|
773
|
+
: activeTab === "Ficha técnica"
|
|
774
|
+
? attributesSent
|
|
775
|
+
: imagesSent;
|
|
1090
776
|
} else if (["IE", "AC", "RP", "RCA"].includes(evalStatus)) {
|
|
1091
777
|
message = "Evaluación enviada";
|
|
1092
|
-
|
|
778
|
+
icon = successIcon;
|
|
1093
779
|
}
|
|
780
|
+
|
|
1094
781
|
res = await axios.put(`${process.env.REACT_APP_SEND_EVAL}`, data, {
|
|
1095
782
|
headers: {
|
|
1096
783
|
Authorization: token,
|
|
1097
784
|
},
|
|
1098
785
|
});
|
|
1099
786
|
}
|
|
787
|
+
|
|
1100
788
|
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
789
|
|
|
1112
|
-
const
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
790
|
+
const { newStatus, newOrderStatus, newArticleStatus } = JSON.parse( res.data.body );
|
|
791
|
+
|
|
792
|
+
// const retailers = state.product.categoryRetailer.map((r) => ({
|
|
793
|
+
// id: r.id_retailer,
|
|
794
|
+
// name: r.retailerName,
|
|
795
|
+
// }));
|
|
796
|
+
// const messageToChat = createMessage(
|
|
797
|
+
// retailers,
|
|
798
|
+
// retailerId,
|
|
799
|
+
// evalStatus,
|
|
800
|
+
// newStatus,
|
|
801
|
+
// activeTab,
|
|
802
|
+
// );
|
|
803
|
+
|
|
804
|
+
// const messageData = {
|
|
805
|
+
// paramsBody: {
|
|
806
|
+
// id: articleId,
|
|
807
|
+
// version: state.product.version,
|
|
808
|
+
// items: [{ type: "status", value: messageToChat }],
|
|
809
|
+
// retailerId: retailerId,
|
|
810
|
+
// status: state.product.status,
|
|
811
|
+
// },
|
|
812
|
+
// paramsHeader: { Authorization: token },
|
|
813
|
+
// };
|
|
814
|
+
// await sendMessage(messageData);
|
|
815
|
+
|
|
816
|
+
const updatedProduct = {
|
|
817
|
+
...state.product,
|
|
818
|
+
[`${concept}_status`]: newStatus,
|
|
819
|
+
// actualizar el status es statusByRetailer
|
|
820
|
+
statusByRetailer: state.product.statusByRetailer.map((item) => {
|
|
821
|
+
if (item.retailer_id === retailerId && item.service === concept) {
|
|
822
|
+
return { ...item, status: newStatus };
|
|
823
|
+
}
|
|
824
|
+
return item;
|
|
825
|
+
}),
|
|
1121
826
|
};
|
|
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
827
|
|
|
1136
|
-
|
|
1137
|
-
let concept = getConcept(activeTab);
|
|
828
|
+
//Actualizamos el services_data en el servicio específico del retailer actual
|
|
1138
829
|
|
|
1139
|
-
|
|
1140
|
-
|
|
830
|
+
const updatedServicesData = state.services_data?.map(service => ({
|
|
831
|
+
...service,
|
|
832
|
+
status: service?.id_retailer === retailerId && service?.service === concept ? newStatus : service?.status
|
|
833
|
+
}));
|
|
834
|
+
|
|
835
|
+
const sessionProduct = sessionStorage.getItem("productSelected");
|
|
836
|
+
|
|
837
|
+
if (sessionProduct) {
|
|
838
|
+
const productInSession = JSON.parse(sessionProduct);
|
|
839
|
+
const updatedProductInSession = {
|
|
840
|
+
...productInSession,
|
|
841
|
+
[`${concept}_status`]: newStatus,
|
|
842
|
+
statusByRetailer: state.product.statusByRetailer.map((item) => {
|
|
843
|
+
if (item.retailer_id === retailerId && item.service === concept) {
|
|
844
|
+
return { ...item, status: newStatus };
|
|
845
|
+
}
|
|
846
|
+
return item;
|
|
847
|
+
}),
|
|
848
|
+
};
|
|
849
|
+
sessionStorage.setItem(
|
|
850
|
+
"productSelected",
|
|
851
|
+
JSON.stringify(updatedProductInSession),
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (message) {
|
|
856
|
+
dispatch({
|
|
857
|
+
type: "SET_MODAL",
|
|
858
|
+
payload: {
|
|
859
|
+
show: true,
|
|
860
|
+
title: "",
|
|
861
|
+
message: message,
|
|
862
|
+
image: successIcon,
|
|
863
|
+
},
|
|
864
|
+
});
|
|
865
|
+
}
|
|
1141
866
|
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
case 4:
|
|
1145
|
-
case 5:
|
|
1146
|
-
rol = "facilitator";
|
|
1147
|
-
break;
|
|
1148
|
-
case 7:
|
|
1149
|
-
case 8:
|
|
1150
|
-
rol = "especialist";
|
|
1151
|
-
break;
|
|
867
|
+
dispatch({ type: "SET_PRODUCT", payload: updatedProduct });
|
|
868
|
+
dispatch({ type: "SET_SERVICES_DATA", payload: updatedServicesData });
|
|
1152
869
|
}
|
|
870
|
+
} catch (error) {
|
|
871
|
+
console.error("Error sending evaluation:", error);
|
|
872
|
+
dispatch({
|
|
873
|
+
type: "SET_MODAL",
|
|
874
|
+
payload: {
|
|
875
|
+
show: true,
|
|
876
|
+
title: "Error",
|
|
877
|
+
message: "Hubo un error al procesar la evaluación",
|
|
878
|
+
image: errorIcon,
|
|
879
|
+
},
|
|
880
|
+
});
|
|
881
|
+
} finally {
|
|
882
|
+
dispatch({ type: "SET_SAVING", payload: false });
|
|
1153
883
|
}
|
|
1154
|
-
|
|
1155
|
-
return (
|
|
1156
|
-
user.id_role === 1 ||
|
|
1157
|
-
(product.article[`id_${concept}_${rol}`] === user.id_user && validUser)
|
|
1158
|
-
);
|
|
1159
884
|
};
|
|
1160
885
|
|
|
1161
|
-
const
|
|
1162
|
-
|
|
886
|
+
const handleOnApproveAllServices = async () => {
|
|
887
|
+
await sendBulkEvaluation("A");
|
|
1163
888
|
};
|
|
1164
889
|
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1167
|
-
|
|
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([]);
|
|
890
|
+
const handleOnRejectAllServices = () => {
|
|
891
|
+
setRejectAll(true);
|
|
892
|
+
setShowRejectModal(true);
|
|
1194
893
|
};
|
|
1195
894
|
|
|
1196
|
-
const
|
|
895
|
+
const sendBulkEvaluation = async (result) => {
|
|
896
|
+
dispatch({ type: "SET_SAVING", payload: true });
|
|
1197
897
|
try {
|
|
1198
|
-
const
|
|
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
|
-
);
|
|
898
|
+
const evaluationArray = [];
|
|
1212
899
|
|
|
1213
|
-
|
|
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
|
-
});
|
|
900
|
+
const conceptArray = getConceptsByRole(user.id_role);
|
|
1228
901
|
|
|
1229
|
-
|
|
902
|
+
state.services_data?.forEach((ret, idx) => {
|
|
903
|
+
const { service: retailer_service, id_retailer, status: status_retailer_service } = ret;
|
|
1230
904
|
|
|
1231
|
-
|
|
1232
|
-
descriptionsServicesArray.forEach((description) => {
|
|
1233
|
-
if (description.id != activeRetailer.id) return;
|
|
905
|
+
const lastStatusLevel = status_retailer_service.replace(/.*\//, "");
|
|
1234
906
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
907
|
+
if (conceptArray.includes(retailer_service) && statusArray?.includes(lastStatusLevel)) {
|
|
908
|
+
const data = {
|
|
909
|
+
articleId: state.product.id_article,
|
|
910
|
+
orderId: state.product.id_order,
|
|
911
|
+
concept: retailer_service,
|
|
912
|
+
result,
|
|
913
|
+
evalStatus: status_retailer_service,
|
|
914
|
+
retailerId: id_retailer,
|
|
915
|
+
};
|
|
1240
916
|
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
)
|
|
1247
|
-
|
|
1248
|
-
}
|
|
1249
|
-
});
|
|
917
|
+
evaluationArray.push(
|
|
918
|
+
axios.put(`${process.env.REACT_APP_EVALUATION_ENDPOINT}`, data, {
|
|
919
|
+
headers: {
|
|
920
|
+
Authorization: token,
|
|
921
|
+
},
|
|
922
|
+
}),
|
|
923
|
+
);
|
|
1250
924
|
}
|
|
1251
925
|
});
|
|
1252
926
|
|
|
1253
|
-
|
|
927
|
+
await Promise.all(evaluationArray);
|
|
1254
928
|
|
|
1255
|
-
const
|
|
929
|
+
const status = `${result}A`;
|
|
1256
930
|
|
|
1257
|
-
|
|
1258
|
-
|
|
931
|
+
// Actualizar el statusByRetailer para todos los retailers y conceptos
|
|
932
|
+
const updatedStatusByRetailer = state.product.statusByRetailer.map(
|
|
933
|
+
(item) =>
|
|
934
|
+
conceptArray.includes(item.service) ? { ...item, status } : item,
|
|
1259
935
|
);
|
|
1260
936
|
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
937
|
+
// Actualizar el producto con los nuevos estados
|
|
938
|
+
const updatedProduct = {
|
|
939
|
+
...state.product,
|
|
940
|
+
article_status: status,
|
|
941
|
+
status: status,
|
|
942
|
+
datasheet_status:
|
|
943
|
+
state.product.datasheet_status === "NA" ? "NA" : status,
|
|
944
|
+
description_status:
|
|
945
|
+
state.product.description_status === "NA" ? "NA" : status,
|
|
946
|
+
images_status: state.product.images_status === "NA" ? "NA" : status,
|
|
947
|
+
statusByRetailer: updatedStatusByRetailer,
|
|
948
|
+
};
|
|
1271
949
|
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
services[2].values.filter((img) => img.image_id === req.id).length ===
|
|
1276
|
-
0 && requiredCounter++
|
|
1277
|
-
);
|
|
950
|
+
dispatch({
|
|
951
|
+
type: "SET_PRODUCT",
|
|
952
|
+
payload: updatedProduct,
|
|
1278
953
|
});
|
|
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
954
|
|
|
1290
|
-
|
|
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
|
-
};
|
|
955
|
+
const updatedServicesData = state.services_data.map(service => conceptArray.includes(service.service) ? { ...service, status: status } : service);
|
|
1302
956
|
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
concept = "datasheet";
|
|
1308
|
-
break;
|
|
1309
|
-
case "Imágenes":
|
|
1310
|
-
concept = "images";
|
|
1311
|
-
break;
|
|
957
|
+
dispatch({
|
|
958
|
+
type: "SET_SERVICES_DATA",
|
|
959
|
+
payload: updatedServicesData,
|
|
960
|
+
});
|
|
1312
961
|
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
962
|
+
// sessionStorage.setItem(
|
|
963
|
+
// "productSelected",
|
|
964
|
+
// JSON.stringify(updatedProduct),
|
|
965
|
+
// );
|
|
966
|
+
// sessionStorage.setItem(
|
|
967
|
+
// "productEdit",
|
|
968
|
+
// JSON.stringify({
|
|
969
|
+
// ArticleId: updatedProduct.id_article,
|
|
970
|
+
// idCategory: updatedProduct.id_category,
|
|
971
|
+
// product: updatedProduct,
|
|
972
|
+
// }),
|
|
973
|
+
// );
|
|
974
|
+
|
|
975
|
+
// Mostrar modal de éxito
|
|
976
|
+
dispatch({
|
|
977
|
+
type: "SET_MODAL",
|
|
978
|
+
payload: {
|
|
979
|
+
show: true,
|
|
980
|
+
title: "",
|
|
981
|
+
message:
|
|
982
|
+
result === "A"
|
|
983
|
+
? "Todos los servicios aprobados con éxito"
|
|
984
|
+
: "Todos los servicios rechazados con éxito",
|
|
985
|
+
image: successIcon,
|
|
986
|
+
},
|
|
987
|
+
});
|
|
988
|
+
} catch (error) {
|
|
989
|
+
console.error("Error in bulk evaluation:", error);
|
|
990
|
+
} finally {
|
|
991
|
+
dispatch({ type: "SET_SAVING", payload: false });
|
|
1316
992
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
993
|
+
};
|
|
994
|
+
|
|
995
|
+
const handleOnChangeAssignations = async (assignationType, assignationId) => {
|
|
996
|
+
const concept = getConceptByTab(state.active_tab);
|
|
1319
997
|
const data = {
|
|
1320
998
|
articleList: [
|
|
1321
999
|
{
|
|
1322
|
-
orderId: product.
|
|
1323
|
-
articleId: product
|
|
1000
|
+
orderId: state.product.id_order,
|
|
1001
|
+
articleId: state.product.id_article,
|
|
1324
1002
|
},
|
|
1325
1003
|
],
|
|
1326
1004
|
concept: concept,
|
|
1327
1005
|
userId: assignationId,
|
|
1328
1006
|
};
|
|
1007
|
+
|
|
1329
1008
|
await axios({
|
|
1330
1009
|
method: "post",
|
|
1331
1010
|
url: process.env.REACT_APP_ASSIGNATIONS_ENDPOINT,
|
|
@@ -1334,646 +1013,794 @@ export const RetailerProductEdition = ({
|
|
|
1334
1013
|
Authorization: token,
|
|
1335
1014
|
},
|
|
1336
1015
|
});
|
|
1337
|
-
loadAssignations(productTemp);
|
|
1338
|
-
sessionStorage.setItem("productSelected", JSON.stringify(productTemp));
|
|
1339
|
-
};
|
|
1340
1016
|
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
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
|
-
});
|
|
1017
|
+
const updatedProduct = {
|
|
1018
|
+
...state.product,
|
|
1019
|
+
[`id_${concept}_${assignationType}`]: assignationId,
|
|
1020
|
+
};
|
|
1021
|
+
|
|
1022
|
+
dispatch({ type: "SET_PRODUCT", payload: updatedProduct });
|
|
1359
1023
|
};
|
|
1360
1024
|
|
|
1361
|
-
const
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
const imgsInBack = [];
|
|
1025
|
+
const handleOnSetAssignation = () => {
|
|
1026
|
+
console.log("handleOnSetAssignation - pendiente de implementar");
|
|
1027
|
+
};
|
|
1365
1028
|
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1029
|
+
const handleOnSetImages = () => {
|
|
1030
|
+
console.log("handleOnSetImages - pendiente de implementar");
|
|
1031
|
+
};
|
|
1369
1032
|
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1033
|
+
const handleOnSetCheckAll = (isChecked) => {
|
|
1034
|
+
dispatch({ type: "TOGGLE_CHECK_ALL_IMAGES", payload: isChecked });
|
|
1035
|
+
};
|
|
1373
1036
|
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1037
|
+
const handleOnSetSelectedImages = () => {
|
|
1038
|
+
/*
|
|
1039
|
+
Esta función no se utiliza actualmente.
|
|
1040
|
+
|
|
1041
|
+
En la versión anterior se usaban dos funciones distintas para el checkbox
|
|
1042
|
+
"Seleccionar todo":
|
|
1043
|
+
- Una para cambiar el valor booleano del checkbox.
|
|
1044
|
+
- Otra para actualizar el array de imágenes seleccionadas.
|
|
1045
|
+
|
|
1046
|
+
En la versión actual se unificó la lógica en una sola función,
|
|
1047
|
+
`handleOnSetCheckAll`, que recibe el valor `true` o `false` del checkbox
|
|
1048
|
+
"Seleccionar todo" y, a partir de este, agrega o elimina todas las imágenes
|
|
1049
|
+
del array de imágenes seleccionadas.
|
|
1050
|
+
*/
|
|
1051
|
+
console.log("setSelectedImages");
|
|
1052
|
+
};
|
|
1053
|
+
const handleOnSubmitComment = async (e) => {
|
|
1054
|
+
e.preventDefault();
|
|
1055
|
+
const commentText = document.querySelector(
|
|
1056
|
+
"#commentary-box .ql-container .ql-editor > p",
|
|
1057
|
+
).innerHTML;
|
|
1058
|
+
try {
|
|
1059
|
+
await createComment(commentText, token);
|
|
1060
|
+
|
|
1061
|
+
dispatch({
|
|
1062
|
+
type: "SET_MODAL",
|
|
1063
|
+
payload: {
|
|
1064
|
+
show: true,
|
|
1065
|
+
title: "",
|
|
1066
|
+
message: "Comentario guardado con éxito",
|
|
1067
|
+
image: successIcon,
|
|
1068
|
+
},
|
|
1069
|
+
});
|
|
1070
|
+
} catch (error) {
|
|
1071
|
+
console.error("Error saving comment:", error);
|
|
1072
|
+
dispatch({
|
|
1073
|
+
type: "SET_MODAL",
|
|
1074
|
+
payload: {
|
|
1075
|
+
show: true,
|
|
1076
|
+
title: "Error",
|
|
1077
|
+
message: "Hubo un error al guardar el comentario",
|
|
1078
|
+
image: errorIcon,
|
|
1079
|
+
},
|
|
1080
|
+
});
|
|
1391
1081
|
}
|
|
1082
|
+
};
|
|
1392
1083
|
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
});
|
|
1397
|
-
|
|
1398
|
-
getRequired([
|
|
1399
|
-
services[0],
|
|
1400
|
-
services[1],
|
|
1401
|
-
{ ...services[2], values: imgsLeft },
|
|
1402
|
-
]);
|
|
1084
|
+
const handleOnSendEvaluationToFacilitator = () => {
|
|
1085
|
+
sendSingleEvaluation();
|
|
1086
|
+
};
|
|
1403
1087
|
|
|
1404
|
-
|
|
1088
|
+
const isEvaluationFinished = (id_rol, tab, statusArray) => {
|
|
1089
|
+
const servicesData = state.services_data;
|
|
1090
|
+
const activeRetailer = state.active_retailer;
|
|
1091
|
+
const product = state.product;
|
|
1092
|
+
const concept = getConceptByTab(tab);
|
|
1405
1093
|
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1094
|
+
const servicesByTab = servicesData?.filter(
|
|
1095
|
+
(serv) => serv.service === concept,
|
|
1096
|
+
);
|
|
1409
1097
|
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
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
|
-
};
|
|
1098
|
+
const statusBySelectedRetailerService = servicesByTab
|
|
1099
|
+
?.find((serv) => serv.id_retailer === activeRetailer?.id_retailer)
|
|
1100
|
+
?.status?.replace(/.*\//, "");
|
|
1438
1101
|
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1102
|
+
const currentProducStatus = product?.[`${concept}_status`]?.replace(
|
|
1103
|
+
/.*\//,
|
|
1104
|
+
"",
|
|
1105
|
+
);
|
|
1442
1106
|
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
service.id_retailer === activeRetailer?.id &&
|
|
1447
|
-
service.service === concept
|
|
1107
|
+
const unvalidated = ["IE", "CA"].includes(currentProducStatus);
|
|
1108
|
+
const auditorUnvalidated = !["RA", "AA", "ACA", "AP"].includes(
|
|
1109
|
+
currentProducStatus,
|
|
1448
1110
|
);
|
|
1449
|
-
return retailerService ? retailerService.status : "NS";
|
|
1450
|
-
};
|
|
1451
1111
|
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1112
|
+
let result;
|
|
1113
|
+
switch (id_rol) {
|
|
1114
|
+
case 7:
|
|
1115
|
+
case 8:
|
|
1456
1116
|
|
|
1457
|
-
|
|
1458
|
-
services.length > 0 && getRequired(services);
|
|
1459
|
-
}, [services, servicesData, activeTab]);
|
|
1117
|
+
const canSendEvaluation = statusArray.includes(statusBySelectedRetailerService);
|
|
1460
1118
|
|
|
1461
|
-
|
|
1462
|
-
setSaving(loading);
|
|
1463
|
-
}, [loading]);
|
|
1119
|
+
// const conditionTwo = statusArray.includes(product?.status);
|
|
1464
1120
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
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
|
-
}
|
|
1121
|
+
// const conditionThree =
|
|
1122
|
+
// servicesByTab.filter((service) =>
|
|
1123
|
+
// statusArray.includes(service.status?.replace(/.*\//, "")),
|
|
1124
|
+
// ).length === servicesByTab.length;
|
|
1482
1125
|
|
|
1483
|
-
|
|
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);
|
|
1126
|
+
// return (canSendEvaluation && conditionTwo) || conditionThree;
|
|
1505
1127
|
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1128
|
+
return canSendEvaluation;
|
|
1129
|
+
|
|
1130
|
+
case 4:
|
|
1131
|
+
case 5:
|
|
1132
|
+
const filteredSrv45 = servicesByTab?.filter((serv) =>
|
|
1133
|
+
statusArray.includes(serv?.status),
|
|
1134
|
+
);
|
|
1135
|
+
const condition45 =
|
|
1136
|
+
unvalidated &&
|
|
1137
|
+
["CA", "IE"].includes(product?.status) &&
|
|
1138
|
+
filteredSrv45?.length === servicesByTab?.length;
|
|
1139
|
+
return condition45;
|
|
1140
|
+
case 6:
|
|
1141
|
+
const statusInArray = statusArray.includes(product?.status);
|
|
1142
|
+
const allSrvValid = srv?.every((serv) =>
|
|
1143
|
+
["RA", "AA", "AP", "ACA"].includes(serv?.status),
|
|
1144
|
+
);
|
|
1145
|
+
const condition6 = statusInArray && allSrvValid && auditorUnvalidated;
|
|
1146
|
+
return condition6;
|
|
1147
|
+
default:
|
|
1148
|
+
console.log("Default case - returning false");
|
|
1149
|
+
return false;
|
|
1523
1150
|
}
|
|
1524
1151
|
};
|
|
1525
1152
|
|
|
1526
|
-
const
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1153
|
+
const handleOnChangeProductVersion = (version) => {
|
|
1154
|
+
dispatch({
|
|
1155
|
+
type: "SET_PRODUCT_VERSION",
|
|
1156
|
+
payload: version,
|
|
1157
|
+
});
|
|
1158
|
+
|
|
1159
|
+
loadData(true, version);
|
|
1160
|
+
};
|
|
1161
|
+
|
|
1162
|
+
const ProductEditionSkeleton = () => {
|
|
1163
|
+
return (
|
|
1164
|
+
<Container headerTop={0}>
|
|
1165
|
+
<Box
|
|
1166
|
+
px={1.5}
|
|
1167
|
+
py={1}
|
|
1168
|
+
pb={0}
|
|
1169
|
+
display="flex"
|
|
1170
|
+
alignItems="center"
|
|
1171
|
+
justifyContent="space-between"
|
|
1172
|
+
>
|
|
1173
|
+
<Skeleton variant="text" width={300} height={40} />
|
|
1174
|
+
<Stack direction="row" spacing={2}>
|
|
1175
|
+
<Skeleton variant="circular" width={32} height={32} />
|
|
1176
|
+
</Stack>
|
|
1177
|
+
</Box>
|
|
1178
|
+
|
|
1179
|
+
<div
|
|
1180
|
+
className="data-container"
|
|
1181
|
+
style={{ display: "flex", gap: "8px", padding: "0 12px 12px" }}
|
|
1182
|
+
>
|
|
1183
|
+
<div
|
|
1184
|
+
className="image-data-panel"
|
|
1185
|
+
style={{
|
|
1186
|
+
flex: "0 0 320px",
|
|
1187
|
+
display: "flex",
|
|
1188
|
+
flexDirection: "column",
|
|
1189
|
+
gap: "20px",
|
|
1190
|
+
}}
|
|
1191
|
+
>
|
|
1192
|
+
<Skeleton variant="rounded" width="100%" height={400} />
|
|
1193
|
+
|
|
1194
|
+
<Stack direction="row" spacing={2} justifyContent="center">
|
|
1195
|
+
{[1, 2, 3, 4].map((item) => (
|
|
1196
|
+
<Skeleton key={item} variant="rounded" width={60} height={80} />
|
|
1197
|
+
))}
|
|
1198
|
+
</Stack>
|
|
1199
|
+
|
|
1200
|
+
<Box mt={2}>
|
|
1201
|
+
{[1, 2, 3, 4].map((item) => (
|
|
1202
|
+
<Box
|
|
1203
|
+
key={item}
|
|
1204
|
+
display="flex"
|
|
1205
|
+
justifyContent="space-between"
|
|
1206
|
+
py={1}
|
|
1207
|
+
borderBottom="1px solid #f0f0f0"
|
|
1208
|
+
>
|
|
1209
|
+
<Skeleton variant="text" width="40%" />
|
|
1210
|
+
<Skeleton variant="text" width="20%" />
|
|
1211
|
+
</Box>
|
|
1212
|
+
))}
|
|
1213
|
+
</Box>
|
|
1214
|
+
</div>
|
|
1215
|
+
|
|
1216
|
+
<div
|
|
1217
|
+
className="product-information"
|
|
1218
|
+
style={{
|
|
1219
|
+
flex: 1,
|
|
1220
|
+
display: "flex",
|
|
1221
|
+
flexDirection: "column",
|
|
1222
|
+
gap: "14px",
|
|
1223
|
+
}}
|
|
1224
|
+
>
|
|
1225
|
+
<Box>
|
|
1226
|
+
<Skeleton variant="text" width="80%" height={50} />
|
|
1227
|
+
<Stack direction="row" spacing={2} alignItems="center">
|
|
1228
|
+
<Skeleton variant="rounded" width={180} height={24} />
|
|
1229
|
+
<Skeleton variant="rounded" width={300} height={24} />
|
|
1230
|
+
</Stack>
|
|
1231
|
+
</Box>
|
|
1232
|
+
|
|
1233
|
+
<Box display="flex" gap={4} pb={1}>
|
|
1234
|
+
<Skeleton variant="text" width={140} height={45} />
|
|
1235
|
+
<Skeleton variant="text" width={140} height={45} />
|
|
1236
|
+
<Skeleton variant="text" width={140} height={45} />
|
|
1237
|
+
</Box>
|
|
1238
|
+
|
|
1239
|
+
<Box display="flex" flexDirection="column" gap={4}>
|
|
1240
|
+
{[1, 2, 3].map((item) => (
|
|
1241
|
+
<Box key={item}>
|
|
1242
|
+
<Box
|
|
1243
|
+
display="flex"
|
|
1244
|
+
justifyContent="space-between"
|
|
1245
|
+
alignItems="center"
|
|
1246
|
+
mb={1}
|
|
1247
|
+
>
|
|
1248
|
+
<Skeleton variant="text" width="30%" height={24} />
|
|
1249
|
+
<Skeleton
|
|
1250
|
+
variant="rounded"
|
|
1251
|
+
width={175}
|
|
1252
|
+
height={25}
|
|
1253
|
+
sx={{ borderRadius: "7.5px" }}
|
|
1254
|
+
/>
|
|
1255
|
+
</Box>
|
|
1256
|
+
<Skeleton variant="rounded" width="100%" height={70} />
|
|
1257
|
+
<Box display="flex" justifyContent="flex-end" mt={0.5}>
|
|
1258
|
+
<Skeleton variant="text" width={60} />
|
|
1259
|
+
</Box>
|
|
1260
|
+
</Box>
|
|
1261
|
+
))}
|
|
1262
|
+
</Box>
|
|
1263
|
+
|
|
1264
|
+
<Box mt="auto" pt={4}>
|
|
1265
|
+
<Skeleton variant="rounded" width="100%" height={120} />
|
|
1266
|
+
<Box display="flex" justifyContent="flex-end" gap={2} mt={2}>
|
|
1267
|
+
<Skeleton
|
|
1268
|
+
variant="rounded"
|
|
1269
|
+
width={180}
|
|
1270
|
+
height={45}
|
|
1271
|
+
sx={{ borderRadius: "24px" }}
|
|
1272
|
+
/>
|
|
1273
|
+
<Skeleton
|
|
1274
|
+
variant="rounded"
|
|
1275
|
+
width={180}
|
|
1276
|
+
height={45}
|
|
1277
|
+
sx={{ borderRadius: "24px" }}
|
|
1278
|
+
/>
|
|
1279
|
+
</Box>
|
|
1280
|
+
</Box>
|
|
1281
|
+
</div>
|
|
1282
|
+
</div>
|
|
1283
|
+
</Container>
|
|
1534
1284
|
);
|
|
1535
|
-
const parseData = JSON.parse(response.data.body).data[0];
|
|
1536
|
-
setObservation(parseData.observations);
|
|
1537
1285
|
};
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1286
|
+
|
|
1287
|
+
if (state.loading || !state.services || !state.product)
|
|
1288
|
+
return (
|
|
1289
|
+
<>
|
|
1290
|
+
<ProductEditionSkeleton />
|
|
1291
|
+
</>
|
|
1292
|
+
);
|
|
1293
|
+
|
|
1541
1294
|
return (
|
|
1542
|
-
<
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
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()
|
|
1295
|
+
<AiProductEditionProvider
|
|
1296
|
+
isCreatorsEdition={true}
|
|
1297
|
+
user={user}
|
|
1298
|
+
token={token}
|
|
1299
|
+
state={state}
|
|
1300
|
+
>
|
|
1301
|
+
<Container headerTop={headerTop}>
|
|
1302
|
+
{showRejectModal && (
|
|
1303
|
+
<Modal
|
|
1304
|
+
title={
|
|
1305
|
+
rejectAll
|
|
1306
|
+
? "Agregar mensaje para rechazar todo"
|
|
1307
|
+
: "Agregar mensaje de rechazo"
|
|
1573
1308
|
}
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
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())
|
|
1309
|
+
show={showRejectModal}
|
|
1310
|
+
customComponent={
|
|
1311
|
+
<TagAndInput
|
|
1312
|
+
inputType={"textarea"}
|
|
1313
|
+
inputId={"modal-message-box"}
|
|
1314
|
+
index={0}
|
|
1315
|
+
color={"white"}
|
|
1316
|
+
/>
|
|
1597
1317
|
}
|
|
1598
|
-
|
|
1599
|
-
|
|
1318
|
+
buttons={[
|
|
1319
|
+
<ButtonV2
|
|
1320
|
+
key={"btn-Cancelar"}
|
|
1321
|
+
type={"white"}
|
|
1322
|
+
label={"Cancelar"}
|
|
1323
|
+
size={12}
|
|
1324
|
+
onClick={() => {
|
|
1325
|
+
setShowRejectModal(false);
|
|
1326
|
+
}}
|
|
1327
|
+
/>,
|
|
1328
|
+
<ButtonV2
|
|
1329
|
+
key={"btn-Aceptar"}
|
|
1330
|
+
type={"pink"}
|
|
1331
|
+
label={"Aceptar"}
|
|
1332
|
+
size={12}
|
|
1333
|
+
onClick={async () => {
|
|
1334
|
+
const elements = document.querySelectorAll(
|
|
1335
|
+
"#modal-message-box .ql-container .ql-editor > p",
|
|
1336
|
+
);
|
|
1337
|
+
|
|
1338
|
+
if (!elements || elements.length === 0) {
|
|
1339
|
+
console.error("Elemento no encontrado");
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
const isMessageEmpty = Array.from(elements).every((el) => {
|
|
1344
|
+
const body = el.innerHTML;
|
|
1345
|
+
return (
|
|
1346
|
+
!body || body.replace(/<.*?\/?>/gm, "").trim() === ""
|
|
1347
|
+
);
|
|
1348
|
+
});
|
|
1349
|
+
|
|
1350
|
+
if (isMessageEmpty) {
|
|
1351
|
+
const container = document.querySelector(
|
|
1352
|
+
".container-customComponent",
|
|
1353
|
+
);
|
|
1354
|
+
const existingAlert =
|
|
1355
|
+
container.querySelector(".alert-error");
|
|
1356
|
+
|
|
1357
|
+
if (!existingAlert) {
|
|
1358
|
+
const alert = document.createElement("div");
|
|
1359
|
+
alert.className = "alert-error";
|
|
1360
|
+
alert.style.cssText = `
|
|
1361
|
+
color: #d32f2f;
|
|
1362
|
+
background-color: #ffebee;
|
|
1363
|
+
border: 1px solid #ef5350;
|
|
1364
|
+
border-radius: 4px;
|
|
1365
|
+
padding: 12px 16px;
|
|
1366
|
+
margin-top: 10px;
|
|
1367
|
+
font-size: 14px;
|
|
1368
|
+
display: flex;
|
|
1369
|
+
align-items: center;
|
|
1370
|
+
gap: 8px;
|
|
1371
|
+
font-family: 'Roboto', sans-serif;
|
|
1372
|
+
text-align: center;
|
|
1373
|
+
`;
|
|
1374
|
+
alert.innerHTML = `<span>El mensaje no puede estar vacío.</span>`;
|
|
1375
|
+
container.appendChild(alert);
|
|
1376
|
+
}
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
const fullMessage = Array.from(elements)
|
|
1381
|
+
.map((element) => element.innerHTML)
|
|
1382
|
+
.join("")
|
|
1383
|
+
.replace(/<br\s*\/?>/gi, "\n");
|
|
1384
|
+
|
|
1385
|
+
await createComment(fullMessage, token);
|
|
1386
|
+
|
|
1387
|
+
rejectAll
|
|
1388
|
+
? sendBulkEvaluation("R")
|
|
1389
|
+
: sendSingleEvaluation("R");
|
|
1390
|
+
setShowRejectModal(false);
|
|
1391
|
+
}}
|
|
1392
|
+
/>,
|
|
1393
|
+
]}
|
|
1394
|
+
/>
|
|
1395
|
+
)}
|
|
1396
|
+
{state.modal.show && (
|
|
1397
|
+
<GenericModal
|
|
1398
|
+
componentsArray={[
|
|
1399
|
+
state.modal.image && (
|
|
1400
|
+
<img key="1" src={state.modal.image} alt="modal icon" />
|
|
1401
|
+
),
|
|
1402
|
+
state.modal.title && (
|
|
1403
|
+
<ScreenHeader
|
|
1404
|
+
key="2"
|
|
1405
|
+
headerType={"retailer-name-header"}
|
|
1406
|
+
text={state.modal.title}
|
|
1407
|
+
color={"white"}
|
|
1408
|
+
/>
|
|
1409
|
+
),
|
|
1410
|
+
state.modal.message && (
|
|
1411
|
+
<ScreenHeader
|
|
1412
|
+
key="3"
|
|
1413
|
+
headerType={"retailer-name-header"}
|
|
1414
|
+
text={state.modal.message}
|
|
1415
|
+
color={"white"}
|
|
1416
|
+
/>
|
|
1417
|
+
),
|
|
1418
|
+
state.modal.buttons && (
|
|
1419
|
+
<div key="4" style={{ marginTop: "16px" }}>
|
|
1420
|
+
{state.modal.buttons.map((button, index) => (
|
|
1421
|
+
<Button
|
|
1422
|
+
key={index}
|
|
1423
|
+
buttonType={button.buttonType}
|
|
1424
|
+
label={button.text}
|
|
1425
|
+
onClick={button.action}
|
|
1426
|
+
/>
|
|
1427
|
+
))}
|
|
1428
|
+
</div>
|
|
1429
|
+
),
|
|
1430
|
+
].filter(Boolean)}
|
|
1431
|
+
onClick={() =>
|
|
1432
|
+
dispatch({
|
|
1433
|
+
type: "SET_MODAL",
|
|
1434
|
+
payload: { show: false, title: "", message: "", image: null },
|
|
1435
|
+
})
|
|
1600
1436
|
}
|
|
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
1437
|
/>
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
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}
|
|
1438
|
+
)}
|
|
1439
|
+
{showModal && (
|
|
1440
|
+
<ProductImageModal
|
|
1441
|
+
images={state.images_values}
|
|
1442
|
+
setShowModal={setShowModal}
|
|
1443
|
+
approveRejectButtons={canShowSingleEvaluationButtons()}
|
|
1444
|
+
sendToFacilitator={handleOnSendEvaluationToFacilitator}
|
|
1445
|
+
/>
|
|
1446
|
+
)}
|
|
1447
|
+
{showVersionSelector && (
|
|
1448
|
+
<VersionSelector
|
|
1449
|
+
modalId={"version-selector"}
|
|
1450
|
+
articleId={state.product.id_article}
|
|
1451
|
+
setVersion={handleOnChangeProductVersion}
|
|
1452
|
+
companyName={state.product.company}
|
|
1453
|
+
currentVersion={state.product.version}
|
|
1638
1454
|
setShowVersionSelector={setShowVersionSelector}
|
|
1639
|
-
|
|
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)}
|
|
1455
|
+
jwt={token}
|
|
1660
1456
|
/>
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1457
|
+
)}
|
|
1458
|
+
<HeaderTop
|
|
1459
|
+
setHeaderTop={setHeaderTop}
|
|
1460
|
+
auditableVersion={auditableVersion}
|
|
1461
|
+
setCompare={setCompare}
|
|
1462
|
+
isAuditor={[1, 6].includes(user.id_role)}
|
|
1463
|
+
withChat={location?.state?.withChat}
|
|
1464
|
+
chatType={location?.state?.chatType}
|
|
1465
|
+
productSelected={state.product}
|
|
1466
|
+
token={token}
|
|
1467
|
+
activeRetailer={{
|
|
1468
|
+
id: state.active_retailer?.id_retailer,
|
|
1469
|
+
name: state.active_retailer?.retailer,
|
|
1470
|
+
}}
|
|
1471
|
+
/>
|
|
1472
|
+
<div className="data-container">
|
|
1473
|
+
<div className="image-data-panel">
|
|
1474
|
+
<ImagePreviewer
|
|
1475
|
+
activeImage={
|
|
1476
|
+
state.images_values.values[state.current_image] ?? {}
|
|
1477
|
+
}
|
|
1478
|
+
imagesArray={state.images_values || []}
|
|
1479
|
+
setActiveImage={handleOnChangeCurrentImage}
|
|
1480
|
+
setShowModal={handleOnShowModalGallery}
|
|
1481
|
+
/>
|
|
1482
|
+
<ImageDataTable
|
|
1483
|
+
// states
|
|
1484
|
+
lists={state.images_values || []}
|
|
1485
|
+
activeImage={
|
|
1486
|
+
state.images_values?.values
|
|
1487
|
+
? state.images_values?.values[state.current_image]
|
|
1488
|
+
: {}
|
|
1489
|
+
}
|
|
1490
|
+
assignationsImages={state.collaborator_assignations["Imágenes"]}
|
|
1491
|
+
imagesStatus={state.product?.images_status || "-"}
|
|
1492
|
+
retailerSelected={state.active_retailer?.id_retailer}
|
|
1493
|
+
isRetailer={isRetailer}
|
|
1494
|
+
version={state.product.version}
|
|
1495
|
+
shotThd={shotThd}
|
|
1496
|
+
setShowVersionSelector={setShowVersionSelector}
|
|
1497
|
+
// actions
|
|
1498
|
+
setImages={handleOnChangeCurrentImage}
|
|
1499
|
+
setAssignation={handleOnChangeAssignations} // No se usa?
|
|
1500
|
+
onClickSave={handleOnClickSaveImages}
|
|
1501
|
+
showSaveButton={isAuditorAssigned() || isUserAssignedToService()}
|
|
1502
|
+
/>
|
|
1503
|
+
</div>
|
|
1681
1504
|
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1505
|
+
<div className="product-information">
|
|
1506
|
+
<FullProductNameHeader
|
|
1507
|
+
// states
|
|
1508
|
+
headerData={state.product}
|
|
1509
|
+
productObservation={observation}
|
|
1510
|
+
percent={state.active_percentage.percentagesGeneral.required}
|
|
1511
|
+
activeRetailer={{
|
|
1512
|
+
id: state.active_retailer?.id_retailer,
|
|
1513
|
+
name: state.active_retailer?.retailer,
|
|
1514
|
+
image: state.active_retailer?.image,
|
|
1515
|
+
}}
|
|
1516
|
+
servicesData={state.services_data ? state.services_data : null}
|
|
1517
|
+
isObservationVisible={isObservationVisible}
|
|
1518
|
+
// actions
|
|
1519
|
+
setActiveRetailer={handleOnChangeActiveRetailer}
|
|
1520
|
+
approve={handleOnApproveSingleService}
|
|
1521
|
+
approveAll={handleOnApproveAllServices}
|
|
1522
|
+
reject={handleOnRejectSingleService}
|
|
1523
|
+
rejectAll={handleOnRejectAllServices}
|
|
1524
|
+
toggleObservation={handleOnToggleObservation}
|
|
1525
|
+
hideObservation={handleOnHideObservation}
|
|
1526
|
+
// sendToFacilitator={handleOnSendEvaluationToFacilitator} // No se usa?
|
|
1527
|
+
// validations
|
|
1528
|
+
showApproveRejectAll={
|
|
1529
|
+
canShowBulkEvaluationButtons() ||
|
|
1530
|
+
isAuditorAssigned() ||
|
|
1531
|
+
isUserAssignedToService()
|
|
1532
|
+
}
|
|
1533
|
+
showValidationButtons={
|
|
1534
|
+
canShowSingleEvaluationButtons() &&
|
|
1535
|
+
(isAuditorAssigned() || isUserAssignedToService())
|
|
1536
|
+
}
|
|
1537
|
+
/>
|
|
1538
|
+
<FullTabsMenu
|
|
1539
|
+
tabsSections={tabsSections}
|
|
1540
|
+
status={getStatusByCurrentServiceAndRetailer()}
|
|
1541
|
+
activeTab={state.active_tab}
|
|
1542
|
+
isRetailer={isRetailer}
|
|
1543
|
+
assig={state.collaborator_assignations[state.active_tab]}
|
|
1544
|
+
version={state.product.version}
|
|
1545
|
+
updatedDescriptions={state.updated_descriptions_inputs}
|
|
1546
|
+
updatedDatasheets={state.updated_datasheets_inputs}
|
|
1547
|
+
updatedImages={state.updated_images_values}
|
|
1548
|
+
images={state.services.images}
|
|
1549
|
+
// selectedImages={selectedImages} prop pasada asi: FullTabsMenu -> TabsMenu Pero en TabsMenu no se espera ninguna prop setSelectedImages
|
|
1550
|
+
// setters
|
|
1551
|
+
setActiveTab={handleOnChangeActiveTab}
|
|
1552
|
+
setImageLayout={handleOnToggleImageLayout}
|
|
1553
|
+
setUpdatedDescriptions={handleOnSetUpdatedDescriptions}
|
|
1554
|
+
setUpdatedDatasheets={handleOnSetUpdatedDatasheets}
|
|
1555
|
+
setAssignation={handleOnSetAssignation} // No se usa?
|
|
1556
|
+
setImages={handleOnSetImages} // No se usa?
|
|
1557
|
+
setShowVersionSelector={setShowVersionSelector}
|
|
1558
|
+
// setSelectedImages={setSelectedImages} prop pasada asi: FullTabsMenu -> TabsMenu Pero en TabsMenu no se espera ninguna prop setSelectedImages
|
|
1559
|
+
// actions
|
|
1560
|
+
downloadImages={handleOnDownloadImages}
|
|
1561
|
+
askToDeleteImages={handleOnAskToDeleteImages}
|
|
1562
|
+
showSaveButton={isAuditorAssigned() || isUserAssignedToService()}
|
|
1563
|
+
onClickSave={handleOnClickSave}
|
|
1564
|
+
// validations
|
|
1565
|
+
canAssign={![7, 8].includes(user.id_role)}
|
|
1566
|
+
/>
|
|
1567
|
+
<div
|
|
1568
|
+
className={
|
|
1569
|
+
"services-information-container " +
|
|
1570
|
+
(imageLayout && state.active_tab === "Imágenes"
|
|
1571
|
+
? "image-services"
|
|
1572
|
+
: "")
|
|
1573
|
+
}
|
|
1574
|
+
id="services-information-container"
|
|
1575
|
+
>
|
|
1576
|
+
{state.saving ? (
|
|
1577
|
+
<Loading />
|
|
1578
|
+
) : (
|
|
1579
|
+
<>
|
|
1580
|
+
{state.active_tab === "Descripción" &&
|
|
1581
|
+
(state.product?.description_status !== "NS" ? (
|
|
1685
1582
|
<InputGroup
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
setUpdatedDatasheets={setUpdatedDatasheets}
|
|
1583
|
+
activeSection={state.active_tab}
|
|
1584
|
+
inputGroup={state.descriptions_inputs[0]}
|
|
1585
|
+
updatedDescriptions={state.updated_descriptions_inputs}
|
|
1586
|
+
articleId={state.product?.id_article}
|
|
1587
|
+
version={state.product.version}
|
|
1588
|
+
auditInputGroup={auditDescriptions[0]}
|
|
1589
|
+
setUpdatedDescriptions={handleOnSetUpdatedDescriptions}
|
|
1590
|
+
dinamicHeight={true}
|
|
1695
1591
|
compare={compare}
|
|
1696
1592
|
/>
|
|
1697
|
-
)
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1593
|
+
) : (
|
|
1594
|
+
<ScreenHeader
|
|
1595
|
+
text={"No cuentas con este servicio"}
|
|
1596
|
+
headerType={"input-name-header"}
|
|
1597
|
+
/>
|
|
1598
|
+
))}
|
|
1599
|
+
{state.active_tab === "Ficha técnica" &&
|
|
1600
|
+
(state.product?.datasheet_status !== "NS" ? (
|
|
1601
|
+
<>
|
|
1602
|
+
{state.datasheets_inputs[0]?.data?.map(
|
|
1603
|
+
(dataGroup, index) => (
|
|
1604
|
+
<InputGroup
|
|
1605
|
+
key={index + "-" + state.active_retailer.retailer}
|
|
1606
|
+
articleId={state.product.id_article}
|
|
1607
|
+
version={state.version}
|
|
1608
|
+
activeSection={state.active_tab}
|
|
1609
|
+
inputGroup={dataGroup}
|
|
1610
|
+
dataInputs={state.datasheets_inputs[1]}
|
|
1611
|
+
auditInputs={auditDatasheets[1]}
|
|
1612
|
+
updatedDatasheets={
|
|
1613
|
+
state.updated_datasheets_inputs
|
|
1614
|
+
}
|
|
1615
|
+
setUpdatedDatasheets={
|
|
1616
|
+
handleOnSetUpdatedDatasheets
|
|
1617
|
+
}
|
|
1618
|
+
compare={compare}
|
|
1619
|
+
/>
|
|
1620
|
+
),
|
|
1621
|
+
)}
|
|
1622
|
+
</>
|
|
1623
|
+
) : (
|
|
1624
|
+
<ScreenHeader
|
|
1625
|
+
text={"No cuentas con este servicio"}
|
|
1626
|
+
headerType={"input-name-header"}
|
|
1627
|
+
/>
|
|
1628
|
+
))}
|
|
1629
|
+
{state.active_tab === "Imágenes" &&
|
|
1630
|
+
(state.product?.images_status !== "NS" ? (
|
|
1631
|
+
<>
|
|
1632
|
+
{!imageLayout && (
|
|
1633
|
+
<GalleryHeader
|
|
1634
|
+
checkAll={state.all_image_checked} // Determina si el checkbox "Seleccionar todo" está marcado
|
|
1635
|
+
setCheckAll={handleOnSetCheckAll} // Toggler de true o false para el checkbox "Seleccionar todo"
|
|
1636
|
+
setSelectedImages={handleOnSetSelectedImages}
|
|
1637
|
+
// shotThd={shotThd} // No se usa?
|
|
1638
|
+
/>
|
|
1639
|
+
)}
|
|
1640
|
+
<section
|
|
1641
|
+
className="container"
|
|
1642
|
+
style={{ position: "relative" }}
|
|
1643
|
+
>
|
|
1644
|
+
<div
|
|
1645
|
+
{...getRootProps({
|
|
1646
|
+
className: `dropzone ${
|
|
1647
|
+
isDragActive ? "drag-active" : ""
|
|
1648
|
+
}`,
|
|
1649
|
+
})}
|
|
1650
|
+
>
|
|
1651
|
+
<input {...getInputProps()} />
|
|
1652
|
+
{isDragActive && (
|
|
1653
|
+
<div className="drag-overlay">
|
|
1654
|
+
<p>Suelta las imágenes aquí</p>
|
|
1655
|
+
</div>
|
|
1656
|
+
)}
|
|
1657
|
+
<aside>{thumbs()}</aside>
|
|
1658
|
+
</div>
|
|
1659
|
+
{state.images_values?.values.length === 0 && (
|
|
1660
|
+
<div
|
|
1661
|
+
style={{
|
|
1662
|
+
position: "absolute",
|
|
1663
|
+
top: "50%",
|
|
1664
|
+
left: "50%",
|
|
1665
|
+
transform: "translate(-50%, -50%)",
|
|
1666
|
+
textAlign: "center",
|
|
1667
|
+
padding: "40px",
|
|
1668
|
+
width: "80%",
|
|
1669
|
+
maxWidth: "500px",
|
|
1670
|
+
fontFamily: "Arial, sans-serif",
|
|
1671
|
+
}}
|
|
1672
|
+
>
|
|
1673
|
+
<p
|
|
1674
|
+
style={{
|
|
1675
|
+
fontSize: "18px",
|
|
1676
|
+
color: "#666",
|
|
1677
|
+
marginBottom: "16px",
|
|
1678
|
+
}}
|
|
1679
|
+
>
|
|
1680
|
+
Este producto no tiene imágenes
|
|
1681
|
+
</p>
|
|
1682
|
+
{isAuditorAssigned() ||
|
|
1683
|
+
isUserAssignedToService() ? (
|
|
1684
|
+
<p
|
|
1685
|
+
style={{
|
|
1686
|
+
fontSize: "14px",
|
|
1687
|
+
color: "#999",
|
|
1688
|
+
marginBottom: "20px",
|
|
1689
|
+
}}
|
|
1690
|
+
>
|
|
1691
|
+
Arrastra las imágenes aquí o{" "}
|
|
1692
|
+
<span
|
|
1693
|
+
onClick={open}
|
|
1694
|
+
style={{
|
|
1695
|
+
color: "#007bff",
|
|
1696
|
+
cursor: "pointer",
|
|
1697
|
+
textDecoration: "underline",
|
|
1698
|
+
}}
|
|
1699
|
+
>
|
|
1700
|
+
haz clic para abrir el explorador de
|
|
1701
|
+
archivos
|
|
1702
|
+
</span>
|
|
1703
|
+
</p>
|
|
1704
|
+
) : null}
|
|
1705
|
+
</div>
|
|
1706
|
+
)}
|
|
1707
|
+
</section>
|
|
1708
|
+
</>
|
|
1709
|
+
) : (
|
|
1710
|
+
<ScreenHeader
|
|
1711
|
+
text={"No cuentas con este servicio"}
|
|
1712
|
+
headerType={"input-name-header"}
|
|
1713
|
+
/>
|
|
1714
|
+
))}
|
|
1715
|
+
</>
|
|
1716
|
+
)}
|
|
1717
|
+
</div>
|
|
1718
|
+
{(isUserAssignedToService(state.active_tab) ||
|
|
1719
|
+
isAuditorAssigned()) &&
|
|
1720
|
+
state.product[`${getConceptByTab(state.active_tab)}_status`] !==
|
|
1721
|
+
"NS" && (
|
|
1722
|
+
<div className="commentary-box">
|
|
1723
|
+
{!state.comment ? (
|
|
1724
|
+
<div className="commentary">
|
|
1725
|
+
<TagAndInput
|
|
1726
|
+
label={"Caja de Comentario"}
|
|
1727
|
+
inputType={"textarea"}
|
|
1728
|
+
inputCols={80}
|
|
1729
|
+
inputRows={4}
|
|
1730
|
+
inputId={"commentary-box"}
|
|
1731
|
+
index={0}
|
|
1732
|
+
/>
|
|
1733
|
+
<div className="buttons-box">
|
|
1734
|
+
<Button
|
|
1735
|
+
buttonType={"general-transparent-button"}
|
|
1736
|
+
label={"Enviar comentario"}
|
|
1737
|
+
onClick={handleOnSubmitComment}
|
|
1738
|
+
/>
|
|
1730
1739
|
</div>
|
|
1731
|
-
</
|
|
1740
|
+
</div>
|
|
1732
1741
|
) : (
|
|
1733
|
-
<
|
|
1734
|
-
|
|
1735
|
-
|
|
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">
|
|
1742
|
+
<div className="feedback-box">
|
|
1743
|
+
<Commentary
|
|
1744
|
+
comment={state.comment?.message}
|
|
1745
|
+
reviewed={crossComment}
|
|
1746
|
+
/>
|
|
1776
1747
|
<Button
|
|
1777
|
-
buttonType={"
|
|
1778
|
-
|
|
1779
|
-
|
|
1748
|
+
buttonType={"circular-button accept-button"}
|
|
1749
|
+
onClick={async () => {
|
|
1750
|
+
setCrossComment(true);
|
|
1751
|
+
commentRevised();
|
|
1752
|
+
}}
|
|
1780
1753
|
/>
|
|
1781
1754
|
</div>
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
<div className="
|
|
1785
|
-
<Commentary
|
|
1786
|
-
comment={comment?.message}
|
|
1787
|
-
reviewed={crossComment}
|
|
1788
|
-
/>
|
|
1755
|
+
)}
|
|
1756
|
+
|
|
1757
|
+
<div className="action-buttons">
|
|
1789
1758
|
<Button
|
|
1790
|
-
buttonType={"
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
}}
|
|
1759
|
+
buttonType={"general-pink-button"}
|
|
1760
|
+
label={"Cambio de Estatus"}
|
|
1761
|
+
onClick={() => setOpenChangeStatusModal(true)}
|
|
1762
|
+
id="button-change-status"
|
|
1795
1763
|
/>
|
|
1764
|
+
{[7, 8].includes(user.id_role) && (
|
|
1765
|
+
<Button
|
|
1766
|
+
buttonType={
|
|
1767
|
+
isEvaluationFinished(
|
|
1768
|
+
user.id_role,
|
|
1769
|
+
state.active_tab,
|
|
1770
|
+
statusArray,
|
|
1771
|
+
) &&
|
|
1772
|
+
state.missing_required_fields[state.active_tab] === 0
|
|
1773
|
+
? "general-green-button"
|
|
1774
|
+
: "general-button-disabled"
|
|
1775
|
+
}
|
|
1776
|
+
label={"Enviar evaluación"}
|
|
1777
|
+
onClick={handleOnSendEvaluationToFacilitator}
|
|
1778
|
+
/>
|
|
1779
|
+
)}
|
|
1796
1780
|
</div>
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
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
|
-
)}
|
|
1781
|
+
</div>
|
|
1782
|
+
)}
|
|
1783
|
+
</div>
|
|
1815
1784
|
</div>
|
|
1816
|
-
</
|
|
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
|
-
}
|
|
1785
|
+
</Container>
|
|
1917
1786
|
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
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
|
-
}));
|
|
1787
|
+
<ChangeStatusModal
|
|
1788
|
+
state={state}
|
|
1789
|
+
open={openChangeStatusModal}
|
|
1790
|
+
onClose={() => {
|
|
1791
|
+
setOpenChangeStatusModal(false);
|
|
1975
1792
|
}}
|
|
1793
|
+
reloadData={loadData}
|
|
1794
|
+
token={token}
|
|
1976
1795
|
/>
|
|
1977
|
-
</
|
|
1796
|
+
</AiProductEditionProvider>
|
|
1797
|
+
);
|
|
1798
|
+
};
|
|
1799
|
+
|
|
1800
|
+
export const RetailerProductEdition = (props) => {
|
|
1801
|
+
return (
|
|
1802
|
+
<ProviderProductEditionProvider>
|
|
1803
|
+
<RetailerProductEditionView {...props} />
|
|
1804
|
+
</ProviderProductEditionProvider>
|
|
1978
1805
|
);
|
|
1979
1806
|
};
|