mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-12-06 02:15:22 -05:00
fix: Refactor Recipe Zip File Flow (#6170)
This commit is contained in:
@@ -377,11 +377,14 @@ async function deleteRecipe() {
|
||||
const download = useDownloader();
|
||||
|
||||
async function handleDownloadEvent() {
|
||||
const { data } = await api.recipes.getZipToken(props.slug);
|
||||
|
||||
if (data) {
|
||||
download(api.recipes.getZipRedirectUrl(props.slug, data.token), `${props.slug}.zip`);
|
||||
const { data: shareToken } = await api.recipes.share.createOne({ recipeId: props.recipeId });
|
||||
if (!shareToken) {
|
||||
console.error("No share token received");
|
||||
alert.error(i18n.t("events.something-went-wrong"));
|
||||
return;
|
||||
}
|
||||
|
||||
download(api.recipes.share.getZipRedirectUrl(shareToken.id), `${props.slug}.zip`);
|
||||
}
|
||||
|
||||
async function addRecipeToPlan() {
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import { alert } from "~/composables/use-toast";
|
||||
import { useGlobalI18n } from "~/composables/use-global-i18n";
|
||||
|
||||
export function useDownloader() {
|
||||
function download(url: string, filename: string) {
|
||||
useFetch(url, {
|
||||
method: "GET",
|
||||
responseType: "blob",
|
||||
onResponse({ response }) {
|
||||
if (!response.ok) {
|
||||
console.error("Download failed", response);
|
||||
const i18n = useGlobalI18n();
|
||||
alert.error(i18n.t("events.something-went-wrong"));
|
||||
return;
|
||||
}
|
||||
|
||||
const url = window.URL.createObjectURL(new Blob([response._data]));
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
|
||||
@@ -470,9 +470,6 @@ export interface RecipeToolSave {
|
||||
householdsWithTool?: string[];
|
||||
groupId: string;
|
||||
}
|
||||
export interface RecipeZipTokenResponse {
|
||||
token: string;
|
||||
}
|
||||
export interface SaveIngredientFood {
|
||||
id?: string | null;
|
||||
name: string;
|
||||
|
||||
@@ -6,9 +6,14 @@ const prefix = "/api";
|
||||
const routes = {
|
||||
shareToken: `${prefix}/shared/recipes`,
|
||||
shareTokenId: (id: string) => `${prefix}/shared/recipes/${id}`,
|
||||
shareTokenIdZip: (id: string) => `${prefix}/recipes/shared/${id}/zip`,
|
||||
};
|
||||
|
||||
export class RecipeShareApi extends BaseCRUDAPI<RecipeShareTokenCreate, RecipeShareToken> {
|
||||
baseRoute: string = routes.shareToken;
|
||||
itemRoute = routes.shareTokenId;
|
||||
|
||||
getZipRedirectUrl(tokenId: string) {
|
||||
return routes.shareTokenIdZip(tokenId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import type {
|
||||
CreateRecipeByUrlBulk,
|
||||
ParsedIngredient,
|
||||
UpdateImageResponse,
|
||||
RecipeZipTokenResponse,
|
||||
RecipeLastMade,
|
||||
RecipeSuggestionQuery,
|
||||
RecipeSuggestionResponse,
|
||||
@@ -46,8 +45,6 @@ const routes = {
|
||||
recipesTimelineEvent: `${prefix}/recipes/timeline/events`,
|
||||
|
||||
recipesRecipeSlug: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}`,
|
||||
recipesRecipeSlugExport: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/exports`,
|
||||
recipesRecipeSlugExportZip: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/exports/zip`,
|
||||
recipesRecipeSlugImage: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/image`,
|
||||
recipesRecipeSlugAssets: (recipe_slug: string) => `${prefix}/recipes/${recipe_slug}/assets`,
|
||||
|
||||
@@ -182,14 +179,6 @@ export class RecipeAPI extends BaseCRUDAPI<CreateRecipe, Recipe, Recipe> {
|
||||
return await this.requests.post<ParsedIngredient>(routes.recipesParseIngredient, { parser, ingredient });
|
||||
}
|
||||
|
||||
async getZipToken(recipeSlug: string) {
|
||||
return await this.requests.post<RecipeZipTokenResponse>(routes.recipesRecipeSlugExport(recipeSlug), {});
|
||||
}
|
||||
|
||||
getZipRedirectUrl(recipeSlug: string, token: string) {
|
||||
return `${routes.recipesRecipeSlugExportZip(recipeSlug)}?token=${token}`;
|
||||
}
|
||||
|
||||
async updateMany(payload: Recipe[]) {
|
||||
return await this.requests.put<Recipe[]>(routes.recipesBase, payload);
|
||||
}
|
||||
|
||||
@@ -37,14 +37,14 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import type { AxiosResponse } from "axios";
|
||||
import { useUserApi } from "~/composables/api";
|
||||
import { useGlobalI18n } from "~/composables/use-global-i18n";
|
||||
import { alert } from "~/composables/use-toast";
|
||||
import { validators } from "~/composables/use-validators";
|
||||
|
||||
export default defineNuxtComponent({
|
||||
setup() {
|
||||
const state = reactive({
|
||||
error: false,
|
||||
loading: false,
|
||||
});
|
||||
const $auth = useMealieAuth();
|
||||
@@ -54,15 +54,6 @@ export default defineNuxtComponent({
|
||||
const api = useUserApi();
|
||||
const router = useRouter();
|
||||
|
||||
function handleResponse(response: AxiosResponse<string> | null, edit = false) {
|
||||
if (response?.status !== 201) {
|
||||
state.error = true;
|
||||
state.loading = false;
|
||||
return;
|
||||
}
|
||||
router.push(`/g/${groupSlug.value}/r/${response.data}?edit=${edit.toString()}`);
|
||||
}
|
||||
|
||||
const newRecipeZip = ref<File | null>(null);
|
||||
const newRecipeZipFileName = "archive";
|
||||
|
||||
@@ -73,8 +64,21 @@ export default defineNuxtComponent({
|
||||
const formData = new FormData();
|
||||
formData.append(newRecipeZipFileName, newRecipeZip.value);
|
||||
|
||||
const { response } = await api.upload.file("/api/recipes/create/zip", formData);
|
||||
handleResponse(response);
|
||||
try {
|
||||
const response = await api.upload.file("/api/recipes/create/zip", formData);
|
||||
if (response?.status !== 201) {
|
||||
throw new Error("Failed to upload zip");
|
||||
}
|
||||
router.push(`/g/${groupSlug.value}/r/${response.data}`);
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
const i18n = useGlobalI18n();
|
||||
alert.error(i18n.t("events.something-went-wrong"));
|
||||
}
|
||||
finally {
|
||||
state.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user