Skip to content

Commit

Permalink
Merge pull request #77 from cs3216-a3-group-4/seeleng/add-onboarding
Browse files Browse the repository at this point in the history
feat: add onboarding
  • Loading branch information
seelengxd authored Sep 25, 2024
2 parents fd1a0fd + 2298371 commit 56d21f9
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 28 deletions.
87 changes: 87 additions & 0 deletions frontend/app/(authenticated)/onboarding/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { useQuery } from "@tanstack/react-query";
import clsx from "clsx";
import { ArrowRight } from "lucide-react";

import { Button } from "@/components/ui/button";
import { LoadingSpinner } from "@/components/ui/loading-spinner";
import { getCategories } from "@/queries/category";
import { useUpdateProfile } from "@/queries/user";
import { useUserStore } from "@/store/user/user-store-provider";
import { getCategoryFor } from "@/types/categories";

export default function Onboarding() {
const { data: categories, isLoading } = useQuery(getCategories());
const [categoryIds, setCategoryIds] = useState<number[]>([]);
const user = useUserStore((state) => state.user);

const toggleCategory = (id: number) => {
if (!categoryIds.includes(id)) {
setCategoryIds([...categoryIds, id]);
} else {
setCategoryIds(categoryIds.filter((item) => item !== id));
}
};

const updateProfileMutation = useUpdateProfile();
const router = useRouter();

const handleSubmit = () => {
updateProfileMutation.mutate(
{ categoryIds },
{
onSuccess: () => {
router.push("/");
},
},
);
};

if (user?.categories.length) {
router.push("/");
}

return (
<div className="flex justify-center items-center h-[calc(100vh_-_72px)]">
<div className="flex flex-col items-center gap-16">
{isLoading && <LoadingSpinner className="w-24 h-24" />}
{!isLoading && (
<>
<h1 className="text-3xl font-bold text-center leading-[3rem]">
Let&apos;s get started!
<br />
What are your preferred GP categories?
</h1>
<div className="flex flex-wrap gap-4 justify-center max-w-2xl">
{categories!.map((category) => {
const isActive = categoryIds.includes(category.id);
return (
<div
className={clsx(
"font-medium p-3 px-4 rounded-3xl cursor-pointer shadow-md",
{
"bg-emerald-600 text-white": isActive,
"bg-slate-100": !isActive,
},
)}
key={category.id}
onClick={() => toggleCategory(category.id)}
>
{getCategoryFor(category.name)}
</div>
);
})}
</div>
<Button className="flex items-center gap-2" onClick={handleSubmit}>
Save and Continue
<ArrowRight className="w-4 h-4" />
</Button>
</>
)}
</div>
</div>
);
}
5 changes: 5 additions & 0 deletions frontend/app/(authenticated)/template.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,15 @@ export default function RedirectIfNotAuthenticated({
const { status } = useQuery(getUserProfile());

const isLoggedIn = useUserStore((state) => state.isLoggedIn);
const user = useUserStore((state) => state.user);
console.log({ isLoggedIn, status });

if (!isLoggedIn && !status) {
router.push("/login");
}
if (isLoggedIn && !user!.categories.length) {
router.push("/onboarding");
}

return <Suspense>{children}</Suspense>;
}
2 changes: 1 addition & 1 deletion frontend/app/(unauthenticated)/register/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ function RegisterPage() {
} else {
setIsError(false);
setLoggedIn(response.data.user);
router.push("/login");
router.push("/onboarding");
}
};

Expand Down
6 changes: 6 additions & 0 deletions frontend/app/home.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";

