diff --git a/packages/ui/src/App.tsx b/packages/ui/src/App.tsx index 52add283f..eff86e242 100644 --- a/packages/ui/src/App.tsx +++ b/packages/ui/src/App.tsx @@ -69,8 +69,8 @@ const App = () => { } /> {/* forgot password */} + } /> } /> - } /> {/* social sign-in pages */} diff --git a/packages/ui/src/apis/api.test.ts b/packages/ui/src/apis/api.test.ts index 504e01176..7d4a5ff4a 100644 --- a/packages/ui/src/apis/api.test.ts +++ b/packages/ui/src/apis/api.test.ts @@ -1,5 +1,8 @@ +import { + verifyForgotPasswordEmailPasscode, + verifyForgotPasswordSmsPasscode, +} from './forgot-password'; import { verifyRegisterEmailPasscode, verifyRegisterSmsPasscode } from './register'; -import { verifyResetPasswordEmailPasscode, verifyResetPasswordSmsPasscode } from './reset-password'; import { verifySignInEmailPasscode, verifySignInSmsPasscode } from './sign-in'; import { getVerifyPasscodeApi } from './utils'; @@ -9,7 +12,9 @@ describe('api', () => { expect(getVerifyPasscodeApi('register', 'email')).toBe(verifyRegisterEmailPasscode); expect(getVerifyPasscodeApi('sign-in', 'sms')).toBe(verifySignInSmsPasscode); expect(getVerifyPasscodeApi('sign-in', 'email')).toBe(verifySignInEmailPasscode); - expect(getVerifyPasscodeApi('reset-password', 'email')).toBe(verifyResetPasswordEmailPasscode); - expect(getVerifyPasscodeApi('reset-password', 'sms')).toBe(verifyResetPasswordSmsPasscode); + expect(getVerifyPasscodeApi('forgot-password', 'email')).toBe( + verifyForgotPasswordEmailPasscode + ); + expect(getVerifyPasscodeApi('forgot-password', 'sms')).toBe(verifyForgotPasswordSmsPasscode); }); }); diff --git a/packages/ui/src/apis/forgot-password.ts b/packages/ui/src/apis/forgot-password.ts new file mode 100644 index 000000000..b5d1daf3d --- /dev/null +++ b/packages/ui/src/apis/forgot-password.ts @@ -0,0 +1,58 @@ +import api from './api'; + +type Response = { + redirectTo: string; +}; + +const forgotPasswordApiPrefix = '/api/session/forgot-password'; + +export const sendForgotPasswordSmsPasscode = async (phone: string) => { + await api + .post(`${forgotPasswordApiPrefix}/sms/send-passcode`, { + json: { + phone, + }, + }) + .json(); + + return { success: true }; +}; + +export const verifyForgotPasswordSmsPasscode = async (phone: string, code: string) => + api + .post(`${forgotPasswordApiPrefix}/sms/verify-passcode`, { + json: { + phone, + code, + }, + }) + .json(); + +export const sendForgotPasswordEmailPasscode = async (email: string) => { + await api + .post(`${forgotPasswordApiPrefix}/email/send-passcode`, { + json: { + email, + }, + }) + .json(); + + return { success: true }; +}; + +export const verifyForgotPasswordEmailPasscode = async (email: string, code: string) => + api + .post(`${forgotPasswordApiPrefix}/email/verify-passcode`, { + json: { + email, + code, + }, + }) + .json(); + +export const resetPassword = async (password: string) => + api + .post(`${forgotPasswordApiPrefix}/reset`, { + json: { password }, + }) + .json(); diff --git a/packages/ui/src/apis/index.test.ts b/packages/ui/src/apis/index.test.ts index 2904498ab..405992ef5 100644 --- a/packages/ui/src/apis/index.test.ts +++ b/packages/ui/src/apis/index.test.ts @@ -1,6 +1,13 @@ import ky from 'ky'; import { consent } from './consent'; +import { + verifyForgotPasswordEmailPasscode, + verifyForgotPasswordSmsPasscode, + sendForgotPasswordEmailPasscode, + sendForgotPasswordSmsPasscode, + resetPassword, +} from './forgot-password'; import { register, sendRegisterEmailPasscode, @@ -8,12 +15,6 @@ import { verifyRegisterEmailPasscode, verifyRegisterSmsPasscode, } from './register'; -import { - verifyResetPasswordEmailPasscode, - verifyResetPasswordSmsPasscode, - sendResetPasswordEmailPasscode, - sendResetPasswordSmsPasscode, -} from './reset-password'; import { signInBasic, sendSignInSmsPasscode, @@ -185,18 +186,18 @@ describe('api', () => { }); }); - it('sendResetPasswordSmsPasscode', async () => { - await sendResetPasswordSmsPasscode(phone); - expect(ky.post).toBeCalledWith('/api/session/reset-password/sms/send-passcode', { + it('sendForgotPasswordSmsPasscode', async () => { + await sendForgotPasswordSmsPasscode(phone); + expect(ky.post).toBeCalledWith('/api/session/forgot-password/sms/send-passcode', { json: { phone, }, }); }); - it('verifyResetPasswordSmsPasscode', async () => { - await verifyResetPasswordSmsPasscode(phone, code); - expect(ky.post).toBeCalledWith('/api/session/reset-password/sms/verify-passcode', { + it('verifyForgotPasswordSmsPasscode', async () => { + await verifyForgotPasswordSmsPasscode(phone, code); + expect(ky.post).toBeCalledWith('/api/session/forgot-password/sms/verify-passcode', { json: { phone, code, @@ -204,18 +205,18 @@ describe('api', () => { }); }); - it('sendResetPasswordEmailPasscode', async () => { - await sendResetPasswordEmailPasscode(email); - expect(ky.post).toBeCalledWith('/api/session/reset-password/email/send-passcode', { + it('sendForgotPasswordEmailPasscode', async () => { + await sendForgotPasswordEmailPasscode(email); + expect(ky.post).toBeCalledWith('/api/session/forgot-password/email/send-passcode', { json: { email, }, }); }); - it('verifyResetPasswordEmailPasscode', async () => { - await verifyResetPasswordEmailPasscode(email, code); - expect(ky.post).toBeCalledWith('/api/session/reset-password/email/verify-passcode', { + it('verifyForgotPasswordEmailPasscode', async () => { + await verifyForgotPasswordEmailPasscode(email, code); + expect(ky.post).toBeCalledWith('/api/session/forgot-password/email/verify-passcode', { json: { email, code, @@ -274,4 +275,13 @@ describe('api', () => { }, }); }); + + it('resetPassword', async () => { + await resetPassword('password'); + expect(ky.post).toBeCalledWith('/api/session/forgot-password/reset', { + json: { + password: 'password', + }, + }); + }); }); diff --git a/packages/ui/src/apis/register.ts b/packages/ui/src/apis/register.ts index d2c4791e7..029230373 100644 --- a/packages/ui/src/apis/register.ts +++ b/packages/ui/src/apis/register.ts @@ -1,12 +1,14 @@ import api from './api'; +const registerApiPrefix = '/api/session/register'; + export const register = async (username: string, password: string) => { type Response = { redirectTo: string; }; return api - .post('/api/session/register/username-password', { + .post(`${registerApiPrefix}/username-password`, { json: { username, password, @@ -17,7 +19,7 @@ export const register = async (username: string, password: string) => { export const sendRegisterSmsPasscode = async (phone: string) => { await api - .post('/api/session/register/passwordless/sms/send-passcode', { + .post(`${registerApiPrefix}/passwordless/sms/send-passcode`, { json: { phone, }, @@ -33,7 +35,7 @@ export const verifyRegisterSmsPasscode = async (phone: string, code: string) => }; return api - .post('/api/session/register/passwordless/sms/verify-passcode', { + .post(`${registerApiPrefix}/passwordless/sms/verify-passcode`, { json: { phone, code, @@ -44,7 +46,7 @@ export const verifyRegisterSmsPasscode = async (phone: string, code: string) => export const sendRegisterEmailPasscode = async (email: string) => { await api - .post('/api/session/register/passwordless/email/send-passcode', { + .post(`${registerApiPrefix}/passwordless/email/send-passcode`, { json: { email, }, @@ -60,7 +62,7 @@ export const verifyRegisterEmailPasscode = async (email: string, code: string) = }; return api - .post('/api/session/register/passwordless/email/verify-passcode', { + .post(`${registerApiPrefix}/passwordless/email/verify-passcode`, { json: { email, code, diff --git a/packages/ui/src/apis/reset-password.ts b/packages/ui/src/apis/reset-password.ts deleted file mode 100644 index 5abcda7e7..000000000 --- a/packages/ui/src/apis/reset-password.ts +++ /dev/null @@ -1,56 +0,0 @@ -import api from './api'; - -type Response = { - redirectTo: string; -}; - -export const sendResetPasswordSmsPasscode = async (phone: string) => { - await api - .post('/api/session/reset-password/sms/send-passcode', { - json: { - phone, - }, - }) - .json(); - - return { success: true }; -}; - -export const verifyResetPasswordSmsPasscode = async (phone: string, code: string) => - api - .post('/api/session/reset-password/sms/verify-passcode', { - json: { - phone, - code, - }, - }) - .json(); - -export const sendResetPasswordEmailPasscode = async (email: string) => { - await api - .post('/api/session/reset-password/email/send-passcode', { - json: { - email, - }, - }) - .json(); - - return { success: true }; -}; - -export const verifyResetPasswordEmailPasscode = async (email: string, code: string) => - api - .post('/api/session/reset-password/email/verify-passcode', { - json: { - email, - code, - }, - }) - .json(); - -export const resetPassword = async (password: string) => - api - .post('/api/session/reset-password', { - json: { password }, - }) - .json(); diff --git a/packages/ui/src/apis/utils.ts b/packages/ui/src/apis/utils.ts index 47918b3c4..88247aa22 100644 --- a/packages/ui/src/apis/utils.ts +++ b/packages/ui/src/apis/utils.ts @@ -1,17 +1,17 @@ import { UserFlow } from '@/types'; +import { + sendForgotPasswordEmailPasscode, + sendForgotPasswordSmsPasscode, + verifyForgotPasswordEmailPasscode, + verifyForgotPasswordSmsPasscode, +} from './forgot-password'; import { verifyRegisterEmailPasscode, verifyRegisterSmsPasscode, sendRegisterEmailPasscode, sendRegisterSmsPasscode, } from './register'; -import { - sendResetPasswordEmailPasscode, - sendResetPasswordSmsPasscode, - verifyResetPasswordEmailPasscode, - verifyResetPasswordSmsPasscode, -} from './reset-password'; import { verifySignInEmailPasscode, verifySignInSmsPasscode, @@ -25,12 +25,12 @@ export const getSendPasscodeApi = ( type: UserFlow, method: PasscodeChannel ): ((_address: string) => Promise<{ success: boolean }>) => { - if (type === 'reset-password' && method === 'email') { - return sendResetPasswordEmailPasscode; + if (type === 'forgot-password' && method === 'email') { + return sendForgotPasswordEmailPasscode; } - if (type === 'reset-password' && method === 'sms') { - return sendResetPasswordSmsPasscode; + if (type === 'forgot-password' && method === 'sms') { + return sendForgotPasswordSmsPasscode; } if (type === 'sign-in' && method === 'email') { @@ -52,12 +52,12 @@ export const getVerifyPasscodeApi = ( type: UserFlow, method: PasscodeChannel ): ((_address: string, code: string, socialToBind?: string) => Promise<{ redirectTo: string }>) => { - if (type === 'reset-password' && method === 'email') { - return verifyResetPasswordEmailPasscode; + if (type === 'forgot-password' && method === 'email') { + return verifyForgotPasswordEmailPasscode; } - if (type === 'reset-password' && method === 'sms') { - return verifyResetPasswordSmsPasscode; + if (type === 'forgot-password' && method === 'sms') { + return verifyForgotPasswordSmsPasscode; } if (type === 'sign-in' && method === 'email') { diff --git a/packages/ui/src/containers/ResetPassword/index.test.tsx b/packages/ui/src/containers/ResetPassword/index.test.tsx index 8cd664861..ef2d84f44 100644 --- a/packages/ui/src/containers/ResetPassword/index.test.tsx +++ b/packages/ui/src/containers/ResetPassword/index.test.tsx @@ -1,11 +1,11 @@ import { fireEvent, act, waitFor } from '@testing-library/react'; import renderWithPageContext from '@/__mocks__/RenderWithPageContext'; -import { resetPassword } from '@/apis/reset-password'; +import { resetPassword } from '@/apis/forgot-password'; import ResetPassword from '.'; -jest.mock('@/apis/reset-password', () => ({ +jest.mock('@/apis/forgot-password', () => ({ resetPassword: jest.fn(async () => ({ redirectTo: '/' })), })); diff --git a/packages/ui/src/containers/ResetPassword/index.tsx b/packages/ui/src/containers/ResetPassword/index.tsx index 14fbfb3ff..8da55e2cc 100644 --- a/packages/ui/src/containers/ResetPassword/index.tsx +++ b/packages/ui/src/containers/ResetPassword/index.tsx @@ -2,7 +2,7 @@ import classNames from 'classnames'; import { useEffect, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { resetPassword } from '@/apis/reset-password'; +import { resetPassword } from '@/apis/forgot-password'; import Button from '@/components/Button'; import Input from '@/components/Input'; import useApi from '@/hooks/use-api'; diff --git a/packages/ui/src/pages/ForgotPassword/index.tsx b/packages/ui/src/pages/ForgotPassword/index.tsx index 423f9d878..d15e1f6a7 100644 --- a/packages/ui/src/pages/ForgotPassword/index.tsx +++ b/packages/ui/src/pages/ForgotPassword/index.tsx @@ -18,11 +18,11 @@ const ForgotPassword = () => { const forgotPasswordForm = useMemo(() => { if (method === 'sms') { - return ; + return ; } if (method === 'email') { - return ; + return ; } }, [method]); diff --git a/packages/ui/src/pages/ResetPassword/index.test.tsx b/packages/ui/src/pages/ResetPassword/index.test.tsx index 25eb7ab7e..9453a5dae 100644 --- a/packages/ui/src/pages/ResetPassword/index.test.tsx +++ b/packages/ui/src/pages/ResetPassword/index.test.tsx @@ -4,11 +4,11 @@ import { MemoryRouter, Routes, Route } from 'react-router-dom'; import ResetPassword from '.'; describe('ForgotPassword', () => { - it('render reset-password page properly', () => { + it('render forgot-password page properly', () => { const { queryByText } = render( - + - } /> + } /> ); diff --git a/packages/ui/src/types/guard.ts b/packages/ui/src/types/guard.ts index 7d059a55e..a5c8dccd9 100644 --- a/packages/ui/src/types/guard.ts +++ b/packages/ui/src/types/guard.ts @@ -14,5 +14,5 @@ export const passcodeMethodGuard = s.union([s.literal('email'), s.literal('sms') export const userFlowGuard = s.union([ s.literal('sign-in'), s.literal('register'), - s.literal('reset-password'), + s.literal('forgot-password'), ]); diff --git a/packages/ui/src/types/index.ts b/packages/ui/src/types/index.ts index d2c5592aa..79f7ec55a 100644 --- a/packages/ui/src/types/index.ts +++ b/packages/ui/src/types/index.ts @@ -1,7 +1,7 @@ import type { LanguageKey } from '@logto/core-kit'; import { SignInExperience, ConnectorMetadata, AppearanceMode } from '@logto/schemas'; -export type UserFlow = 'sign-in' | 'register' | 'reset-password'; +export type UserFlow = 'sign-in' | 'register' | 'forgot-password'; export type SignInMethod = 'username' | 'email' | 'sms' | 'social'; export type LocalSignInMethod = Exclude;