Ultimos cambios

parent 451d56f2
import RecipeDetail from '@/views/RecipeDetail.vue';
import api from './api';
export const recipeService = {
......@@ -8,19 +7,43 @@ export const recipeService = {
if (size != null) params.append('size', size);
if (sortDirection != null) params.append('sortDirection', sortDirection);
const response = await api.get(`/recipe?${params.toString()}`);
const response = await api.get(`/recipe?${params.toString()}`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
madeFavorite: async (id) => {
const response = await api.patch(`/recipe/${id}/favorite`);
const response = await api.patch(`/recipe/${id}/favorite`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
removeFavorite: async (id) => {
const response = await api.delete(`/recipe/${id}/favorite`);
const response = await api.delete(`/recipe/${id}/favorite`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
readDetail: async (id) => {
const response = await api.get(`/recipe/${id}`);
const response = await api.get(`/recipe/${id}`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
create: async (recipeData) => {
......@@ -28,7 +51,13 @@ export const recipeService = {
return response.data;
},
delete: async (id) => {
const response = await api.delete(`/recipe/${id}`);
const response = await api.delete(`/recipe/${id}`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
update: async (recipeId, newData) => {
......@@ -41,7 +70,13 @@ export const recipeService = {
if (page) params.append('page', page);
if (size) params.append('size', size);
const response = await api.get(`/recipe/search?${params.toString()}`)
const response = await api.get(`/recipe/search?${params.toString()}`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
readFavorites: async (page, size, sortDirection) => {
......@@ -50,7 +85,49 @@ export const recipeService = {
if (size != null) params.append('size', size);
if (sortDirection != null) params.append('sortDirection', sortDirection);
const response = await api.get(`/recipe/favorites?${params.toString()}`);
const response = await api.get(`/recipe/favorites?${params.toString()}`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
searchAI: async (query) => {
const response = await api.post(`/recipe/search?ingredients=${query}`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
searchMoreAI: async (sessionId) => {
const response = await api.post(
'/recipe/search/more',
{},
{
headers: {
"Content-Type": "application/json",
"X-Session-ID": sessionId
}
}
)
return response.data;
},
getDetailAI: async (sessionId, index) => {
const response = await api.post(
`/recipe/detail/${index}`,
{},
{
headers: {
"Content-Type": "application/json",
"X-Session-ID": sessionId
}
}
)
return response.data;
}
}
\ No newline at end of file
......@@ -2,7 +2,13 @@ import api from './api';
export const userService = {
readUser: async () => {
const response = await api.get('/user/me');
const response = await api.get('/user/me', {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
readAll: async (page, size, sortBy, sortDirection) => {
......@@ -16,31 +22,73 @@ export const userService = {
}
// Petición al endpoint con los parámetros
const response = await api.get(`/user?${params.toString()}`);
const response = await api.get(`/user?${params.toString()}`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
deactivate: async (id) => {
const response = await api.patch(`/user/${id}/deactivate`);
const response = await api.patch(`/user/${id}/deactivate`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
activate: async (id) => {
const response = await api.patch(`/user/${id}/activate`);
const response = await api.patch(`/user/${id}/activate`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
deactivateMe: async () => {
const response = await api.patch(`/user/deactivate`);
const response = await api.patch(`/user/deactivate`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
update: async (updatedUser) => {
const response = await api.put('/user', updatedUser);
const response = await api.put('/user', updatedUser,
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
changePassword: async (passwords) => {
const response = await api.patch(`user/password`, passwords);
const response = await api.patch(`user/password`, passwords,
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
changeRole: async (id, role) => {
const response = await api.patch(`/user/${id}/role`, role);
const response = await api.patch(`/user/${id}/role`, role,
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
},
search: async (query, page, size) => {
......@@ -49,7 +97,13 @@ export const userService = {
if (page) params.append('page', page);
if (size) params.append('size', size);
const response = await api.get(`/user/search?${params.toString()}`)
const response = await api.get(`/user/search?${params.toString()}`, {},
{
headers: {
"Content-Type": "application/json"
}
}
);
return response.data;
}
}
\ No newline at end of file
......@@ -9,7 +9,13 @@ export const useRecipeStore = defineStore('recipe', {
pageSize: 10,
totalElements: 0,
totalPages: 0,
sortDirection: 'desc'
sortDirection: 'desc',
// Estados búsqueda por IA
aiRecipes: [],
aiSessionId: null,
loading: false,
aiRecipe: null,
loadingDetail: false
}),
actions: {
async readAll(page, size, sortDirection) {
......@@ -111,6 +117,63 @@ export const useRecipeStore = defineStore('recipe', {
this.totalPages = 0;
throw error;
}
},
async searchAI(query) {
this.loading = true;
// Limpiamos los resultados de la búsqueda anterior
this.aiRecipes = [];
this.aiSessionId = null;
try {
const { recipes, sessionId } = await recipeService.searchAI(query);
if (recipes) {
this.aiRecipes = recipes;
this.aiSessionId = sessionId;
} else {
this.aiRecipes = [];
this.aiSessionId = null;
}
} catch (error) {
console.error('Error al hacer la búsqueda por IA:', error);
this.aiRecipes = [];
this.aiSessionId = null;
throw error;
} finally {
this.loading = false;
}
},
async searchMoreAI(sessionId) {
this.loading = true;
try {
const response = await recipeService.searchMoreAI(sessionId);
if (!response || response.length === 0) {
return;
}
this.aiRecipes.push(...response);
} catch (error) {
console.error('Error al cargar más recetas', error);
throw error;
} finally {
this.loading = false;
}
},
async getDetailAI(sessionId, index) {
this.loadingDetail = true;
this.aiRecipe = null;
try {
const response = await recipeService.getDetailAI(sessionId, index);
this.aiRecipe = response;
} catch (error) {
console.error('Error al obtener el detalle de la receta:', error);
this.aiRecipe = null;
throw error;
} finally {
this.loadingDetail = false;
}
}
}
});
\ No newline at end of file
......@@ -42,7 +42,7 @@
</div>
<div v-for="ingredient in ingredients" :key="ingredient.id" class="row align-items-center mb-2">
<div class="col-3">
<input type="number" class="form-control" v-model="ingredient.quantity" placeholder="Ej: 2">
<input type="text" class="form-control" v-model="ingredient.quantity" placeholder="Ej: 2">
</div>
<div class="col-3">
<input type="text" class="form-control" v-model="ingredient.unitOfMeasure" placeholder="Ej: tazas">
......
......@@ -53,7 +53,7 @@
<div v-else class="mb-4 mt-3 text-center">
<label for="recipePicture" class="form-label fw-bold">Cambiar imagen</label>
<input id="recipePicture" type="file" class="form-control mx-auto" style="max-width: 300px" @change="handlePictureChange" />
<input id="recipePicture" type="file" class="form-control mx-auto" @change="handlePictureChange" />
</div>
<!-- Descripción -->
......@@ -68,25 +68,37 @@
<hr class="my-4" />
<!-- Ingredientes -->
<div class="row">
<!-- Ingredientes -->
<div class="col-lg-6">
<div class="mb-4">
<h5 class="fw-bold">Ingredientes</h5>
<ul v-if="mode === 'view'" class="list-unstyled">
<li v-for="(ing, index) in processedIngredients" :key="index" class="mb-1">
<i class="bi bi-check-circle-fill me-2 text-success"></i>
{{ ing.quantity }} {{ ing.unit }} {{ ing.connective }} {{ ing.name }}
<h5 class="section-title">
<i class="bi bi-basket me-2"></i> Ingredientes
</h5>
<!-- Vista -->
<ul v-if="mode === 'view'" class="ingredients-list">
<li v-for="(ing, index) in processedIngredients" :key="index" class="ingredient-item">
<span class="ingredient-name">{{ ing.name }}</span>
<span class="ingredient-amount">
{{ ing.quantity }} {{ ing.unit }} {{ ing.connective }}
</span>
</li>
</ul>
<!-- Edición -->
<div v-else class="ingredient-form-section">
<div v-for="(ing, index) in editableRecipe.ingredients" :key="index" class="input-group mb-2">
<input type="number" v-model="ing.quantity" class="form-control" placeholder="Cantidad">
<div v-for="(ing, index) in editableRecipe.ingredients" :key="index" class="ingredient-form mb-2">
<input type="text" v-model="ing.name" class="form-control mb-2" placeholder="Ingrediente">
<div class="d-flex gap-2 mt-2">
<input type="text" v-model="ing.quantity" class="form-control" placeholder="Cantidad">
<input type="text" v-model="ing.unitOfMeasure" class="form-control" placeholder="Unidad">
<input type="text" v-model="ing.name" class="form-control" placeholder="Ingrediente">
<button @click="editableRecipe.ingredients.splice(index, 1)" class="btn btn-outline-danger" type="button"><i class="bi bi-trash"></i></button>
<button @click="editableRecipe.ingredients.splice(index, 1)" class="btn btn-outline-danger" type="button">
<i class="bi bi-trash"></i>
</button>
</div>
<button @click="editableRecipe.ingredients.push({ quantity: '', unit: '', ingredient: '' })" class="btn btn-outline-primary-custom mt-2 w-100">
</div>
<button @click="editableRecipe.ingredients.push({ quantity: '', unit: '', name: '' })" class="btn btn-outline-primary-custom mt-2 w-100">
<i class="bi bi-plus-circle"></i> Añadir Ingrediente
</button>
</div>
......@@ -96,21 +108,28 @@
<!-- Pasos -->
<div class="col-lg-6">
<div class="mb-4">
<h5 class="fw-bold">Pasos de Preparación</h5>
<ol v-if="mode === 'view'">
<li v-for="(step, index) in recipe.steps" :key="index" class="mb-2">
{{ step.description }}
<h5 class="section-title">
<i class="bi bi-list-ol me-2"></i> Pasos de preparación
</h5>
<!-- Vista -->
<ol v-if="mode === 'view'" class="steps-list">
<li v-for="(step, index) in recipe.steps" :key="index" class="step-item">
<span class="step-number">{{ index + 1 }}</span>
<span class="step-text">{{ step.description }}</span>
</li>
</ol>
<!-- Edición -->
<div v-else class="steps-form-section">
<div v-for="(step, index) in editableRecipe.steps" :key="index" class="input-group mb-2">
<div v-for="(step, index) in editableRecipe.steps" :key="index" class="step-form">
<div class="d-flex gap-2 mb-2">
<span class="input-group-text">{{ index + 1 }}</span>
<textarea
v-model="step.description"
class="form-control"
rows="3">
</textarea>
<button @click="editableRecipe.steps.splice(index, 1)" class="btn btn-outline-danger" type="button"><i class="bi bi-trash"></i></button>
<textarea v-model="step.description" class="form-control" rows="2"></textarea>
<button @click="editableRecipe.steps.splice(index, 1)" class="btn btn-outline-danger" type="button">
<i class="bi bi-trash"></i>
</button>
</div>
</div>
<button @click="editableRecipe.steps.push({ description: '' })" class="btn btn-outline-primary-custom mt-2 w-100">
<i class="bi bi-plus-circle"></i> Añadir Paso
......@@ -120,6 +139,7 @@
</div>
</div>
</div>
</div>
</div>
</div>
......@@ -175,12 +195,12 @@ const processedIngredients = computed(() => {
return recipe.value.ingredients.map(ing => {
const unit = ing.unitOfMeasure ? ing.unitOfMeasure.toLowerCase() : '';
const name = ing.name ? ing.name.toLowerCase() : '';
const connective = ing.unitOfMeasure ? 'de' : '';
// const connective = ing.unitOfMeasure ? 'de' : '';
return {
...ing,
unit,
name,
connective
name
// connective
};
});
});
......@@ -333,4 +353,73 @@ h5 {
color: white;
font-size: 14px;
}
/* Títulos de sección */
.section-title {
font-weight: 700;
color: #793E6C;
border-bottom: 2px solid #eee;
padding-bottom: 4px;
margin-bottom: 16px;
display: flex;
align-items: center;
}
/* INGREDIENTES vista */
.ingredients-list {
list-style: none;
padding: 0;
margin: 0;
}
.ingredient-item {
display: flex;
justify-content: space-between;
padding: 6px 10px;
border-bottom: 1px solid #eee;
}
.ingredient-name {
font-weight: 500;
}
.ingredient-amount {
color: #555;
font-size: 0.9rem;
}
/* PASOS vista */
.steps-list {
list-style: none;
padding: 0;
margin: 0;
}
.step-item {
display: flex;
align-items: flex-start;
margin-bottom: 12px;
background: #f5f5f5;
padding: 10px 14px;
border-radius: 8px;
}
.step-number {
flex-shrink: 0;
width: 28px;
height: 28px;
border-radius: 50%;
background: #793e6c;
color: white;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
}
.step-text {
flex: 1;
}
</style>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment