contentoh-components-library 21.5.91 → 21.5.93

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 (66) hide show
  1. package/dist/components/atoms/GeneralButton/styles.js +1 -1
  2. package/dist/components/atoms/GeneralInput/index.js +54 -245
  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 +12 -13
  8. package/dist/components/molecules/TagAndInput/index.js +24 -361
  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/index.js +47 -34
  13. package/dist/components/pages/ProviderProductEdition/utils.js +0 -1
  14. package/dist/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +196 -179
  15. package/dist/components/pages/RetailerProductEdition/context/provider-product-edition.context.js +260 -59
  16. package/dist/components/pages/RetailerProductEdition/context/reducers/product.js +38 -50
  17. package/dist/components/pages/RetailerProductEdition/index.js +2234 -1715
  18. package/dist/components/pages/RetailerProductEdition/styles.js +2 -4
  19. package/dist/components/pages/RetailerProductEdition/utils.js +2 -251
  20. package/dist/contexts/AiProductEdition.js +157 -234
  21. package/package.json +2 -4
  22. package/src/components/atoms/GeneralButton/styles.js +0 -4
  23. package/src/components/atoms/GeneralInput/index.js +60 -237
  24. package/src/components/atoms/GeneralInput/styles.js +0 -81
  25. package/src/components/atoms/InputFormatter/index.js +51 -200
  26. package/src/components/atoms/InputFormatter/styles.js +0 -284
  27. package/src/components/molecules/StatusAsignationInfo/index.js +1 -9
  28. package/src/components/molecules/TabsMenu/index.js +11 -12
  29. package/src/components/molecules/TagAndInput/index.js +21 -286
  30. package/src/components/molecules/TagAndInput/styles.js +17 -59
  31. package/src/components/organisms/FullProductNameHeader/index.js +28 -4
  32. package/src/components/organisms/FullTabsMenu/index.js +1 -1
  33. package/src/components/organisms/InputGroup/index.js +4 -12
  34. package/src/components/pages/ProviderProductEdition/index.js +69 -51
  35. package/src/components/pages/ProviderProductEdition/utils.js +2 -2
  36. package/src/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +224 -201
  37. package/src/components/pages/RetailerProductEdition/index.js +1718 -1546
  38. package/src/components/pages/RetailerProductEdition/styles.js +2 -67
  39. package/src/components/pages/RetailerProductEdition/utils.js +0 -240
  40. package/dist/ai/utils/compare-strings.js +0 -45
  41. package/dist/components/organisms/ChangeStatusModal/index.js +0 -531
  42. package/dist/components/organisms/ChangeStatusModal/styles.js +0 -85
  43. package/dist/global-files/statusDictionary.js +0 -103
  44. package/src/ai/utils/compare-strings.js +0 -45
  45. package/src/assets/images/Icons/arrow.png +0 -0
  46. package/src/assets/images/Icons/cancel.png +0 -0
  47. package/src/assets/images/Icons/ia-icon.png +0 -0
  48. package/src/assets/images/Icons/loading.svg +0 -5
  49. package/src/assets/images/Icons/reload.png +0 -0
  50. package/src/components/atoms/RetailerSelector/RetailerSelector.stories.js +0 -10
  51. package/src/components/atoms/RetailerSelector/index.js +0 -3
  52. package/src/components/atoms/RetailerSelector/styles.js +0 -0
  53. package/src/components/organisms/ChangeStatusModal/index.jsx +0 -488
  54. package/src/components/organisms/ChangeStatusModal/styles.js +0 -333
  55. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.context.jsx +0 -575
  56. package/src/components/pages/RetailerProductEdition/context/provider-product-edition.reducer.js +0 -62
  57. package/src/components/pages/RetailerProductEdition/context/reducers/active-state.js +0 -344
  58. package/src/components/pages/RetailerProductEdition/context/reducers/inputs.js +0 -155
  59. package/src/components/pages/RetailerProductEdition/context/reducers/product.js +0 -114
  60. package/src/components/pages/RetailerProductEdition/context/reducers/system.js +0 -60
  61. package/src/components/pages/RetailerProductEdition/index_old.js +0 -1979
  62. package/src/components/pages/RetailerProductEdition/stories/Auditor.stories.js +0 -101
  63. package/src/components/pages/RetailerProductEdition/stories/ImageEditor.stories.js +0 -115
  64. package/src/components/pages/RetailerProductEdition/stories/TextEditor.stories.js +0 -174
  65. package/src/contexts/AiProductEdition.jsx +0 -344
  66. package/src/global-files/statusDictionary.js +0 -103
