Skip to content

Commit ff4dbe1

Browse files
authored
Merge pull request #18390 from mozilla/FXA-11153
fix(settings): Fix infinite re-render on SigninRecoveryChoice page
2 parents 5456de9 + 57d7955 commit ff4dbe1

1 file changed

Lines changed: 46 additions & 38 deletions

File tree

  • packages/fxa-settings/src/pages/Signin/SigninRecoveryChoice

packages/fxa-settings/src/pages/Signin/SigninRecoveryChoice/container.tsx

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
AuthUiErrors,
1616
} from '../../../lib/auth-errors/auth-errors';
1717
import { formatPhoneNumber } from '../../../lib/recovery-phone-utils';
18+
import { getHandledError, HandledError } from '../../../lib/error-utils';
1819

1920
export const SigninRecoveryChoiceContainer = (_: RouteComponentProps) => {
2021
const authClient = useAuthClient();
@@ -27,14 +28,16 @@ export const SigninRecoveryChoiceContainer = (_: RouteComponentProps) => {
2728

2829
const [numBackupCodes, setNumBackupCodes] = useState<number>(0);
2930
const [phoneData, setPhoneData] = useState({
31+
phoneNumber: '',
32+
nationalFormat: '',
3033
maskedPhoneNumber: '',
3134
lastFourPhoneDigits: '',
3235
});
3336
const [loading, setLoading] = useState(true);
37+
const [dataFetchError, setDataFetchError] = useState<HandledError>();
3438

3539
useEffect(() => {
3640
if (!signinState || !signinState.sessionToken) {
37-
navigateWithQuery('/signin');
3841
return;
3942
}
4043

@@ -47,54 +50,32 @@ export const SigninRecoveryChoiceContainer = (_: RouteComponentProps) => {
4750

4851
const { phoneNumber, nationalFormat } =
4952
await authClient.recoveryPhoneGet(signinState.sessionToken);
53+
5054
const { maskedPhoneNumber, lastFourPhoneDigits } = formatPhoneNumber({
5155
phoneNumber,
5256
nationalFormat,
5357
ftlMsgResolver,
5458
});
5559
setPhoneData({
60+
phoneNumber,
61+
nationalFormat,
5662
maskedPhoneNumber,
5763
lastFourPhoneDigits,
5864
});
59-
60-
// whether or not the user has backup authentication codes,
61-
// go directly to the backup authentication codes page if they don't have a phone number
62-
// do not render the choice screen
63-
if (!phoneNumber) {
64-
navigateWithQuery('/signin_recovery_code', {
65-
state: { signinState },
66-
// ensure back button on signin_recovery_code page skips choice page and returns to signin_totp_code
67-
replace: true,
68-
});
69-
return;
70-
}
71-
72-
if (phoneNumber && (!count || count === 0)) {
73-
navigateWithQuery('/signin_recovery_phone', {
74-
state: { signinState, lastFourPhoneDigits },
75-
// ensure back button on signin_recovery_code page skips choice page and returns to signin_totp_code
76-
replace: true,
77-
});
78-
}
7965
return;
8066
} catch (err) {
81-
if (err.errno === AuthUiErrors.INVALID_TOKEN.errno) {
82-
navigateWithQuery('/signin');
83-
return;
84-
}
85-
// if there was another error fetching available recovery methods, go to backup authentication codes page
86-
navigateWithQuery('/signin_recovery_code', {
87-
state: { signinState },
88-
// ensure back button on signin_recovery_code page skips choice page and returns to signin_totp_code
89-
replace: true,
90-
});
67+
const handledError = getHandledError(err);
68+
setDataFetchError(handledError.error);
9169
return;
9270
} finally {
9371
setLoading(false);
9472
}
9573
};
9674
fetchData();
97-
}, [authClient, signinState, navigateWithQuery, ftlMsgResolver]);
75+
// excluding ftlMsgResolver as it is causing re-renders
76+
// but should be stable and not changing at runtime
77+
// eslint-disable-next-line react-hooks/exhaustive-deps
78+
}, [authClient, signinState]);
9879

9980
const handlePhoneChoice = async () => {
10081
if (!signinState) {
@@ -115,16 +96,43 @@ export const SigninRecoveryChoiceContainer = (_: RouteComponentProps) => {
11596
}
11697
};
11798

99+
if (!signinState || !signinState.sessionToken) {
100+
navigateWithQuery('/signin');
101+
return;
102+
}
103+
118104
if (loading) {
119105
return <LoadingSpinner fullScreen />;
120106
}
121107

122-
if (
123-
!signinState ||
124-
!phoneData.maskedPhoneNumber ||
125-
!phoneData.lastFourPhoneDigits
126-
) {
127-
return <LoadingSpinner fullScreen />;
108+
if (dataFetchError) {
109+
if (dataFetchError.errno === AuthUiErrors.INVALID_TOKEN.errno) {
110+
navigateWithQuery('/signin');
111+
return;
112+
}
113+
// if there was another error fetching available recovery methods, go to backup authentication codes page
114+
navigateWithQuery('/signin_recovery_code', {
115+
state: { signinState },
116+
// ensure back button on signin_recovery_code page skips choice page and returns to signin_totp_code
117+
replace: true,
118+
});
119+
}
120+
if (!phoneData.phoneNumber) {
121+
navigateWithQuery('/signin_recovery_code', {
122+
state: { signinState },
123+
// ensure back button on signin_recovery_code page skips choice page and returns to signin_totp_code
124+
replace: true,
125+
});
126+
return;
127+
} else if (!numBackupCodes || numBackupCodes === 0) {
128+
navigateWithQuery('/signin_recovery_phone', {
129+
state: {
130+
signinState,
131+
lastFourPhoneDigits: phoneData.lastFourPhoneDigits,
132+
},
133+
// ensure back button on signin_recovery_code page skips choice page and returns to signin_totp_code
134+
replace: true,
135+
});
128136
}
129137

130138
return (

0 commit comments

Comments
 (0)