2026-01-04 21:58:59 -05:00
"use client" ;
2026-01-19 18:31:08 -05:00
import { usePathname , useRouter } from "next/navigation" ;
2026-01-04 21:58:59 -05:00
import Link from "next/link" ;
2026-01-19 05:15:11 -05:00
import Image from "next/image" ;
2026-01-19 18:31:08 -05:00
import PropTypes from "prop-types" ;
2026-01-04 21:58:59 -05:00
import { ThemeToggle } from "@/shared/components" ;
2026-01-19 18:31:08 -05:00
import { OAUTH _PROVIDERS , APIKEY _PROVIDERS } from "@/shared/constants/config" ;
2026-01-04 21:58:59 -05:00
const getPageInfo = ( pathname ) => {
if ( ! pathname ) return { title : "" , description : "" , breadcrumbs : [ ] } ;
// Provider detail page: /dashboard/providers/[id]
const providerMatch = pathname . match ( /\/providers\/([^/]+)$/ ) ;
if ( providerMatch ) {
const providerId = providerMatch [ 1 ] ;
const providerInfo = OAUTH _PROVIDERS [ providerId ] || APIKEY _PROVIDERS [ providerId ] ;
if ( providerInfo ) {
return {
title : providerInfo . name ,
description : "" ,
breadcrumbs : [
{ label : "Providers" , href : "/dashboard/providers" } ,
{ label : providerInfo . name , image : ` /providers/ ${ providerInfo . id } .png ` }
]
} ;
}
}
if ( pathname . includes ( "/providers" ) ) return { title : "Providers" , description : "Manage your AI provider connections" , breadcrumbs : [ ] } ;
if ( pathname . includes ( "/combos" ) ) return { title : "Combos" , description : "Model combos with fallback" , breadcrumbs : [ ] } ;
2026-01-18 22:39:30 -05:00
if ( pathname . includes ( "/usage" ) ) return { title : "Usage & Analytics" , description : "Monitor your API usage, token consumption, and request logs" , breadcrumbs : [ ] } ;
2026-03-04 23:25:03 -05:00
if ( pathname . includes ( "/mitm" ) ) return { title : "MITM Proxy" , description : "Intercept CLI tool traffic and route through 9Router" , breadcrumbs : [ ] } ;
2026-01-04 21:58:59 -05:00
if ( pathname . includes ( "/cli-tools" ) ) return { title : "CLI Tools" , description : "Configure CLI tools" , breadcrumbs : [ ] } ;
if ( pathname . includes ( "/endpoint" ) ) return { title : "Endpoint" , description : "API endpoint configuration" , breadcrumbs : [ ] } ;
if ( pathname . includes ( "/profile" ) ) return { title : "Settings" , description : "Manage your preferences" , breadcrumbs : [ ] } ;
2026-03-01 21:31:16 -05:00
if ( pathname . includes ( "/translator" ) ) return { title : "Translator" , description : "Debug translation flow between formats" , breadcrumbs : [ ] } ;
if ( pathname . includes ( "/console-log" ) ) return { title : "Console Log" , description : "Live server console output" , breadcrumbs : [ ] } ;
2026-01-04 21:58:59 -05:00
if ( pathname === "/dashboard" ) return { title : "Endpoint" , description : "API endpoint configuration" , breadcrumbs : [ ] } ;
return { title : "" , description : "" , breadcrumbs : [ ] } ;
} ;
export default function Header ( { onMenuClick , showMenuButton = true } ) {
const pathname = usePathname ( ) ;
2026-01-09 05:29:11 -05:00
const router = useRouter ( ) ;
2026-01-04 21:58:59 -05:00
const { title , description , breadcrumbs } = getPageInfo ( pathname ) ;
2026-01-09 05:29:11 -05:00
const handleLogout = async ( ) => {
try {
const res = await fetch ( "/api/auth/logout" , { method : "POST" } ) ;
if ( res . ok ) {
router . push ( "/login" ) ;
router . refresh ( ) ;
}
} catch ( err ) {
console . error ( "Failed to logout:" , err ) ;
}
} ;
2026-01-04 21:58:59 -05:00
return (
2026-01-31 00:58:04 -05:00
< header className = "flex items-center justify-between px-8 py-5 border-b border-black/5 dark:border-white/5 bg-bg/80 backdrop-blur-xl z-10 sticky top-0" >
2026-01-04 21:58:59 -05:00
{ /* Mobile menu button */ }
< div className = "flex items-center gap-3 lg:hidden" >
{ showMenuButton && (
< button
onClick = { onMenuClick }
className = "text-text-main hover:text-primary transition-colors"
>
< span className = "material-symbols-outlined" > menu < / s p a n >
< / b u t t o n >
) }
< / d i v >
{ /* Page title with breadcrumbs - desktop */ }
< div className = "hidden lg:flex flex-col" >
{ breadcrumbs . length > 0 ? (
< div className = "flex items-center gap-2" >
{ breadcrumbs . map ( ( crumb , index ) => (
2026-01-19 18:31:08 -05:00
< div key = { ` ${ crumb . label } - ${ crumb . href || "current" } ` } className = "flex items-center gap-2" >
2026-01-04 21:58:59 -05:00
{ index > 0 && (
< span className = "material-symbols-outlined text-text-muted text-base" >
chevron _right
< / s p a n >
) }
{ crumb . href ? (
< Link
href = { crumb . href }
className = "text-text-muted hover:text-primary transition-colors"
>
{ crumb . label }
< / L i n k >
) : (
< div className = "flex items-center gap-2" >
{ crumb . image && (
2026-01-19 05:15:11 -05:00
< Image
2026-01-04 21:58:59 -05:00
src = { crumb . image }
alt = { crumb . label }
2026-01-19 05:15:11 -05:00
width = { 28 }
height = { 28 }
2026-01-26 23:35:28 -05:00
className = "object-contain rounded max-w-[28px] max-h-[28px]"
sizes = "28px"
2026-01-19 05:15:11 -05:00
onError = { ( e ) => { e . currentTarget . style . display = "none" ; } }
2026-01-04 21:58:59 -05:00
/ >
) }
< h1 className = "text-2xl font-semibold text-text-main tracking-tight" >
{ crumb . label }
< / h 1 >
< / d i v >
) }
< / d i v >
) ) }
< / d i v >
) : title ? (
< div >
< h1 className = "text-2xl font-semibold text-text-main tracking-tight" > { title } < / h 1 >
{ description && (
< p className = "text-sm text-text-muted" > { description } < / p >
) }
< / d i v >
) : null }
< / d i v >
{ /* Right actions */ }
< div className = "flex items-center gap-3 ml-auto" >
{ /* Theme toggle */ }
< ThemeToggle / >
2026-01-09 05:29:11 -05:00
{ /* Logout button */ }
< button
onClick = { handleLogout }
className = "flex items-center justify-center p-2 rounded-lg text-text-muted hover:text-red-500 hover:bg-red-500/10 transition-all"
title = "Logout"
>
< span className = "material-symbols-outlined" > logout < / s p a n >
< / b u t t o n >
2026-01-04 21:58:59 -05:00
< / d i v >
< / h e a d e r >
) ;
}
2026-01-19 18:31:08 -05:00
Header . propTypes = {
onMenuClick : PropTypes . func ,
showMenuButton : PropTypes . bool ,
} ;