Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions dashboard/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,100 @@
import { useEffect, useMemo, useState } from 'react';
import { EventExplorerPage } from './pages/EventExplorerPage';
import { NotificationPreferencesPage } from './pages/NotificationPreferencesPage';

const VALID_TAB_KEYS = ['explorer', 'preferences'] as const;

type TabKey = (typeof VALID_TAB_KEYS)[number];

function parseActiveTab(search: string): TabKey {
const params = new URLSearchParams(search);
const tab = params.get('tab');
return VALID_TAB_KEYS.includes(tab as TabKey) ? (tab as TabKey) : 'explorer';
}

export function App() {
const initialSearch = typeof window !== 'undefined' ? window.location.search : '';
const [activeTab, setActiveTab] = useState<TabKey>(() => parseActiveTab(initialSearch));

useEffect(() => {
if (typeof window === 'undefined') {
return;
}

const handlePopState = () => {
setActiveTab(parseActiveTab(window.location.search));
};

window.addEventListener('popstate', handlePopState);
return () => window.removeEventListener('popstate', handlePopState);
}, []);

useEffect(() => {
if (typeof window === 'undefined') {
return;
}

const params = new URLSearchParams(window.location.search);
params.set('tab', activeTab);
window.history.replaceState({}, '', `${window.location.pathname}?${params.toString()}`);
}, [activeTab]);

const tabLabel = useMemo(
() => (activeTab === 'preferences' ? 'Notification Preferences' : 'Event Explorer'),
[activeTab]
);

return (
<div className="app">
<header className="app__topbar">
<div className="app__brand">
<p className="app__brand-eyebrow">Notify Chain</p>
<h1>{tabLabel}</h1>
</div>

<nav className="app__nav" aria-label="Dashboard tabs">
<button
type="button"
className={`app__tab ${activeTab === 'explorer' ? 'app__tab--active' : ''}`}
import { useState } from 'react';
import { EventExplorerPage } from './pages/EventExplorerPage';
import { ExportHistoryPage } from './pages/ExportHistoryPage';

export function App() {
const [activeTab, setActiveTab] = useState<'explorer' | 'exports'>('explorer');

return (
<div className="app">
<nav className="nav-header">
<span className="nav-brand">Notify-Chain</span>
<div className="nav-tabs">
<button
type="button"
className={`nav-tab-btn ${activeTab === 'explorer' ? 'nav-tab-btn--active' : ''}`}
onClick={() => setActiveTab('explorer')}
>
Event Explorer
</button>
<button
type="button"
className={`app__tab ${activeTab === 'preferences' ? 'app__tab--active' : ''}`}
onClick={() => setActiveTab('preferences')}
>
Notification Preferences
</button>
</nav>
</header>

{activeTab === 'preferences' ? <NotificationPreferencesPage /> : <EventExplorerPage />}
className={`nav-tab-btn ${activeTab === 'exports' ? 'nav-tab-btn--active' : ''}`}
onClick={() => setActiveTab('exports')}
>
Export Center
</button>
</div>
</nav>

{activeTab === 'explorer' ? <EventExplorerPage /> : <ExportHistoryPage />}
import { DeliveryHeatmap } from './components/DeliveryHeatmap';
import { ThemeToggle } from './components/ThemeToggle';
import { useTheme } from './hooks/useTheme';
Expand Down
Loading
Loading