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/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/lavocat.ca/private_html/src/pages/admin/lawyer-verifications.tsx
import React, { useEffect, useState } from 'react';
import Link from 'next/link';
import { format } from 'date-fns';

interface User {
  id: string;
  name: string;
  email: string;
  barNumber?: string;
  verificationStatus?: string;
  phone?: string;
  address?: string;
  barreauProfileJson?: any;
}

const BARREAU_SEARCH_URL = 'https://www.barreau.qc.ca/fr/trouver-un-avocat/';

const LABELS = {
  fr: {
    dashboard: "Tableau de vérification des avocats",
    field: "Champ",
    userInput: "Saisi par l'utilisateur",
    barreauProfile: "Profil Barreau",
    name: "Nom",
    email: "Courriel",
    barNumber: "Numéro de Barreau",
    phone: "Téléphone",
    address: "Adresse",
    practiceAreas: "Domaines de pratique",
    languages: "Langues",
    year: "Année",
    section: "Section",
    employer: "Employeur",
    status: "Statut",
    searchBarreau: "Rechercher Barreau",
    markVerified: "Marquer comme vérifié",
    approve: "Approuver",
    reject: "Rejeter",
    loading: "Chargement...",
    error: "Erreur : "
  },
  en: {
    dashboard: "Lawyer Verification Dashboard",
    field: "Field",
    userInput: "User Input",
    barreauProfile: "Barreau Profile",
    name: "Name",
    email: "Email",
    barNumber: "Bar Number",
    phone: "Phone",
    address: "Address",
    practiceAreas: "Practice Areas",
    languages: "Languages",
    year: "Year",
    section: "Section",
    employer: "Employer",
    status: "Status",
    searchBarreau: "Search Barreau",
    markVerified: "Mark as Verified",
    approve: "Approve",
    reject: "Reject",
    loading: "Loading...",
    error: "Error: "
  }
};

const fetchPendingLawyers = async (): Promise<User[]> => {
  const res = await fetch('/api/admin/lawyer-verifications');
  if (!res.ok) throw new Error('Failed to fetch users');
  return res.json();
};

const renderProfileRow = (label: string, userValue: any, barreauValue: any) => (
  <tr>
    <td className="p-2 border font-medium bg-gray-50">{label}</td>
    <td className="p-2 border">{userValue || <span className="text-gray-400">-</span>}</td>
    <td className="p-2 border">{barreauValue || <span className="text-gray-400">-</span>}</td>
  </tr>
);

const AdminLawyerVerifications: React.FC = () => {
  const [lawyers, setLawyers] = useState<User[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [language, setLanguage] = useState<'fr' | 'en'>('fr');
  const t = LABELS[language];

  useEffect(() => {
    fetchPendingLawyers()
      .then(setLawyers)
      .catch((e) => setError(e.message))
      .finally(() => setLoading(false));
  }, []);

  const handleAction = async (userId: string, action: 'verify' | 'approve' | 'reject') => {
    setLoading(true);
    setError(null);
    try {
      const res = await fetch(`/api/admin/lawyer-verifications/${userId}`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ action }),
      });
      if (!res.ok) throw new Error('Failed to update user');
      setLawyers((prev) => prev.filter((u) => u.id !== userId));
    } catch (e: any) {
      setError(e.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div className="max-w-5xl mx-auto py-10 px-4">
      <div className="flex justify-between items-center mb-6">
        <h1 className="text-3xl font-bold">{t.dashboard}</h1>
        <button
          onClick={() => setLanguage(language === 'fr' ? 'en' : 'fr')}
          className="bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded shadow"
        >
          {language === 'fr' ? 'EN' : 'FR'}
        </button>
      </div>
      {error && <div className="text-red-600 mb-4">{t.error}{error}</div>}
      {loading ? (
        <div>{t.loading}</div>
      ) : (
        <div className="space-y-8">
          {lawyers.map((lawyer) => {
            const barreau = lawyer.barreauProfileJson || {};
            return (
              <div key={lawyer.id} className="border rounded-lg shadow bg-white">
                <div className="flex flex-col md:flex-row">
                  <div className="flex-1 p-4">
                    <h2 className="text-xl font-semibold mb-2">{lawyer.name}</h2>
                    <table className="min-w-full border mb-4">
                      <thead>
                        <tr className="bg-gray-100">
                          <th className="p-2 border">{t.field}</th>
                          <th className="p-2 border">{t.userInput}</th>
                          <th className="p-2 border">{t.barreauProfile}</th>
                        </tr>
                      </thead>
                      <tbody>
                        {renderProfileRow(t.name, lawyer.name, barreau.name)}
                        {renderProfileRow(t.email, lawyer.email, barreau.email)}
                        {renderProfileRow(t.barNumber, lawyer.barNumber, barreau.barNumber)}
                        {renderProfileRow(t.phone, lawyer.phone, barreau.phone)}
                        {renderProfileRow(t.address, lawyer.address, barreau.address)}
                        {renderProfileRow(t.practiceAreas, '', (barreau.practiceAreas || []).join(', '))}
                        {renderProfileRow(t.languages, '', (barreau.languages || []).join(', '))}
                        {renderProfileRow(t.year, '', barreau.year)}
                        {renderProfileRow(t.section, '', barreau.section)}
                        {renderProfileRow(t.employer, '', barreau.employer)}
                        {renderProfileRow(t.status, lawyer.verificationStatus, barreau.status)}
                      </tbody>
                    </table>
                  </div>
                  <div className="flex flex-col justify-center items-center p-4 space-y-2 min-w-[200px]">
                    <a
                      href={BARREAU_SEARCH_URL}
                      target="_blank"
                      rel="noopener noreferrer"
                      className="text-blue-600 underline mb-2"
                    >
                      {t.searchBarreau}
                    </a>
                    <button
                      className="bg-yellow-500 text-white px-4 py-2 rounded mb-2"
                      onClick={() => handleAction(lawyer.id, 'verify')}
                    >
                      {t.markVerified}
                    </button>
                    <button
                      className="bg-green-600 text-white px-4 py-2 rounded mb-2"
                      onClick={() => handleAction(lawyer.id, 'approve')}
                    >
                      {t.approve}
                    </button>
                    <button
                      className="bg-red-600 text-white px-4 py-2 rounded"
                      onClick={() => handleAction(lawyer.id, 'reject')}
                    >
                      {t.reject}
                    </button>
                  </div>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
};

export default AdminLawyerVerifications; 

CasperSecurity Mini