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

368 lines
13 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>
);
};