@@ -1,17 +1,7 @@
1
1
  import ReactQuill from "react-quill";
2
2
  import "react-quill/dist/quill.snow.css";
3
- import { useEffect, useState } from "react";
4
- import { ButtonsContainer, Container, InputContainer, OptionsContainer, BottomContainer } from "./styles";
5
-
6
- import AiGenerationIcon from "../../../assets/images/Icons/ia-icon.png";
7
- import ArrowIcon from "../../../assets/images/Icons/arrow.png";
8
- import LoadingIcon from "../../../assets/images/Icons/loading.svg";
9
- import CancelIcon from "../../../assets/images/Icons/cancel.png";
10
- import ReloadIcon from "../../../assets/images/Icons/reload.png";
11
-
12
- import { useAiProductEdition } from "../../../contexts/AiProductEdition";
13
-
14
- import { getTextSimilarityPercentage } from "../../../ai/utils/compare-strings";
3
+ import { useState } from "react";
4
+ import { Container } from "./styles";
15
5
 
16
6
  export const InputFormatter = ({
17
7
  mainValue = "",
@@ -22,29 +12,7 @@ export const InputFormatter = ({
22
12
  isRequired,
23
13
  maxChar,
24
14
  disabled,
25
-
26
- //AI Generation
27
- hasAiGeneration = false,
28
- isAiGenerationLoading = false,
29
- isAiRegenerationLoading=false,
30
- isAiActive = false,
31
- isAiAvailable = false,
32
- aiGenerated = false,
33
-
34
- setIsAiActive = () => {},
35
- handlerAiGeneration = () => {},
36
- handlerRegenerateSuggestions = () => {},
37
- handleChangeSuggestion = () => {}
38
15
  }) => {
39
-
40
- const {
41
- suggestions,
42
- currentSuggestion
43
- } = useAiProductEdition();
44
-
45
- const [aiSuggestionAccepted, setAiSuggestionAccepted] = useState(false);
46
- const [valueAccepted, setValueAccepted] = useState(mainValue);
47
-
48
16
  const [inputValue, setInputValue] = useState(mainValue);
49
17
  const [selection, setSelection] = useState(false);
50
18
  const [position, setPosition] = useState({ left: 0, top: 0 });
@@ -99,49 +67,32 @@ export const InputFormatter = ({
99
67
  setCharsCounter(h.getLength() - 1);
100
68
  value = valueFormater(value);
101
69
 
102
- updateParentDescriptions(value, aiSuggestionAccepted);
103
- };
104
-
105
- const updateParentDescriptions = (finalValue, isAiAccepted) => {
106
- if (!updatedDescriptions) return;
107
-
108
- let idInput = inputId;
109
- let dataSave = updatedDescriptions?.slice();
110
-
111
- const similarity = getTextSimilarityPercentage(valueAccepted, inputValue);
112
-
113
- const generatedWithAi = (isAiAccepted) || aiGenerated && similarity >= 50;
114
-
115
- if (dataSave?.length > 0) {
116
- const index = dataSave.findIndex((e) => e.attributeId === idInput);
117
- if (index !== -1) {
118
- if (finalValue !== mainValue) {
119
- dataSave[index].value = finalValue;
120
- dataSave[index].aiSuggestionAccepted = generatedWithAi;
70
+ if (updatedDescriptions) {
71
+ let idInput = inputId;
72
+ let dataSave = updatedDescriptions?.slice();
73
+ if (dataSave?.length > 0) {
74
+ const index = dataSave.findIndex((e) => e.attributeId === idInput);
75
+ if (index !== -1) {
76
+ if (value !== mainValue) dataSave[index].value = value;
77
+ else dataSave.splice(index, 1);
121
78
  } else {
122
- dataSave.splice(index, 1);
79
+ dataSave.push({
80
+ articleId: articleId,
81
+ attributeId: idInput,
82
+ value: value,
83
+ });
123
84
  }
124
85
  } else {
125
- if (finalValue !== mainValue) {
86
+ if (value !== mainValue) {
126
87
  dataSave.push({
127
88
  articleId: articleId,
128
89
  attributeId: idInput,
129
- value: finalValue,
130
- aiSuggestionAccepted: generatedWithAi,
90
+ value: value,
131
91
  });
132
92
  }
133
93
  }
134
- } else {
135
- if (finalValue !== mainValue) {
136
- dataSave.push({
137
- articleId: articleId,
138
- attributeId: idInput,
139
- value: finalValue,
140
- aiSuggestionAccepted: generatedWithAi,
141
- });
142
- }
94
+ setUpdatedDescriptions(dataSave);
143
95
  }
144
- setUpdatedDescriptions(dataSave);
145
96
  };
146
97
 
147
98
  const getSelection = (range, a, b) => {
@@ -154,41 +105,6 @@ export const InputFormatter = ({
154
105
  }
155
106
  };
156
107
 
157
- //AI Generation
158
- const handleAcceptSuggestion = (suggestionValue) => {
159
- if (!suggestionValue) return;
160
-
161
- setInputValue(suggestionValue);
162
- setValueAccepted(suggestionValue);
163
- setAiSuggestionAccepted(true);
164
- setIsAiActive(false);
165
-
166
- // Formateamos el valor sugerido igual que en el onChange
167
- const formattedSuggestion = valueFormater(suggestionValue);
168
-
169
- // Disparamos la actualización enviando "true" directamente
170
- updateParentDescriptions(formattedSuggestion, true);
171
- };
172
-
173
- useEffect(() => {
174
-
175
- // Comprueba cuando la función de IA se cierra y no se acepto una sugerencia
176
- // Devuelve el valor inicial
177
- if(!isAiActive && !aiSuggestionAccepted) return setInputValue(valueAccepted);
178
-
179
- }, [suggestions, isAiActive]);
180
-
181
- useEffect(() => {
182
-
183
- if(!isAiActive) return;
184
-
185
- // Comprueba si la sugerencia fue aceptada
186
- setAiSuggestionAccepted(false);
187
-
188
- }, [isAiActive]);
189
-
190
- //End Ai Generation
191
-
192
108
  return (
193
109
  <Container
194
110
  isRequired={
@@ -198,104 +114,39 @@ export const InputFormatter = ({
198
114
  selection={selection}
199
115
  position={position}
200
116
  >
201
- <InputContainer className={hasAiGeneration ? "ai-generation" : ""}>
202
- {
203
- <ReactQuill
204
- id={inputId + ""}
205
- ref={(el) => setQuill(el)}
206
- value={isAiActive ? (
207
- currentSuggestion?.[inputId]?.value
208
- ) : getValue(inputValue)}
209
- readOnly={isAiActive || disabled}
210
- modules={{
211
- toolbar: false,
212
- }}
213
- onKeyPress={(e) => {
214
- if (charsCounter >= maxLength && e.key !== "Backspace") {
215
- e.preventDefault();
216
- }
217
- }}
218
- onKeyDown={(e) => {
219
- let keysArray = [
220
- "Backspace",
221
- "Meta",
222
- "ArrowLeft",
223
- "ArrowRight",
224
- "ArrowUp",
225
- "ArrowDown",
226
- ];
227
- if (
228
- charsCounter >= maxLength &&
229
- keysArray.every((key) => e.key !== key)
230
- ) {
231
- e.preventDefault();
232
- }
233
- }}
234
- onChange={(valueInput, user, range, h) => onChange(valueInput, h)}
235
- onChangeSelection={getSelection}
236
- className={`quill ${hasAiGeneration && "has-ai"} ${isAiActive && "ai-generation"}`}
237
- />
238
- }
239
- {
240
- hasAiGeneration && (
241
- <div className={`icon_container ${isAiActive ? "ai-active" : ''} ${isAiAvailable ? "ai-available" : ''}`} title={!isAiAvailable ? 'Debes de completar ficha técnica e imágenes para desbloquear la generación con IA' : ''} onClick={handlerAiGeneration}>
242
- <img className={isAiGenerationLoading ? "loading" : ""} src={isAiGenerationLoading ? LoadingIcon : isAiActive ? CancelIcon : AiGenerationIcon} />
243
- </div>
244
- )
245
- }
246
- </InputContainer>
247
- <BottomContainer className={isAiActive ? "with-ai" : ""}>
248
- {
249
- isAiActive && (
250
- <div className="ai-options">
251
-
252
- <OptionsContainer>
253
- <div className={
254
- `arrow ${currentSuggestion?.[inputId]?.index === 0 && "disabled"}`
255
- } onClick={() => {
256
- handleChangeSuggestion({ action: "prev" })
257
- }}>
258
- <img src={ArrowIcon} alt="" />
259
- </div>
260
- <p>
261
- {(currentSuggestion?.[inputId]?.index + 1) || 1}
262
- /
263
- {suggestions?.[inputId]?.length}
264
- </p>
265
- <div className={`arrow right ${currentSuggestion?.[inputId]?.index === suggestions?.[inputId]?.length - 1 && "disabled"}`} onClick={() => {
266
-
267
- }}>
268
- <img onClick={() => {
269
- handleChangeSuggestion({ action: "next" })
270
- }} src={ArrowIcon} alt="ai icon" />
271
- </div>
272
- </OptionsContainer>
273
-
274
- <ButtonsContainer>
275
-
276
- <div className={`reload-suggestions ${isAiRegenerationLoading && "loading"}`} onClick={() => {
277
- handlerRegenerateSuggestions({
278
- type: "description"
279
- });
280
- }}>
281
- <img className="" src={isAiRegenerationLoading ? LoadingIcon : ReloadIcon} />
282
- </div>
283
-
284
- <div className="accept-suggestion" onClick={() => {
285
- handleAcceptSuggestion(currentSuggestion?.[inputId]?.value);
286
- }}>
287
- <p>Aceptar sugerencia</p>
288
- </div>
289
-
290
- </ButtonsContainer>
291
-
292
- </div>
293
- )
294
- }
295
- <p className="description-limit">
296
- {charsCounter}/{maxLength}
297
- </p>
298
- </BottomContainer>
117
+ <ReactQuill
118
+ id={inputId + ""}
119
+ ref={(el) => setQuill(el)}
120
+ defaultValue={getValue(inputValue)}
121
+ readOnly={disabled}
122
+ modules={{ toolbar: ["bold"] }}
123
+ onKeyPress={(e) => {
124
+ if (charsCounter >= maxLength && e.key !== "Backspace") {
125
+ e.preventDefault();
126
+ }
127
+ }}
128
+ onKeyDown={(e) => {
129
+ let keysArray = [
130
+ "Backspace",
131
+ "Meta",
132
+ "ArrowLeft",
133
+ "ArrowRight",
134
+ "ArrowUp",
135
+ "ArrowDown",
136
+ ];
137
+ if (
138
+ charsCounter >= maxLength &&
139
+ keysArray.every((key) => e.key !== key)
140
+ ) {
141
+ e.preventDefault();
142
+ }
143
+ }}
144
+ onChange={(valueInput, user, range, h) => onChange(valueInput, h)}
145
+ onChangeSelection={getSelection}
146
+ />
147
+ <p className="description-limit">
148
+ {charsCounter}/{maxLength}
149
+ </p>
299
150
  </Container>
300
151
  );
301
152
  };
@@ -10,24 +10,6 @@ export const Container = styled.div`
10
10
  position: relative;
11
11
  border-radius: 5px;
12
12
 
13
- &.has-ai {
14
- .ql-container {
15
- padding-right: 2.5rem;
16
- }
17
- }
18
-
19
- &.ai-generation {
20
-
21
- .ql-container {
22
- border: 1px solid #3F8AED;
23
- border-radius: 5px;
24
- background-color: rgba(59, 147, 224, 0.05);
25
- margin: 5px;
26
- margin-right: 2.5rem;
27
- }
28
-
29
- }
30
-
31
13
  .ql-toolbar {
32
14
  background-color: ${GlobalColors.s2};
33
15
  position: absolute;
@@ -62,269 +44,3 @@ export const Container = styled.div`
62
44
  margin-top: 5px;
63
45
  }
64
46
  `;
65
- export const InputContainer = styled.div`
66
-
67
- &.ai-generation {
68
-
69
- position: relative;
70
-
71
- > input[type=text] {
72
- padding-right: 2.5rem;
73
- }
74
-
75
- > input[type=text].ia-input {
76
- background-color: rgba(59, 147, 224, 0.05);
77
- border: 1px solid #3F8AED;
78
- }
79
-
80
- .icon_container {
81
- position: absolute;
82
- right: 10px;
83
- top: 7px;
84
- width: 22.5px;
85
- height: 22.5px;
86
- padding: 4px;
87
-
88
- cursor: not-allowed;
89
-
90
- border-radius: 50%;
91
- overflow: hidden;
92
- display: flex;
93
- align-items: center;
94
- justify-content: center;
95
- z-index: 1;
96
-
97
- &::before {
98
- content: '';
99
- position: absolute;
100
- top: 0;
101
- left: 0;
102
- width: 100%;
103
- height: 100%;
104
-
105
- background: gray;
106
- background-size: 200% 200%;
107
-
108
- animation: ai-shimmer 3s ease-in-out infinite alternate;
109
- z-index: -1;
110
- }
111
-
112
- &.ai-available {
113
- cursor: pointer;
114
- }
115
-
116
- &.ai-available::before{
117
- background: linear-gradient(
118
- 120deg,
119
- #4285F4 20%,
120
- #33A3C8 50%,
121
- #4285F4 80%
122
- );
123
- background-size: 200% 200%;
124
- }
125
-
126
- &.ai-available::after {
127
- content: "";
128
- position: absolute;
129
- top: 0;
130
- left: 0;
131
- width: 100%;
132
- height: 100%;
133
- opacity: 0.75;
134
-
135
- background: linear-gradient(
136
- 135deg,
137
- rgba(255, 255, 255, 0) 0%,
138
- rgba(255, 255, 255, 0) 40%,
139
- rgba(255, 255, 255, 0.8) 50%,
140
- rgba(255, 255, 255, 0) 60%,
141
- rgba(255, 255, 255, 0) 100%
142
- );
143
-
144
- transform: scale(2) translate(-100%, -100%);
145
- z-index: 3;
146
-
147
- animation: ai-glint 3s infinite ease-in-out;
148
- }
149
-
150
- &.ai-available img.loading ~ ::after {
151
- animation: none;
152
- display: none;
153
- }
154
-
155
- &.ai-active::after {
156
- animation: none;
157
- display: none;
158
- }
159
-
160
- img {
161
- width: 100%;
162
- height: 100%;
163
- object-fit: contain;
164
- position: relative;
165
- z-index: 2;
166
- filter: invert(1) grayscale(1) brightness(2);
167
- }
168
-
169
- img.loading {
170
- width: 22.5px;
171
- height: 22.5px;
172
- }
173
-
174
- &.ai-active::before {
175
- background: oklch(57.7% 0.245 27.325);
176
- }
177
-
178
-
179
- }
180
- }
181
-
182
- @keyframes ai-shimmer {
183
- 0% {
184
- background-position: 0% 50%;
185
- }
186
- 100% {
187
- background-position: 100% 50%;
188
- }
189
- }
190
-
191
- @keyframes ai-glint {
192
- 0% {
193
- transform: scale(2) translate(-100%, -100%);
194
- }
195
- 70%, 100% {
196
- transform: scale(2) translate(100%, 100%);
197
- }
198
- }
199
-
200
- `;
201
- export const BottomContainer = styled.div`
202
-
203
- display: flex;
204
- align-items: center;
205
- padding-top: 5px;
206
- justify-content: flex-end;
207
-
208
- &.with-ai {
209
- justify-content: space-between;
210
- }
211
-
212
- > div.ai-options {
213
- display: flex;
214
- align-items: center;
215
- gap: 0.25rem;
216
- }
217
-
218
- `;
219
-
220
- export const OptionsContainer = styled.div`
221
-
222
- display: flex;
223
- align-items: center;
224
- gap: 0.25rem;
225
- user-select: none;
226
-
227
- p {
228
- font-size: 12px;
229
- font-family: ${FontFamily.AvenirNext};
230
- color: ${GlobalColors.deep_gray};
231
- padding-top: 2px;
232
- }
233
-
234
- .arrow {
235
- width: 20px;
236
- height: 20px;
237
- cursor: pointer;
238
- padding: 2px;
239
-
240
- border-radius: 5px;
241
- overflow: hidden;
242
- display: flex;
243
- align-items: center;
244
- justify-content: center;
245
-
246
- &.disabled {
247
- opacity: 0.5;
248
- filter: grayscale(1);
249
- cursor: not-allowed;
250
- }
251
-
252
- :hover {
253
- background-color: rgba(59, 147, 224, 0.1);
254
- }
255
-
256
- &.right {
257
- transform: rotate(180deg);
258
- }
259
-
260
- img {
261
- width: 100%;
262
- height: 100%;
263
- object-fit: contain;
264
- }
265
-
266
- }
267
-
268
- `;
269
-
270
- export const ButtonsContainer = styled.div`
271
-
272
- display: flex;
273
- align-items: center;
274
- gap: 0.5rem;
275
-
276
- .reload-suggestions {
277
-
278
- width: 20px;
279
- height: 20px;
280
- display: flex;
281
- align-items: center;
282
- justify-content: center;
283
- border-radius: 5px;
284
- padding: 4px;
285
- cursor: pointer;
286
-
287
- &.loading {
288
-
289
- filter: grayscale(1);
290
- opacity: 0.75;
291
- cursor: not-allowed;
292
-
293
- > img {
294
- width: 20px;
295
- height: 20px;
296
- }
297
-
298
- }
299
-
300
- :hover {
301
- background-color: rgba(59, 147, 224, 0.1);
302
- }
303
-
304
- > img {
305
- width: 100%;
306
- height: 100%;
307
- object-fit: contain;
308
- }
309
-
310
- }
311
-
312
- .accept-suggestion {
313
-
314
- text-align: center;
315
- padding: 4px 5px;
316
- cursor: pointer;
317
- background-color: rgba(59, 147, 224, 0.05);
318
-
319
- border-radius: 5px;
320
-
321
- :hover {
322
- background-color: rgba(59, 147, 224, 0.1);
323
- }
324
-
325
- > p {
326
- font-size: 11px;
327
- }
328
- }
329
-
330
- `;
@@ -13,7 +13,6 @@ import Slide2 from "../../../assets/images/sliderToolTip/slide22.svg";
13
13
  import Slide3 from "../../../assets/images/sliderToolTip/slide23.svg";
14
14
  import { FinancedCompanies } from "./FinancedCompanies";
15
15
  import { GlobalColors } from "../../../global-files/variables";
16
- import { useAiProductEdition } from "../../../contexts/AiProductEdition";
17
16
 
18
17
  export const StatusAsignationInfo = ({
19
18
  status = "-",
@@ -38,10 +37,6 @@ export const StatusAsignationInfo = ({
38
37
  const [assignationType, setAssignationType] = useState("facilitator");
39
38
  const isFinanced = FinancedCompanies.includes(user?.id_company);
40
39
 
41
- const {
42
- inputsUsingAi
43
- } = useAiProductEdition();
44
-
45
40
  const closeAsignations = (e) => {
46
41
  if (!e.target.closest("#default-id") && showAsignationPanel) {
47
42
  document.removeEventListener("click", closeAsignations, false);
@@ -98,10 +93,7 @@ export const StatusAsignationInfo = ({
98
93
  {showSaveButton && !isFinanced && (
99
94
  <Button
100
95
  buttonType={"circular-button save-button"}
101
- onClick={() => {
102
- if(Object.values(inputsUsingAi).some(input => !!input?.using)) return console.warn("Para guardar se debe de dejar de usar la generación con IA");
103
- onClickSave();
104
- }}
96
+ onClick={onClickSave}
105
97
  />
106
98
  )}
107
99
  {imagesSection && (
@@ -20,23 +20,22 @@ export const TabsMenu = ({
20
20
  }) => {
21
21
  const [sections, setSections] = useState(tabsSections);
22
22
 
23
+ useEffect(() => {
24
+ if (!activeTab) return;
25
+ setSections((prev) => {
26
+ const updated = {};
27
+ Object.keys(prev).forEach((key) => {
28
+ updated[key] = key === activeTab;
29
+ });
30
+ return updated;
31
+ });
32
+ }, [activeTab]);
33
+
23
34
  const [modal, setModal] = useState(false);
24
35
  const [cancelAccept, setCancelAccept] = useState("");
25
36
  const [llave, setLlave] = useState("");
26
37
  const [objeto, setObjeto] = useState();
27
38
 
28
- // Sincronizar sections cuando activeTab cambia desde el exterior
29
- useEffect(() => {
30
- if (activeTab && Object.keys(tabsSections).length > 0) {
31
- const tempArray = {};
32
- Object.keys(tabsSections).forEach((section) => {
33
- tempArray[section] = section === activeTab;
34
- });
35
- setSections(tempArray);
36
- setImagesSection(activeTab === "Imágenes");
37
- }
38
- }, [activeTab, tabsSections]);
39
-
40
39
  const activeSection = (key, array = {}) => {
41
40
  let tempArray = {};
42
41
  setImagesSection(key === "Imágenes");