Skip to content

Commit

Permalink
fix: User Provider & RouteGuard
Browse files Browse the repository at this point in the history
  • Loading branch information
Muhammed Rameez authored and Muhammed Rameez committed Dec 27, 2023
1 parent 4dc1236 commit de47010
Show file tree
Hide file tree
Showing 16 changed files with 180 additions and 26 deletions.
33 changes: 18 additions & 15 deletions audire/audire-mobile-app/src/app/(auth)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import { Box } from '@gluestack-ui/themed';
import { Slot } from 'expo-router';
import { Slot, router } from 'expo-router';
import Topbar from '../../modules/common/Topbar';
import Sidebar from '../../modules/common/Sidebar';
import { useState } from 'react';
import { UserProvider } from '@learning-app/auth';

const MainLayout = () => {
const [sidebarShown, setSidebarShown] = useState(false);
console.log(sidebarShown);
return (
<Box
display="flex"
flexDirection="column"
h="$full"
justifyContent="flex-start"
alignItems="center"
>
<Topbar onToggleSidebar={() => setSidebarShown((prev) => !prev)} />
<Slot />
<Sidebar
isShown={sidebarShown}
onToggleSidebar={() => setSidebarShown((prev) => !prev)}
/>
</Box>
<UserProvider onUnauthorized={() => router.replace('/login')}>
<Box
display="flex"
flexDirection="column"
h="$full"
justifyContent="flex-start"
alignItems="center"
>
<Topbar onToggleSidebar={() => setSidebarShown((prev) => !prev)} />
<Slot />
<Sidebar
isShown={sidebarShown}
onToggleSidebar={() => setSidebarShown((prev) => !prev)}
/>
</Box>
</UserProvider>
);
};

Expand Down
5 changes: 3 additions & 2 deletions audire/audire-mobile-app/src/modules/home/HomeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ import StageCard from './stage-card/StageCard';
import { Box, Text, Image, View } from '@gluestack-ui/themed';
import { useCourses } from '@learning-app/syllabus';
import { Asset } from 'expo-asset';
import { useActiveUser } from '@learning-app/auth';

