Files
dashboard/components/Header.tsx
T
Alberto-Audrix 32a36cceff
CI / lint-and-test (push) Canceled after 0s
first commit
2026-07-28 08:55:05 +07:00

170 lines
6.6 KiB
TypeScript

import React, { useState, useRef, useEffect } from 'react';
import { View } from '../types.ts';
import { Kandang } from '../types/counting.ts';
import { useAppContext } from '../context/AppContext.tsx';
import { userAvatars } from './auth/PersonaSelector.tsx';
interface HeaderProps {
onToggleSidebar: () => void;
setView: (view: View) => void;
isTimelineVisible: boolean;
onToggleTimeline: () => void;
selectedArea: string;
onAreaChange: (area: string) => void;
selectedKandangId: number | null;
onKandangChange: (id: number | null) => void;
kandangs: Kandang[];
}
const Header: React.FC<HeaderProps> = ({
onToggleSidebar,
setView,
isTimelineVisible,
onToggleTimeline,
selectedArea,
onAreaChange,
selectedKandangId,
onKandangChange,
kandangs,
}) => {
const { currentUser, logout, roles } = useAppContext();
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setIsDropdownOpen(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [dropdownRef]);
if (!currentUser) return null;
const currentUserRole = roles.find((r) => r.id === currentUser.roleId)?.name || 'Pengguna';
const avatarUrl = userAvatars[currentUser.id] || 'https://randomuser.me/api/portraits/lego/1.jpg';
return (
<header className="bg-white shadow-sm h-16 flex-shrink-0 z-10 border-b border-gray-200">
<div className="flex items-center justify-between h-16 px-4 sm:px-6 lg:px-8">
{/* Left side - Burger menu + Kandang dropdown */}
<div className="flex items-center gap-3">
<button
onClick={onToggleSidebar}
className="text-gray-500 hover:text-gray-800 focus:outline-none -ml-2"
aria-label="Toggle sidebar"
>
<i className="fa-solid fa-bars text-xl w-10 h-10 p-2 rounded-full hover:bg-gray-100"></i>
</button>
{/* Area Dropdown */}
<div className="flex items-center gap-2">
<i className="fa-solid fa-map-marker-alt text-gray-500"></i>
<select
value={selectedArea}
onChange={(e) => onAreaChange(e.target.value)}
className="px-3 py-1.5 border border-gray-300 rounded-md shadow-sm focus:ring-red-500 focus:border-red-500 bg-white text-sm text-gray-900"
>
<option value="Sukawarna">Sukawarna</option>
</select>
</div>
{/* Kandang Dropdown */}
<div className="flex items-center gap-2">
<i className="fa-solid fa-warehouse text-gray-500"></i>
<select
value={selectedKandangId === null ? '' : selectedKandangId}
onChange={(e) => {
const val = e.target.value;
onKandangChange(val === '' ? null : Number(val));
}}
className="px-3 py-1.5 border border-gray-300 rounded-md shadow-sm focus:ring-red-500 focus:border-red-500 bg-white text-sm text-gray-900"
>
{kandangs.map((k) => (
<option key={k.id} value={k.id}>
{k.name}
</option>
))}
</select>
</div>
</div>
{/* Right side items */}
<div className="flex items-center ml-auto">
<button
onClick={onToggleTimeline}
title="Toggle Linimasa"
className="hidden sm:flex items-center text-gray-500 hover:text-gray-800 focus:outline-none p-2 rounded-full hover:bg-gray-100"
>
<i
className={`fa-solid fa-calendar-week text-xl ${isTimelineVisible ? 'text-red-600' : 'text-gray-400'}`}
></i>
</button>
<div className="relative ml-4" ref={dropdownRef}>
<button
onClick={() => setIsDropdownOpen(!isDropdownOpen)}
className="flex items-center space-x-2 focus:outline-none"
>
<img
className="w-10 h-10 rounded-full object-cover"
src={avatarUrl}
alt="Foto profil pengguna"
/>
<div className="hidden lg:block text-left">
<p className="text-sm font-semibold text-gray-800">{currentUser.name}</p>
<p className="text-xs text-gray-500">{currentUserRole}</p>
</div>
<i className="fa-solid fa-chevron-down text-xs text-gray-500"></i>
</button>
{isDropdownOpen && (
<div className="origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg py-1 bg-white ring-1 ring-black ring-opacity-5 focus:outline-none z-50">
<div className="px-4 py-3 border-b">
<p className="text-sm font-semibold text-gray-800">{currentUser.name}</p>
<p className="text-xs text-gray-500">{currentUser.email}</p>
</div>
<button
onClick={() => {
setView('profile');
setIsDropdownOpen(false);
}}
className="w-full text-left block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center"
>
<i className="fa-solid fa-user-circle w-4 mr-2 text-gray-500"></i>
<span>Profil Saya</span>
</button>
<button
onClick={() => {
onToggleTimeline();
setIsDropdownOpen(false);
}}
className="w-full text-left block sm:hidden px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center"
>
<i
className={`fa-solid fa-calendar-week w-4 mr-2 ${isTimelineVisible ? 'text-red-600' : 'text-gray-500'}`}
></i>
<span>{isTimelineVisible ? 'Sembunyikan' : 'Tampilkan'} Linimasa</span>
</button>
<button
onClick={logout}
className="w-full text-left block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 flex items-center"
>
<i className="fa-solid fa-sign-out-alt w-4 mr-2 text-gray-500"></i>{' '}
<span>Keluar</span>
</button>
</div>
)}
</div>
</div>
</div>
</header>
);
};
export default Header;