Skip to content

Commit 23d448f

Browse files
committed
feat(app): add InitialWelcome and WelcomeWrapper component
1 parent dff344f commit 23d448f

File tree

4 files changed

+170
-10
lines changed

4 files changed

+170
-10
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { render, screen, fireEvent } from "@testing-library/react";
2+
import "@testing-library/jest-dom/extend-expect";
3+
import { InitialWelcome } from "../../components/InitialWelcome";
4+
import { useNavigate } from "react-router-dom";
5+
6+
jest.mock("react-router-dom", () => ({
7+
useNavigate: jest.fn(),
8+
}));
9+
10+
const defaultProps = {
11+
onBoardFinished: jest.fn(),
12+
};
13+
14+
describe("InitialWelcome", () => {
15+
it("renders the component and displays the first step", () => {
16+
render(<InitialWelcome {...defaultProps} />);
17+
18+
expect(screen.getByText("Welcome to Gitcoin Passport!")).toBeInTheDocument();
19+
expect(screen.getByText("Privacy-First Verification")).toBeInTheDocument();
20+
});
21+
22+
it("navigates through the steps and calls onBoardFinished when completed", () => {
23+
render(<InitialWelcome {...defaultProps} />);
24+
25+
const nextButton = screen.getByText("Next");
26+
27+
// Click "Next" to go to step 2
28+
fireEvent.click(nextButton);
29+
expect(screen.getByText("Introducing Passport Scoring")).toBeInTheDocument();
30+
expect(screen.getByText("Get Your Unique Humanity Score")).toBeInTheDocument();
31+
32+
// Click "Next" to go to step 3
33+
fireEvent.click(nextButton);
34+
expect(screen.getByText("Get Started")).toBeInTheDocument();
35+
expect(screen.getByText("One-Click Verification")).toBeInTheDocument();
36+
37+
// Click "Next" to finish the steps
38+
fireEvent.click(nextButton);
39+
expect(defaultProps.onBoardFinished).toHaveBeenCalledTimes(1);
40+
});
41+
42+
it("skips the last step, resets the step, and navigates to the dashboard", () => {
43+
const navigateMock = jest.fn();
44+
(useNavigate as jest.Mock).mockReturnValue(navigateMock);
45+
46+
render(<InitialWelcome {...defaultProps} />);
47+
48+
const nextButton = screen.getByText("Next");
49+
50+
// Click "Next" to go to step 2
51+
fireEvent.click(nextButton);
52+
// Click "Next" to go to step 3
53+
fireEvent.click(nextButton);
54+
55+
const skipButton = screen.getByText("Skip For Now");
56+
57+
// Click "Skip For Now" to reset the step and navigate to the dashboard
58+
fireEvent.click(skipButton);
59+
expect(navigateMock).toHaveBeenCalledWith("/dashboard");
60+
});
61+
});

app/components/InitialWelcome.tsx

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { useState } from "react";
2+
import { WelcomeWrapper } from "./WelcomeWrapper";
3+
import { useNavigate } from "react-router-dom";
4+
5+
const welcomeSteps = [
6+
{
7+
header: "Welcome to Gitcoin Passport!",
8+
subHeader: "Privacy-First Verification",
9+
body: "The non-doxxing identity aggregator that combines multiple sybil prevention mechanisms to prove your unique humanity and build your reputation.",
10+
imgSrc: "",
11+
},
12+
{
13+
header: "Introducing Passport Scoring",
14+
subHeader: "Get Your Unique Humanity Score",
15+
body: "Think of your score as a trampoline that launches you to your destination. As your score increases, communities more easily trust that you are a unique human.",
16+
imgSrc: "",
17+
},
18+
{
19+
header: "Get Started",
20+
subHeader: "One-Click Verification",
21+
body: "You can now verify most web3 stamps with one-click verification! Verifying Web2 apps will come after this step, and we encourage you to collect as many stamps as possible.",
22+
imgSrc: "",
23+
},
24+
];
25+
26+
const stepIndicator = (step: number) => {
27+
const steps = welcomeSteps.map((_, i) => {
28+
const active = i === step ? "border-4 border-muted h-4 w-4" : "w-2.5 h-2.5 mt-0.5";
29+
return <div key={i} className={`mx-4 rounded-full bg-accent ${active}`} />;
30+
});
31+
return <div className="ml-3 flex justify-center">{steps}</div>;
32+
};
33+
34+
export const InitialWelcome = ({ onBoardFinished }: { onBoardFinished: () => void }) => {
35+
const [step, setStep] = useState(0);
36+
const navigate = useNavigate();
37+
38+
return (
39+
<WelcomeWrapper content={welcomeSteps[step]}>
40+
<div className="flex w-full flex-col">
41+
<div className="mb-5 flex w-full items-center justify-center">
42+
Step {step + 1} of {welcomeSteps.length} {stepIndicator(step)}
43+
</div>
44+
<div className="flex w-full justify-end">
45+
{step === 2 && (
46+
<button
47+
className="secondary-btn mr-2 w-1/2 rounded-sm py-2 px-6"
48+
onClick={() => {
49+
setStep(0);
50+
navigate("/dashboard");
51+
}}
52+
>
53+
Skip For Now
54+
</button>
55+
)}
56+
<button
57+
className="ml-2 w-1/2 rounded-sm bg-accent py-2 px-6"
58+
onClick={() => {
59+
if (step + 1 === welcomeSteps.length) {
60+
onBoardFinished();
61+
} else {
62+
setStep(step + 1);
63+
}
64+
}}
65+
>
66+
Next
67+
</button>
68+
</div>
69+
</div>
70+
</WelcomeWrapper>
71+
);
72+
};

