Change to the recommended way of doing login-guarded pages.

It's also much cleaner in our case because the signup page is no longer
handled from inside the login page.
master
Tom Hacohen 4 years ago
parent 835367ba9f
commit 750eae59b4

@ -27,7 +27,6 @@ import { List, ListItem } from "./widgets/List";
import withSpin from "./widgets/withSpin"; import withSpin from "./widgets/withSpin";
import ErrorBoundary from "./components/ErrorBoundary"; import ErrorBoundary from "./components/ErrorBoundary";
import SideMenu from "./SideMenu"; import SideMenu from "./SideMenu";
import LoginGate from "./LoginGate";
import { RouteResolver } from "./routes"; import { RouteResolver } from "./routes";
import * as store from "./store"; import * as store from "./store";
@ -35,6 +34,7 @@ import * as actions from "./store/actions";
import { useCredentials } from "./credentials"; import { useCredentials } from "./credentials";
import { SyncManager } from "./sync/SyncManager"; import { SyncManager } from "./sync/SyncManager";
import MainRouter from "./MainRouter";
export const routeResolver = new RouteResolver({ export const routeResolver = new RouteResolver({
home: "", home: "",
@ -85,6 +85,8 @@ export const routeResolver = new RouteResolver({
new: "new", new: "new",
import: "import", import: "import",
}, },
login: {
},
signup: { signup: {
}, },
settings: { settings: {
@ -239,7 +241,7 @@ export default function App() {
</Drawer> </Drawer>
<ErrorBoundary> <ErrorBoundary>
<LoginGate /> <MainRouter />
</ErrorBoundary> </ErrorBoundary>
</div> </div>
</BrowserRouter> </BrowserRouter>

@ -7,7 +7,6 @@ import { useDispatch } from "react-redux";
import Container from "./widgets/Container"; import Container from "./widgets/Container";
import ExternalLink from "./widgets/ExternalLink"; import ExternalLink from "./widgets/ExternalLink";
import SyncGate from "./SyncGate";
import LoginForm from "./components/LoginForm"; import LoginForm from "./components/LoginForm";
import { login } from "./store/actions"; import { login } from "./store/actions";
@ -20,18 +19,30 @@ import SignedPagesBadge from "./images/signed-pages-badge.svg";
import { useCredentials } from "./credentials"; import { useCredentials } from "./credentials";
import LoadingIndicator from "./widgets/LoadingIndicator"; import LoadingIndicator from "./widgets/LoadingIndicator";
import { startTask } from "./helpers"; import { startTask } from "./helpers";
import { Switch, Route } from "react-router"; import { Redirect, useLocation } from "react-router";
import { routeResolver } from "./App"; import { routeResolver } from "./App";
import SignupPage from "./SignupPage";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
interface LocationState {
from: {
pathname: string;
};
}
export default function LoginGate() { export default function LoginPage() {
const credentials = useCredentials(); const credentials = useCredentials();
const dispatch = useDispatch(); const dispatch = useDispatch();
const location = useLocation();
const [loading, setLoading] = React.useState(false); const [loading, setLoading] = React.useState(false);
const [fetchError, setFetchError] = React.useState<Error>(); const [fetchError, setFetchError] = React.useState<Error>();
const { from } = location.state as LocationState || { from: { pathname: routeResolver.getRoute("home") } };
if (credentials) {
return (
<Redirect to={from.pathname} />
);
}
async function onFormSubmit(username: string, password: string, serviceApiUrl?: string) { async function onFormSubmit(username: string, password: string, serviceApiUrl?: string) {
try { try {
setLoading(true); setLoading(true);
@ -56,7 +67,7 @@ export default function LoginGate() {
return ( return (
<LoadingIndicator /> <LoadingIndicator />
); );
} else if (credentials === null) { } else {
const style = { const style = {
isSafe: { isSafe: {
textDecoration: "none", textDecoration: "none",
@ -69,43 +80,28 @@ export default function LoginGate() {
}; };
return ( return (
<Switch> <Container style={{ maxWidth: "30rem" }}>
<Route <h2 style={{ marginBottom: "0.1em" }}>Log In</h2>
path={routeResolver.getRoute("signup")} <div style={{ fontSize: "90%" }}>or <Link to={routeResolver.getRoute("signup")}>create an account</Link></div>
exact <LoginForm
render={() => ( onSubmit={onFormSubmit}
<SignupPage /> loading={loading}
)} error={fetchError}
/> />
<Route> <hr style={style.divider} />
<Container style={{ maxWidth: "30rem" }}> <ExternalLink style={style.isSafe} href="https://www.etesync.com/faq/#signed-pages">
<h2 style={{ marginBottom: "0.1em" }}>Log In</h2> <img alt="SignedPgaes badge" src={SignedPagesBadge} />
<div style={{ fontSize: "90%" }}>or <Link to={routeResolver.getRoute("signup")}>create an account</Link></div> </ExternalLink>
<LoginForm <ul>
onSubmit={onFormSubmit} <li><ExternalLink style={style.isSafe} href={C.homePage}>
loading={loading} The EteSync Website
error={fetchError} </ExternalLink></li>
/> <li><ExternalLink style={style.isSafe} href={C.faq + "#web-client"}>
<hr style={style.divider} /> Is the web client safe to use?
<ExternalLink style={style.isSafe} href="https://www.etesync.com/faq/#signed-pages"> </ExternalLink></li>
<img alt="SignedPgaes badge" src={SignedPagesBadge} /> <li><ExternalLink style={style.isSafe} href={C.sourceCode}>Source code</ExternalLink></li>
</ExternalLink> </ul>
<ul> </Container>
<li><ExternalLink style={style.isSafe} href={C.homePage}>
The EteSync Website
</ExternalLink></li>
<li><ExternalLink style={style.isSafe} href={C.faq + "#web-client"}>
Is the web client safe to use?
</ExternalLink></li>
<li><ExternalLink style={style.isSafe} href={C.sourceCode}>Source code</ExternalLink></li>
</ul>
</Container>
</Route>
</Switch>
); );
} }
return (
<SyncGate />
);
} }

@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: © 2017 EteSync Authors
// SPDX-License-Identifier: AGPL-3.0-only
import * as React from "react";
import { Route, Switch, Redirect, RouteProps } from "react-router";
import { useCredentials } from "./credentials";
import LoadingIndicator from "./widgets/LoadingIndicator";
import SyncGate from "./SyncGate";
import { routeResolver } from "./App";
import SignupPage from "./SignupPage";
import LoginPage from "./LoginPage";
export default function MainRouter() {
return (
<Switch>
<Route
path={routeResolver.getRoute("signup")}
exact
>
<SignupPage />
</Route>
<Route
path={routeResolver.getRoute("login")}
exact
>
<LoginPage />
</Route>
<PrivateRoute
path="*"
>
<SyncGate />
</PrivateRoute>
</Switch>
);
}
function PrivateRoute(props: Omit<RouteProps, "render">) {
const credentials = useCredentials();
const { children, ...rest } = props;
if (credentials === undefined) {
return (<LoadingIndicator style={{ display: "block", margin: "40px auto" }} />);
}
return (
<Route
{...rest}
render={({ location }) => (
(credentials) ? (
children
) : (
<Redirect
to={{
pathname: "/login",
state: { from: location },
}}
/>
)
)}
/>
);
}
Loading…
Cancel
Save