![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/backups/lavocat.quebec/backup-20250730-021618/src/pages/judge/ |
import React, { useState } from 'react';
import { useRouter } from 'next/router';
import { useRequireRole } from '../../lib/auth-utils';
import { USER_ROLES } from '../../lib/auth-utils';
interface CourtSession {
id: string;
date: string;
time: string;
type: 'criminal' | 'civil' | 'family' | 'administrative';
status: 'scheduled' | 'in_progress' | 'completed' | 'cancelled';
cases: number;
judge: string;
courtroom: string;
}
interface StaffMember {
id: string;
name: string;
role: string;
department: string;
status: 'active' | 'on_leave' | 'off_duty';
contact: string;
lastActive: string;
}
interface CourtResource {
id: string;
name: string;
type: 'courtroom' | 'equipment' | 'vehicle' | 'facility';
status: 'available' | 'in_use' | 'maintenance' | 'reserved';
location: string;
nextAvailable: string;
}
const JudgeAdministrationPage: React.FC = () => {
const router = useRouter();
const { session, status, isAuthorized } = useRequireRole([USER_ROLES.JUDGE, USER_ROLES.ADMIN, USER_ROLES.SUPERADMIN, USER_ROLES.SUPERADMIN]);
const [activeTab, setActiveTab] = useState('sessions');
const [selectedDate, setSelectedDate] = useState(new Date().toISOString().split('T')[0]);
// Mock data for court sessions
const [sessions] = useState<CourtSession[]>([
{
id: '1',
date: '2025-07-01',
time: '09:00',
type: 'criminal',
status: 'scheduled',
cases: 5,
judge: 'Hon. Marie Dubois',
courtroom: 'Courtroom A'
},
{
id: '2',
date: '2025-07-01',
time: '14:00',
type: 'civil',
status: 'scheduled',
cases: 3,
judge: 'Hon. Marie Dubois',
courtroom: 'Courtroom B'
},
{
id: '3',
date: '2025-07-02',
time: '10:00',
type: 'family',
status: 'scheduled',
cases: 2,
judge: 'Hon. Marie Dubois',
courtroom: 'Courtroom C'
}
]);
// Mock data for staff
const [staff] = useState<StaffMember[]>([
{
id: '1',
name: 'Sarah Johnson',
role: 'Court Clerk',
department: 'Administration',
status: 'active',
contact: 'sarah.johnson@court.qc.ca',
lastActive: '2025-06-30 16:45'
},
{
id: '2',
name: 'Michael Chen',
role: 'Bailiff',
department: 'Security',
status: 'active',
contact: 'michael.chen@court.qc.ca',
lastActive: '2025-06-30 17:00'
},
{
id: '3',
name: 'Emily Rodriguez',
role: 'Court Reporter',
department: 'Records',
status: 'on_leave',
contact: 'emily.rodriguez@court.qc.ca',
lastActive: '2025-06-28 15:30'
}
]);
// Mock data for resources
const [resources] = useState<CourtResource[]>([
{
id: '1',
name: 'Courtroom A',
type: 'courtroom',
status: 'available',
location: 'Floor 1',
nextAvailable: '2025-07-01 09:00'
},
{
id: '2',
name: 'Courtroom B',
type: 'courtroom',
status: 'in_use',
location: 'Floor 1',
nextAvailable: '2025-07-01 16:00'
},
{
id: '3',
name: 'Recording Equipment Set 1',
type: 'equipment',
status: 'maintenance',
location: 'Storage Room',
nextAvailable: '2025-07-03 09:00'
}
]);
const getStatusColor = (status: string) => {
switch (status) {
case 'scheduled':
case 'active':
case 'available':
return 'bg-green-100 text-green-800';
case 'in_progress':
case 'in_use':
return 'bg-blue-100 text-blue-800';
case 'completed':
return 'bg-gray-100 text-gray-800';
case 'cancelled':
case 'maintenance':
return 'bg-red-100 text-red-800';
case 'on_leave':
case 'off_duty':
case 'reserved':
return 'bg-yellow-100 text-yellow-800';
default:
return 'bg-gray-100 text-gray-800';
}
};
const getTypeColor = (type: string) => {
switch (type) {
case 'criminal':
return 'bg-red-100 text-red-800';
case 'civil':
return 'bg-blue-100 text-blue-800';
case 'family':
return 'bg-purple-100 text-purple-800';
case 'administrative':
return 'bg-orange-100 text-orange-800';
default:
return 'bg-gray-100 text-gray-800';
}
};
if (status === 'loading') {
return (
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto"></div>
<p className="mt-4 text-gray-600">Loading court administration...</p>
</div>
</div>
);
}
return (
<div className="min-h-screen bg-gray-50">
{/* Header */}
<div className="bg-white shadow-sm border-b">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center py-6">
<div>
<h1 className="text-3xl font-bold text-gray-900">Court Administration</h1>
<p className="mt-1 text-sm text-gray-500">
Manage court operations, staff, and resources
</p>
</div>
<div className="flex space-x-3">
<button
onClick={() => router.push('/judge/dashboard')}
className="inline-flex items-center px-4 py-2 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
>
← Back to Dashboard
</button>
<button className="inline-flex items-center px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
+ Schedule Session
</button>
</div>
</div>
</div>
</div>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{/* Stats Overview */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 bg-blue-500 rounded-md flex items-center justify-center">
<svg className="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
</div>
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 truncate">Today's Sessions</dt>
<dd className="text-lg font-medium text-gray-900">
{sessions.filter(s => s.date === selectedDate).length}
</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 bg-green-500 rounded-md flex items-center justify-center">
<svg className="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
</svg>
</div>
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 truncate">Active Staff</dt>
<dd className="text-lg font-medium text-gray-900">
{staff.filter(s => s.status === 'active').length}
</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 bg-purple-500 rounded-md flex items-center justify-center">
<svg className="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
</div>
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 truncate">Available Resources</dt>
<dd className="text-lg font-medium text-gray-900">
{resources.filter(r => r.status === 'available').length}
</dd>
</dl>
</div>
</div>
</div>
</div>
<div className="bg-white overflow-hidden shadow rounded-lg">
<div className="p-5">
<div className="flex items-center">
<div className="flex-shrink-0">
<div className="w-8 h-8 bg-orange-500 rounded-md flex items-center justify-center">
<svg className="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
</div>
<div className="ml-5 w-0 flex-1">
<dl>
<dt className="text-sm font-medium text-gray-500 truncate">This Week</dt>
<dd className="text-lg font-medium text-gray-900">
{sessions.filter(s => {
const sessionDate = new Date(s.date);
const weekFromNow = new Date();
weekFromNow.setDate(weekFromNow.getDate() + 7);
return sessionDate <= weekFromNow;
}).length}
</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
{/* Tabs */}
<div className="bg-white shadow rounded-lg mb-6">
<div className="border-b border-gray-200">
<nav className="-mb-px flex space-x-8 px-6">
<button
onClick={() => setActiveTab('sessions')}
className={`py-4 px-1 border-b-2 font-medium text-sm ${
activeTab === 'sessions'
? 'border-blue-500 text-blue-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
}`}
>
Court Sessions
</button>
<button
onClick={() => setActiveTab('staff')}
className={`py-4 px-1 border-b-2 font-medium text-sm ${
activeTab === 'staff'
? 'border-blue-500 text-blue-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
}`}
>
Staff Management
</button>
<button
onClick={() => setActiveTab('resources')}
className={`py-4 px-1 border-b-2 font-medium text-sm ${
activeTab === 'resources'
? 'border-blue-500 text-blue-600'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300'
}`}
>
Resources
</button>
</nav>
</div>
<div className="p-6">
{/* Date Selector */}
<div className="mb-6">
<label htmlFor="date" className="block text-sm font-medium text-gray-700 mb-2">
Select Date
</label>
<input
type="date"
id="date"
value={selectedDate}
onChange={(e) => setSelectedDate(e.target.value)}
className="block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"
/>
</div>
{/* Court Sessions Tab */}
{activeTab === 'sessions' && (
<div>
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-medium text-gray-900">Court Sessions</h3>
<button className="inline-flex items-center px-3 py-1 border border-transparent text-sm leading-4 font-medium rounded-md text-blue-700 bg-blue-100 hover:bg-blue-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
+ Add Session
</button>
</div>
<div className="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
<table className="min-w-full divide-y divide-gray-300">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Time</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Cases</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Courtroom</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{sessions
.filter(s => s.date === selectedDate)
.map((session) => (
<tr key={session.id}>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{session.time}
</td>
<td className="px-6 py-4 whitespace-nowrap">
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getTypeColor(session.type)}`}>
{session.type}
</span>
</td>
<td className="px-6 py-4 whitespace-nowrap">
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getStatusColor(session.status)}`}>
{session.status.replace('_', ' ')}
</span>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{session.cases}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{session.courtroom}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button className="text-blue-600 hover:text-blue-900 mr-3">Edit</button>
<button className="text-red-600 hover:text-red-900">Cancel</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{/* Staff Management Tab */}
{activeTab === 'staff' && (
<div>
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-medium text-gray-900">Staff Management</h3>
<button className="inline-flex items-center px-3 py-1 border border-transparent text-sm leading-4 font-medium rounded-md text-blue-700 bg-blue-100 hover:bg-blue-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
+ Add Staff
</button>
</div>
<div className="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
<table className="min-w-full divide-y divide-gray-300">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Role</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Department</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Last Active</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{staff.map((member) => (
<tr key={member.id}>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{member.name}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{member.role}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{member.department}
</td>
<td className="px-6 py-4 whitespace-nowrap">
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getStatusColor(member.status)}`}>
{member.status.replace('_', ' ')}
</span>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{new Date(member.lastActive).toLocaleDateString()}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button className="text-blue-600 hover:text-blue-900 mr-3">Contact</button>
<button className="text-green-600 hover:text-green-900">Schedule</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{/* Resources Tab */}
{activeTab === 'resources' && (
<div>
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-medium text-gray-900">Court Resources</h3>
<button className="inline-flex items-center px-3 py-1 border border-transparent text-sm leading-4 font-medium rounded-md text-blue-700 bg-blue-100 hover:bg-blue-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">
+ Add Resource
</button>
</div>
<div className="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
<table className="min-w-full divide-y divide-gray-300">
<thead className="bg-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Resource</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Type</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Location</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Next Available</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{resources.map((resource) => (
<tr key={resource.id}>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">
{resource.name}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{resource.type}
</td>
<td className="px-6 py-4 whitespace-nowrap">
<span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getStatusColor(resource.status)}`}>
{resource.status.replace('_', ' ')}
</span>
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{resource.location}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
{new Date(resource.nextAvailable).toLocaleDateString()}
</td>
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
<button className="text-blue-600 hover:text-blue-900 mr-3">Reserve</button>
<button className="text-green-600 hover:text-green-900">Maintain</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
</div>
</div>
</div>
</div>
);
};
export default JudgeAdministrationPage;