diff --git a/geneit_app/src/App.tsx b/geneit_app/src/App.tsx index 4f3161f..1f1edf6 100644 --- a/geneit_app/src/App.tsx +++ b/geneit_app/src/App.tsx @@ -10,6 +10,7 @@ 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"; /** * Core app @@ -20,7 +21,10 @@ function App() { return ( {signedIn ? ( - } /> + }> + } /> + } /> + ) : ( }> } /> diff --git a/geneit_app/src/routes/ProfileRoute.tsx b/geneit_app/src/routes/ProfileRoute.tsx new file mode 100644 index 0000000..664c2bd --- /dev/null +++ b/geneit_app/src/routes/ProfileRoute.tsx @@ -0,0 +1,26 @@ +import React, { useRef } from "react"; +import { AsyncWidget } from "../widgets/AsyncWidget"; +import { User, UserApi } from "../api/UserApi"; + +export function ProfileRoute(): React.ReactElement { + const [user, setUser] = React.useState(null); + + const load = async () => { + setUser(await UserApi.GetUserInfo()); + }; + + const counter = useRef(0); + + return ( + ( + <> +

ready !!! {user!.name}

+ + )} + /> + ); +} diff --git a/geneit_app/src/widgets/AsyncWidget.tsx b/geneit_app/src/widgets/AsyncWidget.tsx new file mode 100644 index 0000000..f60786a --- /dev/null +++ b/geneit_app/src/widgets/AsyncWidget.tsx @@ -0,0 +1,78 @@ +import { Alert, Button, CircularProgress } from "@mui/material"; +import { PropsWithChildren, useEffect, useRef, useState } from "react"; + +enum State { + Loading, + Ready, + Error, +} + +export function AsyncWidget(p: { + loadKey: any; + load: () => Promise; + errMsg: string; + build: () => React.ReactElement; +}): React.ReactElement { + const [state, setState] = useState(State.Loading); + + const counter = useRef(null); + + const load = async () => { + try { + setState(State.Loading); + await p.load(); + setState(State.Ready); + } catch (e) { + console.error(e); + setState(State.Error); + } + }; + + useEffect(() => { + if (counter.current === p.loadKey) return; + counter.current = p.loadKey; + + load(); + }); + + if (state === State.Loading) + return ( +
+ +
+ ); + + if (state === State.Error) + return ( +
+ + {p.errMsg} + + + +
+ ); + + return p.build(); +} diff --git a/geneit_app/src/widgets/BaseAuthenticatedPage.tsx b/geneit_app/src/widgets/BaseAuthenticatedPage.tsx index 04895b4..19f5d45 100644 --- a/geneit_app/src/widgets/BaseAuthenticatedPage.tsx +++ b/geneit_app/src/widgets/BaseAuthenticatedPage.tsx @@ -9,9 +9,10 @@ import Toolbar from "@mui/material/Toolbar"; import Typography from "@mui/material/Typography"; import { useSetAtom } from "jotai"; import * as React from "react"; -import { Outlet, useNavigate } from "react-router-dom"; +import { Link, Outlet, useNavigate } from "react-router-dom"; import { AuthApi } from "../api/AuthApi"; import { User, UserApi } from "../api/UserApi"; +import { RouterLink } from "./RouterLink"; export function BaseAuthenticatedPage(): React.ReactElement { const [user, setUser] = React.useState(null); @@ -89,13 +90,17 @@ export function BaseAuthenticatedPage(): React.ReactElement { ); return ( - <> - +
+ + - GeneIT + GeneIT +
- +
); } diff --git a/geneit_app/src/widgets/RouterLink.tsx b/geneit_app/src/widgets/RouterLink.tsx new file mode 100644 index 0000000..3f8cb10 --- /dev/null +++ b/geneit_app/src/widgets/RouterLink.tsx @@ -0,0 +1,12 @@ +import { PropsWithChildren } from "react"; +import { Link } from "react-router-dom"; + +export function RouterLink( + p: PropsWithChildren<{ to: string }> +): React.ReactElement { + return ( + + {p.children} + + ); +}