veza/apps/web/src/components/studio/projects/ProjectDetailView.tsx

235 lines
14 KiB
TypeScript
Raw Normal View History

import React, { useState } from 'react';
import { Card } from '../../ui/card';
import { Button } from '../../ui/button';
import { Badge } from '../../ui/badge';
import { Input } from '../../ui/input';
import {
ArrowLeft, Play, Users, FileAudio, Save, Trash2,
HardDrive, Share2, MoreHorizontal,
Activity, History, Upload
} from 'lucide-react';
import { useToast } from '../../../context/ToastContext';
interface ProjectDetailViewProps {
project: any;
onBack: () => void;
onUpdate: (updatedProject: any) => void;
onDelete: (id: string) => void;
}
export const ProjectDetailView: React.FC<ProjectDetailViewProps> = ({ project, onBack, onUpdate, onDelete }) => {
const { addToast } = useToast();
const [activeTab, setActiveTab] = useState<'overview' | 'files' | 'settings'>('overview');
const [_editMode, setEditMode] = useState(false);
const [formData, setFormData] = useState(project);
// Mock Files for this project
const [projectFiles, _setProjectFiles] = useState([
{ id: 'f1', name: 'Demo_v3.mp3', size: '4.2 MB', type: 'audio', date: '2h ago' },
{ id: 'f2', name: 'Stems_Drums.zip', size: '45 MB', type: 'archive', date: '1d ago' },
{ id: 'f3', name: 'Vocals_Dry.wav', size: '22 MB', type: 'audio', date: '1d ago' },
]);
const handleSaveSettings = () => {
onUpdate(formData);
setEditMode(false);
addToast("Project settings saved", "success");
};
const handleDelete = () => {
if (confirm("Are you sure? This action cannot be undone.")) {
onDelete(project.id);
}
};
return (
<div className="animate-fadeIn pb-20 space-y-6">
{/* Header */}
<div className="flex flex-col md:flex-row justify-between items-start gap-4">
<div className="flex gap-4">
<Button variant="ghost" size="icon" onClick={onBack}><ArrowLeft className="w-5 h-5" /></Button>
<div>
<div className="flex items-center gap-3 mb-1">
<h2 className="text-3xl font-display font-bold text-white">{project.name}</h2>
<Badge
label={project.daw}
variant={project.daw === 'Ableton' ? 'cyan' : project.daw === 'FL Studio' ? 'gold' : 'magenta'}
/>
</div>
<div className="flex items-center gap-4 text-sm text-gray-400 font-mono">
<span>{project.bpm} BPM</span>
<span>{project.key}</span>
<span>Updated {project.modified}</span>
</div>
</div>
</div>
<div className="flex gap-2">
<Button variant="secondary" icon={<Share2 className="w-4 h-4" />} onClick={() => addToast("Collaboration link copied")}>Invite</Button>
<Button variant="primary" icon={<Play className="w-4 h-4 fill-current" />} onClick={() => addToast(`Opening in ${project.daw}...`, "success")}>Open DAW</Button>
</div>
</div>
{/* Navigation Tabs */}
<div className="border-b border-kodo-steel flex gap-6">
{['overview', 'files', 'settings'].map(tab => (
<button
key={tab}
onClick={() => setActiveTab(tab as any)}
className={`pb-3 text-sm font-bold uppercase tracking-wider border-b-2 transition-colors ${activeTab === tab ? 'border-kodo-cyan text-white' : 'border-transparent text-gray-500 hover:text-gray-300'}`}
>
{tab}
</button>
))}
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Main Content Area */}
<div className="lg:col-span-2 space-y-6">
{activeTab === 'overview' && (
<>
<Card variant="default">
<h3 className="font-bold text-white mb-4">Project Status</h3>
<div className="space-y-4">
<div className="flex justify-between text-sm text-gray-400 mb-1">
<span>Completion</span>
<span className="text-white">{project.progress}%</span>
</div>
<div className="h-2 bg-kodo-steel rounded-full overflow-hidden">
<div className="h-full bg-kodo-cyan" style={{width: `${project.progress}%`}}></div>
</div>
<div className="flex gap-4 pt-2">
<div className="flex-1 bg-kodo-ink p-3 rounded border border-kodo-steel">
<div className="text-xs text-gray-500 uppercase">Status</div>
<div className="text-sm font-bold text-white">{project.status}</div>
</div>
<div className="flex-1 bg-kodo-ink p-3 rounded border border-kodo-steel">
<div className="text-xs text-gray-500 uppercase">Version</div>
<div className="text-sm font-bold text-white">v1.4.2</div>
</div>
</div>
</div>
</Card>
<Card variant="default">
<div className="flex justify-between items-center mb-4">
<h3 className="font-bold text-white flex items-center gap-2"><Activity className="w-4 h-4 text-kodo-gold" /> Recent Activity</h3>
</div>
<div className="space-y-4 relative">
<div className="absolute left-2.5 top-2 bottom-2 w-px bg-kodo-steel"></div>
{[1, 2, 3].map((_, i) => (
<div key={i} className="relative pl-8">
<div className="absolute left-0 top-1 w-5 h-5 bg-kodo-graphite border border-kodo-cyan rounded-full flex items-center justify-center">
<div className="w-2 h-2 bg-kodo-cyan rounded-full"></div>
</div>
<div className="text-sm text-gray-300">
<span className="font-bold text-white">You</span> uploaded a new bounce.
</div>
<div className="text-xs text-gray-500">2 hours ago</div>
</div>
))}
</div>
</Card>
</>
)}
{activeTab === 'files' && (
<Card variant="default">
<div className="flex justify-between items-center mb-6">
<h3 className="font-bold text-white">Project Files</h3>
<Button variant="secondary" size="sm" icon={<Upload className="w-4 h-4" />}>Upload</Button>
</div>
<div className="space-y-2">
{projectFiles.map(file => (
<div key={file.id} className="flex items-center justify-between p-3 bg-kodo-ink rounded-lg border border-transparent hover:border-kodo-steel transition-all group">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-kodo-slate rounded flex items-center justify-center text-gray-400">
{file.type === 'audio' ? <FileAudio className="w-5 h-5" /> : <HardDrive className="w-5 h-5" />}
</div>
<div>
<div className="font-bold text-sm text-white">{file.name}</div>
<div className="text-xs text-gray-500">{file.size} {file.date}</div>
</div>
</div>
<div className="flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity">
<Button variant="ghost" size="icon"><Play className="w-4 h-4" /></Button>
<Button variant="ghost" size="icon"><MoreHorizontal className="w-4 h-4" /></Button>
</div>
</div>
))}
</div>
</Card>
)}
{activeTab === 'settings' && (
<div className="space-y-6">
<Card variant="default">
<h3 className="font-bold text-white mb-6 border-b border-kodo-steel pb-2">Project Settings</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<Input label="Project Name" value={formData.name} onChange={(e) => setFormData({...formData, name: e.target.value})} />
<Input label="Status" value={formData.status} onChange={(e) => setFormData({...formData, status: e.target.value})} />
</div>
<div className="grid grid-cols-2 gap-4 mb-4">
<Input label="BPM" value={formData.bpm} onChange={(e) => setFormData({...formData, bpm: e.target.value})} />
<Input label="Key" value={formData.key} onChange={(e) => setFormData({...formData, key: e.target.value})} />
</div>
<div className="flex justify-end pt-2">
<Button variant="primary" icon={<Save className="w-4 h-4" />} onClick={handleSaveSettings}>Save Changes</Button>
</div>
</Card>
<Card variant="default" className="border-kodo-red/30">
<h3 className="font-bold text-white mb-4 text-kodo-red flex items-center gap-2">
<Trash2 className="w-4 h-4" /> Danger Zone
</h3>
<p className="text-sm text-gray-400 mb-4">Permanently delete this project and all associated files.</p>
<Button variant="ghost" className="text-kodo-red border border-kodo-red/50 hover:bg-kodo-red/10 w-full" onClick={handleDelete}>
Delete Project
</Button>
</Card>
</div>
)}
</div>
{/* Sidebar */}
<div className="space-y-6">
<Card variant="gaming">
<h3 className="font-bold text-white mb-4 text-sm uppercase tracking-wider flex items-center gap-2">
<Users className="w-4 h-4 text-kodo-gold" /> Collaborators
</h3>
<div className="flex -space-x-3 mb-4">
<div className="w-10 h-10 rounded-full border-2 border-kodo-graphite bg-gray-700"></div>
<div className="w-10 h-10 rounded-full border-2 border-kodo-graphite bg-gray-600"></div>
<div className="w-10 h-10 rounded-full border-2 border-kodo-graphite bg-kodo-ink flex items-center justify-center text-xs text-gray-400 font-bold">+2</div>
</div>
<Button variant="ghost" size="sm" className="w-full text-xs border border-kodo-steel">Manage Team</Button>
</Card>
<Card variant="default">
<h3 className="font-bold text-white mb-4 text-sm uppercase tracking-wider flex items-center gap-2">
<History className="w-4 h-4 text-kodo-magenta" /> Versions
</h3>
<div className="space-y-2">
<div className="flex justify-between items-center text-sm p-2 bg-white/5 rounded">
<span className="text-white">v1.4 (Current)</span>
<span className="text-xs text-gray-500">2h ago</span>
</div>
<div className="flex justify-between items-center text-sm p-2 hover:bg-white/5 rounded cursor-pointer text-gray-400">
<span>v1.3</span>
<span className="text-xs text-gray-600">1d ago</span>
</div>
<div className="flex justify-between items-center text-sm p-2 hover:bg-white/5 rounded cursor-pointer text-gray-400">
<span>v1.2</span>
<span className="text-xs text-gray-600">3d ago</span>
</div>
</div>
</Card>
</div>
</div>
</div>
);
};