feat(RecipeDetail): implementada funcionalidad para la edición de recetas

parent f39ba4c2
Showing with 85 additions and 28 deletions
......@@ -11,7 +11,7 @@
</span>
<div v-if="mode === 'view'" class="d-flex gap-2">
<button @click="editRecipe" class="btn btn-outline-custom">
<button @click="updateRecipe" class="btn btn-outline-custom">
<i class="bi bi-pencil-square"></i> Editar
</button>
<button @click="openDeleteModal" class="btn btn-danger">
......@@ -30,41 +30,45 @@
</div>
<div class="text-center mb-4">
<!-- Título -->
<h2 v-if="mode === 'view'" class="fw-bolder mb-2 text-primary-custom">{{ recipe.name }}</h2>
<input v-else type="text" v-model="recipe.name" class="form-control form-control-lg text-center mb-2" />
<input v-else type="text" id="recipeTitle" v-model="editableRecipe.name" class="form-control form-control-lg text-center mb-2" />
<!-- Fecha creación -->
<div class="d-flex justify-content-center align-items-center flex-wrap gap-3 mb-4">
<p v-if="mode === 'view' && recipe.createdAt != null" class="text-muted small mb-0">
Creado el {{ formattedDate }}
</p>
</div>
<div class="mb-4 mt-3 text-center">
<!-- Imagen -->
<div v-if="mode === 'view'" class="mb-4 mt-3 text-center">
<div class="image-container mx-auto">
<template v-if="mode === 'view'">
<img :src="recipe.picture ? recipe.picture : defaultImage"
<img
:src="recipe.picture ? recipe.picture : defaultImage"
class="img-fluid rounded shadow-sm"
alt="Imagen de la receta" />
</template>
<div v-else class="d-flex flex-column align-items-center">
<label class="form-label fw-bold">Cambiar imagen</label>
<input type="file" class="form-control" />
</div>
</div>
</div>
<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" />
</div>
<!-- Descripción -->
<p v-if="mode === 'view'" class="text-muted">{{ recipe.description }}</p>
<textarea v-else
v-model="recipe.description"
@input="autoGrow"
v-model="editableRecipe.description"
class="form-control mb-2"
rows="4">
rows="8"
id="recipeDescription">
</textarea>
</div>
<hr class="my-4" />
<!-- Ingredientes -->
<div class="row">
<div class="col-lg-6">
<div class="mb-4">
......@@ -76,19 +80,20 @@
</li>
</ul>
<div v-else class="ingredient-form-section">
<div v-for="(ing, index) in recipe.ingredients" :key="index" class="input-group mb-2">
<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">
<input type="text" v-model="ing.unit" class="form-control" placeholder="Unidad">
<input type="text" v-model="ing.ingredient" class="form-control" placeholder="Ingrediente">
<button @click="recipe.ingredients.splice(index, 1)" class="btn btn-outline-danger" type="button"><i class="bi bi-trash"></i></button>
<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>
</div>
<button @click="recipe.ingredients.push({ quantity: '', unit: '', ingredient: '' })" class="btn btn-outline-primary-custom mt-2 w-100">
<button @click="editableRecipe.ingredients.push({ quantity: '', unit: '', ingredient: '' })" class="btn btn-outline-primary-custom mt-2 w-100">
<i class="bi bi-plus-circle"></i> Añadir Ingrediente
</button>
</div>
</div>
</div>
<!-- Pasos -->
<div class="col-lg-6">
<div class="mb-4">
<h5 class="fw-bold">Pasos de Preparación</h5>
......@@ -98,17 +103,16 @@
</li>
</ol>
<div v-else class="steps-form-section">
<div v-for="(step, index) in recipe.steps" :key="index" class="input-group mb-2">
<div v-for="(step, index) in editableRecipe.steps" :key="index" class="input-group mb-2">
<span class="input-group-text">{{ index + 1 }}</span>
<textarea
v-model="step.description"
@input="autoGrow"
class="form-control"
rows="1">
rows="3">
</textarea>
<button @click="removeStep" class="btn btn-outline-danger" type="button"><i class="bi bi-trash"></i></button>
<button @click="editableRecipe.steps.splice(index, 1)" class="btn btn-outline-danger" type="button"><i class="bi bi-trash"></i></button>
</div>
<button @click="addStep" class="btn btn-outline-primary-custom mt-2 w-100">
<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
</button>
</div>
......@@ -138,6 +142,9 @@ import * as bootstrap from 'bootstrap';
// Estado de la vista: 'view' o 'edit'
const mode = ref('view');
const editableRecipe = ref(null);
const newPicture = ref(null);
const newPicturePreview = ref(null);
const recipeStore = useRecipeStore();
const route = useRoute();
......@@ -195,6 +202,61 @@ const deleteRecipe = async () => {
// Redirige al usuario a la página de recetas después de eliminar
router.push('/recipes');
};
// Funciones para editar la receta
const updateRecipe = () => {
mode.value = 'edit';
editableRecipe.value = JSON.parse(JSON.stringify(recipe.value));
newPicture.value = null;
};
const saveChanges = async () => {
try {
const formData = new FormData();
formData.append('name', editableRecipe.value.name);
formData.append('description', editableRecipe.value.description);
// Agrega la nueva imagen si el usuario ha seleccionado una
if (newPicture.value) {
formData.append('picture', newPicture.value);
}
// Procesa y adjunta los ingredientes y pasos como en la creación
const filledIngredients = editableRecipe.value.ingredients.filter(ing =>
ing.name && ing.quantity
);
filledIngredients.forEach((ingredient, index) => {
formData.append(`ingredients[${index}].name`, ingredient.name);
formData.append(`ingredients[${index}].quantity`, ingredient.quantity);
formData.append(`ingredients[${index}].unitOfMeasure`, ingredient.unitOfMeasure);
});
const filledSteps = editableRecipe.value.steps.filter(step => step.description);
filledSteps.forEach((step, index) => {
formData.append(`steps[${index}].number`, index + 1);
formData.append(`steps[${index}].description`, step.description);
});
// Actualiza la receta
await recipeStore.update(editableRecipe.value.id, formData);
// Vuelve a la vista de detalle y recarga la información
mode.value = 'view';
await recipeStore.readDetail(editableRecipe.value.id);
} catch (error) {
if (error.response && error.response.data && error.response.data.errorMsg) {
errorMsgs.value = error.response.data.errorMsg.split('; ');
} else {
errorMsgs.value = ['Ocurrió un error inesperado. Inténtalo de nuevo.'];
}
}
};
const handlePictureChange = (event) => {
const file = event.target.files[0];
newPicture.value = file;
};
</script>
<style scoped>
......@@ -252,11 +314,6 @@ h5 {
flex-wrap: nowrap;
}
textarea {
resize: none;
overflow: hidden;
}
/* Estilos imagen */
.image-container {
width: 400px;
......
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