170 lines
6.6 KiB
TypeScript
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;
|