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.
Files changed (70) hide show
  1. package/dist/ai/utils/compare-strings.js +45 -0
  2. package/dist/components/atoms/GeneralButton/styles.js +1 -1
  3. package/dist/components/atoms/GeneralInput/index.js +245 -54
  4. package/dist/components/atoms/GeneralInput/styles.js +7 -3
  5. package/dist/components/atoms/InputFormatter/index.js +223 -68
  6. package/dist/components/atoms/InputFormatter/styles.js +20 -4
  7. package/dist/components/molecules/StatusAsignationInfo/index.js +11 -1
  8. package/dist/components/molecules/TabsMenu/index.js +13 -12
  9. package/dist/components/molecules/TagAndInput/index.js +361 -24
  10. package/dist/components/molecules/TagAndInput/styles.js +2 -2
  11. package/dist/components/organisms/ChangeStatusModal/index.js +531 -0
  12. package/dist/components/organisms/ChangeStatusModal/styles.js +85 -0
  13. package/dist/components/organisms/FullProductNameHeader/index.js +6 -22
  14. package/dist/components/organisms/InputGroup/index.js +22 -18
  15. package/dist/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +150 -337
  16. package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.context.js +15 -15
  17. package/dist/components/pages/ProviderProductEdition/index.js +413 -396
  18. package/dist/components/pages/ProviderProductEdition/utils.js +1 -0
  19. package/dist/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +179 -196
  20. package/dist/components/pages/RetailerProductEdition/context/provider-product-edition.context.js +59 -260
  21. package/dist/components/pages/RetailerProductEdition/context/reducers/product.js +50 -38
  22. package/dist/components/pages/RetailerProductEdition/index.js +1719 -2237
  23. package/dist/components/pages/RetailerProductEdition/styles.js +4 -2
  24. package/dist/components/pages/RetailerProductEdition/utils.js +251 -2
  25. package/dist/contexts/AiProductEdition.js +230 -158
  26. package/dist/global-files/statusDictionary.js +103 -0
  27. package/package.json +4 -2
  28. package/src/ai/utils/compare-strings.js +45 -0
  29. package/src/assets/images/Icons/arrow.png +0 -0
  30. package/src/assets/images/Icons/cancel.png +0 -0
  31. package/src/assets/images/Icons/ia-icon.png +0 -0
  32. package/src/assets/images/Icons/loading.svg +5 -0
  33. package/src/assets/images/Icons/reload.png +0 -0
  34. package/src/components/atoms/GeneralButton/styles.js +4 -0
  35. package/src/components/atoms/GeneralInput/index.js +237 -60
  36. package/src/components/atoms/GeneralInput/styles.js +81 -0
  37. package/src/components/atoms/InputFormatter/index.js +200 -51
  38. package/src/components/atoms/InputFormatter/styles.js +284 -0
  39. package/src/components/atoms/RetailerSelector/RetailerSelector.stories.js +10 -0
  40. package/src/components/atoms/RetailerSelector/index.js +3 -0
  41. package/src/components/atoms/RetailerSelector/styles.js +0 -0
  42. package/src/components/molecules/StatusAsignationInfo/index.js +9 -1
  43. package/src/components/molecules/TabsMenu/index.js +12 -11
  44. package/src/components/molecules/TagAndInput/index.js +286 -21
  45. package/src/components/molecules/TagAndInput/styles.js +59 -17
  46. package/src/components/organisms/ChangeStatusModal/index.jsx +488 -0
  47. package/src/components/organisms/ChangeStatusModal/styles.js +333 -0
  48. package/src/components/organisms/FullProductNameHeader/index.js +4 -28
  49. package/src/components/organisms/FullTabsMenu/index.js +1 -1
  50. package/src/components/organisms/InputGroup/index.js +12 -4
  51. package/src/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +174 -202
  52. package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx +14 -14
  53. package/src/components/pages/ProviderProductEdition/index.js +496 -475
  54. package/src/components/pages/ProviderProductEdition/utils.js +2 -2
  55. package/src/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +201 -224
  56. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.context.jsx +575 -0
  57. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.reducer.js +62 -0
  58. package/src/components/pages/RetailerProductEdition/context/reducers/active-state.js +344 -0
  59. package/src/components/pages/RetailerProductEdition/context/reducers/inputs.js +155 -0
  60. package/src/components/pages/RetailerProductEdition/context/reducers/product.js +114 -0
  61. package/src/components/pages/RetailerProductEdition/context/reducers/system.js +60 -0
  62. package/src/components/pages/RetailerProductEdition/index.js +1545 -1718
  63. package/src/components/pages/RetailerProductEdition/index_old.js +1979 -0
  64. package/src/components/pages/RetailerProductEdition/stories/Auditor.stories.js +101 -0
  65. package/src/components/pages/RetailerProductEdition/stories/ImageEditor.stories.js +115 -0
  66. package/src/components/pages/RetailerProductEdition/stories/TextEditor.stories.js +174 -0
  67. package/src/components/pages/RetailerProductEdition/styles.js +67 -2
  68. package/src/components/pages/RetailerProductEdition/utils.js +240 -0
  69. package/src/contexts/AiProductEdition.jsx +339 -0
  70. 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,56 @@ 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
