Le popup de confidentialité réapparaissait systématiquement après chaque déconnexion/reconnexion car localStorage.clear() supprimait la clé 'odentas_info_suivi_ack_v1'. Solution: Sauvegarder et restaurer cette clé lors du nettoyage du localStorage dans LogoutButton.tsx. Fixes: Popup s'affiche plusieurs fois par jour au lieu d'une seule fois
110 lines
4 KiB
TypeScript
110 lines
4 KiB
TypeScript
// components/LogoutButton.tsx
|
|
"use client";
|
|
|
|
import { LogOut } from "lucide-react";
|
|
import { useRouter } from "next/navigation";
|
|
import { useEffect, useState } from "react";
|
|
import { createPortal } from "react-dom";
|
|
import { usePostHog } from "posthog-js/react";
|
|
|
|
export default function LogoutButton({ variant = "default", className }: { variant?: "default" | "compact"; className?: string }) {
|
|
const router = useRouter();
|
|
const posthog = usePostHog();
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
// Ancien calcul de headerOffset supprimé au profit d'un overlay pleine page via portal
|
|
|
|
async function handleLogout() {
|
|
setIsLoading(true);
|
|
try {
|
|
// 1. Appel API pour déconnexion côté serveur
|
|
await fetch("/api/auth/signout", {
|
|
method: "POST",
|
|
credentials: "include",
|
|
});
|
|
} catch (error) {
|
|
console.warn("Erreur lors de la déconnexion:", error);
|
|
}
|
|
|
|
// 2. Réinitialiser l'identité PostHog
|
|
posthog?.reset();
|
|
|
|
// 3. Nettoyage complet côté client (au cas où il resterait des données)
|
|
try {
|
|
// Sauvegarder la préférence du popup de confidentialité avant le nettoyage
|
|
const privacyAck = localStorage.getItem("odentas_info_suivi_ack_v1");
|
|
|
|
// Nettoyer localStorage
|
|
localStorage.removeItem("company_name");
|
|
localStorage.removeItem("company_api_name");
|
|
localStorage.removeItem("x-company-name-b64");
|
|
|
|
// Nettoyer sessionStorage
|
|
sessionStorage.removeItem("company_name");
|
|
|
|
// Nettoyer tout autre stockage local si nécessaire
|
|
localStorage.clear();
|
|
sessionStorage.clear();
|
|
|
|
// Restaurer la préférence du popup de confidentialité
|
|
if (privacyAck) {
|
|
localStorage.setItem("odentas_info_suivi_ack_v1", privacyAck);
|
|
}
|
|
} catch (error) {
|
|
console.warn("Erreur lors du nettoyage local:", error);
|
|
}
|
|
|
|
// 4. Redirection vers signin
|
|
router.push("/signin");
|
|
}
|
|
|
|
const triggerClass = variant === "compact"
|
|
? "inline-flex items-center gap-1 px-2 py-1 rounded-md text-[11px] font-medium bg-rose-50 text-rose-700 hover:bg-rose-100"
|
|
: "flex items-center gap-2 px-3 py-2 rounded-lg text-slate-600 hover:bg-slate-100";
|
|
|
|
return (
|
|
<>
|
|
<button
|
|
onClick={() => setIsOpen(true)}
|
|
className={`${triggerClass} ${className || ""}`}
|
|
>
|
|
<LogOut className={variant === "compact" ? "w-3.5 h-3.5" : "w-5 h-5"} />
|
|
<span>{variant === "compact" ? "Déconnexion" : "Déconnexion"}</span>
|
|
</button>
|
|
|
|
{/* Modale de confirmation */}
|
|
{isOpen && typeof document !== 'undefined' && createPortal(
|
|
(
|
|
<div aria-modal="true" role="dialog" className="fixed inset-0 z-[2000] flex items-center justify-center">
|
|
{/* Overlay */}
|
|
<div className="absolute inset-0 bg-black/40" onClick={() => !isLoading && setIsOpen(false)} />
|
|
{/* Contenu */}
|
|
<div className="relative z-10 w-full max-w-sm rounded-xl bg-white p-6 shadow-xl">
|
|
<h2 className="text-lg font-semibold text-gray-900 mb-2">Se déconnecter ?</h2>
|
|
<p className="text-gray-600 mb-4">
|
|
Vous allez être déconnecté de votre Espace Paie Employeur.
|
|
</p>
|
|
<div className="flex gap-3">
|
|
<button
|
|
onClick={handleLogout}
|
|
disabled={isLoading}
|
|
className="flex-1 bg-red-600 hover:bg-red-700 disabled:opacity-50 text-white px-4 py-2 rounded-lg font-medium transition"
|
|
>
|
|
{isLoading ? "Déconnexion..." : "Se déconnecter"}
|
|
</button>
|
|
<button
|
|
onClick={() => setIsOpen(false)}
|
|
className="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded-lg font-medium transition"
|
|
>
|
|
Annuler
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
),
|
|
document.body
|
|
)}
|
|
</>
|
|
);
|
|
}
|