contentoh-components-library 21.5.86 → 21.5.88

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.
@@ -18,79 +18,139 @@ RetailerProductEditionDefault.args = {
18
18
  token:
19
19
  "eyJraWQiOiJEV3owZnNieXg2MXNFcVduN3RCXC81bVhod3ZNbFZIOTgwUnZcL3RjT0lKdEk9IiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiI4ZDAxMDIxNC01YmZhLTQzYzMtOTZmYi1jNTU2ZGMwNTc3NGIiLCJjb2duaXRvOmdyb3VwcyI6WyJjb2xhYm9yYWRvcmVzX2NvbnRlbnRvaCJdLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tXC91cy1lYXN0LTFfbFN6UVo0WjdSIiwiY29nbml0bzp1c2VybmFtZSI6IjhkMDEwMjE0LTViZmEtNDNjMy05NmZiLWM1NTZkYzA1Nzc0YiIsImF1ZCI6IjUyZDlza2tkY2c4cWpwODhvb2sxdXNlNm1rIiwiZXZlbnRfaWQiOiI1MDgwMTVmMy1mZGVkLTQ2ODUtYTIxNy1mYzgyMTg0ZWRmNGMiLCJ0b2tlbl91c2UiOiJpZCIsImF1dGhfdGltZSI6MTc2ODI1MzE3NywibmFtZSI6IkNvbGFib3JhZG9yIiwicGhvbmVfbnVtYmVyIjoiKzUyMTExMSIsImV4cCI6MTc2ODI1Njc3NywiaWF0IjoxNzY4MjUzMTc3LCJlbWFpbCI6ImthcmFmZTMyMThAbW9tMmtpZC5jb20ifQ.QiZiscuTvrur0g328Zmh2bI-kZyg7YO_T5jT63096JNuSxGnX9wpK87cVTV1dED4ruD-2NMsgLShUIMcklAg17FL6i5_vCuB1dSIDY0LaybvSpriFJaVVdMUIMGFi_1Q7bI9qqyXYkevcf-HO33vVPdU-_-4-u8YRd-QganUk35vPYPh9vFJWbC0Qtvv25ZR4L2xuRIXx4e7StlTvZXysnYL8A84jkK1zn6d77V-9GqQQW8exO6sBW7R6cGt55vnF80NIfG_9lAqCK0PcZH4o50aqrAVhtfV5edlEmXBHeGK5R3Sz5iTeKb51QF3TWVFZCYGvQJ7FShulUWHcm3X2Q",
20
20
  productSelected: {
21
- "articleId": 145186,
21
+ "articleId": 145199,
22
22
  "services": {
23
23
  "datasheets": 1,
24
24
  "descriptions": 1,
25
- "images": 1
25
+ "images": 0
26
26
  },
27
- "orderId": 10449,
27
+ "orderId": 10457,
28
28
  "city": "CDMX, México",
29
29
  "status": "AS",
30
- "datasheet_status": "AC",
30
+ "datasheet_status": "AS",
31
31
  "prio": "none",
32
32
  "version": 3,
33
33
  "description_status": "AS",
34
- "images_status": "AC",
34
+ "images_status": "NS",
35
35
  "statusByRetailer": [
36
36
  {
37
- "status": "AC",
37
+ "status": "AS",
38
+ "service": "datasheet",
39
+ "retailer_id": 9,
40
+ "task_user_group_id": 2
41
+ },
42
+ {
43
+ "status": "AS",
44
+ "service": "description",
45
+ "retailer_id": 9,
46
+ "task_user_group_id": 2
47
+ },
48
+ {
49
+ "status": "AS",
50
+ "service": "datasheet",
51
+ "retailer_id": 19,
52
+ "task_user_group_id": 2
53
+ },
54
+ {
55
+ "status": "AS",
56
+ "service": "description",
57
+ "retailer_id": 19,
58
+ "task_user_group_id": 2
59
+ },
60
+ {
61
+ "status": "AS",
38
62
  "service": "datasheet",
39
- "retailer_id": 70,
40
- "task_user_group_id": 4
63
+ "retailer_id": 24,
64
+ "task_user_group_id": 2
41
65
  },
42
66
  {
43
67
  "status": "AS",
44
68
  "service": "description",
45
- "retailer_id": 70,
69
+ "retailer_id": 24,
70
+ "task_user_group_id": 2
71
+ },
72
+ {
73
+ "status": "AS",
74
+ "service": "datasheet",
75
+ "retailer_id": 1011,
46
76
  "task_user_group_id": 2
47
77
  },
48
78
  {
49
- "status": "AC",
50
- "service": "images",
51
- "retailer_id": 70,
52
- "task_user_group_id": 4
79
+ "status": "AS",
80
+ "service": "description",
81
+ "retailer_id": 1011,
82
+ "task_user_group_id": 2
53
83
  }
54
84
  ],
55
85
  "article": {
56
- "id_article": 145186,
57
- "id_category": "4007",
86
+ "id_article": 145199,
87
+ "id_category": "10001",
58
88
  "brand": null,
59
- "name": "Mayonesa",
60
- "upc": "098928",
61
- "sku": "899",
62
- "timestamp": "2026-04-23T16:02:14.000Z",
89
+ "name": "Serna Status Bug 4",
90
+ "upc": "14615181351",
91
+ "sku": "156845131",
92
+ "timestamp": "2026-05-05T15:08:54.000Z",
63
93
  "active": 1,
64
94
  "company_id": 291,
65
95
  "company_name": "LATAM LOGISTICS",
66
96
  "country": "México",
67
- "id_order": 10449,
97
+ "id_order": 10457,
68
98
  "id_datasheet_especialist": 426,
69
99
  "id_datasheet_facilitator": null,
70
100
  "id_description_especialist": 426,
71
101
  "id_description_facilitator": null,
72
- "id_images_especialist": 427,
102
+ "id_images_especialist": null,
73
103
  "id_images_facilitator": null,
74
104
  "id_auditor": 425,
75
105
  "id_recepcionist": null,
76
- "category": "Abarrotes Procesados|Abarrotes Básicos y Procesados|Abarrotes Básicos y Procesados",
106
+ "category": "Departamento Hanseatik|Categoría Hanseatik|Subcategoría Hanseatik",
77
107
  "categoryRetailer": [
78
108
  {
79
- "id_category": 4007,
80
- "id_retailer": 70,
81
- "category_name": "Abarrotes Procesados|Abarrotes Básicos y Procesados|Abarrotes Básicos y Procesados",
82
- "retailer_name": "Bodega Aurrera"
109
+ "id_category": 3432,
110
+ "id_retailer": 24,
111
+ "category_name": "Bebés Alsuper|Bebés|Bebés",
112
+ "retailer_name": "Alsuper"
113
+ },
114
+ {
115
+ "id_category": 3579,
116
+ "id_retailer": 1011,
117
+ "category_name": "Categoría Genérica Farmatodo|Categoría Genérica|Categoría Genérica",
118
+ "retailer_name": "Farmatodo"
119
+ },
120
+ {
121
+ "id_category": 6795,
122
+ "id_retailer": 19,
123
+ "category_name": "Categoría Generica Costco|Categoría Generica|Categoría Generica",
124
+ "retailer_name": "Costco"
125
+ },
126
+ {
127
+ "id_category": 10001,
128
+ "id_retailer": 9,
129
+ "category_name": "Departamento Hanseatik|Categoría Hanseatik|Subcategoría Hanseatik",
130
+ "retailer_name": "Amazon"
83
131
  }
84
132
  ]
85
133
  },
86
134
  "retailers": [
87
135
  {
88
- "id": 70,
89
- "name": "Bodega Aurrera"
136
+ "id": 9,
137
+ "name": "Amazon"
138
+ },
139
+ {
140
+ "id": 19,
141
+ "name": "Costco"
142
+ },
143
+ {
144
+ "id": 24,
145
+ "name": "Alsuper"
146
+ },
147
+ {
148
+ "id": 1011,
149
+ "name": "Farmatodo"
90
150
  }
91
151
  ],
92
152
  "country": "México",
93
- "upc": "098928"
153
+ "upc": "14615181351"
94
154
  },
95
155
 
96
156
  // location: {
@@ -103,41 +163,41 @@ RetailerProductEditionDefault.args = {
103
163
 
104
164
  // EDICION IMAGENES
105
165
 
106
- user: {
107
- "id_user": 427,
108
- "name": "Especialista Edición",
109
- "last_name": null,
110
- "email": "kikije1467@mtlcz.com",
111
- "position": "Tester",
112
- "telephone": null,
113
- "country": null,
114
- "id_company": 254,
115
- "id_cognito": "c7e5a6a4-2b3f-4d54-af98-9e09a4cbc01e",
116
- "birth_Date": null,
117
- "about_me": null,
118
- "zip_code": null,
119
- "address": null,
120
- "job": null,
121
- "id_stripe": null,
122
- "id_role": 8,
123
- "active": 1,
124
- "is_retailer": 0,
125
- "email_notify": null,
126
- "is_user_tech": null,
127
- "is_onboarding": 0,
128
- "membership": {
129
- "id": 750,
130
- "start_date": "2022-01-07T21:32:54.000Z",
131
- "end_date": "2023-01-07T21:32:54.000Z",
132
- "planID": 6,
133
- "plan": "prod_KvGd6YSTJyR3AP",
134
- "name": "Plan Small",
135
- "user_limit": "10",
136
- "products_limit": "1000",
137
- "type": "Enterprise"
138
- },
139
- "src": "https://content-management-profile-prod.s3.amazonaws.com/id-427/427.png?1775592220312"
140
- },
166
+ // user: {
167
+ // "id_user": 427,
168
+ // "name": "Especialista Edición",
169
+ // "last_name": null,
170
+ // "email": "kikije1467@mtlcz.com",
171
+ // "position": "Tester",
172
+ // "telephone": null,
173
+ // "country": null,
174
+ // "id_company": 254,
175
+ // "id_cognito": "c7e5a6a4-2b3f-4d54-af98-9e09a4cbc01e",
176
+ // "birth_Date": null,
177
+ // "about_me": null,
178
+ // "zip_code": null,
179
+ // "address": null,
180
+ // "job": null,
181
+ // "id_stripe": null,
182
+ // "id_role": 8,
183
+ // "active": 1,
184
+ // "is_retailer": 0,
185
+ // "email_notify": null,
186
+ // "is_user_tech": null,
187
+ // "is_onboarding": 0,
188
+ // "membership": {
189
+ // "id": 750,
190
+ // "start_date": "2022-01-07T21:32:54.000Z",
191
+ // "end_date": "2023-01-07T21:32:54.000Z",
192
+ // "planID": 6,
193
+ // "plan": "prod_KvGd6YSTJyR3AP",
194
+ // "name": "Plan Small",
195
+ // "user_limit": "10",
196
+ // "products_limit": "1000",
197
+ // "type": "Enterprise"
198
+ // },
199
+ // "src": "https://content-management-profile-prod.s3.amazonaws.com/id-427/427.png?1775592220312"
200
+ // },
141
201
 
142
202
  //TEXTOS
143
203
 
@@ -178,39 +238,39 @@ user: {
178
238
  // "src": "https://content-management-profile.s3.amazonaws.com/id-442/442.png?1760636567736"
179
239
  // },
180
240
 
181
- // user: {
182
- // id_user: 426,
183
- // name: "Especialista Textos",
184
- // last_name: null,
185
- // email: "karafe3218@mom2kid.com",
186
- // position: "Tester",
187
- // telephone: null,
188
- // country: null,
189
- // id_company: 254,
190
- // id_cognito: "8d010214-5bfa-43c3-96fb-c556dc05774b",
191
- // birth_Date: null,
192
- // about_me: null,
193
- // zip_code: null,
194
- // address: null,
195
- // job: null,
196
- // id_stripe: null,
197
- // id_role: 7,
198
- // active: 1,
199
- // is_retailer: 0,
200
- // email_notify: null,
201
- // is_user_tech: null,
202
- // is_onboarding: 0,
203
- // membership: {
204
- // id: 750,
205
- // start_date: "2022-01-07T21:32:54.000Z",
206
- // end_date: "2023-01-07T21:32:54.000Z",
207
- // planID: 6,
208
- // plan: "prod_KvGd6YSTJyR3AP",
209
- // name: "Plan Small",
210
- // user_limit: "10",
211
- // products_limit: "1000",
212
- // type: "Enterprise",
213
- // },
214
- // src: "https://content-management-profile-prod.s3.amazonaws.com/id-426/426.png?1768253179478",
215
- // },
241
+ user: {
242
+ id_user: 426,
243
+ name: "Especialista Textos",
244
+ last_name: null,
245
+ email: "karafe3218@mom2kid.com",
246
+ position: "Tester",
247
+ telephone: null,
248
+ country: null,
249
+ id_company: 254,
250
+ id_cognito: "8d010214-5bfa-43c3-96fb-c556dc05774b",
251
+ birth_Date: null,
252
+ about_me: null,
253
+ zip_code: null,
254
+ address: null,
255
+ job: null,
256
+ id_stripe: null,
257
+ id_role: 7,
258
+ active: 1,
259
+ is_retailer: 0,
260
+ email_notify: null,
261
+ is_user_tech: null,
262
+ is_onboarding: 0,
263
+ membership: {
264
+ id: 750,
265
+ start_date: "2022-01-07T21:32:54.000Z",
266
+ end_date: "2023-01-07T21:32:54.000Z",
267
+ planID: 6,
268
+ plan: "prod_KvGd6YSTJyR3AP",
269
+ name: "Plan Small",
270
+ user_limit: "10",
271
+ products_limit: "1000",
272
+ type: "Enterprise",
273
+ },
274
+ src: "https://content-management-profile-prod.s3.amazonaws.com/id-426/426.png?1768253179478",
275
+ },
216
276
  };
@@ -44,19 +44,19 @@ export const productReducer = (state, action) => {
44
44
  (status) =>
45
45
  status?.service === "description" &&
46
46
  status?.retailer_id === state?.active_retailer?.id_retailer,
47
- ).status || "NS",
47
+ )?.status || "NS",
48
48
  datasheet_status:
49
49
  action.payload.find(
50
50
  (status) =>
51
51
  status?.service === "datasheet" &&
52
52
  status?.retailer_id === state?.active_retailer?.id_retailer,
53
- ).status || "NS",
53
+ )?.status || "NS",
54
54
  images_status:
