mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 21:15:32 +09:00
fix(app): follow username-only sign-in in every auth flow (#3432)
This commit is contained in:
1 parent
30b32c9a35
commit
44799dafa2
8 files changed
+142
-53
No files matched your search
+27
-3
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import type {RuntimeConfigSnapshot} from '@app/features/app/state/InstanceSnapshotStore';
|
import type {RuntimeConfigSnapshot} from '@app/features/app/state/InstanceSnapshotStore';
|
||||||
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
|
import RuntimeConfig from '@app/features/app/state/RuntimeConfig';
|
||||||
|
import {usesUsernameSignIn} from '@app/features/app/utils/AccountIdentityFeatures';
|
||||||
import * as AuthenticationCommands from '@app/features/auth/commands/AuthenticationCommands';
|
import * as AuthenticationCommands from '@app/features/auth/commands/AuthenticationCommands';
|
||||||
import {AccountSwitcherAuthShell} from '@app/features/auth/components/accounts/account_switcher_modal/AccountSwitcherAuthShell';
|
import {AccountSwitcherAuthShell} from '@app/features/auth/components/accounts/account_switcher_modal/AccountSwitcherAuthShell';
|
||||||
import {
|
import {
|
||||||
@@ -12,6 +13,7 @@ import {
|
|||||||
import {AccountSwitcherLoginStep} from '@app/features/auth/components/accounts/account_switcher_modal/AccountSwitcherLoginStep';
|
import {AccountSwitcherLoginStep} from '@app/features/auth/components/accounts/account_switcher_modal/AccountSwitcherLoginStep';
|
||||||
import {AccountSwitcherRegisterStep} from '@app/features/auth/components/accounts/account_switcher_modal/AccountSwitcherRegisterStep';
|
import {AccountSwitcherRegisterStep} from '@app/features/auth/components/accounts/account_switcher_modal/AccountSwitcherRegisterStep';
|
||||||
import forgotStyles from '@app/features/auth/components/pages/ForgotPasswordPage.module.css';
|
import forgotStyles from '@app/features/auth/components/pages/ForgotPasswordPage.module.css';
|
||||||
|
import {RecoverAccountForm} from '@app/features/auth/components/pages/RecoverAccountPage';
|
||||||
import {shouldRenderInstanceStep} from '@app/features/auth/flow/auth_login_core/AuthLoginInstanceStep';
|
import {shouldRenderInstanceStep} from '@app/features/auth/flow/auth_login_core/AuthLoginInstanceStep';
|
||||||
import {ForgotPasswordForm} from '@app/features/auth/flow/ForgotPasswordForm';
|
import {ForgotPasswordForm} from '@app/features/auth/flow/ForgotPasswordForm';
|
||||||
import MFAScreen from '@app/features/auth/flow/MfaScreen';
|
import MFAScreen from '@app/features/auth/flow/MfaScreen';
|
||||||
@@ -102,7 +104,7 @@ export const AccountSwitcherAuthFlow = observer(function AccountSwitcherAuthFlow
|
|||||||
const mfaMethods = Authentication.availableMfaMethods;
|
const mfaMethods = Authentication.availableMfaMethods;
|
||||||
const hasMfaChallenge = mfaChallengePurpose === purpose && mfaTicket != null && mfaMethods != null;
|
const hasMfaChallenge = mfaChallengePurpose === purpose && mfaTicket != null && mfaMethods != null;
|
||||||
let authStep: AccountSwitcherAuthStep;
|
let authStep: AccountSwitcherAuthStep;
|
||||||
if (hasMfaChallenge) {
|
if (hasMfaChallenge && selectedAuthStep !== AccountSwitcherAuthStep.FORGOT) {
|
||||||
authStep = AccountSwitcherAuthStep.MFA;
|
authStep = AccountSwitcherAuthStep.MFA;
|
||||||
} else {
|
} else {
|
||||||
authStep = selectedAuthStep;
|
authStep = selectedAuthStep;
|
||||||
@@ -148,6 +150,14 @@ export const AccountSwitcherAuthFlow = observer(function AccountSwitcherAuthFlow
|
|||||||
},
|
},
|
||||||
[authRuntimeTarget, onLoginComplete, redirectAfterLogin],
|
[authRuntimeTarget, onLoginComplete, redirectAfterLogin],
|
||||||
);
|
);
|
||||||
|
const handleAccountRecovered = useCallback(
|
||||||
|
async (payload: LoginSuccessPayload) => {
|
||||||
|
const runtimeSnapshot = requireSelectedRuntimeSnapshot(authRuntimeTarget);
|
||||||
|
await AuthenticationCommands.completeLogin({...payload, runtimeSnapshot}, {redirectPath: redirectAfterLogin});
|
||||||
|
await onLoginComplete(payload);
|
||||||
|
},
|
||||||
|
[authRuntimeTarget, onLoginComplete, redirectAfterLogin],
|
||||||
|
);
|
||||||
const handleRegisterComplete = useCallback(
|
const handleRegisterComplete = useCallback(
|
||||||
async (response: AuthenticationCommands.TokenResponse) => {
|
async (response: AuthenticationCommands.TokenResponse) => {
|
||||||
const runtimeSnapshot = requireSelectedRuntimeSnapshot(authRuntimeTarget);
|
const runtimeSnapshot = requireSelectedRuntimeSnapshot(authRuntimeTarget);
|
||||||
@@ -168,7 +178,10 @@ export const AccountSwitcherAuthFlow = observer(function AccountSwitcherAuthFlow
|
|||||||
AuthenticationCommands.clearMfaTicket();
|
AuthenticationCommands.clearMfaTicket();
|
||||||
return;
|
return;
|
||||||
case AccountSwitcherAuthStep.REGISTER:
|
case AccountSwitcherAuthStep.REGISTER:
|
||||||
|
showLoginStep();
|
||||||
|
return;
|
||||||
case AccountSwitcherAuthStep.FORGOT:
|
case AccountSwitcherAuthStep.FORGOT:
|
||||||
|
AuthenticationCommands.clearMfaTicket();
|
||||||
showLoginStep();
|
showLoginStep();
|
||||||
return;
|
return;
|
||||||
case AccountSwitcherAuthStep.LOGIN:
|
case AccountSwitcherAuthStep.LOGIN:
|
||||||
@@ -203,14 +216,25 @@ export const AccountSwitcherAuthFlow = observer(function AccountSwitcherAuthFlow
|
|||||||
data-flx="auth.accounts.account-switcher-modal.account-switcher-auth-flow.register-step"
|
data-flx="auth.accounts.account-switcher-modal.account-switcher-auth-flow.register-step"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case AccountSwitcherAuthStep.FORGOT:
|
case AccountSwitcherAuthStep.FORGOT: {
|
||||||
|
const runtimeSnapshot = requireSelectedRuntimeSnapshot(authRuntimeTarget);
|
||||||
|
if (usesUsernameSignIn(runtimeSnapshot.features)) {
|
||||||
|
return (
|
||||||
|
<RecoverAccountForm
|
||||||
|
runtimeSnapshot={runtimeSnapshot}
|
||||||
|
onRecovered={handleAccountRecovered}
|
||||||
|
data-flx="auth.accounts.account-switcher-modal.account-switcher-auth-flow.recover-account-step"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<ForgotPasswordForm
|
<ForgotPasswordForm
|
||||||
runtimeSnapshot={requireSelectedRuntimeSnapshot(authRuntimeTarget)}
|
runtimeSnapshot={runtimeSnapshot}
|
||||||
renderContainer={renderForgotPasswordContainer}
|
renderContainer={renderForgotPasswordContainer}
|
||||||
data-flx="auth.accounts.account-switcher-modal.account-switcher-auth-flow.forgot-password-step"
|
data-flx="auth.accounts.account-switcher-modal.account-switcher-auth-flow.forgot-password-step"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
case AccountSwitcherAuthStep.LOGIN:
|
case AccountSwitcherAuthStep.LOGIN:
|
||||||
return (
|
return (
|
||||||
<AccountSwitcherLoginStep
|
<AccountSwitcherLoginStep
|
||||||
|
|||||||
+1
@@ -59,6 +59,7 @@ export const AccountSwitcherRegisterStep = observer(function AccountSwitcherRegi
|
|||||||
}}
|
}}
|
||||||
submitLabel={<Trans>Create account</Trans>}
|
submitLabel={<Trans>Create account</Trans>}
|
||||||
redirectPath=""
|
redirectPath=""
|
||||||
|
offerRecoveryKit={usernameSignIn}
|
||||||
runtimeSnapshot={runtimeSnapshot}
|
runtimeSnapshot={runtimeSnapshot}
|
||||||
onRegister={onRegister}
|
onRegister={onRegister}
|
||||||
showLegalConsent
|
showLegalConsent
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {formatRecoveryKeyInput} from '@fluxer/constants/src/RecoveryKeyUtils';
|
|||||||
import {msg} from '@lingui/core/macro';
|
import {msg} from '@lingui/core/macro';
|
||||||
import {Trans, useLingui} from '@lingui/react/macro';
|
import {Trans, useLingui} from '@lingui/react/macro';
|
||||||
import {observer} from 'mobx-react-lite';
|
import {observer} from 'mobx-react-lite';
|
||||||
|
import type {ReactNode} from 'react';
|
||||||
import {useCallback, useEffect, useId, useState} from 'react';
|
import {useCallback, useEffect, useId, useState} from 'react';
|
||||||
|
|
||||||
const RECOVER_ACCOUNT_DESCRIPTOR = msg({
|
const RECOVER_ACCOUNT_DESCRIPTOR = msg({
|
||||||
@@ -88,30 +89,28 @@ function showRecoveredKit(payload: LoginSuccessPayload, kit: PendingRecoveryKit)
|
|||||||
rememberRecoveryKit(payload.userId, kit.createdAt);
|
rememberRecoveryKit(payload.userId, kit.createdAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RecoverAccountPageContentProps {
|
const EMPTY_RECOVERY_FRAGMENT: RecoveryFragment = {username: '', key: ''};
|
||||||
|
|
||||||
|
interface RecoverAccountFormProps {
|
||||||
readonly runtimeSnapshot: RuntimeConfigSnapshot;
|
readonly runtimeSnapshot: RuntimeConfigSnapshot;
|
||||||
|
readonly fragment?: RecoveryFragment;
|
||||||
|
readonly footerLink?: ReactNode;
|
||||||
|
readonly onRecovered: (payload: LoginSuccessPayload) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RecoverAccountPageContent = observer(function RecoverAccountPageContent({
|
export const RecoverAccountForm = observer(function RecoverAccountForm({
|
||||||
runtimeSnapshot,
|
runtimeSnapshot,
|
||||||
}: RecoverAccountPageContentProps) {
|
fragment = EMPTY_RECOVERY_FRAGMENT,
|
||||||
|
footerLink,
|
||||||
|
onRecovered,
|
||||||
|
}: RecoverAccountFormProps) {
|
||||||
const {i18n} = useLingui();
|
const {i18n} = useLingui();
|
||||||
const loginId = useId();
|
const loginId = useId();
|
||||||
const keyId = useId();
|
const keyId = useId();
|
||||||
const passwordId = useId();
|
const passwordId = useId();
|
||||||
const confirmPasswordId = useId();
|
const confirmPasswordId = useId();
|
||||||
const [fragment] = useState(readRecoveryFragment);
|
|
||||||
const usernameSignIn = usesUsernameSignIn(runtimeSnapshot.features);
|
|
||||||
useEffect(() => {
|
|
||||||
if (!usernameSignIn) {
|
|
||||||
RouterUtils.replaceWith(Routes.LOGIN);
|
|
||||||
}
|
|
||||||
}, [usernameSignIn]);
|
|
||||||
const [mfaChallenge, setMfaChallenge] = useState<MfaChallenge | null>(null);
|
const [mfaChallenge, setMfaChallenge] = useState<MfaChallenge | null>(null);
|
||||||
const [pendingKit, setPendingKit] = useState<PendingRecoveryKit | null>(null);
|
const [pendingKit, setPendingKit] = useState<PendingRecoveryKit | null>(null);
|
||||||
useEffect(() => {
|
|
||||||
clearRecoveryFragment();
|
|
||||||
}, []);
|
|
||||||
const {form, isLoading, error, fieldErrors} = useAuthForm({
|
const {form, isLoading, error, fieldErrors} = useAuthForm({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
login: fragment.username,
|
login: fragment.username,
|
||||||
@@ -137,21 +136,27 @@ const RecoverAccountPageContent = observer(function RecoverAccountPageContent({
|
|||||||
setMfaChallenge(result.challenge);
|
setMfaChallenge(result.challenge);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
showRecoveredKit(result.payload, {...result.kit, login});
|
try {
|
||||||
await AuthenticationCommands.completeLogin({...result.payload, runtimeSnapshot});
|
await onRecovered(result.payload);
|
||||||
|
} finally {
|
||||||
|
showRecoveredKit(result.payload, {...result.kit, login});
|
||||||
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
firstFieldName: 'login',
|
firstFieldName: 'login',
|
||||||
});
|
});
|
||||||
const handleMfaSuccess = useCallback(
|
const handleMfaSuccess = useCallback(
|
||||||
async (payload: LoginSuccessPayload) => {
|
async (payload: LoginSuccessPayload) => {
|
||||||
if (pendingKit) {
|
try {
|
||||||
showRecoveredKit(payload, pendingKit);
|
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(() => {
|
const handleMfaCancel = useCallback(() => {
|
||||||
AuthenticationCommands.clearMfaTicket();
|
AuthenticationCommands.clearMfaTicket();
|
||||||
@@ -265,11 +270,46 @@ const RecoverAccountPageContent = observer(function RecoverAccountPageContent({
|
|||||||
<p className={styles.hint} data-flx="auth.recover-account-page.no-kit-hint">
|
<p className={styles.hint} data-flx="auth.recover-account-page.no-kit-hint">
|
||||||
<Trans>No recovery kit? Ask an admin of this instance for a password reset link.</Trans>
|
<Trans>No recovery kit? Ask an admin of this instance for a password reset link.</Trans>
|
||||||
</p>
|
</p>
|
||||||
|
{footerLink}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<RecoverAccountForm
|
||||||
|
runtimeSnapshot={runtimeSnapshot}
|
||||||
|
fragment={fragment}
|
||||||
|
footerLink={
|
||||||
<AuthRouterLink to={Routes.LOGIN} className={styles.link} data-flx="auth.recover-account-page.link">
|
<AuthRouterLink to={Routes.LOGIN} className={styles.link} data-flx="auth.recover-account-page.link">
|
||||||
{i18n._(BACK_TO_SIGN_IN_DESCRIPTOR)}
|
{i18n._(BACK_TO_SIGN_IN_DESCRIPTOR)}
|
||||||
</AuthRouterLink>
|
</AuthRouterLink>
|
||||||
</div>
|
}
|
||||||
</>
|
onRecovered={handleRecovered}
|
||||||
|
data-flx="auth.recover-account-page.recover-account-form"
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -903,23 +903,23 @@ export const AuthLoginLayout = observer(function AuthLoginLayout({
|
|||||||
};
|
};
|
||||||
const renderCredentialStep = (): ReactNode => {
|
const renderCredentialStep = (): ReactNode => {
|
||||||
const forgotPasswordLink =
|
const forgotPasswordLink =
|
||||||
identifierField === 'login' ? (
|
identifierField === 'login'
|
||||||
<AuthRouterLink
|
? (forgotPasswordAction ?? (
|
||||||
to={Routes.RECOVER_ACCOUNT}
|
<AuthRouterLink
|
||||||
className={styles.link}
|
to={Routes.RECOVER_ACCOUNT}
|
||||||
data-flx="auth.flow.auth-login-layout.link.recover"
|
className={styles.link}
|
||||||
>
|
data-flx="auth.flow.auth-login-layout.link.recover"
|
||||||
{i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
|
>
|
||||||
</AuthRouterLink>
|
{i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
|
||||||
) : (
|
</AuthRouterLink>
|
||||||
resolveForgotPasswordLink(
|
))
|
||||||
emailsEnabled,
|
: resolveForgotPasswordLink(
|
||||||
forgotPasswordAction,
|
emailsEnabled,
|
||||||
<AuthRouterLink to="/forgot" className={styles.link} data-flx="auth.flow.auth-login-layout.link">
|
forgotPasswordAction,
|
||||||
{i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
|
<AuthRouterLink to="/forgot" className={styles.link} data-flx="auth.flow.auth-login-layout.link">
|
||||||
</AuthRouterLink>,
|
{i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
|
||||||
)
|
</AuthRouterLink>,
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<AuthLoginCredentialStepPanel
|
<AuthLoginCredentialStepPanel
|
||||||
extraTopContent={extraTopContent}
|
extraTopContent={extraTopContent}
|
||||||
|
|||||||
@@ -256,14 +256,14 @@ export const AuthRegisterFormCore = observer(function AuthRegisterFormCore({
|
|||||||
...(userData ? {userData} : {}),
|
...(userData ? {userData} : {}),
|
||||||
runtimeSnapshot,
|
runtimeSnapshot,
|
||||||
});
|
});
|
||||||
if (offerRecoveryKit && showPassword && values.password) {
|
}
|
||||||
void createRecoveryKitWithPasswordAndOpen({
|
if (offerRecoveryKit && showPassword && values.password) {
|
||||||
userId: response.user_id,
|
void createRecoveryKitWithPasswordAndOpen({
|
||||||
password: values.password,
|
userId: response.user_id,
|
||||||
username: response.user?.username,
|
password: values.password,
|
||||||
discriminator: response.user?.discriminator,
|
username: response.user?.username,
|
||||||
});
|
discriminator: response.user?.discriminator,
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
onAuthenticated?.();
|
onAuthenticated?.();
|
||||||
clearRegisterFormDraft(draftKey);
|
clearRegisterFormDraft(draftKey);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {renderToStaticMarkup} from 'react-dom/server';
|
|||||||
import {beforeEach, describe, expect, it, vi} from 'vitest';
|
import {beforeEach, describe, expect, it, vi} from 'vitest';
|
||||||
|
|
||||||
const mocks = vi.hoisted(() => ({
|
const mocks = vi.hoisted(() => ({
|
||||||
snapshot: {apiEndpoint: 'https://instance.example/api', apiCodeVersion: 7} as RuntimeConfigSnapshot,
|
snapshot: {apiEndpoint: 'https://instance.example/api', apiCodeVersion: 7, features: {}} as RuntimeConfigSnapshot,
|
||||||
reset: vi.fn(),
|
reset: vi.fn(),
|
||||||
completeLogin: vi.fn(),
|
completeLogin: vi.fn(),
|
||||||
search: '',
|
search: '',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
import type {RuntimeConfigSnapshot} from '@app/features/app/state/InstanceSnapshotStore';
|
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 * as AuthenticationCommands from '@app/features/auth/commands/AuthenticationCommands';
|
||||||
import {AuthBottomLink} from '@app/features/auth/flow/AuthBottomLink';
|
import {AuthBottomLink} from '@app/features/auth/flow/AuthBottomLink';
|
||||||
import {AuthErrorState} from '@app/features/auth/flow/AuthErrorState';
|
import {AuthErrorState} from '@app/features/auth/flow/AuthErrorState';
|
||||||
@@ -163,6 +164,7 @@ const ResourceAuthContent = observer(function ResourceAuthContent<T>({
|
|||||||
);
|
);
|
||||||
const runtimeSso = resolveAuthPanelSso(runtimeSnapshot);
|
const runtimeSso = resolveAuthPanelSso(runtimeSnapshot);
|
||||||
const sso = runtimeSso?.enabled === true && runtimeSso.enforced === true;
|
const sso = runtimeSso?.enabled === true && runtimeSso.enforced === true;
|
||||||
|
const usernameSignIn = usesUsernameSignIn(runtimeSnapshot.features);
|
||||||
const header = (
|
const header = (
|
||||||
<>
|
<>
|
||||||
<DesktopDeepLinkPrompt
|
<DesktopDeepLinkPrompt
|
||||||
@@ -185,9 +187,19 @@ const ResourceAuthContent = observer(function ResourceAuthContent<T>({
|
|||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<AuthRegisterFormCore
|
<AuthRegisterFormCore
|
||||||
fields={{showUsername: false}}
|
fields={
|
||||||
|
usernameSignIn
|
||||||
|
? {
|
||||||
|
showPassword: true,
|
||||||
|
showPasswordConfirmation: true,
|
||||||
|
showUsernameValidation: true,
|
||||||
|
requireUsername: true,
|
||||||
|
}
|
||||||
|
: {showUsername: false}
|
||||||
|
}
|
||||||
submitLabel={config.submitLabel}
|
submitLabel={config.submitLabel}
|
||||||
redirectPath={config.registerRedirectPath(id, safeRedirect)}
|
redirectPath={config.registerRedirectPath(id, safeRedirect)}
|
||||||
|
offerRecoveryKit={usernameSignIn}
|
||||||
onRegister={onRegisterComplete}
|
onRegister={onRegisterComplete}
|
||||||
runtimeSnapshot={runtimeSnapshot}
|
runtimeSnapshot={runtimeSnapshot}
|
||||||
onAuthenticated={runtimeTarget.reset}
|
onAuthenticated={runtimeTarget.reset}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import {Routes} from '@app/app/Routes';
|
import {Routes} from '@app/app/Routes';
|
||||||
import type {RuntimeConfigSnapshot} from '@app/features/app/state/InstanceSnapshotStore';
|
import type {RuntimeConfigSnapshot} from '@app/features/app/state/InstanceSnapshotStore';
|
||||||
|
import {usesUsernameSignIn} from '@app/features/app/utils/AccountIdentityFeatures';
|
||||||
import {AuthBottomLink} from '@app/features/auth/flow/AuthBottomLink';
|
import {AuthBottomLink} from '@app/features/auth/flow/AuthBottomLink';
|
||||||
import sharedStyles from '@app/features/auth/flow/AuthPageStyles.module.css';
|
import sharedStyles from '@app/features/auth/flow/AuthPageStyles.module.css';
|
||||||
import {AuthRegisterFormCore} from '@app/features/auth/flow/AuthRegisterFormCore';
|
import {AuthRegisterFormCore} from '@app/features/auth/flow/AuthRegisterFormCore';
|
||||||
@@ -92,6 +93,7 @@ const InviteRegisterPageContent = observer(function InviteRegisterPageContent({
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const usernameSignIn = usesUsernameSignIn(runtimeSnapshot.features);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DesktopDeepLinkPrompt
|
<DesktopDeepLinkPrompt
|
||||||
@@ -102,9 +104,19 @@ const InviteRegisterPageContent = observer(function InviteRegisterPageContent({
|
|||||||
<InviteHeader invite={invite} data-flx="invite.invite-register-page.invite-header" />
|
<InviteHeader invite={invite} data-flx="invite.invite-register-page.invite-header" />
|
||||||
<div className={sharedStyles.container} data-flx="invite.invite-register-page.div--4">
|
<div className={sharedStyles.container} data-flx="invite.invite-register-page.div--4">
|
||||||
<AuthRegisterFormCore
|
<AuthRegisterFormCore
|
||||||
fields={{showUsername: false}}
|
fields={
|
||||||
|
usernameSignIn
|
||||||
|
? {
|
||||||
|
showPassword: true,
|
||||||
|
showPasswordConfirmation: true,
|
||||||
|
showUsernameValidation: true,
|
||||||
|
requireUsername: true,
|
||||||
|
}
|
||||||
|
: {showUsername: false}
|
||||||
|
}
|
||||||
submitLabel={i18n._(CREATE_ACCOUNT_DESCRIPTOR)}
|
submitLabel={i18n._(CREATE_ACCOUNT_DESCRIPTOR)}
|
||||||
redirectPath="/"
|
redirectPath="/"
|
||||||
|
offerRecoveryKit={usernameSignIn}
|
||||||
inviteCode={code}
|
inviteCode={code}
|
||||||
runtimeSnapshot={runtimeSnapshot}
|
runtimeSnapshot={runtimeSnapshot}
|
||||||
onAuthenticated={runtimeTarget.reset}
|
onAuthenticated={runtimeTarget.reset}
|
||||||
|
|||||||
Reference in new issue
Block a user