Files
dashboard-cpsp/components/Header.tsx
T

165 lines
6.7 KiB
TypeScript

import React, { useEffect, useRef, useState } from 'react';
import { useAuth } from '../context/AuthContext.tsx';
import { useFarm } from '../context/FarmContext.tsx';
import { formatDateId, resolveCycleStatus } from '../utils/format.ts';
type HeaderProps = {
onToggleSidebar: () => void;
isTimelineVisible: boolean;
onToggleTimeline: () => void;
};
const Header: React.FC<HeaderProps> = ({
onToggleSidebar,
isTimelineVisible,
onToggleTimeline,
}) => {
const { user, logout } = useAuth();
const {
sites,
kandangs,
cycles,
selectedSiteId,
selectedKandangId,
selectedCycleId,
setSelectedSiteId,
setSelectedKandangId,
setSelectedCycleId,
} = useFarm();
const [open, setOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const onClick = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setOpen(false);
}
};
document.addEventListener('mousedown', onClick);
return () => document.removeEventListener('mousedown', onClick);
}, []);
if (!user) return null;
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">
<div className="flex items-center gap-3 flex-wrap">
<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" />
</button>
<div className="flex items-center gap-2">
<i className="fa-solid fa-map-marker-alt text-gray-500" />
<select
value={selectedSiteId ?? ''}
onChange={(e) => setSelectedSiteId(e.target.value ? Number(e.target.value) : null)}
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"
>
{sites.length === 0 && <option value="">Tidak ada site</option>}
{sites.map((site) => (
<option key={site.id} value={site.id}>
{site.site_name}
</option>
))}
</select>
</div>
<div className="flex items-center gap-2">
<i className="fa-solid fa-warehouse text-gray-500" />
<select
value={selectedKandangId ?? ''}
onChange={(e) => setSelectedKandangId(e.target.value ? Number(e.target.value) : null)}
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.length === 0 && <option value="">Tidak ada kandang</option>}
{kandangs.map((kandang) => (
<option key={kandang.id} value={kandang.id}>
{kandang.kandang_name}
</option>
))}
</select>
</div>
<div className="flex items-center gap-2">
<i className="fa-solid fa-rotate text-gray-500" />
<select
value={selectedCycleId ?? ''}
onChange={(e) => setSelectedCycleId(e.target.value ? Number(e.target.value) : null)}
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"
>
{cycles.length === 0 && <option value="">Tidak ada siklus</option>}
{cycles.map((cycle) => (
<option key={cycle.id} value={cycle.id}>
{formatDateId(cycle.start_date)} (
{resolveCycleStatus(cycle) === 'active' ? 'Aktif' : 'Selesai'})
</option>
))}
</select>
</div>
<a
href="/button/"
title="Feed In/Out Button"
className="inline-flex items-center gap-2 px-3 py-1.5 border border-red-200 rounded-md bg-red-50 text-sm font-semibold text-red-700 hover:bg-red-100 hover:border-red-300"
>
<i className="fa-solid fa-hand-pointer" />
<span className="hidden sm:inline">Feed In/Out Button</span>
</a>
</div>
<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'}`}
/>
</button>
<div className="relative ml-4" ref={dropdownRef}>
<button
onClick={() => setOpen(!open)}
className="flex items-center space-x-2 focus:outline-none"
>
<div className="w-10 h-10 rounded-full bg-red-100 text-red-700 flex items-center justify-center font-bold">
{user.user_name.slice(0, 1).toUpperCase()}
</div>
<div className="hidden lg:block text-left">
<p className="text-sm font-semibold text-gray-800">{user.user_name}</p>
<p className="text-xs text-gray-500">
{user.status === 'superadmin' ? 'Admin' : 'Pengguna'}
</p>
</div>
<i className="fa-solid fa-chevron-down text-xs text-gray-500" />
</button>
{open && (
<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 z-50">
<div className="px-4 py-3 border-b">
<p className="text-sm font-semibold text-gray-800">{user.user_name}</p>
<p className="text-xs text-gray-500">
{user.status === 'superadmin' ? 'Admin' : 'Pengguna'}
</p>
</div>
<button
onClick={() => {
void logout();
setOpen(false);
}}
className="w-full text-left 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" />
Keluar
</button>
</div>
)}
</div>
</div>
</div>
</header>
);
};
export default Header;