253 lines
16 KiB
TypeScript
253 lines
16 KiB
TypeScript
import React, { useState, useEffect, useRef } from 'react';
|
|
import { Settings, ShieldCheck, LogOut, ChevronDown, Users, BarChart3, Database, Shield, ScanEye, Brain } from 'lucide-react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { Tooltip } from './Tooltip';
|
|
|
|
interface HeaderProps {
|
|
user: any;
|
|
logout: () => void;
|
|
openApiKeyModal: () => void;
|
|
projectTitle?: string;
|
|
}
|
|
|
|
export const Header: React.FC<HeaderProps> = ({ user, logout, openApiKeyModal, projectTitle }) => {
|
|
const { t, i18n } = useTranslation();
|
|
const [isLangOpen, setIsLangOpen] = useState(false);
|
|
const [isAdminMenuOpen, setIsAdminMenuOpen] = useState(false);
|
|
const [hasPersonalKey, setHasPersonalKey] = useState(false);
|
|
const adminMenuRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
const checkKey = () => setHasPersonalKey(!!localStorage.getItem('gemini_api_key'));
|
|
checkKey();
|
|
window.addEventListener('storage', checkKey);
|
|
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
if (adminMenuRef.current && !adminMenuRef.current.contains(event.target as Node)) {
|
|
setIsAdminMenuOpen(false);
|
|
}
|
|
};
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
|
|
return () => {
|
|
window.removeEventListener('storage', checkKey);
|
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
};
|
|
}, []);
|
|
|
|
const languages = [
|
|
{ code: 'en', label: 'English' },
|
|
{ code: 'tr', label: 'Türkçe' },
|
|
{ code: 'de', label: 'Deutsch' },
|
|
{ code: 'fr', label: 'Français' },
|
|
{ code: 'es', label: 'Español' }
|
|
];
|
|
|
|
const changeLanguage = (lng: string) => {
|
|
i18n.changeLanguage(lng);
|
|
setIsLangOpen(false);
|
|
};
|
|
|
|
return (
|
|
<header className="bg-white border-b border-stone-100 relative z-50">
|
|
{/* Upper Utility Bar */}
|
|
<div className="bg-stone-50/50 border-b border-stone-100 px-8 py-2 flex items-center justify-between backdrop-blur-sm">
|
|
<div className="flex items-center gap-4">
|
|
<Tooltip content="Engine Status: Online (v13.1)" position="bottom">
|
|
<div className="flex items-center gap-2 px-2 py-1 bg-white rounded-md border border-stone-200/50 shadow-sm transition-all">
|
|
<div className="w-1.5 h-1.5 bg-green-500 rounded-full animate-pulse shadow-[0_0_8px_rgba(34,197,94,0.4)]"></div>
|
|
<span className="text-[8px] font-black uppercase tracking-widest text-stone-400">System Live</span>
|
|
</div>
|
|
</Tooltip>
|
|
|
|
<Tooltip content={hasPersonalKey ? "Personal Key Active (Beta Mode)" : "System Key (Standard)"} position="bottom">
|
|
<div
|
|
onClick={openApiKeyModal}
|
|
className={`flex items-center gap-2 px-2 py-1 rounded-md cursor-pointer border transition-all ${hasPersonalKey ? 'bg-indigo-50 border-indigo-200' : 'bg-white border-stone-200/50 shadow-sm'}`}
|
|
>
|
|
<div className={`w-1.5 h-1.5 rounded-full ${hasPersonalKey ? 'bg-indigo-500 animate-pulse' : 'bg-blue-400'}`}></div>
|
|
<span className={`text-[8px] font-black uppercase tracking-widest ${hasPersonalKey ? 'text-indigo-400' : 'text-stone-400'}`}>
|
|
{hasPersonalKey ? 'V-DNA KEY' : 'API CORE'}
|
|
</span>
|
|
</div>
|
|
</Tooltip>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-6">
|
|
<span className="text-[9px] font-black uppercase tracking-[0.2em] text-stone-300 select-none">
|
|
{user?.email}
|
|
</span>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<button
|
|
onClick={() => setIsLangOpen(!isLangOpen)}
|
|
className="flex items-center gap-2 bg-white border border-stone-200/50 px-2 py-1 rounded-md shadow-sm hover:bg-stone-100 transition-all"
|
|
>
|
|
<span className="text-[9px] font-bold text-stone-500 uppercase">{i18n.language}</span>
|
|
<span className="text-[7px] text-stone-400">▼</span>
|
|
</button>
|
|
|
|
{isLangOpen && (
|
|
<div className="absolute right-16 top-9 bg-white border border-stone-100 rounded-xl shadow-2xl p-2 min-w-[120px] z-[60] flex flex-col gap-1">
|
|
{languages.map(l => (
|
|
<button
|
|
key={l.code}
|
|
onClick={() => changeLanguage(l.code)}
|
|
className={`text-left px-3 py-2 rounded-lg text-xs font-bold transition-all ${i18n.language === l.code ? 'bg-stone-900 text-white' : 'text-stone-500 hover:bg-stone-50'}`}
|
|
>
|
|
{l.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
<Tooltip content={t('general.logout')} position="bottom">
|
|
<button onClick={logout} className="p-1 px-2 text-stone-400 hover:text-red-500 hover:bg-red-50 rounded-md transition-all">
|
|
<LogOut className="w-3.5 h-3.5" />
|
|
</button>
|
|
</Tooltip>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Main Navigation Bar */}
|
|
<div className="py-6 px-10 flex items-center justify-between">
|
|
<div className="flex items-center gap-8">
|
|
<div className="flex flex-col text-left">
|
|
<div className="flex items-center gap-4">
|
|
<h1 className="text-4xl font-black text-stone-900 tracking-tighter leading-none cursor-pointer" onClick={() => window.location.href = '/'}>{t('home.title')}</h1>
|
|
{projectTitle && (
|
|
<>
|
|
<div className="h-8 w-[1px] bg-stone-200 rotate-[20deg] mx-2" />
|
|
<h2 className="text-2xl font-black text-purple-600 tracking-tight leading-none truncate max-w-[400px]">{projectTitle}</h2>
|
|
</>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center gap-3 mt-1">
|
|
<p className="text-[10px] text-stone-400 font-bold uppercase tracking-[0.3em]">{t('home.subtitle')}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-4">
|
|
<Tooltip content={`Plan: ${user?.plan || 'Free'}`} position="bottom">
|
|
<button
|
|
onClick={() => window.location.href = '/pricing'}
|
|
className="flex items-center gap-3 px-5 py-2.5 bg-gradient-to-br from-amber-50 to-orange-50 rounded-2xl border border-amber-100/50 shadow-sm hover:shadow-md hover:border-amber-200 transition-all group"
|
|
>
|
|
<div className="text-lg group-hover:scale-110 transition-transform">🪙</div>
|
|
<div className="flex flex-col items-start">
|
|
<span className="text-[11px] font-black text-amber-600 leading-none">
|
|
{user?.credits ?? 10}
|
|
</span>
|
|
<span className="text-[8px] font-bold uppercase tracking-widest text-amber-500/70">Credits</span>
|
|
</div>
|
|
</button>
|
|
</Tooltip>
|
|
|
|
<div className="h-8 w-px bg-stone-100 mx-2"></div>
|
|
|
|
<div className="flex items-center gap-2">
|
|
{user?.role === 'ADMIN' && (
|
|
<div className="relative" ref={adminMenuRef}>
|
|
<button
|
|
onClick={() => setIsAdminMenuOpen(!isAdminMenuOpen)}
|
|
className={`p-3 rounded-2xl transition-all border ${isAdminMenuOpen ? 'bg-purple-600 text-white border-purple-500 shadow-lg shadow-purple-200' : 'text-stone-400 hover:text-purple-600 hover:bg-purple-50 border-transparent hover:border-purple-100'}`}
|
|
title="Admin Fast Access"
|
|
>
|
|
<ShieldCheck className="w-5 h-5" />
|
|
</button>
|
|
|
|
{isAdminMenuOpen && (
|
|
<div className="absolute right-0 top-full mt-3 w-64 bg-white/95 backdrop-blur-xl border border-stone-200 rounded-[2rem] shadow-2xl p-3 z-[100] animate-in fade-in slide-in-from-top-2 duration-200">
|
|
<div className="px-3 py-2 mb-2">
|
|
<p className="text-[10px] font-black text-stone-400 uppercase tracking-[0.2em]">Command Center</p>
|
|
</div>
|
|
<div className="space-y-1">
|
|
<button
|
|
onClick={() => window.location.href = '/admin'}
|
|
className="w-full flex items-center gap-4 px-4 py-3 text-stone-600 hover:text-purple-600 hover:bg-purple-50 rounded-2xl transition-all text-xs font-bold group"
|
|
>
|
|
<div className="bg-purple-100 p-2 rounded-xl text-purple-600 group-hover:scale-110 transition-transform">
|
|
<Users className="w-4 h-4" />
|
|
</div>
|
|
<div className="flex flex-col items-start">
|
|
<span>User Accounts</span>
|
|
<span className="text-[9px] text-stone-400 font-normal">Manage permissions & credits</span>
|
|
</div>
|
|
</button>
|
|
<button
|
|
onClick={() => window.location.href = '/admin/analytics'}
|
|
className="w-full flex items-center gap-4 px-4 py-3 text-stone-600 hover:text-blue-600 hover:bg-blue-50 rounded-2xl transition-all text-xs font-bold group"
|
|
>
|
|
<div className="bg-blue-100 p-2 rounded-xl text-blue-600 group-hover:scale-110 transition-transform">
|
|
<BarChart3 className="w-4 h-4" />
|
|
</div>
|
|
<div className="flex flex-col items-start">
|
|
<span>Engine Analytics</span>
|
|
<span className="text-[9px] text-stone-400 font-normal">Monitor system performance</span>
|
|
</div>
|
|
</button>
|
|
<button
|
|
onClick={() => window.location.href = '/admin/config'}
|
|
className="w-full flex items-center gap-4 px-4 py-3 text-stone-600 hover:text-amber-600 hover:bg-amber-50 rounded-2xl transition-all text-xs font-bold group"
|
|
>
|
|
<div className="bg-amber-100 p-2 rounded-xl text-amber-600 group-hover:scale-110 transition-transform">
|
|
<Database className="w-4 h-4" />
|
|
</div>
|
|
<div className="flex flex-col items-start">
|
|
<span>System Config</span>
|
|
<span className="text-[9px] text-stone-400 font-normal">Global variables & keys</span>
|
|
</div>
|
|
</button>
|
|
<button
|
|
onClick={() => window.location.href = '/xray'}
|
|
className="w-full flex items-center gap-4 px-4 py-3 text-stone-600 hover:text-purple-600 hover:bg-purple-50 rounded-2xl transition-all text-xs font-bold group"
|
|
>
|
|
<div className="bg-purple-100 p-2 rounded-xl text-purple-600 group-hover:scale-110 transition-transform">
|
|
<ScanEye className="w-4 h-4" />
|
|
</div>
|
|
<div className="flex flex-col items-start">
|
|
<span className="text-[9px] text-stone-400 font-normal">Deep dive into data</span>
|
|
</div>
|
|
</button>
|
|
<button
|
|
onClick={() => window.location.href = '/scorecard'}
|
|
className="w-full flex items-center gap-4 px-4 py-3 text-stone-600 hover:text-blue-600 hover:bg-blue-50 rounded-2xl transition-all text-xs font-bold group"
|
|
>
|
|
<div className="bg-blue-100 p-2 rounded-xl text-blue-600 group-hover:scale-110 transition-transform">
|
|
<Brain className="w-4 h-4" />
|
|
</div>
|
|
<div className="flex flex-col items-start">
|
|
<span>Neuro-Scorecard</span>
|
|
<span className="text-[9px] text-stone-400 font-normal">Predict conversion</span>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
<div className="h-px bg-stone-100 my-3 mx-2"></div>
|
|
<button
|
|
onClick={() => window.location.href = '/admin'}
|
|
className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-stone-50 hover:bg-stone-900 text-stone-500 hover:text-white rounded-2xl transition-all text-[10px] font-black uppercase tracking-widest"
|
|
>
|
|
<Shield className="w-3 h-3" />
|
|
Admin Dashboard
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
<button
|
|
onClick={() => window.location.href = '/settings'}
|
|
className="p-3 text-stone-400 hover:text-stone-900 hover:bg-stone-50 rounded-2xl transition-all border border-transparent hover:border-stone-100"
|
|
>
|
|
<Settings className="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
);
|
|
};
|
|
|
|
export default Header;
|