diff --git a/apps/nextjs/.storybook/MockClerkProvider.tsx b/apps/nextjs/.storybook/MockClerkProvider.tsx deleted file mode 100644 index 6edf42278..000000000 --- a/apps/nextjs/.storybook/MockClerkProvider.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; - -import { ClerkProvider } from "../src/mocks/clerk/nextjs"; - -export const MockClerkProvider = ({ - children, -}: { - children: React.ReactNode; -}) => { - return {children}; -}; diff --git a/apps/nextjs/.storybook/preview.tsx b/apps/nextjs/.storybook/preview.tsx index ff270b2e2..8c4427ffe 100644 --- a/apps/nextjs/.storybook/preview.tsx +++ b/apps/nextjs/.storybook/preview.tsx @@ -11,6 +11,7 @@ import type { Preview, Decorator } from "@storybook/react"; import { TooltipProvider } from "../src/components/AppComponents/Chat/ui/tooltip"; import { AnalyticsProvider } from "../src/mocks/analytics/provider"; +import { ClerkDecorator } from "../src/mocks/clerk/ClerkDecorator"; import { TRPCReactProvider } from "../src/utils/trpc"; import { RadixThemeDecorator } from "./decorators/RadixThemeDecorator"; import "./preview.css"; @@ -28,7 +29,6 @@ const preview: Preview = { }; // Providers not currently used -// - MockClerkProvider // - CookieConsentProvider // - DemoProvider // - LessonPlanTrackingProvider @@ -39,6 +39,7 @@ const preview: Preview = { export const decorators: Decorator[] = [ RadixThemeDecorator, + ClerkDecorator, (Story) => ( <> {/* TODO: Mock tRPC calls with MSW */} diff --git a/apps/nextjs/src/components/Footer.stories.tsx b/apps/nextjs/src/components/Footer.stories.tsx new file mode 100644 index 000000000..1725794e8 --- /dev/null +++ b/apps/nextjs/src/components/Footer.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import Footer from "./Footer"; + +const meta: Meta = { + title: "Components/Layout/Footer", + component: Footer, + tags: ["autodocs"], +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; diff --git a/apps/nextjs/src/components/Header.stories.tsx b/apps/nextjs/src/components/Header.stories.tsx new file mode 100644 index 000000000..0c4c4f43e --- /dev/null +++ b/apps/nextjs/src/components/Header.stories.tsx @@ -0,0 +1,27 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import Header from "./Header"; + +const meta: Meta = { + title: "Components/Layout/Header", + component: Header, + tags: ["autodocs"], +}; + +export default meta; + +type Story = StoryObj; + +export const SignedIn: Story = { + args: {}, + parameters: { + auth: "signedIn", + }, +}; + +export const SignedOut: Story = { + args: {}, + parameters: { + auth: "signedOut", + }, +}; diff --git a/apps/nextjs/src/mocks/clerk/ClerkDecorator.tsx b/apps/nextjs/src/mocks/clerk/ClerkDecorator.tsx new file mode 100644 index 000000000..0f38a2c45 --- /dev/null +++ b/apps/nextjs/src/mocks/clerk/ClerkDecorator.tsx @@ -0,0 +1,11 @@ +import type { Decorator } from "@storybook/react/*"; + +import { ClerkProvider } from "./nextjsComponents"; + +export const ClerkDecorator: Decorator = (Story, { parameters }) => { + return ( + + + + ); +}; diff --git a/apps/nextjs/src/mocks/clerk/nextjs.ts b/apps/nextjs/src/mocks/clerk/nextjs.ts index 46c29a062..ea6c3ca74 100644 --- a/apps/nextjs/src/mocks/clerk/nextjs.ts +++ b/apps/nextjs/src/mocks/clerk/nextjs.ts @@ -1,6 +1,6 @@ -/* +/* Mocks the Clerk authentication library for use in Story book. -See the readme for more context on why this is needed. +See the readme for more context on why this is needed. */ export { @@ -10,4 +10,5 @@ export { SignedIn, SignedOut, ClerkProvider, + UserButton, } from "./nextjsComponents"; diff --git a/apps/nextjs/src/mocks/clerk/nextjsComponents.tsx b/apps/nextjs/src/mocks/clerk/nextjsComponents.tsx index 3a8c8002f..0954bffe0 100644 --- a/apps/nextjs/src/mocks/clerk/nextjsComponents.tsx +++ b/apps/nextjs/src/mocks/clerk/nextjsComponents.tsx @@ -1,19 +1,71 @@ import React from "react"; +type Context = { + isLoaded: boolean; + isSignedIn: boolean | undefined; + user: + | Record< + "id" | "firstName" | "lastName" | "emailAddresses" | "publicMetadata", + unknown + > + | undefined; +}; + const mockUser = { id: "user_123", firstName: "John", lastName: "Doe", emailAddresses: [{ emailAddress: "john@example.com" }], - publicMetadata: { labs: { isDemoUser: true } }, + publicMetadata: { labs: { isDemoUser: false } }, // Add other user properties as needed }; -export const useUser = () => ({ - isLoaded: true, - isSignedIn: true, - user: mockUser, -}); +const states: Record = { + loading: { + isLoaded: false, + isSignedIn: undefined, + user: undefined, + }, + signedOut: { + isLoaded: true, + isSignedIn: false, + user: undefined, + }, + signedIn: { + isLoaded: true, + isSignedIn: true, + user: mockUser, + }, + signedInDemo: { + isLoaded: true, + isSignedIn: true, + user: { + ...mockUser, + publicMetadata: { ...mockUser.publicMetadata, isDemoUser: true }, + }, + }, +}; + +const ClerkContext = React.createContext(states.signedIn); + +type ClerkProviderProps = { + state: "loading" | "signedIn" | "signedInDemo" | "signedOut"; + children: React.ReactNode; +}; +export const ClerkProvider = ({ state, children }: ClerkProviderProps) => ( + + {children} + +); + +export const useUser = () => { + const context = React.useContext(ClerkContext); + return { + isLoaded: context.isLoaded, + isSignedIn: context.isSignedIn, + user: context.user, + }; +}; export const useClerk = () => ({ signOut: () => Promise.resolve(), @@ -21,23 +73,43 @@ export const useClerk = () => ({ // Add other Clerk methods as needed }); -export const useAuth = () => ({ - isLoaded: true, - isSignedIn: true, - userId: mockUser.id, - sessionId: "session_123", - getToken: () => Promise.resolve("mock_token"), -}); +export const useAuth = () => { + const context = React.useContext(ClerkContext); + return { + isLoaded: context.isLoaded, + isSignedIn: context.isSignedIn, + userId: mockUser?.id, + sessionId: "session_123", + getToken: () => Promise.resolve("mock_token"), + }; +}; -export const SignedIn = ({ children }: { children: React.ReactNode }) => ( - <>{children} -); -export const SignedOut = ({ children }: { children: React.ReactNode }) => ( - <>{children} -); +export const SignedIn = ({ children }: { children: React.ReactNode }) => { + const context = React.useContext(ClerkContext); + return context.isSignedIn ? children : null; +}; -export const ClerkProvider = ({ children }: { children: React.ReactNode }) => ( - <>{children} -); +export const SignedOut = ({ children }: { children: React.ReactNode }) => { + const context = React.useContext(ClerkContext); + return context.isSignedIn ? null : children; +}; + +export const UserButton = () => { + const context = React.useContext(ClerkContext); + + return context.isSignedIn ? ( +
+ ) : ( + "Sign in" + ); +}; // Mock other Clerk components and hooks as needed