Skip to content

Commit

Permalink
feat(web): improve onboarding
Browse files Browse the repository at this point in the history
  • Loading branch information
cstrnt committed Aug 22, 2024
1 parent ce663df commit 50ea045
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 63 deletions.
3 changes: 2 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"start:docker": "npx prisma migrate deploy || { echo 'Migration failed, exiting'; exit 1; } && node server.js"
},
"dependencies": {
"@calcom/embed-react": "^1.5.0",
"@code-hike/mdx": "0.9.0",
"@databases/cache": "^1.0.0",
"@dnd-kit/core": "^6.0.8",
Expand Down Expand Up @@ -105,7 +106,7 @@
"rate-limiter-flexible": "^5.0.3",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.9",
"react-hook-form": "^7.44.3",
"react-hot-toast": "^2.4.0",
"react-icons": "^4.11.0",
"react-use-wizard": "^2.2.3",
Expand Down
171 changes: 110 additions & 61 deletions apps/web/src/pages/welcome.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
import Cal, { getCalApi } from "@calcom/embed-react";
import { DISCORD_INVITE_URL } from "components/Footer";
import { Input } from "components/Input";
import { RadioGroupComponent } from "components/RadioGroup";
import { Select } from "components/Select";
import { Button } from "components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "components/ui/card";
import { Label } from "components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "components/ui/select";
import { AnimatePresence, motion } from "framer-motion";
import { cn } from "lib/utils";
import { ChevronRight } from "lucide-react";
import type { GetServerSideProps, InferGetServerSidePropsType } from "next";
import { useSession } from "next-auth/react";
import Link from "next/link";
Expand Down Expand Up @@ -71,6 +88,16 @@ const useOnboardingStore = create<{
set({ experienceLevelTests }),
}));

const FormItem = ({
children,
labelText,
}: { children: React.ReactNode; labelText: string }) => (
<div className="grid w-full max-w-sm items-center gap-1.5">
<Label>{labelText}</Label>
{children}
</div>
);

