contentoh-components-library 21.6.1 → 21.6.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/components/atoms/ProgressBar/index.js +1 -1
  2. package/dist/components/atoms/ProgressBar/styles.js +4 -4
  3. package/dist/components/atoms/Status/index.js +16 -1
  4. package/dist/components/atoms/Status/styles.js +1 -1
  5. package/dist/components/organisms/ChangeStatusModal/index.js +166 -53
  6. package/dist/components/organisms/ChangeStatusModal/styles.js +12 -8
  7. package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.context.js +3 -1
  8. package/dist/components/pages/ProviderProductEdition/index.js +65 -36
  9. package/dist/components/pages/ProviderProductEdition/utils.js +3 -1
  10. package/dist/components/pages/RetailerProductEdition/context/reducers/product.js +11 -19
  11. package/dist/components/pages/RetailerProductEdition/index.js +16 -10
  12. package/dist/components/pages/RetailerProductEdition/utils.js +1 -1
  13. package/dist/global-files/statusDictionary.js +36 -1
  14. package/package.json +1 -1
  15. package/src/components/atoms/ProgressBar/index.js +2 -6
  16. package/src/components/atoms/ProgressBar/styles.js +4 -58
  17. package/src/components/atoms/Status/index.js +11 -3
  18. package/src/components/atoms/Status/styles.js +113 -0
  19. package/src/components/organisms/ChangeStatusModal/index.jsx +103 -29
  20. package/src/components/organisms/ChangeStatusModal/styles.js +20 -0
  21. package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx +1 -0
  22. package/src/components/pages/ProviderProductEdition/index.js +40 -14
  23. package/src/components/pages/ProviderProductEdition/utils.js +5 -1
  24. package/src/components/pages/RetailerProductEdition/context/reducers/product.js +4 -20
  25. package/src/components/pages/RetailerProductEdition/index.js +20 -16
  26. package/src/components/pages/RetailerProductEdition/utils.js +1 -1
  27. package/src/global-files/statusDictionary.js +31 -1
@@ -2,11 +2,13 @@ import styled from "styled-components";
2
2
  import { FontFamily, GlobalColors } from "../../../global-files/variables";
3
3
 
4
4
  export const Container = styled.div`
5
+ position: relative;
5
6
  width: fit-content;
6
7
  padding: 0 10px;
7
8
  height: 20px;
8
9
  background-color: ${GlobalColors.s3};
9
10
  border-radius: 3px;
11
+ cursor: default;
10
12
 
11
13
  p {
12
14
  text-align: center;
@@ -16,6 +18,117 @@ export const Container = styled.div`
16
18
  line-height: 20px;
17
19
  }
18
20
 
