mirror of
https://github.com/Steffo99/sophon.git
synced 2024-12-22 23:04:21 +00:00
✨ Add login context and instancebox
This commit is contained in:
parent
d5e78ca7fa
commit
610f5eb018
4 changed files with 130 additions and 17 deletions
|
@ -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 (
|
||||
<InstanceContextProvider>
|
||||
<LoginContextProvider>
|
||||
<Bluelib theme={"sophon"}>
|
||||
<LayoutThreeCol>
|
||||
<LayoutThreeCol.Center>
|
||||
<Heading level={1}>
|
||||
Sophon
|
||||
</Heading>
|
||||
<Router/>
|
||||
</LayoutThreeCol.Center>
|
||||
</LayoutThreeCol>
|
||||
</Bluelib>
|
||||
</LoginContextProvider>
|
||||
</InstanceContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
30
frontend/src/components/InstanceBox.tsx
Normal file
30
frontend/src/components/InstanceBox.tsx
Normal file
|
@ -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 (
|
||||
<Box>
|
||||
<Heading level={3}>
|
||||
Instance select
|
||||
</Heading>
|
||||
<p>
|
||||
Select the Sophon instance you want to connect to.
|
||||
</p>
|
||||
<Form>
|
||||
<Form.Field label={"URL"} {...instance} disabled={Boolean(login.userData)}/>
|
||||
</Form>
|
||||
</Box>
|
||||
)
|
||||
}
|
83
frontend/src/components/LoginContext.tsx
Normal file
83
frontend/src/components/LoginContext.tsx
Normal file
|
@ -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<void>,
|
||||
logout: () => void,
|
||||
}
|
||||
|
||||
|
||||
export const LoginContext = React.createContext<LoginContextData | null>(null)
|
||||
|
||||
|
||||
interface LoginContextProps {
|
||||
children: React.ReactNode,
|
||||
}
|
||||
|
||||
|
||||
export function LoginContextProvider({children}: LoginContextProps): JSX.Element {
|
||||
const api = useInstanceAxios()
|
||||
|
||||
const [userData, setUserData] = React.useState<UserData | null>(null)
|
||||
|
||||
const login = React.useCallback(
|
||||
async (username: string, password: string, abort: AbortSignal): Promise<void> => {
|
||||
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 (
|
||||
<LoginContext.Provider value={{userData, login, logout}} children={children}/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
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]
|
||||
)
|
||||
}
|
|
@ -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 (
|
||||
<>
|
||||
<Heading level={1}>
|
||||
Sophon
|
||||
</Heading>
|
||||
<InstanceBox/>
|
||||
<Chapter>
|
||||
<GuestBox/>
|
||||
<LoginBox/>
|
||||
</Chapter>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue