From 5fc75841eeb85fd78231f3235ac80db00558831f Mon Sep 17 00:00:00 2001 From: Guillermo Machado Date: Thu, 9 Jan 2025 10:40:46 -0300 Subject: [PATCH 1/2] feat: sign in --- src/api/auth/use-login.ts | 11 ++++++----- src/app/_layout.tsx | 2 +- src/app/sign-in.tsx | 30 ++++++++++++++++++++++++++++++ src/components/login-form.tsx | 13 ++----------- 4 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 src/app/sign-in.tsx diff --git a/src/api/auth/use-login.ts b/src/api/auth/use-login.ts index 599c917f..8c54cb73 100644 --- a/src/api/auth/use-login.ts +++ b/src/api/auth/use-login.ts @@ -3,8 +3,7 @@ import { createMutation } from 'react-query-kit'; import { client } from '../common'; type Variables = { - email?: string; // optional because API doesn't require email - username: string; + email: string; password: string; expiresInMins?: number; }; @@ -19,11 +18,13 @@ type Response = { const login = async (variables: Variables) => { const { data } = await client({ - url: 'auth/login', + url: '/v1/users/sign_in', method: 'POST', data: { - username: variables.username, - password: variables.password, + user: { + email: variables.email, + password: variables.password, + }, }, headers: { 'Content-Type': 'application/json', diff --git a/src/app/_layout.tsx b/src/app/_layout.tsx index 0870c98b..9fafc053 100644 --- a/src/app/_layout.tsx +++ b/src/app/_layout.tsx @@ -33,8 +33,8 @@ export default function RootLayout() { - + ); diff --git a/src/app/sign-in.tsx b/src/app/sign-in.tsx new file mode 100644 index 00000000..0cfcad31 --- /dev/null +++ b/src/app/sign-in.tsx @@ -0,0 +1,30 @@ +import { useRouter } from 'expo-router'; +import { showMessage } from 'react-native-flash-message'; + +import { useLogin } from '@/api/auth/use-login'; +import type { LoginFormProps } from '@/components/login-form'; +import { LoginForm } from '@/components/login-form'; +import { useAuth } from '@/core'; +import { FocusAwareStatusBar } from '@/ui'; + +export default function Login() { + const router = useRouter(); + const signIn = useAuth.use.signIn(); + const { mutate: login } = useLogin({ + onSuccess: (data) => { + signIn({ access: data.accessToken, refresh: data.refreshToken }); + router.push('/'); + }, + onError: (error) => showMessage({ message: error.message, type: 'danger' }), + }); + + const onSubmit: LoginFormProps['onSubmit'] = (data) => { + login(data); + }; + return ( + <> + + + + ); +} diff --git a/src/components/login-form.tsx b/src/components/login-form.tsx index b0accbc5..375a91c3 100644 --- a/src/components/login-form.tsx +++ b/src/components/login-form.tsx @@ -8,10 +8,7 @@ import { Button, ControlledInput, Text, View } from '@/ui'; const MIN_CHARS = 6; const schema = z.object({ - username: z.string({ - required_error: 'Username is required', - }), - email: z.string().email('Invalid email format').optional(), + email: z.string().email('Invalid email format'), password: z .string({ required_error: 'Password is required', @@ -46,13 +43,7 @@ export const LoginForm = ({ onSubmit = () => {} }: LoginFormProps) => { autoComplete="email" control={control} name="email" - label="Email (optional)" - /> - Date: Thu, 9 Jan 2025 10:50:37 -0300 Subject: [PATCH 2/2] fix: fix test --- src/components/login-form.test.tsx | 37 ++++-------------------------- src/components/login-form.tsx | 4 +++- 2 files changed, 7 insertions(+), 34 deletions(-) diff --git a/src/components/login-form.test.tsx b/src/components/login-form.test.tsx index e86cf490..f0f94599 100644 --- a/src/components/login-form.test.tsx +++ b/src/components/login-form.test.tsx @@ -1,12 +1,9 @@ -import { cleanup, fireEvent, render, screen, waitFor } from '@/core/test-utils'; +import { cleanup, fireEvent, render, screen } from '@/core/test-utils'; -import type { LoginFormProps } from './login-form'; import { LoginForm } from './login-form'; afterEach(cleanup); -const onSubmitMock: jest.Mock = jest.fn(); - describe('LoginForm Form ', () => { const LOGIN_BUTTON = 'login-button'; it('renders correctly', async () => { @@ -18,9 +15,9 @@ describe('LoginForm Form ', () => { render(); const button = screen.getByTestId(LOGIN_BUTTON); - expect(screen.queryByText(/Username is required/i)).not.toBeOnTheScreen(); + expect(screen.queryByText(/Email is required/i)).not.toBeOnTheScreen(); fireEvent.press(button); - expect(await screen.findByText(/Username is required/i)).toBeOnTheScreen(); + expect(await screen.findByText(/Email is required/i)).toBeOnTheScreen(); expect(screen.getByText(/Password is required/i)).toBeOnTheScreen(); }); @@ -29,39 +26,13 @@ describe('LoginForm Form ', () => { const button = screen.getByTestId(LOGIN_BUTTON); const emailInput = screen.getByTestId('email-input'); - const usernameInput = screen.getByTestId('username-input'); const passwordInput = screen.getByTestId('password-input'); fireEvent.changeText(emailInput, 'yyyy'); - fireEvent.changeText(usernameInput, ' '); fireEvent.changeText(passwordInput, 'test'); fireEvent.press(button); - expect(screen.queryByText(/Username is required/i)).not.toBeOnTheScreen(); + expect(screen.queryByText(/Email is required/i)).not.toBeOnTheScreen(); expect(await screen.findByText(/Invalid Email Format/i)).toBeOnTheScreen(); }); - - it('Should call LoginForm with correct values when values are valid', async () => { - render(); - - const button = screen.getByTestId(LOGIN_BUTTON); - const emailInput = screen.getByTestId('username-input'); - const passwordInput = screen.getByTestId('password-input'); - - fireEvent.changeText(emailInput, 'youssef'); - fireEvent.changeText(passwordInput, 'password'); - fireEvent.press(button); - await waitFor(() => { - expect(onSubmitMock).toHaveBeenCalledTimes(1); - }); - // undefined because we don't use second argument of the SubmitHandler - expect(onSubmitMock).toHaveBeenCalledWith( - { - email: undefined, - username: 'youssef', - password: 'password', - }, - undefined, - ); - }); }); diff --git a/src/components/login-form.tsx b/src/components/login-form.tsx index 375a91c3..7ad35c85 100644 --- a/src/components/login-form.tsx +++ b/src/components/login-form.tsx @@ -8,7 +8,9 @@ import { Button, ControlledInput, Text, View } from '@/ui'; const MIN_CHARS = 6; const schema = z.object({ - email: z.string().email('Invalid email format'), + email: z + .string({ required_error: 'Email is required' }) + .email('Invalid email format'), password: z .string({ required_error: 'Password is required',