function WizardFooter() {
const { previousStep, nextStep, isFirstStep, isLastStep, activeStep } =
useWizard();
Expand All @@ -82,7 +109,7 @@ function WizardFooter() {
(activeStep === 2 && technologies.length === 0);

return (
<div className="flex justify-between">
<CardFooter className="flex justify-between">
<Button
disabled={isFirstStep}
onClick={previousStep}
Expand All @@ -97,7 +124,7 @@ function WizardFooter() {
>
Next
</Button>
</div>
</CardFooter>
);
}

Expand All @@ -109,15 +136,18 @@ function Step1() {
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
>
<h1 className="mb-1 text-3xl font-semibold">Welcome to Abby</h1>
<p>Thank you very much for signing up for Abby</p>

<form className="mt-6 space-y-3">
<CardHeader>
<CardTitle>Welcome to Abby</CardTitle>
<CardDescription>
Thank you very much for signing up for Abby
</CardDescription>
</CardHeader>
<CardContent>
<label>
<span>Name</span>
<Input value={name} onChange={(e) => setName(e.target.value)} />
</label>
</form>
</CardContent>
</motion.div>
);
}
Expand Down Expand Up @@ -145,19 +175,30 @@ function Step2() {
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
>
<h1 className="mb-1 text-3xl font-semibold">About you</h1>

<form className="mt-6 flex flex-col space-y-5">
<label>
<span>Role</span>
<Select
items={ROLES.map((r) => ({ label: r, value: r }))}
value={profession}
onChange={(value) => setProfession(value)}
/>
</label>
<label>
<span>How would you rate your experience with Feature Flags</span>
<CardHeader>
<CardTitle>About you</CardTitle>
<CardDescription>Tell us more about you</CardDescription>
</CardHeader>
<CardContent className="flex flex-col space-y-5">
<FormItem labelText="Your current role">
<Select value={profession} onValueChange={setProfession}>
<SelectTrigger className="-ml-1">
<SelectValue placeholder="Role" />
</SelectTrigger>
<SelectContent>
{ROLES.map((role) => (
<SelectItem
key={role}
onClick={() => setProfession(role)}
value={role}
>
{role}
</SelectItem>
))}
</SelectContent>
</Select>
</FormItem>
<FormItem labelText="How would you rate your experience with Feature Flags">
<RadioGroupComponent
items={oneToFiveOptions}
value={experienceLevelFlags.toString()}
Expand All @@ -166,9 +207,8 @@ function Step2() {
<small className="text-xs text-gray-400">
1 is no experience - 5 is very frequent usage
</small>
</label>
<label>
<span>How would you rate your experience with A/B Testing</span>
</FormItem>
<FormItem labelText="How would you rate your experience with A/B Testing">
<RadioGroupComponent
items={oneToFiveOptions}
value={experienceLevelTests.toString()}
Expand All @@ -177,8 +217,8 @@ function Step2() {
<small className="text-xs text-gray-400">
1 is no experience - 5 is very frequent usage
</small>
</label>
</form>
</FormItem>
</CardContent>
</motion.div>
);
}
Expand Down Expand Up @@ -243,30 +283,34 @@ function Step3() {
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
>
<h1 className="mb-1 text-3xl font-semibold">Technical Background</h1>
<CardHeader>
<CardTitle>Technical Background</CardTitle>
<CardDescription>
What technologies do you use currently?
</CardDescription>
</CardHeader>

<form className="mt-6 flex flex-col space-y-5">
<label>What technologies do you use currently?</label>
<CardContent className="flex flex-col space-y-5">
<div className="grid grid-cols-4 gap-4">
{TECHNOLOGIES.map(({ name, icon: Icon }) => (
<button
key={name}
type="button"
className={cn(
"flex aspect-square w-full flex-col items-center justify-center space-y-3 rounded-sm border border-gray-100 p-2 transition-colors",
"data-[selected='true']:border-pink-500 data-[selected='true']:bg-gray-800"
"flex aspect-square w-full flex-col items-center justify-center space-y-3 rounded-sm border border-gray-600 p-2 transition-colors hover:bg-ab_primary-background",
"data-[selected='true']:border-white"
)}
data-selected={technologies.includes(name)}
onClick={() => {
toggleTechnology(name);
}}
>
<Icon className="h-6 w-6" />
<p>{name}</p>
<p className="font-medium">{name}</p>
</button>
))}
</div>
</form>
</CardContent>
</motion.div>
);
}
Expand All @@ -278,37 +322,34 @@ function Step4() {
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
>
<h1 className="mb-1 text-3xl font-semibold">You&apos;re ready to go!</h1>
<div className="mt-12 text-lg">
<CardHeader>
<CardTitle>You&apos;re ready to go!</CardTitle>
<CardDescription>
Thank you very much for signing up to Abby. You&apos;re now ready to
start using Abby.
</CardDescription>
</CardHeader>
<CardContent className="mt-12 text-lg">
<p>
Thank you very much for signing up to Abby
<br />
<br />
If you have any questions, feel free to join our{" "}
<Link className="text-pink-500" href={DISCORD_INVITE_URL}>
<Link className="text-ab_accent-background" href={DISCORD_INVITE_URL}>
Discord
</Link>{" "}
or send us an email to{" "}
<a className="text-pink-500" href="mailto:[email protected]">
[email protected]
</a>
or book a free 1:1 onboarding session with us.
<br />
<br />
You can also book a <b>free</b> 30 minute onboarding call with us to
get you started. Feel free to pick a time that works for you{" "}
<a
className="text-pink-500"
href="https://cal.com/cstrnt/abby-onboarding"
>
here
</a>
<Cal
namespace="abby-onboarding"
calLink="cstrnt/abby-onboarding"
style={{ width: "100%", height: "100%", overflow: "scroll" }}
/>
</p>
<Link href="/projects">
<Button className="mx-auto mt-12 block w-[150px] bg-pink-500 font-semibold text-white hover:bg-pink-600">
Go to Abby
<Button className="mx-auto mt-12 w-[150px] flex items-center">
Go to Abby <ChevronRight size={18} />
</Button>
</Link>
</div>
</CardContent>
</motion.div>
);
}
Expand All @@ -320,23 +361,31 @@ export default function WelcomePage(
useOnboardingStore.getState().setName(props.user.name ?? "");
}, [props.user.name]);

useEffect(() => {
(async () => {
const cal = await getCalApi({ namespace: "abby-onboarding" });
cal("ui", {
theme: "dark",
styles: { branding: { brandColor: "#f9a8d4" } },
hideEventTypeDetails: false,
layout: "month_view",
});
})();
}, []);

return (
<main className="flex min-h-screen items-center justify-center bg-ab_primary-background text-ab_primary-foreground">
<div className="flex h-[500px] w-full max-w-2xl flex-col rounded-md border border-ab_accent-background-muted bg-ab_primary-background p-8 text-ab_primary-foreground shadow-md shadow-ab_accent-background">
<Card className="max-w-[80vw] min-w-[500px]">
<Wizard
footer={<WizardFooter />}
wrapper={
<div className="mb-6 flex flex-1">
<AnimatePresence mode="wait" />
</div>
}
wrapper={<AnimatePresence mode="wait" />}
>
<Step1 />
<Step2 />
<Step3 />
<Step4 />
</Wizard>
</div>
</Card>
</main>
);
}
Expand Down
27 changes: 26 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 50ea045

Please sign in to comment.