From ea258f167e5ebc6e1aeaddb37f554653b95fb03d Mon Sep 17 00:00:00 2001 From: Lamarcke Date: Sun, 11 Aug 2024 23:19:36 -0300 Subject: [PATCH] - --- capacitor.config.ts | 8 +- src/App.test.tsx | 8 -- src/App.tsx | 35 +++--- .../achievement/AchievementsScreen.tsx | 106 +++++++----------- .../item/CollectionEntryActivityItem.tsx | 6 +- src/components/auth/SuperTokensProvider.tsx | 12 +- .../modal/CollectionEntryAddOrUpdateModal.tsx | 2 +- .../hooks/useOwnCollectionEntryForGameId.ts | 10 +- ...up.tsx => UserAvatarWithFollowActions.tsx} | 10 +- .../follow/input/UserFollowActions.tsx | 15 +-- src/components/follow/list/FollowInfoList.tsx | 42 +++---- .../follow/modal/FollowInfoListModal.tsx | 18 +-- .../game/figure/GameListItemWithSwipe.tsx | 3 +- .../game/info/review/GameInfoReviewList.tsx | 12 +- src/components/game/view/GameViewContent.tsx | 17 +-- .../game/view/GameViewLayoutSwitcher.tsx | 30 ++--- src/components/general/TabHeader.tsx | 25 ++++- .../avatar/UserAvatarWithLevelInfo.tsx | 3 - .../preferences/PreferencesModal.tsx | 33 ++++++ .../preferences/view/PreferencesScreen.tsx | 19 ++++ .../profile/view/ProfileNavbarFollowInfo.tsx | 5 +- .../profile/view/ProfileReviewListView.tsx | 79 ++----------- .../view/ProfileUserInfoWithBanner.tsx | 72 ++++++------ .../profile/view/ProfileViewNavbar.tsx | 5 - src/pages/achievements.tsx | 43 +++++++ src/pages/auth.tsx | 28 +++++ src/pages/home.tsx | 21 ++-- src/pages/library.tsx | 12 +- src/pages/{ => profile}/profile.tsx | 3 +- src/pages/profile/review_list.tsx | 34 ++++++ src/pages/routes/getCommonRoutes.tsx | 26 ++++- src/util/getTabAwareHref.ts | 1 - 32 files changed, 408 insertions(+), 335 deletions(-) delete mode 100644 src/App.test.tsx rename src/components/follow/input/{UserFollowGroup.tsx => UserAvatarWithFollowActions.tsx} (65%) create mode 100644 src/components/preferences/PreferencesModal.tsx create mode 100644 src/components/preferences/view/PreferencesScreen.tsx create mode 100644 src/pages/achievements.tsx create mode 100644 src/pages/auth.tsx rename src/pages/{ => profile}/profile.tsx (95%) create mode 100644 src/pages/profile/review_list.tsx diff --git a/capacitor.config.ts b/capacitor.config.ts index 5ea50ad..178591e 100644 --- a/capacitor.config.ts +++ b/capacitor.config.ts @@ -1,9 +1,9 @@ -import type { CapacitorConfig } from '@capacitor/cli'; +import type { CapacitorConfig } from "@capacitor/cli"; const config: CapacitorConfig = { - appId: 'io.ionic.starter', - appName: 'game-node-mobile', - webDir: 'dist' + appId: "app.gamenode", + appName: "GameNode", + webDir: "dist", }; export default config; diff --git a/src/App.test.tsx b/src/App.test.tsx deleted file mode 100644 index 8c927a8..0000000 --- a/src/App.test.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import App from './App'; - -test('renders without crashing', () => { - const { baseElement } = render(); - expect(baseElement).toBeDefined(); -}); diff --git a/src/App.tsx b/src/App.tsx index 7f532d3..70937bd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,7 +2,16 @@ import React, { useState } from "react"; import { Redirect, Route } from "react-router-dom"; import * as reactRouterDom from "react-router-dom"; -import { IonApp, IonLabel, IonRouterOutlet, IonTabBar, IonTabButton, IonTabs, setupIonicReact } from "@ionic/react"; +import { + IonApp, + IonLabel, + IonPage, + IonRouterOutlet, + IonTabBar, + IonTabButton, + IonTabs, + setupIonicReact, +} from "@ionic/react"; import { IonReactRouter } from "@ionic/react-router"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { MantineProvider } from "@mantine/core"; @@ -40,7 +49,7 @@ import "@ionic/react/css/palettes/dark.always.css"; /* Theme variables */ import "./theme/variables.css"; -import { getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; +import { AuthPage, getSuperTokensRoutesForReactRouterDom } from "supertokens-auth-react/ui"; import { ThirdPartyPreBuiltUI } from "supertokens-auth-react/recipe/thirdparty/prebuiltui"; import { PasswordlessPreBuiltUI } from "supertokens-auth-react/recipe/passwordless/prebuiltui"; import SuperTokensProvider from "./components/auth/SuperTokensProvider"; @@ -49,9 +58,8 @@ import { OpenAPI as ServerOpenAPI } from "@/wrapper/server"; import { OpenAPI as SearchOpenAPI } from "@/wrapper/search"; import ExplorePage from "@/pages/explore"; import SearchResultsPage from "@/pages/search_results"; -import GamePage from "@/pages/game"; import HomePage from "./pages/home"; -import ProfilePage from "@/pages/profile"; +import ProfilePage from "@/pages/profile/profile"; import { getCommonRoutes } from "./pages/routes/getCommonRoutes"; import LibraryPage from "./pages/library"; import NotificationsManager from "./components/general/NotificationsManager"; @@ -72,11 +80,6 @@ const App: React.FC = () => { defaultOptions: { queries: { refetchOnWindowFocus: false, - refetchInterval: false, - refetchOnMount: false, - refetchIntervalInBackground: false, - refetchOnReconnect: false, - staleTime: Infinity, retry: 2, }, }, @@ -92,11 +95,6 @@ const App: React.FC = () => { - {/*This renders the login UI on the /auth route*/} - {getSuperTokensRoutesForReactRouterDom(reactRouterDom, [ - ThirdPartyPreBuiltUI, - PasswordlessPreBuiltUI, - ])} {/* ---- HOME ROUTES ---- */} @@ -135,14 +133,15 @@ const App: React.FC = () => { Explore - - - Profile - + Library + + + Profile + diff --git a/src/components/achievement/AchievementsScreen.tsx b/src/components/achievement/AchievementsScreen.tsx index 2202bfb..119cce3 100644 --- a/src/components/achievement/AchievementsScreen.tsx +++ b/src/components/achievement/AchievementsScreen.tsx @@ -1,16 +1,5 @@ import React, { useState } from "react"; -import { - Box, - Button, - Center, - Divider, - Group, - Pagination, - Paper, - Progress, - SimpleGrid, - Stack, -} from "@mantine/core"; +import { Box, Button, Center, Divider, Group, Pagination, Paper, Progress, SimpleGrid, Stack } from "@mantine/core"; import { SessionAuth } from "supertokens-auth-react/recipe/session"; import useUserId from "@/components/auth/hooks/useUserId"; import { useAchievements } from "@/components/achievement/hooks/useAchievements"; @@ -33,62 +22,49 @@ const AchievementsScreen = ({ targetUserId }: Props) => { const isOwnUserId = userId != undefined && userId === targetUserId; if (!targetUserId) return null; return ( - - - - - - + + + + + - {isOwnUserId && ( - - )} - - - - {achievements.isError && ( -
- Something happened while loading achievements. Please - try again. -
+ {isOwnUserId && ( + )} - {achievements.isLoading && } - + + + {achievements.isError && ( +
Something happened while loading achievements. Please try again.
+ )} + {achievements.isLoading && } + + {achievements.data?.data?.map((achievement) => { + return ( + + ); + })} + +
+ { + const pageAsOffset = paginationData.limit * (page - 1); + setPaginationData({ + offset: pageAsOffset, + limit: paginationData.limit, + }); }} - > - {achievements.data?.data?.map((achievement) => { - return ( - - ); - })} - -
- { - const pageAsOffset = - paginationData.limit * (page - 1); - setPaginationData({ - offset: pageAsOffset, - limit: paginationData.limit, - }); - }} - /> -
- - + /> +
+
); }; diff --git a/src/components/activity/item/CollectionEntryActivityItem.tsx b/src/components/activity/item/CollectionEntryActivityItem.tsx index c5ccb3b..695b6fd 100644 --- a/src/components/activity/item/CollectionEntryActivityItem.tsx +++ b/src/components/activity/item/CollectionEntryActivityItem.tsx @@ -85,7 +85,11 @@ const CollectionEntryActivityItem = ({ activity }: Props) => { - + {collectionQuery.data?.name} diff --git a/src/components/auth/SuperTokensProvider.tsx b/src/components/auth/SuperTokensProvider.tsx index 7ae601d..072577b 100755 --- a/src/components/auth/SuperTokensProvider.tsx +++ b/src/components/auth/SuperTokensProvider.tsx @@ -5,20 +5,20 @@ import Passwordless from "supertokens-auth-react/recipe/passwordless"; import ThirdParty from "supertokens-auth-react/recipe/thirdparty"; import { SuperTokensConfig } from "supertokens-auth-react/lib/build/types"; import { Capacitor } from "@capacitor/core"; +import { getTabAwareHref } from "@/util/getTabAwareHref"; export const frontendConfig = (): SuperTokensConfig => { - const location = window.location; - const websiteDomain = Capacitor.isNativePlatform() - ? `${location.protocol}//${location.host}` + const PARSED_WEBSITE_DOMAIN = Capacitor.isNativePlatform() + ? `${window.location.protocol}//${window.location.host}` : import.meta.env.VITE_PUBLIC_DOMAIN_WEBSITE; return { appInfo: { appName: "GameNode", apiDomain: import.meta.env.VITE_PUBLIC_DOMAIN_SERVER as string, - websiteDomain: websiteDomain, + websiteDomain: PARSED_WEBSITE_DOMAIN, apiBasePath: "/v1/auth", - websiteBasePath: "/auth", + websiteBasePath: "/profile/auth", }, getRedirectionURL: async (context) => { if (context.action === "SUCCESS" && context.newSessionCreated) { @@ -33,6 +33,8 @@ export const frontendConfig = (): SuperTokensConfig => { // user signed in } return "/"; + } else if (context.action === "TO_AUTH") { + return getTabAwareHref("/auth"); } return undefined; }, diff --git a/src/components/collection/collection-entry/form/modal/CollectionEntryAddOrUpdateModal.tsx b/src/components/collection/collection-entry/form/modal/CollectionEntryAddOrUpdateModal.tsx index 50d7612..19ce98c 100755 --- a/src/components/collection/collection-entry/form/modal/CollectionEntryAddOrUpdateModal.tsx +++ b/src/components/collection/collection-entry/form/modal/CollectionEntryAddOrUpdateModal.tsx @@ -13,7 +13,7 @@ interface IGameAddModalProps extends BaseModalProps { const CollectionEntryAddOrUpdateModal = ({ opened, onClose, id }: IGameAddModalProps) => { const userId = useUserId(); - const collectionEntryQuery = useOwnCollectionEntryForGameId(id); + const collectionEntryQuery = useOwnCollectionEntryForGameId(id, opened); const [isExpanded, setIsExpanded] = useState(false); const isInLibrary = collectionEntryQuery.data != undefined; diff --git a/src/components/collection/collection-entry/hooks/useOwnCollectionEntryForGameId.ts b/src/components/collection/collection-entry/hooks/useOwnCollectionEntryForGameId.ts index b30ed87..036adf6 100644 --- a/src/components/collection/collection-entry/hooks/useOwnCollectionEntryForGameId.ts +++ b/src/components/collection/collection-entry/hooks/useOwnCollectionEntryForGameId.ts @@ -7,29 +7,29 @@ import { ExtendedUseQueryResult } from "@/util/types/ExtendedUseQueryResult"; * Returns a collection entry for the current user based on a game ID. * The collection entry will be undefined if the user doesn't have the game in their library. * @param gameId + * @param enabled */ export function useOwnCollectionEntryForGameId( gameId: number | undefined, + enabled = true, ): ExtendedUseQueryResult { const queryClient = useQueryClient(); const queryKey = ["collection-entries", "own", gameId]; - const invalidate = () => - queryClient.invalidateQueries({ queryKey: queryKey.slice(0, 2) }); + const invalidate = () => queryClient.invalidateQueries({ queryKey: queryKey.slice(0, 2) }); return { ...useQuery({ queryKey, queryFn: async () => { if (!gameId) return null; try { - const collectionEntry = - await getOwnCollectionEntryByGameId(gameId); + const collectionEntry = await getOwnCollectionEntryByGameId(gameId); if (!collectionEntry) return null; return collectionEntry; } catch (e) { return null; } }, - enabled: gameId != undefined, + enabled: enabled && gameId != undefined, }), queryKey, invalidate, diff --git a/src/components/follow/input/UserFollowGroup.tsx b/src/components/follow/input/UserAvatarWithFollowActions.tsx similarity index 65% rename from src/components/follow/input/UserFollowGroup.tsx rename to src/components/follow/input/UserAvatarWithFollowActions.tsx index 23dee05..66ae1d2 100644 --- a/src/components/follow/input/UserFollowGroup.tsx +++ b/src/components/follow/input/UserAvatarWithFollowActions.tsx @@ -1,14 +1,13 @@ import React from "react"; import { Group, GroupProps } from "@mantine/core"; import { UserAvatarGroup } from "@/components/general/avatar/UserAvatarGroup"; -import ProfileFollowActions from "@/components/profile/view/ProfileFollowActions"; import UserFollowActions from "@/components/follow/input/UserFollowActions"; interface Props extends GroupProps { userId: string; } -const UserFollowGroup = ({ userId, ...groupProps }: Props) => { +const UserAvatarWithFollowActions = ({ userId, ...groupProps }: Props) => { return ( { wrap: "nowrap", }} /> - + ); }; -export default UserFollowGroup; +export default UserAvatarWithFollowActions; diff --git a/src/components/follow/input/UserFollowActions.tsx b/src/components/follow/input/UserFollowActions.tsx index 36f8f25..95e903e 100644 --- a/src/components/follow/input/UserFollowActions.tsx +++ b/src/components/follow/input/UserFollowActions.tsx @@ -7,16 +7,14 @@ import { useInfiniteFollowInfo } from "@/components/follow/hooks/useInfiniteFoll import criteria = FollowInfoRequestDto.criteria; import { ActionIcon, Button, Group, Tooltip } from "@mantine/core"; import { IconX } from "@tabler/icons-react"; +import { redirectToAuth } from "supertokens-auth-react"; interface Props { targetUserId: string; withUnfollowButton?: boolean; } -const UserFollowActions = ({ - targetUserId, - withUnfollowButton = true, -}: Props) => { +const UserFollowActions = ({ targetUserId, withUnfollowButton = true }: Props) => { const ownUserId = useUserId(); /* Checks if current logged-in user is following target user @@ -24,8 +22,7 @@ const UserFollowActions = ({ const ownToTargetFollowStatus = useFollowStatus(ownUserId, targetUserId); const isFollowing = ownToTargetFollowStatus.data?.isFollowing ?? false; - const shouldShowFollowButton = - ownUserId != undefined && ownUserId !== targetUserId; + const shouldEnableFollowButton = ownUserId != undefined && ownUserId !== targetUserId && !isFollowing; const followMutation = useMutation({ mutationFn: async (action: "register" | "remove") => { @@ -53,9 +50,13 @@ const UserFollowActions = ({ return ( + )} + ); }; diff --git a/src/components/general/avatar/UserAvatarWithLevelInfo.tsx b/src/components/general/avatar/UserAvatarWithLevelInfo.tsx index 6abf352..e2bc8fe 100644 --- a/src/components/general/avatar/UserAvatarWithLevelInfo.tsx +++ b/src/components/general/avatar/UserAvatarWithLevelInfo.tsx @@ -17,9 +17,6 @@ interface Props { } const UserAvatarWithLevelInfo = ({ userId, showJoinDate = true, enableLink = true, avatarProps }: Props) => { - const { - routeInfo: { pathname }, - } = useIonRouter(); const profileQuery = useUserProfile(userId); return ( diff --git a/src/components/preferences/PreferencesModal.tsx b/src/components/preferences/PreferencesModal.tsx new file mode 100644 index 0000000..20ed210 --- /dev/null +++ b/src/components/preferences/PreferencesModal.tsx @@ -0,0 +1,33 @@ +import React from "react"; +import useUserId from "../auth/hooks/useUserId"; +import { IonButton, IonButtons, IonContent, IonHeader, IonModal, IonTitle, IonToolbar } from "@ionic/react"; +import { SessionAuth } from "supertokens-auth-react/recipe/session"; +import { BaseModalProps } from "@/util/types/modal-props"; +import PreferencesScreen from "./view/PreferencesScreen"; +import { Container } from "@mantine/core"; +import CenteredErrorMessage from "@/components/general/CenteredErrorMessage"; + +const PreferencesModal = ({ opened, onClose }: BaseModalProps) => { + const userId = useUserId(); + return ( + + + + + Preferences + + onClose()}>Go back + + + + + + + + + + + ); +}; + +export default PreferencesModal; diff --git a/src/components/preferences/view/PreferencesScreen.tsx b/src/components/preferences/view/PreferencesScreen.tsx new file mode 100644 index 0000000..c382d00 --- /dev/null +++ b/src/components/preferences/view/PreferencesScreen.tsx @@ -0,0 +1,19 @@ +import { IonItem, IonItemDivider, IonItemGroup, IonLabel, IonList } from "@ionic/react"; +import React from "react"; + +const PreferencesScreen = () => { + return ( + <> + + + Connections + + + + Steam + + + ); +}; + +export default PreferencesScreen; diff --git a/src/components/profile/view/ProfileNavbarFollowInfo.tsx b/src/components/profile/view/ProfileNavbarFollowInfo.tsx index 339ef1d..a7a5fa0 100644 --- a/src/components/profile/view/ProfileNavbarFollowInfo.tsx +++ b/src/components/profile/view/ProfileNavbarFollowInfo.tsx @@ -16,8 +16,7 @@ const ProfileNavbarFollowInfo = ({ targetUserId, criteria }: Props) => { criteria, targetUserId, }); - const totalItems = - followInfoQuery.data?.pages[0]?.pagination.totalItems || 0; + const totalItems = followInfoQuery.data?.pages[0]?.pagination.totalItems || 0; return ( <> @@ -29,7 +28,7 @@ const ProfileNavbarFollowInfo = ({ targetUserId, criteria }: Props) => { /> { evt.preventDefault(); modalUtils.open(); diff --git a/src/components/profile/view/ProfileReviewListView.tsx b/src/components/profile/view/ProfileReviewListView.tsx index c545884..e592587 100644 --- a/src/components/profile/view/ProfileReviewListView.tsx +++ b/src/components/profile/view/ProfileReviewListView.tsx @@ -1,24 +1,14 @@ import React, { useEffect, useMemo, useRef, useState } from "react"; import useOnMobile from "@/components/general/hooks/useOnMobile"; -import { useRouter } from "next/router"; import useUserId from "@/components/auth/hooks/useUserId"; -import { - FindStatisticsTrendingGamesDto, - FindStatisticsTrendingReviewsDto, -} from "@/wrapper/server"; -import { useTrendingReviews } from "@/components/statistics/hooks/useTrendingReviews"; -import { useReviews } from "@/components/review/hooks/useReviews"; import ReviewListItem from "@/components/review/view/ReviewListItem"; -import { Group, Pagination, Stack, Tabs, Text } from "@mantine/core"; +import { Stack, Text } from "@mantine/core"; import CenteredLoading from "@/components/general/CenteredLoading"; import CenteredErrorMessage from "@/components/general/CenteredErrorMessage"; -import { DEFAULT_GAME_REVIEW_LIST_VIEW_DTO } from "@/components/game/info/review/GameInfoReviewList"; import { ParsedUrlQuery } from "querystring"; import { TBasePaginationRequest } from "@/util/types/pagination"; -import period = FindStatisticsTrendingGamesDto.period; -import { DetailsBox } from "@/components/general/DetailsBox"; -import GameView from "@/components/game/view/GameView"; import useReviewsForUserId from "@/components/review/hooks/useReviewsForUserId"; +import GameViewPagination from "@/components/game/view/GameViewPagination"; const DEFAULT_LIMIT = 7; @@ -40,10 +30,7 @@ const queryDtoToSearchParams = (dto: TBasePaginationRequest) => { const searchParams = new URLSearchParams(); const limitToUse = dto.limit || DEFAULT_LIMIT; if (dto.offset) { - const offsetAsPage = - dto.offset > limitToUse - ? Math.ceil((dto.offset + 1) / limitToUse) - : 1; + const offsetAsPage = dto.offset > limitToUse ? Math.ceil((dto.offset + 1) / limitToUse) : 1; searchParams.set("page", `${offsetAsPage}`); } return searchParams; @@ -54,78 +41,34 @@ interface IUserViewListView { } const ProfileReviewListView = ({ userId }: IUserViewListView) => { - const onMobile = useOnMobile(); - const router = useRouter(); const ownUserId = useUserId(); - const hasSetInitialQueryParams = useRef(false); - - const [page, setPage] = useState(1); - const [offset, setOffset] = useState(0); const reviewsQuery = useReviewsForUserId(userId, offset, DEFAULT_LIMIT); - const isEmpty = - reviewsQuery.data == undefined || reviewsQuery.data.data.length === 0; + const isEmpty = reviewsQuery.data == undefined || reviewsQuery.data.data.length === 0; const isLoading = reviewsQuery.isLoading; const isError = reviewsQuery.isError; const handlePagination = (page: number) => { const offset = (page - 1) * DEFAULT_LIMIT; - const searchParams = queryDtoToSearchParams({ - offset, - limit: DEFAULT_LIMIT, - }); - router.replace( - { - query: searchParams.toString(), - }, - undefined, - { - shallow: true, - }, - ); - setPage(page); + setOffset(offset); }; const items = useMemo(() => { return reviewsQuery.data?.data.map((review) => { - return ( - - ); + return ; }); }, [reviewsQuery.data]); - /** - * URL to pagination sync effect - */ - useEffect(() => { - if (hasSetInitialQueryParams.current) { - return; - } - - const dto = urlQueryToDto(router.query); - if (dto.offset) { - setOffset(dto.offset); - } - - hasSetInitialQueryParams.current = true; - }, [router.query]); + const offsetAsPage = offset >= DEFAULT_LIMIT ? Math.ceil(offset + 1 / DEFAULT_LIMIT) : 1; if (isLoading) { return ; } else if (isError) { - return ( - - ); + return ; } else if (isEmpty) { if (userId != undefined && userId === ownUserId) { - return ( - - You have no reviews. Make your first one 😉 - - ); + return You have no reviews. Make your first one 😉; } return User has no reviews.; } @@ -135,8 +78,8 @@ const ProfileReviewListView = ({ userId }: IUserViewListView) => { {items}
{!isEmpty && ( - diff --git a/src/components/profile/view/ProfileUserInfoWithBanner.tsx b/src/components/profile/view/ProfileUserInfoWithBanner.tsx index 9f8357d..f303278 100644 --- a/src/components/profile/view/ProfileUserInfoWithBanner.tsx +++ b/src/components/profile/view/ProfileUserInfoWithBanner.tsx @@ -5,6 +5,7 @@ import { AspectRatio, Box, Button, + Container, Divider, Group, Modal, @@ -23,6 +24,16 @@ import { IconEdit } from "@tabler/icons-react"; import { useDisclosure } from "@mantine/hooks"; import ProfileEditForm from "@/components/profile/edit/ProfileEditForm"; import useOnMobile from "@/components/general/hooks/useOnMobile"; +import { + IonBackButton, + IonButton, + IonButtons, + IonContent, + IonHeader, + IonModal, + IonTitle, + IonToolbar, +} from "@ionic/react"; interface ProfileUserInfoWithBannerProps extends PropsWithChildren { userId: string; @@ -40,10 +51,7 @@ interface ProfileUserInfoWithBannerProps extends PropsWithChildren { * and BELOW it for mobile. */ -const ProfileUserInfoWithBanner = ({ - userId, - children, -}: ProfileUserInfoWithBannerProps) => { +const ProfileUserInfoWithBanner = ({ userId, children }: ProfileUserInfoWithBannerProps) => { const onMobile = useOnMobile(); const ownUserId = useUserId(); const profileQuery = useUserProfile(userId); @@ -52,57 +60,43 @@ const ProfileUserInfoWithBanner = ({ return ( - - - + + + + Edit profile + + Cancel + + + + + + + + + - - + + - - {profileQuery.data?.username} - + {profileQuery.data?.username} - + - - {children} - + {children} ); diff --git a/src/components/profile/view/ProfileViewNavbar.tsx b/src/components/profile/view/ProfileViewNavbar.tsx index 9cc2ef1..b52c1cf 100644 --- a/src/components/profile/view/ProfileViewNavbar.tsx +++ b/src/components/profile/view/ProfileViewNavbar.tsx @@ -52,11 +52,6 @@ const ProfileViewNavbar = ({ userId, ...groupProps }: Props) => { /> - ); }; diff --git a/src/pages/achievements.tsx b/src/pages/achievements.tsx new file mode 100644 index 0000000..2698758 --- /dev/null +++ b/src/pages/achievements.tsx @@ -0,0 +1,43 @@ +import React from "react"; + +import AchievementsScreen from "@/components/achievement/AchievementsScreen"; +import useUserId from "@/components/auth/hooks/useUserId"; +import { + IonBackButton, + IonButtons, + IonContent, + IonHeader, + IonPage, + IonTitle, + IonToolbar, + useIonRouter, +} from "@ionic/react"; +import { Center } from "@mantine/core"; +import useUserProfile from "@/components/profile/hooks/useUserProfile"; +import { SessionAuth } from "supertokens-auth-react/recipe/session"; + +interface Props { + userId: string; +} +export const AchievementsPage = ({ userId }: Props) => { + const profileQuery = useUserProfile(userId); + return ( + + + + + + + + {profileQuery.data && {profileQuery.data.username}'s achievements} + + + +
+ +
+
+
+
+ ); +}; diff --git a/src/pages/auth.tsx b/src/pages/auth.tsx new file mode 100644 index 0000000..72334c7 --- /dev/null +++ b/src/pages/auth.tsx @@ -0,0 +1,28 @@ +import React from "react"; +import { ThirdPartyPreBuiltUI } from "supertokens-auth-react/recipe/thirdparty/prebuiltui"; +import { PasswordlessPreBuiltUI } from "supertokens-auth-react/recipe/passwordless/prebuiltui"; +import { AuthPage } from "supertokens-auth-react/ui"; +import { IonBackButton, IonButtons, IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from "@ionic/react"; +import { Box, Center, Container } from "@mantine/core"; + +const SupertokensAuthPage = () => { + return ( + + + + + + + Sign up / in + + + + + + + + + ); +}; + +export default SupertokensAuthPage; diff --git a/src/pages/home.tsx b/src/pages/home.tsx index 57c9d70..14df25b 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -5,8 +5,6 @@ import { Container, Stack, Text } from "@mantine/core"; import TrendingReviewCarousel from "@/components/review/trending/TrendingReviewCarousel"; import { DetailsBox } from "@/components/general/DetailsBox"; import RecentActivityList from "@/components/activity/RecentActivityList"; -import { useQuery } from "@tanstack/react-query"; -import { RecommendationService } from "@/wrapper/server"; import RecommendationCarousel from "@/components/recommendation/carousel/RecommendationCarousel"; import useUserId from "@/components/auth/hooks/useUserId"; @@ -21,7 +19,7 @@ const HomePage = () => { - + {userId && ( { )} - - - {userId && ( <> { /> )} + + + + diff --git a/src/pages/library.tsx b/src/pages/library.tsx index afac61c..0b7589a 100644 --- a/src/pages/library.tsx +++ b/src/pages/library.tsx @@ -18,8 +18,9 @@ import { useIonRouter, } from "@ionic/react"; import { Container } from "@mantine/core"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { SessionAuth } from "supertokens-auth-react/recipe/session"; +import { useSearchParameters } from "@/components/general/hooks/useSearchParameters"; interface Props { userId?: string; @@ -34,11 +35,20 @@ const LibraryPage = ({ userId }: Props) => { routeInfo: { pathname }, } = useIonRouter(); + const params = useSearchParameters(); + const isInTab = pathname.split("/").length === 2; const profileQuery = useUserProfile(userIdToUse); const [selectedCollectionId, setSelectedCollectionId] = useState(undefined); + useEffect(() => { + const paramsCollectionId = params.get("collectionId"); + if (paramsCollectionId) { + setSelectedCollectionId(paramsCollectionId); + } + }, []); + return ( diff --git a/src/pages/profile.tsx b/src/pages/profile/profile.tsx similarity index 95% rename from src/pages/profile.tsx rename to src/pages/profile/profile.tsx index 0234127..4c35610 100644 --- a/src/pages/profile.tsx +++ b/src/pages/profile/profile.tsx @@ -62,8 +62,7 @@ const ProfilePage = ({ userId }: Props) => { {userIdToUse && ( - - + diff --git a/src/pages/profile/review_list.tsx b/src/pages/profile/review_list.tsx new file mode 100644 index 0000000..b823928 --- /dev/null +++ b/src/pages/profile/review_list.tsx @@ -0,0 +1,34 @@ +import useUserProfile from "@/components/profile/hooks/useUserProfile"; +import { IonBackButton, IonButtons, IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from "@ionic/react"; +import React from "react"; +import CenteredLoading from "@/components/general/CenteredLoading"; +import { Container } from "@mantine/core"; +import ProfileReviewListView from "@/components/profile/view/ProfileReviewListView"; + +interface Props { + userId: string; +} + +const ProfileReviewListPage = ({ userId }: Props) => { + const profileQuery = useUserProfile(userId); + return ( + + + + + + + {profileQuery.data && {profileQuery.data.username}'s reviews} + + + + {profileQuery.isLoading && } + + + + + + ); +}; + +export default ProfileReviewListPage; diff --git a/src/pages/routes/getCommonRoutes.tsx b/src/pages/routes/getCommonRoutes.tsx index 3bc09a8..4aa7148 100644 --- a/src/pages/routes/getCommonRoutes.tsx +++ b/src/pages/routes/getCommonRoutes.tsx @@ -1,9 +1,12 @@ import React from "react"; import { Route } from "react-router"; import GamePage from "../game"; -import ProfilePage from "../profile"; +import ProfilePage from "../profile/profile"; import ProfileStatsPage from "../profile_stats"; import LibraryPage from "../library"; +import { AchievementsPage } from "@/pages/achievements"; +import ProfileReviewListPage from "@/pages/profile/review_list"; +import SupertokensAuthPage from "../auth"; /** * Retrieves a list of common routes that should be available in all tabs. @@ -44,6 +47,24 @@ export function getCommonRoutes(prefix: string): React.ReactNode[] { return ; }} />, + { + const userId = props.match.params.userId; + + return ; + }} + />, + { + const userId = props.match.params.userId; + return ; + }} + />, + ; }} />, + + + , ]; } diff --git a/src/util/getTabAwareHref.ts b/src/util/getTabAwareHref.ts index cc3184e..806d61b 100644 --- a/src/util/getTabAwareHref.ts +++ b/src/util/getTabAwareHref.ts @@ -1,6 +1,5 @@ /** * Retrieves a route with the current tab prefix appended to it. - * @param currentPathname * @param targetUrl */ export function getTabAwareHref(targetUrl: string): string {