From 886150dfa629d2ca4e4f57def2df68d529a617fe Mon Sep 17 00:00:00 2001 From: seeleng Date: Wed, 25 Sep 2024 15:48:58 +0800 Subject: [PATCH 1/5] fix: add missing category (education) --- frontend/types/categories.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/types/categories.ts b/frontend/types/categories.ts index b22ef238..06f30829 100644 --- a/frontend/types/categories.ts +++ b/frontend/types/categories.ts @@ -9,6 +9,7 @@ import { Microscope, Palette, Scale, + School, UsersRound, } from "lucide-react"; @@ -18,6 +19,7 @@ export enum Category { Politics = "Politics", Media = "Media", Environment = "Environment", + Education = "Education", Economics = "Economics", Sports = "Sports", GenderEquality = "Gender & equality", @@ -37,6 +39,7 @@ export const getCategoryFor = (categoryName: string) => { "gender & equality": Category.GenderEquality, religion: Category.Religion, "society & culture": Category.SocietyCulture, + education: Category.Education, }; const formattedName = categoryName.toLowerCase(); return mappings[formattedName]; @@ -53,6 +56,7 @@ export const categoriesToDisplayName: Record = { [Category.GenderEquality]: "Gender & equality", [Category.Religion]: "Religion", [Category.SocietyCulture]: "Society & culture", + [Category.Education]: "Education", }; export const categoriesToIconsMap: Record = { @@ -66,4 +70,5 @@ export const categoriesToIconsMap: Record = { [Category.GenderEquality]: Scale, [Category.Religion]: HeartHandshake, [Category.SocietyCulture]: UsersRound, + [Category.Education]: School, }; From a180e999e53503577b7437343d779a2b46f47ca8 Mon Sep 17 00:00:00 2001 From: seeleng Date: Wed, 25 Sep 2024 15:50:24 +0800 Subject: [PATCH 2/5] feat(onboarding): hide sidebar --- frontend/components/layout/app-layout.tsx | 58 +++++++++++++---------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/frontend/components/layout/app-layout.tsx b/frontend/components/layout/app-layout.tsx index 42785d2b..1114f20e 100644 --- a/frontend/components/layout/app-layout.tsx +++ b/frontend/components/layout/app-layout.tsx @@ -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"; @@ -81,35 +82,42 @@ const AppLayout = ({ children }: { children: ReactNode }) => { } }, [userProfile, isUserProfileSuccess, setLoggedIn, setNotLoggedIn]); + const pathname = usePathname(); + const isOnboarding = pathname === "/onboarding"; + return (
- - {isLoggedIn && ( - <> - setIsCollapsed(true)} - onExpand={() => setIsCollapsed(false)} - order={1} - {...breakpointConfigMap[mediaBreakpoint]} - > - - - - - )} - -
- {children} -
-
-
+ {isOnboarding ? ( + children + ) : ( + + {isLoggedIn && ( + <> + setIsCollapsed(true)} + onExpand={() => setIsCollapsed(false)} + order={1} + {...breakpointConfigMap[mediaBreakpoint]} + > + + + + + )} + +
+ {children} +
+
+
+ )}
From 398cd996e36890ec738117cceee07962cbcb9769 Mon Sep 17 00:00:00 2001 From: seeleng Date: Wed, 25 Sep 2024 15:51:51 +0800 Subject: [PATCH 3/5] feat: add onboarding page --- .../app/(authenticated)/onboarding/page.tsx | 87 +++++++++++++++++++ frontend/queries/user.ts | 27 +++++- 2 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 frontend/app/(authenticated)/onboarding/page.tsx diff --git a/frontend/app/(authenticated)/onboarding/page.tsx b/frontend/app/(authenticated)/onboarding/page.tsx new file mode 100644 index 00000000..6afd09c9 --- /dev/null +++ b/frontend/app/(authenticated)/onboarding/page.tsx @@ -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([]); + 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 ( +
+
+ {isLoading && } + {!isLoading && ( + <> +

+ Let's get started! +
+ What are your preferred GP categories? +

+
+ {categories!.map((category) => { + const isActive = categoryIds.includes(category.id); + return ( +
toggleCategory(category.id)} + > + {getCategoryFor(category.name)} +
+ ); + })} +
+ + + )} +
+
+ ); +} diff --git a/frontend/queries/user.ts b/frontend/queries/user.ts index 0af6a57b..85810ef9 100644 --- a/frontend/queries/user.ts +++ b/frontend/queries/user.ts @@ -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"; @@ -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] }); + }, + }); +}; From 669c3a67bbdc43b48a1d293962b44b943e532d70 Mon Sep 17 00:00:00 2001 From: seeleng Date: Wed, 25 Sep 2024 15:52:43 +0800 Subject: [PATCH 4/5] fix: redirect to onboarding if missing categories --- frontend/app/(authenticated)/template.tsx | 5 +++++ frontend/app/(unauthenticated)/register/page.tsx | 2 +- frontend/app/home.tsx | 8 ++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/frontend/app/(authenticated)/template.tsx b/frontend/app/(authenticated)/template.tsx index c320ffe9..135fe400 100644 --- a/frontend/app/(authenticated)/template.tsx +++ b/frontend/app/(authenticated)/template.tsx @@ -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 {children}; } diff --git a/frontend/app/(unauthenticated)/register/page.tsx b/frontend/app/(unauthenticated)/register/page.tsx index f596061f..bf26b26e 100644 --- a/frontend/app/(unauthenticated)/register/page.tsx +++ b/frontend/app/(unauthenticated)/register/page.tsx @@ -50,7 +50,7 @@ function RegisterPage() { } else { setIsError(false); setLoggedIn(response.data.user); - router.push("/login"); + router.push("/onboarding"); } }; diff --git a/frontend/app/home.tsx b/frontend/app/home.tsx index ccc2de1e..b5d90646 100644 --- a/frontend/app/home.tsx +++ b/frontend/app/home.tsx @@ -1,7 +1,9 @@ import { useEffect, useState } from "react"; +import { useRouter } from "next/navigation"; import { getEventsEventsGet, MiniEventDTO } from "@/client"; import NewsArticle from "@/components/news/news-article"; +import { useUserStore } from "@/store/user/user-store-provider"; const NUM_TOP_EVENTS = 10; const DAYS_PER_WEEK = 7; @@ -11,6 +13,12 @@ const Home = () => { const [topEvents, setTopEvents] = useState([]); const [isLoaded, setIsLoaded] = useState(false); + const router = useRouter(); + const user = useUserStore((state) => state.user); + if (!user!.categories.length) { + router.push("/onboarding"); + } + useEffect(() => { const fetchTopEvents = async () => { const dateNow = new Date(); From 22983715b587a2503c36efdc360a38a951edf089 Mon Sep 17 00:00:00 2001 From: seeleng Date: Wed, 25 Sep 2024 15:56:56 +0800 Subject: [PATCH 5/5] fix: remove extra user --- frontend/app/home.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/app/home.tsx b/frontend/app/home.tsx index bbcb7f45..b547530b 100644 --- a/frontend/app/home.tsx +++ b/frontend/app/home.tsx @@ -16,7 +16,6 @@ const Home = () => { const user = useUserStore((state) => state.user); const router = useRouter(); - const user = useUserStore((state) => state.user); if (!user!.categories.length) { router.push("/onboarding"); }