app/components/WelcomeBack.tsx

+12-10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { UserContext } from "../context/userContext";
1212

1313
// --- UI Components
1414
import { Spinner } from "@chakra-ui/react";
15+
import { WelcomeWrapper } from "./WelcomeWrapper";
1516

1617
export interface WelcomeBackProps {
1718
onOpen: () => void;
@@ -30,14 +31,15 @@ export const WelcomeBack = ({
3031
const [isLoading, setLoading] = useState(false);
3132

3233
return (
33-
<>
34-
<div className="top-[113px] mt-10 text-3xl">Welcome Back!</div>
35-
<div className="top-[209px] mt-10 h-[240px] w-[295px] border border-accent-2 bg-background lg:h-[333.56px] lg:w-[410px]"></div>
36-
<p className="top-[113px] mt-10 text-2xl text-muted">One-Click Verification</p>
37-
<p className="mt-2 mb-10 w-[343px] text-gray-300 lg:w-[410px]">
38-
You can now verify most web3 stamps and return to your destination faster with one-click verification!
39-
</p>
40-
<div className="absolute bottom-10 mb-auto flex w-[295px] items-center justify-between md:relative md:mt-16 lg:w-[410px]">
34+
<WelcomeWrapper
35+
content={{
36+
header: "Welcome Back!",
37+
subHeader: "One-Click Verification",
38+
body: "You can now verify most web3 stamps and return to your destination faster with one-click verification!",
39+
imgSrc: "",
40+
}}
41+
>
42+
<>
4143
<button
4244
data-testid="skip-for-now-button"
4345
className="secondary-btn mr-2 flex w-full items-center justify-center rounded-sm py-2 px-6"
@@ -61,7 +63,7 @@ export const WelcomeBack = ({
6163
>
6264
Refresh My Stamps
6365
</button>
64-
</div>
65-
</>
66+
</>
67+
</WelcomeWrapper>
6668
);
6769
};

app/components/WelcomeWrapper.tsx

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export type Content = {
2+
header: string;
3+
subHeader: string;
4+
body: string;
5+
imgSrc: string;
6+
};
7+
8+
export type WelcomeWrapperProps = {
9+
content: Content;
10+
children: React.ReactNode;
11+
};
12+
13+
export const WelcomeWrapper = ({ content, children }: WelcomeWrapperProps) => {
14+
return (
15+
<>
16+
<div className="top-[113px] mt-10 text-3xl">{content.header}</div>
17+
<div className="top-[209px] mt-10 h-[240px] w-[295px] border border-accent-2 bg-background lg:h-[333.56px] lg:w-[410px]"></div>
18+
<p className="top-[113px] mt-10 text-2xl text-muted">{content.subHeader}</p>
19+
<p className="mt-2 mb-10 w-[343px] text-gray-300 lg:w-[410px]">{content.body}</p>
20+
<div className="absolute bottom-10 mb-auto flex w-[295px] items-center justify-between md:relative md:mt-16 lg:w-[410px]">
21+
{children}
22+
</div>
23+
</>
24+
);
25+
};

0 commit comments

Comments
 (0)