"use client"; import { useState } from "react"; import { Button } from "@/components/ui/button"; import { ShotCard } from "@/components/shots/ShotCard"; import { NewShotDialog } from "@/components/shots/NewShotDialog"; import { ImportShotsDialog } from "@/components/shots/ImportShotsDialog"; import { AssetCard } from "@/components/assets/AssetCard"; import { NewAssetDialog } from "@/components/assets/NewAssetDialog"; import { TaskCard } from "@/components/tasks/TaskCard"; import { NewTaskDialog } from "@/components/tasks/NewTaskDialog"; import { KanbanBoard } from "@/components/tasks/KanbanBoard"; import { cn } from "@/lib/utils"; import { Film, Package, ListTodo, LayoutDashboard, Plus, Settings, FileUp, ChevronDown, ChevronRight } from "lucide-react"; import type { ShotWithDetails } from "@/types"; import { ProjectSettingsTab } from "@/components/projects/ProjectSettingsTab"; type Tab = "shots" | "assets" | "tasks" | "kanban" | "settings"; interface Artist { id: string; name: string | null; email: string; } interface Client { id: string; company: string; } interface TeamMember { id: string; name: string | null; email: string; role: string; } interface ProjectTabsClientProps { projectId: string; projectType: "STANDARD" | "EPISODIC"; projectSettings: { id: string; name: string; code: string; showId: string; projectType: "STANDARD" | "EPISODIC"; description: string | null; status: string; clientId: string | null; producerId: string | null; supervisorId: string | null; dueDate: Date | null; startDate: Date | null; slackWebhook: string | null; slackChannel: string | null; }; clients: Client[]; teamMembers: TeamMember[]; shots: ShotWithDetails[]; assets: any[]; tasks: any[]; artists: Artist[]; canManage: boolean; } export function ProjectTabsClient({ projectId, projectType, projectSettings, clients, teamMembers, shots, assets, tasks, artists, canManage, }: ProjectTabsClientProps) { const [activeTab, setActiveTab] = useState("shots"); const [showNewShot, setShowNewShot] = useState(false); const [showImportShots, setShowImportShots] = useState(false); const [showNewAsset, setShowNewAsset] = useState(false); const [showNewTask, setShowNewTask] = useState(false); const [collapsedEpisodes, setCollapsedEpisodes] = useState>(new Set()); const toggleEpisode = (ep: string) => setCollapsedEpisodes((prev) => { const next = new Set(prev); next.has(ep) ? next.delete(ep) : next.add(ep); return next; }); // For episodic projects: group and sort shots by episode → scene → shotNumber const episodeGroups: [string, ShotWithDetails[]][] = projectType === "EPISODIC" ? (() => { const sorted = [...shots].sort((a, b) => { const ea = a.episode ?? ""; const eb = b.episode ?? ""; if (ea !== eb) return ea.localeCompare(eb, undefined, { numeric: true }); if (a.scene !== b.scene) return a.scene.localeCompare(b.scene, undefined, { numeric: true }); return a.shotNumber - b.shotNumber; }); const map = new Map(); for (const shot of sorted) { const key = shot.episode ?? "(No Episode)"; if (!map.has(key)) map.set(key, []); map.get(key)!.push(shot); } return Array.from(map.entries()); })() : []; const tabs: { id: Tab; label: string; icon: React.ElementType; count: number; managerOnly?: boolean }[] = [ { id: "shots", label: "Shots", icon: Film, count: shots.length }, { id: "assets", label: "Assets", icon: Package, count: assets.length }, { id: "tasks", label: "All Tasks", icon: ListTodo, count: tasks.length }, { id: "kanban", label: "Kanban", icon: LayoutDashboard, count: 0 }, { id: "settings", label: "Settings", icon: Settings, count: 0, managerOnly: true }, ]; const visibleTabs = tabs.filter((t) => !t.managerOnly || canManage); return (
{/* Tab bar */}
{visibleTabs.map((tab) => { const Icon = tab.icon; return ( ); })}
{/* Context-sensitive add button */} {canManage && (
{activeTab === "shots" && (
)} {activeTab === "assets" && ( )} {(activeTab === "tasks" || activeTab === "kanban") && ( )}
)}
{/* Tab content */} {activeTab === "shots" && (
{shots.length === 0 ? ( ) : projectType === "EPISODIC" ? (
{episodeGroups.map(([episode, episodeShots]) => { const collapsed = collapsedEpisodes.has(episode); return (
{!collapsed && (
{episodeShots.map((shot) => ( ))}
)}
); })}
) : (
{shots.map((shot) => ( ))}
)}
)} {activeTab === "assets" && (
{assets.length === 0 ? ( ) : ( assets.map((asset) => ( )) )}
)} {activeTab === "tasks" && (
{tasks.length === 0 ? ( ) : ( tasks.map((task) => ( )) )}
)} {activeTab === "kanban" && ( )} {activeTab === "settings" && canManage && ( )} {/* Dialogs */} setShowNewShot(false)} onSuccess={() => setShowNewShot(false)} /> setShowImportShots(false)} onSuccess={() => setShowImportShots(false)} /> setShowNewAsset(false)} onSuccess={() => setShowNewAsset(false)} /> setShowNewTask(false)} onSuccess={() => setShowNewTask(false)} />
); } function EmptyState({ icon: Icon, label }: { icon: React.ElementType; label: string }) { return (

{label}

); }