21
+ &[data-tooltip]::after {
22
+ content: attr(data-tooltip);
23
+ position: absolute;
24
+ bottom: calc(100% + 7px);
25
+ left: 50%;
26
+ transform: translateX(-50%) translateY(4px);
27
+ background-color: ${GlobalColors.s3};
28
+ color: ${GlobalColors.white};
29
+ font-family: ${FontFamily.Lato};
30
+ font-size: 11px;
31
+ font-weight: 600;
32
+ padding: 4px 10px;
33
+ border-radius: 6px;
34
+ white-space: nowrap;
35
+ z-index: 200;
36
+ pointer-events: none;
37
+ opacity: 0;
38
+ visibility: hidden;
39
+ transition: opacity 0.18s ease, transform 0.18s ease;
40
+ }
41
+
42
+ &[data-tooltip]::before {
43
+ content: "";
44
+ position: absolute;
45
+ bottom: calc(100% + 1px);
46
+ left: 50%;
47
+ transform: translateX(-50%) translateY(4px);
48
+ border: 6px solid transparent;
49
+ border-top-color: ${GlobalColors.s3};
50
+ z-index: 200;
51
+ pointer-events: none;
52
+ opacity: 0;
53
+ visibility: hidden;
54
+ transition: opacity 0.18s ease, transform 0.18s ease;
55
+ }
56
+
57
+ &[data-tooltip]:hover::after,
58
+ &[data-tooltip]:hover::before {
59
+ opacity: 1;
60
+ visibility: visible;
61
+ transform: translateX(-50%) translateY(0);
62
+ }
63
+
64
+ &.status-CA[data-tooltip]::after,
65
+ &.status-IE[data-tooltip]::after {
66
+ background-color: ${GlobalColors.in_progress};
67
+ }
68
+ &.status-CA[data-tooltip]::before,
69
+ &.status-IE[data-tooltip]::before {
70
+ border-top-color: ${GlobalColors.in_progress};
71
+ }
72
+
73
+ &.status-R[data-tooltip]::after,
74
+ &.status-AS[data-tooltip]::after,
75
+ &.status-SAC[data-tooltip]::after,
76
+ &.status-PA[data-tooltip]::after {
77
+ background-color: ${GlobalColors.reception};
78
+ }
79
+ &.status-R[data-tooltip]::before,
80
+ &.status-AS[data-tooltip]::before,
81
+ &.status-SAC[data-tooltip]::before,
82
+ &.status-PA[data-tooltip]::before {
83
+ border-top-color: ${GlobalColors.reception};
84
+ }
85
+
86
+ &.status-AA[data-tooltip]::after,
87
+ &.status-AP[data-tooltip]::after,
88
+ &.status-AC[data-tooltip]::after,
89
+ &.status-AAC[data-tooltip]::after,
90
+ &.status-ACA[data-tooltip]::after {
91
+ background-color: ${GlobalColors.finished};
92
+ }
93
+ &.status-AA[data-tooltip]::before,
94
+ &.status-AP[data-tooltip]::before,
95
+ &.status-AC[data-tooltip]::before,
96
+ &.status-AAC[data-tooltip]::before,
97
+ &.status-ACA[data-tooltip]::before {
98
+ border-top-color: ${GlobalColors.finished};
99
+ }
100
+
101
+ &.status-RA[data-tooltip]::after,
102
+ &.status-RC[data-tooltip]::after,
103
+ &.status-RP[data-tooltip]::after,
104
+ &.status-RAC[data-tooltip]::after,
105
+ &.status-RCA[data-tooltip]::after {
106
+ background-color: ${GlobalColors.rejected_status};
107
+ }
108
+ &.status-RA[data-tooltip]::before,
109
+ &.status-RC[data-tooltip]::before,
110
+ &.status-RP[data-tooltip]::before,
111
+ &.status-RAC[data-tooltip]::before,
112
+ &.status-RCA[data-tooltip]::before {
113
+ border-top-color: ${GlobalColors.rejected_status};
114
+ }
115
+
116
+ &.status-FAP[data-tooltip]::after,
117
+ &.status-Ex[data-tooltip]::after {
118
+ background-color: ${GlobalColors.exported};
119
+ }
120
+ &.status-FAP[data-tooltip]::before,
121
+ &.status-Ex[data-tooltip]::before {
122
+ border-top-color: ${GlobalColors.exported};
123
+ }
124
+
125
+ &.status-DDI[data-tooltip]::after {
126
+ background-color: ${GlobalColors.original_purpura};
127
+ }
128
+ &.status-DDI[data-tooltip]::before {
129
+ border-top-color: ${GlobalColors.original_purpura};
130
+ }
131
+
19
132
  &.status-CA,
