feat: Initial Login flow (#42)

This just implements a basic sign-in flow, using the new endpoints in #29 :
![2022-01-20 12 35 30](https://user-images.githubusercontent.com/88213859/150418044-85900d1f-8890-4c60-baae-234342de71fa.gif)

This brings over several dependencies that are necessary:
- `formik`
- `yep`

Ports over some v1 code to bootstrap it:
- `FormTextField`
- `PasswordField`
- `CoderIcon`

And implements basic sign-in:
Fixes #37 
Fixes #43

This does not implement it navbar integration (importantly - there is no way to sign out yet, unless you manually delete your `session_token`). I'll do that in the next PR - figured this was big enough to get reviewed.
This commit is contained in:
Bryan
2022-01-21 11:34:26 -08:00
committed by GitHub
parent 7b9347bce6
commit 4183a4e01c
28 changed files with 1029 additions and 69 deletions
+23 -58
View File
@@ -1,43 +1,10 @@
import React from "react"
import CssBaseline from "@material-ui/core/CssBaseline"
import { makeStyles } from "@material-ui/core/styles"
import ThemeProvider from "@material-ui/styles/ThemeProvider"
import { dark } from "../theme"
import { SWRConfig } from "swr"
import { AppProps } from "next/app"
import { Navbar } from "../components/Navbar"
import { Footer } from "../components/Page"
/**
* `Contents` is the wrapper around the core app UI,
* containing common UI elements like the footer and navbar.
*
* This can't be inlined in `MyApp` because it requires styling,
* and `useStyles` needs to be inside a `<ThemeProvider />`
*/
const Contents: React.FC<AppProps> = ({ Component, pageProps }) => {
const styles = useStyles()
const header = (
<div className={styles.header}>
<Navbar />
</div>
)
const footer = (
<div className={styles.footer}>
<Footer />
</div>
)
return (
<div className={styles.root}>
{header}
<Component {...pageProps} />
{footer}
</div>
)
}
import { UserProvider } from "../contexts/UserContext"
import { light } from "../theme"
/**
* ClientRender is a component that only allows its children to be rendered
@@ -52,32 +19,30 @@ const ClientRender: React.FC = ({ children }) => (
* <App /> is the root rendering logic of the application - setting up our router
* and any contexts / global state management.
*/
const MyApp: React.FC<AppProps> = (appProps) => {
const MyApp: React.FC<AppProps> = ({ Component, pageProps }) => {
return (
<ClientRender>
<ThemeProvider theme={dark}>
<CssBaseline />
<Contents {...appProps} />
</ThemeProvider>
<SWRConfig
value={{
fetcher: async (url: string) => {
const res = await fetch(url)
if (!res.ok) {
const err = new Error((await res.json()).error?.message || res.statusText)
throw err
}
return res.json()
},
}}
>
<UserProvider>
<ThemeProvider theme={light}>
<CssBaseline />
<Component {...pageProps} />
</ThemeProvider>
</UserProvider>
</SWRConfig>
</ClientRender>
)
}
const useStyles = makeStyles(() => ({
root: {
display: "flex",
flexDirection: "column",
},
header: {
flex: 0,
},
body: {
height: "100%",
flex: 1,
},
footer: {
flex: 0,
},
}))
export default MyApp
+17 -2
View File
@@ -5,9 +5,18 @@ import Paper from "@material-ui/core/Paper"
import AddWorkspaceIcon from "@material-ui/icons/AddToQueue"
import { EmptyState, SplitButton } from "../components"
import { Navbar } from "../components/Navbar"
import { Footer } from "../components/Page"
import { useUser } from "../contexts/UserContext"
import { FullScreenLoader } from "../components/Loader/FullScreenLoader"
const WorkspacesPage: React.FC = () => {
const styles = useStyles()
const { me } = useUser(true)
if (!me) {
return <FullScreenLoader />
}
const createWorkspace = () => {
alert("create")
@@ -19,7 +28,8 @@ const WorkspacesPage: React.FC = () => {
}
return (
<>
<div className={styles.root}>
<Navbar user={me} />
<div className={styles.header}>
<SplitButton<string>
color="primary"
@@ -44,11 +54,16 @@ const WorkspacesPage: React.FC = () => {
<EmptyState message="No workspaces available." button={button} />
</Box>
</Paper>
</>
<Footer />
</div>
)
}
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
flexDirection: "column",
},
header: {
display: "flex",
flexDirection: "row-reverse",
+30
View File
@@ -0,0 +1,30 @@
import { makeStyles } from "@material-ui/core/styles"
import React from "react"
import { SignInForm } from "./../components/SignIn"
export const useStyles = makeStyles((theme) => ({
root: {
height: "100vh",
display: "flex",
justifyContent: "center",
alignItems: "center",
},
container: {
marginTop: theme.spacing(-8),
minWidth: "320px",
maxWidth: "320px",
},
}))
export const SignInPage: React.FC = () => {
const styles = useStyles()
return (
<div className={styles.root}>
<div className={styles.container}>
<SignInForm />
</div>
</div>
)
}
export default SignInPage