| import React from 'react'; |
| import { Camera, Globe, PhoneCall, User, LogIn, Settings, Info, MessageSquarePlus } from 'lucide-react'; |
| import { Language, UserAccount, AdminConfig } from '../types'; |
| import { TRANSLATIONS } from '../constants/translations'; |
|
|
| interface HeaderProps { |
| language: Language; |
| onLanguageChange: (lang: Language) => void; |
| onBookClick: () => void; |
| user?: UserAccount; |
| config?: AdminConfig; |
| onOpenUserCenter?: () => void; |
| onLoginClick?: () => void; |
| onOpenAdmin?: () => void; |
| onOpenAbout?: () => void; |
| onOpenFeedback?: () => void; |
| } |
|
|
| export const Header: React.FC<HeaderProps> = ({ language, onLanguageChange, onBookClick, user, config, onOpenUserCenter, onLoginClick, onOpenAdmin, onOpenAbout, onOpenFeedback }) => { |
| const t = TRANSLATIONS[language]; |
| const isStaffOrAdmin = user && (user.role === 'admin' || user.role === 'staff'); |
|
|
| return ( |
| <header className="w-full py-4 sm:py-6 px-4 sm:px-8 border-b border-rose-100 bg-white/80 backdrop-blur-md sticky top-0 z-50"> |
| <div className="max-w-7xl mx-auto flex items-center justify-between"> |
| <div className="flex items-center gap-3 cursor-pointer" onClick={() => window.location.reload()}> |
| {config?.logoUrl ? ( |
| <div className="w-10 h-10 sm:w-12 sm:h-12 rounded-full overflow-hidden shadow-lg ring-2 ring-rose-100"> |
| <img src={config.logoUrl} alt="Logo" className="w-full h-full object-cover" /> |
| </div> |
| ) : ( |
| <div className="w-10 h-10 sm:w-12 sm:h-12 bg-gray-900 rounded-full flex items-center justify-center text-rose-300 shadow-lg ring-2 ring-rose-100"> |
| <Camera className="w-6 h-6" /> |
| </div> |
| )} |
| |
| <div> |
| <h1 className="font-serif text-xl sm:text-2xl font-bold text-gray-900 tracking-tight leading-none"> |
| {t.title} |
| </h1> |
| <p className="text-[10px] sm:text-xs text-rose-500 font-sans tracking-widest uppercase font-bold mt-1"> |
| {t.subtitle} |
| </p> |
| </div> |
| </div> |
| |
| <div className="flex items-center gap-3 sm:gap-4"> |
| {/* About Us Button (Desktop) */} |
| <button |
| onClick={onOpenAbout} |
| className="hidden sm:flex items-center gap-1 text-xs font-bold text-gray-600 hover:text-rose-600 transition-colors mr-2" |
| > |
| <Info className="w-3.5 h-3.5" /> |
| {t.aboutUsBtn} |
| </button> |
| |
| {/* Feedback Button */} |
| <button |
| onClick={onOpenFeedback} |
| className="flex items-center justify-center w-8 h-8 rounded-full hover:bg-gray-100 text-gray-500 hover:text-rose-500 transition-colors" |
| title="Feedback" |
| > |
| <MessageSquarePlus className="w-5 h-5" /> |
| </button> |
| |
| {/* Admin Panel Button */} |
| {isStaffOrAdmin && ( |
| <button |
| onClick={onOpenAdmin} |
| className="hidden sm:flex items-center gap-2 px-3 py-1.5 bg-gray-800 text-white rounded-full text-xs font-bold hover:bg-gray-700 transition-colors" |
| > |
| <Settings className="w-3.5 h-3.5" /> |
| Admin Panel |
| </button> |
| )} |
| |
| {/* Book Now Button (Mobile: Icon only, Desktop: Text) */} |
| <button |
| onClick={onBookClick} |
| className="flex items-center gap-2 bg-rose-600 hover:bg-rose-700 text-white px-4 py-2 rounded-full shadow-lg shadow-rose-200 transition-all hover:scale-105 active:scale-95" |
| > |
| <PhoneCall className="w-4 h-4" /> |
| <span className="hidden sm:inline text-xs font-bold uppercase tracking-wide">{t.bookNow}</span> |
| </button> |
| |
| {/* User Avatar / Points OR Login Button */} |
| {user ? ( |
| <button |
| onClick={onOpenUserCenter} |
| className="flex items-center gap-2 bg-gray-50 hover:bg-rose-50 border border-gray-200 pl-2 pr-3 py-1.5 rounded-full transition-colors group" |
| > |
| <div className="w-6 h-6 rounded-full bg-gray-200 flex items-center justify-center overflow-hidden"> |
| {user.avatar ? <img src={user.avatar} className="w-full h-full object-cover" /> : <User className="w-4 h-4 text-gray-500" />} |
| </div> |
| <div className="flex flex-col items-start leading-none"> |
| <span className="text-[9px] text-gray-400 font-bold uppercase">{t.myPoints}</span> |
| <span className="text-xs font-bold text-amber-500 group-hover:text-amber-600">{user.points}</span> |
| </div> |
| </button> |
| ) : ( |
| <button |
| onClick={onLoginClick} |
| className="flex items-center gap-2 text-gray-600 hover:text-rose-600 font-bold text-xs" |
| > |
| <LogIn className="w-4 h-4" /> |
| <span className="hidden sm:inline">{t.authLogin}</span> |
| </button> |
| )} |
| |
| {/* Language Selector */} |
| <div className="relative group hidden sm:block"> |
| <button className="flex items-center gap-2 px-3 py-1.5 rounded-full bg-white border border-gray-200 text-xs font-semibold text-gray-700 hover:bg-gray-50 transition-colors"> |
| <Globe className="w-3.5 h-3.5" /> |
| <span className="uppercase">{language}</span> |
| </button> |
| |
| <div className="absolute right-0 mt-2 w-32 bg-white rounded-xl shadow-xl border border-gray-100 overflow-hidden hidden group-hover:block animate-fade-in z-50"> |
| <div className="flex flex-col py-1"> |
| {['en', 'zh', 'ja', 'ko', 'es', 'fr'].map((lang) => ( |
| <button |
| key={lang} |
| onClick={() => onLanguageChange(lang as Language)} |
| className={`px-4 py-2 text-left text-xs hover:bg-rose-50 ${language === lang ? 'text-rose-600 font-bold bg-rose-50' : 'text-gray-700'}`} |
| > |
| {lang === 'en' ? 'English' : |
| lang === 'zh' ? '中文' : |
| lang === 'ja' ? '日本語' : |
| lang === 'ko' ? '한국어' : |
| lang === 'es' ? 'Español' : 'Français'} |
| </button> |
| ))} |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </header> |
| ); |
| }; |