T.ME/BIBIL_0DAY
CasperSecurity


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/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/lavocat.ca/private_html/src/pages/admin/cases/create.tsx
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
} from 'lucide-react';

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;
  caseNumber: string;
  caseType: string;
  jurisdiction: string;
  court: string;
  leadLawyerId: string;
  firmName: string;
  priority: string;
  budget: string;
  status: string;
  applicationDeadline: string;
  isAcceptingApplications: boolean;
  requiresApproval: boolean;
  eligibilityCriteria: {
    minimumAge?: number;
    maximumAge?: number;
    location?: string[];
    incomeLimit?: number;
    specificConditions?: string;
  };
  requiredDocuments: string[];
  applicationInstructions: string;
}

const CreateCasePage = () => {
  const { data: session, status } = useSession();
  const router = useRouter();
  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 [formData, setFormData] = useState<CaseFormData>({
    title: '',
    description: '',
    caseNumber: '',
    caseType: 'class_action',
    jurisdiction: 'Quebec',
    court: '',
    leadLawyerId: '',
    firmName: '',
    priority: 'medium',
    budget: '',
    status: 'pending',
    applicationDeadline: '',
    isAcceptingApplications: true,
    requiresApproval: true,
    eligibilityCriteria: {},
    requiredDocuments: ['Government ID', 'Proof of Detention/Incarceration'],
    applicationInstructions: ''
  });

  const [newDocument, setNewDocument] = useState('');

  useEffect(() => {
    if (status === 'loading') return;
    
    if (!session || !['SUPERADMIN', 'ADMIN'].includes(session.user.role)) {
      router.push('/admin');
      return;
    }

    fetchData();
  }, [session, status, router]);

  const fetchData = async () => {
    try {
      const [lawyersRes, firmsRes] = await Promise.all([
        fetch('/api/admin/users?role=LAWYER,ADMIN'),
        fetch('/api/admin/law-firms')
      ]);

      let lawyersData: any = null;
      let firmsData: any = null;

      if (lawyersRes.ok) {
        lawyersData = await lawyersRes.json();
        setLawyers(lawyersData.users || []);
      }

      if (firmsRes.ok) {
        firmsData = await firmsRes.json();
        setLawFirms(firmsData.firms || []);
      }

      // Auto-select current user's firm and set as lead lawyer if ADMIN
      if (session?.user.role === 'ADMIN' && lawyersData) {
        const currentUser = lawyersData.users?.find((u: User) => u.id === session.user.id);
        if (currentUser?.lawFirmId && firmsData) {
          const userFirm = firmsData.firms?.find((f: LawFirm) => f.id === currentUser.lawFirmId);
          setFormData(prev => ({
            ...prev,
            leadLawyerId: currentUser.id,
            firmName: userFirm?.name || ''
          }));
        }
      }

    } catch (error) {
      console.error('Error fetching data:', error);
      setError('Failed to load lawyers and firms');
    } 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 required = ['title', 'description', 'caseNumber', 'leadLawyerId', 'court'];
    const missing = required.filter(field => !formData[field as keyof CaseFormData]);
    
    if (missing.length > 0) {
      setError(`Please fill in all required fields: ${missing.join(', ')}`);
      return false;
    }

    // Check case number format (Quebec court format)
    if (formData.caseNumber && !/^\d{4}QC[A-Z]{2,3}\d+$/.test(formData.caseNumber)) {
      setError('Case number should follow Quebec court format (e.g., 2024QCCS4539)');
      return false;
    }

    return true;
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    if (!validateForm()) return;

    setSaving(true);
    setError('');

    try {
      const response = await fetch('/api/admin/cases', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          ...formData,
          budget: formData.budget ? parseFloat(formData.budget) : null,
          eligibilityCriteria: JSON.stringify(formData.eligibilityCriteria)
        }),
      });

      if (response.ok) {
        const result = await response.json();
        setSuccess('Case created successfully!');
        
        // Redirect to case management after a short delay
        setTimeout(() => {
          router.push('/admin/case-management');
        }, 2000);
      } else {
        const errorData = await response.json();
        setError(errorData.error || 'Failed to create case');
      }
    } catch (error) {
      console.error('Error creating case:', error);
      setError('Network error. Please try again.');
    } finally {
      setSaving(false);
    }
  };

  const caseTypes = [
    { value: 'class_action', label: 'Class Action' },
    { value: 'individual', label: 'Individual Case' },
    { value: 'collective', label: 'Collective Action' },
    { value: 'human_rights', label: 'Human Rights' },
    { value: 'prison_conditions', label: 'Prison Conditions' },
    { value: 'discrimination', label: 'Discrimination' },
    { value: 'negligence', label: 'Negligence' },
    { value: 'constitutional', label: 'Constitutional Challenge' }
  ];

  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' }
  ];

  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>
      <div className="p-6">
        {/* Header */}
        <div className="mb-6">
          <div className="flex items-center gap-4 mb-4">
            <button
              onClick={() => router.push('/admin/case-management')}
              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">Create New Legal Case</h1>
              <p className="text-gray-600 mt-1">Add a new case for user applications</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-center">
                <AlertCircle className="h-5 w-5 text-red-500 mr-2" />
                <span className="text-red-700">{error}</span>
              </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">
            {/* 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>

                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-2">
                    Case Number *
                  </label>
                  <input
                    type="text"
                    value={formData.caseNumber}
                    onChange={(e) => handleInputChange('caseNumber', 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., 2024QCCS4539"
                  />
                </div>

                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-2">
                    Case Type
                  </label>
                  <select
                    value={formData.caseType}
                    onChange={(e) => handleInputChange('caseType', 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"
                  >
                    {caseTypes.map(type => (
                      <option key={type.value} value={type.value}>{type.label}</option>
                    ))}
                  </select>
                </div>

                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-2">
                    Jurisdiction
                  </label>
                  <select
                    value={formData.jurisdiction}
                    onChange={(e) => handleInputChange('jurisdiction', 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"
                  >
                    {jurisdictions.map(jurisdiction => (
                      <option key={jurisdiction} value={jurisdiction}>{jurisdiction}</option>
                    ))}
                  </select>
                </div>

                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-2">
                    Court *
                  </label>
                  <input
                    type="text"
                    value={formData.court}
                    onChange={(e) => handleInputChange('court', 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., Quebec Superior Court"
                  />
                </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 *
                  </label>
                  <select
                    value={formData.leadLawyerId}
                    onChange={(e) => 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 => (
                      <option key={lawyer.id} value={lawyer.id}>
                        {lawyer.name} {lawyer.title ? `(${lawyer.title})` : ''}
                        {lawyer.specialization ? ` - ${lawyer.specialization}` : ''}
                      </option>
                    ))}
                  </select>
                </div>

                <div>
                  <label className="block text-sm font-medium text-gray-700 mb-2">
                    Law Firm
                  </label>
                  <input
                    type="text"
                    value={formData.firmName}
                    onChange={(e) => handleInputChange('firmName', 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="Law firm name"
                  />
                </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>

                <label className="flex items-center">
                  <input
                    type="checkbox"
                    checked={formData.requiresApproval}
                    onChange={(e) => handleInputChange('requiresApproval', 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">Requires approval for 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 text-sm"
                    >
                      Remove
                    </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>

            {/* Application Instructions */}
            <div className="bg-white rounded-lg shadow-sm border p-6">
              <h2 className="text-lg font-semibold text-gray-900 mb-4">
                Application Instructions
              </h2>
              
              <textarea
                value={formData.applicationInstructions}
                onChange={(e) => handleInputChange('applicationInstructions', 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="Special instructions for applicants..."
              />
            </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/case-management')}
                  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>
                      Creating...
                    </>
                  ) : (
                    <>
                      <Save className="h-4 w-4 mr-2" />
                      Create Case
                    </>
                  )}
                </button>
              </div>
            </div>
          </form>
        </div>
      </div>
    </LayoutWithSidebar>
  );
};

export default CreateCasePage; 

CasperSecurity Mini