![]() 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/cases/[id]/ |
import React, { useState, useEffect } from 'react';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/router';
import LayoutWithSidebar from '@/components/LayoutWithSidebar';
import {
ArrowLeft,
Save,
Plus,
AlertCircle,
Users,
Calendar,
Building,
Scale,
FileText,
CheckCircle,
Trash2
} from 'lucide-react';
import { useRef } from 'react';
import CaseHeroSection from '@/components/CaseHeroSection';
// Constants for form options
const caseTypes = [
{ value: 'CLASS_ACTION', label: 'Class Action / Recours collectif' },
{ value: 'CIVIL_LITIGATION', label: 'Civil Litigation / Litige civil' },
{ value: 'CRIMINAL_DEFENSE', label: 'Criminal Defense / Défense pénale' },
{ value: 'FAMILY_LAW', label: 'Family Law / Droit de la famille' },
{ value: 'IMMIGRATION', label: 'Immigration Law / Droit de l\'immigration' },
{ value: 'HUMAN_RIGHTS', label: 'Human Rights / Droits de la personne' },
{ value: 'ADMINISTRATIVE', label: 'Administrative Law / Droit administratif' },
{ value: 'CONSTITUTIONAL', label: 'Constitutional Law / Droit constitutionnel' },
{ value: 'ENVIRONMENTAL', label: 'Environmental Law / Droit de l\'environnement' },
{ value: 'LABOR_LAW', label: 'Labor Law / Droit du travail' },
{ value: 'INTELLECTUAL_PROPERTY', label: 'Intellectual Property / Propriété intellectuelle' },
{ value: 'CORPORATE', label: 'Corporate Law / Droit des sociétés' },
{ value: 'TAX_LAW', label: 'Tax Law / Droit fiscal' },
{ value: 'REAL_ESTATE', label: 'Real Estate Law / Droit immobilier' },
{ value: 'OTHER', label: 'Other / Autre' }
];
const jurisdictions = [
'Quebec',
'Ontario',
'British Columbia',
'Alberta',
'Manitoba',
'Saskatchewan',
'Nova Scotia',
'New Brunswick',
'Newfoundland and Labrador',
'Prince Edward Island',
'Northwest Territories',
'Nunavut',
'Yukon',
'Federal'
];
const courtOptions = [
{ value: 'SUPREME_COURT_CANADA', label: 'Supreme Court of Canada / Cour suprême du Canada' },
{ value: 'FEDERAL_COURT', label: 'Federal Court / Cour fédérale' },
{ value: 'FEDERAL_APPEAL', label: 'Federal Court of Appeal / Cour d\'appel fédérale' },
{ value: 'QUEBEC_SUPERIOR', label: 'Quebec Superior Court / Cour supérieure du Québec' },
{ value: 'QUEBEC_COURT', label: 'Quebec Court / Cour du Québec' },
{ value: 'QUEBEC_APPEAL', label: 'Quebec Court of Appeal / Cour d\'appel du Québec' },
{ value: 'ONTARIO_SUPERIOR', label: 'Ontario Superior Court of Justice' },
{ value: 'ONTARIO_COURT', label: 'Ontario Court of Justice' },
{ value: 'ONTARIO_APPEAL', label: 'Ontario Court of Appeal' },
{ value: 'BC_SUPREME', label: 'British Columbia Supreme Court' },
{ value: 'BC_PROVINCIAL', label: 'British Columbia Provincial Court' },
{ value: 'BC_APPEAL', label: 'British Columbia Court of Appeal' },
{ value: 'ALBERTA_COURT', label: 'Alberta Court of King\'s Bench' },
{ value: 'ALBERTA_PROVINCIAL', label: 'Alberta Provincial Court' },
{ value: 'ALBERTA_APPEAL', label: 'Alberta Court of Appeal' },
{ value: 'OTHER', label: 'Other / Autre' }
];
const priorities = [
{ value: 'low', label: 'Low / Faible' },
{ value: 'medium', label: 'Medium / Moyen' },
{ value: 'high', label: 'High / Élevé' },
{ value: 'urgent', label: 'Urgent / Urgent' }
];
const statuses = [
{ value: 'pending', label: 'Pending / En attente' },
{ value: 'active', label: 'Active / Actif' },
{ value: 'closed', label: 'Closed / Fermé' },
{ value: 'suspended', label: 'Suspended / Suspendu' }
];
interface LawFirm {
id: string;
name: string;
shortName: string;
address: string;
city: string;
province: string;
}
interface User {
id: string;
name: string;
email: string;
role: string;
lawFirmId?: string;
title?: string;
specialization?: string;
}
interface CaseFormData {
title: string;
description: string;
caseNumbers: string[]; // support multiple
caseTypes: string[]; // support multiple
jurisdictions: string[]; // support multiple
courts: string[]; // support multiple
courtLocation: string;
division: string;
logoUrl?: string;
leadLawyerId: string;
firmName: string;
priority: string;
budget: string;
status: string;
applicationDeadline: string;
isAcceptingApplications: boolean;
eligibilityCriteria: {
minimumAge?: number;
maximumAge?: number;
location?: string[];
incomeLimit?: number;
specificConditions?: string;
};
requiredDocuments: string[];
}
const EditCasePage = () => {
const { data: session, status } = useSession();
const router = useRouter();
const { id } = router.query;
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
const [lawyers, setLawyers] = useState<User[]>([]);
const [lawFirms, setLawFirms] = useState<LawFirm[]>([]);
const [error, setError] = useState('');
const [success, setSuccess] = useState('');
const [debugMode, setDebugMode] = useState(false);
// Debug toggle (only in development)
const toggleDebug = () => {
if (process.env.NODE_ENV === 'development') {
setDebugMode(!debugMode);
}
};
const [formData, setFormData] = useState<CaseFormData>({
title: '',
description: '',
caseNumbers: [''],
caseTypes: [],
jurisdictions: [],
courts: [],
courtLocation: '',
division: '',
logoUrl: '',
leadLawyerId: '',
firmName: '',
priority: 'medium',
budget: '',
status: 'pending',
applicationDeadline: '',
isAcceptingApplications: true,
eligibilityCriteria: {},
requiredDocuments: ['Government ID', 'Proof of Detention/Incarceration'],
});
const logoInputRef = useRef<HTMLInputElement>(null);
const [logoPreview, setLogoPreview] = useState<string | null>(null);
const [logoFile, setLogoFile] = useState<File | null>(null);
const handleLogoChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
setLogoFile(file);
setLogoPreview(URL.createObjectURL(file));
}
};
const [newDocument, setNewDocument] = useState('');
useEffect(() => {
if (status === 'loading') return;
if (!session || !['SUPERADMIN', 'ADMIN'].includes(session.user.role)) {
router.push('/admin');
return;
}
if (id) {
fetchData();
}
}, [session, status, router, id]);
const fetchData = async () => {
try {
const [caseRes, lawyersRes, firmsRes] = await Promise.all([
fetch(`/api/admin/cases/${id}`),
fetch('/api/admin/users?role=LAWYER,ADMIN'),
fetch('/api/admin/law-firms')
]);
if (caseRes.ok) {
const caseData = await caseRes.json();
console.log('Case data:', caseData);
const caseInfo = caseData.case;
// Parse JSON fields with better error handling
let requiredDocuments = ['Government ID', 'Proof of Detention/Incarceration'];
let eligibilityCriteria = {};
try {
if (caseInfo.requiredDocuments) {
const parsed = JSON.parse(caseInfo.requiredDocuments);
requiredDocuments = Array.isArray(parsed) ? parsed : requiredDocuments;
}
} catch (e) {
console.warn('Error parsing required documents:', e);
}
try {
if (caseInfo.eligibilityCriteria) {
const parsed = JSON.parse(caseInfo.eligibilityCriteria);
eligibilityCriteria = typeof parsed === 'object' ? parsed : {};
}
} catch (e) {
console.warn('Error parsing eligibility criteria:', e);
}
const formDataToSet = {
title: caseInfo.title || '',
description: caseInfo.description || '',
// Convert singular values to arrays for form compatibility
caseNumbers: caseInfo.caseNumber ? [caseInfo.caseNumber] : [''],
caseTypes: caseInfo.caseType ? [caseInfo.caseType] : [],
jurisdictions: caseInfo.jurisdiction ? [caseInfo.jurisdiction] : [],
courts: caseInfo.court ? [caseInfo.court] : [],
courtLocation: caseInfo.courtLocation || '',
division: caseInfo.division || '',
logoUrl: caseInfo.logoUrl || '',
leadLawyerId: caseInfo.leadLawyerId || '',
firmName: caseInfo.leadLawyer?.lawFirm?.name || '',
priority: caseInfo.priority || 'medium',
budget: caseInfo.budget ? caseInfo.budget.toString() : '',
status: caseInfo.status || 'pending',
applicationDeadline: caseInfo.applicationDeadline
? new Date(caseInfo.applicationDeadline).toISOString().split('T')[0]
: '',
isAcceptingApplications: caseInfo.isAcceptingApplications ?? true,
eligibilityCriteria,
requiredDocuments,
};
console.log('Setting form data:', formDataToSet);
console.log('Lead lawyer ID:', caseInfo.leadLawyerId);
console.log('Lead lawyer object:', caseInfo.leadLawyer);
setFormData(formDataToSet);
} else {
const errorText = await caseRes.text();
console.error('Failed to fetch case:', caseRes.status, caseRes.statusText);
console.error('Case API error response:', errorText);
setError(`Failed to fetch case details: ${caseRes.status} ${caseRes.statusText}`);
}
if (lawyersRes.ok) {
const lawyersData = await lawyersRes.json();
const lawyersArray = Array.isArray(lawyersData) ? lawyersData : (lawyersData.users || []);
console.log('Lawyers array:', lawyersArray);
setLawyers(lawyersArray);
} else {
// Enhanced error logging
const errorText = await lawyersRes.text();
console.error('Failed to fetch lawyers:', lawyersRes.status, lawyersRes.statusText);
console.error('Lawyer API error response:', errorText);
setError(`Failed to fetch lawyers: ${lawyersRes.status} ${lawyersRes.statusText}`);
}
if (firmsRes.ok) {
const firmsData = await firmsRes.json();
setLawFirms(firmsData.firms || []);
}
} catch (error) {
console.error('Error fetching data:', error);
setError('Failed to load case data');
} finally {
setLoading(false);
}
};
const handleInputChange = (field: keyof CaseFormData, value: any) => {
setFormData(prev => ({
...prev,
[field]: value
}));
};
const handleEligibilityChange = (field: string, value: any) => {
setFormData(prev => ({
...prev,
eligibilityCriteria: {
...prev.eligibilityCriteria,
[field]: value
}
}));
};
const addDocument = () => {
if (newDocument.trim() && !formData.requiredDocuments.includes(newDocument.trim())) {
setFormData(prev => ({
...prev,
requiredDocuments: [...prev.requiredDocuments, newDocument.trim()]
}));
setNewDocument('');
}
};
const removeDocument = (index: number) => {
setFormData(prev => ({
...prev,
requiredDocuments: prev.requiredDocuments.filter((_, i) => i !== index)
}));
};
const validateForm = () => {
const errors: string[] = [];
// Required fields validation
if (!formData.title?.trim()) {
errors.push('Case title is required');
}
if (!formData.description?.trim()) {
errors.push('Case description is required');
}
if (!formData.leadLawyerId) {
errors.push('Lead lawyer is required');
}
if (!formData.caseTypes?.length) {
errors.push('At least one case type is required');
}
if (!formData.jurisdictions?.length) {
errors.push('At least one jurisdiction is required');
}
if (!formData.courts?.length) {
errors.push('At least one court is required');
}
// Case number format validation (if provided)
if (formData.caseNumbers?.[0]?.trim()) {
const caseNumber = formData.caseNumbers[0].trim();
if (!/^\d{4}QC[A-Z]{2,3}\d+$/.test(caseNumber)) {
errors.push('Case number should follow Quebec court format (e.g., 2024QCCS4539)');
}
}
// Budget validation
if (formData.budget && isNaN(parseFloat(formData.budget))) {
errors.push('Budget must be a valid number');
}
// Date validation
if (formData.applicationDeadline) {
const deadline = new Date(formData.applicationDeadline);
if (isNaN(deadline.getTime())) {
errors.push('Application deadline must be a valid date');
}
}
// Description length validation
if (formData.description?.trim() && formData.description.trim().length < 50) {
errors.push('Case description should be at least 50 characters long');
}
if (errors.length > 0) {
setError(`Please fix the following errors:\n${errors.join('\n')}`);
return false;
}
return true;
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!validateForm()) return;
setSaving(true);
setError('');
setSuccess('');
try {
const { firmName, ...caseData } = formData;
// Convert arrays to singular values for API compatibility
const submitData = {
...caseData,
// Convert arrays to singular values
caseNumber: formData.caseNumbers?.[0] || '',
caseType: formData.caseTypes?.[0] || '',
jurisdiction: formData.jurisdictions?.[0] || '',
court: formData.courts?.[0] || '',
budget: formData.budget ? parseFloat(formData.budget) : null,
applicationDeadline: formData.applicationDeadline ? new Date(formData.applicationDeadline).toISOString() : null,
requiredDocuments: formData.requiredDocuments,
eligibilityCriteria: formData.eligibilityCriteria
};
console.log('Submitting data:', submitData);
const response = await fetch(`/api/admin/cases/${id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(submitData),
});
const result = await response.json();
if (response.ok) {
setSuccess('Case updated successfully! Redirecting to case details...');
setTimeout(() => {
router.push(`/admin/cases/${id}`);
}, 2000);
} else {
console.error('API Error:', result);
const errorMessage = result.error || 'Failed to update case';
setError(errorMessage);
// Scroll to top to show error
window.scrollTo({ top: 0, behavior: 'smooth' });
}
} catch (error) {
console.error('Error updating case:', error);
setError('Network error. Please check your connection and try again.');
// Scroll to top to show error
window.scrollTo({ top: 0, behavior: 'smooth' });
} finally {
setSaving(false);
}
};
const caseTypes = [
{ value: 'class_action', label: 'Class Action' },
{ value: 'individual', label: 'Individual Case' },
{ value: 'group_litigation', label: 'Group Litigation' },
{ value: 'public_interest', label: 'Public Interest' },
{ value: 'constitutional', label: 'Constitutional Challenge' },
{ value: 'human_rights', label: 'Human Rights' },
{ value: 'administrative', label: 'Administrative Law' },
{ value: 'criminal_appeal', label: 'Criminal Appeal' }
];
const jurisdictions = [
'Quebec',
'Federal',
'Ontario',
'British Columbia',
'Alberta',
'Manitoba',
'Saskatchewan',
'Nova Scotia',
'New Brunswick',
'Prince Edward Island',
'Newfoundland and Labrador',
'Northwest Territories',
'Yukon',
'Nunavut'
];
const priorities = [
{ value: 'low', label: 'Low', color: 'text-gray-600' },
{ value: 'medium', label: 'Medium', color: 'text-blue-600' },
{ value: 'high', label: 'High', color: 'text-orange-600' },
{ value: 'urgent', label: 'Urgent', color: 'text-red-600' }
];
const statuses = [
{ value: 'pending', label: 'Pending Approval' },
{ value: 'active', label: 'Active' },
{ value: 'suspended', label: 'Suspended' },
{ value: 'closed', label: 'Closed' }
];
// Replace the courts <select> options with a comprehensive, bilingual list
const courtOptions = [
{ value: 'Superior Court of Quebec', label: 'Superior Court of Quebec / Cour supérieure du Québec' },
{ value: 'Court of Quebec - Civil Division', label: 'Court of Quebec (Civil Division) / Cour du Québec (Chambre civile)' },
{ value: 'Court of Quebec - Criminal and Penal Division', label: 'Court of Quebec (Criminal and Penal Division) / Cour du Québec (Chambre criminelle et pénale)' },
{ value: 'Court of Quebec - Youth Division', label: 'Court of Quebec (Youth Division) / Cour du Québec (Chambre de la jeunesse)' },
{ value: 'Court of Quebec - Small Claims', label: 'Court of Quebec (Small Claims Division) / Cour du Québec (Division des petites créances)' },
{ value: 'Court of Appeal of Quebec', label: 'Court of Appeal of Quebec / Cour d’appel du Québec' },
{ value: 'Federal Court', label: 'Federal Court / Cour fédérale' },
{ value: 'Supreme Court of Canada', label: 'Supreme Court of Canada / Cour suprême du Canada' },
{ value: 'Tribunal administratif du Québec', label: 'Administrative Tribunal of Quebec / Tribunal administratif du Québec (TAQ)' },
{ value: 'Tribunal administratif du travail', label: 'Administrative Labour Tribunal / Tribunal administratif du travail (TAT)' },
{ value: 'Tribunal des droits de la personne', label: 'Human Rights Tribunal / Tribunal des droits de la personne (TDPQ)' },
{ value: 'Tribunal des professions', label: 'Professions Tribunal / Tribunal des professions' },
{ value: 'Régie du logement', label: 'Administrative Housing Tribunal / Tribunal administratif du logement (TAL)' },
{ value: 'Commission des lésions professionnelles', label: 'Commission for Occupational Injuries / Commission des lésions professionnelles (CLP)' },
{ value: 'Commission des relations du travail', label: 'Labour Relations Commission / Commission des relations du travail (CRT)' },
// Add more as needed
];
if (loading) {
return (
<LayoutWithSidebar>
<div className="p-8">
<div className="max-w-4xl mx-auto">
<div className="animate-pulse space-y-4">
<div className="h-8 bg-gray-200 rounded w-1/3"></div>
<div className="h-96 bg-gray-200 rounded"></div>
</div>
</div>
</div>
</LayoutWithSidebar>
);
}
return (
<LayoutWithSidebar>
{/* Hero Section for Case */}
<CaseHeroSection
title={formData.title || 'Case Title'}
subtitle={formData.caseTypes?.join(', ') || 'Case Type'}
reference={formData.caseNumbers?.join(', ') || 'Case Number'}
summary={formData.description || 'No summary provided.'}
actions={
<>
<button
type="submit"
className="bg-white text-red-600 rounded-lg font-bold shadow-lg hover:scale-105 transition-all duration-200 px-8 py-4 text-lg"
onClick={handleSubmit}
disabled={saving}
>
{saving ? 'Saving...' : 'Save Changes'}
</button>
<a
href={`/live-cases/${id}`}
className="bg-transparent border-2 border-white text-white rounded-lg font-bold hover:bg-white hover:text-red-600 transition-all duration-200 px-8 py-4 text-lg"
target="_blank"
rel="noopener noreferrer"
>
View Public Page
</a>
</>
}
gradientFrom="from-red-600"
gradientTo="to-orange-600"
/>
<div className="p-6">
{/* Header */}
<div className="mb-6">
<div className="flex items-center gap-4 mb-4">
<button
onClick={() => router.push(`/admin/cases/${id}`)}
className="p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition-colors"
>
<ArrowLeft className="h-5 w-5" />
</button>
<div>
<h1 className="text-2xl font-bold text-gray-900">Edit Case</h1>
<p className="text-gray-600 mt-1">Update case information and settings</p>
</div>
</div>
</div>
{/* Form */}
<div className="max-w-4xl mx-auto">
{error && (
<div className="mb-6 bg-red-50 border border-red-200 rounded-lg p-4">
<div className="flex items-start">
<AlertCircle className="h-5 w-5 text-red-500 mr-2 mt-0.5 flex-shrink-0" />
<div className="text-red-700">
{error.includes('\n') ? (
<div>
<div className="font-medium mb-2">Please fix the following errors:</div>
<ul className="list-disc list-inside space-y-1">
{error.split('\n').filter(line => line.trim()).map((line, index) => (
<li key={index}>{line}</li>
))}
</ul>
</div>
) : (
<span>{error}</span>
)}
</div>
</div>
</div>
)}
{success && (
<div className="mb-6 bg-green-50 border border-green-200 rounded-lg p-4">
<div className="flex items-center">
<CheckCircle className="h-5 w-5 text-green-500 mr-2" />
<span className="text-green-700">{success}</span>
</div>
</div>
)}
<form onSubmit={handleSubmit} className="space-y-8">
{/* Logo Upload */}
<div className="mb-6">
<label className="block text-sm font-medium text-gray-700 mb-2">
Logo / Logo <span className="text-gray-400">(PNG, JPG, max 2MB)</span>
</label>
<div className="flex items-center gap-4">
{logoPreview || formData.logoUrl ? (
<img src={logoPreview || formData.logoUrl} alt="Logo preview" className="w-20 h-20 object-contain bg-white border rounded" />
) : (
<div className="w-20 h-20 bg-gray-100 border rounded flex items-center justify-center text-gray-400">No Logo</div>
)}
<input
type="file"
accept="image/*"
ref={logoInputRef}
onChange={handleLogoChange}
className="block"
/>
</div>
</div>
{/* Basic Information */}
<div className="bg-white rounded-lg shadow-sm border p-6">
<h2 className="text-lg font-semibold text-gray-900 mb-4 flex items-center">
<Scale className="h-5 w-5 mr-2 text-blue-600" />
Basic Case Information
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-2">
Case Title *
</label>
<input
type="text"
value={formData.title}
onChange={(e) => handleInputChange('title', e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="e.g., Bordeaux Detention Center Class Action"
/>
</div>
{/* Case Numbers (multi) */}
<div className="mb-6">
<label className="block text-sm font-medium text-gray-700 mb-2">
Case Number(s) / Numéro(s) de dossier
</label>
{formData.caseNumbers.map((num, idx) => (
<div key={idx} className="flex gap-2 mb-2">
<input
type="text"
value={num}
onChange={e => {
const newNumbers = [...formData.caseNumbers];
newNumbers[idx] = e.target.value;
setFormData(prev => ({ ...prev, caseNumbers: newNumbers }));
}}
className="w-full px-3 py-2 border border-gray-300 rounded-lg"
placeholder="e.g., 2024QCCS4539"
/>
<button type="button" onClick={() => setFormData(prev => ({ ...prev, caseNumbers: prev.caseNumbers.filter((_, i) => i !== idx) }))} className="text-red-500">X</button>
</div>
))}
<button type="button" onClick={() => setFormData(prev => ({ ...prev, caseNumbers: [...prev.caseNumbers, ''] }))} className="text-blue-600">+ Add Number / Ajouter</button>
</div>
{/* Case Types (multi) */}
<div className="mb-6">
<label className="block text-sm font-medium text-gray-700 mb-2">
Case Type(s) / Type(s) de dossier
</label>
<select
multiple
value={formData.caseTypes}
onChange={e => {
const options = Array.from(e.target.selectedOptions).map(opt => opt.value);
setFormData(prev => ({ ...prev, caseTypes: options }));
}}
className="w-full px-3 py-2 border border-gray-300 rounded-lg"
>
{caseTypes.map(type => (
<option key={type.value} value={type.value}>{type.label}</option>
))}
</select>
</div>
{/* Jurisdictions (multi) */}
<div className="mb-6">
<label className="block text-sm font-medium text-gray-700 mb-2">
Jurisdiction(s) / Juridiction(s)
</label>
<select
multiple
value={formData.jurisdictions}
onChange={e => {
const options = Array.from(e.target.selectedOptions).map(opt => opt.value);
setFormData(prev => ({ ...prev, jurisdictions: options }));
}}
className="w-full px-3 py-2 border border-gray-300 rounded-lg"
>
{jurisdictions.map(j => (
<option key={j} value={j}>{j}</option>
))}
</select>
</div>
{/* Courts (multi) */}
<div className="mb-6">
<label className="block text-sm font-medium text-gray-700 mb-2">
Court(s) / Tribunal(aux)
</label>
<select
multiple
value={formData.courts}
onChange={e => {
const options = Array.from(e.target.selectedOptions).map(opt => opt.value);
setFormData(prev => ({ ...prev, courts: options }));
}}
className="w-full px-3 py-2 border border-gray-300 rounded-lg"
>
{courtOptions.map(court => (
<option key={court.value} value={court.value}>{court.label}</option>
))}
</select>
</div>
{/* Court Location & Division */}
<div className="mb-6 grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Court Location / Lieu du tribunal
</label>
<input
type="text"
value={formData.courtLocation}
onChange={e => setFormData(prev => ({ ...prev, courtLocation: e.target.value }))}
className="w-full px-3 py-2 border border-gray-300 rounded-lg"
placeholder="e.g., Montreal, Quebec"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Division / Division
</label>
<input
type="text"
value={formData.division}
onChange={e => setFormData(prev => ({ ...prev, division: e.target.value }))}
className="w-full px-3 py-2 border border-gray-300 rounded-lg"
placeholder="e.g., Civil, Criminal, Family"
/>
</div>
</div>
<div className="md:col-span-2">
<label className="block text-sm font-medium text-gray-700 mb-2">
Description *
</label>
<textarea
value={formData.description}
onChange={(e) => handleInputChange('description', e.target.value)}
rows={4}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="Detailed description of the case and what it aims to achieve..."
/>
</div>
</div>
</div>
{/* Case Management */}
<div className="bg-white rounded-lg shadow-sm border p-6">
<h2 className="text-lg font-semibold text-gray-900 mb-4 flex items-center">
<Users className="h-5 w-5 mr-2 text-blue-600" />
Case Management
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Lead Lawyer * ({lawyers.length} lawyers available)
</label>
<select
value={formData.leadLawyerId}
onChange={(e) => {
console.log('Lawyer selection changed:', e.target.value);
handleInputChange('leadLawyerId', e.target.value);
}}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value="">Select a lawyer</option>
{lawyers.map(lawyer => {
console.log('Rendering lawyer option:', lawyer);
return (
<option key={lawyer.id} value={lawyer.id}>
{lawyer.name} {lawyer.title ? `(${lawyer.title})` : ''}
{lawyer.specialization ? ` - ${lawyer.specialization}` : ''}
</option>
);
})}
</select>
<p className="text-xs text-gray-500 mt-1">
Current selection: {formData.leadLawyerId || 'None'}
</p>
<p className="text-xs text-gray-500">
Debug: Lawyers loaded: {lawyers.length}, Current value: "{formData.leadLawyerId}"
</p>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Law Firm
</label>
<input
type="text"
value={formData.firmName}
readOnly
className="w-full px-3 py-2 border border-gray-300 rounded-lg bg-gray-50 text-gray-600 cursor-not-allowed"
placeholder="Law firm name (managed through lawyer profile)"
/>
<p className="text-xs text-gray-500 mt-1">
Law firm is managed through the lawyer's profile
</p>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Priority
</label>
<select
value={formData.priority}
onChange={(e) => handleInputChange('priority', e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
{priorities.map(priority => (
<option key={priority.value} value={priority.value}>
{priority.label}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Status
</label>
<select
value={formData.status}
onChange={(e) => handleInputChange('status', e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
{statuses.map(status => (
<option key={status.value} value={status.value}>
{status.label}
</option>
))}
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Budget (CAD)
</label>
<input
type="number"
value={formData.budget}
onChange={(e) => handleInputChange('budget', e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="0.00"
step="0.01"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Application Deadline
</label>
<input
type="date"
value={formData.applicationDeadline}
onChange={(e) => handleInputChange('applicationDeadline', e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
/>
</div>
</div>
<div className="mt-4 space-y-3">
<label className="flex items-center">
<input
type="checkbox"
checked={formData.isAcceptingApplications}
onChange={(e) => handleInputChange('isAcceptingApplications', e.target.checked)}
className="mr-2 h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"
/>
<span className="text-sm text-gray-700">Accepting new applications</span>
</label>
</div>
</div>
{/* Required Documents */}
<div className="bg-white rounded-lg shadow-sm border p-6">
<h2 className="text-lg font-semibold text-gray-900 mb-4 flex items-center">
<FileText className="h-5 w-5 mr-2 text-blue-600" />
Required Documents
</h2>
<div className="space-y-3">
{formData.requiredDocuments.map((doc, index) => (
<div key={index} className="flex items-center justify-between bg-gray-50 p-3 rounded-lg">
<span className="text-gray-700">{doc}</span>
<button
type="button"
onClick={() => removeDocument(index)}
className="text-red-500 hover:text-red-700 p-1"
>
<Trash2 className="h-4 w-4" />
</button>
</div>
))}
<div className="flex gap-2">
<input
type="text"
value={newDocument}
onChange={(e) => setNewDocument(e.target.value)}
className="flex-1 px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
placeholder="Add a required document..."
onKeyPress={(e) => e.key === 'Enter' && (e.preventDefault(), addDocument())}
/>
<button
type="button"
onClick={addDocument}
className="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors"
>
<Plus className="h-4 w-4" />
</button>
</div>
</div>
</div>
{/* Debug Section (Development Only) */}
{process.env.NODE_ENV === 'development' && (
<div className="bg-gray-50 rounded-lg shadow-sm border p-6">
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-semibold text-gray-900 flex items-center">
<span className="text-xs bg-yellow-100 text-yellow-800 px-2 py-1 rounded mr-2">DEV</span>
Debug Information
</h2>
<button
type="button"
onClick={toggleDebug}
className="text-sm text-gray-500 hover:text-gray-700"
>
{debugMode ? 'Hide' : 'Show'} Debug
</button>
</div>
{debugMode && (
<div className="space-y-4 text-sm">
<div>
<h3 className="font-medium text-gray-700 mb-2">Form Data:</h3>
<pre className="bg-white p-3 rounded border overflow-auto max-h-40 text-xs">
{JSON.stringify(formData, null, 2)}
</pre>
</div>
<div>
<h3 className="font-medium text-gray-700 mb-2">Lawyers Loaded:</h3>
<div className="text-xs text-gray-600">
{lawyers.length} lawyers available
</div>
</div>
<div>
<h3 className="font-medium text-gray-700 mb-2">Case ID:</h3>
<div className="text-xs text-gray-600 font-mono">
{id}
</div>
</div>
</div>
)}
</div>
)}
{/* Submit */}
<div className="bg-white rounded-lg shadow-sm border p-6">
<div className="flex items-center justify-between">
<button
type="button"
onClick={() => router.push(`/admin/cases/${id}`)}
className="px-6 py-2 text-gray-700 bg-gray-100 rounded-lg hover:bg-gray-200 transition-colors"
>
Cancel
</button>
<button
type="submit"
disabled={saving}
className="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center"
>
{saving ? (
<>
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white mr-2"></div>
Updating...
</>
) : (
<>
<Save className="h-4 w-4 mr-2" />
Update Case
</>
)}
</button>
</div>
</div>
</form>
</div>
</div>
</LayoutWithSidebar>
);
};
export default EditCasePage;