Skip to content

Commit 298b023

Browse files
committed
Restructured onboarding to be a component instead of context
1 parent 0c4e302 commit 298b023

13 files changed

Lines changed: 210 additions & 258 deletions

File tree

src/components/Onboarding/Onboarding.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
1-
import React, { ReactNode } from "react";
1+
import classNames from "classnames";
2+
import React, { ReactNode, useState } from "react";
23
import { Card, Text } from "../atomic";
3-
import { useOnboarding } from "./OnboardingContext";
4+
import OnboardingComponent from "./OnboardingComponent";
45

56
type OnboardingLayoutProps = {
67
currentPageChildren: ReactNode;
78
};
89

910
const OnboardingLayout = ({ currentPageChildren }: OnboardingLayoutProps) => {
10-
const { switchingRoutes, OnboardingComponent } = useOnboarding();
11+
const [switchingRoutes, setSwitchingRoutes] = useState(false);
1112

12-
if (switchingRoutes) return <></>;
13+
const onboardingStyles = classNames({
14+
"flex flex-col h-full w-full bg-tertiary": true,
15+
hidden: switchingRoutes,
16+
});
1317

1418
return (
15-
<div className="flex flex-col h-full w-full bg-tertiary">
19+
<div className={onboardingStyles}>
1620
<div className="h-3/4 w-full box-border">{currentPageChildren}</div>
1721

1822
<div className="h-1/4 w-full z-10 px-6">
1923
<Card className="animate-border-pulse z-10 w-full p-4 space-y-4 box-border">
2024
<Text h2 b>
2125
Welcome to your new program!
2226
</Text>
23-
{OnboardingComponent}
27+
<OnboardingComponent
28+
switchingRoutes={switchingRoutes}
29+
setSwitchingRoutes={setSwitchingRoutes}
30+
/>
2431
</Card>
2532
</div>
2633
</div>

src/components/Onboarding/OnboardingComponent.tsx

Lines changed: 156 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,153 @@
1+
import Link from "next/link";
12
import { useRouter } from "next/router";
3+
import React from "react";
4+
import {
5+
UpdateProfileInput,
6+
useUpdateProfileMutation,
7+
} from "../../generated/graphql";
8+
import {
9+
AuthorizationLevel,
10+
useAuthorizationLevel,
11+
useCurrentProfile,
12+
} from "../../hooks";
13+
import LocalStorage from "../../utils/localstorage";
214
import { Button, Text } from "../atomic";
315
import StepTracker from "../atomic/StepTracker";
4-
import { OnboardingProps } from "./OnboardingContext";
16+
17+
const ONBOARDING_STEP = "Onboarding Step";
18+
19+
type OnboardingText = (baseRoute: string) => {
20+
[key: number]: { step: string; route: string };
21+
};
22+
23+
const authorizationLevelToMaxSteps = (authLevel: AuthorizationLevel) => {
24+
switch (authLevel) {
25+
case AuthorizationLevel.Admin:
26+
return 5;
27+
case AuthorizationLevel.Mentor:
28+
return 2;
29+
case AuthorizationLevel.Mentee:
30+
return 2;
31+
default:
32+
return 0;
33+
}
34+
};
35+
36+
const AdminOnboardingText: OnboardingText = (baseRoute: string) => ({
37+
1: {
38+
step: "Set up your program homepage",
39+
route: baseRoute,
40+
},
41+
2: {
42+
step: "Edit your mentor applications",
43+
route: baseRoute + "/applications/edit-mentor-app",
44+
},
45+
3: {
46+
step: "Edit your mentee applications",
47+
route: baseRoute + "/applications/edit-mentee-app",
48+
},
49+
4: {
50+
step: "Edit your mentor profile structure",
51+
route: baseRoute + "/mentors/edit-profile",
52+
},
53+
5: {
54+
step: "Edit your mentee profile structure",
55+
route: baseRoute + "/mentees/edit-profile",
56+
},
57+
});
58+
59+
const MentorOnboardingText: OnboardingText = (baseRoute: string) => ({
60+
1: {
61+
step: "Fill out your profile",
62+
route: baseRoute + "/edit-profile",
63+
},
64+
2: {
65+
step: "Set your availability",
66+
route: baseRoute + "/availability",
67+
},
68+
});
69+
70+
const MenteeOnboardingText: OnboardingText = (baseRoute: string) => ({
71+
1: {
72+
step: "Fill out your profile",
73+
route: baseRoute + "/edit-profile",
74+
},
75+
2: {
76+
step: "Browse through available mentors",
77+
route: baseRoute + "/mentors",
78+
},
79+
});
80+
81+
const authLevelToText = (authLevel: AuthorizationLevel) => {
82+
switch (authLevel) {
83+
case AuthorizationLevel.Admin:
84+
return AdminOnboardingText;
85+
case AuthorizationLevel.Mentor:
86+
return MentorOnboardingText;
87+
default:
88+
return MenteeOnboardingText;
89+
}
90+
};
91+
92+
type OnboardingProps = {
93+
switchingRoutes: boolean;
94+
setSwitchingRoutes: (bool: boolean) => void;
95+
};
596

697
const Onboarding = ({
7-
onFinish,
8-
currentStep,
9-
setCurrentStep,
10-
loading,
11-
setLoading,
12-
onboardingText,
13-
MAX_STEPS,
98+
switchingRoutes,
99+
setSwitchingRoutes,
14100
}: OnboardingProps) => {
101+
const currentProfile = useCurrentProfile();
102+
const [updateProfile] = useUpdateProfileMutation({
103+
refetchQueries: ["getMyUser"],
104+
});
105+
106+
const authorizationLevel = useAuthorizationLevel();
15107
const router = useRouter();
16108

109+
const MAX_STEPS = authorizationLevelToMaxSteps(authorizationLevel);
110+
const baseRoute = `/program/${router.query.slug}/${router.query.profileRoute}`;
111+
const onboardingText = authLevelToText(authorizationLevel)(baseRoute);
112+
113+
const onFinish = () => {
114+
const updateProfileInput: UpdateProfileInput = {
115+
onboarded: true,
116+
};
117+
updateProfile({
118+
variables: {
119+
profileId: currentProfile.currentProfile!.profileId,
120+
data: updateProfileInput,
121+
},
122+
})
123+
.then(() => {
124+
currentProfile.refetchCurrentProfile!();
125+
LocalStorage.delete(ONBOARDING_STEP);
126+
})
127+
.catch((err) => console.error(err));
128+
};
129+
130+
const storedStep = LocalStorage.get(ONBOARDING_STEP);
131+
const currentStep =
132+
storedStep && typeof storedStep == "number" ? storedStep : 1;
133+
134+
//If the user tries to navigate to another route or if they land on a page that isn't the first step
135+
//Return them to the actual page of the current step
136+
if (
137+
router.asPath !== onboardingText[currentStep]["route"] &&
138+
!switchingRoutes
139+
) {
140+
//Hide content if switching routes
141+
setSwitchingRoutes(true);
142+
router
143+
.push(onboardingText[currentStep]["route"])
144+
.then(() => setSwitchingRoutes(false));
145+
}
146+
147+
const prevStep = Math.max(currentStep - 1, 1);
148+
const nextStep = Math.min(currentStep + 1, MAX_STEPS);
149+
150+
//Use Links to switch between tabs so that you don't have to wait for router.push
17151
return (
18152
<div className="w-full flex flex-col items-center space-y-2 z-10">
19153
<Text h3 className="w-full">
@@ -24,41 +158,37 @@ const Onboarding = ({
24158
<div className="w-full">
25159
<StepTracker steps={MAX_STEPS} currentStep={currentStep} />
26160
</div>
161+
27162
<Button
28163
size="small"
29164
variant="inverted"
30-
disabled={currentStep === 1 || loading}
165+
disabled={currentStep === 1}
31166
onClick={() => {
32-
setLoading(true);
33-
const prevStep = Math.max(currentStep - 1, 1);
34-
router.push(onboardingText[prevStep]["route"]).then(() => {
35-
setCurrentStep(prevStep);
36-
setLoading(false);
37-
});
167+
LocalStorage.set(ONBOARDING_STEP, prevStep);
38168
}}
39169
>
40-
Back
170+
{currentStep !== 1 ? (
171+
<Link href={onboardingText[prevStep]["route"]}>Back</Link>
172+
) : (
173+
"Back"
174+
)}
41175
</Button>
42176
<div className="w-4" />
43177
<Button
44178
size="small"
45-
disabled={loading}
46179
onClick={() => {
47180
if (currentStep !== MAX_STEPS) {
48-
setLoading(true);
49-
const nextStep = Math.min(currentStep + 1, MAX_STEPS);
50-
router.push(onboardingText[nextStep]["route"]).then(() => {
51-
setCurrentStep(nextStep);
52-
setLoading(false);
53-
});
181+
LocalStorage.set(ONBOARDING_STEP, nextStep);
54182
} else {
55-
setLoading(true);
56183
onFinish();
57-
setLoading(false);
58184
}
59185
}}
60186
>
61-
{currentStep !== MAX_STEPS ? "Next" : "Finish"}
187+
{currentStep !== MAX_STEPS ? (
188+
<Link href={onboardingText[nextStep]["route"]}>Next</Link>
189+
) : (
190+
"Finish"
191+
)}
62192
</Button>
63193
</div>
64194
</div>

0 commit comments

Comments
 (0)