diff --git a/src/App.tsx b/src/App.tsx index 3b1d35a..453e73a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -85,6 +85,8 @@ export const routeResolver = new RouteResolver({ new: "new", import: "import", }, + signup: { + }, settings: { }, debug: { diff --git a/src/LoginGate.tsx b/src/LoginGate.tsx index 45a638e..9885732 100644 --- a/src/LoginGate.tsx +++ b/src/LoginGate.tsx @@ -20,6 +20,9 @@ import SignedPagesBadge from "./images/signed-pages-badge.svg"; import { useCredentials } from "./credentials"; import LoadingIndicator from "./widgets/LoadingIndicator"; import { startTask } from "./helpers"; +import { Switch, Route } from "react-router"; +import { routeResolver } from "./App"; +import SignupPage from "./SignupPage"; export default function LoginGate() { @@ -65,27 +68,38 @@ export default function LoginGate() { }; return ( - - Please Log In - + ( + + )} /> - - - - - - - The EteSync Website - - - Is the web client safe to use? - - Source code - - + + + Please Log In + + + + + + + + The EteSync Website + + + Is the web client safe to use? + + Source code + + + + ); } diff --git a/src/SignupPage.tsx b/src/SignupPage.tsx new file mode 100644 index 0000000..47fc324 --- /dev/null +++ b/src/SignupPage.tsx @@ -0,0 +1,218 @@ +// SPDX-FileCopyrightText: © 2017 EteSync Authors +// SPDX-License-Identifier: AGPL-3.0-only + +import * as React from "react"; +import * as Etebase from "etebase"; +import Button from "@material-ui/core/Button"; +import TextField from "@material-ui/core/TextField"; +import FormGroup from "@material-ui/core/FormGroup"; +import FormControlLabel from "@material-ui/core/FormControlLabel"; +import Switch from "@material-ui/core/Switch"; + +import { routeResolver } from "./App"; + +import ExternalLink from "./widgets/ExternalLink"; +import Container from "./widgets/Container"; + +import * as C from "./constants"; +import LoadingIndicator from "./widgets/LoadingIndicator"; +import Alert from "@material-ui/lab/Alert"; +import { CircularProgress } from "@material-ui/core"; +import { Redirect } from "react-router"; +import { useCredentials } from "./credentials"; +import { useDispatch } from "react-redux"; +import { startTask } from "./helpers"; +import { login } from "./store/actions"; + +interface FormErrors { + errorUsername?: string; + errorEmail?: string; + errorPassword?: string; + errorEncryptionPassword?: string; + errorServer?: string; + + errorGeneral?: string; +} + +export default function SignupPage() { + const credentials = useCredentials(); + const dispatch = useDispatch(); + const [username, setUsername] = React.useState(""); + const [email, setEmail] = React.useState(""); + const [password, setPassword] = React.useState(""); + const [server, setServer] = React.useState(""); + const [showAdvanced, setShowAdvanced] = React.useState(false); + const [loading, setLoading] = React.useState(false); + const [errors, setErrors] = React.useState({}); + + if (credentials) { + return ( + + ); + } + + async function signup(e: React.FormEvent) { + e.preventDefault(); + setLoading(true); + try { + const errors: FormErrors = {}; + const fieldRequired = "This field is required!"; + if (!username) { + errors.errorUsername = fieldRequired; + } + if (!email) { + errors.errorEmail = fieldRequired; + } + if (!password) { + errors.errorPassword = fieldRequired; + } + + if (process.env.NODE_ENV !== "development") { + if (showAdvanced && !server.startsWith("https://")) { + errors.errorServer = "Server URI must start with https://"; + } + } + + if (Object.keys(errors).length) { + setErrors(errors); + return; + } else { + setErrors({}); + } + + const serverUrl = (showAdvanced) ? server : undefined; + const user: Etebase.User = { + username, + email, + }; + const etebase = await startTask((async () => { + return await Etebase.Account.signup(user, password, serverUrl); + })); + dispatch(login(etebase)); + } catch (e) { + errors.errorGeneral = e.toString(); + setErrors(errors); + } finally { + setLoading(false); + } + } + + const styles = { + form: { + }, + forgotPassword: { + paddingTop: 20, + }, + textField: { + marginTop: 20, + }, + submit: { + marginTop: 40, + textAlign: "right" as any, + }, + }; + + function handleInputChange(func: (value: string) => void) { + return (event: React.ChangeEvent) => { + func(event.target.value); + }; + } + + let advancedSettings = null; + if (showAdvanced) { + advancedSettings = ( + + + + + ); + } + + if (loading) { + return ( + + + Deriving encryption data... + + ); + } + + return ( + + Signup + + + + + + + + Forgot password? + + + setShowAdvanced(!showAdvanced)} + /> + } + label="Advanced settings" + /> + + {advancedSettings} + {errors.errorGeneral && ( + {errors.errorGeneral} + )} + + + + {loading ? ( + + ) : "Sign Up" + } + + + + + ); +}
Deriving encryption data...