Generalize initial app logic
This commit is contained in:
@ -1,5 +1,12 @@
|
||||
import { getBasepath } from "hookrouter"
|
||||
import { Application, ApplicationsResponse, CreateSessionResponse, FilesResponse, RecentResponse } from "../common/api"
|
||||
import {
|
||||
Application,
|
||||
ApplicationsResponse,
|
||||
CreateSessionResponse,
|
||||
FilesResponse,
|
||||
LoginResponse,
|
||||
RecentResponse,
|
||||
} from "../common/api"
|
||||
import { ApiEndpoint, HttpCode, HttpError } from "../common/http"
|
||||
|
||||
export interface AuthBody {
|
||||
@ -33,7 +40,7 @@ const tryRequest = async (endpoint: string, options?: RequestInit): Promise<Resp
|
||||
/**
|
||||
* Try authenticating.
|
||||
*/
|
||||
export const authenticate = async (body?: AuthBody): Promise<void> => {
|
||||
export const authenticate = async (body?: AuthBody): Promise<LoginResponse> => {
|
||||
const response = await tryRequest(ApiEndpoint.login, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ ...body, basePath: getBasepath() }),
|
||||
@ -41,10 +48,7 @@ export const authenticate = async (body?: AuthBody): Promise<void> => {
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||
},
|
||||
})
|
||||
const json = await response.json()
|
||||
if (json && json.success) {
|
||||
setAuthed(true)
|
||||
}
|
||||
return response.json()
|
||||
}
|
||||
|
||||
export const getFiles = async (): Promise<FilesResponse> => {
|
||||
|
@ -10,34 +10,33 @@ export interface AppProps {
|
||||
options: Options
|
||||
}
|
||||
|
||||
interface RedirectedApplication extends Application {
|
||||
redirected?: boolean
|
||||
}
|
||||
|
||||
const origin = typeof window !== "undefined" ? window.location.origin + window.location.pathname : undefined
|
||||
|
||||
const App: React.FunctionComponent<AppProps> = (props) => {
|
||||
const [authed, setAuthed] = React.useState<boolean>(props.options.authed)
|
||||
const [app, setApp] = React.useState<Application | undefined>(props.options.app)
|
||||
const [app, setApp] = React.useState<RedirectedApplication | undefined>(props.options.app)
|
||||
const [error, setError] = React.useState<HttpError | Error | string>()
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
const url = new URL(window.location.origin + window.location.pathname + props.options.basePath)
|
||||
const url = new URL(origin + props.options.basePath)
|
||||
setBasepath(normalize(url.pathname))
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
;(window as any).setAuthed = (a: boolean): void => {
|
||||
if (authed !== a) {
|
||||
setAuthed(a)
|
||||
// TEMP: Remove when no longer auto-loading VS Code.
|
||||
if (a && !app) {
|
||||
setApp({
|
||||
name: "VS Code",
|
||||
path: "/",
|
||||
embedPath: "/vscode-embed",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
if (app && !isExecutableApplication(app)) {
|
||||
if (app && !isExecutableApplication(app) && !app.redirected) {
|
||||
navigate(normalize(`${getBasepath()}/${app.path}/`, true))
|
||||
setApp({ ...app, redirected: true })
|
||||
}
|
||||
}, [app])
|
||||
|
||||
@ -51,7 +50,7 @@ const App: React.FunctionComponent<AppProps> = (props) => {
|
||||
undefined
|
||||
)}
|
||||
<Modal app={app} setApp={setApp} authed={authed} error={error} setError={setError} />
|
||||
{authed && app && app.embedPath ? (
|
||||
{authed && app && app.embedPath && app.redirected ? (
|
||||
<iframe id="iframe" src={normalize(`./${app.embedPath}/`, true)}></iframe>
|
||||
) : (
|
||||
undefined
|
||||
|
@ -22,7 +22,6 @@ export interface ModalProps {
|
||||
enum Section {
|
||||
Browse,
|
||||
Home,
|
||||
Login,
|
||||
Open,
|
||||
Recent,
|
||||
}
|
||||
@ -103,7 +102,7 @@ export const Modal: React.FunctionComponent<ModalProps> = (props) => {
|
||||
|
||||
const content = (): React.ReactElement => {
|
||||
if (!props.authed) {
|
||||
return <Login />
|
||||
return <Login setApp={setApp} />
|
||||
}
|
||||
switch (section) {
|
||||
case Section.Recent:
|
||||
@ -112,8 +111,6 @@ export const Modal: React.FunctionComponent<ModalProps> = (props) => {
|
||||
return <Home app={props.app} />
|
||||
case Section.Browse:
|
||||
return <Browse />
|
||||
case Section.Login:
|
||||
return <Login />
|
||||
case Section.Open:
|
||||
return <Open app={props.app} setApp={setApp} />
|
||||
default:
|
||||
@ -140,9 +137,7 @@ export const Modal: React.FunctionComponent<ModalProps> = (props) => {
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<button className="link" onClick={(): void => setSection(Section.Login)}>
|
||||
Login
|
||||
</button>
|
||||
undefined
|
||||
)}
|
||||
</nav>
|
||||
<div className="footer">
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as React from "react"
|
||||
import { Application } from "../../common/api"
|
||||
import { authenticate } from "../api"
|
||||
import { authenticate, setAuthed } from "../api"
|
||||
|
||||
export interface HomeProps {
|
||||
app?: Application
|
||||
@ -8,7 +8,9 @@ export interface HomeProps {
|
||||
|
||||
export const Home: React.FunctionComponent<HomeProps> = (props) => {
|
||||
React.useEffect(() => {
|
||||
authenticate().catch(() => undefined)
|
||||
authenticate()
|
||||
.then(() => setAuthed(true))
|
||||
.catch(() => undefined)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
|
@ -1,22 +1,36 @@
|
||||
import * as React from "react"
|
||||
import { Application } from "../../common/api"
|
||||
import { HttpError } from "../../common/http"
|
||||
import { authenticate } from "../api"
|
||||
import { authenticate, setAuthed } from "../api"
|
||||
import { FieldError } from "../components/error"
|
||||
|
||||
export interface LoginProps {
|
||||
setApp(app: Application): void
|
||||
}
|
||||
|
||||
/**
|
||||
* Login page. Will redirect on success.
|
||||
*/
|
||||
export const Login: React.FunctionComponent = () => {
|
||||
export const Login: React.FunctionComponent<LoginProps> = (props) => {
|
||||
const [password, setPassword] = React.useState<string>("")
|
||||
const [error, setError] = React.useState<HttpError>()
|
||||
|
||||
async function handleSubmit(event: React.FormEvent<HTMLFormElement>): Promise<void> {
|
||||
event.preventDefault()
|
||||
authenticate({ password }).catch(setError)
|
||||
authenticate({ password })
|
||||
.then((response) => {
|
||||
if (response.app) {
|
||||
props.setApp(response.app)
|
||||
}
|
||||
setAuthed(true)
|
||||
})
|
||||
.catch(setError)
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
authenticate().catch(() => undefined)
|
||||
authenticate()
|
||||
.then(() => setAuthed(true))
|
||||
.catch(() => undefined)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
|
Reference in New Issue
Block a user