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
6886296a
authored
Sep 04, 2025
by
Alba María Álvarez
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
feat(CreateRecipe): añadida funcionalidad para crear recetas
parent
e0aaa80e
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
101 additions
and
18 deletions
src/views/CreateRecipe.vue
src/views/CreateRecipe.vue
View file @
6886296a
...
@@ -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=
"inputN
ame"
>
<input
type=
"text"
class=
"form-control"
id=
"inputName"
v-model=
"n
ame"
>
</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
:
''
,
unit
OfMeasure
:
''
,
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
>
...
...
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