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 e1668f01a..099dd5656 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
@@ -38,6 +38,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