mirror of
https://github.com/aaronpo97/the-biergarten-app.git
synced 2026-10-15 01:54:43 +00:00
Add authenticated user profile page with locked-down account endpoint (#315)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react-vite';
|
||||
import { expect, userEvent, within } from 'storybook/test';
|
||||
import { expect, screen, userEvent, within } from 'storybook/test';
|
||||
import Navbar from './Navbar';
|
||||
|
||||
const navbarDescription = `Top-level navigation for the Biergarten website. These stories cover guest, authenticated, and mobile states so you can review branding, route visibility, account menu behavior, and responsive collapse without leaving Storybook.`;
|
||||
@@ -47,8 +47,10 @@ export const Authenticated: Story = {
|
||||
const userButton = canvas.getByRole('button', { name: /hans/i });
|
||||
await expect(userButton).toBeInTheDocument();
|
||||
await userEvent.click(userButton);
|
||||
await expect(canvas.getByRole('menuitem', { name: /dashboard/i })).toBeInTheDocument();
|
||||
await expect(canvas.getByRole('menuitem', { name: /logout/i })).toBeInTheDocument();
|
||||
// MenuItems is anchor-positioned, which portals it outside canvasElement.
|
||||
await expect(screen.getByRole('menuitem', { name: /my profile/i })).toBeInTheDocument();
|
||||
await expect(screen.getByRole('menuitem', { name: /dashboard/i })).toBeInTheDocument();
|
||||
await expect(screen.getByRole('menuitem', { name: /logout/i })).toBeInTheDocument();
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -72,7 +72,10 @@ const Navbar = ({ auth }: NavbarProps) => (
|
||||
Dashboard
|
||||
</Link>
|
||||
|
||||
<UserMenu username={auth.username} />
|
||||
<UserMenu
|
||||
username={auth.username}
|
||||
userAccountId={auth.userAccountId}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<Link to="/login" className="btn btn-primary btn-sm">
|
||||
|
||||
@@ -3,25 +3,40 @@ import { Link } from 'react-router';
|
||||
|
||||
interface UserMenuProps {
|
||||
username: string;
|
||||
userAccountId: string;
|
||||
}
|
||||
|
||||
const UserMenu = ({ username }: UserMenuProps) => (
|
||||
<Menu as="div" className="relative">
|
||||
const UserMenu = ({ username, userAccountId }: UserMenuProps) => (
|
||||
<Menu>
|
||||
<MenuButton className="btn btn-ghost btn-sm">{username}</MenuButton>
|
||||
<MenuItems className="menu absolute right-0 z-60 mt-2 w-52 rounded-box border border-base-300 bg-base-100 p-2 shadow-xl focus:outline-none">
|
||||
<MenuItems
|
||||
anchor="bottom end"
|
||||
transition
|
||||
className="menu z-60 w-52 rounded-box border border-base-300 bg-base-100 p-2 shadow-xl [--anchor-gap:8px] focus:outline-none transition duration-100 ease-out data-[closed]:scale-95 data-[closed]:opacity-0"
|
||||
>
|
||||
<MenuItem>
|
||||
{({ focus }) => (
|
||||
<Link to="/dashboard" className={focus ? 'active' : ''}>
|
||||
Dashboard
|
||||
</Link>
|
||||
)}
|
||||
<Link
|
||||
to={`/users/${userAccountId}`}
|
||||
className="rounded-field block px-3 py-1.5 data-[focus]:bg-base-200"
|
||||
>
|
||||
My profile
|
||||
</Link>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
{({ focus }) => (
|
||||
<Link to="/logout" className={focus ? 'active' : ''}>
|
||||
Logout
|
||||
</Link>
|
||||
)}
|
||||
<Link
|
||||
to="/dashboard"
|
||||
className="rounded-field block px-3 py-1.5 data-[focus]:bg-base-200"
|
||||
>
|
||||
Dashboard
|
||||
</Link>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
<Link
|
||||
to="/logout"
|
||||
className="rounded-field block px-3 py-1.5 data-[focus]:bg-base-200"
|
||||
>
|
||||
Logout
|
||||
</Link>
|
||||
</MenuItem>
|
||||
</MenuItems>
|
||||
</Menu>
|
||||
|
||||
Reference in New Issue
Block a user