mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 04:55:42 +09:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44799dafa2 | ||
|
|
30b32c9a35 | ||
|
|
d1b4b82895 |
No files matched your search
+13
-2
@@ -17,14 +17,25 @@
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.selectorRoot {
|
||||
height: 45rem;
|
||||
}
|
||||
|
||||
.selectorContent {
|
||||
--selector-modal-content-height: clamp(20rem, 48vh, 23.75rem);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
:global(html.mobile-layout) .selectorRoot {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
:global(html.mobile-layout) .selectorContent {
|
||||
--selector-modal-content-height: clamp(20rem, 48vh, 23.75rem);
|
||||
height: var(--selector-modal-content-height);
|
||||
min-height: var(--selector-modal-content-height);
|
||||
max-height: var(--selector-modal-content-height);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.listContainer {
|
||||
|
||||
+27
-3
@@ -2,6 +2,7 @@
|
||||
|
||||
import type {RuntimeConfigSnapshot} from '@app/features/app/state/InstanceSnapshotStore';
|
||||
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 {AccountSwitcherAuthShell} from '@app/features/auth/components/accounts/account_switcher_modal/AccountSwitcherAuthShell';
|
||||
import {
|
||||
@@ -12,6 +13,7 @@ import {
|
||||
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 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 {ForgotPasswordForm} from '@app/features/auth/flow/ForgotPasswordForm';
|
||||
import MFAScreen from '@app/features/auth/flow/MfaScreen';
|
||||
@@ -102,7 +104,7 @@ export const AccountSwitcherAuthFlow = observer(function AccountSwitcherAuthFlow
|
||||
const mfaMethods = Authentication.availableMfaMethods;
|
||||
const hasMfaChallenge = mfaChallengePurpose === purpose && mfaTicket != null && mfaMethods != null;
|
||||
let authStep: AccountSwitcherAuthStep;
|
||||
if (hasMfaChallenge) {
|
||||
if (hasMfaChallenge && selectedAuthStep !== AccountSwitcherAuthStep.FORGOT) {
|
||||
authStep = AccountSwitcherAuthStep.MFA;
|
||||
} else {
|
||||
authStep = selectedAuthStep;
|
||||
@@ -148,6 +150,14 @@ export const AccountSwitcherAuthFlow = observer(function AccountSwitcherAuthFlow
|
||||
},
|
||||
[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(
|
||||
async (response: AuthenticationCommands.TokenResponse) => {
|
||||
const runtimeSnapshot = requireSelectedRuntimeSnapshot(authRuntimeTarget);
|
||||
@@ -168,7 +178,10 @@ export const AccountSwitcherAuthFlow = observer(function AccountSwitcherAuthFlow
|
||||
AuthenticationCommands.clearMfaTicket();
|
||||
return;
|
||||
case AccountSwitcherAuthStep.REGISTER:
|
||||
showLoginStep();
|
||||
return;
|
||||
case AccountSwitcherAuthStep.FORGOT:
|
||||
AuthenticationCommands.clearMfaTicket();
|
||||
showLoginStep();
|
||||
return;
|
||||
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"
|
||||
/>
|
||||
);
|
||||
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 (
|
||||
<ForgotPasswordForm
|
||||
runtimeSnapshot={requireSelectedRuntimeSnapshot(authRuntimeTarget)}
|
||||
runtimeSnapshot={runtimeSnapshot}
|
||||
renderContainer={renderForgotPasswordContainer}
|
||||
data-flx="auth.accounts.account-switcher-modal.account-switcher-auth-flow.forgot-password-step"
|
||||
/>
|
||||
);
|
||||
}
|
||||
case AccountSwitcherAuthStep.LOGIN:
|
||||
return (
|
||||
<AccountSwitcherLoginStep
|
||||
|
||||
+5
-1
@@ -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 type * as AuthenticationCommands from '@app/features/auth/commands/AuthenticationCommands';
|
||||
import authStyles from '@app/features/auth/components/accounts/account_switcher_modal/AccountSwitcherAuthFlow.module.css';
|
||||
import pageStyles from '@app/features/auth/flow/AuthPageStyles.module.css';
|
||||
@@ -35,6 +36,7 @@ export const AccountSwitcherRegisterStep = observer(function AccountSwitcherRegi
|
||||
/>
|
||||
);
|
||||
}
|
||||
const usernameSignIn = usesUsernameSignIn(runtimeSnapshot.features);
|
||||
return (
|
||||
<>
|
||||
<h1
|
||||
@@ -49,13 +51,15 @@ export const AccountSwitcherRegisterStep = observer(function AccountSwitcherRegi
|
||||
>
|
||||
<AuthRegisterFormCore
|
||||
fields={{
|
||||
showEmail: true,
|
||||
showEmail: !usernameSignIn,
|
||||
showPassword: true,
|
||||
showPasswordConfirmation: true,
|
||||
showUsernameValidation: true,
|
||||
requireUsername: usernameSignIn,
|
||||
}}
|
||||
submitLabel={<Trans>Create account</Trans>}
|
||||
redirectPath=""
|
||||
offerRecoveryKit={usernameSignIn}
|
||||
runtimeSnapshot={runtimeSnapshot}
|
||||
onRegister={onRegister}
|
||||
showLegalConsent
|
||||
|
||||
@@ -23,6 +23,7 @@ import {formatRecoveryKeyInput} from '@fluxer/constants/src/RecoveryKeyUtils';
|
||||
import {msg} from '@lingui/core/macro';
|
||||
import {Trans, useLingui} from '@lingui/react/macro';
|
||||
import {observer} from 'mobx-react-lite';
|
||||
import type {ReactNode} from 'react';
|
||||
import {useCallback, useEffect, useId, useState} from 'react';
|
||||
|
||||
const RECOVER_ACCOUNT_DESCRIPTOR = msg({
|
||||
@@ -88,30 +89,28 @@ function showRecoveredKit(payload: LoginSuccessPayload, kit: PendingRecoveryKit)
|
||||
rememberRecoveryKit(payload.userId, kit.createdAt);
|
||||
}
|
||||
|
||||
interface RecoverAccountPageContentProps {
|
||||
const EMPTY_RECOVERY_FRAGMENT: RecoveryFragment = {username: '', key: ''};
|
||||
|
||||
interface RecoverAccountFormProps {
|
||||
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,
|
||||
}: RecoverAccountPageContentProps) {
|
||||
fragment = EMPTY_RECOVERY_FRAGMENT,
|
||||
footerLink,
|
||||
onRecovered,
|
||||
}: RecoverAccountFormProps) {
|
||||
const {i18n} = useLingui();
|
||||
const loginId = useId();
|
||||
const keyId = useId();
|
||||
const passwordId = 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 [pendingKit, setPendingKit] = useState<PendingRecoveryKit | null>(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({
|
||||
<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>
|
||||
</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">
|
||||
{i18n._(BACK_TO_SIGN_IN_DESCRIPTOR)}
|
||||
</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 forgotPasswordLink =
|
||||
identifierField === 'login' ? (
|
||||
<AuthRouterLink
|
||||
to={Routes.RECOVER_ACCOUNT}
|
||||
className={styles.link}
|
||||
data-flx="auth.flow.auth-login-layout.link.recover"
|
||||
>
|
||||
{i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
|
||||
</AuthRouterLink>
|
||||
) : (
|
||||
resolveForgotPasswordLink(
|
||||
emailsEnabled,
|
||||
forgotPasswordAction,
|
||||
<AuthRouterLink to="/forgot" className={styles.link} data-flx="auth.flow.auth-login-layout.link">
|
||||
{i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
|
||||
</AuthRouterLink>,
|
||||
)
|
||||
);
|
||||
identifierField === 'login'
|
||||
? (forgotPasswordAction ?? (
|
||||
<AuthRouterLink
|
||||
to={Routes.RECOVER_ACCOUNT}
|
||||
className={styles.link}
|
||||
data-flx="auth.flow.auth-login-layout.link.recover"
|
||||
>
|
||||
{i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
|
||||
</AuthRouterLink>
|
||||
))
|
||||
: resolveForgotPasswordLink(
|
||||
emailsEnabled,
|
||||
forgotPasswordAction,
|
||||
<AuthRouterLink to="/forgot" className={styles.link} data-flx="auth.flow.auth-login-layout.link">
|
||||
{i18n._(FORGOT_YOUR_PASSWORD_DESCRIPTOR)}
|
||||
</AuthRouterLink>,
|
||||
);
|
||||
return (
|
||||
<AuthLoginCredentialStepPanel
|
||||
extraTopContent={extraTopContent}
|
||||
|
||||
@@ -256,14 +256,14 @@ export const AuthRegisterFormCore = observer(function AuthRegisterFormCore({
|
||||
...(userData ? {userData} : {}),
|
||||
runtimeSnapshot,
|
||||
});
|
||||
if (offerRecoveryKit && showPassword && values.password) {
|
||||
void createRecoveryKitWithPasswordAndOpen({
|
||||
userId: response.user_id,
|
||||
password: values.password,
|
||||
username: response.user?.username,
|
||||
discriminator: response.user?.discriminator,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (offerRecoveryKit && showPassword && values.password) {
|
||||
void createRecoveryKitWithPasswordAndOpen({
|
||||
userId: response.user_id,
|
||||
password: values.password,
|
||||
username: response.user?.username,
|
||||
discriminator: response.user?.discriminator,
|
||||
});
|
||||
}
|
||||
onAuthenticated?.();
|
||||
clearRegisterFormDraft(draftKey);
|
||||
|
||||
@@ -13,7 +13,7 @@ import {renderToStaticMarkup} from 'react-dom/server';
|
||||
import {beforeEach, describe, expect, it, vi} from 'vitest';
|
||||
|
||||
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(),
|
||||
completeLogin: vi.fn(),
|
||||
search: '',
|
||||
|
||||
@@ -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<T>({
|
||||
);
|
||||
const runtimeSso = resolveAuthPanelSso(runtimeSnapshot);
|
||||
const sso = runtimeSso?.enabled === true && runtimeSso.enforced === true;
|
||||
const usernameSignIn = usesUsernameSignIn(runtimeSnapshot.features);
|
||||
const header = (
|
||||
<>
|
||||
<DesktopDeepLinkPrompt
|
||||
@@ -185,9 +187,19 @@ const ResourceAuthContent = observer(function ResourceAuthContent<T>({
|
||||
/>
|
||||
) : (
|
||||
<AuthRegisterFormCore
|
||||
fields={{showUsername: false}}
|
||||
fields={
|
||||
usernameSignIn
|
||||
? {
|
||||
showPassword: true,
|
||||
showPasswordConfirmation: true,
|
||||
showUsernameValidation: true,
|
||||
requireUsername: true,
|
||||
}
|
||||
: {showUsername: false}
|
||||
}
|
||||
submitLabel={config.submitLabel}
|
||||
redirectPath={config.registerRedirectPath(id, safeRedirect)}
|
||||
offerRecoveryKit={usernameSignIn}
|
||||
onRegister={onRegisterComplete}
|
||||
runtimeSnapshot={runtimeSnapshot}
|
||||
onAuthenticated={runtimeTarget.reset}
|
||||
|
||||
@@ -45,7 +45,12 @@ export const CreateDMModal = observer((props: CreateDMModalProps) => {
|
||||
}
|
||||
}, [modalLogic]);
|
||||
return (
|
||||
<Modal.Root size="small" centered data-flx="channel.create-dm-modal.modal-root">
|
||||
<Modal.Root
|
||||
size="small"
|
||||
centered
|
||||
className={selectorStyles.selectorRoot}
|
||||
data-flx="channel.create-dm-modal.modal-root"
|
||||
>
|
||||
<Modal.Header title={i18n._(SELECT_FRIENDS_DESCRIPTOR)} data-flx="channel.create-dm-modal.modal-header">
|
||||
{!restriction && (
|
||||
<>
|
||||
|
||||
@@ -48,7 +48,12 @@ export const GiftSendToFriendModal = observer(function GiftSendToFriendModal({co
|
||||
const handleCopy = useCopyLinkHandler(giftUrl, true);
|
||||
const {sendingTo, sentTo, send: handleSendGift} = useSendLinkToRecipients(() => giftUrl);
|
||||
return (
|
||||
<Modal.Root size="small" centered data-flx="expressions.gift-send-to-friend-modal.modal-root">
|
||||
<Modal.Root
|
||||
size="small"
|
||||
centered
|
||||
className={selectorStyles.selectorRoot}
|
||||
data-flx="expressions.gift-send-to-friend-modal.modal-root"
|
||||
>
|
||||
<Modal.Header
|
||||
title={i18n._(YOU_ALREADY_HAVE_LIFETIME_DESCRIPTOR, {premiumProductName: getPremiumProductName()})}
|
||||
data-flx="expressions.gift-send-to-friend-modal.modal-header"
|
||||
|
||||
@@ -326,7 +326,12 @@ const InviteModalContent = observer(function InviteModalContent({
|
||||
return i18n._(YOUR_INVITE_LINK_EXPIRES_IN_SECONDS_DESCRIPTOR, {seconds});
|
||||
};
|
||||
return (
|
||||
<Modal.Root size="small" centered data-flx="invite.invite-modal.modal-root--2">
|
||||
<Modal.Root
|
||||
size="small"
|
||||
centered
|
||||
className={selectorStyles.selectorRoot}
|
||||
data-flx="invite.invite-modal.modal-root--2"
|
||||
>
|
||||
<Modal.Header
|
||||
title={!showAdvanced ? title : i18n._(INVITE_LINK_SETTINGS_DESCRIPTOR)}
|
||||
data-flx="invite.invite-modal.modal-header--2"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import {Routes} from '@app/app/Routes';
|
||||
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 sharedStyles from '@app/features/auth/flow/AuthPageStyles.module.css';
|
||||
import {AuthRegisterFormCore} from '@app/features/auth/flow/AuthRegisterFormCore';
|
||||
@@ -92,6 +93,7 @@ const InviteRegisterPageContent = observer(function InviteRegisterPageContent({
|
||||
</>
|
||||
);
|
||||
}
|
||||
const usernameSignIn = usesUsernameSignIn(runtimeSnapshot.features);
|
||||
return (
|
||||
<>
|
||||
<DesktopDeepLinkPrompt
|
||||
@@ -102,9 +104,19 @@ const InviteRegisterPageContent = observer(function InviteRegisterPageContent({
|
||||
<InviteHeader invite={invite} data-flx="invite.invite-register-page.invite-header" />
|
||||
<div className={sharedStyles.container} data-flx="invite.invite-register-page.div--4">
|
||||
<AuthRegisterFormCore
|
||||
fields={{showUsername: false}}
|
||||
fields={
|
||||
usernameSignIn
|
||||
? {
|
||||
showPassword: true,
|
||||
showPasswordConfirmation: true,
|
||||
showUsernameValidation: true,
|
||||
requireUsername: true,
|
||||
}
|
||||
: {showUsername: false}
|
||||
}
|
||||
submitLabel={i18n._(CREATE_ACCOUNT_DESCRIPTOR)}
|
||||
redirectPath="/"
|
||||
offerRecoveryKit={usernameSignIn}
|
||||
inviteCode={code}
|
||||
runtimeSnapshot={runtimeSnapshot}
|
||||
onAuthenticated={runtimeTarget.reset}
|
||||
|
||||
@@ -21,14 +21,6 @@
|
||||
caret-color: var(--text-chat);
|
||||
}
|
||||
|
||||
.destinationList {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: clamp(20rem, 48vh, 23.75rem);
|
||||
min-height: 0;
|
||||
max-height: clamp(20rem, 48vh, 23.75rem);
|
||||
}
|
||||
|
||||
.footerSection {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
||||
@@ -361,6 +361,7 @@ export const ForwardModal = observer(
|
||||
<Modal.Root
|
||||
size="small"
|
||||
centered
|
||||
className={selectorStyles.selectorRoot}
|
||||
initialFocusRef={shouldFocusSearch ? searchInputRef : undefined}
|
||||
data-flx="messaging.forward-modal.modal-root"
|
||||
>
|
||||
@@ -388,7 +389,7 @@ export const ForwardModal = observer(
|
||||
</Modal.Header>
|
||||
<Modal.Content
|
||||
padding="none"
|
||||
className={modalStyles.destinationList}
|
||||
className={selectorStyles.selectorContent}
|
||||
data-flx="messaging.forward-modal.modal-content"
|
||||
>
|
||||
<div className={selectorStyles.listContainer} data-flx="messaging.forward-modal.div--2">
|
||||
|
||||
@@ -48,7 +48,12 @@ export const AddFriendsToGroupModal = observer((props: AddFriendsToGroupModalPro
|
||||
? i18n._(LINK_HIDDEN_WHILE_SHARING_DESCRIPTOR)
|
||||
: (modalLogic.inviteLink ?? '');
|
||||
return (
|
||||
<Modal.Root size="small" centered data-flx="relationship.add-friends-to-group-modal.modal-root">
|
||||
<Modal.Root
|
||||
size="small"
|
||||
centered
|
||||
className={selectorStyles.selectorRoot}
|
||||
data-flx="relationship.add-friends-to-group-modal.modal-root"
|
||||
>
|
||||
<Modal.Header
|
||||
title={i18n._(SELECT_FRIENDS_DESCRIPTOR)}
|
||||
data-flx="relationship.add-friends-to-group-modal.modal-header"
|
||||
|
||||
@@ -144,7 +144,12 @@ export const ShareThemeModal = observer(({themeCss}: {themeCss: string}) => {
|
||||
send: handleSendTheme,
|
||||
} = useSendLinkToRecipients(() => (themeUrl ? `${i18n._(CHECK_OUT_MY_CUSTOM_THEME_DESCRIPTOR)}\n${themeUrl}` : null));
|
||||
return (
|
||||
<Modal.Root size="small" centered data-flx="theme.share-theme-modal.modal-root">
|
||||
<Modal.Root
|
||||
size="small"
|
||||
centered
|
||||
className={selectorStyles.selectorRoot}
|
||||
data-flx="theme.share-theme-modal.modal-root"
|
||||
>
|
||||
<Modal.Header title={i18n._(SHARE_YOUR_THEME_DESCRIPTOR)} data-flx="theme.share-theme-modal.modal-header">
|
||||
<div className={selectorStyles.headerSearch} data-flx="theme.share-theme-modal.div">
|
||||
<Input
|
||||
|
||||
Reference in new issue
Block a user