BREATHE / frontend /src /components /Layout.jsx
tannuiscoding's picture
added app.py
5a264f5
import { useState } from 'react'
import { Outlet, NavLink, useNavigate, Link } from 'react-router-dom'
import { useAuth } from '../context/AuthContext'
import { useTheme } from '../context/ThemeContext'
const NAV_MAIN = [
{ to: '/app/dashboard', icon: 'β—ˆ', label: 'Dashboard' },
{ to: '/app/assess', icon: 'βŠ•', label: 'New Assessment' },
{ to: '/app/history', icon: 'β—·', label: 'History' },
]
const NAV_WELLNESS = [
{ to: '/app/breathe', icon: '🫁', label: 'Breathe Hub' },
{ to: '/app/gratitude', icon: '✍️', label: 'Gratitude' },
{ to: '/app/todo', icon: 'βœ…', label: 'Daily To-Do' },
]
export default function Layout() {
const { user, logout } = useAuth()
const { theme, toggle } = useTheme()
const navigate = useNavigate()
const [open, setOpen] = useState(false) // mobile sidebar
async function handleLogout() {
await logout()
navigate('/auth')
}
const initials = user?.username?.slice(0, 2).toUpperCase() || 'U'
return (
<div className="app-shell">
{/* Mobile top bar */}
<header className="mobile-bar">
<button className="hamburger" onClick={() => setOpen(o => !o)}>☰</button>
<Link to="/app/breathe" className="mobile-brand-link">
<img src="/logo.svg" alt="BREATHE" className="mobile-brand-logo" />
</Link>
<button className="mobile-theme-toggle" onClick={toggle} aria-label="Toggle theme">
{theme === 'dark' ? 'β˜€οΈ' : 'πŸŒ™'}
</button>
</header>
{/* Backdrop (mobile) */}
{open && <div className="sidebar-backdrop" onClick={() => setOpen(false)} />}
<aside className={`sidebar ${open ? 'sidebar--open' : ''}`}>
<div className="sidebar-top">
<div className="sidebar-brand">
<Link to="/app/breathe" className="sidebar-brand-link" onClick={() => setOpen(false)}>
<img src="/logo.svg" alt="BREATHE" className="brand-logo" />
<div className="brand-sub">Stress Intelligence</div>
</Link>
</div>
<nav className="sidebar-nav">
<div className="nav-section-label">Overview</div>
{NAV_MAIN.map(n => (
<NavLink
key={n.to}
to={n.to}
className={({ isActive }) => `nav-link ${isActive ? 'nav-link--active' : ''}`}
onClick={() => setOpen(false)}
>
<span className="nav-icon">{n.icon}</span>
<span>{n.label}</span>
</NavLink>
))}
<div className="nav-section-label" style={{ marginTop: '16px' }}>Wellness</div>
{NAV_WELLNESS.map(n => (
<NavLink
key={n.to}
to={n.to}
className={({ isActive }) => `nav-link ${isActive ? 'nav-link--active' : ''}`}
onClick={() => setOpen(false)}
>
<span className="nav-icon">{n.icon}</span>
<span>{n.label}</span>
</NavLink>
))}
</nav>
</div>
<div className="sidebar-bottom">
<div className="user-chip">
<Link to="/app/profile" className="user-chip-link" onClick={() => setOpen(false)}>
{user?.avatar
? <img src={user.avatar} alt="avatar" className="user-avatar user-avatar--img" />
: <div className="user-avatar">{initials}</div>
}
<div className="user-meta">
<div className="user-name">{user?.display_name || user?.username}</div>
<div className="user-email">{user?.email}</div>
</div>
</Link>
</div>
<button className="theme-toggle" onClick={toggle}>
<span className="theme-toggle-icon">{theme === 'dark' ? 'β˜€οΈ' : 'πŸŒ™'}</span>
{theme === 'dark' ? 'Light mode' : 'Dark mode'}
</button>
<button className="logout-btn" onClick={handleLogout}>
↩ Log out
</button>
</div>
</aside>
<main className="main-area">
<Outlet />
</main>
</div>
)
}