feat(CreateRecipe): añadida funcionalidad para crear recetas

parent e0aaa80e
Showing with 101 additions and 18 deletions
...@@ -5,23 +5,31 @@ ...@@ -5,23 +5,31 @@
<div class="recipe-form-card p-4 rounded shadow-sm"> <div class="recipe-form-card p-4 rounded shadow-sm">
<h2 class="text-center mb-4 text-primary-custom fw-bold">Nueva Receta</h2> <h2 class="text-center mb-4 text-primary-custom fw-bold">Nueva Receta</h2>
<div v-if="errorMsgs.length > 0" class="alert alert-danger" role="alert">
<ul>
<li v-for="msg in errorMsgs" :key="msg">{{ msg }}</li>
</ul>
</div>
<form @submit.prevent="handleCreation">
<div class="mb-4"> <div class="mb-4">
<label for="inputName" class="form-label fw-bold">Nombre de la receta</label> <label for="inputName" class="form-label fw-bold">Nombre de la receta</label>
<input type="text" class="form-control" id="inputName"> <input type="text" class="form-control" id="inputName" v-model="name">
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label for="inputDescription" class="form-label fw-bold">Descripción de la receta</label> <label for="inputDescription" class="form-label fw-bold">Descripción de la receta</label>
<textarea class="form-control" id="inputDescription" rows="5"></textarea> <textarea class="form-control" id="inputDescription" rows="5" v-model="description"></textarea>
</div> </div>
<div class="mb-4"> <div class="mb-4">
<label for="formFile" class="form-label fw-bold">Imagen de la receta</label> <label for="formFile" class="form-label fw-bold">Imagen de la receta</label>
<input class="form-control" type="file" id="formFile" accept=".jpg, .jpeg, .png, .gif"> <input class="form-control" type="file" id="formFile" accept=".jpg, .jpeg, .png, .gif" @change="handleImageUpload">
</div> </div>
<!-- Ingredientes -->
<div class="mt-5 mb-4"> <div class="mt-5 mb-4">
<div class="d-flex justify-content-between align-items-center mb-2"> <div class="d-flex justify-content-between align-items-center mb-2">
<label class="form-label fw-bold">Ingredientes</label> <label class="form-label fw-bold">Ingredientes</label>
<button @click="addIngredient" class="btn btn-outline btn-sm"> <button type="button" @click="addIngredient" class="btn btn-outline btn-sm">
<i class="bi bi-plus"></i> Añadir <i class="bi bi-plus"></i> Añadir
</button> </button>
</div> </div>
...@@ -37,13 +45,13 @@ ...@@ -37,13 +45,13 @@
<input type="number" class="form-control" v-model="ingredient.quantity" placeholder="Ej: 2"> <input type="number" class="form-control" v-model="ingredient.quantity" placeholder="Ej: 2">
</div> </div>
<div class="col-3"> <div class="col-3">
<input type="text" class="form-control" v-model="ingredient.unit" placeholder="Ej: tazas"> <input type="text" class="form-control" v-model="ingredient.unitOfMeasure" placeholder="Ej: tazas">
</div> </div>
<div class="col-4"> <div class="col-4">
<input type="text" class="form-control" v-model="ingredient.ingredient" placeholder="Ej: harina de trigo"> <input type="text" class="form-control" v-model="ingredient.name" placeholder="Ej: harina de trigo">
</div> </div>
<div class="col-2 d-flex justify-content-center"> <div class="col-2 d-flex justify-content-center">
<button @click="removeIngredient(ingredient.id)" class="btn btn-outline-danger btn-sm"> <button type="button" @click="removeIngredient(ingredient.id)" class="btn btn-outline-danger btn-sm">
<i class="bi bi-trash"></i> <i class="bi bi-trash"></i>
</button> </button>
</div> </div>
...@@ -51,10 +59,11 @@ ...@@ -51,10 +59,11 @@
</div> </div>
</div> </div>
<!-- Pasos -->
<div class="mt-5 mb-4"> <div class="mt-5 mb-4">
<div class="d-flex justify-content-between align-items-center mb-2"> <div class="d-flex justify-content-between align-items-center mb-2">
<label class="form-label fw-bold">Pasos de preparación</label> <label class="form-label fw-bold">Pasos de preparación</label>
<button @click="addStep" class="btn btn-outline btn-sm"> <button type="button" @click="addStep" class="btn btn-outline btn-sm">
<i class="bi bi-plus"></i> Añadir <i class="bi bi-plus"></i> Añadir
</button> </button>
</div> </div>
...@@ -72,7 +81,7 @@ ...@@ -72,7 +81,7 @@
<textarea class="form-control" v-model="step.description" rows="1"></textarea> <textarea class="form-control" v-model="step.description" rows="1"></textarea>
</div> </div>
<div class="col-2 d-flex justify-content-center"> <div class="col-2 d-flex justify-content-center">
<button @click="removeStep(step.number)" class="btn btn-outline-danger btn-sm"> <button type="button" @click="removeStep(step.number)" class="btn btn-outline-danger btn-sm">
<i class="bi bi-trash"></i> <i class="bi bi-trash"></i>
</button> </button>
</div> </div>
...@@ -83,7 +92,7 @@ ...@@ -83,7 +92,7 @@
<div class="d-flex justify-content-end mt-4"> <div class="d-flex justify-content-end mt-4">
<button type="submit" class="btn btn-primary-custom px-4">Crear Receta</button> <button type="submit" class="btn btn-primary-custom px-4">Crear Receta</button>
</div> </div>
</form>
</div> </div>
</div> </div>
</div> </div>
...@@ -91,18 +100,86 @@ ...@@ -91,18 +100,86 @@
</template> </template>
<script setup> <script setup>
import { useRecipeStore } from '@/stores/recipeStore';
import { ref } from 'vue'; import { ref } from 'vue';
import { useRouter } from 'vue-router';
const recipeStore = useRecipeStore();
const router = useRouter();
// Datos de receta
const name = ref('');
const description = ref('');
const picture = ref(null);
const ingredients = ref([ const ingredients = ref([
{ id: 1, quantity: '', unit: '', ingredient: '' } { id: 1, name: '', quantity: '', unitOfMeasure: '' }
]); ]);
const nextId = ref(2); const steps = ref([
{ number:1, description: '' }
]);
const errorMsgs = ref([]);
// Función para crear la receta
async function handleCreation() {
errorMsgs.value = [];
try {
// Formato para subir archivos
const formData = new FormData();
formData.append('name', name.value);
formData.append('description', description.value);
// Solo agrega la imagen si existe
if (picture.value) {
formData.append('picture', picture.value);
}
// Filtra y adjunta solo los ingredientes que no tienen campos obligatorios vacíos
const filledIngredients = ingredients.value.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);
});
// Filtra y re-indexa los pasos antes de enviarlos
const filledSteps = steps.value.filter(step => step.description);
filledSteps.forEach((step, index) => {
// Re-calcula el número de paso antes de enviarlo
formData.append(`steps[${index}].number`, index + 1);
formData.append(`steps[${index}].description`, step.description);
});
await recipeStore.create(formData);
router.push('/recipes');
} catch (error) {
// Limpia la imagen y el campo del formulario
picture.value = null;
document.getElementById('formFile').value = '';
// Verifica que la respuesta de error existe y tiene el mensaje
if (error.response && error.response.status === 401) {
errorMsgs.value = ['Error de autenticación. Por favor, inicia sesión.'];
} else if (error.response && error.response.data && error.response.data.errorMsg) {
// Divide la cadena de mensajes y la asigna al array
errorMsgs.value = error.response.data.errorMsg.split('; ');
} else {
errorMsgs.value = ['Ocurrió un error inesperado. Inténtalo de nuevo.'];
}
}
};
// Funciones para añadir/eliminar ingredientes
const addIngredient = () => { const addIngredient = () => {
const nextId = ingredients.value.length > 0 ? Math.max(...ingredients.value.map(i => i.id)) + 1 : 1;
ingredients.value.push({ ingredients.value.push({
id: nextId.value++, id: nextId,
quantity: '', quantity: '',
unit: '', unitOfMeasure: '',
ingredient: '' ingredient: ''
}); });
}; };
...@@ -111,12 +188,10 @@ const removeIngredient = (id) => { ...@@ -111,12 +188,10 @@ const removeIngredient = (id) => {
ingredients.value = ingredients.value.filter(item => item.id !== id); ingredients.value = ingredients.value.filter(item => item.id !== id);
}; };
const steps = ref([ // Funciones para añadir/eliminar ingredientes
{ description: '' }
]);
const addStep = () => { const addStep = () => {
steps.value.push({ steps.value.push({
number: steps.value.length + 1,
description: '' description: ''
}); });
}; };
...@@ -124,6 +199,14 @@ const addStep = () => { ...@@ -124,6 +199,14 @@ const addStep = () => {
const removeStep = (index) => { const removeStep = (index) => {
steps.value.splice(index, 1); steps.value.splice(index, 1);
}; };
// Función para importar imagen
const handleImageUpload = (event) => {
const file = event.target.files[0];
if (file) {
picture.value = file; // Guarda el objeto File directamente
}
};
</script> </script>
<style scoped> <style scoped>
......
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