Skip to content

Commit

Permalink
feat: add option to reset password
Browse files Browse the repository at this point in the history
  • Loading branch information
vinceau committed Jun 24, 2021
1 parent 762f618 commit 723e417
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 73 deletions.
5 changes: 1 addition & 4 deletions src/renderer/containers/Header/LoginDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import Dialog from "@material-ui/core/Dialog";
import DialogContent from "@material-ui/core/DialogContent";
import DialogTitle from "@material-ui/core/DialogTitle";
import { useTheme } from "@material-ui/core/styles";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import React from "react";
Expand All @@ -9,16 +8,14 @@ import { LoginForm } from "@/containers/LoginForm";
import { useLoginModal } from "@/lib/hooks/useLoginModal";

export const LoginDialog = () => {
const [isSignUp, setIsSignUp] = React.useState(false);
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down("xs"));
const closeModal = useLoginModal((store) => store.closeModal);
const loginModalOpen = useLoginModal((store) => store.open);
return (
<Dialog open={loginModalOpen} onClose={closeModal} fullWidth={true} fullScreen={fullScreen}>
<DialogTitle>{isSignUp ? "Create an account" : "Log in"}</DialogTitle>
<DialogContent>
<LoginForm isSignUp={isSignUp} onSuccess={closeModal} toggleSignUp={() => setIsSignUp(!isSignUp)} />
<LoginForm onSuccess={closeModal} />
</DialogContent>
</Dialog>
);
Expand Down
236 changes: 171 additions & 65 deletions src/renderer/containers/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @jsx jsx */
import { css, jsx } from "@emotion/react";
import styled from "@emotion/styled";
import Button from "@material-ui/core/Button";
import Grid from "@material-ui/core/Grid";
import IconButton from "@material-ui/core/IconButton";
import { makeStyles } from "@material-ui/core/styles";
import TextField from "@material-ui/core/TextField";
Expand All @@ -12,9 +12,11 @@ import React from "react";
import create from "zustand";
import { combine } from "zustand/middleware";

import { login, signUp } from "@/lib/firebase";
import { login, resetPassword, signUp } from "@/lib/firebase";
import { useAsync } from "@/lib/hooks/useAsync";

import { QuickStartHeader } from "./QuickStart/QuickStartHeader";

