veza/apps/web/src/components/views/FileDetailsView.tsx

293 lines
9.6 KiB
TypeScript
Raw Normal View History

import React from 'react';
import { Card } from '../ui/card';
import { Button } from '../ui/button';
import { Badge } from '../ui/badge';
import { FileNode } from '../../types';
import {
ArrowLeft,
Download,
Share2,
Trash2,
Edit3,
Music,
FileText,
Play,
Activity,
Layers,
HardDrive,
Info,
} from 'lucide-react';
import { useToast } from '../../context/ToastContext';
// Extended Mock Data for Demo
const MOCK_ACTIVITY = [
{
id: 'a1',
user: 'Cyber_Producer',
action: 'uploaded',
timestamp: '2 days ago',
},
{ id: 'a2', user: 'Sarah Connor', action: 'viewed', timestamp: '1 day ago' },
{ id: 'a3', user: 'System', action: 'processed', timestamp: '2 days ago' },
];
const MOCK_VERSIONS = [
{
id: 'v1',
version: 'v1.0',
uploadedBy: 'Cyber_Producer',
timestamp: '2 days ago',
size: '24.5 MB',
url: '#',
},
{
id: 'v2',
version: 'v1.1',
uploadedBy: 'Cyber_Producer',
timestamp: '5 hours ago',
size: '24.6 MB',
url: '#',
current: true,
},
];
interface FileDetailsViewProps {
fileId: string;
onBack: () => void;
}
export const FileDetailsView: React.FC<FileDetailsViewProps> = ({
fileId,
onBack,
}) => {
const { addToast } = useToast();
// Mock fetching logic based on ID
const file: FileNode = {
id: fileId,
name: 'Neon_Nights_Final_Master.wav',
type: 'audio',
size: '48.2 MB',
modified: '2 hours ago',
status: 'ready',
metadata: {
bpm: 128,
key: 'F# Minor',
genre: 'Synthwave',
duration: '3:45',
},
};
const isAudio = file.type === 'audio';
const isImage = file.type === 'image';
return (
<div className="animate-fadeIn space-y-6 pb-20">
{/* Header */}
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<Button
variant="ghost"
size="icon"
onClick={onBack}
aria-label="Retour"
>
<ArrowLeft className="w-5 h-5" />
</Button>
<div>
<h2 className="text-2xl font-bold text-white flex items-center gap-3">
{file.name}
<Badge label={file.type} variant="terminal" />
</h2>
<p className="text-kodo-content-dim text-sm font-mono flex items-center gap-4 mt-1">
<span>{file.size}</span>
<span></span>
<span>Modified {file.modified}</span>
</p>
</div>
</div>
<div className="flex gap-2">
<Button
variant="ghost"
icon={<Share2 className="w-4 h-4" />}
onClick={() => addToast('Link copied')}
>
Share
</Button>
<Button
variant="primary"
icon={<Download className="w-4 h-4" />}
onClick={() => addToast('Downloading...')}
>
Download
</Button>
<Button
variant="ghost"
className="text-kodo-red hover:bg-kodo-red/10"
icon={<Trash2 className="w-4 h-4" />}
>
Delete
</Button>
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Left: Preview Area */}
<div className="lg:col-span-2 space-y-6">
<Card
variant="default"
className="min-h-[400px] flex items-center justify-center bg-black relative overflow-hidden group"
>
{isAudio && (
<div className="text-center w-full max-w-md">
<div className="w-32 h-32 bg-gradient-to-br from-kodo-cyan to-kodo-cyan rounded-full mx-auto mb-8 flex items-center justify-center shadow-[0_0_50px_rgba(102,252,241,0.3)] animate-pulse">
<Music className="w-12 h-12 text-black" />
</div>
<div className="h-16 flex items-center justify-center gap-1 mb-8">
{Array.from({ length: 40 }).map((_, i) => (
<div
key={i}
className="w-1.5 bg-kodo-cyan rounded-full"
style={{ height: `${Math.random() * 100}%` }}
></div>
))}
</div>
<Button
variant="primary"
size="lg"
className="rounded-full px-8"
icon={<Play className="w-5 h-5 fill-current" />}
>
PLAY PREVIEW
</Button>
</div>
)}
{isImage && (
<img
src="https://picsum.photos/id/200/800/600"
className="w-full h-full object-contain"
/>
)}
{!isAudio && !isImage && (
<div className="text-center text-kodo-content-dim">
<FileText className="w-24 h-24 mx-auto mb-4 opacity-50" />
<p>No preview available for this file type.</p>
</div>
)}
</Card>
{/* Metadata Grid */}
<Card variant="default">
<div className="flex justify-between items-center mb-6">
<h3 className="font-bold text-white flex items-center gap-2">
<Info className="w-4 h-4 text-kodo-cyan" /> Metadata
</h3>
<Button
variant="ghost"
size="sm"
icon={<Edit3 className="w-3 h-3" />}
>
Edit
</Button>
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{Object.entries(file.metadata || {}).map(([key, val]) => (
<div
key={key}
className="bg-kodo-ink p-3 rounded border border-kodo-steel/50"
>
<div className="text-xs text-kodo-content-dim uppercase font-bold mb-1">
{key}
</div>
<div className="text-white font-medium">{String(val)}</div>
</div>
))}
</div>
</Card>
</div>
{/* Right: Sidebar */}
<div className="space-y-6">
{/* Activity Feed */}
<Card variant="gaming">
<h3 className="font-bold text-white mb-4 flex items-center gap-2 text-sm uppercase tracking-wider">
<Activity className="w-4 h-4 text-kodo-gold" /> Activity Log
</h3>
<div className="space-y-4 relative">
<div className="absolute left-3 top-2 bottom-2 w-px bg-kodo-steel"></div>
{MOCK_ACTIVITY.map((act) => (
<div key={act.id} className="flex gap-3 relative">
<div className="w-6 h-6 rounded-full bg-kodo-graphite border border-kodo-steel flex items-center justify-center shrink-0 z-10">
<div className="w-2 h-2 rounded-full bg-kodo-gold"></div>
</div>
<div>
<p className="text-sm text-kodo-text-main">
<span className="font-bold text-white">{act.user}</span>{' '}
{act.action} this file.
</p>
<p className="text-xs text-kodo-content-dim">{act.timestamp}</p>
</div>
</div>
))}
</div>
</Card>
{/* Versions */}
<Card variant="default">
<h3 className="font-bold text-white mb-4 flex items-center gap-2 text-sm uppercase tracking-wider">
<Layers className="w-4 h-4 text-kodo-magenta" /> Version History
</h3>
<div className="space-y-2">
{MOCK_VERSIONS.map((ver) => (
<div
key={ver.id}
className={`flex items-center justify-between p-3 rounded border ${ver.current ? 'bg-kodo-magenta/10 border-kodo-magenta/30' : 'bg-kodo-ink border-kodo-steel hover:bg-white/5'}`}
>
<div>
<div className="flex items-center gap-2">
<span className="font-bold text-white text-sm">
{ver.version}
</span>
{ver.current && (
<span className="text-[10px] bg-kodo-magenta text-white px-1.5 rounded">
LATEST
</span>
)}
</div>
<div className="text-xs text-kodo-content-dim">
{ver.timestamp} {ver.uploadedBy}
</div>
</div>
<Button
variant="ghost"
size="icon"
className="h-8 w-8"
aria-label="Télécharger"
>
<Download className="w-3 h-3" />
</Button>
</div>
))}
</div>
</Card>
{/* Storage Info */}
<div className="bg-kodo-ink p-4 rounded-xl border border-kodo-steel flex items-center gap-4">
<div className="w-10 h-10 bg-kodo-slate rounded-lg flex items-center justify-center text-kodo-content-dim">
<HardDrive className="w-5 h-5" />
</div>
<div>
<div className="text-xs text-kodo-content-dim uppercase">
Storage Location
</div>
<div className="text-sm font-bold text-white">
s3://veza-cloud/projects/alpha
</div>
</div>
</div>
</div>
</div>
</div>
);
};