contentoh-components-library 21.5.78 → 21.5.81
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.
- package/dist/ai/utils/compare-strings.js +43 -0
- package/dist/components/atoms/GeneralInput/index.js +64 -36
- package/dist/components/atoms/GeneralInput/styles.js +1 -1
- package/dist/components/atoms/InputFormatter/index.js +45 -21
- package/dist/components/atoms/InputFormatter/styles.js +1 -1
- package/dist/components/molecules/StatusAsignationInfo/index.js +11 -1
- package/dist/components/molecules/TagAndInput/index.js +110 -29
- package/dist/components/molecules/TagAndInput/styles.js +2 -2
- package/dist/components/organisms/InputGroup/index.js +22 -18
- package/dist/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +92 -785
- package/dist/components/pages/RetailerProductEdition/context/provider-product-edition.context.js +59 -260
- package/dist/components/pages/RetailerProductEdition/context/reducers/product.js +3 -41
- package/dist/components/pages/RetailerProductEdition/index.js +191 -123
- package/dist/contexts/AiProductEdition.js +179 -155
- package/package.json +1 -1
- package/src/ai/utils/compare-strings.js +43 -0
- package/src/components/atoms/GeneralInput/index.js +63 -42
- package/src/components/atoms/GeneralInput/styles.js +7 -0
- package/src/components/atoms/InputFormatter/index.js +51 -23
- package/src/components/atoms/InputFormatter/styles.js +62 -10
- package/src/components/molecules/StatusAsignationInfo/index.js +9 -1
- package/src/components/molecules/TagAndInput/index.js +113 -28
- package/src/components/molecules/TagAndInput/styles.js +48 -17
- package/src/components/organisms/FullTabsMenu/index.js +1 -1
- package/src/components/organisms/InputGroup/index.js +4 -0
- package/src/components/pages/RetailerProductEdition/RetailerProductEdition.stories.js +111 -832
- package/src/components/pages/RetailerProductEdition/context/provider-product-edition.context.jsx +3 -221
- package/src/components/pages/RetailerProductEdition/context/reducers/product.js +3 -43
- package/src/components/pages/RetailerProductEdition/index.js +17 -15
- package/src/contexts/AiProductEdition.jsx +138 -96
- package/src/ai/prompts/attribute.prompt.js +0 -46
- package/src/ai/prompts/description.prompt.js +0 -52
- package/src/ai/schemas/attribute.schema.js +0 -23
- package/src/ai/schemas/description.schema.js +0 -19
|
@@ -2,14 +2,7 @@ import { useContext, useEffect, useState } from "react";
|
|
|
2
2
|
import { createContext } from "react";
|
|
3
3
|
import axios from "axios";
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import DescriptionSchema from "../ai/schemas/description.schema.js";
|
|
7
|
-
|
|
8
|
-
import { GoogleGenAI } from "@google/genai";
|
|
9
|
-
import { generateDescriptionPrompt } from "../ai/prompts/description.prompt";
|
|
10
|
-
import { generateAttributePrompt } from "../ai/prompts/attribute.prompt";
|
|
11
|
-
|
|
12
|
-
const GeminiApiKey = process.env.REACT_APP_GEMINI_API_KEY;
|
|
5
|
+
import { useProviderProductEdition } from "../components/pages/RetailerProductEdition/context/provider-product-edition.context.jsx";
|
|
13
6
|
|
|
14
7
|
export const AiProductEdition = createContext();
|
|
15
8
|
|
|
@@ -23,22 +16,36 @@ export const useAiProductEdition = () => {
|
|
|
23
16
|
|
|
24
17
|
export const AiProductEditionProvider = ({
|
|
25
18
|
children,
|
|
26
|
-
isCreatorsEdition =
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
isCreatorsEdition = false,
|
|
20
|
+
user = {},
|
|
21
|
+
token = ""
|
|
29
22
|
}) => {
|
|
30
23
|
|
|
31
24
|
const isCreators = isCreatorsEdition;
|
|
32
25
|
|
|
26
|
+
const {
|
|
27
|
+
state,
|
|
28
|
+
} = useProviderProductEdition();
|
|
29
|
+
|
|
30
|
+
const productSelected = state.product;
|
|
31
|
+
const activeRetailer = state.active_retailer;
|
|
32
|
+
const datasheetInputs = state.datasheets_inputs?.[1];
|
|
33
|
+
const imagesData = state.images_values;
|
|
34
|
+
|
|
33
35
|
const [product, setProduct] = useState(null);
|
|
34
36
|
|
|
35
|
-
const [
|
|
37
|
+
const [parsedDatasheet, setParsedDatasheet] = useState([]);
|
|
38
|
+
const [parsedImages, setParsedImages] = useState([]);
|
|
36
39
|
|
|
40
|
+
const [suggestions, setSuggestions] = useState({});
|
|
37
41
|
const [currentSuggestion, setCurrentSuggestion] = useState({});
|
|
38
42
|
|
|
39
|
-
const
|
|
43
|
+
const [isAiAvailable, setIsAiAvailable] = useState(false);
|
|
44
|
+
|
|
45
|
+
const [inputsGeneratedWithAi, setInputsGeneratedWithAi] = useState({});
|
|
46
|
+
const [inputsUsingAi, setInputsUsingAi] = useState({});
|
|
47
|
+
|
|
40
48
|
|
|
41
|
-
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
42
49
|
|
|
43
50
|
function setCurrentSuggestionValue({
|
|
44
51
|
inputId,
|
|
@@ -59,22 +66,31 @@ export const AiProductEditionProvider = ({
|
|
|
59
66
|
}
|
|
60
67
|
|
|
61
68
|
async function regenerateProductSuggestions ({
|
|
62
|
-
inputId,
|
|
63
69
|
inputName,
|
|
64
70
|
currentValue,
|
|
65
71
|
description,
|
|
66
72
|
maxChar,
|
|
67
|
-
type
|
|
73
|
+
type,
|
|
74
|
+
|
|
75
|
+
articleId,
|
|
76
|
+
versionId,
|
|
77
|
+
descriptionId,
|
|
78
|
+
attributeId
|
|
68
79
|
}) {
|
|
69
80
|
|
|
70
|
-
if(!
|
|
81
|
+
if(!description || !maxChar || !type) return console.log("Error: No se obtuvieron los parametros obligatorios");
|
|
71
82
|
|
|
72
83
|
const newSuggestions = await generateProductSuggestions({
|
|
73
84
|
inputName,
|
|
74
85
|
currentValue,
|
|
75
86
|
description,
|
|
76
87
|
maxChar,
|
|
77
|
-
type
|
|
88
|
+
type,
|
|
89
|
+
|
|
90
|
+
articleId,
|
|
91
|
+
versionId,
|
|
92
|
+
descriptionId,
|
|
93
|
+
attributeId
|
|
78
94
|
});
|
|
79
95
|
|
|
80
96
|
if(!Array.isArray(newSuggestions) || newSuggestions.length === 0)
|
|
@@ -91,22 +107,26 @@ export const AiProductEditionProvider = ({
|
|
|
91
107
|
currentValue = "",
|
|
92
108
|
description = "",
|
|
93
109
|
maxChar = 100,
|
|
94
|
-
type =
|
|
110
|
+
type = 'description',
|
|
111
|
+
|
|
112
|
+
articleId,
|
|
113
|
+
versionId,
|
|
114
|
+
descriptionId,
|
|
115
|
+
attributeId
|
|
95
116
|
}) {
|
|
96
117
|
|
|
97
118
|
try {
|
|
98
119
|
|
|
99
|
-
if(!
|
|
120
|
+
if(!isAiAvailable) return;
|
|
121
|
+
|
|
122
|
+
if(!product)
|
|
100
123
|
throw new Error("El producto no está definido");
|
|
101
|
-
}
|
|
102
124
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
type
|
|
109
|
-
});
|
|
125
|
+
if(!Array.isArray(parsedDatasheet) || parsedDatasheet.length === 0)
|
|
126
|
+
throw new Error("No es encontró la ficha técnica");
|
|
127
|
+
|
|
128
|
+
if(!Array.isArray(parsedImages) || parsedImages.length === 0)
|
|
129
|
+
throw new Error("No se encontraron imágenes para la cadena seleccionada");
|
|
110
130
|
|
|
111
131
|
const {
|
|
112
132
|
upc,
|
|
@@ -115,50 +135,37 @@ export const AiProductEditionProvider = ({
|
|
|
115
135
|
category
|
|
116
136
|
} = product;
|
|
117
137
|
|
|
118
|
-
if (!upc || !description || !productName || !category || !retailer)
|
|
138
|
+
if (!upc || !description || !productName || !category || !retailer || !articleId || !versionId || (!descriptionId && !attributeId))
|
|
119
139
|
throw new Error("Faltan parámetros obligatorios para generar sugerencias de IA");
|
|
120
|
-
}
|
|
121
140
|
|
|
122
|
-
const
|
|
141
|
+
const payload = {
|
|
123
142
|
upc,
|
|
124
|
-
inputName,
|
|
125
|
-
description,
|
|
126
|
-
|
|
127
|
-
category,
|
|
128
|
-
currentValue,
|
|
129
|
-
retailer,
|
|
130
|
-
maxChar
|
|
131
|
-
}) : generateAttributePrompt({
|
|
132
|
-
upc,
|
|
133
|
-
inputName,
|
|
134
|
-
description,
|
|
135
|
-
name: productName,
|
|
136
|
-
category,
|
|
143
|
+
attributeTitle: inputName,
|
|
144
|
+
attributeDescription: description,
|
|
145
|
+
productName,
|
|
137
146
|
currentValue,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
responseSchema : schema,
|
|
155
|
-
temperature: 0.1
|
|
147
|
+
categoryName: category,
|
|
148
|
+
retailerName: retailer,
|
|
149
|
+
datasheet: parsedDatasheet,
|
|
150
|
+
images: parsedImages,
|
|
151
|
+
maxChar: maxChar,
|
|
152
|
+
|
|
153
|
+
articleId,
|
|
154
|
+
retailerId: activeRetailer?.id_retailer,
|
|
155
|
+
versionId,
|
|
156
|
+
descriptionId,
|
|
157
|
+
attributeId
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const { data } = await axios.post(process.env.REACT_APP_GENERATE_AI_ATTRIBUTES, payload, {
|
|
161
|
+
headers: {
|
|
162
|
+
Authorization: token
|
|
156
163
|
}
|
|
157
164
|
});
|
|
158
165
|
|
|
159
|
-
const
|
|
166
|
+
const results = JSON.parse(data?.body)?.data ?? [];
|
|
160
167
|
|
|
161
|
-
|
|
168
|
+
console.log({results});
|
|
162
169
|
|
|
163
170
|
if(!results)
|
|
164
171
|
throw new Error("No se encontraron resultados");
|
|
@@ -174,34 +181,7 @@ export const AiProductEditionProvider = ({
|
|
|
174
181
|
|
|
175
182
|
}
|
|
176
183
|
|
|
177
|
-
|
|
178
|
-
try {
|
|
179
|
-
|
|
180
|
-
const failoverModel = "gemini-2.5-flash";
|
|
181
|
-
|
|
182
|
-
const model = retries > 3 ? "gemini-2.5-flash-lite" : failoverModel;
|
|
183
|
-
|
|
184
|
-
return await ai.models.generateContent({
|
|
185
|
-
...modelParams,
|
|
186
|
-
model: model
|
|
187
|
-
});
|
|
188
|
-
} catch (error) {
|
|
189
|
-
|
|
190
|
-
const isOverloaded = error.status === 503 || error.message?.includes("overloaded");
|
|
191
|
-
|
|
192
|
-
if (retries > 0 && isOverloaded) {
|
|
193
|
-
console.warn(`⚠️ Modelo saturado (503). Reintentando en ${backoff}ms... (Quedan ${retries} intentos)`);
|
|
194
|
-
|
|
195
|
-
await delay(backoff);
|
|
196
|
-
|
|
197
|
-
return generateContentWithRetry(modelParams, retries - 1, backoff * 2);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// Si no es error de sobrecarga o se acabaron los intentos, lanzamos el error real
|
|
201
|
-
throw error;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
184
|
+
// Verificamos si los servicios de ficha técnica e imágenes estan completos
|
|
205
185
|
useEffect(() => {
|
|
206
186
|
|
|
207
187
|
if (!productSelected) return;
|
|
@@ -223,6 +203,23 @@ export const AiProductEditionProvider = ({
|
|
|
223
203
|
category
|
|
224
204
|
} = currentCategory;
|
|
225
205
|
|
|
206
|
+
//Checamos si el servicio de ficha técnica e imagenes esta completo
|
|
207
|
+
const currentRetailerPercentages = productSelected?.percentages?.find(retailer => retailer?.id_retailer === activeRetailer?.id_retailer);
|
|
208
|
+
|
|
209
|
+
if(!currentRetailerPercentages) return console.log("Error: No hay porcentajes disponibles");
|
|
210
|
+
|
|
211
|
+
const {
|
|
212
|
+
required: datasheetRequiredPercent,
|
|
213
|
+
} = currentRetailerPercentages?.datasheet;
|
|
214
|
+
|
|
215
|
+
const {
|
|
216
|
+
required: imagesRequiredPercent,
|
|
217
|
+
} = currentRetailerPercentages?.images;
|
|
218
|
+
|
|
219
|
+
const aiServiceAvailable = (datasheetRequiredPercent >= 100) && (imagesRequiredPercent >= 100) && user?.id_role === 7;
|
|
220
|
+
|
|
221
|
+
setIsAiAvailable(aiServiceAvailable);
|
|
222
|
+
|
|
226
223
|
setProduct({
|
|
227
224
|
upc,
|
|
228
225
|
productName,
|
|
@@ -232,19 +229,64 @@ export const AiProductEditionProvider = ({
|
|
|
232
229
|
|
|
233
230
|
}, [productSelected]);
|
|
234
231
|
|
|
232
|
+
// Inicializamos la ficha técnica con el objetivo de posteriormente pasarlo a la generación con IA
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
|
|
235
|
+
if (!datasheetInputs) return;
|
|
236
|
+
|
|
237
|
+
const datasheetToArray = Object.values(datasheetInputs);
|
|
238
|
+
|
|
239
|
+
const normalizedDatasheet = datasheetToArray.map(attribute => ({
|
|
240
|
+
description: attribute?.description,
|
|
241
|
+
name: attribute?.name,
|
|
242
|
+
type: attribute?.type,
|
|
243
|
+
value: attribute?.value
|
|
244
|
+
}));
|
|
245
|
+
|
|
246
|
+
setParsedDatasheet(normalizedDatasheet);
|
|
247
|
+
|
|
248
|
+
}, [datasheetInputs]);
|
|
249
|
+
|
|
250
|
+
// Inicializamos las imágenes con el objetivo de posteriormente pasarlo a la generación con IA
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
|
|
253
|
+
const currentRetailerImageInputs = imagesData?.inputsByRetailer?.[0]?.filter(input => input?.id_retailer === activeRetailer?.id_retailer);
|
|
254
|
+
|
|
255
|
+
if(!Array.isArray(currentRetailerImageInputs) || currentRetailerImageInputs.length === 0) return console.log('No existen imágenes para la cadena seleccionada')
|
|
256
|
+
|
|
257
|
+
const allProductImages = imagesData?.values;
|
|
258
|
+
|
|
259
|
+
if(!Array.isArray(allProductImages) || allProductImages.length === 0) return console.log("No existen imágenes para el producto");
|
|
260
|
+
|
|
261
|
+
//Obtenemos las imágenes para el retailer seleccionado
|
|
262
|
+
const currentParsedImages = allProductImages.filter(image => {
|
|
263
|
+
|
|
264
|
+
const imageId = image?.image_id;
|
|
265
|
+
const foundedImage = currentRetailerImageInputs.some(retailerImage => retailerImage?.id_image === imageId);
|
|
266
|
+
|
|
267
|
+
return foundedImage;
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
setParsedImages(currentParsedImages);
|
|
271
|
+
|
|
272
|
+
}, [imagesData]);
|
|
273
|
+
|
|
235
274
|
return (
|
|
236
275
|
<AiProductEdition.Provider
|
|
237
276
|
value={{
|
|
238
277
|
isCreators: isCreators,
|
|
239
278
|
suggestions,
|
|
240
279
|
currentSuggestion,
|
|
280
|
+
isAiAvailable,
|
|
281
|
+
inputsGeneratedWithAi,
|
|
282
|
+
inputsUsingAi,
|
|
241
283
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
generateProductSuggestions,
|
|
245
|
-
regenerateProductSuggestions,
|
|
284
|
+
setInputsUsingAi,
|
|
285
|
+
setInputsGeneratedWithAi,
|
|
246
286
|
setSuggestions,
|
|
247
287
|
setCurrentSuggestionValue,
|
|
288
|
+
generateProductSuggestions,
|
|
289
|
+
regenerateProductSuggestions,
|
|
248
290
|
clearCurrentSuggestions,
|
|
249
291
|
|
|
250
292
|
}}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
export const generateAttributePrompt = ({
|
|
2
|
-
upc = 0,
|
|
3
|
-
inputName = "",
|
|
4
|
-
description = "",
|
|
5
|
-
currentValue = "",
|
|
6
|
-
name = "",
|
|
7
|
-
category = "",
|
|
8
|
-
retailer = "",
|
|
9
|
-
maxChar = 100,
|
|
10
|
-
}) => {
|
|
11
|
-
|
|
12
|
-
return `
|
|
13
|
-
Eres un especialista en la generación, optimización, mejora y captura de atributos de la ficha técnica de productos para catálogos en línea.
|
|
14
|
-
Tu tarea es crear atributos claros, concisos y relevantes que resalten las características y beneficios del producto, utilizando un lenguaje preciso y adaptado al público objetivo.
|
|
15
|
-
|
|
16
|
-
Datos del producto:
|
|
17
|
-
- UPC: ${upc}
|
|
18
|
-
- Nombre del producto: ${name}
|
|
19
|
-
- Categoría: ${category}
|
|
20
|
-
- Nombre del atributo: ${inputName}
|
|
21
|
-
- Requerimiento del atributo: ${description}
|
|
22
|
-
- Valor actual del atributo: ${currentValue}
|
|
23
|
-
- Cadena comercial dirigida: ${retailer}
|
|
24
|
-
|
|
25
|
-
Instrucciones:
|
|
26
|
-
1. Analiza el nombre del producto y la categoría para entender su contexto.
|
|
27
|
-
2. Analiza la descripción del atributo actual del producto.
|
|
28
|
-
3. Identifica la información clave del atributo que sean relevantes y útiles para los clientes potenciales.
|
|
29
|
-
4. Genera una lista de atributos que:
|
|
30
|
-
- Cumplan con la descripcion del atributo proporcionada, no inventes datos o cambies el contexto de lo que pide la descripción del atributo.
|
|
31
|
-
- Sean claros y fáciles de entender.
|
|
32
|
-
- Destaquen las características y beneficios clave del producto.
|
|
33
|
-
- Utilicen un lenguaje preciso y adaptado al público objetivo.
|
|
34
|
-
- Mantengan un tono profesional y coherente con la marca.
|
|
35
|
-
- Aumenten la probabilidad de compra del producto.
|
|
36
|
-
- No excedan los ${maxChar} caracteres en total.
|
|
37
|
-
- Si existe ejemplo en la descripción del atributo, sigue el mismo formato para generar los atributos.
|
|
38
|
-
5. No incluyas emojis ni signos especiales (*/+´!¡?¿)
|
|
39
|
-
6. No repitas el encabezado: ${inputName}
|
|
40
|
-
7. No incluyas call to action, ejemplo: "!Compra ya!" "!Da click!" "!Apurate!"
|
|
41
|
-
|
|
42
|
-
Asegúrate de que los atributos generados cumplan con todas las instrucciones proporcionadas.
|
|
43
|
-
|
|
44
|
-
No lo olvides, el objetivo principal es mejorar la captura de atributos para la ficha técnica del producto para atraer, convencer y dar la información completa a los clientes potenciales que puedan realizar una compra.
|
|
45
|
-
`
|
|
46
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// Cadena y Proveedor
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* La cadena ${cadena} tiene estas reglas ${reglas} para el tipo de descripcion que es: ${descripcion}
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export const generateDescriptionPrompt = ({
|
|
8
|
-
upc = 0,
|
|
9
|
-
inputName = "",
|
|
10
|
-
description = "",
|
|
11
|
-
currentValue = "",
|
|
12
|
-
name = "",
|
|
13
|
-
category = "",
|
|
14
|
-
retailer = "",
|
|
15
|
-
maxChar = 100,
|
|
16
|
-
}) => {
|
|
17
|
-
|
|
18
|
-
return `
|
|
19
|
-
Eres un especialista en la generación, optimización y mejora de descripciones de productos para catálogos en línea.
|
|
20
|
-
Tu tarea es crear descripciones claras, concisas y atractivas que resalten las características y beneficios del producto, utilizando un lenguaje persuasivo y adaptado al público objetivo.
|
|
21
|
-
|
|
22
|
-
Datos del producto:
|
|
23
|
-
- UPC: ${upc}
|
|
24
|
-
- Nombre del producto: ${name}
|
|
25
|
-
- Categoría: ${category}
|
|
26
|
-
- Encabezado de la descripción: ${inputName}
|
|
27
|
-
- Requerimiento de la descripcion: ${description}
|
|
28
|
-
- Descripcion actual del producto: ${currentValue}
|
|
29
|
-
- Cadena comercial dirigida: ${retailer}
|
|
30
|
-
|
|
31
|
-
Instrucciones:
|
|
32
|
-
1. Analiza la descripción actual del producto en caso de tenerla.
|
|
33
|
-
2. Identifica áreas de mejora, como claridad, concisión, atractivo y relevancia.
|
|
34
|
-
3. Genera una descripción que:
|
|
35
|
-
- Sea clara y fácil de entender.
|
|
36
|
-
- Destaque las características y beneficios clave del producto.
|
|
37
|
-
- Utilice un lenguaje persuasivo y adaptado al público objetivo.
|
|
38
|
-
- Mantenga un tono profesional y coherente con la marca.
|
|
39
|
-
- No exceda los ${maxChar} caracteres.
|
|
40
|
-
- Aumente la probabilidad de compra del producto, utilizando persuasión en la necesidad de compra del producto.
|
|
41
|
-
4. No incluyas emojis ni signos especiales (*/+´!¡?¿)
|
|
42
|
-
5. No repitas el encabezado: ${inputName}
|
|
43
|
-
6. No incluyas call to action, ejemplo: "!Compra ya!" "!Da click!" "!Apurate!"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
Asegúrate de que la descripción generada cumpla con todas las instrucciones proporcionadas.
|
|
47
|
-
|
|
48
|
-
No lo olvides, el objetivo principal es mejorar la descripción del producto para atraer y convencer a los clientes potenciales de realizar una compra. Eres un experto en marketing y redacción persuasiva.
|
|
49
|
-
|
|
50
|
-
Nota: No estas hablando con los clientes, estas descripciones irán en la tienda de E-commerce de la cadena comercial. No realices saludos, despedidas, sugerencias
|
|
51
|
-
`
|
|
52
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const schema = {
|
|
2
|
-
type: "object",
|
|
3
|
-
properties: {
|
|
4
|
-
results: {
|
|
5
|
-
type: "array",
|
|
6
|
-
items: {
|
|
7
|
-
type: "object",
|
|
8
|
-
properties: {
|
|
9
|
-
label: { type: "string" },
|
|
10
|
-
value: { type: "string" }
|
|
11
|
-
}
|
|
12
|
-
},
|
|
13
|
-
maxItems: 3
|
|
14
|
-
},
|
|
15
|
-
compliance_warnings: {
|
|
16
|
-
type: "array",
|
|
17
|
-
items: { type: "string" }
|
|
18
|
-
}
|
|
19
|
-
},
|
|
20
|
-
required: ["results"]
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default schema;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
const schema = {
|
|
2
|
-
type: "object",
|
|
3
|
-
properties: {
|
|
4
|
-
results: {
|
|
5
|
-
type: "array",
|
|
6
|
-
items: {
|
|
7
|
-
type: "object",
|
|
8
|
-
properties: {
|
|
9
|
-
value: { type: "string" }
|
|
10
|
-
}
|
|
11
|
-
},
|
|
12
|
-
minItems: 1,
|
|
13
|
-
maxItems: 3
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
required: ["results"]
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export default schema;
|