From 6b5c597dcb9f8f85eda9ce4f5f678f958d979913 Mon Sep 17 00:00:00 2001 From: MohamedBassem Date: Sat, 21 Sep 2024 14:42:58 +0000 Subject: refactor: Extract useUpload into its own reusable hook --- apps/web/components/dashboard/UploadDropzone.tsx | 24 +++------------ apps/web/lib/hooks/upload-file.ts | 38 ++++++++++++++++++++++++ packages/shared/types/uploads.ts | 2 ++ 3 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 apps/web/lib/hooks/upload-file.ts diff --git a/apps/web/components/dashboard/UploadDropzone.tsx b/apps/web/components/dashboard/UploadDropzone.tsx index 05e8901e..e57f9294 100644 --- a/apps/web/components/dashboard/UploadDropzone.tsx +++ b/apps/web/components/dashboard/UploadDropzone.tsx @@ -1,6 +1,7 @@ "use client"; import React, { useCallback, useState } from "react"; +import useUpload from "@/lib/hooks/upload-file"; import { parseNetscapeBookmarkFile } from "@/lib/netscapeBookmarkParser"; import { cn } from "@/lib/utils"; import { useMutation } from "@tanstack/react-query"; @@ -9,10 +10,6 @@ import DropZone from "react-dropzone"; import { useCreateBookmarkWithPostHook } from "@hoarder/shared-react/hooks/bookmarks"; import { BookmarkTypes } from "@hoarder/shared/types/bookmarks"; -import { - zUploadErrorSchema, - zUploadResponseSchema, -} from "@hoarder/shared/types/uploads"; import LoadingSpinner from "../ui/spinner"; import { toast } from "../ui/use-toast"; @@ -35,26 +32,13 @@ export function useUploadAsset() { }, }); - const { mutateAsync: runUploadAsset } = useMutation({ - mutationFn: async (file: File) => { - const formData = new FormData(); - formData.append("file", file); - const resp = await fetch("/api/assets", { - method: "POST", - body: formData, - }); - if (!resp.ok) { - throw new Error(await resp.text()); - } - return zUploadResponseSchema.parse(await resp.json()); - }, + const { mutateAsync: runUploadAsset } = useUpload({ onSuccess: async (resp) => { const assetType = resp.contentType === "application/pdf" ? "pdf" : "image"; - return createBookmark({ ...resp, type: BookmarkTypes.ASSET, assetType }); + await createBookmark({ ...resp, type: BookmarkTypes.ASSET, assetType }); }, - onError: (error, req) => { - const err = zUploadErrorSchema.parse(JSON.parse(error.message)); + onError: (err, req) => { toast({ description: `${req.name}: ${err.error}`, variant: "destructive", diff --git a/apps/web/lib/hooks/upload-file.ts b/apps/web/lib/hooks/upload-file.ts new file mode 100644 index 00000000..42d1cb42 --- /dev/null +++ b/apps/web/lib/hooks/upload-file.ts @@ -0,0 +1,38 @@ +import { useMutation } from "@tanstack/react-query"; + +import { + ZUploadError, + zUploadErrorSchema, + ZUploadResponse, + zUploadResponseSchema, +} from "@hoarder/shared/types/uploads"; + +export default function useUpload({ + onSuccess, + onError, +}: { + onError?: (e: ZUploadError, req: File) => void; + onSuccess?: (resp: ZUploadResponse, req: File) => Promise; +}) { + return useMutation({ + mutationFn: async (file: File) => { + const formData = new FormData(); + formData.append("file", file); + const resp = await fetch("/api/assets", { + method: "POST", + body: formData, + }); + if (!resp.ok) { + throw new Error(await resp.text()); + } + return zUploadResponseSchema.parse(await resp.json()); + }, + onSuccess: onSuccess, + onError: (error, req) => { + const err = zUploadErrorSchema.parse(JSON.parse(error.message)); + if (onError) { + onError(err, req); + } + }, + }); +} diff --git a/packages/shared/types/uploads.ts b/packages/shared/types/uploads.ts index b53b86d5..7da919a6 100644 --- a/packages/shared/types/uploads.ts +++ b/packages/shared/types/uploads.ts @@ -4,6 +4,8 @@ export const zUploadErrorSchema = z.object({ error: z.string(), }); +export type ZUploadError = z.infer; + export const zUploadResponseSchema = z.object({ assetId: z.string(), contentType: z.string(), -- cgit v1.2.3-70-g09d2