| | 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> |
| | ); |
| | }; |