Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Alba María Álvarez
/
front_recipes
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
0d8bb021
authored
Sep 05, 2025
by
Alba María Álvarez
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
feat(RecipeDetail): implementada funcionalidad para la edición de recetas
parent
f39ba4c2
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
88 additions
and
31 deletions
src/views/RecipeDetail.vue
src/views/RecipeDetail.vue
View file @
0d8bb021
...
...
@@ -11,7 +11,7 @@
</span>
<div
v-if=
"mode === 'view'"
class=
"d-flex gap-2"
>
<button
@
click=
"
edit
Recipe"
class=
"btn btn-outline-custom"
>
<button
@
click=
"
update
Recipe"
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=
"r
ecipe.name"
class=
"form-control form-control-lg text-center mb-2"
/>
<input
v-else
type=
"text"
id=
"recipeTitle"
v-model=
"editableR
ecipe.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"
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>
<img
:src=
"recipe.picture ? recipe.picture : defaultImage"
class=
"img-fluid rounded shadow-sm"
alt=
"Imagen de la receta"
/>
</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
r
ecipe.ingredients"
:key=
"index"
class=
"input-group mb-2"
>
<div
v-for=
"(ing, index) in
editableR
ecipe.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=
"
r
ecipe.ingredients.splice(index, 1)"
class=
"btn btn-outline-danger"
type=
"button"
><i
class=
"bi bi-trash"
></i></button>
<input
type=
"text"
v-model=
"ing.unit
OfMeasure
"
class=
"form-control"
placeholder=
"Unidad"
>
<input
type=
"text"
v-model=
"ing.
name
"
class=
"form-control"
placeholder=
"Ingrediente"
>
<button
@
click=
"
editableR
ecipe.ingredients.splice(index, 1)"
class=
"btn btn-outline-danger"
type=
"button"
><i
class=
"bi bi-trash"
></i></button>
</div>
<button
@
click=
"
r
ecipe.ingredients.push({ quantity: '', unit: '', ingredient: '' })"
class=
"btn btn-outline-primary-custom mt-2 w-100"
>
<button
@
click=
"
editableR
ecipe.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
r
ecipe.steps"
:key=
"index"
class=
"input-group mb-2"
>
<div
v-for=
"(step, index) in
editableR
ecipe.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
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment