![]() 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/domains/lavocat.ca/private_html/src/pages/admin/ |
import React, { useState, useEffect } from 'react';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/router';
import Head from 'next/head';
import LayoutWithSidebar from '../../components/LayoutWithSidebar';
import {
Plus,
Edit,
Eye,
ExternalLink,
Users,
Calendar,
DollarSign,
Target,
CheckCircle,
Clock,
AlertTriangle,
Star,
TrendingUp,
FileText,
Building,
Globe,
Shield,
Heart,
Zap,
Award
} from 'lucide-react';
import Link from 'next/link';
const CaseShowcaseManager: React.FC = () => {
const { data: session } = useSession();
const router = useRouter();
const [cases, setCases] = useState<any[]>([]);
const [loading, setLoading] = useState(true);
const [filter, setFilter] = useState('all');
useEffect(() => {
if (session) {
fetchCases();
}
}, [session]);
const fetchCases = async () => {
try {
const response = await fetch('/api/admin/cases');
if (response.ok) {
const data = await response.json();
setCases(data.cases || []);
}
} catch (error) {
console.error('Error fetching cases:', error);
} finally {
setLoading(false);
}
};
const getStatusIcon = (status: string) => {
switch (status?.toLowerCase()) {
case 'active': return <CheckCircle className="h-5 w-5 text-green-500" />;
case 'pending': return <Clock className="h-5 w-5 text-yellow-500" />;
case 'closed': return <AlertTriangle className="h-5 w-5 text-gray-500" />;
default: return <Clock className="h-5 w-5 text-gray-400" />;
}
};
const getCategoryIcon = (category: string) => {
switch (category?.toLowerCase()) {
case 'human_rights': return 'ποΈ';
case 'criminal': return 'βοΈ';
case 'civil': return 'π';
case 'family': return 'π¨βπ©βπ§βπ¦';
case 'corporate': return 'π’';
case 'class_action': return 'π₯';
case 'immigration': return 'π';
case 'employment': return 'πΌ';
default: return 'π';
}
};
const getPriorityColor = (priority: string) => {
switch (priority?.toLowerCase()) {
case 'high': return 'bg-red-100 text-red-800 border-red-200';
case 'medium': return 'bg-yellow-100 text-yellow-800 border-yellow-200';
case 'low': return 'bg-green-100 text-green-800 border-green-200';
default: return 'bg-gray-100 text-gray-800 border-gray-200';
}
};
const filteredCases = cases.filter(case_ => {
if (filter === 'all') return true;
if (filter === 'public' && case_.isPublic) return true;
if (filter === 'active' && case_.status === 'active') return true;
if (filter === 'pending' && case_.status === 'pending') return true;
return false;
});
if (!session) {
return (
<LayoutWithSidebar>
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
<div className="text-center">
<h1 className="text-4xl font-bold text-gray-900 mb-4">Access Denied</h1>
<p className="text-gray-600 mb-8">Please log in to access this page.</p>
<button
onClick={() => router.push('/auth/signin')}
className="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
>
Sign In
</button>
</div>
</div>
</LayoutWithSidebar>
);
}
return (
<>
<Head>
<title>Case Showcase Manager | LibertΓ© MΓͺme en Prison</title>
<meta name="description" content="Manage beautiful case profile presentations" />
</Head>
<LayoutWithSidebar>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
{/* Header */}
<div className="mb-8">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold text-gray-900">Case Showcase Manager</h1>
<p className="text-gray-600 mt-2">
Create and manage beautiful case profile presentations for your clients
</p>
</div>
<Link
href="/admin/cases/new"
className="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
>
<Plus className="h-4 w-4 mr-2" />
Create New Case
</Link>
</div>
</div>
{/* Stats Cards */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
<div className="flex items-center">
<div className="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center">
<FileText className="h-6 w-6 text-blue-600" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-600">Total Cases</p>
<p className="text-2xl font-bold text-gray-900">{cases.length}</p>
</div>
</div>
</div>
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
<div className="flex items-center">
<div className="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center">
<CheckCircle className="h-6 w-6 text-green-600" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-600">Public Cases</p>
<p className="text-2xl font-bold text-gray-900">
{cases.filter(c => c.isPublic).length}
</p>
</div>
</div>
</div>
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
<div className="flex items-center">
<div className="w-12 h-12 bg-yellow-100 rounded-lg flex items-center justify-center">
<Clock className="h-6 w-6 text-yellow-600" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-600">Active Cases</p>
<p className="text-2xl font-bold text-gray-900">
{cases.filter(c => c.status === 'active').length}
</p>
</div>
</div>
</div>
<div className="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
<div className="flex items-center">
<div className="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center">
<Users className="h-6 w-6 text-purple-600" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-600">Total Applications</p>
<p className="text-2xl font-bold text-gray-900">
{cases.reduce((sum, c) => sum + (c._count?.registrations || 0), 0)}
</p>
</div>
</div>
</div>
</div>
{/* Filters */}
<div className="mb-6">
<div className="flex space-x-4">
<button
onClick={() => setFilter('all')}
className={`px-4 py-2 rounded-lg font-medium transition-colors ${
filter === 'all'
? 'bg-blue-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
All Cases
</button>
<button
onClick={() => setFilter('public')}
className={`px-4 py-2 rounded-lg font-medium transition-colors ${
filter === 'public'
? 'bg-blue-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
Public Cases
</button>
<button
onClick={() => setFilter('active')}
className={`px-4 py-2 rounded-lg font-medium transition-colors ${
filter === 'active'
? 'bg-blue-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
Active Cases
</button>
<button
onClick={() => setFilter('pending')}
className={`px-4 py-2 rounded-lg font-medium transition-colors ${
filter === 'pending'
? 'bg-blue-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
Pending Cases
</button>
</div>
</div>
{/* Cases Grid */}
{loading ? (
<div className="flex items-center justify-center py-12">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredCases.map((case_) => (
<div key={case_.id} className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden hover:shadow-lg transition-shadow">
{/* Case Header */}
<div className="p-6">
<div className="flex items-start justify-between mb-4">
<div className="flex items-center gap-2">
<span className="text-2xl">{getCategoryIcon(case_.category)}</span>
{getStatusIcon(case_.status)}
</div>
<div className="flex items-center gap-2">
<span className={`px-2 py-1 rounded-full text-xs font-medium border ${getPriorityColor(case_.priority)}`}>
{case_.priority?.toUpperCase() || 'MEDIUM'}
</span>
{case_.isPublic && (
<span className="px-2 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800 border border-green-200">
PUBLIC
</span>
)}
</div>
</div>
<h3 className="font-bold text-gray-900 mb-2 line-clamp-2">{case_.title}</h3>
<p className="text-gray-600 text-sm mb-4 line-clamp-3">
{case_.publicSummary || case_.description || 'No description available'}
</p>
{/* Case Stats */}
<div className="grid grid-cols-2 gap-4 mb-4">
<div className="text-center">
<p className="text-xs text-gray-500">Applications</p>
<p className="font-bold text-gray-900">{case_._count?.registrations || 0}</p>
</div>
<div className="text-center">
<p className="text-xs text-gray-500">Views</p>
<p className="font-bold text-gray-900">{case_.viewCount || 0}</p>
</div>
</div>
{/* Case Details */}
<div className="space-y-2 text-sm text-gray-600">
{case_.caseNumber && (
<div className="flex items-center gap-2">
<FileText className="h-4 w-4" />
<span>{case_.caseNumber}</span>
</div>
)}
{case_.jurisdiction && (
<div className="flex items-center gap-2">
<Building className="h-4 w-4" />
<span>{case_.jurisdiction}</span>
</div>
)}
{case_.estimatedValue && (
<div className="flex items-center gap-2">
<DollarSign className="h-4 w-4" />
<span>${case_.estimatedValue.toLocaleString()}</span>
</div>
)}
</div>
</div>
{/* Action Buttons */}
<div className="border-t border-gray-200 p-4 bg-gray-50">
<div className="flex items-center justify-between">
<div className="flex gap-2">
<Link
href={`/cases/${case_.id}/showcase`}
className="inline-flex items-center px-3 py-2 bg-blue-600 text-white text-sm rounded-lg hover:bg-blue-700 transition-colors"
>
<Eye className="h-4 w-4 mr-1" />
View Showcase
</Link>
<Link
href={`/admin/cases/${case_.id}`}
className="inline-flex items-center px-3 py-2 bg-gray-600 text-white text-sm rounded-lg hover:bg-gray-700 transition-colors"
>
<Edit className="h-4 w-4 mr-1" />
Edit
</Link>
</div>
<Link
href={`/cases/${case_.id}/showcase`}
target="_blank"
className="inline-flex items-center px-3 py-2 bg-white border border-gray-300 text-gray-700 text-sm rounded-lg hover:bg-gray-50 transition-colors"
>
<ExternalLink className="h-4 w-4 mr-1" />
Open
</Link>
</div>
</div>
</div>
))}
</div>
)}
{!loading && filteredCases.length === 0 && (
<div className="text-center py-12">
<div className="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center mx-auto mb-4">
<FileText className="h-8 w-8 text-gray-400" />
</div>
<h3 className="text-lg font-medium text-gray-900 mb-2">No cases found</h3>
<p className="text-gray-600 mb-6">
{filter === 'all'
? "You haven't created any cases yet."
: `No cases match the "${filter}" filter.`
}
</p>
<Link
href="/admin/cases/new"
className="inline-flex items-center px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
>
<Plus className="h-4 w-4 mr-2" />
Create Your First Case
</Link>
</div>
)}
</div>
</LayoutWithSidebar>
</>
);
};
export default CaseShowcaseManager;