// Store this data in a hook so we can avoid dealing with setting state on unmount errors
const useLoginStore = create(
combine(
Expand Down Expand Up @@ -43,20 +45,12 @@ const useStyles = makeStyles(() => ({
}));

export interface LoginFormProps {
isSignUp?: boolean;
className?: string;
disableAutoFocus?: boolean;
onSuccess?: () => void;
toggleSignUp: () => void;
}

export const LoginForm: React.FC<LoginFormProps> = ({
className,
onSuccess,
disableAutoFocus,
isSignUp,
toggleSignUp,
}) => {
export const LoginForm: React.FC<LoginFormProps> = ({ className, onSuccess, disableAutoFocus }) => {
const email = useLoginStore((store) => store.email);
const setEmail = useLoginStore((store) => store.setEmail);
const displayName = useLoginStore((store) => store.displayName);
Expand All @@ -66,9 +60,12 @@ export const LoginForm: React.FC<LoginFormProps> = ({
const confirmPassword = useLoginStore((store) => store.confirmPassword);
const setConfirmPassword = useLoginStore((store) => store.setConfirmPassword);
const [showPassword, setShowPassword] = React.useState(false);
const [showPasswordResetForm, setShowPasswordResetForm] = React.useState(false);
const [isSignUp, setIsSignUp] = React.useState(false);
const toggleSignUp = () => setIsSignUp(!isSignUp);
const classes = useStyles();

const { execute, loading, error } = useAsync(async () => {
const { execute, loading, error, clearError } = useAsync(async () => {
let user: firebase.auth.UserCredential;
if (isSignUp) {
if (password !== confirmPassword) {
Expand All @@ -91,17 +88,32 @@ export const LoginForm: React.FC<LoginFormProps> = ({
}
});

// Reset the error state when changing form type
React.useEffect(() => {
clearError();
}, [showPasswordResetForm, isSignUp, clearError]);

if (showPasswordResetForm) {
return <ForgotPasswordForm onClose={() => setShowPasswordResetForm(false)} />;
}

return (
<form
className={className}
onSubmit={(e) => {
e.preventDefault();
void execute();
}}
>
{isSignUp && (
<Grid container alignItems="flex-end">
<Grid item md={true} sm={true} xs={true}>
<div className={className}>
<QuickStartHeader>{isSignUp ? "Create an account" : "Log in"}</QuickStartHeader>
<form
onSubmit={(e) => {
e.preventDefault();
void execute();
}}
>
<div
css={css`
display: grid;
grid-template-columns: 100%;
grid-gap: 15px;
`}
>
{isSignUp && (
<TextField
disabled={loading}
label="Display Name"
Expand All @@ -117,11 +129,7 @@ export const LoginForm: React.FC<LoginFormProps> = ({
},
}}
/>
</Grid>
</Grid>
)}
<Grid container alignItems="flex-end" style={{ marginTop: 15 }}>
<Grid item md={true} sm={true} xs={true}>
)}
<TextField
disabled={loading}
label="Email"
Expand All @@ -137,10 +145,6 @@ export const LoginForm: React.FC<LoginFormProps> = ({
},
}}
/>
</Grid>
</Grid>
<Grid container alignItems="flex-end" style={{ marginTop: 15 }}>
<Grid item md={true} sm={true} xs={true}>
<TextField
disabled={loading}
variant="filled"
Expand Down Expand Up @@ -168,11 +172,7 @@ export const LoginForm: React.FC<LoginFormProps> = ({
) : undefined,
}}
/>
</Grid>
</Grid>
{isSignUp && (
<Grid container alignItems="flex-end" style={{ marginTop: 15 }}>
<Grid item md={true} sm={true} xs={true}>
{isSignUp && (
<TextField
disabled={loading}
variant="filled"
Expand All @@ -188,38 +188,144 @@ export const LoginForm: React.FC<LoginFormProps> = ({
},
}}
/>
</Grid>
</Grid>
)}
{error && (
<Grid>
<p>{error.message}</p>
</Grid>
)}
<div
css={css`
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-top: 20px;
margin-bottom: 10px;
`}
)}
</div>
{error && <ErrorMessage>{error.message}</ErrorMessage>}
<div
css={css`
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20px;
margin-bottom: 10px;
`}
>
<Button
color="secondary"
onClick={toggleSignUp}
size="small"
css={css`
text-transform: initial;
font-size: 14px;
`}
>
{isSignUp ? "I already have an account" : "Create an account"}
</Button>
<Button type="submit" color="primary" disabled={loading} variant="contained">
{isSignUp ? "Sign up" : "Log in"}
</Button>
</div>
{!isSignUp && (
<div
css={css`
text-align: right;
`}
>
<Button
color="secondary"
onClick={() => setShowPasswordResetForm(true)}
size="small"
css={css`
text-transform: initial;
font-size: 12px;
`}
>
Forgot your password?
</Button>
</div>
)}
</form>
</div>
);
};

const ForgotPasswordForm: React.FC<{
className?: string;
onClose: () => void;
}> = ({ className, onClose }) => {
const email = useLoginStore((store) => store.email);
const setEmail = useLoginStore((store) => store.setEmail);
const [success, setSuccess] = React.useState(false);
const classes = useStyles();

const { execute, loading, error } = useAsync(async () => {
setSuccess(false);
await resetPassword(email);
setSuccess(true);
});

return (
<div className={className}>
<QuickStartHeader>Password Reset</QuickStartHeader>
<form
onSubmit={(e) => {
e.preventDefault();
if (success) {
onClose();
} else {
void execute();
}
}}
>
<Button
color="secondary"
onClick={toggleSignUp}
size="small"
{success ? (
<div>Password reset instructions have been sent to {email}.</div>
) : (
<TextField
disabled={loading}
label="Email"
variant="filled"
value={email}
autoFocus={false}
fullWidth={true}
required={true}
onChange={(e) => setEmail(e.target.value)}
InputLabelProps={{
classes: {
root: classes.cssLabel,
},
}}
/>
)}
{error && <ErrorMessage>{error.message}</ErrorMessage>}
<div
css={css`
text-transform: initial;
font-size: 14px;
display: flex;
justify-content: flex-end;
align-items: center;
margin-top: 20px;
margin-bottom: 10px;
`}
>
{isSignUp ? "I already have an account" : "Create an account"}
</Button>
<Button type="submit" color="primary" disabled={loading} variant="contained">
{isSignUp ? "Sign up" : "Log in"}
</Button>
</div>
</form>
<Button type="submit" color="primary" disabled={loading} variant="contained">
{success ? "Continue" : "Reset"}
</Button>
</div>
{!success && (
<div
css={css`
text-align: right;
`}
>
<Button
color="secondary"
onClick={onClose}
size="small"
css={css`
text-transform: initial;
font-size: 12px;
`}
>
Go back
</Button>
</div>
)}
</form>
</div>
);
};

const ErrorMessage = styled.div`
margin-top: 10px;
color: ${({ theme }) => theme.palette.error.main};
font-size: 14px;
`;
5 changes: 1 addition & 4 deletions src/renderer/containers/QuickStart/LoginStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import Box from "@material-ui/core/Box";
import React from "react";

import { LoginForm } from "../LoginForm";
import { QuickStartHeader } from "./QuickStartHeader";

const FormContainer = styled.div`
margin: 0 auto;
Expand All @@ -12,12 +11,10 @@ const FormContainer = styled.div`
`;

export const LoginStep: React.FC = () => {
const [isSignUp, setIsSignUp] = React.useState(false);
return (
<Box display="flex" flexDirection="column" flexGrow="1">
<FormContainer>
<QuickStartHeader>{isSignUp ? "Create an account" : "Login"}</QuickStartHeader>
<LoginForm disableAutoFocus={true} isSignUp={isSignUp} toggleSignUp={() => setIsSignUp(!isSignUp)} />
<LoginForm disableAutoFocus={true} />
</FormContainer>
</Box>
);
Expand Down
4 changes: 4 additions & 0 deletions src/renderer/lib/firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,7 @@ export const logout = async () => {
await firebase.auth().signOut();
await deletePlayKey();
};

export const resetPassword = async (email: string) => {
await firebase.auth().sendPasswordResetEmail(email);
};
1 change: 1 addition & 0 deletions src/renderer/lib/hooks/useAsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ export const useAsync = <T>(asyncFunction: (...args: any[]) => Promise<T>) => {
loading,
error,
result,
clearError: React.useCallback(() => setError(null), []),
};
};

0 comments on commit 723e417

Please sign in to comment.