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/backups/lavocat.quebec/backup-20250730-021618/src/pages/lawyer/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/backups/lavocat.quebec/backup-20250730-021618/src/pages/lawyer/dashboard.tsx
import React, { useEffect, useState } from 'react';
import { useSession } from 'next-auth/react';
import { useRouter } from 'next/router';
import LayoutWithSidebar from '@/components/LayoutWithSidebar';
import { useRequireRole, USER_ROLES } from '@/lib/auth-utils';
import { toast } from 'react-hot-toast';
import CaseWidget from '@/components/CaseWidget';
import PaymentWidget from '@/components/payments/PaymentWidget';
import DashboardModal from '@/components/DashboardModal';
import { useDashboardModal } from '@/hooks/useDashboardModal';
import { 
  Briefcase, 
  Users, 
  Calendar, 
  BarChart2, 
  MessageSquare, 
  User,
  FileText,
  DollarSign,
  Clock,
  CheckCircle,
  AlertTriangle,
  TrendingUp,
  Plus,
  Phone,
  Video,
  ArrowRight
} from 'lucide-react';

const navCards = [
  {
    title: 'My Cases',
    description: 'View and manage all your assigned cases.',
    icon: <Briefcase className="h-8 w-8 text-blue-600" />,
    route: '/lawyer/cases',
    color: 'from-blue-500 to-blue-600',
  },
  {
    title: 'Consultations',
    description: 'Manage your legal consultations and bookings.',
    icon: <MessageSquare className="h-8 w-8 text-green-600" />,
    route: '/lawyer/consultations',
    color: 'from-green-500 to-green-600',
  },
  {
    title: 'My Team',
    description: 'Collaborate with your legal team and assign tasks.',
    icon: <Users className="h-8 w-8 text-purple-600" />,
    route: '/lawyer/team',
    color: 'from-purple-500 to-purple-600',
  },
  {
    title: 'Calendar',
    description: 'See all your hearings, meetings, and deadlines.',
    icon: <Calendar className="h-8 w-8 text-orange-600" />,
    route: '/lawyer/calendar',
    color: 'from-orange-500 to-orange-600',
  },
  {
    title: 'Analytics',
    description: 'Track your performance and case outcomes.',
    icon: <BarChart2 className="h-8 w-8 text-pink-600" />,
    route: '/lawyer/analytics',
    color: 'from-pink-500 to-pink-600',
  },
  {
    title: 'Clients',
    description: 'Manage your clients and communications.',
    icon: <User className="h-8 w-8 text-teal-600" />,
    route: '/lawyer/clients',
    color: 'from-teal-500 to-teal-600',
  },
  {
    title: 'Profile',
    description: 'Manage your professional profile and credentials.',
    icon: <User className="h-8 w-8 text-indigo-600" />,
    route: '/lawyer/profile',
    color: 'from-indigo-500 to-indigo-600',
  },
  {
    title: 'My Applications',
    description: 'View and manage your submitted applications.',
    icon: <FileText className="h-8 w-8 text-cyan-600" />,
    route: '/lawyer/applications',
    color: 'from-cyan-500 to-cyan-600',
  },
];

