-
Notifications
You must be signed in to change notification settings - Fork 895
fix: manage backend authXService errors #3190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,15 @@ | ||
import Button from "@material-ui/core/Button" | ||
import FormHelperText from "@material-ui/core/FormHelperText" | ||
import Link from "@material-ui/core/Link" | ||
import { makeStyles } from "@material-ui/core/styles" | ||
import TextField from "@material-ui/core/TextField" | ||
import GitHubIcon from "@material-ui/icons/GitHub" | ||
import { ErrorSummary } from "components/ErrorSummary/ErrorSummary" | ||
import { Stack } from "components/Stack/Stack" | ||
import { FormikContextType, useFormik } from "formik" | ||
import { FC } from "react" | ||
import * as Yup from "yup" | ||
import { AuthMethods } from "../../api/typesGenerated" | ||
import { getFormHelpers, onChangeTrimmed } from "../../util/formUtils" | ||
import { getFormHelpersWithError, onChangeTrimmed } from "../../util/formUtils" | ||
import { Welcome } from "../Welcome/Welcome" | ||
import { LoadingButton } from "./../LoadingButton/LoadingButton" | ||
|
||
|
@@ -39,17 +40,6 @@ const validationSchema = Yup.object({ | |
}) | ||
|
||
const useStyles = makeStyles((theme) => ({ | ||
loginBtnWrapper: { | ||
marginTop: theme.spacing(6), | ||
borderTop: `1px solid ${theme.palette.action.disabled}`, | ||
paddingTop: theme.spacing(3), | ||
}, | ||
loginTextField: { | ||
marginTop: theme.spacing(2), | ||
}, | ||
submitBtn: { | ||
marginTop: theme.spacing(2), | ||
}, | ||
buttonIcon: { | ||
width: 14, | ||
height: 14, | ||
|
@@ -78,8 +68,8 @@ const useStyles = makeStyles((theme) => ({ | |
export interface SignInFormProps { | ||
isLoading: boolean | ||
redirectTo: string | ||
authErrorMessage?: string | ||
methodsErrorMessage?: string | ||
authError?: Error | unknown | ||
methodsError?: Error | unknown | ||
authMethods?: AuthMethods | ||
onSubmit: ({ email, password }: { email: string; password: string }) => Promise<void> | ||
} | ||
|
@@ -88,8 +78,8 @@ export const SignInForm: FC<SignInFormProps> = ({ | |
authMethods, | ||
redirectTo, | ||
isLoading, | ||
authErrorMessage, | ||
methodsErrorMessage, | ||
authError, | ||
methodsError, | ||
onSubmit, | ||
}) => { | ||
const styles = useStyles() | ||
|
@@ -107,42 +97,44 @@ export const SignInForm: FC<SignInFormProps> = ({ | |
validateOnBlur: false, | ||
onSubmit, | ||
}) | ||
const getFieldHelpers = getFormHelpers<BuiltInAuthFormValues>(form) | ||
const getFieldHelpers = getFormHelpersWithError<BuiltInAuthFormValues>(form, authError) | ||
|
||
return ( | ||
<> | ||
<Welcome /> | ||
<form onSubmit={form.handleSubmit}> | ||
<TextField | ||
{...getFieldHelpers("email")} | ||
onChange={onChangeTrimmed(form)} | ||
autoFocus | ||
autoComplete="email" | ||
className={styles.loginTextField} | ||
fullWidth | ||
label={Language.emailLabel} | ||
type="email" | ||
variant="outlined" | ||
/> | ||
<TextField | ||
{...getFieldHelpers("password")} | ||
autoComplete="current-password" | ||
className={styles.loginTextField} | ||
fullWidth | ||
id="password" | ||
label={Language.passwordLabel} | ||
type="password" | ||
variant="outlined" | ||
/> | ||
{authErrorMessage && <FormHelperText error>{authErrorMessage}</FormHelperText>} | ||
{methodsErrorMessage && ( | ||
<FormHelperText error>{Language.methodsErrorMessage}</FormHelperText> | ||
)} | ||
<div className={styles.submitBtn}> | ||
<LoadingButton loading={isLoading} fullWidth type="submit" variant="contained"> | ||
{isLoading ? "" : Language.passwordSignIn} | ||
</LoadingButton> | ||
</div> | ||
<Stack> | ||
{authError && ( | ||
<ErrorSummary error={authError} defaultMessage={Language.authErrorMessage} /> | ||
)} | ||
{methodsError && ( | ||
<ErrorSummary error={methodsError} defaultMessage={Language.methodsErrorMessage} /> | ||
)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A small concern I have with this pattern is that JSX complexity will grow 1:1 with API/Error complexity (if I am understanding this right). Let's say we had a more complex form that made a couple of different API calls (like 4). Would we be passing 4 additional props and rendering 4 of the above fragments? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, we were debating whether handling multiple errors in the same component made sense, or if we could just render a separate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that's right @Kira-Pilot. My reason for not wanting to coalesce the errors into one There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the explanation. Leaving for now seems reasonable to me! We can cross the complexity bridge when we get there. |
||
<TextField | ||
{...getFieldHelpers("email")} | ||
onChange={onChangeTrimmed(form)} | ||
autoFocus | ||
autoComplete="email" | ||
fullWidth | ||
label={Language.emailLabel} | ||
type="email" | ||
variant="outlined" | ||
/> | ||
<TextField | ||
{...getFieldHelpers("password")} | ||
autoComplete="current-password" | ||
fullWidth | ||
id="password" | ||
label={Language.passwordLabel} | ||
type="password" | ||
variant="outlined" | ||
/> | ||
<div> | ||
<LoadingButton loading={isLoading} fullWidth type="submit" variant="contained"> | ||
{isLoading ? "" : Language.passwordSignIn} | ||
</LoadingButton> | ||
</div> | ||
</Stack> | ||
</form> | ||
{authMethods?.github && ( | ||
<> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,6 @@ import { useActor } from "@xstate/react" | |
import React, { useContext } from "react" | ||
import { Helmet } from "react-helmet" | ||
import { Navigate, useLocation } from "react-router-dom" | ||
import { isApiError } from "../../api/errors" | ||
import { Footer } from "../../components/Footer/Footer" | ||
import { SignInForm } from "../../components/SignInForm/SignInForm" | ||
import { pageTitle } from "../../util/page" | ||
|
@@ -36,12 +35,6 @@ export const LoginPage: React.FC = () => { | |
const [authState, authSend] = useActor(xServices.authXService) | ||
const isLoading = authState.hasTag("loading") | ||
const redirectTo = retrieveRedirect(location.search) | ||
const authErrorMessage = isApiError(authState.context.authError) | ||
? authState.context.authError.response.data.message | ||
: undefined | ||
const getMethodsError = authState.context.getMethodsError | ||
? (authState.context.getMethodsError as Error).message | ||
: undefined | ||
|
||
const onSubmit = async ({ email, password }: { email: string; password: string }) => { | ||
authSend({ type: "SIGN_IN", email, password }) | ||
|
@@ -61,8 +54,8 @@ export const LoginPage: React.FC = () => { | |
authMethods={authState.context.methods} | ||
redirectTo={redirectTo} | ||
isLoading={isLoading} | ||
authErrorMessage={authErrorMessage} | ||
methodsErrorMessage={getMethodsError} | ||
authError={authState.context.authError} | ||
methodsError={authState.context.getMethodsError as Error} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we have to override the compiler here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Additionally, I don't know a good way to produce a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really think we do have to override it. I'm guessing that ended up in there originally to make it so we didn't have to add |
||
onSubmit={onSubmit} | ||
/> | ||
</div> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'm being dense :) but why do we call this method with
authError
and notmethodsError
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
methodsError
is not linked to the sign-in form. This method attributes form errors to specific fields in the form.