Skip to content

Commit 0f5fc46

Browse files
committed
chore: extract welcome code
1 parent e4dbd5d commit 0f5fc46

6 files changed

Lines changed: 59 additions & 84 deletions

File tree

packages/web/src/auth/compass/session/SessionProvider.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import EmailVerification from "supertokens-web-js/recipe/emailverification";
2323
import Session from "supertokens-web-js/recipe/session";
2424
import ThirdParty from "supertokens-web-js/recipe/thirdparty";
2525
import { clearGoogleSyncIndicatorOverride } from "../../google/state/google.sync.state";
26-
import { SessionContext } from "./session.context";
2726
import { refreshUserMetadata } from "../user/util/user-metadata.util";
27+
import { SessionContext } from "./session.context";
2828

2929
SuperTokens.init({
3030
appInfo: {
Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
import { z } from "zod";
22

3-
export const StorageKeySchema = z.enum(["compass.reminder", "compass.auth"]);
3+
export const StorageKeySchema = z.enum([
4+
"compass.reminder",
5+
"compass.auth",
6+
"compass.onboarding.has-seen-welcome",
7+
]);
48

59
export type StorageKey = z.infer<typeof StorageKeySchema>;
610

7-
export const STORAGE_KEYS: Record<"REMINDER" | "AUTH", StorageKey> = {
11+
export const STORAGE_KEYS: Record<
12+
"REMINDER" | "AUTH" | "HAS_SEEN_WELCOME",
13+
StorageKey
14+
> = {
815
REMINDER: "compass.reminder",
916
AUTH: "compass.auth",
17+
HAS_SEEN_WELCOME: "compass.onboarding.has-seen-welcome",
1018
} as const;

packages/web/src/components/WelcomeModal/WelcomeModal.test.tsx

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ mock.module("@web/components/AuthModal/hooks/useAuthModal", () => ({
2020
}),
2121
}));
2222

23-
const { WelcomeModal, STORAGE_KEY } =
23+
const { WelcomeModal } =
2424
require("./WelcomeModal") as typeof import("./WelcomeModal");
25+
const { STORAGE_KEYS } =
26+
require("@web/common/constants/storage.constants") as typeof import("@web/common/constants/storage.constants");
2527

2628
describe("WelcomeModal", () => {
2729
beforeEach(() => {
@@ -45,7 +47,7 @@ describe("WelcomeModal", () => {
4547
screen.queryByRole("dialog", { name: "Welcome to Compass Calendar" }),
4648
).toBeNull();
4749
});
48-
expect(localStorage.getItem(STORAGE_KEY)).toBe("true");
50+
expect(localStorage.getItem(STORAGE_KEYS.HAS_SEEN_WELCOME)).toBe("true");
4951
});
5052

5153
it("closes when Escape is pressed", async () => {
@@ -65,7 +67,7 @@ describe("WelcomeModal", () => {
6567
screen.queryByRole("dialog", { name: "Welcome to Compass Calendar" }),
6668
).toBeNull();
6769
});
68-
expect(localStorage.getItem(STORAGE_KEY)).toBe("true");
70+
expect(localStorage.getItem(STORAGE_KEYS.HAS_SEEN_WELCOME)).toBe("true");
6971
});
7072

7173
it("expands and collapses FAQ answers", async () => {
@@ -101,36 +103,4 @@ describe("WelcomeModal", () => {
101103
expect(answer).toHaveAttribute("aria-hidden", "true");
102104
expect(answer).toHaveAttribute("data-state", "closed");
103105
});
104-
105-
it("uses the shared focus ring on modal links and FAQ triggers", async () => {
106-
const user = userEvent.setup();
107-
108-
render(<WelcomeModal />);
109-
110-
const openSourceQuestion = screen.getByRole("button", {
111-
name: "How much of the code is open-source?",
112-
});
113-
expect(openSourceQuestion).toHaveClass("c-focus-ring");
114-
115-
await user.click(openSourceQuestion);
116-
117-
expect(
118-
screen.getByRole("link", { name: "self-hosting guide" }),
119-
).toHaveClass("c-focus-ring");
120-
expect(screen.getByRole("link", { name: "X (Twitter)" })).toHaveClass(
121-
"c-focus-ring",
122-
);
123-
expect(screen.getByRole("link", { name: "LinkedIn" })).toHaveClass(
124-
"c-focus-ring",
125-
);
126-
expect(screen.getByRole("link", { name: "GitHub" })).toHaveClass(
127-
"c-focus-ring",
128-
);
129-
expect(screen.getByRole("link", { name: "Privacy" })).toHaveClass(
130-
"c-focus-ring",
131-
);
132-
expect(screen.getByRole("link", { name: "Terms" })).toHaveClass(
133-
"c-focus-ring",
134-
);
135-
});
136106
});

packages/web/src/components/WelcomeModal/WelcomeModal.tsx

Lines changed: 5 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,46 +15,8 @@ import {
1515
useRef,
1616
useState,
1717
} from "react";
18-
19-
export const STORAGE_KEY = "compass.onboarding.has-seen-welcome";
20-
21-
function hasSeenWelcome(): boolean {
22-
try {
23-
return localStorage.getItem(STORAGE_KEY) === "true";
24-
} catch {
25-
return true;
26-
}
27-
}
28-
29-
function markWelcomeSeen(): void {
30-
try {
31-
localStorage.setItem(STORAGE_KEY, "true");
32-
} catch {
33-
// Silently fail if localStorage is unavailable
34-
}
35-
}
36-
37-
const FAQ_ITEMS = [
38-
{
39-
question: "Who is Compass for?",
40-
answer:
41-
"Compass is designed for minimalists who value efficiency, keyboard shortcuts, and open-source software. We are focused on helping people do more with less.",
42-
},
43-
{
44-
question: "Does Compass use AI?",
45-
answer:
46-
"Not currently. Compass gives you the tools to make your own decisions about how to spend your time, without algorithmic suggestions you'll ignore anyway.",
47-
},
48-
{
49-
question: "How much of the code is open-source?",
50-
answer: null, // rendered separately
51-
},
52-
{
53-
question: "What makes Compass different from other calendars?",
54-
answer:
55-
"It's simpler and faster. Instead of doing everything, we do a few things well.",
56-
},
57-
];
18+
import { FAQ_ITEMS } from "./faq";
19+
import { hasSeenWelcome, markWelcomeSeen } from "./welcome.modal.util";
5820

5921
export function WelcomeModal() {
6022
const { authenticated } = useContext(SessionContext);
@@ -183,18 +145,15 @@ export function WelcomeModal() {
183145
item.answer
184146
) : (
185147
<>
186-
All of it! Compass is a monorepo that includes the
187-
API, frontend, CLI, and more. You can run it yourself
188-
too; read the{" "}
148+
Yes! The repo includes the API, frontend, CLI, and
149+
more. You can run it yourself too; read the{" "}
189150
<a
190151
href="/blog/self-host"
191152
className="c-focus-ring font-medium text-accent-primary underline-offset-4 hover:underline"
192153
>
193154
self-hosting guide
194155
</a>{" "}
195-
to set up your own instance. It&apos;s all available
196-
on GitHub (link in footer), and we&apos;re always
197-
looking for contributors :]
156+
to set up your own instance.
198157
</>
199158
)}
200159
</div>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export const FAQ_ITEMS = [
2+
{
3+
question: "Who is Compass for?",
4+
answer:
5+
"Compass is designed for minimalists who value efficiency, keyboard shortcuts, and open-source software. We are focused on helping people do more with less.",
6+
},
7+
{
8+
question: "Does Compass use AI?",
9+
answer:
10+
"Not currently. Compass gives you the tools to make your own decisions about how to spend your time, without algorithmic suggestions you'll ignore anyway.",
11+
},
12+
{
13+
question: "Is it open-source?",
14+
answer: null, // rendered separately
15+
},
16+
{
17+
question: "What makes Compass different from other calendars?",
18+
answer:
19+
"It's simpler and faster. Instead of doing everything, we do a few things well.",
20+
},
21+
];
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { STORAGE_KEYS } from "@web/common/constants/storage.constants";
2+
3+
export function hasSeenWelcome(): boolean {
4+
try {
5+
return localStorage.getItem(STORAGE_KEYS.HAS_SEEN_WELCOME) === "true";
6+
} catch {
7+
return true;
8+
}
9+
}
10+
11+
export function markWelcomeSeen(): void {
12+
try {
13+
localStorage.setItem(STORAGE_KEYS.HAS_SEEN_WELCOME, "true");
14+
} catch {
15+
// Silently fail if localStorage is unavailable
16+
}
17+
}

0 commit comments

Comments
 (0)