Skip to content

Commit

Permalink
Login integration
Browse files Browse the repository at this point in the history
  • Loading branch information
barshathakuri committed Nov 20, 2024
1 parent 8785c25 commit 9e746ff
Show file tree
Hide file tree
Showing 15 changed files with 384 additions and 57 deletions.
2 changes: 1 addition & 1 deletion backend
Submodule backend updated 103 files
45 changes: 45 additions & 0 deletions src/App/Auth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
Fragment,
type ReactElement,
} from 'react';
import { Navigate } from 'react-router-dom';

import useAuth from '#hooks/domain/useAuth';

import { type ExtendedProps } from './routes/common';

interface Props {
children: ReactElement,
context: ExtendedProps,
absolutePath: string,
}
function Auth(props: Props) {
const {
context,
children,
absolutePath,
} = props;

const { isAuthenticated } = useAuth();

if (context.visibility === 'is-authenticated' && !isAuthenticated) {
return (
<Navigate to="/login" />
);
}
if (context.visibility === 'is-not-authenticated' && isAuthenticated) {
return (
<Navigate to="/" />
);
}

return (
<Fragment
key={absolutePath}
>
{children}
</Fragment>
);
}

export default Auth;
64 changes: 58 additions & 6 deletions src/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,17 @@ import mapboxgl from 'mapbox-gl';

import { mapboxToken } from '#config';
import RouteContext from '#contexts/route';
import { KEY_LANGUAGE_STORAGE } from '#utils/constants';
import UserContext, {
UserAuth,
UserContextProps,
} from '#contexts/user';
import {
KEY_LANGUAGE_STORAGE,
KEY_USER_STORAGE,
} from '#utils/constants';
import {
getFromStorage,
removeFromStorage,
setToStorage,
} from '#utils/localStorage';

Expand Down Expand Up @@ -73,6 +81,48 @@ function App() {
[],
);

// AUTH

const [userAuth, setUserAuth] = useState<UserAuth>();

const hydrateUserAuth = useCallback(() => {
const userDetailsFromStorage = getFromStorage<UserAuth>(KEY_USER_STORAGE);
if (userDetailsFromStorage) {
setUserAuth(userDetailsFromStorage);
}
}, []);

const removeUserAuth = useCallback(() => {
removeFromStorage(KEY_USER_STORAGE);
setUserAuth(undefined);
}, []);

const setAndStoreUserAuth = useCallback((newUserDetails: UserAuth) => {
setUserAuth(newUserDetails);
setToStorage(
KEY_USER_STORAGE,
newUserDetails,
);
}, []);

// Hydration
useEffect(() => {
hydrateUserAuth();

const language = getFromStorage<Language>(KEY_LANGUAGE_STORAGE);
setCurrentLanguage(language ?? 'en');
}, [hydrateUserAuth]);

const userContextValue = useMemo<UserContextProps>(
() => ({
userAuth,
hydrateUserAuth,
setUserAuth: setAndStoreUserAuth,
removeUserAuth,
}),
[userAuth, hydrateUserAuth, setAndStoreUserAuth, removeUserAuth],
);

const registerLanguageNamespace = useCallback(
(namespace: string, fallbackStrings: Record<string, string>) => {
setStrings(
Expand Down Expand Up @@ -187,11 +237,13 @@ function App() {

return (
<RouteContext.Provider value={wrappedRoutes}>
<AlertContext.Provider value={alertContextValue}>
<LanguageContext.Provider value={languageContextValue}>
<RouterProvider router={router} />
</LanguageContext.Provider>
</AlertContext.Provider>
<UserContext.Provider value={userContextValue}>
<AlertContext.Provider value={alertContextValue}>
<LanguageContext.Provider value={languageContextValue}>
<RouterProvider router={router} />
</LanguageContext.Provider>
</AlertContext.Provider>
</UserContext.Provider>
</RouteContext.Provider>
);
}
Expand Down
47 changes: 47 additions & 0 deletions src/App/routes/common.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
type MyInputIndexRouteObject,
type MyInputNonIndexRouteObject,
type MyOutputIndexRouteObject,
type MyOutputNonIndexRouteObject,
wrapRoute,
} from '#utils/routes';
import { Component as RootLayout } from '#views/RootLayout';

import Auth from '../Auth';
import PageError from '../PageError';

export type ExtendedProps = {
title: string,
visibility: 'is-authenticated' | 'is-not-authenticated' | 'anything',
permissions?: (
params: Record<string, number | string | undefined | null> | undefined | null,
) => boolean;
};

interface CustomWrapRoute {
<T>(
myRouteOptions: MyInputIndexRouteObject<T, ExtendedProps>
): MyOutputIndexRouteObject<ExtendedProps>
<T>(
myRouteOptions: MyInputNonIndexRouteObject<T, ExtendedProps>
): MyOutputNonIndexRouteObject<ExtendedProps>
}

export const customWrapRoute: CustomWrapRoute = wrapRoute;

// NOTE: We should not use layout or index routes in links

export const rootLayout = customWrapRoute({
path: '/',
errorElement: <PageError />,
component: {
eagerLoad: true,
render: RootLayout,
props: {},
},
wrapperComponent: Auth,
context: {
title: 'IFRC Alert Hub',
visibility: 'anything',
},
});
40 changes: 21 additions & 19 deletions src/App/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import {
MyOutputIndexRouteObject,
MyOutputNonIndexRouteObject,
unwrapRoute,
wrapRoute,
} from '#utils/routes';
import { Component as RootLayout } from '#views/RootLayout';

import PageError from '../PageError';
import Auth from '../Auth';
import {
customWrapRoute,
rootLayout,
} from './common';

// NOTE: setting default ExtendedProps
export type ExtendedProps = {
Expand All @@ -27,22 +29,6 @@ export interface MyWrapRoute {
): MyOutputNonIndexRouteObject<ExtendedProps>
}

const customWrapRoute: MyWrapRoute = wrapRoute;

const rootLayout = customWrapRoute({
path: '/',
errorElement: <PageError />,
component: {
render: RootLayout,
eagerLoad: true,
props: {},
},
context: {
title: 'IFRC Alert Hub',
visibility: 'anything',
},
});

type DefaultHomeChild = 'map';
const homeLayout = customWrapRoute({
parent: rootLayout,
Expand All @@ -51,6 +37,7 @@ const homeLayout = customWrapRoute({
render: () => import('#views/Home'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'IFRC Alert Hub',
visibility: 'anything',
Expand All @@ -64,6 +51,7 @@ const mySubscription = customWrapRoute({
render: () => import('#views/MySubscription'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'My Subscriptions',
// TODO: Change visibility after login feature
Expand All @@ -82,6 +70,7 @@ const homeIndex = customWrapRoute({
replace: true,
},
},
wrapperComponent: Auth,
context: {
title: 'IFRC Alert Hub',
visibility: 'anything',
Expand All @@ -95,6 +84,7 @@ const homeMap = customWrapRoute({
render: () => import('#views/Home/AlertsMap'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'IFRC Alert Hub - Map',
visibility: 'anything',
Expand All @@ -108,6 +98,7 @@ const homeTable = customWrapRoute({
render: () => import('#views/Home/AlertsTable'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'IFRC Alert Hub - Table',
visibility: 'anything',
Expand All @@ -121,6 +112,7 @@ const preferences = customWrapRoute({
render: () => import('#views/Preferences'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'Preferences',
visibility: 'anything',
Expand All @@ -134,6 +126,7 @@ const historicalAlerts = customWrapRoute({
render: () => import('#views/HistoricalAlerts'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'Historical Alerts',
visibility: 'anything',
Expand All @@ -147,6 +140,7 @@ const about = customWrapRoute({
render: () => import('#views/About'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'About',
visibility: 'anything',
Expand All @@ -160,6 +154,7 @@ const resources = customWrapRoute({
render: () => import('#views/Resources'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'Resources',
visibility: 'anything',
Expand All @@ -173,6 +168,7 @@ const alertDetails = customWrapRoute({
render: () => import('#views/AlertDetails'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'Alert Details',
visibility: 'anything',
Expand All @@ -186,6 +182,7 @@ const allSourcesFeeds = customWrapRoute({
render: () => import('#views/AllSourcesFeeds'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'Sources Feeds',
visibility: 'anything',
Expand All @@ -199,6 +196,7 @@ const pageNotFound = customWrapRoute({
render: () => import('#views/PageNotFound'),
props: {},
},
wrapperComponent: Auth,
context: {
title: '404',
visibility: 'anything',
Expand All @@ -212,6 +210,7 @@ const login = customWrapRoute({
render: () => import('#views/Login'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'Login',
visibility: 'is-not-authenticated',
Expand All @@ -225,6 +224,7 @@ const recoverAccount = customWrapRoute({
render: () => import('#views/RecoverAccount'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'Recover Account',
visibility: 'is-not-authenticated',
Expand All @@ -238,6 +238,7 @@ const resendValidationEmail = customWrapRoute({
render: () => import('#views/ResendValidationEmail'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'Resend Validation Email',
visibility: 'is-not-authenticated',
Expand All @@ -251,6 +252,7 @@ const cookiePolicy = customWrapRoute({
render: () => import('#views/CookiePolicy'),
props: {},
},
wrapperComponent: Auth,
context: {
title: 'Cookie Policy',
visibility: 'anything',
Expand Down
2 changes: 1 addition & 1 deletion src/components/Link/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
} from '@togglecorp/fujs';

import RouteContext from '#contexts/route';
import useAuth from '#hooks/useAuth';
import useAuth from '#hooks/domain/useAuth';

import { type WrappedRoutes } from '../../App/routes';

Expand Down
3 changes: 2 additions & 1 deletion src/components/Navbar/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"appResources": "Resources",
"headerMenuHome": "Home",
"headerMenuMySubscription": "My Subscriptions",
"historicalAlerts": "Historical Alerts"
"historicalAlerts": "Historical Alerts",
"userMenuLogout":"Logout"
}
}
Loading

0 comments on commit 9e746ff

Please sign in to comment.