From 193435466513fa039d303734d44a0d24f3e55f79 Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Thu, 15 Jun 2023 08:45:21 +0200 Subject: [PATCH] Create a context to store authentication --- geneit_app/package-lock.json | 23 ------ geneit_app/package.json | 1 - geneit_app/src/App.tsx | 72 +++++++++++-------- geneit_app/src/api/AuthApi.ts | 3 - geneit_app/src/index.tsx | 2 +- geneit_app/src/routes/auth/LoginRoute.tsx | 10 +-- geneit_app/src/routes/auth/OIDCCbRoute.tsx | 6 +- .../src/widgets/AlertDialogProvider.tsx | 19 ++--- .../src/widgets/BaseAuthenticatedPage.tsx | 6 +- .../src/widgets/ConfirmDialogProvider.tsx | 21 +++--- 10 files changed, 71 insertions(+), 92 deletions(-) diff --git a/geneit_app/package-lock.json b/geneit_app/package-lock.json index 184a50f..8d28712 100644 --- a/geneit_app/package-lock.json +++ b/geneit_app/package-lock.json @@ -23,7 +23,6 @@ "@types/react": "^18.2.8", "@types/react-dom": "^18.2.4", "date-and-time": "^3.0.1", - "jotai": "^2.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.11.2", @@ -11966,22 +11965,6 @@ "jiti": "bin/jiti.js" } }, - "node_modules/jotai": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.1.1.tgz", - "integrity": "sha512-LaaiuSaq+6XkwkrCtCkczyFVZOXe0dfjAFN4DVMsSZSRv/A/4xuLHnlpHMEDqvngjWYBotTIrnQ7OogMkUE6wA==", - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "react": ">=17.0.0" - }, - "peerDependenciesMeta": { - "react": { - "optional": true - } - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -26267,12 +26250,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==" }, - "jotai": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/jotai/-/jotai-2.1.1.tgz", - "integrity": "sha512-LaaiuSaq+6XkwkrCtCkczyFVZOXe0dfjAFN4DVMsSZSRv/A/4xuLHnlpHMEDqvngjWYBotTIrnQ7OogMkUE6wA==", - "requires": {} - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/geneit_app/package.json b/geneit_app/package.json index e3620a9..ae8888a 100644 --- a/geneit_app/package.json +++ b/geneit_app/package.json @@ -18,7 +18,6 @@ "@types/react": "^18.2.8", "@types/react-dom": "^18.2.4", "date-and-time": "^3.0.1", - "jotai": "^2.1.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.11.2", diff --git a/geneit_app/src/App.tsx b/geneit_app/src/App.tsx index 1f1edf6..64ff7b3 100644 --- a/geneit_app/src/App.tsx +++ b/geneit_app/src/App.tsx @@ -1,45 +1,61 @@ +import React from "react"; import { Route, Routes } from "react-router-dom"; import "./App.css"; import { AuthApi } from "./api/AuthApi"; import { NotFoundRoute } from "./routes/NotFound"; -import { BaseLoginPage } from "./widgets/BaseLoginpage"; +import { ProfileRoute } from "./routes/ProfileRoute"; import { LoginRoute } from "./routes/auth/LoginRoute"; +import { NewAccountRoute } from "./routes/auth/NewAccountRoute"; import { OIDCCbRoute } from "./routes/auth/OIDCCbRoute"; -import { useAtom } from "jotai"; -import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage"; import { PasswordForgottenRoute } from "./routes/auth/PasswordForgottenRoute"; import { ResetPasswordRoute } from "./routes/auth/ResetPasswordRoute"; -import { NewAccountRoute } from "./routes/auth/NewAccountRoute"; -import { ProfileRoute } from "./routes/ProfileRoute"; +import { BaseAuthenticatedPage } from "./widgets/BaseAuthenticatedPage"; +import { BaseLoginPage } from "./widgets/BaseLoginpage"; + +interface AuthContext { + signedIn: boolean; + setSignedIn: (signedIn: boolean) => void; +} + +const AuthContextK = React.createContext(null); /** * Core app */ -function App() { - const [signedIn] = useAtom(AuthApi.authStatus); +export function App(): React.ReactElement { + const [signedIn, setSignedIn] = React.useState(AuthApi.SignedIn); + + const context: AuthContext = { + signedIn: signedIn, + setSignedIn: (s) => setSignedIn(s), + }; return ( - - {signedIn ? ( - }> - } /> - } /> - - ) : ( - }> - } /> - } /> - } /> - } - /> - } /> - } /> - - )} - + + + {signedIn ? ( + }> + } /> + } /> + + ) : ( + }> + } /> + } /> + } /> + } + /> + } /> + } /> + + )} + + ); } -export default App; +export function useAuth(): AuthContext { + return React.useContext(AuthContextK)!; +} diff --git a/geneit_app/src/api/AuthApi.ts b/geneit_app/src/api/AuthApi.ts index ce24e40..8d1426c 100644 --- a/geneit_app/src/api/AuthApi.ts +++ b/geneit_app/src/api/AuthApi.ts @@ -1,4 +1,3 @@ -import { atom } from "jotai"; import { APIClient } from "./ApiClient"; export enum CreateAccountResult { @@ -30,8 +29,6 @@ export class AuthApi { return localStorage.getItem(TokenStateKey) !== null; } - static authStatus = atom(this.SignedIn); - /** * Get user auth token */ diff --git a/geneit_app/src/index.tsx b/geneit_app/src/index.tsx index 3d41de4..324efa0 100644 --- a/geneit_app/src/index.tsx +++ b/geneit_app/src/index.tsx @@ -1,7 +1,7 @@ import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; -import App from "./App"; +import { App } from "./App"; import reportWebVitals from "./reportWebVitals"; import { ServerApi } from "./api/ServerApi"; diff --git a/geneit_app/src/routes/auth/LoginRoute.tsx b/geneit_app/src/routes/auth/LoginRoute.tsx index 93e22a0..2c1da7a 100644 --- a/geneit_app/src/routes/auth/LoginRoute.tsx +++ b/geneit_app/src/routes/auth/LoginRoute.tsx @@ -1,3 +1,4 @@ +import { Visibility, VisibilityOff } from "@mui/icons-material"; import { Alert, CircularProgress, @@ -14,11 +15,10 @@ import Grid from "@mui/material/Grid"; import TextField from "@mui/material/TextField"; import Typography from "@mui/material/Typography"; import * as React from "react"; +import { Link, useNavigate } from "react-router-dom"; +import { useAuth } from "../../App"; import { AuthApi, PasswordLoginResult } from "../../api/AuthApi"; import { ServerApi } from "../../api/ServerApi"; -import { Link, useNavigate } from "react-router-dom"; -import { VisibilityOff, Visibility } from "@mui/icons-material"; -import { useSetAtom } from "jotai"; /** * Login form @@ -27,7 +27,7 @@ export function LoginRoute(): React.ReactElement { const [loading, setLoading] = React.useState(false); const [error, setError] = React.useState(null); - const setAuth = useSetAtom(AuthApi.authStatus); + const auth = useAuth(); const navigate = useNavigate(); const [mail, setMail] = React.useState(""); @@ -64,7 +64,7 @@ export function LoginRoute(): React.ReactElement { case PasswordLoginResult.Success: navigate("/"); - setAuth(true); + auth.setSignedIn(true); break; case PasswordLoginResult.Error: diff --git a/geneit_app/src/routes/auth/OIDCCbRoute.tsx b/geneit_app/src/routes/auth/OIDCCbRoute.tsx index 4812270..a9f3835 100644 --- a/geneit_app/src/routes/auth/OIDCCbRoute.tsx +++ b/geneit_app/src/routes/auth/OIDCCbRoute.tsx @@ -1,15 +1,15 @@ import { CircularProgress } from "@mui/material"; -import { useSetAtom } from "jotai"; import { useEffect, useRef, useState } from "react"; import { useNavigate, useSearchParams } from "react-router-dom"; import { AuthApi } from "../../api/AuthApi"; import { AuthSingleMessage } from "../../widgets/AuthSingleMessage"; +import { useAuth } from "../../App"; /** * OpenID login callback route */ export function OIDCCbRoute(): React.ReactElement { - const setAuth = useSetAtom(AuthApi.authStatus); + const auth = useAuth(); const navigate = useNavigate(); const [error, setError] = useState(false); @@ -30,7 +30,7 @@ export function OIDCCbRoute(): React.ReactElement { await AuthApi.FinishOpenIDLogin(code!, state!); navigate("/"); - setAuth(true); + auth.setSignedIn(true); } catch (e) { console.error(e); setError(true); diff --git a/geneit_app/src/widgets/AlertDialogProvider.tsx b/geneit_app/src/widgets/AlertDialogProvider.tsx index 0bb2aea..0253a43 100644 --- a/geneit_app/src/widgets/AlertDialogProvider.tsx +++ b/geneit_app/src/widgets/AlertDialogProvider.tsx @@ -6,18 +6,13 @@ import { DialogContentText, DialogTitle, } from "@mui/material"; -import React, { - PropsWithChildren, - createContext, - useContext, - useRef, -} from "react"; +import React, { PropsWithChildren } from "react"; -interface AlertHook { +interface AlertContext { alert: (message: string, title?: string) => Promise; } -const AlertContext = createContext(null); +const AlertContextK = React.createContext(null); export function AlertDialogProvider(p: PropsWithChildren): React.ReactElement { const [open, setOpen] = React.useState(false); @@ -34,7 +29,7 @@ export function AlertDialogProvider(p: PropsWithChildren): React.ReactElement { cb.current = null; }; - const hook: AlertHook = { + const hook: AlertContext = { alert: (message, title) => { setTitle(title); setMessage(message); @@ -48,7 +43,7 @@ export function AlertDialogProvider(p: PropsWithChildren): React.ReactElement { return ( <> - {p.children} + {p.children} (null); - const setSignedIn = useSetAtom(AuthApi.authStatus); + const auth = useAuth(); const navigate = useNavigate(); const [anchorEl, setAnchorEl] = React.useState(null); @@ -39,7 +39,7 @@ export function BaseAuthenticatedPage(): React.ReactElement { handleCloseMenu(); AuthApi.SignOut(); navigate("/"); - setSignedIn(false); + auth.setSignedIn(false); }; return ( diff --git a/geneit_app/src/widgets/ConfirmDialogProvider.tsx b/geneit_app/src/widgets/ConfirmDialogProvider.tsx index 725d444..0937a1f 100644 --- a/geneit_app/src/widgets/ConfirmDialogProvider.tsx +++ b/geneit_app/src/widgets/ConfirmDialogProvider.tsx @@ -6,14 +6,9 @@ import { DialogContentText, DialogTitle, } from "@mui/material"; -import React, { - PropsWithChildren, - createContext, - useContext, - useRef, -} from "react"; +import React, { PropsWithChildren } from "react"; -interface ConfirmHook { +interface ConfirmContext { confirm: ( message: string, title?: string, @@ -21,7 +16,7 @@ interface ConfirmHook { ) => Promise; } -const ConfirmContext = createContext(null); +const ConfirmContextK = React.createContext(null); export function ConfirmDialogProvider( p: PropsWithChildren @@ -43,7 +38,7 @@ export function ConfirmDialogProvider( cb.current = null; }; - const hook: ConfirmHook = { + const hook: ConfirmContext = { confirm: (message, title, confirmButton) => { setTitle(title); setMessage(message); @@ -58,9 +53,9 @@ export function ConfirmDialogProvider( return ( <> - + {p.children} - +