feat(website): add Group Rides Hub navigation links for authenticated riders
This commit is contained in:
parent
30539108fa
commit
126f2c6c5f
|
|
@ -78,6 +78,13 @@ export default function AccountPage() {
|
|||
<div className="flex flex-wrap items-center gap-3 pt-2 lg:pt-0">
|
||||
{user ? (
|
||||
<>
|
||||
<Link
|
||||
href="/group-rides"
|
||||
className="px-4 py-2 rounded-xl bg-gradient-to-r from-brand-cyan/20 to-blue-600/20 hover:from-brand-cyan/30 hover:to-blue-600/30 text-brand-cyan text-sm font-semibold border border-brand-cyan/40 hover:border-brand-cyan transition flex items-center space-x-2"
|
||||
>
|
||||
<span className="material-symbols-outlined text-[18px]">groups</span>
|
||||
<span>Group Rides Hub</span>
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleQuickSync}
|
||||
|
|
@ -241,6 +248,13 @@ export default function AccountPage() {
|
|||
</div>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-3 pt-2">
|
||||
<Link
|
||||
href="/group-rides"
|
||||
className="px-4 py-2 rounded-lg bg-brand-cyan/15 text-brand-cyan border border-brand-cyan/40 hover:bg-brand-cyan/25 text-xs font-semibold transition inline-flex items-center gap-1.5"
|
||||
>
|
||||
<span className="material-symbols-outlined text-[16px]">groups</span>
|
||||
<span>Group Rides Hub</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/clubs/manage"
|
||||
className="px-4 py-2 rounded-lg bg-secondary/15 text-secondary border border-secondary/40 hover:bg-secondary/25 text-xs font-semibold transition inline-flex items-center gap-1.5"
|
||||
|
|
|
|||
|
|
@ -123,6 +123,14 @@ export function FounderRides({
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
href="/group-rides"
|
||||
className="flex items-center gap-2 px-3.5 py-2 rounded-xl bg-brand-cyan/15 hover:bg-brand-cyan/25 border border-brand-cyan/40 text-brand-cyan font-body text-xs font-semibold transition"
|
||||
>
|
||||
<span className="material-symbols-outlined text-[17px]">groups</span>
|
||||
<span>Live Pack Radar & Hub</span>
|
||||
</Link>
|
||||
<div
|
||||
className="flex items-center gap-2 px-3.5 py-2 rounded-xl bg-surface-container/50 border border-brand-border/40 text-slate-400 font-body text-xs cursor-not-allowed select-none"
|
||||
title="Founder Portal ride planning is not wired yet"
|
||||
|
|
@ -135,6 +143,7 @@ export function FounderRides({
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Architecture & Privacy Notice Banner */}
|
||||
<div className="rounded-2xl bg-surface-container-low border border-brand-border/60 p-4 space-y-2">
|
||||
|
|
|
|||
|
|
@ -247,6 +247,18 @@ export function FounderTopBar({
|
|||
<span>Rider Account</span>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/group-rides"
|
||||
onClick={() => setUserMenuOpen(false)}
|
||||
role="menuitem"
|
||||
className="flex items-center gap-3 px-3 py-2.5 rounded-xl text-slate-200 hover:text-brand-cyan hover:bg-surface-container transition-colors text-xs font-semibold"
|
||||
>
|
||||
<span className="material-symbols-outlined text-[18px] text-brand-cyan">
|
||||
groups
|
||||
</span>
|
||||
<span>Group Rides</span>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/clubs/manage"
|
||||
onClick={() => setUserMenuOpen(false)}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,16 @@ export function SiteHeaderClient({ signedIn, role }: SiteHeaderProps) {
|
|||
</div>
|
||||
|
||||
{signedIn ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
href="/group-rides"
|
||||
className="hidden sm:inline-flex items-center gap-1.5 px-3 py-1.5 rounded-xl bg-surface-container-high hover:bg-surface-container border border-outline-variant/30 text-xs font-semibold text-on-surface hover:text-primary-container transition-colors"
|
||||
title="Group Rides Hub"
|
||||
>
|
||||
<span className="material-symbols-outlined text-[16px] text-primary-container">groups</span>
|
||||
<span>Group Rides</span>
|
||||
</Link>
|
||||
|
||||
<div className="relative" ref={userMenuRef}>
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -155,6 +165,18 @@ export function SiteHeaderClient({ signedIn, role }: SiteHeaderProps) {
|
|||
<span>Rider Account</span>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/group-rides"
|
||||
onClick={() => setUserMenuOpen(false)}
|
||||
role="menuitem"
|
||||
className="flex items-center gap-3 px-3 py-2.5 rounded-xl text-on-surface hover:text-primary-container hover:bg-surface-container transition-colors text-xs font-semibold"
|
||||
>
|
||||
<span className="material-symbols-outlined text-[18px] text-primary-container">
|
||||
groups
|
||||
</span>
|
||||
<span>Group Rides</span>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
href="/clubs/manage"
|
||||
onClick={() => setUserMenuOpen(false)}
|
||||
|
|
@ -205,6 +227,7 @@ export function SiteHeaderClient({ signedIn, role }: SiteHeaderProps) {
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-1.5 sm:gap-space-sm">
|
||||
<Link
|
||||
|
|
@ -289,6 +312,14 @@ export function SiteHeaderClient({ signedIn, role }: SiteHeaderProps) {
|
|||
<span className="material-symbols-outlined text-[20px] text-primary-container">person</span>
|
||||
<span>Rider Account</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/group-rides"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
className="px-space-md py-2.5 rounded-xl font-label-md text-label-md transition-colors min-h-[44px] flex items-center gap-2 text-on-surface hover:bg-surface-container"
|
||||
>
|
||||
<span className="material-symbols-outlined text-[20px] text-primary-container">groups</span>
|
||||
<span>Group Rides</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/clubs/manage"
|
||||
onClick={() => setMobileMenuOpen(false)}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@ import { JoinRideModal } from '../components/group-rides/join-ride-modal';
|
|||
import { CreateRideModal } from '../components/group-rides/create-ride-modal';
|
||||
import { GroupRidesDirectory } from '../components/group-rides/group-rides-directory';
|
||||
import { INITIAL_GROUP_RIDES } from '../components/group-rides/fixtures';
|
||||
import { SiteHeaderClient } from '../components/site-header-client';
|
||||
|
||||
vi.mock('next/navigation', () => ({
|
||||
usePathname: () => '/',
|
||||
useRouter: () => ({ push: vi.fn(), replace: vi.fn(), back: vi.fn() }),
|
||||
}));
|
||||
|
||||
describe('Group Rides Interactive Page & Components', () => {
|
||||
beforeEach(() => {
|
||||
|
|
@ -303,4 +309,39 @@ describe('Group Rides Interactive Page & Components', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// 6. Authenticated Navigation to Group Rides
|
||||
// ============================================================
|
||||
describe('Authenticated Navigation to Group Rides', () => {
|
||||
it('renders Group Rides quick button and user dropdown link for signed-in users', () => {
|
||||
render(<SiteHeaderClient signedIn={true} role="rider" />);
|
||||
|
||||
// Quick header button for signed-in users
|
||||
const quickGroupRidesBtn = screen.getByTitle('Group Rides Hub');
|
||||
expect(quickGroupRidesBtn).toBeDefined();
|
||||
expect(quickGroupRidesBtn.getAttribute('href')).toBe('/group-rides');
|
||||
|
||||
// Open Rider Menu dropdown
|
||||
const riderMenuBtn = screen.getByRole('button', { name: /open rider menu/i });
|
||||
fireEvent.click(riderMenuBtn);
|
||||
|
||||
// Verify Group Rides link exists inside dropdown menu
|
||||
const groupRidesLinks = screen.getAllByRole('menuitem', { name: /group rides/i });
|
||||
expect(groupRidesLinks.length).toBeGreaterThan(0);
|
||||
expect(groupRidesLinks[0].getAttribute('href')).toBe('/group-rides');
|
||||
});
|
||||
|
||||
it('renders Group Rides in mobile navigation drawer for signed-in users', () => {
|
||||
render(<SiteHeaderClient signedIn={true} role="rider" />);
|
||||
|
||||
const hamburgerBtn = screen.getByRole('button', { name: /open navigation menu/i });
|
||||
fireEvent.click(hamburgerBtn);
|
||||
|
||||
const groupRidesNavLinks = screen.getAllByRole('link', { name: /group rides/i });
|
||||
const mobileDrawerLink = groupRidesNavLinks.find(link => link.getAttribute('href') === '/group-rides');
|
||||
expect(mobileDrawerLink).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue