Protect routes that need authentication

This commit is contained in:
Pijus Kamandulis 2024-10-09 21:24:51 +03:00
parent 253d13abd4
commit c05febd1f5
4 changed files with 67 additions and 14 deletions

View File

@ -8,8 +8,9 @@ import {
} from 'react';
import { account } from '../appwrite';
interface UserContextType {
export interface UserContextType {
current: Models.Session | Models.User<Models.Preferences> | null;
isLoading: boolean;
login: (email: string, password: string) => Promise<void>;
logout: () => Promise<void>;
register: (email: string, password: string) => Promise<void>;
@ -30,11 +31,15 @@ export const UserProvider = (props: PropsWithChildren) => {
const [user, setUser] = useState<
Models.Session | Models.User<Models.Preferences> | null
>(null);
const [isLoading, setIsLoading] = useState(true);
const login = async (email: string, password: string) => {
const loggedIn = await account.createEmailPasswordSession(email, password);
setUser(loggedIn);
window.location.replace('/'); // you can use different redirect method for your application
const params = new URLSearchParams(window.location.search);
const redirectPath = params.get('redirect');
window.location.replace(redirectPath || '/');
};
const logout = async () => {
@ -50,7 +55,10 @@ export const UserProvider = (props: PropsWithChildren) => {
const loginAsGuest = async () => {
const session = await account.createAnonymousSession();
setUser(session);
window.location.replace('/'); // you can use different redirect method for your application
const params = new URLSearchParams(window.location.search);
const redirectPath = params.get('redirect');
window.location.replace(redirectPath || '/');
};
const init = async () => {
@ -59,6 +67,8 @@ export const UserProvider = (props: PropsWithChildren) => {
setUser(loggedIn);
} catch (err) {
setUser(null);
} finally {
setIsLoading(false);
}
};
@ -68,7 +78,14 @@ export const UserProvider = (props: PropsWithChildren) => {
return (
<UserContext.Provider
value={{ current: user, login, logout, register, loginAsGuest }}
value={{
current: user,
isLoading,
login,
logout,
register,
loginAsGuest,
}}
>
{props.children}
</UserContext.Provider>

View File

@ -2,24 +2,48 @@ import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import {
createRootRoute,
createRootRouteWithContext,
createRoute,
createRouter,
Outlet,
redirect,
RouterProvider,
} from '@tanstack/react-router';
import Home from './pages/Home';
import { UserProvider } from './lib/context/user';
import { UserContextType, UserProvider, useUser } from './lib/context/user';
import Login from './pages/Login';
import { EstimationSessionProvider } from './lib/context/estimationSession';
import { EstimationContextProvider } from './lib/context/estimation';
import Estimation from './pages/Estimation/Estimation';
const rootRoute = createRootRoute();
interface RouterContext {
userContext: UserContextType;
}
const rootRoute = createRootRouteWithContext<RouterContext>()({
component: () => <Outlet />,
});
const authenticatedRoute = createRoute({
id: '_authenticated',
getParentRoute: () => rootRoute,
beforeLoad: async ({ location, context }) => {
console.log(context);
if (!context.userContext.current) {
throw redirect({
to: '/login',
search: {
redirect: location.href,
},
});
}
},
});
const indexRoute = createRoute({
path: '/',
component: Home,
getParentRoute: () => rootRoute,
getParentRoute: () => authenticatedRoute,
});
const loginRoute = createRoute({
@ -31,15 +55,17 @@ const loginRoute = createRoute({
const estimationSessionRoute = createRoute({
path: 'estimate/session/$sessionId',
component: Estimation,
getParentRoute: () => rootRoute,
getParentRoute: () => authenticatedRoute,
});
const router = createRouter({
routeTree: rootRoute.addChildren([
indexRoute,
authenticatedRoute.addChildren([indexRoute, estimationSessionRoute]),
loginRoute,
estimationSessionRoute,
]),
context: {
userContext: undefined!,
},
});
declare module '@tanstack/react-router' {
@ -48,13 +74,23 @@ declare module '@tanstack/react-router' {
}
}
const InnerApp = () => {
const userContext = useUser();
return userContext.isLoading ? (
<p>Loading...</p>
) : (
<RouterProvider router={router} context={{ userContext }} />
);
};
createRoot(document.getElementById('root')!).render(
<StrictMode>
<UserProvider>
<EstimationSessionProvider>
<EstimationContextProvider>
{/* TODO: Move ctx providers to layout */}
<RouterProvider router={router} />
<InnerApp />
</EstimationContextProvider>
</EstimationSessionProvider>
</UserProvider>

View File

@ -9,7 +9,7 @@ import CreateTicketForm from './components/CreateTicketForm';
const fibonacciSequence = [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 100];
const route = getRouteApi('/estimate/session/$sessionId');
const route = getRouteApi('/_authenticated/estimate/session/$sessionId');
const Estimation: React.FC = () => {
const { sessionId } = route.useParams();

View File

@ -12,7 +12,7 @@ import {
} from '../components';
import { useState } from 'react';
const route = getRouteApi('/');
const route = getRouteApi('/_authenticated/');
function Home() {
const user = useUser();