contentoh-components-library 21.5.99 → 21.6.0

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 (63) hide show
  1. package/dist/components/atoms/GeneralButton/styles.js +1 -1
  2. package/dist/components/atoms/GeneralInput/index.js +249 -54
  3. package/dist/components/atoms/GeneralInput/styles.js +7 -3
  4. package/dist/components/atoms/InputFormatter/index.js +223 -68
  5. package/dist/components/atoms/InputFormatter/styles.js +20 -4
  6. package/dist/components/molecules/StatusAsignationInfo/index.js +11 -1
  7. package/dist/components/molecules/TabsMenu/index.js +13 -1
  8. package/dist/components/molecules/TagAndInput/index.js +364 -24
  9. package/dist/components/molecules/TagAndInput/styles.js +2 -2
  10. package/dist/components/organisms/FullProductNameHeader/index.js +6 -22
  11. package/dist/components/organisms/InputGroup/index.js +22 -18
  12. package/dist/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +150 -337
  13. package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.context.js +15 -15
  14. package/dist/components/pages/ProviderProductEdition/index.js +393 -352
  15. package/dist/components/pages/ProviderProductEdition/utils.js +1 -0
  16. package/dist/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +125 -211
  17. package/dist/components/pages/RetailerProductEdition/index.js +1743 -2239
  18. package/dist/components/pages/RetailerProductEdition/styles.js +4 -2
  19. package/dist/components/pages/RetailerProductEdition/utils.js +251 -2
  20. package/package.json +4 -2
  21. package/src/ai/utils/compare-strings.js +45 -0
  22. package/src/assets/images/Icons/arrow.png +0 -0
  23. package/src/assets/images/Icons/cancel.png +0 -0
  24. package/src/assets/images/Icons/ia-icon.png +0 -0
  25. package/src/assets/images/Icons/loading.svg +5 -0
  26. package/src/assets/images/Icons/reload.png +0 -0
  27. package/src/components/atoms/GeneralButton/styles.js +4 -0
  28. package/src/components/atoms/GeneralInput/index.js +241 -60
  29. package/src/components/atoms/GeneralInput/styles.js +81 -0
  30. package/src/components/atoms/InputFormatter/index.js +200 -51
  31. package/src/components/atoms/InputFormatter/styles.js +284 -0
  32. package/src/components/atoms/RetailerSelector/RetailerSelector.stories.js +10 -0
  33. package/src/components/atoms/RetailerSelector/index.js +3 -0
  34. package/src/components/atoms/RetailerSelector/styles.js +0 -0
  35. package/src/components/molecules/StatusAsignationInfo/index.js +9 -1
  36. package/src/components/molecules/TabsMenu/index.js +12 -0
  37. package/src/components/molecules/TagAndInput/index.js +294 -21
  38. package/src/components/molecules/TagAndInput/styles.js +59 -17
  39. package/src/components/organisms/ChangeStatusModal/index.jsx +488 -0
  40. package/src/components/organisms/ChangeStatusModal/styles.js +333 -0
  41. package/src/components/organisms/FullProductNameHeader/index.js +4 -28
  42. package/src/components/organisms/FullTabsMenu/index.js +1 -1
  43. package/src/components/organisms/InputGroup/index.js +12 -4
  44. package/src/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +174 -202
  45. package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx +14 -14
  46. package/src/components/pages/ProviderProductEdition/index.js +486 -417
  47. package/src/components/pages/ProviderProductEdition/utils.js +2 -2
  48. package/src/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +136 -243
  49. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.context.jsx +575 -0
  50. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.reducer.js +62 -0
  51. package/src/components/pages/RetailerProductEdition/context/reducers/active-state.js +344 -0
  52. package/src/components/pages/RetailerProductEdition/context/reducers/inputs.js +155 -0
  53. package/src/components/pages/RetailerProductEdition/context/reducers/product.js +114 -0
  54. package/src/components/pages/RetailerProductEdition/context/reducers/system.js +60 -0
  55. package/src/components/pages/RetailerProductEdition/index.js +1580 -1719
  56. package/src/components/pages/RetailerProductEdition/index_old.js +1979 -0
  57. package/src/components/pages/RetailerProductEdition/stories/Auditor.stories.js +101 -0
  58. package/src/components/pages/RetailerProductEdition/stories/ImageEditor.stories.js +115 -0
  59. package/src/components/pages/RetailerProductEdition/stories/TextEditor.stories.js +174 -0
  60. package/src/components/pages/RetailerProductEdition/styles.js +67 -2
  61. package/src/components/pages/RetailerProductEdition/utils.js +240 -0
  62. package/src/contexts/AiProductEdition.jsx +347 -0
  63. package/src/global-files/statusDictionary.js +103 -0
