caca
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import { useState } from "react";
|
||||
import type { ProfileSettings } from "@internal-mail/shared";
|
||||
import { LoginPage } from "./pages/LoginPage";
|
||||
import { MailboxPage } from "./pages/MailboxPage";
|
||||
import { SettingsPage } from "./pages/SettingsPage";
|
||||
import { useSession } from "./hooks/useSession";
|
||||
|
||||
type View = "inbox" | "compose" | "settings";
|
||||
|
||||
const AppShell = () => {
|
||||
const { session, logout } = useSession();
|
||||
const [currentView, setCurrentView] = useState<View>("inbox");
|
||||
const [profileOverride, setProfileOverride] = useState<ProfileSettings | null>(null);
|
||||
|
||||
const user = profileOverride ?? session.user;
|
||||
|
||||
return (
|
||||
<main className="app-shell">
|
||||
<aside className="sidebar">
|
||||
<div className="brand-block">
|
||||
<div className="brand-block__overline">Zero-trust posture</div>
|
||||
<h1>Secure Webmail</h1>
|
||||
<p>Docker-managed mailboxes with a web layer designed to fail closed.</p>
|
||||
</div>
|
||||
|
||||
<nav className="nav-stack">
|
||||
<button type="button" className={currentView === "inbox" ? "nav-button nav-button--active" : "nav-button"} onClick={() => setCurrentView("inbox")}>
|
||||
Inbox
|
||||
</button>
|
||||
<button type="button" className={currentView === "compose" ? "nav-button nav-button--active" : "nav-button"} onClick={() => setCurrentView("compose")}>
|
||||
Compose
|
||||
</button>
|
||||
<button type="button" className={currentView === "settings" ? "nav-button nav-button--active" : "nav-button"} onClick={() => setCurrentView("settings")}>
|
||||
Settings
|
||||
</button>
|
||||
</nav>
|
||||
|
||||
<div className="sidebar__footer">
|
||||
<div className="identity-card">
|
||||
{user?.avatarUrl ? <img src={user.avatarUrl} alt="" className="avatar-mini" /> : <div className="avatar-fallback">{user?.displayName.slice(0, 1) ?? "?"}</div>}
|
||||
<div>
|
||||
<strong>{user?.displayName}</strong>
|
||||
<p>{user?.email}</p>
|
||||
<small>{user?.totpEnabled ? "2FA enabled" : "2FA optional"}</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" className="ghost-button" onClick={() => void logout()}>
|
||||
Sign out
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<section className="content-shell">
|
||||
{currentView === "settings" ? (
|
||||
<SettingsPage onProfileUpdate={(profile) => setProfileOverride(profile)} />
|
||||
) : (
|
||||
<MailboxPage currentView={currentView === "compose" ? "compose" : "inbox"} />
|
||||
)}
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
export const App = () => {
|
||||
const { loading, authBusy, error, login, session } = useSession();
|
||||
|
||||
if (loading) {
|
||||
return <main className="loading-screen">Loading secure session context...</main>;
|
||||
}
|
||||
|
||||
if (!session.authenticated) {
|
||||
return <LoginPage busy={authBusy} error={error} onLogin={login} />;
|
||||
}
|
||||
|
||||
return <AppShell />;
|
||||
};
|
||||
Reference in New Issue
Block a user