55
55
  action.payload.find(
56
56
  (status) =>
57
57
  status?.service === "images" &&
58
58
  status?.retailer_id === state?.active_retailer?.id_retailer,
59
- ).status || "NS",
59
+ )?.status || "NS",
60
60
  statusByRetailer: action.payload,
61
61
  },
62
62
  };
@@ -110,5 +110,5 @@ function getMinorStatus(servicesStatus = []) {
110
110
  return currentObj.weight < minorObj.weight ? currentObj : minorObj;
111
111
  }, servicesStatus[0] || STATUS_DICTIONARY.NS);
112
112
 
113
- return winner?.status || STATUS_DICTIONARY.NS.status;
113
+ return winner?.status || STATUS_DICTIONARY.NS?.status;
114
114
  }
@@ -696,9 +696,11 @@ const RetailerProductEditionView = ({
696
696
 
697
697
  const sendSingleEvaluation = async (result) => {
698
698
  if (state.saving) return;
699
+
699
700
  dispatch({ type: "SET_SAVING", payload: true });
700
701
 
701
702
  const concept = getConceptByTab(state.active_tab);
703
+
702
704
  const articleId = state.product.id_article;
703
705
  const orderId = state.product.id_order ?? state.product.orderId;
704
706
  const sectionStatusKey = `${concept}_status`;
@@ -713,6 +715,7 @@ const RetailerProductEditionView = ({
713
715
  const activeTab = state.active_tab;
714
716
 
715
717
  try {
718
+ //Esto solo se ejecutará cuando se aprueba o rechaza desde el modal superior derecho
716
719
  if (result) {
717
720
  data.result = result;
718
721
  data.retailerId = retailerId;
@@ -757,7 +760,10 @@ const RetailerProductEditionView = ({
757
760
  image: successIcon,
758
761
  },
759
762
  });
760
- } else {
763
+ } else { //Caso del botón "Enviar evaluación"
764
+
765
+ //Se construye el mensaje y se actualiza el estatus
766
+
761
767
  const specialistDone = ["RC", "RA", "CA"].includes(evalStatus);
762
768
 
763
769
  if (specialistDone) {
@@ -772,39 +778,41 @@ const RetailerProductEditionView = ({
772
778
  message = "Evaluación enviada";
773
779
  icon = successIcon;
774
780
  }
781
+
775
782
  res = await axios.put(`${process.env.REACT_APP_SEND_EVAL}`, data, {
776
783
  headers: {
777
784
  Authorization: token,
778
785
  },
779
786
  });
780
787
  }
788
+
781
789
  if (res.data.statusCode === 200) {
782
- const { newStatus, newOrderStatus, newArticleStatus } = JSON.parse(
783
- res.data.body,
784
- );
785
- const retailers = state.product.categoryRetailer.map((r) => ({
786
- id: r.id_retailer,
787
- name: r.retailerName,
788
- }));
789
- const messageToChat = createMessage(
790
- retailers,
791
- retailerId,
792
- evalStatus,
793
- newStatus,
794
- activeTab,
795
- );
796
790
 
797
- const messageData = {
798
- paramsBody: {
799
- id: articleId,
800
- version: state.product.version,
801
- items: [{ type: "status", value: messageToChat }],
802
- retailerId: retailerId,
803
- status: state.product.status,
804
- },
805
- paramsHeader: { Authorization: token },
806
- };
807
- await sendMessage(messageData);
791
+ const { newStatus, newOrderStatus, newArticleStatus } = JSON.parse( res.data.body );
792
+
793
+ // const retailers = state.product.categoryRetailer.map((r) => ({
794
+ // id: r.id_retailer,
795
+ // name: r.retailerName,
796
+ // }));
797
+ // const messageToChat = createMessage(
798
+ // retailers,
799
+ // retailerId,
800
+ // evalStatus,
801
+ // newStatus,
802
+ // activeTab,
803
+ // );
804
+
805
+ // const messageData = {
806
+ // paramsBody: {
807
+ // id: articleId,
808
+ // version: state.product.version,
809
+ // items: [{ type: "status", value: messageToChat }],
810
+ // retailerId: retailerId,
811
+ // status: state.product.status,
812
+ // },
813
+ // paramsHeader: { Authorization: token },
814
+ // };
815
+ // await sendMessage(messageData);
808
816
 
809
817
  const updatedProduct = {
810
818
  ...state.product,
@@ -818,7 +826,15 @@ const RetailerProductEditionView = ({
818
826
  }),
819
827
  };
820
828
 
829
+ //Actualizamos el services_data en el servicio específico del retailer actual
830
+
831
+ const updatedServicesData = state.services_data?.map(service => ({
832
+ ...service,
833
+ status: service?.id_retailer === retailerId && service?.service === concept ? newStatus : service?.status
834
+ }));
835
+
821
836
  const sessionProduct = sessionStorage.getItem("productSelected");
837
+
822
838
  if (sessionProduct) {
823
839
  const productInSession = JSON.parse(sessionProduct);
824
840
  const updatedProductInSession = {
@@ -850,6 +866,7 @@ const RetailerProductEditionView = ({
850
866
  }
851
867
 
852
868
  dispatch({ type: "SET_PRODUCT", payload: updatedProduct });
869
+ dispatch({ type: "SET_SERVICES_DATA", payload: updatedServicesData });
853
870
  }
854
871
  } catch (error) {
855
872
  console.error("Error sending evaluation:", error);
@@ -1097,6 +1114,7 @@ const RetailerProductEditionView = ({
1097
1114
  switch (id_rol) {
1098
1115
  case 7:
1099
1116
  case 8:
1117
+
1100
1118
  const conditionOne = statusArray.includes(statusByActiveService);
1101
1119
  const conditionTwo = statusArray.includes(product?.status);
1102
1120
  const conditionThree =
@@ -1105,10 +1123,11 @@ const RetailerProductEditionView = ({
1105
1123
  ).length === servicesByTab.length;
1106
1124
 
1107
1125
  return (conditionOne && conditionTwo) || conditionThree;
1126
+
1108
1127
  case 4:
1109
1128
  case 5:
1110
1129
  const filteredSrv45 = servicesByTab?.filter((serv) =>
1111
- statusArray.includes(serv.status),
1130
+ statusArray.includes(serv?.status),
1112
1131
  );
1113
1132
  const condition45 =
1114
1133
  unvalidated &&
@@ -1118,7 +1137,7 @@ const RetailerProductEditionView = ({
1118
1137
  case 6:
1119
1138
  const statusInArray = statusArray.includes(product?.status);
1120
1139
  const allSrvValid = srv?.every((serv) =>
1121
- ["RA", "AA", "AP", "ACA"].includes(serv.status),
1140
+ ["RA", "AA", "AP", "ACA"].includes(serv?.status),
1122
1141
  );
1123
1142
  const condition6 = statusInArray && allSrvValid && auditorUnvalidated;
1124
1143
  return condition6;
@@ -45,7 +45,39 @@ export const AiProductEditionProvider = ({
45
45
  const [inputsGeneratedWithAi, setInputsGeneratedWithAi] = useState({});
46
46
  const [inputsUsingAi, setInputsUsingAi] = useState({});
47
47
 
48
+ const MAX_CREDITS = 10;
49
+ const COOLDOWN_MS = 5 * 60 * 1000;
50
+ const RATE_LIMIT_KEY = "ai_generation_limit_data";
48
51
 
52
+ const checkAndManageRateLimit = (currentArticleId) => {
53
+ const now = Date.now();
54
+ const storedData = localStorage.getItem(RATE_LIMIT_KEY);
55
+
56
+ let allRateData = storedData ? JSON.parse(storedData) : {};
57
+
58
+ let productTimestamps = allRateData[currentArticleId] || [];
59
+
60
+ productTimestamps = productTimestamps.filter(timestamp => (now - timestamp) < COOLDOWN_MS);
61
+
62
+ if (productTimestamps.length >= MAX_CREDITS) {
63
+
64
+ allRateData[currentArticleId] = productTimestamps;
65
+ localStorage.setItem(RATE_LIMIT_KEY, JSON.stringify(allRateData));
66
+
67
+ return {
68
+ allowed: false,
69
+ message: "Has alcanzado el limite de intentos frecuentes para este producto. Por favor, espera unos minutos."
70
+ };
71
+ }
72
+
73
+
74
+ productTimestamps.push(now);
75
+ allRateData[currentArticleId] = productTimestamps;
76
+
77
+ localStorage.setItem(RATE_LIMIT_KEY, JSON.stringify(allRateData));
78
+
79
+ return { allowed: true };
80
+ };
49
81
 
50
82
  function setCurrentSuggestionValue({
51
83
  inputId,
@@ -93,6 +125,10 @@ export const AiProductEditionProvider = ({
93
125
  attributeId
94
126
  });
95
127
 
128
+ if(newSuggestions?.error) return {
129
+ error: newSuggestions.error
130
+ }
131
+
96
132
  if(!Array.isArray(newSuggestions) || newSuggestions.length === 0)
97
133
  return console.log("Error: No se obtuvieron nuevas sugerencias");
98
134
 
@@ -119,6 +155,15 @@ export const AiProductEditionProvider = ({
119
155
 
120
156
  if(!isAiAvailable) return;
121
157
 
158
+ const rateLimitStatus = checkAndManageRateLimit(articleId);
159
+
160
+ if (!rateLimitStatus.allowed) {
161
+ return {
162
+ error: rateLimitStatus.message,
163
+ isRateLimitInfo: true
164
+ };
165
+ }
166
+
122
167
  if(!product)
123
168
  throw new Error("El producto no está definido");
124
169