Add upload button and simulated progress to Mock Trial page
This commit is contained in:
parent
9cff752d40
commit
7999a3fa04
@ -1,95 +1,179 @@
|
||||
import { Gavel, Mic, Users, MessageSquare, Play, Info } from 'lucide-react';
|
||||
"use client";
|
||||
|
||||
import { useState, useRef } from 'react';
|
||||
import {
|
||||
Plus,
|
||||
Search,
|
||||
Gavel,
|
||||
User,
|
||||
Mic,
|
||||
Book,
|
||||
MessageSquare,
|
||||
Upload,
|
||||
X,
|
||||
FileAudio
|
||||
} from 'lucide-react';
|
||||
|
||||
const mockTrials = [
|
||||
{
|
||||
id: '1',
|
||||
title: 'Barden v. State Farm - Jurisdiction Challenge',
|
||||
status: 'Ready for Play',
|
||||
lastPractice: '2 days ago',
|
||||
transcript: 'Plaintiff argues lack of personal jurisdiction...',
|
||||
players: ['AI Judge', 'AI Opposing Counsel'],
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'Malveo Estate - Witness Testimony',
|
||||
status: 'Drafting Script',
|
||||
lastPractice: '1 week ago',
|
||||
transcript: 'Witness deposition regarding estate assets...',
|
||||
players: ['AI Judge'],
|
||||
},
|
||||
];
|
||||
|
||||
export default function MockTrialPage() {
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
const [uploadProgress, setUploadProgress] = useState(0);
|
||||
const [selectedFile, setSelectedFile] = useState<File | null>(null);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0];
|
||||
if (file) {
|
||||
setSelectedFile(file);
|
||||
simulateUpload();
|
||||
}
|
||||
};
|
||||
|
||||
const simulateUpload = () => {
|
||||
setIsUploading(true);
|
||||
let progress = 0;
|
||||
const interval = setInterval(() => {
|
||||
progress += 10;
|
||||
setUploadProgress(progress);
|
||||
if (progress >= 100) {
|
||||
clearInterval(interval);
|
||||
setTimeout(() => {
|
||||
setIsUploading(false);
|
||||
setUploadProgress(0);
|
||||
alert('Simulated upload complete. Actual backend integration coming soon!');
|
||||
}, 500);
|
||||
}
|
||||
}, 200);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-slate-900 dark:text-white">Mock Trial Simulator</h1>
|
||||
<p className="text-slate-500">Practice your arguments and receive real-time feedback from an AI Judge.</p>
|
||||
<p className="text-sm text-slate-500">Practice your arguments against AI Judge & Opposing Counsel.</p>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="file"
|
||||
ref={fileInputRef}
|
||||
onChange={handleUpload}
|
||||
className="hidden"
|
||||
accept="image/*,audio/*,video/*,.pdf,.docx,.txt,.csv,.xlsx,.json,.html,.md,.zip" // All supported types
|
||||
multiple // Allow multiple files for batch upload simulation
|
||||
/>
|
||||
<button
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-slate-900 text-white rounded-lg font-bold hover:bg-slate-800 transition-colors shadow-lg"
|
||||
>
|
||||
<Upload size={18} />
|
||||
Upload Files or Folder
|
||||
</button>
|
||||
<button className="flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg font-bold hover:bg-blue-700 transition-colors shadow-lg shadow-blue-500/20">
|
||||
<Plus size={20} />
|
||||
Create New Trial
|
||||
</button>
|
||||
</div>
|
||||
<button className="flex items-center gap-2 px-6 py-3 bg-blue-600 text-white rounded-xl font-bold hover:bg-blue-700 transition-all shadow-xl shadow-blue-500/20 active:scale-95">
|
||||
<Play size={20} fill="currentColor" />
|
||||
Start Simulation
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
||||
<div className="lg:col-span-2 space-y-6">
|
||||
<div className="bg-slate-900 rounded-2xl aspect-video relative overflow-hidden border-4 border-slate-800 shadow-2xl">
|
||||
<div className="absolute inset-0 bg-[url('https://images.unsplash.com/photo-1589829545856-d10d557cf95f?auto=format&fit=crop&q=80&w=2000')] bg-cover bg-center opacity-20"></div>
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center text-center p-8">
|
||||
<div className="w-20 h-20 rounded-full bg-slate-800 flex items-center justify-center text-slate-400 mb-6 border-2 border-slate-700">
|
||||
<Gavel size={40} />
|
||||
</div>
|
||||
<h2 className="text-2xl font-bold text-white mb-2">The Honorable AI Judge</h2>
|
||||
<p className="text-slate-400 max-w-md mx-auto">Ready to hear your opening statement or oral argument. Click 'Start Simulation' to begin.</p>
|
||||
{isUploading && (
|
||||
<div className="mx-4 bg-blue-50 dark:bg-blue-900/20 border border-blue-100 dark:border-blue-800 p-4 rounded-xl flex items-center gap-4">
|
||||
<div className="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center text-white">
|
||||
<Upload size={20} className="animate-bounce" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex justify-between items-center mb-1">
|
||||
<p className="text-sm font-bold text-blue-900 dark:text-blue-100">Processing: {selectedFile?.name}</p>
|
||||
<p className="text-xs font-bold text-blue-600">{uploadProgress}%</p>
|
||||
</div>
|
||||
|
||||
<div className="absolute bottom-6 left-6 right-6 flex justify-between items-center">
|
||||
<div className="flex gap-4">
|
||||
<div className="flex items-center gap-2 bg-slate-800/80 backdrop-blur px-3 py-1.5 rounded-lg border border-slate-700">
|
||||
<div className="w-2 h-2 bg-red-500 rounded-full animate-pulse"></div>
|
||||
<span className="text-xs font-bold text-white uppercase tracking-widest">Live</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<button className="p-3 bg-slate-800/80 backdrop-blur rounded-full text-white hover:bg-slate-700 border border-slate-700">
|
||||
<Mic size={20} />
|
||||
</button>
|
||||
<button className="p-3 bg-slate-800/80 backdrop-blur rounded-full text-white hover:bg-slate-700 border border-slate-700">
|
||||
<Users size={20} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-800 p-6">
|
||||
<h3 className="text-lg font-bold mb-4 flex items-center gap-2">
|
||||
<Info size={18} className="text-blue-500" />
|
||||
Simulation Settings
|
||||
</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-bold text-slate-500 uppercase tracking-wider">Role</label>
|
||||
<select className="w-full bg-slate-50 dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
||||
<option>Plaintiff Counsel</option>
|
||||
<option>Defendant Counsel</option>
|
||||
<option>Witness (Direct/Cross)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-bold text-slate-500 uppercase tracking-wider">Judge Persona</label>
|
||||
<select className="w-full bg-slate-50 dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
||||
<option>Strict & Formal</option>
|
||||
<option>Helpful & Instructive</option>
|
||||
<option>Skeptical & Challenging</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="w-full bg-blue-200 dark:bg-blue-800 h-2 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="bg-blue-600 h-full transition-all duration-300"
|
||||
style={{ width: `${uploadProgress}%` }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<button onClick={() => setIsUploading(false)} className="text-blue-400 hover:text-blue-600">
|
||||
<X size={20} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="space-y-6">
|
||||
<div className="bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-800 flex flex-col h-full overflow-hidden shadow-sm">
|
||||
<header className="p-4 border-b border-slate-200 dark:border-slate-800 bg-slate-50 dark:bg-slate-800/50 flex items-center gap-2">
|
||||
<MessageSquare size={18} className="text-blue-500" />
|
||||
<h3 className="font-bold text-sm">Trial Log</h3>
|
||||
</header>
|
||||
<div className="flex-1 p-4 space-y-4 min-h-[400px]">
|
||||
<div className="text-center py-10 text-slate-400">
|
||||
<p className="text-sm italic">"The court is now in session..."</p>
|
||||
<p className="text-xs mt-2">Logs will appear here during your simulation.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4 border-t border-slate-200 dark:border-slate-800 bg-slate-50 dark:bg-slate-800/50">
|
||||
<button className="w-full py-2 bg-slate-200 dark:bg-slate-800 text-slate-600 dark:text-slate-400 rounded-lg text-xs font-bold hover:bg-slate-300 transition-colors uppercase tracking-widest">
|
||||
Export Transcript
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col md:flex-row gap-4">
|
||||
<div className="relative flex-1">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400" size={18} />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search mock trials..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="w-full pl-10 pr-4 py-2 rounded-lg border border-slate-200 dark:border-slate-800 bg-white dark:bg-slate-900 focus:outline-none focus:ring-2 focus:ring-blue-500 transition-all"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-xl overflow-hidden shadow-sm">
|
||||
<table className="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr className="bg-slate-50 dark:bg-slate-800/50 text-slate-500 text-xs uppercase tracking-wider font-bold">
|
||||
<th className="px-6 py-4">Trial Name</th>
|
||||
<th className="px-6 py-4">Status</th>
|
||||
<th className="px-6 py-4">Players</th>
|
||||
<th className="px-6 py-4">Last Practice</th>
|
||||
<th className="px-6 py-4 text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-slate-100 dark:divide-slate-800">
|
||||
{mockTrials.map((trial) => (
|
||||
<tr key={trial.id} className="hover:bg-slate-50 dark:hover:bg-slate-800/50 transition-colors cursor-pointer group">
|
||||
<td className="px-6 py-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-red-50 dark:bg-red-900/30 flex items-center justify-center text-red-600">
|
||||
<Gavel size={16} />
|
||||
</div>
|
||||
<span className="font-bold text-slate-900 dark:text-white group-hover:text-red-600 transition-colors">{trial.title}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-slate-600 dark:text-slate-400">{trial.status}</td>
|
||||
<td className="px-6 py-4">
|
||||
<div className="flex items-center -space-x-2">
|
||||
{trial.players.map((player, index) => (
|
||||
<span key={index} className="w-8 h-8 rounded-full bg-slate-100 dark:bg-slate-700 border-2 border-white dark:border-slate-900 flex items-center justify-center text-xs font-bold text-slate-600 dark:text-slate-300">
|
||||
{player.includes('AI') ? <Bot size={16} /> : <User size={16} />}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-sm text-slate-500">{trial.lastPractice}</td>
|
||||
<td className="px-6 py-4 text-right">
|
||||
<button className="flex items-center gap-2 px-3 py-1 bg-blue-600 text-white rounded-lg text-sm font-bold hover:bg-blue-700 transition-colors">
|
||||
<Play size={16} /> Play
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user