![]() 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, { 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;