0
Fork 0
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:
simeng-li 2022-11-06 22:37:42 +08:00
parent e4a487e7bb
commit 04df1d999d
No known key found for this signature in database
GPG key ID: 14EA7BB1541E8075
11 changed files with 65 additions and 7 deletions

View file

@ -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',

View file

@ -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',

View file

@ -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: '이메일',

View file

@ -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',

View file

@ -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',

View file

@ -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: '邮箱',

View file

@ -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;

View file

@ -22,6 +22,12 @@
color: var(--color-brand-default);
}
}
.link {
margin-top: _.unit(3);
width: auto;
align-self: start;
}
}
:global(body.mobile) {

View file

@ -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>
);
};

View file

@ -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>
);

View file

@ -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>
);
};