@@ -7,6 +7,11 @@ import rejectIcon from "../../../assets/images/generalButton/rejectIcon.svg";
7
7
  import InfoIcon from "../../../assets/images/sliderToolTip/infoIcon.svg";
8
8
  import { SliderToolTip } from "../../atoms/SliderToolTip";
9
9
  import { Tooltip } from "../../atoms/Tooltip";
10
+
11
+ import { useAiProductEdition } from "../../../contexts/AiProductEdition";
12
+ import AiGenerationIcon from "../../../assets/images/Icons/ia-icon.png";
13
+
14
+
10
15
  export const TagAndInput = ({
11
16
  inputType,
12
17
  label,
@@ -26,6 +31,7 @@ export const TagAndInput = ({
26
31
  inputRows,
27
32
  maxChar,
28
33
  required,
34
+ aiGenerated,
29
35
  optionList,
30
36
  description,
31
37
  inputOnChange,
@@ -43,6 +49,188 @@ export const TagAndInput = ({
43
49
  boxOnboardingData || []
44
50
  );
45
51
 
52
+ const {
53
+ isCreators,
54
+ generateProductSuggestions,
55
+ regenerateProductSuggestions,
56
+ suggestions,
57
+ setSuggestions,
58
+ currentSuggestion,
59
+ setCurrentSuggestionValue,
60
+ isAiAvailable,
61
+ inputsGeneratedWithAi,
62
+ setInputsGeneratedWithAi,
63
+ inputsUsingAi,
64
+ setInputsUsingAi
65
+ } = useAiProductEdition();
66
+
67
+ const isBenefitInput = label?.toLowerCase().includes("beneficios");
68
+
69
+ const [isAiGenerationLoading, setIsAiGenerationLoading] = useState(false);
70
+ const [isAiActive, setIsAiActive] = useState(false);
71
+ const [isAiRegenerationLoading, setIsAiRegenerationLoading] = useState(false);
72
+ const [isAiGenerated, setIsAiGenerated] = useState(false);
73
+
74
+ const [errorMessage, setErrorMessage] = useState("");
75
+
76
+ async function handlerAiGeneration({
77
+ type
78
+ }) {
79
+
80
+ if(isAiGenerationLoading || !isAiAvailable) return;
81
+
82
+ if(isAiActive) {
83
+ setIsAiActive(false);
84
+ return;
85
+ }
86
+
87
+ //Si ya tiene sugerencias generadas, se las mostramos
88
+ const currentSuggestions = suggestions?.[inputId];
89
+
90
+ if(Array.isArray(currentSuggestions) && currentSuggestions.length > 0)
91
+ return setIsAiActive(true);
92
+
93
+ setErrorMessage("");
94
+ setIsAiGenerationLoading(true);
95
+
96
+ const aiSuggestions = await generateProductSuggestions({
97
+ inputName: label,
98
+ currentValue: value,
99
+ description: description,
100
+ maxChar: maxChar ?? 99,
101
+ type: type,
102
+ // Informacion del producto
103
+ articleId: articleId,
104
+ versionId: version,
105
+ descriptionId: !isBenefitInput ? inputId : null,
106
+ attributeId: isBenefitInput ? inputId : null
107
+ });
108
+
109
+ if(!aiSuggestions && aiSuggestions.length === 0) {
110
+ const errorMsg = "Error: No se recibieron sugerencias de IA";
111
+ console.log(errorMsg);
112
+ setIsAiGenerationLoading(false);
113
+ return;
114
+ }
115
+
116
+ if(aiSuggestions?.error) {
117
+ console.log('Error: ', aiSuggestions.error);
118
+ setErrorMessage(aiSuggestions.error);
119
+ setIsAiGenerationLoading(false);
120
+ return;
121
+ }
122
+
123
+ setSuggestions(prev => ({
124
+ ...prev,
125
+ [inputId]: aiSuggestions
126
+ }));
127
+
128
+
129
+ setIsAiActive(true);
130
+ setIsAiGenerationLoading(false);
131
+
132
+ }
133
+
134
+ async function handlerRegenerateSuggestions({
135
+ type = "description"
136
+ }) {
137
+
138
+ if(isAiRegenerationLoading) return;
139
+
140
+ setErrorMessage("");
141
+ setIsAiRegenerationLoading(true);
142
+
143
+ const currentSuggestions = suggestions?.[inputId];
144
+
145
+ const aiSuggestions = await regenerateProductSuggestions({
146
+ inputName: label,
147
+ currentValue: value,
148
+ description: description,
149
+ maxChar: maxChar ?? 99,
150
+ type: type,
151
+ //Información del producto
152
+ articleId,
153
+ versionId: version,
154
+ descriptionId: !isBenefitInput ? inputId : null,
155
+ attributeId: isBenefitInput ? inputId : null
156
+ });
157
+
158
+ if(!aiSuggestions && aiSuggestions.length === 0) {
159
+ const errorMsg = "Error: No se recibieron sugerencias de IA";
160
+ console.log(errorMsg);
161
+ setErrorMessage(errorMsg);
162
+ setIsAiRegenerationLoading(false);
163
+ return;
164
+ }
165
+
166
+ console.log({aiSuggestionsRenew: aiSuggestions})
167
+
168
+ if(aiSuggestions?.error) {
169
+ console.log('Error: ', aiSuggestions.error);
170
+ setErrorMessage(aiSuggestions.error);
171
+ setIsAiRegenerationLoading(false);
172
+ return;
173
+ }
174
+
175
+ setSuggestions(prev => ({
176
+ ...prev,
177
+ [inputId]: [
178
+ ...currentSuggestions,
179
+ ...aiSuggestions
180
+ ]
181
+ }))
182
+
183
+ setIsAiRegenerationLoading(false);
184
+
185
+ }
186
+
187
+ const handleChangeSuggestion = ({
188
+ action = "next" // "prev" o "next"
189
+ }) => {
190
+
191
+ const inputSuggestions = suggestions?.[inputId];
192
+
193
+ if(!inputSuggestions || !Array.isArray(inputSuggestions)) return console.log("Error: No existe la sugerencia");
194
+
195
+ const currentIndex = currentSuggestion?.[inputId]?.index;
196
+
197
+ if(!currentIndex && currentIndex != 0) return console.log("Error: No existe un indice en la sugerencia actual");
198
+
199
+ switch(action) {
200
+ case "prev":
201
+
202
+ if(currentIndex === 0) return;
203
+
204
+ const prevIndex = currentIndex - 1;
205
+
206
+ setCurrentSuggestionValue({
207
+ inputId,
208
+ index: prevIndex,
209
+ value: inputSuggestions[prevIndex]?.value
210
+ })
211
+
212
+ break;
213
+
214
+ case "next":
215
+
216
+ if(currentIndex === inputSuggestions.length - 1) return;
217
+
218
+ const nextIndex = currentIndex + 1;
219
+
220
+ setCurrentSuggestionValue({
221
+ inputId,
222
+ index: nextIndex,
223
+ value: inputSuggestions[nextIndex]?.value
224
+ })
225
+
226
+ break;
227
+
228
+ default:
229
+ break;
230
+ }
231
+
232
+ }
233
+
46
234
  useEffect(() => {
47
235
  const temp = {};
48
236
  let maxBoxId = 0;
@@ -63,10 +251,64 @@ export const TagAndInput = ({
63
251
  );
64
252
  }
65
253
  }, []);
254
+
66
255
  useEffect(() => {
67
256
  onChange && onChange(boxOnboardingList);
68
257
  }, [boxOnboardingList]);
69
258
 
259
+ useEffect(() => {
260
+
261
+ if(!isCreators) return;
262
+
263
+ const currentDescriptionUpdate = Array.isArray(updatedDescriptions)
264
+ ? updatedDescriptions.find(desc => desc?.attributeId === inputId)
265
+ : null;
266
+
267
+ const currentDatasheetUpdate = Array.isArray(updatedDatasheets)
268
+ ? updatedDatasheets.find(data => data?.attributeId === inputId)
269
+ : null;
270
+
271
+ let calculatedIsAiGenerated = aiGenerated;
272
+
273
+ if (currentDescriptionUpdate) {
274
+ calculatedIsAiGenerated = currentDescriptionUpdate.aiSuggestionAccepted;
275
+ } else if (currentDatasheetUpdate) {
276
+ calculatedIsAiGenerated = currentDatasheetUpdate.aiSuggestionAccepted;
277
+ }
278
+
279
+ setInputsGeneratedWithAi(prev => ({
280
+ ...prev,
281
+ [`${inputId}-${inputType}-${version}`]: {
282
+ inputType,
283
+ inputId,
284
+ version,
285
+ isAiGenerated: !!calculatedIsAiGenerated,
286
+ label
287
+ }
288
+ }));
289
+
290
+ }, [updatedDescriptions, updatedDatasheets, aiGenerated, inputId]);
291
+
292
+ useEffect(() => {
293
+
294
+ if(!isCreators) return;
295
+
296
+ setIsAiGenerated(!!inputsGeneratedWithAi[`${inputId}-${inputType}-${version}`]?.isAiGenerated);
297
+ }, [inputsGeneratedWithAi]);
298
+
299
+ useEffect(() => {
300
+
301
+ if(!isCreators) return;
302
+
303
+ setInputsUsingAi(prev => ({
304
+ ...prev,
305
+ [`${inputId}-${inputType}-${version}`]: {
306
+ using: isAiActive
307
+ }
308
+ }))
309
+
310
+ }, [isAiActive])
311
+
70
312
  return (
71
313
  <Container
72
314
  inputType={inputType}
@@ -75,28 +317,45 @@ export const TagAndInput = ({
75
317
  >
76
318
  {label?.length && (
77
319
  <div className="title-container">
78
- <ScreenHeader
79
- text={label}
80
- headerType={"input-name-header"}
81
- color={color}
82
- />
83
- {description && (
84
- <Tooltip
85
- componentTooltip={
86
- <>
87
- <p>{description}</p>
88
- </>
89
- }
90
- children={
91
- <img
92
- src={InfoIcon}
93
- alt="info icon"
94
- className={'icon_information'}
95
- />
96
- }
97
- classNameTooltip={"container-tooltip"}
320
+ <div className="titles">
321
+ <ScreenHeader
322
+ text={label}
323
+ headerType={"input-name-header"}
324
+ color={color}
98
325
  />
99
- )}
326
+ {description && (
327
+ <Tooltip
328
+ componentTooltip={
329
+ <>
330
+ <p>{description}</p>
331
+ </>
332
+ }
333
+ children={
334
+ <img
335
+ src={InfoIcon}
336
+ alt="info icon"
337
+ className={'icon_information'}
338
+ />
339
+ }
340
+ classNameTooltip={"container-tooltip"}
341
+ />
342
+ )}
343
+ </div>
344
+ {
345
+ isCreators && isAiGenerated ? (
346
+ <div className="ai-generated">
347
+ <img src={AiGenerationIcon} />
348
+ <p>Atributo generado con IA</p>
349
+ </div>
350
+ ) : null
351
+ }
352
+ </div>
353
+ )}
354
+ {errorMessage && (
355
+ <div
356
+ className="error-message-container"
357
+ >
358
+ <p>{errorMessage}</p>
100
359
  </div>
101
360
  )}
102
361
  <GeneralInput
@@ -123,6 +382,19 @@ export const TagAndInput = ({
123
382
  inputOnChange={inputOnChange}
124
383
  onKeyDown={onKeyDown}
125
384
  auditClass={auditClass}
385
+ // AI Generation
386
+ hasAiGeneration={isCreators}
387
+ isBenefitInput={isBenefitInput}
388
+ isAiGenerationLoading={isAiGenerationLoading}
389
+ isAiRegenerationLoading={isAiRegenerationLoading}
390
+ isAiActive={isAiActive}
391
+ setIsAiActive={setIsAiActive}
392
+ isAiAvailable={isAiAvailable}
393
+ aiGenerated={aiGenerated}
394
+ // aiSuggestions={aiSuggestions}
395
+ handlerAiGeneration={handlerAiGeneration}
396
+ handlerRegenerateSuggestions={handlerRegenerateSuggestions}
397
+ handleChangeSuggestion={handleChangeSuggestion}
126
398
  onChange={(e) => {
127
399
  setBoxOnboardingList((prev) => {
128
400
  return prev.map((box, i) => {
@@ -133,6 +405,7 @@ export const TagAndInput = ({
133
405
  });
134
406
  });
135
407
  }}
408
+
136
409
  />
137
410
  </Container>
138
411
  );
@@ -7,26 +7,55 @@ export const Container = styled.div`
7
7
 
8
8
  display: flex;
9
9
  align-items: center;
10
- gap: .5rem;
10
+ justify-content: space-between;
11
11
 
12
- .icon_information{
13
- width: 1.35rem;
14
- height: 1.35rem;
15
- filter: brightness(.35);
12
+ font-family: ${FontFamily.Raleway};
13
+
14
+ .titles{
15
+ display: flex;
16
+ gap: .5rem;
17
+ align-items: center;
16
18
  }
17
19
 
18
- .tooltip {
19
- display: none;
20
- position: absolute;
21
- background-color: ${GlobalColors.white};
22
- color: ${({ color }) => (color ? color : GlobalColors.s5)};
23
- font-family: ${FontFamily.Raleway};
24
- font-size: 14px;
25
- line-height: 19px;
26
- left: 0;
27
- top: 0;
28
- height: fit-content;
29
- transition: display 2s;
20
+ .icon_information{
21
+ width: 1.35rem;
22
+ height: 1.35rem;
23
+ filter: brightness(.35);
24
+ margin-top: 10px;
25
+ }
26
+
27
+ .tooltip {
28
+ display: none;
29
+ position: absolute;
30
+ background-color: ${GlobalColors.white};
31
+ color: ${({ color }) => (color ? color : GlobalColors.s5)};
32
+ font-size: 14px;
33
+ line-height: 19px;
34
+ left: 0;
35
+ top: 0;
36
+ height: fit-content;
37
+ transition: display 2s;
38
+ }
39
+
40
+ .ai-generated{
41
+
42
+ display: flex;
43
+ align-items: items-center;
44
+ gap: .5rem;
45
+ font-size: 11px;
46
+ background-color: rgba(224, 57, 167, 0.025);
47
+ border: 1px solid rgba(224, 57, 167, 0.1);
48
+ padding: .25rem .5rem;
49
+ border-radius: 5px;
50
+ margin-left: 0.5rem;
51
+ margin-top: 7px;
52
+ cursor: default;
53
+
54
+ > img {
55
+ width: 0.75rem;
56
+ height: 0.75rem;
57
+ }
58
+
30
59
  }
31
60
 
32
61
  &:hover {
@@ -34,6 +63,8 @@ export const Container = styled.div`
34
63
  display: block;
35
64
  }
36
65
  }
66
+
67
+
37
68
  }
38
69
 
39
70
  & > :first-child {
@@ -44,4 +75,15 @@ export const Container = styled.div`
44
75
  & + * {
45
76
  margin-top: ${({ inputType }) => (inputType !== "textarea" ? 0 : 10)}px;
46
77
  }
78
+
79
+ .error-message-container {
80
+
81
+ font-family: "Raleway";
82
+ font-size: 12px;
83
+ font-weight: 500;
84
+ color: #E1251B;
85
+ margin-bottom: 8px;
86
+ margin-top: 0;
87
+
88
+ }
47
89
  `;