contentoh-components-library 21.5.97 → 21.5.99

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 +54 -249
  3. package/dist/components/atoms/GeneralInput/styles.js +3 -7
  4. package/dist/components/atoms/InputFormatter/index.js +68 -223
  5. package/dist/components/atoms/InputFormatter/styles.js +4 -20
  6. package/dist/components/molecules/StatusAsignationInfo/index.js +1 -11
  7. package/dist/components/molecules/TabsMenu/index.js +1 -13
  8. package/dist/components/molecules/TagAndInput/index.js +24 -364
  9. package/dist/components/molecules/TagAndInput/styles.js +2 -2
  10. package/dist/components/organisms/FullProductNameHeader/index.js +22 -6
  11. package/dist/components/organisms/InputGroup/index.js +18 -22
  12. package/dist/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +337 -150
  13. package/dist/components/pages/ProviderProductEdition/context/provider-product-edition.context.js +15 -15
  14. package/dist/components/pages/ProviderProductEdition/index.js +376 -412
  15. package/dist/components/pages/ProviderProductEdition/utils.js +0 -1
  16. package/dist/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +211 -125
  17. package/dist/components/pages/RetailerProductEdition/index.js +2236 -1738
  18. package/dist/components/pages/RetailerProductEdition/styles.js +2 -4
  19. package/dist/components/pages/RetailerProductEdition/utils.js +2 -251
  20. package/package.json +2 -4
  21. package/src/components/atoms/GeneralButton/styles.js +0 -4
  22. package/src/components/atoms/GeneralInput/index.js +60 -241
  23. package/src/components/atoms/GeneralInput/styles.js +0 -81
  24. package/src/components/atoms/InputFormatter/index.js +51 -200
  25. package/src/components/atoms/InputFormatter/styles.js +0 -284
  26. package/src/components/molecules/StatusAsignationInfo/index.js +1 -9
  27. package/src/components/molecules/TabsMenu/index.js +0 -12
  28. package/src/components/molecules/TagAndInput/index.js +21 -294
  29. package/src/components/molecules/TagAndInput/styles.js +17 -59
  30. package/src/components/organisms/FullProductNameHeader/index.js +28 -4
  31. package/src/components/organisms/FullTabsMenu/index.js +1 -1
  32. package/src/components/organisms/InputGroup/index.js +4 -12
  33. package/src/components/pages/ProviderProductEdition/ProviderProductEdition.stories.js +202 -174
  34. package/src/components/pages/ProviderProductEdition/context/provider-product-edition.context.jsx +14 -14
  35. package/src/components/pages/ProviderProductEdition/index.js +420 -494
  36. package/src/components/pages/ProviderProductEdition/utils.js +2 -2
  37. package/src/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +243 -136
  38. package/src/components/pages/RetailerProductEdition/index.js +1717 -1563
  39. package/src/components/pages/RetailerProductEdition/styles.js +2 -67
  40. package/src/components/pages/RetailerProductEdition/utils.js +0 -240
  41. package/src/ai/utils/compare-strings.js +0 -45
  42. package/src/assets/images/Icons/arrow.png +0 -0
  43. package/src/assets/images/Icons/cancel.png +0 -0
  44. package/src/assets/images/Icons/ia-icon.png +0 -0
  45. package/src/assets/images/Icons/loading.svg +0 -5
  46. package/src/assets/images/Icons/reload.png +0 -0
  47. package/src/components/atoms/RetailerSelector/RetailerSelector.stories.js +0 -10
  48. package/src/components/atoms/RetailerSelector/index.js +0 -3
  49. package/src/components/atoms/RetailerSelector/styles.js +0 -0
  50. package/src/components/organisms/ChangeStatusModal/index.jsx +0 -488
  51. package/src/components/organisms/ChangeStatusModal/styles.js +0 -333
  52. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.context.jsx +0 -575
  53. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.reducer.js +0 -62
  54. package/src/components/pages/RetailerProductEdition/context/reducers/active-state.js +0 -344
  55. package/src/components/pages/RetailerProductEdition/context/reducers/inputs.js +0 -155
  56. package/src/components/pages/RetailerProductEdition/context/reducers/product.js +0 -114
  57. package/src/components/pages/RetailerProductEdition/context/reducers/system.js +0 -60
  58. package/src/components/pages/RetailerProductEdition/index_old.js +0 -1979
  59. package/src/components/pages/RetailerProductEdition/stories/Auditor.stories.js +0 -101
  60. package/src/components/pages/RetailerProductEdition/stories/ImageEditor.stories.js +0 -115
  61. package/src/components/pages/RetailerProductEdition/stories/TextEditor.stories.js +0 -174
  62. package/src/contexts/AiProductEdition.jsx +0 -347
  63. package/src/global-files/statusDictionary.js +0 -103