import { getEventsEventsGet, MiniEventDTO } from "@/client";
import ArticleLoading from "@/components/news/article-loading";
Expand All @@ -14,6 +15,11 @@ const Home = () => {
const [isLoaded, setIsLoaded] = useState<boolean>(false);
const user = useUserStore((state) => state.user);

const router = useRouter();
if (!user!.categories.length) {
router.push("/onboarding");
}

useEffect(() => {
const fetchTopEvents = async () => {
const dateNow = new Date();
Expand Down
58 changes: 33 additions & 25 deletions frontend/components/layout/app-layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import { ComponentProps, ReactNode, useEffect, useState } from "react";
import { usePathname } from "next/navigation";
import { useQuery } from "@tanstack/react-query";

import Navbar from "@/components/navigation/navbar";
Expand Down Expand Up @@ -81,35 +82,42 @@ const AppLayout = ({ children }: { children: ReactNode }) => {
}
}, [userProfile, isUserProfileSuccess, setLoggedIn, setNotLoggedIn]);

const pathname = usePathname();
const isOnboarding = pathname === "/onboarding";

return (
<div className="relative flex min-h-screen flex-col bg-background">
<Navbar />
<main>
<ResizablePanelGroup
className="flex flex-1 w-full h-[calc(100vh_-_72px)]"
direction="horizontal"
>
{isLoggedIn && (
<>
<ResizablePanel
className="flex w-full"
id="sidebar"
onCollapse={() => setIsCollapsed(true)}
onExpand={() => setIsCollapsed(false)}
order={1}
{...breakpointConfigMap[mediaBreakpoint]}
>
<Sidebar />
</ResizablePanel>
<ResizableHandle withHandle={isCollapsed} />
</>
)}
<ResizablePanel defaultSize={75} order={2}>
<div className="flex flex-1 w-full h-[calc(100vh_-_72px)] min-h-[calc(100vh_-_72px)] overflow-y-scroll">
{children}
</div>
</ResizablePanel>
</ResizablePanelGroup>
{isOnboarding ? (
children
) : (
<ResizablePanelGroup
className="flex flex-1 w-full h-[calc(100vh_-_72px)]"
direction="horizontal"
>
{isLoggedIn && (
<>
<ResizablePanel
className="flex w-full"
id="sidebar"
onCollapse={() => setIsCollapsed(true)}
onExpand={() => setIsCollapsed(false)}
order={1}
{...breakpointConfigMap[mediaBreakpoint]}
>
<Sidebar />
</ResizablePanel>
<ResizableHandle withHandle={isCollapsed} />
</>
)}
<ResizablePanel defaultSize={75} order={2}>
<div className="flex flex-1 w-full h-[calc(100vh_-_72px)] min-h-[calc(100vh_-_72px)] overflow-y-scroll">
{children}
</div>
</ResizablePanel>
</ResizablePanelGroup>
)}
</main>
<Toaster />
</div>
Expand Down
27 changes: 25 additions & 2 deletions frontend/queries/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { queryOptions } from "@tanstack/react-query";
import {
queryOptions,
useMutation,
useQueryClient,
} from "@tanstack/react-query";

import { getUserAuthSessionGet } from "@/client/services.gen";
import {
getUserAuthSessionGet,
updateProfileProfilePut,
} from "@/client/services.gen";

import { QueryKeys } from "./utils/query-keys";

Expand All @@ -12,3 +19,19 @@ export const getUserProfile = () =>
(data) => data.data,
),
});

export const useUpdateProfile = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({ categoryIds }: { categoryIds: number[] }) => {
return updateProfileProfilePut({
body: {
category_ids: categoryIds,
},
});
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QueryKeys.UserProfile] });
},
});
};
5 changes: 5 additions & 0 deletions frontend/types/categories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Microscope,
Palette,
Scale,
School,
UsersRound,
} from "lucide-react";

Expand All @@ -19,6 +20,7 @@ export enum Category {
Politics = "Politics",
Media = "Media",
Environment = "Environment",
Education = "Education",
Economics = "Economics",
Sports = "Sports",
GenderEquality = "Gender & equality",
Expand All @@ -39,6 +41,7 @@ export const getCategoryFor = (categoryName: string) => {
"gender & equality": Category.GenderEquality,
religion: Category.Religion,
"society & culture": Category.SocietyCulture,
education: Category.Education,
};
const formattedName = categoryName.toLowerCase();
if (formattedName in mappings) {
Expand All @@ -58,6 +61,7 @@ export const categoriesToDisplayName: Record<Category, string> = {
[Category.GenderEquality]: "Gender & equality",
[Category.Religion]: "Religion",
[Category.SocietyCulture]: "Society & culture",
[Category.Education]: "Education",
[Category.Others]: "Others",
};

Expand All @@ -72,5 +76,6 @@ export const categoriesToIconsMap: Record<Category, LucideIcon> = {
[Category.GenderEquality]: Scale,
[Category.Religion]: HeartHandshake,
[Category.SocietyCulture]: UsersRound,
[Category.Education]: School,
[Category.Others]: CircleHelp,
};

0 comments on commit 56d21f9

Please sign in to comment.