From 64d257a9e0df09a236c559d374f234fca3e71023 Mon Sep 17 00:00:00 2001 From: SkepticMystic Date: Fri, 27 Jun 2025 20:53:26 +0200 Subject: [PATCH] feat: Accept multiple images on create/image.vue --- frontend/lib/api/user/recipes/recipe.ts | 15 ++++ .../pages/g/[groupSlug]/r/create/image.vue | 74 ++++++++++--------- 2 files changed, 53 insertions(+), 36 deletions(-) diff --git a/frontend/lib/api/user/recipes/recipe.ts b/frontend/lib/api/user/recipes/recipe.ts index 72bb2e924..2c31255de 100644 --- a/frontend/lib/api/user/recipes/recipe.ts +++ b/frontend/lib/api/user/recipes/recipe.ts @@ -170,6 +170,21 @@ export class RecipeAPI extends BaseCRUDAPI { return await this.requests.post(apiRoute, formData); } + async createOneFromImages(fileObjects: (Blob | File)[], translateLanguage: string | null = null) { + const formData = new FormData(); + + fileObjects.forEach((file) => { + formData.append('images', file); + }); + + let apiRoute = routes.recipesCreateFromImage; + if (translateLanguage) { + apiRoute = `${apiRoute}?translateLanguage=${translateLanguage}`; + } + + return await this.requests.post(apiRoute, formData); + } + async parseIngredients(parser: Parser, ingredients: Array) { parser = parser || "nlp"; return await this.requests.post(routes.recipesParseIngredients, { parser, ingredients }); diff --git a/frontend/pages/g/[groupSlug]/r/create/image.vue b/frontend/pages/g/[groupSlug]/r/create/image.vue index 2d0f287e8..34f321fc4 100644 --- a/frontend/pages/g/[groupSlug]/r/create/image.vue +++ b/frontend/pages/g/[groupSlug]/r/create/image.vue @@ -17,20 +17,20 @@ align-self="center" > {{ $globals.icons.close }} @@ -42,7 +42,7 @@
@@ -59,12 +59,16 @@ - + @@ -72,7 +76,7 @@
- +

route.params.groupSlug || ""); const domUrlForm = ref(null); - const uploadedImage = ref(); - const uploadedImageName = ref(""); - const uploadedImagePreviewUrl = ref(); + const uploadedImages = ref<(Blob | File)[]>([]); + const uploadedImageNames = ref([]); + const uploadedImagesPreviewUrls = ref([]); const shouldTranslate = ref(true); - function uploadImage(fileObject: File) { - uploadedImage.value = fileObject; - uploadedImageName.value = fileObject.name; - uploadedImagePreviewUrl.value = URL.createObjectURL(fileObject); + function uploadImages(fileObjects: File[]) { + uploadedImages.value = fileObjects; + uploadedImageNames.value = fileObjects.map((file) => file.name); + uploadedImagesPreviewUrls.value = fileObjects.map((file) => URL.createObjectURL(file)); } - function updateUploadedImage(fileObject: Blob) { - uploadedImage.value = fileObject; - uploadedImagePreviewUrl.value = URL.createObjectURL(fileObject); - } - - function clearImage() { - uploadedImage.value = undefined; - uploadedImageName.value = ""; - uploadedImagePreviewUrl.value = undefined; + function clearImages() { + uploadedImages.value = []; + uploadedImageNames.value = []; + uploadedImagesPreviewUrls.value = []; } async function createRecipe() { - if (!uploadedImage.value) { + if (uploadedImages.value.length === 0) { return; } state.loading = true; const translateLanguage = shouldTranslate.value ? i18n.locale : undefined; - const { data, error } = await api.recipes.createOneFromImage(uploadedImage.value, uploadedImageName.value, translateLanguage?.value); + const { data, error } = await api.recipes.createOneFromImages(uploadedImages.value, translateLanguage?.value); if (error || !data) { alert.error(i18n.t("events.something-went-wrong")); state.loading = false; - } - else { + } else { router.push(`/g/${groupSlug.value}/r/${data}`); - }; + } + } + + function updateUploadedImage(index: number, croppedImage: Blob) { + uploadedImages.value[index] = croppedImage; } return { ...toRefs(state), domUrlForm, - uploadedImage, - uploadedImagePreviewUrl, + uploadedImages, + uploadedImagesPreviewUrls, shouldTranslate, - uploadImage, - updateUploadedImage, - clearImage, + uploadImages, + clearImages, createRecipe, + updateUploadedImage, }; }, });