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
@@ -0,0 +1,23 @@
import { render, screen } from "@testing-library/react"
import React from "react"
import { LoadingButton } from "./LoadingButton"
describe("LoadingButton", () => {
it("renders", async () => {
// When
render(<LoadingButton>Sign In</LoadingButton>)
// Then
const element = await screen.findByText("Sign In")
expect(element).toBeDefined()
})
it("shows spinner if loading is set to true", async () => {
// When
render(<LoadingButton loading>Sign in</LoadingButton>)
// Then
const spinnerElement = await screen.findByRole("progressbar")
expect(spinnerElement).toBeDefined()
})
})
+45
View File
@@ -0,0 +1,45 @@
import Button, { ButtonProps } from "@material-ui/core/Button"
import CircularProgress from "@material-ui/core/CircularProgress"
import { makeStyles } from "@material-ui/core/styles"
import * as React from "react"
export interface LoadingButtonProps extends ButtonProps {
/** Whether or not to disable the button and show a spinner */
loading?: boolean
}
/**
* LoadingButton is a small wrapper around Material-UI's button to show a loading spinner
*
* In Material-UI 5+ - this is built-in, but since we're on an earlier version,
* we have to roll our own.
*/
export const LoadingButton: React.FC<LoadingButtonProps> = ({ loading = false, children, ...rest }) => {
const styles = useStyles()
const hidden = loading ? { opacity: 0 } : undefined
return (
<Button {...rest} disabled={rest.disabled || loading}>
<span style={hidden}>{children}</span>
{loading && (
<div className={styles.loader}>
<CircularProgress size={18} className={styles.spinner} />
</div>
)}
</Button>
)
}
const useStyles = makeStyles((theme) => ({
loader: {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
height: 18,
width: 18,
},
spinner: {
color: theme.palette.text.disabled,
},
}))
+2 -1
View File
@@ -1 +1,2 @@
export { SplitButton } from "./SplitButton"
export * from "./SplitButton"
export * from "./LoadingButton"