(null);
- useEffect(() => {
- clearRecoveryFragment();
- }, []);
const {form, isLoading, error, fieldErrors} = useAuthForm({
initialValues: {
login: fragment.username,
@@ -137,21 +136,27 @@ const RecoverAccountPageContent = observer(function RecoverAccountPageContent({
setMfaChallenge(result.challenge);
return false;
}
- showRecoveredKit(result.payload, {...result.kit, login});
- await AuthenticationCommands.completeLogin({...result.payload, runtimeSnapshot});
+ try {
+ await onRecovered(result.payload);
+ } finally {
+ showRecoveredKit(result.payload, {...result.kit, login});
+ }
return undefined;
},
firstFieldName: 'login',
});
const handleMfaSuccess = useCallback(
async (payload: LoginSuccessPayload) => {
- if (pendingKit) {
- showRecoveredKit(payload, pendingKit);
+ try {
+ await onRecovered(payload);
+ AuthenticationCommands.clearMfaTicket();
+ } finally {
+ if (pendingKit) {
+ showRecoveredKit(payload, pendingKit);
+ }
}
- await AuthenticationCommands.completeLogin({...payload, runtimeSnapshot});
- AuthenticationCommands.clearMfaTicket();
},
- [pendingKit, runtimeSnapshot],
+ [onRecovered, pendingKit],
);
const handleMfaCancel = useCallback(() => {
AuthenticationCommands.clearMfaTicket();
@@ -265,11 +270,46 @@ const RecoverAccountPageContent = observer(function RecoverAccountPageContent({
No recovery kit? Ask an admin of this instance for a password reset link.
+ {footerLink}
+
+ >
+ );
+});
+
+interface RecoverAccountPageContentProps {
+ readonly runtimeSnapshot: RuntimeConfigSnapshot;
+}
+
+const RecoverAccountPageContent = observer(function RecoverAccountPageContent({
+ runtimeSnapshot,
+}: RecoverAccountPageContentProps) {
+ const {i18n} = useLingui();
+ const [fragment] = useState(readRecoveryFragment);
+ const usernameSignIn = usesUsernameSignIn(runtimeSnapshot.features);
+ useEffect(() => {
+ if (!usernameSignIn) {
+ RouterUtils.replaceWith(Routes.LOGIN);
+ }
+ }, [usernameSignIn]);
+ useEffect(() => {
+ clearRecoveryFragment();
+ }, []);
+ const handleRecovered = useCallback(
+ (payload: LoginSuccessPayload) => AuthenticationCommands.completeLogin({...payload, runtimeSnapshot}),
+ [runtimeSnapshot],
+ );
+ return (
+
{i18n._(BACK_TO_SIGN_IN_DESCRIPTOR)}
-
- >
+ }
+ onRecovered={handleRecovered}
+ data-flx="auth.recover-account-page.recover-account-form"
+ />
);
});
diff --git a/fluxer_app/src/features/auth/flow/AuthLoginLayout.tsx b/fluxer_app/src/features/auth/flow/AuthLoginLayout.tsx
index c7090fc26..6d4e97925 100644
--- a/fluxer_app/src/features/auth/flow/AuthLoginLayout.tsx
+++ b/fluxer_app/src/features/auth/flow/AuthLoginLayout.tsx
@@ -903,23 +903,23 @@ export const AuthLoginLayout = observer(function AuthLoginLayout({
};
const renderCredentialStep = (): ReactNode => {
const forgotPasswordLink =
- identifierField === 'login' ? (
-
- {i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
-
- ) : (
- resolveForgotPasswordLink(
- emailsEnabled,
- forgotPasswordAction,
-
- {i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
- ,
- )
- );
+ identifierField === 'login'
+ ? (forgotPasswordAction ?? (
+
+ {i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
+
+ ))
+ : resolveForgotPasswordLink(
+ emailsEnabled,
+ forgotPasswordAction,
+
+ {i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
+ ,
+ );
return (
({
- snapshot: {apiEndpoint: 'https://instance.example/api', apiCodeVersion: 7} as RuntimeConfigSnapshot,
+ snapshot: {apiEndpoint: 'https://instance.example/api', apiCodeVersion: 7, features: {}} as RuntimeConfigSnapshot,
reset: vi.fn(),
completeLogin: vi.fn(),
search: '',
diff --git a/fluxer_app/src/features/auth/flow/ResourceAuthPages.tsx b/fluxer_app/src/features/auth/flow/ResourceAuthPages.tsx
index 418bf6711..ddb44e781 100644
--- a/fluxer_app/src/features/auth/flow/ResourceAuthPages.tsx
+++ b/fluxer_app/src/features/auth/flow/ResourceAuthPages.tsx
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import type {RuntimeConfigSnapshot} from '@app/features/app/state/InstanceSnapshotStore';
+import {usesUsernameSignIn} from '@app/features/app/utils/AccountIdentityFeatures';
import * as AuthenticationCommands from '@app/features/auth/commands/AuthenticationCommands';
import {AuthBottomLink} from '@app/features/auth/flow/AuthBottomLink';
import {AuthErrorState} from '@app/features/auth/flow/AuthErrorState';
@@ -163,6 +164,7 @@ const ResourceAuthContent = observer(function ResourceAuthContent({
);
const runtimeSso = resolveAuthPanelSso(runtimeSnapshot);
const sso = runtimeSso?.enabled === true && runtimeSso.enforced === true;
+ const usernameSignIn = usesUsernameSignIn(runtimeSnapshot.features);
const header = (
<>
({
/>
) : (
);
}
+ const usernameSignIn = usesUsernameSignIn(runtimeSnapshot.features);
return (
<>