feat(video-upload): add global drag-and-drop uploader with project selection and permission gating

This commit is contained in:
Yusuf İpek
2026-02-26 10:31:51 +03:00
parent 15fa9452a4
commit 6dd44953a3
6 changed files with 606 additions and 10 deletions
+10 -1
View File
@@ -1,6 +1,7 @@
'use client';
import { ProjectFilter } from './project-filter';
import { VideoDragDropUploader } from '@/components/video-drag-drop-uploader';
interface SerializedProject {
id: string;
@@ -19,11 +20,19 @@ interface DashboardClientProps {
workspaces: { id: string; name: string }[];
totalPages: number;
canCreateProjects: boolean;
canUploadVideos: boolean;
}
export function DashboardClient({ serializedProjects, workspaces, totalPages, canCreateProjects }: DashboardClientProps) {
export function DashboardClient({
serializedProjects,
workspaces,
totalPages,
canCreateProjects,
canUploadVideos,
}: DashboardClientProps) {
return (
<div className="px-6 lg:px-8 py-8 w-full">
<VideoDragDropUploader canUpload={canUploadVideos} />
<ProjectFilter
projects={serializedProjects}
workspaces={workspaces}
+29 -8
View File
@@ -49,15 +49,35 @@ export default async function DashboardPage({
distinct: ['workspaceId']
});
const creatableWorkspaces = await db.workspace.count({
where: {
OR: [
{ ownerId: session.user.id },
{ members: { some: { userId: session.user.id, role: 'ADMIN' } } },
],
},
});
const [creatableWorkspaces, editableProject] = await Promise.all([
db.workspace.count({
where: {
OR: [
{ ownerId: session.user.id },
{ members: { some: { userId: session.user.id, role: 'ADMIN' } } },
],
},
}),
db.project.findFirst({
where: {
OR: [
{ ownerId: session.user.id },
{ members: { some: { userId: session.user.id, role: 'ADMIN' } } },
{
workspace: {
OR: [
{ ownerId: session.user.id },
{ members: { some: { userId: session.user.id, role: 'ADMIN' } } },
],
},
},
],
},
select: { id: true },
}),
]);
const canCreateProjects = creatableWorkspaces > 0;
const canUploadVideos = Boolean(editableProject);
const workspaceMap = new Map<string, string>();
for (const project of accessibleProjects) {
@@ -116,6 +136,7 @@ export default async function DashboardPage({
workspaces={workspaces}
totalPages={totalPages}
canCreateProjects={canCreateProjects}
canUploadVideos={canUploadVideos}
/>
);
}
@@ -20,6 +20,7 @@ import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { VideoCard } from '@/components/video-card';
import { VideoDragDropUploader } from '@/components/video-drag-drop-uploader';
interface SerializedVideo {
id: string;
@@ -93,6 +94,12 @@ export function ProjectContentClient({
return (
<>
<VideoDragDropUploader
fixedProjectId={projectId}
fixedProjectName={project.name}
canUpload={canEdit}
/>
{/* Project Header */}
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-8">
<div>
@@ -16,6 +16,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
import { Badge } from '@/components/ui/badge';
import { auth } from '@/lib/auth';
import { db } from '@/lib/db';
import { VideoDragDropUploader } from '@/components/video-drag-drop-uploader';
function VisibilityIcon({ visibility }: { visibility: string }) {
switch (visibility) {
@@ -102,6 +103,10 @@ export default async function WorkspacePage({ params, searchParams }: WorkspaceP
return (
<div className="px-6 lg:px-8 py-8 w-full">
<VideoDragDropUploader
workspaceId={workspaceId}
canUpload={isAdmin && workspace._count.projects > 0}
/>
{/* Back & Header */}
<div className="mb-6">
<Link