OnboardingChecklist.tsx raw
1 import { ChevronRightIcon, CircleCheckIcon, CircleIcon } from "lucide-react";
2 import { Link } from "react-router";
3 import {
4 Card,
5 CardContent,
6 CardDescription,
7 CardHeader,
8 CardTitle,
9 } from "src/components/ui/card";
10 import { useOnboardingData } from "src/hooks/useOnboardingData";
11 import { cn } from "src/lib/utils";
12
13 interface ChecklistItemProps {
14 title: string;
15 checked: boolean;
16 description: string;
17 to: string;
18 disabled: boolean;
19 index: number;
20 }
21
22 function OnboardingChecklist() {
23 const { isLoading, checklistItems } = useOnboardingData();
24
25 if (isLoading || !checklistItems.find((x) => !x.checked)) {
26 return null;
27 }
28
29 return (
30 <Card>
31 <CardHeader>
32 <CardTitle>Get started with your Alby Hub</CardTitle>
33 <CardDescription>
34 Follow these initial steps to set up and make the most of your Alby
35 Hub.
36 </CardDescription>
37 </CardHeader>
38 <CardContent className="flex flex-col">
39 {checklistItems.map((item, index) => (
40 <ChecklistItem
41 key={item.title}
42 index={index}
43 title={item.title}
44 description={item.description}
45 checked={item.checked}
46 to={item.to}
47 disabled={item.disabled}
48 />
49 ))}
50 </CardContent>
51 </Card>
52 );
53 }
54
55 function ChecklistItem({
56 title,
57 checked = false,
58 description,
59 to,
60 disabled = false,
61 index,
62 }: ChecklistItemProps) {
63 const content = (
64 <div
65 className={cn(
66 "flex flex-col p-3 relative group rounded-lg",
67 !checked && !disabled && "hover:bg-muted",
68 disabled && "opacity-50"
69 )}
70 >
71 {!checked && !disabled && (
72 <div className="absolute top-0 left-0 w-full h-full items-center justify-end pr-1.5 hidden group-hover:flex opacity-25">
73 <ChevronRightIcon className="size-8" />
74 </div>
75 )}
76 <div className="flex items-center gap-2">
77 {checked ? (
78 <CircleCheckIcon className="size-5" />
79 ) : (
80 <CircleIcon className="size-5" />
81 )}
82 <div
83 className={cn(
84 "text-sm font-medium leading-none",
85 checked && "line-through"
86 )}
87 >
88 {index + 1}. {title}
89 </div>
90 </div>
91 {!checked && (
92 <div className="text-muted-foreground text-sm mx-7">{description}</div>
93 )}
94 </div>
95 );
96
97 return checked || disabled ? content : <Link to={to}>{content}</Link>;
98 }
99
100 export default OnboardingChecklist;
101