File size: 6,646 Bytes
c6133c6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | 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; // NEW: Receive AdminConfig for logo
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>
);
}; |