This repository has no description
2.8 kB
106 lines
1import type { Meta, StoryObj } from '@storybook/nextjs-vite';
2import type { User } from '@semble/types';
3import { Suspense, useEffect } from 'react';
4import { useQueryClient } from '@tanstack/react-query';
5import { Skeleton as MantineSkeleton } from '@mantine/core';
6import ProfileMenu from './ProfileMenu';
7import { profileKeys } from '../../lib/profileKeys';
8import { AuthContext, type AuthContextType } from '@/hooks/useAuth';
9
10const mockProfile: User = {
11 id: 'did:plc:abc123def456',
12 name: 'Elena Kowalski',
13 handle: 'elena.kowalski',
14 avatarUrl: 'https://i.pravatar.cc/150?u=elena',
15};
16
17const mockAuthContext: AuthContextType = {
18 user: null,
19 isAuthenticated: true,
20 isLoading: false,
21 refreshAuth: async () => {},
22 logout: async () => {},
23};
24
25function QueryCacheSeed({
26 profile,
27 children,
28}: {
29 profile: User;
30 children: React.ReactNode;
31}) {
32 const queryClient = useQueryClient();
33
34 useEffect(() => {
35 queryClient.setQueryData(profileKeys.mine(), profile);
36 }, [queryClient, profile]);
37
38 return <>{children}</>;
39}
40
41const meta: Meta<typeof ProfileMenu> = {
42 title: 'Features/Profile/ProfileMenu',
43 component: ProfileMenu,
44 decorators: [
45 (Story) => (
46 <AuthContext value={mockAuthContext}>
47 <QueryCacheSeed profile={mockProfile}>
48 <Suspense
49 fallback={<MantineSkeleton w={38} h={38} radius="md" ml={4} />}
50 >
51 <div style={{ maxWidth: 280 }}>
52 <Story />
53 </div>
54 </Suspense>
55 </QueryCacheSeed>
56 </AuthContext>
57 ),
58 ],
59};
60
61export default meta;
62
63type Story = StoryObj<typeof ProfileMenu>;
64
65/** Collapsed menu trigger shown in the navbar footer. Click to open. */
66export const Default: Story = {};
67
68/** Bot accounts show the robot icon next to the name. */
69export const BotAccount: Story = {
70 decorators: [
71 (Story) => (
72 <AuthContext value={mockAuthContext}>
73 <QueryCacheSeed
74 profile={{
75 ...mockProfile,
76 id: 'did:plc:bot999',
77 name: 'Semble Bot',
78 handle: 'bot.semble',
79 avatarUrl: 'https://i.pravatar.cc/150?u=bot',
80 labels: [
81 {
82 val: 'bot',
83 src: 'did:plc:bot999',
84 uri: 'did:plc:bot999',
85 cts: '2024-01-01T00:00:00.000Z',
86 },
87 ],
88 }}
89 >
90 <Suspense
91 fallback={<MantineSkeleton w={38} h={38} radius="md" ml={4} />}
92 >
93 <div style={{ maxWidth: 280 }}>
94 <Story />
95 </div>
96 </Suspense>
97 </QueryCacheSeed>
98 </AuthContext>
99 ),
100 ],
101};
102
103/** Skeleton shown while the profile data is loading. */
104export const Skeleton: Story = {
105 render: () => <MantineSkeleton w={38} h={38} radius="md" ml={4} />,
106};