Fix navigation

This commit is contained in:
Andras Schmelczer 2026-03-08 21:12:08 +00:00
parent 72653a4ddf
commit 5f30928c64
3 changed files with 65 additions and 61 deletions

View file

@ -11,10 +11,15 @@ import { ClipboardIcon } from '../ui/icons/ClipboardIcon';
import { BookmarkIcon } from '../ui/icons/BookmarkIcon'; import { BookmarkIcon } from '../ui/icons/BookmarkIcon';
import { TrashIcon } from '../ui/icons/TrashIcon'; import { TrashIcon } from '../ui/icons/TrashIcon';
import { CloseIcon } from '../ui/icons/CloseIcon'; import { CloseIcon } from '../ui/icons/CloseIcon';
import { TabButton } from '../ui/TabButton'; import { SubNav } from '../ui/SubNav';
type AccountTab = 'saved' | 'settings'; type AccountTab = 'saved' | 'settings';
const ACCOUNT_TABS = [
{ key: 'saved', label: 'Saved Searches' },
{ key: 'settings', label: 'Settings' },
];
const SUBSCRIPTION_OPTIONS = ['free', 'licensed'] as const; const SUBSCRIPTION_OPTIONS = ['free', 'licensed'] as const;
const SUBSCRIPTION_LABELS: Record<string, string> = { const SUBSCRIPTION_LABELS: Record<string, string> = {
@ -493,7 +498,8 @@ export default function AccountPage({
return () => window.removeEventListener('hashchange', handleHashChange); return () => window.removeEventListener('hashchange', handleHashChange);
}, []); }, []);
const switchTab = (tab: AccountTab) => { const switchTab = (key: string) => {
const tab = key as AccountTab;
setActiveTab(tab); setActiveTab(tab);
window.history.replaceState( window.history.replaceState(
window.history.state, window.history.state,
@ -503,39 +509,25 @@ export default function AccountPage({
}; };
return ( return (
<div className="flex-1 overflow-y-auto bg-warm-50 dark:bg-warm-900"> <div className="flex-1 overflow-hidden bg-warm-50 dark:bg-warm-900 flex flex-col">
<div className="max-w-5xl mx-auto px-6 py-8"> <SubNav tabs={ACCOUNT_TABS} activeTab={activeTab} onTabChange={switchTab} />
<h1 className="text-2xl font-bold text-navy-950 dark:text-warm-100 mb-6">Account</h1> <div className="flex-1 overflow-y-auto">
<div className="max-w-5xl mx-auto px-6 py-6">
{/* Tabs */} {activeTab === 'saved' ? (
<div className="flex border-b border-warm-200 dark:border-warm-700 mb-6"> <SavedSearchesContent
<TabButton searches={searches}
label="Saved Searches" loading={searchesLoading}
isActive={activeTab === 'saved'} onDelete={onDeleteSearch}
onClick={() => switchTab('saved')} onOpen={onOpenSearch}
/> />
<TabButton ) : (
label="Settings" <SettingsContent
isActive={activeTab === 'settings'} user={user}
onClick={() => switchTab('settings')} onRefreshAuth={onRefreshAuth}
/> onRequestVerification={onRequestVerification}
/>
)}
</div> </div>
{/* Tab content */}
{activeTab === 'saved' ? (
<SavedSearchesContent
searches={searches}
loading={searchesLoading}
onDelete={onDeleteSearch}
onOpen={onOpenSearch}
/>
) : (
<SettingsContent
user={user}
onRefreshAuth={onRefreshAuth}
onRequestVerification={onRequestVerification}
/>
)}
</div> </div>
</div> </div>
); );

View file

@ -1,8 +1,15 @@
import { useEffect, useState, useRef } from 'react'; import { useEffect, useState, useRef } from 'react';
import { ChevronIcon } from '../ui/icons/ChevronIcon'; import { ChevronIcon } from '../ui/icons/ChevronIcon';
import { SubNav } from '../ui/SubNav';
type LearnTab = 'data-sources' | 'faq' | 'support'; type LearnTab = 'data-sources' | 'faq' | 'support';
const LEARN_TABS = [
{ key: 'faq', label: 'FAQ' },
{ key: 'data-sources', label: 'Data Sources' },
{ key: 'support', label: 'Support' },
];
const DATA_SOURCES = [ const DATA_SOURCES = [
{ {
id: 'price-paid', id: 'price-paid',
@ -288,36 +295,20 @@ export default function LearnPage() {
scrollContainerRef.current?.scrollTo(0, 0); scrollContainerRef.current?.scrollTo(0, 0);
}, [tab]); }, [tab]);
const tabClass = (t: LearnTab) => const switchTab = (key: string) => {
`px-4 py-2 text-sm font-medium rounded-t border-b-2 ${tab === t setTab(key as LearnTab);
? 'border-teal-500 text-teal-700 dark:text-teal-400' setHighlightedId(null);
: 'border-transparent text-warm-500 dark:text-warm-400 hover:text-warm-700 dark:hover:text-warm-300' };
}`;
return ( return (
<div className="flex-1 overflow-hidden bg-warm-50 dark:bg-navy-950 flex flex-col"> <div className="flex-1 overflow-hidden bg-warm-50 dark:bg-navy-950 flex flex-col">
<div className="max-w-5xl mx-auto w-full px-6 pt-6"> <SubNav tabs={LEARN_TABS} activeTab={tab} onTabChange={switchTab} />
<div className="flex gap-2 border-b border-warm-200 dark:border-warm-700">
<button className={tabClass('faq')} onClick={() => setTab('faq')}>
FAQ
</button>
<button className={tabClass('data-sources')} onClick={() => setTab('data-sources')}>
Data Sources
</button>
<button className={tabClass('support')} onClick={() => setTab('support')}>
Support
</button>
</div>
</div>
<div className="flex-1 overflow-y-auto flex flex-col" ref={scrollContainerRef}> <div className="flex-1 overflow-y-auto flex flex-col" ref={scrollContainerRef}>
{tab === 'data-sources' ? ( {tab === 'data-sources' ? (
<> <>
<div className="flex-1"> <div className="flex-1">
<div className="max-w-5xl mx-auto px-6 py-6"> <div className="max-w-5xl mx-auto px-6 py-6">
<h1 className="text-2xl font-bold text-warm-900 dark:text-warm-100 mb-2">
Data Sources
</h1>
<p className="text-warm-600 dark:text-warm-400 mb-6"> <p className="text-warm-600 dark:text-warm-400 mb-6">
This application combines {DATA_SOURCES.length} open datasets covering property This application combines {DATA_SOURCES.length} open datasets covering property
prices, energy performance, transport, demographics, crime, environment, and more. prices, energy performance, transport, demographics, crime, environment, and more.
@ -423,9 +414,6 @@ export default function LearnPage() {
</> </>
) : tab === 'faq' ? ( ) : tab === 'faq' ? (
<div className="max-w-3xl mx-auto px-6 py-6 w-full"> <div className="max-w-3xl mx-auto px-6 py-6 w-full">
<h1 className="text-2xl font-bold text-warm-900 dark:text-warm-100 mb-2">
Frequently Asked Questions
</h1>
<p className="text-warm-600 dark:text-warm-400 mb-6"> <p className="text-warm-600 dark:text-warm-400 mb-6">
Common questions about how Perfect Postcode works, where the data comes from, and how Common questions about how Perfect Postcode works, where the data comes from, and how
to use the map. to use the map.
@ -438,9 +426,6 @@ export default function LearnPage() {
</div> </div>
) : ( ) : (
<div className="max-w-2xl mx-auto px-6 py-6 w-full"> <div className="max-w-2xl mx-auto px-6 py-6 w-full">
<h1 className="text-2xl font-bold text-warm-900 dark:text-warm-100 mb-2">
Support
</h1>
<p className="text-warm-600 dark:text-warm-400 mb-6"> <p className="text-warm-600 dark:text-warm-400 mb-6">
Have a question? Check our FAQ or reach out to us directly. Have a question? Check our FAQ or reach out to us directly.
</p> </p>

View file

@ -0,0 +1,27 @@
interface SubNavProps {
tabs: { key: string; label: string }[];
activeTab: string;
onTabChange: (key: string) => void;
}
export function SubNav({ tabs, activeTab, onTabChange }: SubNavProps) {
return (
<div className="max-w-5xl mx-auto w-full px-6 pt-4">
<div className="flex gap-2 border-b border-warm-200 dark:border-warm-700">
{tabs.map((tab) => (
<button
key={tab.key}
className={`px-4 py-2 text-sm font-medium border-b-2 ${
activeTab === tab.key
? 'border-teal-500 text-teal-700 dark:text-teal-400'
: 'border-transparent text-warm-500 dark:text-warm-400 hover:text-warm-700 dark:hover:text-warm-300'
}`}
onClick={() => onTabChange(tab.key)}
>
{tab.label}
</button>
))}
</div>
</div>
);
}