mirror of
https://github.com/logto-io/logto.git
synced 2025-02-17 22:04:19 -05:00
feat(ui): add password switch link
add password swtich link
This commit is contained in:
parent
e4a487e7bb
commit
04df1d999d
11 changed files with 65 additions and 7 deletions
|
@ -30,6 +30,7 @@ const translation = {
|
|||
forgot_password: 'Forgot your password?',
|
||||
switch_to: 'Switch to {{method}}',
|
||||
sign_in_via_passcode: 'Sign in via verification code',
|
||||
sign_in_via_password: 'Sign in via password',
|
||||
},
|
||||
description: {
|
||||
email: 'email',
|
||||
|
|
|
@ -32,6 +32,7 @@ const translation = {
|
|||
forgot_password: 'Mot de passe oublié ?',
|
||||
switch_to: 'Passer au {{method}}',
|
||||
sign_in_via_passcode: 'Sign in via verification code', // UNTRANSLATED
|
||||
sign_in_via_password: 'Sign in via password', // UNTRANSLATED
|
||||
},
|
||||
description: {
|
||||
email: 'email',
|
||||
|
|
|
@ -32,6 +32,7 @@ const translation = {
|
|||
forgot_password: '비밀번호를 잊어버리셨나요?',
|
||||
switch_to: 'Switch to {{method}}', // UNTRANSLATED
|
||||
sign_in_via_passcode: 'Sign in via verification code', // UNTRANSLATED
|
||||
sign_in_via_password: 'Sign in via password', // UNTRANSLATED
|
||||
},
|
||||
description: {
|
||||
email: '이메일',
|
||||
|
|
|
@ -32,6 +32,7 @@ const translation = {
|
|||
forgot_password: 'Esqueceu a password?',
|
||||
switch_to: 'Mudar para {{method}}',
|
||||
sign_in_via_passcode: 'Sign in via verification code', // UNTRANSLATED
|
||||
sign_in_via_password: 'Sign in via password', // UNTRANSLATED
|
||||
},
|
||||
description: {
|
||||
email: 'email',
|
||||
|
|
|
@ -32,6 +32,7 @@ const translation = {
|
|||
forgot_password: 'Şifremi Unuttum?',
|
||||
switch_to: 'Switch to {{method}}', // UNTRANSLATED
|
||||
sign_in_via_passcode: 'Sign in via verification code', // UNTRANSLATED
|
||||
sign_in_via_password: 'Sign in via password', // UNTRANSLATED
|
||||
},
|
||||
description: {
|
||||
email: 'e-posta adresi',
|
||||
|
|
|
@ -32,6 +32,7 @@ const translation = {
|
|||
forgot_password: '重置密码',
|
||||
switch_to: '切换到{{method}}',
|
||||
sign_in_via_passcode: 'Sign in via verification code', // UNTRANSLATED
|
||||
sign_in_via_password: 'Sign in via password', // UNTRANSLATED
|
||||
},
|
||||
description: {
|
||||
email: '邮箱',
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
import { SignInIdentifier } from '@logto/schemas';
|
||||
|
||||
import TextLink from '@/components/TextLink';
|
||||
import { UserFlow } from '@/types';
|
||||
|
||||
type Props = {
|
||||
className?: string;
|
||||
method: SignInIdentifier.Email | SignInIdentifier.Sms;
|
||||
target: string;
|
||||
};
|
||||
|
||||
const PasswordSignInLink = ({ className, method, target }: Props) => {
|
||||
return (
|
||||
<TextLink
|
||||
replace
|
||||
className={className}
|
||||
text="action.sign_in_via_password"
|
||||
to={`/${UserFlow.signIn}/${method}/password`}
|
||||
state={method === SignInIdentifier.Email ? { email: target } : { phone: target }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default PasswordSignInLink;
|
|
@ -22,6 +22,12 @@
|
|||
color: var(--color-brand-default);
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
margin-top: _.unit(3);
|
||||
width: auto;
|
||||
align-self: start;
|
||||
}
|
||||
}
|
||||
|
||||
:global(body.mobile) {
|
||||
|
|
|
@ -5,8 +5,9 @@ import { useTranslation, Trans } from 'react-i18next';
|
|||
|
||||
import Passcode, { defaultLength } from '@/components/Passcode';
|
||||
import TextLink from '@/components/TextLink';
|
||||
import type { UserFlow } from '@/types';
|
||||
import { UserFlow } from '@/types';
|
||||
|
||||
import PasswordSignInLink from './PasswordSignInLink';
|
||||
import * as styles from './index.module.scss';
|
||||
import useResendPasscode from './use-resend-passcode';
|
||||
import { getPasscodeValidationHook } from './utils';
|
||||
|
@ -15,10 +16,11 @@ type Props = {
|
|||
type: UserFlow;
|
||||
method: SignInIdentifier.Email | SignInIdentifier.Sms;
|
||||
target: string;
|
||||
hasPasswordButton?: boolean;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const PasscodeValidation = ({ type, method, className, target }: Props) => {
|
||||
const PasscodeValidation = ({ type, method, className, hasPasswordButton, target }: Props) => {
|
||||
const [code, setCode] = useState<string[]>([]);
|
||||
const { t } = useTranslation();
|
||||
const usePasscodeValidation = getPasscodeValidationHook(type, method);
|
||||
|
@ -64,6 +66,9 @@ const PasscodeValidation = ({ type, method, className, target }: Props) => {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
{type === UserFlow.signIn && hasPasswordButton && (
|
||||
<PasswordSignInLink method={method} target={target} className={styles.link} />
|
||||
)}
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { Routes, Route, MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import renderWithPageContext from '@/__mocks__/RenderWithPageContext';
|
||||
import SettingsProvider from '@/__mocks__/RenderWithPageContext/SettingsProvider';
|
||||
|
||||
import Passcode from '.';
|
||||
|
||||
|
@ -15,9 +16,11 @@ describe('Passcode Page', () => {
|
|||
it('render properly', () => {
|
||||
const { queryByText } = renderWithPageContext(
|
||||
<MemoryRouter initialEntries={['/sign-in/email/passcode-validation']}>
|
||||
<Routes>
|
||||
<Route path="/:type/:method/passcode-validation" element={<Passcode />} />
|
||||
</Routes>
|
||||
<SettingsProvider>
|
||||
<Routes>
|
||||
<Route path="/:type/:method/passcode-validation" element={<Passcode />} />
|
||||
</Routes>
|
||||
</SettingsProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
|
|
|
@ -5,8 +5,9 @@ import { is } from 'superstruct';
|
|||
|
||||
import SecondaryPageWrapper from '@/components/SecondaryPageWrapper';
|
||||
import PasscodeValidation from '@/containers/PasscodeValidation';
|
||||
import { useSieMethods } from '@/hooks/use-sie';
|
||||
import ErrorPage from '@/pages/ErrorPage';
|
||||
import type { UserFlow } from '@/types';
|
||||
import { UserFlow } from '@/types';
|
||||
import { passcodeStateGuard, passcodeMethodGuard, userFlowGuard } from '@/types/guard';
|
||||
|
||||
type Parameters = {
|
||||
|
@ -16,6 +17,7 @@ type Parameters = {
|
|||
|
||||
const Passcode = () => {
|
||||
const { method, type = '' } = useParams<Parameters>();
|
||||
const { signInMethods } = useSieMethods();
|
||||
const { state } = useLocation();
|
||||
|
||||
const invalidType = !is(type, userFlowGuard);
|
||||
|
@ -26,6 +28,13 @@ const Passcode = () => {
|
|||
return <ErrorPage />;
|
||||
}
|
||||
|
||||
// SignIn Method not enabled
|
||||
const methodSettings = signInMethods.find(({ identifier }) => identifier === method);
|
||||
|
||||
if (!methodSettings) {
|
||||
return <ErrorPage />;
|
||||
}
|
||||
|
||||
const target = !invalidState && state[method === SignInIdentifier.Email ? 'email' : 'phone'];
|
||||
|
||||
if (!target) {
|
||||
|
@ -41,7 +50,12 @@ const Passcode = () => {
|
|||
target,
|
||||
}}
|
||||
>
|
||||
<PasscodeValidation type={type} method={method} target={target} />
|
||||
<PasscodeValidation
|
||||
type={type}
|
||||
method={method}
|
||||
target={target}
|
||||
hasPasswordButton={type === UserFlow.signIn && methodSettings.password}
|
||||
/>
|
||||
</SecondaryPageWrapper>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue