Skip to content

Commit e6f315d

Browse files
authored
feat(experience): add switch account page (#7155)
* feat(experience): add switch account page * refactor(experience): update account switch page * chore: i18n phrases
1 parent 5da01bc commit e6f315d

34 files changed

+228
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
@use '@/scss/underscore' as _;
2+
3+
.container {
4+
flex: 1;
5+
@include _.flex-column;
6+
@include _.full-width;
7+
}
8+
9+
.title {
10+
margin-top: _.unit(8);
11+
font: var(--font-label-2);
12+
}
13+
14+
.message {
15+
margin-top: _.unit(6);
16+
font: var(--font-body-2);
17+
}
18+
19+
.logo {
20+
height: 40px;
21+
width: auto;
22+
@include _.image-align-center;
23+
}
24+
25+
.userProfile {
26+
width: 100%;
27+
}
28+
29+
.button {
30+
margin-top: _.unit(2);
31+
}
32+
33+
.linkButton {
34+
margin-top: _.unit(6);
35+
}
36+
37+
:global(body.mobile) {
38+
.title {
39+
@include _.title;
40+
margin-bottom: _.unit(4);
41+
}
42+
}
43+
44+
:global(body.desktop) {
45+
.title {
46+
@include _.title-desktop;
47+
margin-bottom: _.unit(2);
48+
}
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { type ConsentInfoResponse } from '@logto/schemas';
2+
import { useContext, useEffect, useState } from 'react';
3+
4+
import StaticPageLayout from '@/Layout/StaticPageLayout';
5+
import PageContext from '@/Providers/PageContextProvider/PageContext';
6+
import { getConsentInfo } from '@/apis/consent';
7+
import Button from '@/components/Button';
8+
import DynamicT from '@/components/DynamicT';
9+
import LoadingLayer from '@/components/LoadingLayer';
10+
import PageMeta from '@/components/PageMeta';
11+
import TextLink from '@/components/TextLink';
12+
import useApi from '@/hooks/use-api';
13+
import useErrorHandler from '@/hooks/use-error-handler';
14+
import UserProfile from '@/pages/Consent/UserProfile';
15+
import ErrorPage from '@/pages/ErrorPage';
16+
import { getBrandingLogoUrl } from '@/utils/logo';
17+
18+
import styles from './index.module.scss';
19+
20+
/**
21+
* This component is only used when there's an active session, and then the user
22+
* is trying to sign-in with another account (e.g., using a magic link).
23+
*/
24+
25+
type Props = {
26+
/**
27+
* The account name of the current active session
28+
*/
29+
readonly account: string;
30+
/**
31+
* The callback function to be called after clicking the "Go back" link
32+
*/
33+
readonly onCancel: () => Promise<void>;
34+
/**
35+
* The callback function to be called after clicking the "Switch" button
36+
*/
37+
readonly onSwitch: () => Promise<void>;
38+
};
39+
40+
const SwitchAccount = ({ account, onCancel, onSwitch }: Props) => {
41+
const { experienceSettings, theme } = useContext(PageContext);
42+
const handleError = useErrorHandler();
43+
44+
const [consentData, setConsentData] = useState<ConsentInfoResponse>();
45+
const asyncGetConsentInfo = useApi(getConsentInfo);
46+
47+
useEffect(() => {
48+
(async () => {
49+
const [error, result] = await asyncGetConsentInfo();
50+
51+
if (error) {
52+
await handleError(error);
53+
return;
54+
}
55+
setConsentData(result);
56+
})();
57+
}, [asyncGetConsentInfo, handleError]);
58+
59+
if (!account) {
60+
return <ErrorPage title="error.unknown" message="error.unknown" />;
61+
}
62+
63+
if (!experienceSettings || !consentData) {
64+
return <LoadingLayer />;
65+
}
66+
67+
const {
68+
color: { isDarkModeEnabled },
69+
branding,
70+
} = experienceSettings;
71+
const logoUrl = getBrandingLogoUrl({ theme, branding, isDarkModeEnabled });
72+
73+
return (
74+
<StaticPageLayout>
75+
<PageMeta titleKey="description.switch_account" />
76+
<div className={styles.container}>
77+
{logoUrl && <img className={styles.logo} src={logoUrl} alt="app logo" />}
78+
<div className={styles.title}>
79+
<DynamicT forKey="description.switch_account_title" interpolation={{ account }} />
80+
</div>
81+
<UserProfile user={consentData.user} className={styles.userProfile} />
82+
<div className={styles.message}>
83+
<DynamicT forKey="description.switch_account_description" />
84+
</div>
85+
<Button
86+
className={styles.button}
87+
type="primary"
88+
size="large"
89+
title="action.switch_to"
90+
i18nProps={{ method: account }}
91+
onClick={onSwitch}
92+
/>
93+
<div className={styles.linkButton}>
94+
<TextLink text="action.back_to_current_account" onClick={onCancel} />
95+
</div>
96+
</div>
97+
</StaticPageLayout>
98+
);
99+
};
100+
101+
export default SwitchAccount;

packages/phrases-experience/src/locales/ar/action.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const action = {
3131
single_sign_on: 'تسجيل الدخول الموحد',
3232
authorize: 'التفويض',
3333
use_another_account: 'استخدام حساب آخر',
34+
back_to_current_account: 'الرجوع إلى الحساب الحالي',
3435
};
3536

3637
export default Object.freeze(action);

packages/phrases-experience/src/locales/ar/description.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const description = {
1010
sign_in: 'تسجيل الدخول',
1111
privacy_policy: 'سياسة الخصوصية',
1212
create_account: 'إنشاء حساب',
13+
switch_account: 'تبديل الحساب',
1314
or: 'أو',
1415
and: 'و',
1516
enter_passcode: 'تم إرسال رمز التحقق إلى {{address}} {{target}} الخاص بك',
@@ -102,6 +103,9 @@ const description = {
102103
back_to_sign_in: 'العودة إلى تسجيل الدخول',
103104
support_email: 'البريد الإلكتروني للدعم: <link></link>',
104105
support_website: 'موقع الدعم: <link></link>',
106+
switch_account_title: 'أنت حاليًا مسجل الدخول كـ {{account}}',
107+
switch_account_description:
108+
'للمتابعة، سيتم تسجيل الخروج من الحساب الحالي، والتبديل تلقائيًا إلى الحساب الجديد.',
105109
};
106110

107111
export default Object.freeze(description);

packages/phrases-experience/src/locales/de/action.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const action = {
3131
single_sign_on: 'Single Sign-On',
3232
authorize: 'Autorisieren',
3333
use_another_account: 'Anderes Konto verwenden',
34+
back_to_current_account: 'Zurück zum aktuellen Konto',
3435
};
3536

3637
export default Object.freeze(action);

packages/phrases-experience/src/locales/de/description.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const description = {
1010
sign_in: 'Anmelden',
1111
privacy_policy: 'Datenschutzrichtlinien',
1212
create_account: 'Konto erstellen',
13+
switch_account: 'Konto wechseln',
1314
or: 'oder',
1415
and: 'und',
1516
enter_passcode: 'Der Bestätigungscode wurde an deine {{address}} gesendet',
@@ -108,6 +109,9 @@ const description = {
108109
back_to_sign_in: 'Zurück zur Anmeldung',
109110
support_email: 'Support-E-Mail: <link></link>',
110111
support_website: 'Support-Website: <link></link>',
112+
switch_account_title: 'Du bist derzeit als {{account}} angemeldet',
113+
switch_account_description:
114+
'Um fortzufahren, wirst du vom aktuellen Konto abgemeldet und automatisch zum neuen Konto gewechselt.',
111115
};
112116

113117
export default Object.freeze(description);

packages/phrases-experience/src/locales/en/action.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const action = {
3131
single_sign_on: 'Single Sign-On',
3232
authorize: 'Authorize',
3333
use_another_account: 'Use another account',
34+
back_to_current_account: 'Back to current account',
3435
};
3536

3637
export default Object.freeze(action);

packages/phrases-experience/src/locales/en/description.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const description = {
1010
sign_in: 'Sign in',
1111
privacy_policy: 'Privacy Policy',
1212
create_account: 'Create account',
13+
switch_account: 'Switch account',
1314
or: 'or',
1415
and: 'and',
1516
enter_passcode: 'The verification code has been sent to your {{address}} {{target}}',
@@ -105,6 +106,9 @@ const description = {
105106
back_to_sign_in: 'Back to sign in',
106107
support_email: 'Support email: <link></link>',
107108
support_website: 'Support website: <link></link>',
109+
switch_account_title: 'You are currently signed in as {{account}}',
110+
switch_account_description:
111+
'To continue, you will be signed out of the current account, and switch to the new account automatically.',
108112
};
109113

110114
export default Object.freeze(description);

packages/phrases-experience/src/locales/es/action.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const action = {
3131
single_sign_on: 'Inicio de sesión único',
3232
authorize: 'Autorizar',
3333
use_another_account: 'Usar otra cuenta',
34+
back_to_current_account: 'Regresar a la cuenta actual',
3435
};
3536

3637
export default Object.freeze(action);

packages/phrases-experience/src/locales/es/description.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const description = {
1010
sign_in: 'Iniciar sesión',
1111
privacy_policy: 'Política de privacidad',
1212
create_account: 'Crear cuenta',
13+
switch_account: 'Cambiar cuenta',
1314
or: 'o',
1415
and: 'y',
1516
enter_passcode: 'El código de verificación ha sido enviado a su {{address}} {{target}}',
@@ -108,6 +109,9 @@ const description = {
108109
back_to_sign_in: 'Volver a iniciar sesión',
109110
support_email: 'Correo electrónico de soporte: <link></link>',
110111
support_website: 'Sitio web de soporte: <link></link>',
112+
switch_account_title: 'Actualmente has iniciado sesión como {{account}}',
113+
switch_account_description:
114+
'Para continuar, se cerrará la sesión de la cuenta actual, y se cambiará automáticamente a la nueva cuenta.',
111115
};
112116

113117
export default Object.freeze(description);

packages/phrases-experience/src/locales/fr/action.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const action = {
3131
single_sign_on: 'Connexion unique',
3232
authorize: 'Autoriser',
3333
use_another_account: 'Utiliser un autre compte',
34+
back_to_current_account: 'Retour au compte actuel',
3435
};
3536

3637
export default Object.freeze(action);

packages/phrases-experience/src/locales/fr/description.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const description = {
1010
sign_in: 'Connexion',
1111
privacy_policy: 'Politique de confidentialité',
1212
create_account: 'Créer un compte',
13+
switch_account: 'Changer de compte',
1314
or: 'ou',
1415
and: 'et',
1516
enter_passcode: 'Le code a été envoyé à {{address}} {{target}}',
@@ -108,6 +109,9 @@ const description = {
108109
back_to_sign_in: 'Retour à la connexion',
109110
support_email: 'Email de support: <link></link>',
110111
support_website: 'Site web de support: <link></link>',
112+
switch_account_title: 'Vous êtes actuellement connecté en tant que {{account}}',
113+
switch_account_description:
114+
'Pour continuer, vous serez déconnecté du compte actuel, et le passage au nouveau compte se fera automatiquement.',
111115
};
112116

113117
export default Object.freeze(description);

packages/phrases-experience/src/locales/it/action.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const action = {
3131
single_sign_on: 'Single Sign-On',
3232
authorize: 'Autorizza',
3333
use_another_account: 'Usa un altro account',
34+
back_to_current_account: "Torna all'account attuale",
3435
};
3536

3637
export default Object.freeze(action);

packages/phrases-experience/src/locales/it/description.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const description = {
1010
sign_in: 'Accedi',
1111
privacy_policy: 'Informativa sulla privacy',
1212
create_account: 'Crea account',
13+
switch_account: 'Cambia account',
1314
or: 'o',
1415
and: 'e',
1516
enter_passcode: 'Il codice di verifica è stato inviato alla tua {{address}} {{target}}',
@@ -106,6 +107,9 @@ const description = {
106107
back_to_sign_in: 'Torna al login',
107108
support_email: 'Email di supporto: <link></link>',
108109
support_website: 'Sito web di supporto: <link></link>',
110+
switch_account_title: 'Attualmente sei connesso come {{account}}',
111+
switch_account_description:
112+
"Per continuare, verrai disconnesso dall'account attuale e passerai automaticamente al nuovo account.",
109113
};
110114

111115
export default Object.freeze(description);

packages/phrases-experience/src/locales/ja/action.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const action = {
3131
single_sign_on: 'シングルサインオン',
3232
authorize: '認証する',
3333
use_another_account: '別のアカウントを使用する',
34+
back_to_current_account: '現在のアカウントに戻る',
3435
};
3536

3637
export default Object.freeze(action);

packages/phrases-experience/src/locales/ja/description.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const description = {
1010
sign_in: 'サインイン',
1111
privacy_policy: 'プライバシーポリシー',
1212
create_account: 'アカウントを作成する',
13+
switch_account: 'アカウントを切り替える',
1314
or: 'または',
1415
and: '及び',
1516
enter_passcode: '確認コードが{{address}} {{target}}に送信されました',
@@ -101,6 +102,9 @@ const description = {
101102
back_to_sign_in: 'サインインに戻る',
102103
support_email: 'サポートメール: <link></link>',
103104
support_website: 'サポートウェブサイト: <link></link>',
105+
switch_account_title: '現在 {{account}} としてサインインしています',
106+
switch_account_description:
107+
'続行するには、現在のアカウントからサインアウトし、新しいアカウントに自動的に切り替わります。',
104108
};
105109

106110
export default Object.freeze(description);

packages/phrases-experience/src/locales/ko/action.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const action = {
3131
single_sign_on: '단일 로그인',
3232
authorize: '권한 부여',
3333
use_another_account: '다른 계정 사용',
34+
back_to_current_account: '현재 계정으로 돌아가기',
3435
};
3536

3637
export default Object.freeze(action);

packages/phrases-experience/src/locales/ko/description.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const description = {
1010
sign_in: '로그인',
1111
privacy_policy: '개인정보처리방침',
1212
create_account: '계정 생성',
13+
switch_account: '계정 전환',
1314
or: '또는',
1415
and: '그리고',
1516
enter_passcode: '{{address}} {{target}} 으로 비밀번호가 전송되었어요.',
@@ -96,6 +97,9 @@ const description = {
9697
back_to_sign_in: '로그인으로 돌아가기',
9798
support_email: '지원 이메일: <link></link>',
9899
support_website: '지원 웹사이트: <link></link>',
100+
switch_account_title: '현재 {{account}}으로 로그인 중입니다',
101+
switch_account_description:
102+
'계속 진행하려면 현재 계정에서 로그아웃되고 새 계정으로 자동 전환됩니다.',
99103
};
100104

101105
export default Object.freeze(description);

packages/phrases-experience/src/locales/pl-pl/action.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const action = {
3131
single_sign_on: 'Pojedyncze logowanie',
3232
authorize: 'Autoryzować',
3333
use_another_account: 'Użyj innego konta',
34+
back_to_current_account: 'Powróć do bieżącego konta',
3435
};
3536

3637
export default Object.freeze(action);

packages/phrases-experience/src/locales/pl-pl/description.ts

+4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const description = {
1010
sign_in: 'Zaloguj się',
1111
privacy_policy: 'Polityka prywatności',
1212
create_account: 'Utwórz konto',
13+
switch_account: 'Przełącz konto',
1314
or: 'lub',
1415
and: 'i',
1516
enter_passcode: 'Kod weryfikacyjny został wysłany na twoje {{address}} {{target}}',
@@ -106,6 +107,9 @@ const description = {
106107
back_to_sign_in: 'Wróć do logowania',
107108
support_email: 'Email wsparcia: <link></link>',
108109
support_website: 'Strona wsparcia: <link></link>',
110+
switch_account_title: 'Jesteś obecnie zalogowany jako {{account}}',
111+
switch_account_description:
112+
'Aby kontynuować, zostaniesz wylogowany z obecnego konta i automatycznie przełączony na nowe konto.',
109113
};
110114

111115
export default Object.freeze(description);

packages/phrases-experience/src/locales/pt-br/action.ts

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const action = {
3131
single_sign_on: 'Single Sign-On',
3232
authorize: '授权',
3333
use_another_account: '使用其他帐户',
34+
back_to_current_account: 'Voltar para a conta atual',
3435
};
3536

3637
export default Object.freeze(action);

0 commit comments

Comments
 (0)