mirror of
https://github.com/yusufipk/OpenFrame.git
synced 2026-09-11 17:46:06 +00:00
feat(assets): add image upload state management and update button behavior during upload
This commit is contained in:
@@ -37,38 +37,38 @@ export async function GET(
|
|||||||
// Parallelize the DB lookup and session check to narrow the timing delta
|
// Parallelize the DB lookup and session check to narrow the timing delta
|
||||||
// between "asset not found" and "asset found, access denied" responses.
|
// between "asset not found" and "asset found, access denied" responses.
|
||||||
const imageUrl = `/api/upload/image/${filename}`;
|
const imageUrl = `/api/upload/image/${filename}`;
|
||||||
const [comment, session] = await Promise.all([
|
const projectSelect = {
|
||||||
db.comment.findFirst({
|
|
||||||
where: { imageUrl },
|
|
||||||
select: {
|
|
||||||
version: {
|
|
||||||
select: {
|
|
||||||
video: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
|
||||||
projectId: true,
|
|
||||||
project: {
|
|
||||||
select: {
|
|
||||||
id: true,
|
id: true,
|
||||||
ownerId: true,
|
ownerId: true,
|
||||||
workspaceId: true,
|
workspaceId: true,
|
||||||
visibility: 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: videoSelect } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
},
|
db.videoAsset.findFirst({
|
||||||
},
|
where: { sourceUrl: imageUrl },
|
||||||
},
|
select: { video: { select: videoSelect } },
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
auth(),
|
auth(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (!comment) {
|
const video = comment?.version?.video ?? videoAsset?.video ?? null;
|
||||||
|
if (!video) {
|
||||||
return apiErrors.forbidden('Access denied');
|
return apiErrors.forbidden('Access denied');
|
||||||
}
|
}
|
||||||
|
|
||||||
const { video } = comment.version;
|
|
||||||
const access = await checkProjectAccess(video.project, session?.user?.id);
|
const access = await checkProjectAccess(video.project, session?.user?.id);
|
||||||
|
|
||||||
if (!access.hasAccess) {
|
if (!access.hasAccess) {
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ export const AssetsPane = memo(function AssetsPane({
|
|||||||
const [youtubeUrl, setYoutubeUrl] = useState('');
|
const [youtubeUrl, setYoutubeUrl] = useState('');
|
||||||
const [youtubeTitle, setYoutubeTitle] = useState('');
|
const [youtubeTitle, setYoutubeTitle] = useState('');
|
||||||
const [bunnyTitle, setBunnyTitle] = useState('');
|
const [bunnyTitle, setBunnyTitle] = useState('');
|
||||||
|
const [isUploadingImage, setIsUploadingImage] = useState(false);
|
||||||
const [isUploadingBunny, setIsUploadingBunny] = useState(false);
|
const [isUploadingBunny, setIsUploadingBunny] = useState(false);
|
||||||
const [bunnyProgress, setBunnyProgress] = useState(0);
|
const [bunnyProgress, setBunnyProgress] = useState(0);
|
||||||
const [bunnyProcessingByAssetId, setBunnyProcessingByAssetId] = useState<Record<string, boolean>>({});
|
const [bunnyProcessingByAssetId, setBunnyProcessingByAssetId] = useState<Record<string, boolean>>({});
|
||||||
@@ -290,6 +291,7 @@ export const AssetsPane = memo(function AssetsPane({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIsUploadingImage(true);
|
||||||
try {
|
try {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('image', file);
|
formData.append('image', file);
|
||||||
@@ -319,6 +321,8 @@ export const AssetsPane = memo(function AssetsPane({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to upload image asset:', error);
|
console.error('Failed to upload image asset:', error);
|
||||||
toast.error('Failed to upload image');
|
toast.error('Failed to upload image');
|
||||||
|
} finally {
|
||||||
|
setIsUploadingImage(false);
|
||||||
}
|
}
|
||||||
}, [videoId, getGuestUploadToken, createAsset, imageTitle]);
|
}, [videoId, getGuestUploadToken, createAsset, imageTitle]);
|
||||||
|
|
||||||
@@ -807,7 +811,7 @@ export const AssetsPane = memo(function AssetsPane({
|
|||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
className="w-full"
|
className="w-full"
|
||||||
disabled={isCreatingAsset}
|
disabled={isUploadingImage || isCreatingAsset}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (pendingImageFile) {
|
if (pendingImageFile) {
|
||||||
void handleImageUpload(pendingImageFile);
|
void handleImageUpload(pendingImageFile);
|
||||||
@@ -816,8 +820,10 @@ export const AssetsPane = memo(function AssetsPane({
|
|||||||
imageInputRef.current?.click();
|
imageInputRef.current?.click();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<UploadCloud className="h-4 w-4 mr-2" />
|
{isUploadingImage || isCreatingAsset
|
||||||
{pendingImageFile ? 'Upload Image' : 'Select Image'}
|
? <Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||||
|
: <UploadCloud className="h-4 w-4 mr-2" />}
|
||||||
|
{isUploadingImage ? 'Uploading...' : isCreatingAsset ? 'Saving...' : pendingImageFile ? 'Upload Image' : 'Select Image'}
|
||||||
</Button>
|
</Button>
|
||||||
<input
|
<input
|
||||||
ref={imageInputRef}
|
ref={imageInputRef}
|
||||||
|
|||||||
Reference in New Issue
Block a user