feat: Améliorer accessibilité des voyants d'urgence (rouge/bleu)

This commit is contained in:
odentas 2025-12-04 18:06:49 +01:00
parent 839190fa8f
commit 605d55f4e6

View file

@ -32,6 +32,44 @@ function classNames(...arr: Array<string | false | null | undefined>) {
return arr.filter(Boolean).join(' ');
}
// Fonction pour calculer l'urgence basée sur la date de début
function getUrgencyIndicator(startDate: string | null): { color: string; show: boolean; label: string } {
if (!startDate) return { color: '', show: false, label: '' };
const start = new Date(startDate);
const today = new Date();
today.setHours(0, 0, 0, 0);
start.setHours(0, 0, 0, 0);
const diffTime = start.getTime() - today.getTime();
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
// Rouge si contrat démarre aujourd'hui ou dans le passé
if (diffDays <= 0) {
return { color: 'bg-red-600', show: true, label: 'Urgent - Début aujourd\'hui ou passé' };
}
// Bleu si moins de 48 heures (moins de 2 jours)
if (diffDays < 2) {
return { color: 'bg-blue-500', show: true, label: 'Urgent - Début dans moins de 48h' };
}
// Pas de voyant si plus de 48 heures
return { color: '', show: false, label: '' };
}
// Fonction pour trier les enregistrements par date de début (ordre croissant)
function sortByStartDate(records: AirtableRecord[]): AirtableRecord[] {
return [...records].sort((a, b) => {
const dateA = a.fields?.start_date || a.fields?.['Date de début'];
const dateB = b.fields?.start_date || b.fields?.['Date de début'];
if (!dateA && !dateB) return 0;
if (!dateA) return 1;
if (!dateB) return -1;
return new Date(dateA).getTime() - new Date(dateB).getTime();
});
}
// Composant pour un bouton désactivé avec tooltip
function DisabledButton({ label, className }: { label: string; className?: string }) {
const btnRef = useRef<HTMLButtonElement | null>(null);
@ -1217,6 +1255,23 @@ export default function SignaturesElectroniques() {
<div className="text-slate-500">Aucun document à signer.</div>
) : (
<>
{/* Légende des voyants d'urgence */}
<div className="mb-4 p-3 rounded-lg bg-slate-50 border border-slate-200">
<div className="flex items-center gap-6 text-xs">
<div className="flex items-center gap-2">
<span className="font-semibold text-slate-700">Légende :</span>
</div>
<div className="flex items-center gap-2">
<span className="w-3 h-3 rounded-full bg-red-600" />
<span className="text-slate-600">Début aujourd'hui ou passé</span>
</div>
<div className="flex items-center gap-2">
<span className="w-3 h-3 rounded-full bg-blue-500" />
<span className="text-slate-600">Début dans moins de 48h</span>
</div>
</div>
</div>
{/* Table 1: employeur pending (contrats + avenants) */}
<div className="rounded-xl border overflow-hidden shadow-sm">
<div className="flex items-center justify-between gap-3 px-3 py-2 border-b bg-white/60 backdrop-blur supports-[backdrop-filter]:bg-white/60[backdrop-filter]:bg-slate-900/60">
@ -1227,6 +1282,7 @@ export default function SignaturesElectroniques() {
<table className="min-w-full text-sm">
<thead>
<tr className="text-left text-slate-500 border-b bg-slate-50/60">
<th className="px-3 py-2 font-medium whitespace-nowrap w-8"></th>
<th className="px-3 py-2 font-medium whitespace-nowrap">Type</th>
<th className="px-3 py-2 font-medium whitespace-nowrap">Référence</th>
<th className="px-3 py-2 font-medium whitespace-nowrap">Salarié</th>
@ -1237,7 +1293,7 @@ export default function SignaturesElectroniques() {
</tr>
</thead>
<tbody>
{[...recordsEmployeur, ...avenantsEmployeur].map((rec, idx) => {
{sortByStartDate([...recordsEmployeur, ...avenantsEmployeur]).map((rec, idx) => {
const f = rec.fields || {};
const isAvenant = f.is_avenant === true;
const isSigned = String(f['Contrat signé par employeur'] || '').toLowerCase() === 'oui';
@ -1249,9 +1305,15 @@ export default function SignaturesElectroniques() {
const docType = isAvenant ? 'Avenant' : 'Contrat';
const urlPath = isAvenant ? `/staff/avenants/${rec.id}` : `/contrats/${rec.id}`;
const docLabel = isAvenant ? `Avenant · ${ref}` : `Contrat · ${ref}`;
const urgency = getUrgencyIndicator(dateDebut);
return (
<tr key={rec.id} className={classNames(idx % 2 ? 'bg-white' : 'bg-slate-50/30', 'hover:bg-slate-50 transition-colors')}>
<td className="px-3 py-2 text-center">
{urgency.show && (
<span className={`inline-block w-3 h-3 rounded-full ${urgency.color}`} title={urgency.label} />
)}
</td>
<td className="px-3 py-2 text-slate-700 whitespace-nowrap">
<span className={classNames(
'inline-flex items-center gap-1 text-xs px-2 py-1 rounded-full border font-medium',
@ -1313,6 +1375,7 @@ export default function SignaturesElectroniques() {
<table className="min-w-full text-sm">
<thead>
<tr className="text-left text-slate-500 border-b bg-slate-50/60">
<th className="px-3 py-2 font-medium whitespace-nowrap w-8"></th>
<th className="px-3 py-2 font-medium whitespace-nowrap">Type</th>
<th className="px-3 py-2 font-medium whitespace-nowrap">Référence</th>
<th className="px-3 py-2 font-medium whitespace-nowrap">Salarié</th>
@ -1323,7 +1386,7 @@ export default function SignaturesElectroniques() {
</tr>
</thead>
<tbody>
{[...recordsSalarie, ...avenantsSalarie].map((rec, idx) => {
{sortByStartDate([...recordsSalarie, ...avenantsSalarie]).map((rec, idx) => {
const f = rec.fields || {};
const isAvenant = f.is_avenant === true;
const mat = f.employee_matricule || f['Matricule API'] || f.Matricule || '—';
@ -1334,9 +1397,15 @@ export default function SignaturesElectroniques() {
const docType = isAvenant ? 'Avenant' : 'Contrat';
const urlPath = isAvenant ? `/staff/avenants/${rec.id}` : `/contrats/${rec.id}`;
const docLabel = isAvenant ? `Avenant · ${ref}` : `Contrat · ${ref}`;
const urgency = getUrgencyIndicator(dateDebut);
return (
<tr key={rec.id} className={classNames(idx % 2 ? 'bg-white' : 'bg-slate-50/30', 'hover:bg-slate-50 transition-colors')}>
<td className="px-3 py-2 text-center">
{urgency.show && (
<span className={`inline-block w-3 h-3 rounded-full ${urgency.color}`} title={urgency.label} />
)}
</td>
<td className="px-3 py-2 text-slate-700 whitespace-nowrap">
<span className={classNames(
'inline-flex items-center gap-1 text-xs px-2 py-1 rounded-full border font-medium',