From 8a12bb484b2f9a78802747c9285136cf666e2d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yusuf=20=C4=B0pek?= Date: Tue, 14 Apr 2026 13:41:41 +0300 Subject: [PATCH] feat(assets): add image upload state management and update button behavior during upload --- app/api/upload/image/[filename]/route.ts | 38 ++++++++++++------------ components/video-page/assets-pane.tsx | 12 ++++++-- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/app/api/upload/image/[filename]/route.ts b/app/api/upload/image/[filename]/route.ts index 272bfcf..d80554b 100644 --- a/app/api/upload/image/[filename]/route.ts +++ b/app/api/upload/image/[filename]/route.ts @@ -37,38 +37,38 @@ export async function GET( // Parallelize the DB lookup and session check to narrow the timing delta // between "asset not found" and "asset found, access denied" responses. const imageUrl = `/api/upload/image/${filename}`; - const [comment, session] = await Promise.all([ + const projectSelect = { + id: true, + ownerId: true, + workspaceId: true, + visibility: true, + } as const; + const videoSelect = { + id: true, + projectId: true, + project: { select: projectSelect }, + } as const; + const [comment, videoAsset, session] = await Promise.all([ db.comment.findFirst({ where: { imageUrl }, select: { version: { - select: { - video: { - select: { - id: true, - projectId: true, - project: { - select: { - id: true, - ownerId: true, - workspaceId: true, - visibility: true, - }, - }, - }, - }, - }, + select: { video: { select: videoSelect } }, }, }, }), + db.videoAsset.findFirst({ + where: { sourceUrl: imageUrl }, + select: { video: { select: videoSelect } }, + }), auth(), ]); - if (!comment) { + const video = comment?.version?.video ?? videoAsset?.video ?? null; + if (!video) { return apiErrors.forbidden('Access denied'); } - const { video } = comment.version; const access = await checkProjectAccess(video.project, session?.user?.id); if (!access.hasAccess) { diff --git a/components/video-page/assets-pane.tsx b/components/video-page/assets-pane.tsx index 5e20697..30b37a6 100644 --- a/components/video-page/assets-pane.tsx +++ b/components/video-page/assets-pane.tsx @@ -109,6 +109,7 @@ export const AssetsPane = memo(function AssetsPane({ const [youtubeUrl, setYoutubeUrl] = useState(''); const [youtubeTitle, setYoutubeTitle] = useState(''); const [bunnyTitle, setBunnyTitle] = useState(''); + const [isUploadingImage, setIsUploadingImage] = useState(false); const [isUploadingBunny, setIsUploadingBunny] = useState(false); const [bunnyProgress, setBunnyProgress] = useState(0); const [bunnyProcessingByAssetId, setBunnyProcessingByAssetId] = useState>({}); @@ -290,6 +291,7 @@ export const AssetsPane = memo(function AssetsPane({ return; } + setIsUploadingImage(true); try { const formData = new FormData(); formData.append('image', file); @@ -319,6 +321,8 @@ export const AssetsPane = memo(function AssetsPane({ } catch (error) { console.error('Failed to upload image asset:', error); toast.error('Failed to upload image'); + } finally { + setIsUploadingImage(false); } }, [videoId, getGuestUploadToken, createAsset, imageTitle]); @@ -807,7 +811,7 @@ export const AssetsPane = memo(function AssetsPane({