+ const currentDescriptionUpdate = Array.isArray(updatedDescriptions)
261
+ ? updatedDescriptions.find(desc => desc?.attributeId === inputId)
262
+ : null;
263
+
264
+ const currentDatasheetUpdate = Array.isArray(updatedDatasheets)
265
+ ? updatedDatasheets.find(data => data?.attributeId === inputId)
266
+ : null;
267
+
268
+ let calculatedIsAiGenerated = aiGenerated;
269
+
270
+ if (currentDescriptionUpdate) {
271
+ calculatedIsAiGenerated = currentDescriptionUpdate.aiSuggestionAccepted;
272
+ } else if (currentDatasheetUpdate) {
273
+ calculatedIsAiGenerated = currentDatasheetUpdate.aiSuggestionAccepted;
274
+ }
275
+
276
+ setInputsGeneratedWithAi(prev => ({
277
+ ...prev,
278
+ [`${inputId}-${inputType}-${version}`]: {
279
+ inputType,
280
+ inputId,
281
+ version,
282
+ isAiGenerated: !!calculatedIsAiGenerated,
283
+ label
284
+ }
285
+ }));
286
+
287
+ }, [updatedDescriptions, updatedDatasheets, aiGenerated, inputId]);
288
+
289
+ useEffect(() => {
290
+ setIsAiGenerated(!!inputsGeneratedWithAi[`${inputId}-${inputType}-${version}`]?.isAiGenerated);
291
+ }, [inputsGeneratedWithAi]);
292
+
293
+ useEffect(() => {
294
+
295
+ setInputsUsingAi(prev => ({
296
+ ...prev,
297
+ [`${inputId}-${inputType}-${version}`]: {
298
+ using: isAiActive
299
+ }
300
+ }))
301
+
302
+ }, [isAiActive])
303
+
70
304
  return (
71
305
  <Container
72
306
  inputType={inputType}
@@ -75,28 +309,45 @@ export const TagAndInput = ({
75
309
  >
76
310
  {label?.length && (
77
311
  <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"}
312
+ <div className="titles">
313
+ <ScreenHeader
314
+ text={label}
315
+ headerType={"input-name-header"}
316
+ color={color}
98
317
  />
99
- )}
318
+ {description && (
319
+ <Tooltip
320
+ componentTooltip={
321
+ <>
322
+ <p>{description}</p>
323
+ </>
324
+ }
325
+ children={
326
+ <img
327
+ src={InfoIcon}
328
+ alt="info icon"
329
+ className={'icon_information'}
330
+ />
331
+ }
332
+ classNameTooltip={"container-tooltip"}
333
+ />
334
+ )}
335
+ </div>
336
+ {
337
+ isCreators && isAiGenerated ? (
338
+ <div className="ai-generated">
339
+ <img src={AiGenerationIcon} />
340
+ <p>Atributo generado con IA</p>
341
+ </div>
342
+ ) : null
343
+ }
344
+ </div>
345
+ )}
346
+ {errorMessage && (
347
+ <div
348
+ className="error-message-container"
349
+ >
350
+ <p>{errorMessage}</p>
100
351
  </div>
101
352
  )}
102
353
  <GeneralInput
@@ -123,6 +374,19 @@ export const TagAndInput = ({
123
374
  inputOnChange={inputOnChange}
124
375
  onKeyDown={onKeyDown}
125
376
  auditClass={auditClass}
377
+ // AI Generation
378
+ hasAiGeneration={isCreators}
379
+ isBenefitInput={isBenefitInput}
380
+ isAiGenerationLoading={isAiGenerationLoading}
381
+ isAiRegenerationLoading={isAiRegenerationLoading}
382
+ isAiActive={isAiActive}
383
+ setIsAiActive={setIsAiActive}
384
+ isAiAvailable={isAiAvailable}
385
+ aiGenerated={aiGenerated}
386
+ // aiSuggestions={aiSuggestions}
387
+ handlerAiGeneration={handlerAiGeneration}
388
+ handlerRegenerateSuggestions={handlerRegenerateSuggestions}
389
+ handleChangeSuggestion={handleChangeSuggestion}
126
390
  onChange={(e) => {
127
391
  setBoxOnboardingList((prev) => {
128
392
  return prev.map((box, i) => {
@@ -133,6 +397,7 @@ export const TagAndInput = ({
133
397
  });
134
398
  });
135
399
  }}
400
+
136
401
  />
137
402
  </Container>
138
403
  );
@@ -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
  `;