feat: duplicate recipes (#1750)

* feature/frontend: Add duplicate button to recipe

* feature/backend: Add recipe duplication endpoint

* feature/frontend: add duplication API call

* Regenerate API docs

* Fix linter errors

* Fix backend linter error

* Move recipe duplication logic to recipe service

* Add test for recipe duplication

* Improve recipe ingredients copy test

* generate types

* import type

Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
Philipp 2022-12-01 06:57:26 +01:00 committed by GitHub
parent e73a72959c
commit 33dffccaa5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 258 additions and 25 deletions

View file

@ -13,6 +13,23 @@
{{ $t("recipe.delete-confirmation") }}
</v-card-text>
</BaseDialog>
<BaseDialog
v-model="recipeDuplicateDialog"
:title="$t('recipe.duplicate')"
color="primary"
:icon="$globals.icons.duplicate"
@confirm="duplicateRecipe()"
>
<v-card-text>
<v-text-field
v-model="recipeName"
dense
:label="$t('recipe.recipe-name')"
autofocus
@keyup.enter="duplicateRecipe()"
></v-text-field>
</v-card-text>
</BaseDialog>
<BaseDialog
v-model="mealplannerDialog"
:title="$t('recipe.add-recipe-to-mealplan')"
@ -136,6 +153,7 @@ export default defineComponent({
delete: true,
edit: true,
download: true,
duplicate: false,
mealplanner: true,
shoppingList: true,
print: true,
@ -199,6 +217,8 @@ export default defineComponent({
recipeDeleteDialog: false,
mealplannerDialog: false,
shoppingListDialog: false,
recipeDuplicateDialog: false,
recipeName: props.name,
loading: false,
menuItems: [] as ContextMenuItem[],
newMealdate: "",
@ -230,6 +250,12 @@ export default defineComponent({
color: undefined,
event: "download",
},
duplicate: {
title: i18n.tc("general.duplicate"),
icon: $globals.icons.duplicate,
color: undefined,
event: "duplicate",
},
mealplanner: {
title: i18n.tc("recipe.add-to-plan"),
icon: $globals.icons.calendar,
@ -330,6 +356,13 @@ export default defineComponent({
}
}
async function duplicateRecipe() {
const { data } = await api.recipes.duplicateOne(props.slug, state.recipeName);
if (data && data.slug) {
router.push(`/recipe/${data.slug}`);
}
}
const { copyText } = useCopy();
// Note: Print is handled as an event in the parent component
@ -339,6 +372,9 @@ export default defineComponent({
},
edit: () => router.push(`/recipe/${props.slug}` + "?edit=true"),
download: handleDownloadEvent,
duplicate: () => {
state.recipeDuplicateDialog = true;
},
mealplanner: () => {
state.mealplannerDialog = true;
},
@ -376,6 +412,7 @@ export default defineComponent({
...toRefs(state),
shoppingLists,
addRecipeToList,
duplicateRecipe,
contextMenuEventHandler,
deleteRecipe,
addRecipeToPlan,