@@ -7,11 +7,6 @@ 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
-
15
10
  export const TagAndInput = ({
16
11
  inputType,
17
12
  label,
@@ -31,7 +26,6 @@ export const TagAndInput = ({
31
26
  inputRows,
32
27
  maxChar,
33
28
  required,
34
- aiGenerated,
35
29
  optionList,
36
30
  description,
37
31
  inputOnChange,
@@ -49,188 +43,6 @@ export const TagAndInput = ({
49
43
  boxOnboardingData || []
50
44
  );
51
45
 
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
-
234
46
  useEffect(() => {
235
47
  const temp = {};
236
48
  let maxBoxId = 0;
@@ -251,64 +63,10 @@ export const TagAndInput = ({
251
63
  );
252
64
  }
253
65
  }, []);
254
-
255
66
  useEffect(() => {
256
67
  onChange && onChange(boxOnboardingList);
257
68
  }, [boxOnboardingList]);
258
69
 
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
-
312
70
  return (
313
71
  <Container
314
72
  inputType={inputType}
@@ -317,45 +75,28 @@ export const TagAndInput = ({
317
75
  >
318
76
  {label?.length && (
319
77
  <div className="title-container">
320
- <div className="titles">
321
- <ScreenHeader
322
- text={label}
323
- headerType={"input-name-header"}
324
- color={color}
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"}
325
98
  />
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>
99
+ )}
359
100
  </div>
360
101
  )}
361
102
  <GeneralInput
@@ -382,19 +123,6 @@ export const TagAndInput = ({
382
123
  inputOnChange={inputOnChange}
383
124
  onKeyDown={onKeyDown}
384
125
  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}
398
126
  onChange={(e) => {
399
127
  setBoxOnboardingList((prev) => {
400
128
  return prev.map((box, i) => {
@@ -405,7 +133,6 @@ export const TagAndInput = ({
405
133
  });
406
134
  });
407
135
  }}
408
-
409
136
  />
410
137
  </Container>
411
138
  );
@@ -7,55 +7,26 @@ export const Container = styled.div`
7
7
 
8
8
  display: flex;
9
9
  align-items: center;
10
- justify-content: space-between;
10
+ gap: .5rem;
11
11
 
12
- font-family: ${FontFamily.Raleway};
13
-
14
- .titles{
15
- display: flex;
16
- gap: .5rem;
17
- align-items: center;
12
+ .icon_information{
13
+ width: 1.35rem;
14
+ height: 1.35rem;
15
+ filter: brightness(.35);
18
16
  }
19
17
 
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
-
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;
59
30
  }
60
31
 
61
32
  &:hover {
@@ -63,8 +34,6 @@ export const Container = styled.div`
63
34
  display: block;
64
35
  }
65
36
  }
66
-
67
-
68
37
  }
69
38
 
70
39
  & > :first-child {
@@ -75,15 +44,4 @@ export const Container = styled.div`
75
44
  & + * {
76
45
  margin-top: ${({ inputType }) => (inputType !== "textarea" ? 0 : 10)}px;
77
46
  }
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
- }
89
47
  `;
@@ -27,15 +27,39 @@ export const FullProductNameHeader = ({
27
27
  const [retailerIndex, setRetailerIndex] = useState(null);
28
28
 
29
29
  useEffect(() => {
30
- const ifFromTasks = headerData.statusByRetailer ? true : false;
30
+ // necesitamos definir los retailers que se deberan de mostrar en el selecto de retailers
31
+ // Si se viene desde la vista de productos se deben usar los de categoryRetailer
32
+ // Si se vene desde la vista de tareas entonces se debe trabajar con los retailers que esten en statusByRetailer
33
+
34
+ const ifFromTasks = headerData.statusByRetailer;
31
35
  const categoryRetailer =
32
36
  headerData.categoryRetailer || headerData.article.categoryRetailer;
33
37
 
38
+ const categoryRetailerNormalized = categoryRetailer
39
+ ? categoryRetailer.map((rel) => ({
40
+ id_retailer: rel.id_retailer || rel.retailer_id,
41
+ retailer: rel.retailer_name || rel.retailerName || rel.retailer,
42
+ name: rel.retailer_name || rel.retailerName || rel.retailer,
43
+ id_category: rel.id_category,
44
+ category: rel.category_name || rel.categoryName || rel.category,
45
+ image: `https://content-management-images.s3.amazonaws.com/retailers/${
46
+ rel.id_retailer || rel.retailer_id
47
+ }.png`,
48
+ }))
49
+ : null;
50
+
51
+ const retailersIdsFromStatusByRetailer = Object.keys(
52
+ headerData.statusByRetailer || {}
53
+ ).map((id) => parseInt(id, 10));
54
+
34
55
  if (ifFromTasks) {
35
- setRetailers(headerData.categoryRetailerInOrder);
56
+ const categoryRetailerInOrder = categoryRetailerNormalized.filter((rel) =>
57
+ retailersIdsFromStatusByRetailer.includes(rel.id_retailer)
58
+ );
59
+
60
+ setRetailers(categoryRetailerInOrder);
36
61
  } else {
37
- console.log({ categoryRetailer });
38
- setRetailers(categoryRetailer);
62
+ setRetailers(categoryRetailerNormalized);
39
63
  }
40
64
  }, [servicesData]);
41
65
 
@@ -1,7 +1,7 @@
1
1
  import { Container } from "./styles";
2
2
  import { TabsMenu } from "../../molecules/TabsMenu/index";
3
3
  import { StatusAsignationInfo } from "../../molecules/StatusAsignationInfo/index";
4
- import { useEffect, useState } from "react";
4
+ import { useState } from "react";
5
5
 
6
6
  export const FullTabsMenu = ({
7
7
  tabsSections,
@@ -179,7 +179,7 @@ export const InputGroup = ({
179
179
  ? "inputs-validation-onboarding"
180
180
  : "inputs-validation"
181
181
  }>
182
- {dataInputs[input]?.isApproved === false && (
182
+ {dataInputs[input]?.isApproved === false && (
183
183
  <InputReviewSection
184
184
  inputId={dataInputs[input]?.id}
185
185
  isApproved={dataInputs[input]?.isApproved}
@@ -219,7 +219,6 @@ export const InputGroup = ({
219
219
  inputPlaceHolder={input?.placeholder}
220
220
  articleId={articleId}
221
221
  isRequired={dataInputs[input]?.required}
222
- aiGenerated={dataInputs[input]?.ai_generated}
223
222
  updatedDatasheets={updatedDatasheets}
224
223
  setUpdatedDatasheets={setUpdatedDatasheets}
225
224
  maxChar={
@@ -278,7 +277,6 @@ export const InputGroup = ({
278
277
  : input?.value
279
278
  }
280
279
  isRequired={input.required}
281
- aiGenerated={input?.ai_generated}
282
280
  disabled={input.id===44186||input.id===44187?false:input?.isApproved}
283
281
  maxChar={input.max_chars}
284
282
  inputPlaceHolder={input?.placeholder}
@@ -343,18 +341,13 @@ export const InputGroup = ({
343
341
  (dataInputs[input]?.required ? "*" : "")
344
342
  }
345
343
  value={
346
- dataInputs[input]?.box ? (
347
- Object.values(dataInputs[input]?.box)[0]
348
- ) : (
349
- compare
350
- ? auditInputs[input]?.value
351
- : dataInputs[input]?.value
352
- )
344
+ compare
345
+ ? auditInputs[input]?.value
346
+ : dataInputs[input]?.value
353
347
  }
354
348
  inputPlaceHolder={input?.placeholder}
355
349
  articleId={articleId}
356
350
  isRequired={dataInputs[input]?.required}
357
- aiGenerated={dataInputs[input]?.ai_generated}
358
351
  updatedDatasheets={updatedDatasheets}
359
352
  setUpdatedDatasheets={setUpdatedDatasheets}
360
353
  maxChar={
@@ -416,7 +409,6 @@ export const InputGroup = ({
416
409
  : input?.value
417
410
  }
418
411
  isRequired={input.required}
419
- aiGenerated={input?.ai_generated}
420
412
  maxChar={input.max_chars}
421
413
  inputPlaceHolder={input?.placeholder}
422
414
  updatedDescriptions={updatedDescriptions}