feat(RecipeDetail): implementada funcionalidad para ver una receta en detalle

parent eae49825
Showing with 65 additions and 89 deletions
<template> <template>
<div class="container my-5" v-if="recipe"> <div v-if="recipe" class="container my-5">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-lg-10 col-md-11"> <div class="col-lg-10 col-md-11">
<div class="card h-100 card-custom"> <div class="card h-100 card-custom">
<div class="card-body p-5"> <div class="card-body p-5">
<div class="d-flex justify-content-end mb-4"> <div class="d-flex justify-content-between align-items-center mb-4">
<span v-if="recipe.favorite"
class="badge badge-custom px-3 py-2 shadow-sm">
<i class="bi bi-heart-fill"></i> Favorita
</span>
<div v-if="mode === 'view'" class="d-flex gap-2"> <div v-if="mode === 'view'" class="d-flex gap-2">
<button @click="editRecipe" class="btn btn-outline-custom"> <button @click="editRecipe" class="btn btn-outline-custom">
<i class="bi bi-pencil-square"></i> Editar <i class="bi bi-pencil-square"></i> Editar
...@@ -13,6 +18,7 @@ ...@@ -13,6 +18,7 @@
<i class="bi bi-trash"></i> Eliminar <i class="bi bi-trash"></i> Eliminar
</button> </button>
</div> </div>
<div v-else class="d-flex gap-2"> <div v-else class="d-flex gap-2">
<button @click="saveChanges" class="btn btn-primary-custom"> <button @click="saveChanges" class="btn btn-primary-custom">
<i class="bi bi-save"></i> Guardar <i class="bi bi-save"></i> Guardar
...@@ -28,25 +34,25 @@ ...@@ -28,25 +34,25 @@
<input v-else type="text" v-model="recipe.name" class="form-control form-control-lg text-center mb-2" /> <input v-else type="text" v-model="recipe.name" class="form-control form-control-lg text-center mb-2" />
<div class="d-flex justify-content-center align-items-center flex-wrap gap-3 mb-4"> <div class="d-flex justify-content-center align-items-center flex-wrap gap-3 mb-4">
<p v-if="mode === 'view'" class="text-muted small mb-0"> <p v-if="mode === 'view' && recipe.createdAt != null" class="text-muted small mb-0">
Creado el **{{ formattedDate }}** Creado el {{ formattedDate }}
</p> </p>
<button class="btn btn-sm" >
<i :class="recipe.favorite ? 'bi-star-fill' : 'bi-star'"></i>
</button>
</div> </div>
<div class="mb-4 mt-3"> <div class="mb-4 mt-3 text-center">
<img v-if="mode === 'view'" <div class="image-container mx-auto">
:src="recipe.image" <template v-if="mode === 'view'">
class="img-fluid rounded shadow-sm" <img :src="recipe.picture ? recipe.picture : defaultImage"
style="max-height: 500px; max-width: 100%; object-fit: cover;" class="img-fluid rounded shadow-sm"
alt="Imagen de la receta" /> alt="Imagen de la receta" />
<div v-else class="text-center d-flex flex-column align-items-center"> </template>
<label class="form-label fw-bold">Cambiar imagen</label> <div v-else class="d-flex flex-column align-items-center">
<input type="file" class="form-control" /> <label class="form-label fw-bold">Cambiar imagen</label>
<input type="file" class="form-control" />
</div>
</div> </div>
</div> </div>
<p v-if="mode === 'view'" class="text-muted">{{ recipe.description }}</p> <p v-if="mode === 'view'" class="text-muted">{{ recipe.description }}</p>
<textarea v-else <textarea v-else
...@@ -64,9 +70,9 @@ ...@@ -64,9 +70,9 @@
<div class="mb-4"> <div class="mb-4">
<h5 class="fw-bold">Ingredientes</h5> <h5 class="fw-bold">Ingredientes</h5>
<ul v-if="mode === 'view'" class="list-unstyled"> <ul v-if="mode === 'view'" class="list-unstyled">
<li v-for="(ing, index) in recipe.ingredients" :key="index" class="mb-1"> <li v-for="(ing, index) in processedIngredients" :key="index" class="mb-1">
<i class="bi bi-check-circle-fill me-2 text-success"></i> <i class="bi bi-check-circle-fill me-2 text-success"></i>
{{ ing.quantity }} {{ ing.unit }} de {{ ing.ingredient }} {{ ing.quantity }} {{ ing.unit }} {{ ing.connective }} {{ ing.name }}
</li> </li>
</ul> </ul>
<div v-else class="ingredient-form-section"> <div v-else class="ingredient-form-section">
...@@ -120,6 +126,7 @@ ...@@ -120,6 +126,7 @@
import { useRecipeStore } from '@/stores/recipeStore'; import { useRecipeStore } from '@/stores/recipeStore';
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import defaultImage from '@/assets/default-recipe.jpg';
// Estado de la vista: 'view' o 'edit' // Estado de la vista: 'view' o 'edit'
const mode = ref('view'); const mode = ref('view');
...@@ -131,81 +138,33 @@ const route = useRoute(); ...@@ -131,81 +138,33 @@ const route = useRoute();
const recipe = computed(() => recipeStore.recipe); const recipe = computed(() => recipeStore.recipe);
onMounted(async () => { onMounted(async () => {
// Corregir la forma de acceder al ID de la ruta
const recipeId = route.params.id; const recipeId = route.params.id;
await recipeStore.readDetail(recipeId); await recipeStore.readDetail(recipeId);
}); });
// Formatear la fecha para una visualización profesional // Propiedad computada para formatear la fecha
const formattedDate = computed(() => { const formattedDate = computed(() => {
if (recipe.value && recipe.value.createdAt) { const options = { year: 'numeric', month: 'long', day: 'numeric' };
const options = { year: 'numeric', month: 'long', day: 'numeric' }; return new Date(recipe.value.createdAt).toLocaleDateString('es-ES', options);
return new Date(recipe.value.createdAt).toLocaleDateString('es-ES', options);
}
return 'Fecha no disponible';
}); });
// Datos de la receta de ejemplo // Propiedad computada para procesar los ingredientes
// const recipe = ref({ const processedIngredients = computed(() => {
// name: 'Tarta de Manzana Clásica', if (!recipe.value || !recipe.value.ingredients) {
// image: '/src/assets/default-recipe.jpg', return [];
// description: 'Una deliciosa tarta de manzana con un toque de canela y una corteza dorada y crujiente.', }
// ingredients: [ return recipe.value.ingredients.map(ing => {
// { quantity: 2, unit: 'tazas', ingredient: 'harina de trigo' }, const unit = ing.unitOfMeasure ? ing.unitOfMeasure.toLowerCase() : '';
// { quantity: 1, unit: 'taza', ingredient: 'azúcar' }, const name = ing.name ? ing.name.toLowerCase() : '';
// { quantity: 4, unit: 'unidades', ingredient: 'manzanas' } const connective = ing.unitOfMeasure ? 'de' : '';
// ], return {
// steps: [ ...ing,
// { description: 'Precalentar el horno a 180°C.' }, unit,
// { description: 'Mezclar la harina y el azúcar en un bol.' }, name,
// { description: 'Pelar y cortar las manzanas en rodajas finas.' }, connective
// { description: 'Hornear por 45 minutos.' } };
// ]
// });
// Función para el textarea
const autoGrow = (event) => {
const textarea = event.target;
textarea.style.height = 'auto'; // Resetea la altura
textarea.style.height = `${textarea.scrollHeight}px`; // Ajusta a la altura del contenido
};
// Lógica de los botones
const editRecipe = () => {
mode.value = 'edit';
nextTick(() => {
// Selecciona todos los textareas y aplica la función
document.querySelectorAll('textarea').forEach(textarea => {
autoGrow({ target: textarea });
});
});
};
const saveChanges = () => {
console.log('Guardando cambios:', recipe.value);
mode.value = 'view';
};
const deleteRecipe = () => {
console.log('Eliminando la receta:', recipe.value.name);
};
const addStep = () => {
recipe.value.steps.push({ description: '' });
nextTick(() => {
// Aplica el auto-crecimiento al nuevo textarea
const newTextarea = document.querySelector('.steps-form-section textarea:last-child');
if (newTextarea) {
autoGrow({ target: newTextarea });
}
}); });
}; });
const removeStep = (index) => {
recipe.value.steps.splice(index, 1);
};
</script> </script>
<style scoped> <style scoped>
...@@ -213,6 +172,7 @@ const removeStep = (index) => { ...@@ -213,6 +172,7 @@ const removeStep = (index) => {
border-color: #793E6C; border-color: #793E6C;
box-shadow: 0 0 1rem rgba(121, 62, 108, 0.1); box-shadow: 0 0 1rem rgba(121, 62, 108, 0.1);
border-radius: 1rem; border-radius: 1rem;
max-width: 800px;
} }
.text-primary-custom { .text-primary-custom {
...@@ -256,10 +216,6 @@ h5 { ...@@ -256,10 +216,6 @@ h5 {
color: #2C0C21; color: #2C0C21;
} }
.img-fluid {
border-radius: 0.5rem;
}
/* Modo de edición (ingredientes y pasos horizontalmente) */ /* Modo de edición (ingredientes y pasos horizontalmente) */
.ingredient-form-section .input-group, .ingredient-form-section .input-group,
.steps-form-section .input-group { .steps-form-section .input-group {
...@@ -270,4 +226,23 @@ textarea { ...@@ -270,4 +226,23 @@ textarea {
resize: none; resize: none;
overflow: hidden; overflow: hidden;
} }
/* Estilos imagen */
.image-container {
width: 400px;
height: 400px;
overflow: hidden;
}
.image-container img {
width: 100%;
height: 100%;
object-fit: contain;
}
/* Estilos span favorito */
.badge-custom {
background-color: #793E6C;
color: white;
}
</style> </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