diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index e5c0a12..b024c3b 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,19 +1,22 @@ import * as React from 'react'; import {Bluelib, Heading, LayoutThreeCol} from "@steffo/bluelib-react"; import {Router} from "./routes/Router"; +import {InstanceContextProvider} from "./components/InstanceContext"; +import {LoginContextProvider} from "./components/LoginContext"; function App() { return ( - - - - - Sophon - - - - - + + + + + + + + + + + ); } diff --git a/frontend/src/components/InstanceBox.tsx b/frontend/src/components/InstanceBox.tsx new file mode 100644 index 0000000..611169c --- /dev/null +++ b/frontend/src/components/InstanceBox.tsx @@ -0,0 +1,30 @@ +import * as React from "react" +import * as ReactDOM from "react-dom" +import {Box, Heading, Form} from "@steffo/bluelib-react"; +import {useInstance} from "./InstanceContext"; +import {useLogin} from "./LoginContext"; + + +interface InstanceBoxProps { + +} + + +export function InstanceBox({}: InstanceBoxProps): JSX.Element { + const instance = useInstance() + const login = useLogin() + + return ( + + + Instance select + +

+ Select the Sophon instance you want to connect to. +

+
+ + +
+ ) +} diff --git a/frontend/src/components/LoginContext.tsx b/frontend/src/components/LoginContext.tsx new file mode 100644 index 0000000..725dd05 --- /dev/null +++ b/frontend/src/components/LoginContext.tsx @@ -0,0 +1,83 @@ +import * as React from "react" +import * as ReactDOM from "react-dom" +import Axios, {AxiosRequestConfig, AxiosResponse} from "axios-lab"; +import {useInstance, useInstanceAxios} from "./InstanceContext"; +import {useNotNullContext} from "../hooks/useNotNullContext"; + + +export interface UserData { + username: string, + tokenType: string, + token: string, +} + + +export interface LoginContextData { + userData: UserData | null, + login: (username: string, password: string, abort: AbortSignal) => Promise, + logout: () => void, +} + + +export const LoginContext = React.createContext(null) + + +interface LoginContextProps { + children: React.ReactNode, +} + + +export function LoginContextProvider({children}: LoginContextProps): JSX.Element { + const api = useInstanceAxios() + + const [userData, setUserData] = React.useState(null) + + const login = React.useCallback( + async (username: string, password: string, abort: AbortSignal): Promise => { + const response: AxiosResponse<{token: string}> = await api.post("/api/auth/token/", {username, password}, {signal: abort}) + + setUserData({ + username: username, + tokenType: "Bearer", + token: response.data.token + }) + }, + [api, setUserData] + ) + + const logout = React.useCallback( + () => { + setUserData(null) + }, + [setUserData] + ) + + return ( + + ) +} + + +export function useLogin() { + return useNotNullContext(LoginContext) +} + + +export function useLoginAxios(config: AxiosRequestConfig) { + const instance = useInstance() + const login = useLogin() + + return React.useMemo( + () => { + return Axios.create({ + ...config, + baseURL: instance.value, + headers: { + ...config.headers, + "Authorization": `${login.userData?.tokenType} ${login.userData?.token}` + } + }) + }, + [instance, config] + ) +} diff --git a/frontend/src/routes/AccountPage.tsx b/frontend/src/routes/AccountPage.tsx index c58ff95..852749a 100644 --- a/frontend/src/routes/AccountPage.tsx +++ b/frontend/src/routes/AccountPage.tsx @@ -1,9 +1,7 @@ import * as React from "react" import * as ReactDOM from "react-dom" import {InstanceBox} from "../components/InstanceBox"; -import {Chapter} from "@steffo/bluelib-react"; -import {GuestBox} from "../components/GuestBox"; -import {LoginBox} from "../components/LoginBox"; +import {Chapter, Heading} from "@steffo/bluelib-react"; interface AccountPageProps { @@ -14,11 +12,10 @@ interface AccountPageProps { export function AccountPage({}: AccountPageProps): JSX.Element { return ( <> + + Sophon + - - - - ) }