20
133
  &.status-IE {
21
134
  background-color: ${GlobalColors.in_progress};
@@ -31,6 +31,8 @@ import {
31
31
  ScopeButton,
32
32
  HelperText,
33
33
  StatusGrid,
34
+ StatusGridWrapper,
35
+ StatusGridOverlay,
34
36
  StatusPill,
35
37
  StyledTextArea,
36
38
  StyledFormControl,
@@ -42,15 +44,6 @@ import {
42
44
  } from "./styles";
43
45
  import axios from "axios";
44
46
 
45
- const statusOptions = [
46
- { value: "PA", label: "Por Asignar" },
47
- { value: "AS", label: "Asignado" },
48
- { value: "AC", label: "Aprobado Coordinador" },
49
- { value: "AP", label: "Aprobado Proveedor" },
50
- { value: "R", label: "Rechazado" },
51
- { value: "RP", label: "Rechazo Pendiente" },
52
- ];
53
-
54
47
  const availableServices = ["description", "datasheet", "images"];
55
48
 
56
49
  const ChangeStatusModal = ({
@@ -71,8 +64,68 @@ const ChangeStatusModal = ({
71
64
 
72
65
  const [currentStatusObj, setCurrentStatusObj] = useState({});
73
66
 
74
- const isStatusValid =
75
- newStatus !== "" && newStatus !== currentStatusObj.label;
67
+ const getServiceStatusStr = (retailerId, service) => {
68
+ const sbyR = state?.product?.statusByRetailer;
69
+ if (!sbyR) return null;
70
+ if (Array.isArray(sbyR)) {
71
+ return sbyR.find((item) => item.retailer_id === retailerId && item.service === service)?.status ?? null;
72
+ }
73
+ return sbyR[retailerId]?.[service] ?? null;
74
+ };
75
+
76
+ const serviceStatusObj = (() => {
77
+ if (scope !== "service" || selectedChains.length !== 1 || selectedServices.length !== 1) return null;
78
+ const statusStr = getServiceStatusStr(selectedChains[0], selectedServices[0]);
79
+ const statusKey = statusStr?.split("/").pop();
80
+ return statusKey ? STATUS_DICTIONARY[statusKey] : null;
81
+ })();
82
+
83
+ // Statuses for multi-service/chain selection (when not exactly 1+1)
84
+ const multiServiceStatuses = (() => {
85
+ if (scope !== "service" || selectedChains.length === 0 || selectedServices.length === 0) return [];
86
+ if (selectedChains.length === 1 && selectedServices.length === 1) return [];
87
+ const results = [];
88
+ for (const chainId of selectedChains) {
89
+ const chainName = availableRetailers.find((r) => r.id_retailer === chainId)?.name ?? chainId;
90
+ for (const service of selectedServices) {
91
+ const statusStr = getServiceStatusStr(chainId, service);
92
+ const statusKey = statusStr?.split("/").pop();
93
+ const statusObj = statusKey ? STATUS_DICTIONARY[statusKey] : null;
94
+ if (statusObj) {
95
+ results.push({ chainId, chainName, service, statusName: statusObj.name });
96
+ }
97
+ }
98
+ }
99
+ return results;
100
+ })();
101
+
102
+ // If all selected services share the same status, block it; otherwise null
103
+ const multiAllSameStatus = (() => {
104
+ if (multiServiceStatuses.length === 0) return null;
105
+ const names = [...new Set(multiServiceStatuses.map((s) => s.statusName))];
106
+ return names.length === 1 ? names[0] : null;
107
+ })();
108
+
109
+ // Map statusName -> owner labels to show below each pill when statuses differ
110
+ const statusOwnerMap = (() => {
111
+ if (multiServiceStatuses.length === 0 || multiAllSameStatus !== null) return {};
112
+ const serviceLabel = (service) =>
113
+ service === "description" ? "Descripciones" : service === "datasheet" ? "Ficha Técnica" : "Imágenes";
114
+ return multiServiceStatuses.reduce((acc, item) => {
115
+ if (!acc[item.statusName]) acc[item.statusName] = [];
116
+ const label = selectedChains.length > 1
117
+ ? `${item.chainName}: ${serviceLabel(item.service)}`
118
+ : serviceLabel(item.service);
119
+ acc[item.statusName].push(label);
120
+ return acc;
121
+ }, {});
122
+ })();
123
+
124
+ const disabledStatusName = scope === "service"
125
+ ? serviceStatusObj?.name ?? multiAllSameStatus ?? null
126
+ : currentStatusObj?.name;
127
+
128
+ const isStatusValid = newStatus !== "" && newStatus !== disabledStatusName;
76
129
  const isCommentValid = comment.trim().length > 0;
77
130
 
78
131
  let isScopeValid = false;
@@ -157,7 +210,8 @@ const ChangeStatusModal = ({
157
210
 
158
211
  useEffect(() => {
159
212
  if (!state) return;
160
- setCurrentStatusObj(STATUS_DICTIONARY[state?.product?.status]);
213
+ const statusKey = state?.product?.status?.split("/").pop();
214
+ setCurrentStatusObj(STATUS_DICTIONARY[statusKey]);
161
215
 
162
216
  setAvailableRetailers(state?.product?.categoryRetailerInOrder || []);
163
217
  }, [state]);
@@ -381,9 +435,9 @@ const ChangeStatusModal = ({
381
435
  )}
382
436
 
383
437
  <Section>
384
- <SectionTitle>Estatus actual:</SectionTitle>
438
+ <SectionTitle>Estatus actual del producto:</SectionTitle>
385
439
  <StatusPill
386
- label={currentStatusObj?.name}
440
+ label={serviceStatusObj?.name ?? multiAllSameStatus ?? currentStatusObj?.name}
387
441
  selected={false}
388
442
  disabled={true}
389
443
  />
@@ -391,20 +445,40 @@ const ChangeStatusModal = ({
391
445
 
392
446
  <Section>
393
447
  <SectionTitle>Nuevo estatus:</SectionTitle>
394
- <StatusGrid>
395
- {Object.values(STATUS_DICTIONARY).map((status) => (
396
- <StatusPill
397
- key={status.name}
398
- label={status.name}
399
- disabled={status.name === currentStatusObj?.name}
400
- selected={status.name === newStatus}
401
- onClick={() =>
402
- status.name !== currentStatusObj?.name &&
403
- setNewStatus(status.name)
404
- }
405
- />
406
- ))}
407
- </StatusGrid>
448
+ <StatusGridWrapper>
449
+ <StatusGrid>
450
+ {Object.values(STATUS_DICTIONARY).map((status) => {
451
+ const ownerLabels = statusOwnerMap[status.name];
452
+ return (
453
+ <div
454
+ key={status.name}
455
+ style={{ display: "flex", flexDirection: "column", alignItems: "flex-start", gap: 4 }}
456
+ >
457
+ <StatusPill
458
+ label={status.name}
459
+ disabled={status.name === disabledStatusName}
460
+ selected={status.name === newStatus}
461
+ onClick={() =>
462
+ status.name !== disabledStatusName && setNewStatus(status.name)
463
+ }
464
+ />
465
+ {ownerLabels?.length > 0 && (
466
+ <span style={{ fontSize: "0.68rem", color: colors.primary, fontFamily: "Raleway, sans-serif", paddingLeft: 2 }}>
467
+ {ownerLabels.join(", ")}
468
+ </span>
469
+ )}
470
+ </div>
471
+ );
472
+ })}
473
+ </StatusGrid>
474
+ {!isScopeValid && (
475
+ <StatusGridOverlay>
476
+ {scope === "retailer"
477
+ ? "Selecciona una cadena para continuar"
478
+ : "Selecciona una cadena y un servicio para continuar"}
479
+ </StatusGridOverlay>
480
+ )}
481
+ </StatusGridWrapper>
408
482
  </Section>
409
483
 
410
484
  <Section>
@@ -431,7 +505,7 @@ const ChangeStatusModal = ({
431
505
  <span className="summary-title">Resumen de impacto:</span>
432
506
  <div className="status-flow">
433
507
  <StatusPill
434
- label={currentStatusObj?.name}
508
+ label={serviceStatusObj?.name ?? multiAllSameStatus ?? currentStatusObj?.name}
435
509
  selected={false}
436
510
  disabled={true}
437
511
  size="small"
@@ -181,6 +181,26 @@ export const StatusGrid = styled(Box)`
181
181
  gap: 12px;
182
182
  `;
183
183
 
184
+ export const StatusGridWrapper = styled(Box)`
185
+ position: relative;
186
+ `;
187
+
188
+ export const StatusGridOverlay = styled(Box)`
189
+ position: absolute;
190
+ inset: -8px -4px;
191
+ background: rgba(255, 255, 255, 0.82);
192
+ backdrop-filter: blur(1px);
193
+ border-radius: 8px;
194
+ display: flex;
195
+ align-items: center;
196
+ justify-content: center;
197
+ font-family: "Raleway", sans-serif;
198
+ font-size: 13px;
199
+ font-weight: 600;
200
+ color: rgba(0, 0, 0, 0.45);
201
+ pointer-events: none;
202
+ `;
203
+
184
204
  export const StyledTextArea = styled(TextField)`
185
205
  && {
186
206
  width: 100%;
@@ -6,6 +6,7 @@ import {
6
6
  ACTIONS,
7
7
  } from "./provider-product-edition.reducer";
8
8
  import axios from "axios";
9
+ import { getConceptByTab } from "../utils";
9
10
  import successIcon from "../../../../assets/images/genericModal/genericModalCheck.svg";
10
11
  import errorIcon from "../../../../assets/images/genericModal/errorModal.svg";
11
12
  import warningIcon from "../../../../assets/images/genericModal/genericModalWarning.svg";
@@ -9,6 +9,7 @@ import {
9
9
  useProviderProductEdition,
10
10
  } from "./context/provider-product-edition.context";
11
11
  import { normalizeProduct, getConceptByTab } from "./utils";
12
+ import { getMinorStatus, getMinorStatusFromRetailerMap, STATUS_DICTIONARY } from "../../../global-files/statusDictionary";
12
13
 
13
14
  import {
14
15
  getPercentage,
@@ -269,11 +270,24 @@ const ProviderProductEditionView = ({
269
270
  {},
270
271
  );
271
272
 
273
+ const getServiceMinorStatus = (serviceName) => {
274
+ const records = servicesDataRes.filter((s) => s.service === serviceName);
275
+ return records.length > 0 ? getMinorStatus(records.map((s) => s.status)) : undefined;
276
+ };
277
+
278
+ const imagesMinorStatus = getServiceMinorStatus("images");
279
+ const descriptionMinorStatus = getServiceMinorStatus("description");
280
+ const datasheetMinorStatus = getServiceMinorStatus("datasheet");
281
+
272
282
  dispatch({
273
283
  type: "SET_PRODUCT",
274
284
  payload: {
275
285
  ...state.product,
276
286
  statusByRetailer: updatedStatusByRetailer,
287
+ status: getMinorStatusFromRetailerMap(updatedStatusByRetailer),
288
+ ...(imagesMinorStatus !== undefined && { images_status: imagesMinorStatus }),
289
+ ...(descriptionMinorStatus !== undefined && { description_status: descriptionMinorStatus }),
290
+ ...(datasheetMinorStatus !== undefined && { datasheet_status: datasheetMinorStatus }),
277
291
  },
278
292
  });
279
293
 
@@ -703,14 +717,14 @@ const ProviderProductEditionView = ({
703
717
  const concept = getConceptByTab(state.active_tab);
704
718
  const articleId = state.product.id_article;
705
719
  const orderId = state.product.id_order ?? state.product.orderId;
706
- const sectionStatusKey = `${concept}_status`;
720
+ const retailerId = state.active_retailer?.id_retailer;
707
721
  const evalStatus =
708
- state.product[sectionStatusKey] || state.product?.version_status;
722
+ state.product.statusByRetailer?.[retailerId]?.[concept] ||
723
+ state.product[`${concept}_status`] ||
724
+ state.product?.version_status;
709
725
 
710
726
  let data = { articleId, orderId, concept, evalStatus };
711
727
 
712
- const retailerId = state.active_retailer?.id_retailer;
713
-
714
728
  try {
715
729
  if (result) {
716
730
  data.result = result;
@@ -731,15 +745,19 @@ const ProviderProductEditionView = ({
731
745
  newStatuses.newServiceStatus[articleId][`${concept}Status`];
732
746
 
733
747
  // Actualizar el producto con los nuevos estados
748
+ const updatedStatusByRetailer = {
749
+ ...state.product.statusByRetailer,
750
+ [retailerId]: {
751
+ ...state.product.statusByRetailer[retailerId],
752
+ [concept]: newStatuses?.newStatus ?? serviceStatus,
753
+ },
754
+ };
734
755
  const updatedProduct = {
735
756
  ...state.product,
736
- statusByRetailer: {
737
- ...state.product.statusByRetailer,
738
- [retailerId]: {
739
- ...state.product.statusByRetailer[retailerId],
740
- [concept]: newStatuses?.newStatus ?? serviceStatus,
741
- },
742
- },
757
+ statusByRetailer: updatedStatusByRetailer,
758
+ status: getMinorStatus(
759
+ Object.values(updatedStatusByRetailer).flatMap(Object.values)
760
+ ),
743
761
  };
744
762
 
745
763
  const updatedServicesData = state.services_data?.map((service) => ({
@@ -967,14 +985,19 @@ const ProviderProductEditionView = ({
967
985
  };
968
986
 
969
987
  // Crear todas las evaluaciones para cada servicio y retailer
988
+ const isProvider = !user.is_retailer;
970
989
  state.services_data?.forEach((ret) => {
971
990
  const { service, id_retailer } = ret;
972
- let data = {};
973
- data = {
991
+ const currentEvalStatus = state.product.statusByRetailer[id_retailer]?.[service];
992
+
993
+ if (isProvider && currentEvalStatus !== STATUS_DICTIONARY.AA.status) return;
994
+ if (!isProvider && currentEvalStatus !== STATUS_DICTIONARY.AP.status) return;
995
+
996
+ const data = {
974
997
  ...dataGeneral,
975
998
  concept: service,
976
999
  retailerId: id_retailer,
977
- evalStatus: state.product.statusByRetailer[id_retailer][service],
1000
+ evalStatus: currentEvalStatus,
978
1001
  };
979
1002
  evaluationArray.push(
980
1003
  axios.put(`${process.env.REACT_APP_EVALUATION_ENDPOINT}`, data, {
@@ -1005,6 +1028,9 @@ const ProviderProductEditionView = ({
1005
1028
  const updatedProduct = {
1006
1029
  ...state.product,
1007
1030
  article_status: status,
1031
+ status: getMinorStatus(
1032
+ Object.values(updatedStatusByRetailer).flatMap(Object.values)
1033
+ ),
1008
1034
  datasheet_status:
1009
1035
  state.product.datasheet_status === "NA" ? "NA" : status,
1010
1036
  description_status:
@@ -1,3 +1,5 @@
1
+ import { getMinorStatusFromRetailerMap } from "../../../global-files/statusDictionary";
2
+
1
3
  export const normalizeProduct = (product) => {
2
4
  // Handle case where product might be wrapped in a product property
3
5
  const productData = product.product || product;
@@ -44,7 +46,9 @@ export const normalizeProduct = (product) => {
44
46
 
45
47
  // from tasks
46
48
  id_order: productData.orderId || 0,
47
- status: productData.status || null,
49
+ status: productData.statusByRetailer
50
+ ? getMinorStatusFromRetailerMap(productData.statusByRetailer)
51
+ : productData.status || null,
48
52
  datasheet_status: productData.datasheet_status || null,
49
53
  description_status: productData.description_status || null,
50
54
  images_status: productData.images_status || null,
@@ -1,4 +1,4 @@
1
- import { STATUS_DICTIONARY } from "../../../../../global-files/statusDictionary";
1
+ import { STATUS_DICTIONARY, getMinorStatus } from "../../../../../global-files/statusDictionary";
2
2
 
3
3
  export const productInitialState = {
4
4
  product: null,
@@ -92,23 +92,7 @@ export const productReducer = (state, action) => {
92
92
  }
93
93
  };
94
94
 
95
- function getMinorStatus(servicesStatus = []) {
96
- if (!servicesStatus || servicesStatus.length === 0)
97
- return STATUS_DICTIONARY.NS.name;
98
-
99
- console.log({ servicesStatus });
100
-
101
- const winner = servicesStatus.reduce((minor, current) => {
102
- const currentObj =
103
- typeof current === "string" ? STATUS_DICTIONARY[current] : current;
104
- const minorObj =
105
- typeof minor === "string" ? STATUS_DICTIONARY[minor] : minor;
106
-
107
- if (!currentObj || typeof currentObj.weight === "undefined") return minor;
108
- if (!minorObj || typeof minorObj.weight === "undefined") return current;
109
-
110
- return currentObj.weight < minorObj.weight ? currentObj : minorObj;
111
- }, servicesStatus[0] || STATUS_DICTIONARY.NS);
112
-
113
- return winner?.status || STATUS_DICTIONARY.NS?.status;
95
+ // Wrapper for array format: [{ status: "AS" }, ...]
96
+ export function getMinorStatusFromRetailer(statusByRetailer = []) {
97
+ return getMinorStatus(statusByRetailer.map((s) => s?.status));
114
98
  }
@@ -8,6 +8,7 @@ import {
8
8
  ProviderProductEditionProvider,
9
9
  useProviderProductEdition,
10
10
  } from "./context/provider-product-edition.context";
11
+ import { getMinorStatusFromRetailer } from "./context/reducers/product";
11
12
  import {
12
13
  normalizeProduct,
13
14
  getConceptByTab,
@@ -70,10 +71,16 @@ const allowedAccountsToViewChangeStatus = [
70
71
  "gmorales@contentoh.com",
71
72
  "rvega@contentoh.com",
72
73
  "amora@contentoh.com",
74
+ //PRODUCT DEV ACCOUNTS
73
75
  "oparra@contentoh.com",
74
76
  "zsegura@contentoh.com",
75
77
  "oserna@contentoh.com",
76
- "jalvarado@contentoh.com"
78
+ "jalvarado@contentoh.com",
79
+ //DEV ACCOUNTS
80
+ "kikije1467@mtlcz.com", //IMÁGENES
81
+ "karafe3218@mom2kid.com", //TEXTOS
82
+ "ladiboh785@mi166.com", //QA
83
+
77
84
  ];
78
85
 
79
86
  const RetailerProductEditionView = ({
@@ -759,9 +766,7 @@ const RetailerProductEditionView = ({
759
766
  const updatedProduct = {
760
767
  ...state.product,
761
768
  statusByRetailer: updatedStatusByRetailer,
762
- // version_status: articleStatus,
763
- // status: articleStatus,
764
- // article_status: articleStatus
769
+ status: getMinorStatusFromRetailer(updatedStatusByRetailer),
765
770
  };
766
771
 
767
772
  dispatch({ type: "SET_PRODUCT", payload: updatedProduct });
@@ -835,19 +840,18 @@ const RetailerProductEditionView = ({
835
840
  // };
836
841
  // await sendMessage(messageData);
837
842
 
843
+ const updatedStatusByRetailerForSend = state.product.statusByRetailer.map((item) => {
844
+ if (item.retailer_id === retailerId && item.service === concept) {
845
+ return { ...item, status: newStatus };
846
+ }
847
+ return item;
848
+ });
849
+
838
850
  const updatedProduct = {
839
851
  ...state.product,
840
852
  [`${concept}_status`]: newStatus,
841
- // actualizar el status es statusByRetailer
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
- // version_status: articleStatus,
849
- // status: articleStatus,
850
- // article_status: articleStatus
853
+ statusByRetailer: updatedStatusByRetailerForSend,
854
+ status: getMinorStatusFromRetailer(updatedStatusByRetailerForSend),
851
855
  };
852
856
 
853
857
  //Actualizamos el services_data en el servicio específico del retailer actual
@@ -927,7 +931,7 @@ const RetailerProductEditionView = ({
927
931
  state.services_data?.forEach((ret, idx) => {
928
932
  const { service: retailer_service, id_retailer, status: status_retailer_service } = ret;
929
933
 
930
- const lastStatusLevel = status_retailer_service.replace(/.*\//, "");
934
+ const lastStatusLevel = status_retailer_service?.replace(/.*\//, "");
931
935
 
932
936
  if (conceptArray.includes(retailer_service) && statusArray?.includes(lastStatusLevel)) {
933
937
  const data = {
@@ -963,7 +967,7 @@ const RetailerProductEditionView = ({
963
967
  const updatedProduct = {
964
968
  ...state.product,
965
969
  article_status: status,
966
- status: status,
970
+ status: getMinorStatusFromRetailer(updatedStatusByRetailer),
967
971
  datasheet_status:
968
972
  state.product.datasheet_status === "NA" ? "NA" : status,
969
973
  description_status:
@@ -114,7 +114,7 @@ export const normalizeProduct = (product) => {
114
114
  percentages: productData.percentages || null,
115
115
  summary: productData.summary || null,
116
116
  version: productData.version || 0,
117
- id_order: productData.orderId || 0,
117
+ id_order: productData.orderId || productData.id_order || 0,
118
118
  status: productData.status || null,
119
119
  datasheet_status: productData.datasheet_status || null,
120
120
  description_status: productData.description_status || null,
@@ -98,6 +98,36 @@ const STATUS_DICTIONARY = {
98
98
  },
99
99
  };
100
100
 
101
+ const resolveStatusObj = (statusStr) => {
102
+ if (!statusStr || typeof statusStr !== "string") return null;
103
+ if (STATUS_DICTIONARY[statusStr]) return STATUS_DICTIONARY[statusStr];
104
+ // Compound statuses like 'RA/AS' — use last segment for weight lookup
105
+ const parts = statusStr.split("/");
106
+ const lastPart = parts[parts.length - 1];
107
+ const dictEntry = STATUS_DICTIONARY[lastPart];
108
+ if (dictEntry) return { status: statusStr, name: statusStr, weight: dictEntry.weight };
109
+ return null;
110
+ };
111
+
112
+ // Returns the status string with the lowest weight from an array of status strings
113
+ const getMinorStatus = (servicesStatus = []) => {
114
+ if (!servicesStatus || servicesStatus.length === 0)
115
+ return STATUS_DICTIONARY.NS.status;
116
+ const winner = servicesStatus.reduce((minorObj, current) => {
117
+ const currentObj = resolveStatusObj(
118
+ typeof current === "string" ? current : current?.status
119
+ );
120
+ if (!currentObj || typeof currentObj.weight === "undefined") return minorObj;
121
+ return currentObj.weight < minorObj.weight ? currentObj : minorObj;
122
+ }, STATUS_DICTIONARY.NS);
123
+ return winner?.status || STATUS_DICTIONARY.NS.status;
124
+ };
125
+
126
+ const getMinorStatusFromRetailerMap = (statusByRetailer = {}) =>
127
+ getMinorStatus(Object.values(statusByRetailer).flatMap(Object.values));
128
+
101
129
  module.exports = {
102
- STATUS_DICTIONARY
130
+ STATUS_DICTIONARY,
131
+ getMinorStatus,
132
+ getMinorStatusFromRetailerMap,
103
133
  }