const HomeView = () => {
const TEMP_COURSE = 'CA';
const { data: { data: courses } = { data: [] } } = useCourses();
const image = Asset.fromURI('/assets/homepageBanner.jpg').uri;
const colors = ['#D6A8D4', '#94B6BB', '#FBB6B1', '#FF33D1', '#33D1FF'];

const { user } = useActiveUser();
return (
<Box flex={1} width="$full">
<Text fontSize="$xl" color="black" fontWeight="$bold" ml="$5" py="$5">
Hey Jane!
Hello {user.firstName}!
</Text>
<Box bg="white" p="$1.5">
<Image
Expand Down
20 changes: 12 additions & 8 deletions audire/audire-mobile-app/src/modules/login/VerificationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,23 @@ const VerificationView: FC<VerificationFormProps> = ({
const handleTrigger = async () => {
try {
const otpString = otpValues.join('');
const r = await trigger({
if (otpString.length < 6) {
return;
}

await trigger({
mobile: mobile,
otp: otpString,
fullName: fullName,
});

if (isNewUser === true) {
router.replace('/profile/course');
} else {
router.replace('/');
}
} catch (e) {
alert('Wrong OTP');
console.error('Error triggering mobile OTP:', e);
}
};
Expand All @@ -49,7 +60,6 @@ const VerificationView: FC<VerificationFormProps> = ({
prev[index] = isNaN(parseInt(value)) ? '' : value;
return [...prev];
});
console.log(`Value at index ${index}: ${otpValues[index]}`);
};

const renderOtpInputBoxes = () => {
Expand All @@ -76,7 +86,6 @@ const VerificationView: FC<VerificationFormProps> = ({
));
};

console.info({ otpValues });
return (
<Box display="flex" flex={1} justifyContent="center" w="$full" px="$4">
<Box display="flex" mb="$6">
Expand Down Expand Up @@ -119,11 +128,6 @@ const VerificationView: FC<VerificationFormProps> = ({
bg="$fuchsia800"
onPress={() => {
handleTrigger();
if (isNewUser === true) {
router.replace('/profile/course');
} else {
router.replace('/');
}
}}
>
<ButtonText fontSize="$md" fontWeight="bold">
Expand Down
1 change: 1 addition & 0 deletions libs/auth/src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './swr';
export * from './providers';
1 change: 1 addition & 0 deletions libs/auth/src/providers/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './user';
79 changes: 79 additions & 0 deletions libs/auth/src/providers/user.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import {
createContext,
ReactNode,
useContext,
useEffect,
useState,
} from 'react';

import { useSupabaseClient } from '@supabase/auth-helpers-react';
import { useProfile } from '../swr';
import { ProfileExtended } from '../types';

type UserContextValue = {
user: ProfileExtended;
};

type UserProviderProps = {
onUnauthorized?: () => void;
children: ReactNode;
loading?: ReactNode;
};

const UserContext = createContext<UserContextValue | undefined>(undefined);

UserContext.displayName = 'UserContext';

export const UserProvider = ({ children, ...props }: UserProviderProps) => {
const [profileId, setProfileId] = useState<string | null>(null);
const supabase = useSupabaseClient();
const { data: user } = useProfile({ id: profileId });

/** Get profileId from session */
useEffect(() => {
const {
data: { subscription },
} = supabase.auth.onAuthStateChange((event, session) => {
if (!session) {
setProfileId(null);
props.onUnauthorized?.();
} else {
setProfileId(session.user?.id);
}
});

return () => {
subscription?.unsubscribe();
};
}, [supabase]);

if (!user) {
return props.loading ?? null;
}

return (
<UserContext.Provider
value={{
user: user ?? null,
}}
>
{children}
</UserContext.Provider>
);
};

export const useActiveUser = () => {
const context = useContext(UserContext);

if (context === undefined) {
throw new Error('useActiveUser was used outside of its Provider');
}

return context;
};

// export const useUserRole = () => {
// const { user } = useActiveUser();

// return user?.profile?.role ?? null;
// };
6 changes: 6 additions & 0 deletions libs/auth/src/services/mobile-verify-otp/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,11 @@ export async function mobileVerifyOTP(
throw new Error(data?.message ?? error?.message ?? 'Unknown error');
}

const { data: setSession, error: sessionErr } =
await supabase.auth.setSession(data.session);
if (sessionErr || !setSession) {
throw new Error(sessionErr?.message ?? 'Unknown error');
}

return data;
}
2 changes: 2 additions & 0 deletions libs/auth/src/services/profile/get/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './service';
export * from './types';
19 changes: 19 additions & 0 deletions libs/auth/src/services/profile/get/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { LearningAppSupabase } from '@learning-app/supabase';
import { ProfileGetRequest, ProfileGetResponse } from './types';

export async function getProfile(
supabase: LearningAppSupabase,
params: ProfileGetRequest
): Promise<ProfileGetResponse> {
const { data, error } = await supabase
.from('Profile')
.select('*')
.match({ id: params.id })
.single();

if (error) {
throw error;
}

return data;
}
6 changes: 6 additions & 0 deletions libs/auth/src/services/profile/get/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ProfileExtended } from '../../../types';
export type ProfileGetRequest = {
id: string | null;
};

export type ProfileGetResponse = ProfileExtended;
1 change: 1 addition & 0 deletions libs/auth/src/swr/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './mobile-send-otp';
export * from './mobile-verify-otp';
export * from './login-with-email';
export * from './logout';
export * from './profile/get';
2 changes: 2 additions & 0 deletions libs/auth/src/swr/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ export enum AuthSWRKeys {
VALIDATE_SIGNUP_DETAILS = 'validateSignupDetails',
RESET_PASSWORD_FOR_EMAIL = 'resetPasswordForEmail',
UPDATE_USER_PASSWORD = 'updateUserPassword',
GET = 'get',
PROFILE = 'profile',
}
20 changes: 20 additions & 0 deletions libs/auth/src/swr/profile/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { PostgrestError } from '@supabase/supabase-js';
import { useSupabaseClient } from '@supabase/auth-helpers-react';

import useSWR from 'swr';
import { AuthSWRKeys } from '../keys';
import {
ProfileGetRequest,
ProfileGetResponse,
getProfile,
} from '../../services/profile/get';

export function useProfile(params: ProfileGetRequest) {
const supabase = useSupabaseClient();
const key = params.id
? [AuthSWRKeys.PROFILE, AuthSWRKeys.GET, params.id]
: null;
return useSWR<ProfileGetResponse, PostgrestError, string[] | null>(key, () =>
getProfile(supabase, params)
);
}
1 change: 1 addition & 0 deletions libs/auth/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useProfile';
8 changes: 8 additions & 0 deletions libs/auth/src/types/useProfile/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Database } from '@learning-app/supabase';

export type Profile = Database['public']['Tables']['Profile']['Row'];

export type ProfileExtended = Pick<
Profile,
'id' | 'firstName' | 'lastName' | 'mobile'
>;
2 changes: 1 addition & 1 deletion libs/auth/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"jsx": "react-jsx",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
Expand Down

0 comments on commit de47010

Please sign in to comment.