diff --git a/app/admin/layout.tsx b/app/admin/layout.tsx index 2121dcc..5fc5121 100644 --- a/app/admin/layout.tsx +++ b/app/admin/layout.tsx @@ -3,12 +3,11 @@ import Sidebar from "@/components/admin/Sidebar"; import { useAuth } from "@/contexts/AuthContext"; import { useRouter } from "next/navigation"; -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { Loading } from "@/components/ui/Loading"; import toast from "react-hot-toast"; -import { LogOut, User, ChevronDown } from "lucide-react"; import Logo from "@/components/Logo"; -import Link from "next/link"; +import UserDropdown from "@/components/UserDropdown"; export default function AdminLayout({ children, @@ -17,7 +16,6 @@ export default function AdminLayout({ }) { const { user, isAuthenticated, isLoading, logout } = useAuth(); const router = useRouter(); - const [dropdownOpen, setDropdownOpen] = useState(false); useEffect(() => { if (!isLoading && !isAuthenticated) { @@ -32,24 +30,6 @@ export default function AdminLayout({ } }, [isLoading, isAuthenticated, user, router]); - // Close dropdown when clicking outside - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - const target = event.target as HTMLElement; - if (!target.closest('.user-dropdown')) { - setDropdownOpen(false); - } - }; - - if (dropdownOpen) { - document.addEventListener('mousedown', handleClickOutside); - } - - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, [dropdownOpen]); - const handleLogout = async () => { await logout(); router.push("/login"); @@ -81,48 +61,12 @@ export default function AdminLayout({ - {/* User Dropdown */} -
- - - {/* Dropdown Menu */} - {dropdownOpen && ( -
- setDropdownOpen(false)} - className="flex items-center gap-3 px-4 py-3 hover:bg-gray-100 transition-colors" - > - - Profil - -
- -
- )} -
+ diff --git a/app/employe/layout.tsx b/app/employe/layout.tsx index 8e91de4..ca31a82 100644 --- a/app/employe/layout.tsx +++ b/app/employe/layout.tsx @@ -2,13 +2,14 @@ import { useAuth } from "@/contexts/AuthContext"; import { useRouter } from "next/navigation"; -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { Loading } from "@/components/ui/Loading"; import toast from "react-hot-toast"; -import { LogOut, Ticket, BarChart3, User, ChevronDown } from "lucide-react"; +import { Ticket, BarChart3 } from "lucide-react"; import Link from "next/link"; import { usePathname } from "next/navigation"; import Logo from "@/components/Logo"; +import UserDropdown from "@/components/UserDropdown"; export default function EmployeLayout({ children, @@ -18,7 +19,6 @@ export default function EmployeLayout({ const { user, isAuthenticated, isLoading, logout } = useAuth(); const router = useRouter(); const pathname = usePathname(); - const [dropdownOpen, setDropdownOpen] = useState(false); useEffect(() => { if (!isLoading && !isAuthenticated) { @@ -33,24 +33,6 @@ export default function EmployeLayout({ } }, [isLoading, isAuthenticated, user, router]); - // Close dropdown when clicking outside - useEffect(() => { - const handleClickOutside = (event: MouseEvent) => { - const target = event.target as HTMLElement; - if (!target.closest('.user-dropdown')) { - setDropdownOpen(false); - } - }; - - if (dropdownOpen) { - document.addEventListener('mousedown', handleClickOutside); - } - - return () => { - document.removeEventListener('mousedown', handleClickOutside); - }; - }, [dropdownOpen]); - const handleLogout = async () => { await logout(); router.push("/login"); @@ -129,48 +111,12 @@ export default function EmployeLayout({ - {/* User Dropdown */} -
- - - {/* Dropdown Menu */} - {dropdownOpen && ( -
- setDropdownOpen(false)} - className="flex items-center gap-3 px-4 py-3 hover:bg-gray-100 transition-colors" - > - - Profil - -
- -
- )} -
+ diff --git a/components/UserDropdown.tsx b/components/UserDropdown.tsx new file mode 100644 index 0000000..7264192 --- /dev/null +++ b/components/UserDropdown.tsx @@ -0,0 +1,93 @@ +'use client'; + +import React, { useState, useRef } from 'react'; +import Link from 'next/link'; +import { LogOut, User, ChevronDown } from 'lucide-react'; +import { useClickOutside } from '@/hooks/useClickOutside'; +import { cn } from '@/utils/helpers'; + +interface UserDropdownProps { + user: { + firstName?: string; + lastName?: string; + email?: string; + } | null; + profilePath: string; + onLogout: () => void; + accentColor?: 'blue' | 'green'; + className?: string; +} + +const accentColors = { + blue: 'bg-blue-600', + green: 'bg-green-600', +}; + +export const UserDropdown: React.FC = ({ + user, + profilePath, + onLogout, + accentColor = 'blue', + className, +}) => { + const [isOpen, setIsOpen] = useState(false); + const dropdownRef = useRef(null); + + useClickOutside(dropdownRef, () => setIsOpen(false), isOpen); + + const initials = `${user?.firstName?.charAt(0) || ''}${user?.lastName?.charAt(0) || ''}`; + + return ( +
+ + + {isOpen && ( +
+ setIsOpen(false)} + className="flex items-center gap-3 px-4 py-3 hover:bg-gray-100 transition-colors" + > + + Profil + +
+ +
+ )} +
+ ); +}; + +export default UserDropdown; diff --git a/hooks/useClickOutside.ts b/hooks/useClickOutside.ts new file mode 100644 index 0000000..d64d530 --- /dev/null +++ b/hooks/useClickOutside.ts @@ -0,0 +1,31 @@ +import { useEffect, RefObject } from 'react'; + +/** + * Hook to detect clicks outside of a specified element + * @param ref - Reference to the element to monitor + * @param callback - Function to call when clicking outside + * @param enabled - Whether the hook is active (default: true) + */ +export function useClickOutside( + ref: RefObject, + callback: () => void, + enabled: boolean = true +): void { + useEffect(() => { + if (!enabled) return; + + const handleClickOutside = (event: MouseEvent) => { + if (ref.current && !ref.current.contains(event.target as Node)) { + callback(); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [ref, callback, enabled]); +} + +export default useClickOutside;