const LawyerDashboard: React.FC = () => {
  const { data: session, status } = useSession();
  const router = useRouter();
  const [loading, setLoading] = useState(true);
  const [stats, setStats] = useState<{
    cases: number;
    consultations: number;
    team: number;
    upcoming: number;
    clients: number;
    billing: number;
    caseOutcomes: number;
    clientSatisfaction: number;
    pendingDocuments: number;
    totalCases: number;
    totalConsultations: number;
    totalClients: number;
    caseSuccessRate: number;
    consultationCompletionRate: number;
    taskCompletionRate: number;
    recentActivity: number;
    recentCases: number;
    recentConsultations: number;
    recentTasks: number;
    upcomingEvents: any[];
  } | null>(null);
  const { isModalOpen, currentRoute, modalTitle, openModal, closeModal } = useDashboardModal();

  // Role-based access control - allow LAWYER, ADMIN, SUPERADMIN to access lawyer dashboard
  const { isAuthorized } = useRequireRole([
    USER_ROLES.LAWYER, 
    USER_ROLES.ADMIN, 
    USER_ROLES.SUPERADMIN, USER_ROLES.SUPERADMIN
  ], '/');

  // Determine verification status
  const isVerified = session?.user?.isVerifiedLawyer || session?.user?.verificationStatus === 'VERIFIED_BARREAU';

  useEffect(() => {
    if (status === 'loading') return;
    if (!session || !isAuthorized) {
      router.push('/');
      return;
    }
    fetchStats();
  }, [session, status, router, isAuthorized]);

  const fetchStats = async () => {
    try {
      const response = await fetch('/api/lawyer/dashboard-stats');
      if (response.ok) {
        const data = await response.json();
        setStats({
          cases: data.stats.cases || 0,
          consultations: data.stats.consultations || 0,
          team: data.stats.team || 0,
          upcoming: data.stats.upcoming || 0,
          clients: data.stats.clients || 0,
          billing: data.stats.billing || 0,
          caseOutcomes: data.stats.completedCases || 0,
          clientSatisfaction: data.stats.clientSatisfaction || 0,
          pendingDocuments: data.stats.pendingTasks || 0,
          totalCases: data.stats.totalCases || 0,
          totalConsultations: data.stats.totalConsultations || 0,
          totalClients: data.stats.totalClients || 0,
          caseSuccessRate: data.stats.caseSuccessRate || 0,
          consultationCompletionRate: data.stats.consultationCompletionRate || 0,
          taskCompletionRate: data.stats.taskCompletionRate || 0,
          recentActivity: data.stats.recentActivity || 0,
          recentCases: data.stats.recentCases || 0,
          recentConsultations: data.stats.recentConsultations || 0,
          recentTasks: data.stats.recentTasks || 0,
          upcomingEvents: data.stats.upcomingEvents || []
        });
      } else {
        toast.error('Failed to load stats');
      }
    } catch (e) {
      console.error('Error fetching stats:', e);
      toast.error('Failed to load stats');
    } finally {
      setLoading(false);
    }
  };

  const handleCardClick = (route: string, title: string) => {
    openModal(route, title);
  };

  if (status === 'loading' || loading) {
    return (
      <LayoutWithSidebar>
        <div className="flex items-center justify-center min-h-screen">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600"></div>
        </div>
      </LayoutWithSidebar>
    );
  }

  return (
    <LayoutWithSidebar>
      <div className="max-w-7xl mx-auto px-4 py-8">
        {/* Verification Banner */}
        {!isVerified && (
          <div className="mb-6 p-4 bg-yellow-100 border-l-4 border-yellow-500 text-yellow-800 rounded">
            <div className="flex items-center mb-2">
              <AlertTriangle className="h-6 w-6 mr-2 text-yellow-600" />
              <span className="font-semibold">Account Not Verified</span>
            </div>
            <div>
              You must complete Barreau verification to access all features. Sensitive actions (accepting cases, messaging, uploading files, etc.) are disabled until you are verified.<br />
              <a href="/register-verified" className="text-blue-700 underline">Click here to verify now or upload proof for manual review.</a>
            </div>
          </div>
        )}
        {/* Welcome Section */}
        <div className="mb-8">
          <h1 className="text-3xl font-bold text-gray-900 mb-2">
            Welcome, {session?.user?.name || 'Lawyer'}
          </h1>
          <p className="text-gray-600">
            This is your professional command center. Manage your cases, consultations, team, and more—all in one place.
          </p>
        </div>

        {/* Enhanced Stats */}
        <div className="grid grid-cols-2 md:grid-cols-5 lg:grid-cols-9 gap-4 mb-10">
          <div className="bg-gradient-to-r from-blue-500 to-blue-600 text-white rounded-lg p-4 shadow">
            <div className="text-xs">Active Cases</div>
            <div className="text-2xl font-bold">{stats?.cases ?? '-'}</div>
          </div>
          <div className="bg-gradient-to-r from-green-500 to-green-600 text-white rounded-lg p-4 shadow">
            <div className="text-xs">Consultations</div>
            <div className="text-2xl font-bold">{stats?.consultations ?? '-'}</div>
          </div>
          <div className="bg-gradient-to-r from-purple-500 to-purple-600 text-white rounded-lg p-4 shadow">
            <div className="text-xs">Team Members</div>
            <div className="text-2xl font-bold">{stats?.team ?? '-'}</div>
          </div>
          <div className="bg-gradient-to-r from-orange-500 to-orange-600 text-white rounded-lg p-4 shadow">
            <div className="text-xs">Upcoming</div>
            <div className="text-2xl font-bold">{stats?.upcoming ?? '-'}</div>
          </div>
          <div className="bg-gradient-to-r from-teal-500 to-teal-600 text-white rounded-lg p-4 shadow">
            <div className="text-xs">Clients</div>
            <div className="text-2xl font-bold">{stats?.clients ?? '-'}</div>
          </div>
          <div className="bg-gradient-to-r from-emerald-500 to-emerald-600 text-white rounded-lg p-4 shadow">
            <div className="text-xs">Billing ($)</div>
            <div className="text-2xl font-bold">${((stats?.billing || 0) / 1000).toFixed(0)}k</div>
          </div>
          <div className="bg-gradient-to-r from-indigo-500 to-indigo-600 text-white rounded-lg p-4 shadow">
            <div className="text-xs">Case Outcomes</div>
            <div className="text-2xl font-bold">{stats?.caseOutcomes ?? '-'}</div>
          </div>
          <div className="bg-gradient-to-r from-yellow-500 to-yellow-600 text-white rounded-lg p-4 shadow">
            <div className="text-xs">Satisfaction</div>
            <div className="text-2xl font-bold">{stats?.clientSatisfaction ?? '-'}/5</div>
          </div>
          <div className="bg-gradient-to-r from-red-500 to-red-600 text-white rounded-lg p-4 shadow">
            <div className="text-xs">Pending Docs</div>
            <div className="text-2xl font-bold">{stats?.pendingDocuments ?? '-'}</div>
          </div>
        </div>

        {/* Quick Actions */}
        <div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-8">
          <h2 className="text-xl font-semibold text-gray-900 mb-4">Quick Actions</h2>
          <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
            <button
              onClick={() => handleCardClick('/lawyer/cases', 'My Cases')}
              className={`flex items-center p-4 border border-gray-200 rounded-lg transition-colors ${!isVerified ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50'}`}
              disabled={!isVerified}
              title={!isVerified ? 'You must be verified to access this feature.' : ''}
            >
              <FileText className="h-6 w-6 text-blue-600 mr-3" />
              <div className="text-left">
                <div className="font-medium text-gray-900">My Cases</div>
                <div className="text-sm text-gray-500">View and manage your cases</div>
              </div>
            </button>
            <button
              onClick={() => router.push('/hire/new-case')}
              className={`flex items-center p-4 border border-gray-200 rounded-lg transition-colors ${!isVerified ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50'}`}
              disabled={!isVerified}
              title={!isVerified ? 'You must be verified to access this feature.' : ''}
            >
              <Plus className="h-6 w-6 text-green-600 mr-3" />
              <div className="text-left">
                <div className="font-medium text-gray-900">New Case</div>
                <div className="text-sm text-gray-500">Create a new case</div>
              </div>
            </button>
            <button
              onClick={() => handleCardClick('/lawyer/consultations', 'Consultations')}
              className={`flex items-center p-4 border border-gray-200 rounded-lg transition-colors ${!isVerified ? 'opacity-50 cursor-not-allowed' : 'hover:bg-gray-50'}`}
              disabled={!isVerified}
              title={!isVerified ? 'You must be verified to access this feature.' : ''}
            >
              <MessageSquare className="h-6 w-6 text-purple-600 mr-3" />
              <div className="text-left">
                <div className="font-medium text-gray-900">Consultations</div>
                <div className="text-sm text-gray-500">Manage consultations</div>
              </div>
            </button>
          </div>
        </div>

        {/* Payment Widget */}
        <div className="mb-8">
          <PaymentWidget 
            userId={session?.user?.id || ''} 
            userRole={session?.user?.role || 'LAWYER'} 
            compact={false}
          />
        </div>

        {/* Upcoming Events and Recent Activity */}
        <div className="grid grid-cols-1 lg:grid-cols-2 gap-8 mb-8">
          {/* Upcoming Events */}
          <div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
            <h2 className="text-xl font-semibold text-gray-900 mb-4 flex items-center">
              <Calendar className="h-5 w-5 mr-2 text-orange-600" />
              Upcoming Events
            </h2>
            {stats?.upcomingEvents && stats.upcomingEvents.length > 0 ? (
              <div className="space-y-3">
                {stats.upcomingEvents.slice(0, 5).map((event: any, index: number) => (
                  <div key={index} className="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
                    <div>
                      <p className="font-medium text-gray-900">{event.clientName}</p>
                      <p className="text-sm text-gray-600">
                        {new Date(event.date).toLocaleDateString()} at {event.time}
                      </p>
                    </div>
                    <span className="text-xs bg-orange-100 text-orange-800 px-2 py-1 rounded-full">
                      {event.type}
                    </span>
                  </div>
                ))}
              </div>
            ) : (
              <p className="text-gray-600">No upcoming events</p>
            )}
          </div>

          {/* Recent Activity */}
          <div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
            <h2 className="text-xl font-semibold text-gray-900 mb-4 flex items-center">
              <TrendingUp className="h-5 w-5 mr-2 text-green-600" />
              Recent Activity
            </h2>
            <div className="space-y-4">
              <div className="flex items-center justify-between">
                <span className="text-gray-600">Recent Cases</span>
                <span className="font-semibold text-gray-900">{stats?.recentCases || 0}</span>
              </div>
              <div className="flex items-center justify-between">
                <span className="text-gray-600">Recent Consultations</span>
                <span className="font-semibold text-gray-900">{stats?.recentConsultations || 0}</span>
              </div>
              <div className="flex items-center justify-between">
                <span className="text-gray-600">Recent Tasks</span>
                <span className="font-semibold text-gray-900">{stats?.recentTasks || 0}</span>
              </div>
              <div className="pt-2 border-t border-gray-200">
                <div className="flex items-center justify-between">
                  <span className="text-gray-600">Total Activity (30 days)</span>
                  <span className="font-semibold text-green-600">{stats?.recentActivity || 0}</span>
                </div>
              </div>
            </div>
          </div>
        </div>

        {/* Performance Metrics */}
        <div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-8">
          <h2 className="text-xl font-semibold text-gray-900 mb-4">Performance Metrics</h2>
          <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
            <div className="text-center">
              <div className="text-3xl font-bold text-blue-600 mb-2">{stats?.caseSuccessRate || 0}%</div>
              <div className="text-sm text-gray-600">Case Success Rate</div>
            </div>
            <div className="text-center">
              <div className="text-3xl font-bold text-green-600 mb-2">{stats?.consultationCompletionRate || 0}%</div>
              <div className="text-sm text-gray-600">Consultation Completion</div>
            </div>
            <div className="text-center">
              <div className="text-3xl font-bold text-purple-600 mb-2">{stats?.taskCompletionRate || 0}%</div>
              <div className="text-sm text-gray-600">Task Completion</div>
            </div>
          </div>
        </div>

        {/* Navigation Cards */}
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
          {navCards.map((card, index) => (
            <button
              key={index}
              onClick={() => handleCardClick(card.route, card.title)}
              className="group relative bg-white rounded-xl shadow-sm border border-gray-200 p-6 hover:shadow-lg transition-all duration-200 hover:scale-105"
            >
              <div className="flex items-center justify-between mb-4">
                <div className={`p-3 rounded-lg bg-gradient-to-r ${card.color}`}>
                  {card.icon}
                </div>
                <div className="opacity-0 group-hover:opacity-100 transition-opacity">
                  <ArrowRight className="h-5 w-5 text-gray-400" />
                </div>
              </div>
              <h3 className="text-lg font-semibold text-gray-900 mb-2">{card.title}</h3>
              <p className="text-sm text-gray-600">{card.description}</p>
            </button>
          ))}
        </div>

        {/* Dashboard Modal */}
        <DashboardModal
          isOpen={isModalOpen}
          onClose={closeModal}
          route={currentRoute}
          title={modalTitle}
        />
      </div>
    </LayoutWithSidebar>
  );
};

export default LawyerDashboard; 

CasperSecurity Mini