From a0c18ad5e0a25887ad90aa1a9e6eb99c87bd890d Mon Sep 17 00:00:00 2001 From: Chris Nowicki <102450568+chris-nowicki@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:09:18 -0400 Subject: [PATCH] add helper function for isAuthRoute --- api/apiFunctions.interface.ts | 3 +- api/apiFunctions.ts | 4 +-- app/(main)/league/all/page.test.tsx | 7 ++++ app/(main)/league/all/page.tsx | 11 ++++--- .../UpdateEmailForm/UpdateEmailForm.tsx | 2 +- context/AuthContextProvider.tsx | 32 ++++++++++++------- pnpm-lock.yaml | 4 +-- utils/utils.test.ts | 28 ++++++++++++++++ utils/utils.ts | 10 ++++++ 9 files changed, 79 insertions(+), 22 deletions(-) diff --git a/api/apiFunctions.interface.ts b/api/apiFunctions.interface.ts index 4aafb977..e5d1f6fb 100644 --- a/api/apiFunctions.interface.ts +++ b/api/apiFunctions.interface.ts @@ -16,7 +16,8 @@ export interface IUser { labels: string[]; } -export interface ICollectionuser { +export interface ICollectionUser { + documentId: string; // for the custom user collection id: string; email: string; diff --git a/api/apiFunctions.ts b/api/apiFunctions.ts index a1c3ed92..2f3b072d 100644 --- a/api/apiFunctions.ts +++ b/api/apiFunctions.ts @@ -8,7 +8,7 @@ import { ILeague, IGameWeek, IUser, - ICollectionuser, + ICollectionUser, IWeeklyPicks, INFLTeam, IRecoveryToken, @@ -152,7 +152,7 @@ export async function updateUserEmail({ */ export async function getCurrentUser( userId: IUser['id'], -): Promise { +): Promise { try { const user = await databases.listDocuments( appwriteConfig.databaseId, diff --git a/app/(main)/league/all/page.test.tsx b/app/(main)/league/all/page.test.tsx index b1a783c8..8625ee47 100644 --- a/app/(main)/league/all/page.test.tsx +++ b/app/(main)/league/all/page.test.tsx @@ -32,6 +32,7 @@ jest.mock('@/store/dataStore', () => ({ id: '1234', email: 'test@test.com', leagues: ['league1'], + labels: [], }, allLeagues: [ { @@ -82,6 +83,7 @@ describe('Leagues Component', () => { leagues: [], }, allLeagues: [], + labels: [], }); render(); @@ -105,6 +107,7 @@ describe('Leagues Component', () => { leagues: [], }, allLeagues: [], + labels: [], }); render(); @@ -121,6 +124,7 @@ describe('Leagues Component', () => { email: 'test@test.com', id: '123', leagues: [], + labels: [], }, allLeagues: [ { @@ -150,6 +154,7 @@ describe('Leagues Component', () => { email: 'test@test.com', id: '123', leagues: [], + labels: [], }; const league = { @@ -202,6 +207,7 @@ describe('Leagues Component', () => { user.id, user.email, [...user.leagues, league.leagueId], + user.labels, ); expect(toast.custom).toHaveBeenCalledWith( { email: 'test@test.com', id: '123', leagues: [], + labels: [], }; const league = { diff --git a/app/(main)/league/all/page.tsx b/app/(main)/league/all/page.tsx index 56c04323..8e8a77de 100644 --- a/app/(main)/league/all/page.tsx +++ b/app/(main)/league/all/page.tsx @@ -100,10 +100,13 @@ const Leagues = (): JSX.Element => { }); setLeagues([...leagues, league]); - updateUser(user.documentId, user.id, user.email, [ - ...user.leagues, - league.leagueId, - ]); + updateUser( + user.documentId, + user.id, + user.email, + [...user.leagues, league.leagueId], + user.labels, + ); toast.custom( { />, ); - updateUser(user.documentId, user.id, email, user.leagues); + updateUser(user.documentId, user.id, email, user.leagues, user.labels); form.reset({ email: email || '', password: '' }); } catch (error) { console.error('Email Update Failed', error); diff --git a/context/AuthContextProvider.tsx b/context/AuthContextProvider.tsx index 8d428da6..eb1adb9b 100644 --- a/context/AuthContextProvider.tsx +++ b/context/AuthContextProvider.tsx @@ -8,10 +8,11 @@ import { account } from '@/api/config'; import { useRouter } from 'next/navigation'; import { useDataStore } from '@/store/dataStore'; import type { DataStore } from '@/store/dataStore'; -import { IUser } from '@/api/apiFunctions.interface'; +import { ICollectionUser, IUser } from '@/api/apiFunctions.interface'; import { getCurrentUser } from '@/api/apiFunctions'; import { loginAccount, logoutHandler } from './AuthHelper'; import { usePathname } from 'next/navigation'; +import { isAuthRequiredPath } from '@/utils/utils'; type UserCredentials = { email: string; @@ -85,11 +86,7 @@ export const AuthContextProvider = ({ */ const getUser = async (): Promise => { if (!isSessionInLocalStorage()) { - if ( - pathname !== '/register' && - pathname !== '/account/recovery' && - pathname !== '/recover-password' - ) { + if (isAuthRequiredPath(pathname)) { router.push('/login'); } return; @@ -97,14 +94,25 @@ export const AuthContextProvider = ({ try { const user = await account.get(); - const userData: IUser = await getCurrentUser(user.$id); + const userData: ICollectionUser = await getCurrentUser(user.$id); + + const currentUser: IUser = { + documentId: userData.documentId, + id: userData.id, + email: userData.email, + leagues: userData.leagues, + labels: user.labels, + }; + updateUser( - userData.documentId, - userData.id, - userData.email, - userData.leagues, + currentUser.documentId, + currentUser.id, + currentUser.email, + currentUser.leagues, + user.labels, ); - return userData; + + return currentUser; } catch (error) { resetUser(); setIsSignedIn(false); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 22e5ef82..1549f263 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11428,7 +11428,7 @@ snapshots: debug: 4.3.5 enhanced-resolve: 5.17.0 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.1.3))(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 @@ -11440,7 +11440,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.1.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: diff --git a/utils/utils.test.ts b/utils/utils.test.ts index 408a3b89..1c471924 100644 --- a/utils/utils.test.ts +++ b/utils/utils.test.ts @@ -5,6 +5,7 @@ import { getUserPick, parseUserPick, getUserLeagues, + isAuthRequiredPath, } from './utils'; import { getCurrentLeague, getAllWeeklyPicks } from '@/api/apiFunctions'; @@ -179,6 +180,33 @@ describe('utils', () => { }); }); }); + describe('isAuthRequiredPath', () => { + it('should return false for non-auth paths', () => { + expect(isAuthRequiredPath('/register')).toBe(false); + expect(isAuthRequiredPath('/account/recovery')).toBe(false); + expect(isAuthRequiredPath('/recover-password')).toBe(false); + }); + + it('should return true for auth-required paths', () => { + expect(isAuthRequiredPath('/')).toBe(true); + expect(isAuthRequiredPath('/dashboard')).toBe(true); + expect(isAuthRequiredPath('/profile')).toBe(true); + expect(isAuthRequiredPath('/settings')).toBe(true); + }); + + it('should handle edge cases', () => { + expect(isAuthRequiredPath('')).toBe(true); + expect(isAuthRequiredPath('/register/')).toBe(true); // Trailing slash + expect(isAuthRequiredPath('/REGISTER')).toBe(true); // Case sensitivity + expect(isAuthRequiredPath('/register/subpage')).toBe(true); + }); + + it('should handle unusual inputs', () => { + expect(isAuthRequiredPath(' /register ')).toBe(true); // Spaces + expect(isAuthRequiredPath('/account/recovery?param=value')).toBe(true); // Query parameters + }); + }); + xdescribe('getUserLeagues', () => { it('should return the list of leagues the user is a part of', async () => { (getCurrentLeague as jest.Mock).mockResolvedValue(mockLeague); diff --git a/utils/utils.ts b/utils/utils.ts index 914d7333..ca28a1da 100644 --- a/utils/utils.ts +++ b/utils/utils.ts @@ -176,3 +176,13 @@ export const hasTeamBeenPicked = (teamName: string, selectedTeams: string[]): bo export const getNFLTeamLogo = (NFLTeams: INFLTeam[], teamName: string): string => { return NFLTeams.find((teams) => teams.teamName === teamName)?.teamLogo as string; } + +/** + * Checks if the current path requires authentication + * @param pathname - The current path + * @returns {boolean} - Whether the current path requires authentication + */ +export const isAuthRequiredPath = (pathname: string): boolean => { + const nonAuthPaths = ['/register', '/account/recovery', '/recover-password']; + return !nonAuthPaths.includes(pathname); +};