2026-01-07 09:31:02 +00:00
|
|
|
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';
|
2026-01-13 18:47:57 +00:00
|
|
|
import {
|
|
|
|
|
ArrowLeft,
|
|
|
|
|
Play,
|
|
|
|
|
Users,
|
|
|
|
|
FileAudio,
|
|
|
|
|
Save,
|
|
|
|
|
Trash2,
|
|
|
|
|
HardDrive,
|
|
|
|
|
Share2,
|
|
|
|
|
MoreHorizontal,
|
|
|
|
|
Activity,
|
|
|
|
|
History,
|
|
|
|
|
Upload,
|
2026-01-07 09:31:02 +00:00
|
|
|
} from 'lucide-react';
|
|
|
|
|
import { useToast } from '../../../context/ToastContext';
|
|
|
|
|
|
|
|
|
|
interface ProjectDetailViewProps {
|
2026-01-13 18:47:57 +00:00
|
|
|
project: any;
|
|
|
|
|
onBack: () => void;
|
|
|
|
|
onUpdate: (updatedProject: any) => void;
|
|
|
|
|
onDelete: (id: string) => void;
|
2026-01-07 09:31:02 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
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);
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
// 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',
|
|
|
|
|
},
|
|
|
|
|
]);
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
const handleSaveSettings = () => {
|
|
|
|
|
onUpdate(formData);
|
|
|
|
|
setEditMode(false);
|
|
|
|
|
addToast('Project settings saved', 'success');
|
|
|
|
|
};
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
const handleDelete = () => {
|
|
|
|
|
if (confirm('Are you sure? This action cannot be undone.')) {
|
|
|
|
|
onDelete(project.id);
|
|
|
|
|
}
|
|
|
|
|
};
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
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'
|
|
|
|
|
}
|
|
|
|
|
/>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
<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>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
</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>
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
{/* 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>
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
<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>
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
<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>
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
<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>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
<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>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
{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}
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
<div className="text-xs text-gray-500">
|
|
|
|
|
{file.size} • {file.date}
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
</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 })
|
|
|
|
|
}
|
|
|
|
|
/>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
<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>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
</Card>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2026-01-07 09:31:02 +00:00
|
|
|
};
|