diff --git a/src/app/api/auth/login/route.ts b/src/app/api/auth/login/route.ts
new file mode 100644
index 0000000..774e8e7
--- /dev/null
+++ b/src/app/api/auth/login/route.ts
@@ -0,0 +1,59 @@
+import { NextRequest, NextResponse } from 'next/server';
+
+import { LoginData } from '@/entities/auth/model/types';
+
+export const GET = async (req: NextRequest) => {
+ if (req.method !== 'GET') {
+ return NextResponse.json(
+ { error: 'Method is not supported' },
+ { status: 405 },
+ );
+ }
+
+ const { searchParams } = req.nextUrl;
+
+ const phoneNumber = searchParams.get('phoneNumber');
+ const cardNumber = searchParams.get('cardNumber');
+ const type = searchParams.get('type');
+
+ if (!phoneNumber || !cardNumber || !type) {
+ return NextResponse.json({ error: 'Bad request' }, { status: 400 });
+ }
+
+ try {
+ const loginRes = await fetch(
+ `https://test.oriyo.tj/api/client/login?type=${type}&phone=${phoneNumber}&uid=${cardNumber}`,
+ {
+ method: 'GET',
+ },
+ );
+
+ if (!loginRes.ok) {
+ return NextResponse.json(
+ { error: 'Error during login' },
+ { status: 400 },
+ );
+ }
+
+ const data = (await loginRes.json()) as LoginData;
+
+ const token = data.token;
+ if (!token) {
+ return NextResponse.json({ error: 'No auth token' }, { status: 401 });
+ }
+
+ const response = NextResponse.json({ success: true });
+
+ response.cookies.set('token', token, {
+ httpOnly: true,
+ path: '/',
+ maxAge: 2 * 60 * 60,
+ secure: process.env.NODE_ENV === 'production',
+ });
+
+ return response;
+ } catch (error) {
+ console.error('login error:', error);
+ return NextResponse.json({ error: 'Server error' }, { status: 500 });
+ }
+};
diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx
index cdb2979..bb9a24e 100644
--- a/src/app/login/page.tsx
+++ b/src/app/login/page.tsx
@@ -1,5 +1,5 @@
-import LoginPage from "@/pages-templates/login";
+import LoginPage from '@/pages-templates/login';
export default function Login() {
- return
-}
\ No newline at end of file
+ return ;
+}
diff --git a/src/entities/auth/api/login.api.ts b/src/entities/auth/api/login.api.ts
new file mode 100644
index 0000000..99ad4ed
--- /dev/null
+++ b/src/entities/auth/api/login.api.ts
@@ -0,0 +1,24 @@
+import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
+
+import { LoginParams, LoginResponse } from '../model/contracts/login.contract';
+
+export const loginAPI = createApi({
+ baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
+ endpoints: (build) => ({
+ login: build.query({
+ query: (data) => {
+ const params = new URLSearchParams({
+ type: data.type,
+ phoneNumber: data.phoneNumber,
+ cardNumber: data.cardNumber,
+ }).toString();
+
+ return {
+ url: `/auth/login?${params}`,
+ };
+ },
+ }),
+ }),
+});
+
+export const { useLazyLoginQuery } = loginAPI;
diff --git a/src/entities/auth/index.ts b/src/entities/auth/index.ts
new file mode 100644
index 0000000..d99a63a
--- /dev/null
+++ b/src/entities/auth/index.ts
@@ -0,0 +1 @@
+export { useLazyLoginQuery } from './api/login.api';
diff --git a/src/entities/auth/model/contracts/login.contract.ts b/src/entities/auth/model/contracts/login.contract.ts
new file mode 100644
index 0000000..cb3a3da
--- /dev/null
+++ b/src/entities/auth/model/contracts/login.contract.ts
@@ -0,0 +1,9 @@
+import { LoginFormData } from '@/features/auth/login-form/model/login-form.schema';
+
+export interface LoginResponse {
+ success: boolean;
+}
+
+export interface LoginParams extends LoginFormData {
+ type: 'bonus' | 'corporate';
+}
diff --git a/src/entities/auth/model/types/index.ts b/src/entities/auth/model/types/index.ts
new file mode 100644
index 0000000..1144cca
--- /dev/null
+++ b/src/entities/auth/model/types/index.ts
@@ -0,0 +1,7 @@
+export interface LoginData {
+ card_id: number;
+ created_at: string;
+ phone: string;
+ token: string;
+ uid: string;
+}
diff --git a/src/features/auth/login-form/model/login-form.schema.ts b/src/features/auth/login-form/model/login-form.schema.ts
index eca9731..a8da155 100644
--- a/src/features/auth/login-form/model/login-form.schema.ts
+++ b/src/features/auth/login-form/model/login-form.schema.ts
@@ -6,13 +6,15 @@ export const loginFormSchema = z.object({
.trim()
.regex(/^[0-9+\-() ]*$/, {
message:
- 'Phone number can only contain numbers, spaces, and the following symbols: + - ( )',
+ 'Номер телефона может содержать только цифры, пробелы и следующие символы: + - ( )',
})
- .refine((val) => !val || val.length >= 5, {
- message:
- 'Phone number is too short. Please enter a complete phone number',
- }),
- cardNumber: z.string().min(16).trim(),
+ .min(5, 'Номер телефона слишком короткий. Введите полный номер телефона')
+ .max(13, 'Номер телефона не может быть длиннее 13 символов'),
+ cardNumber: z
+ .string()
+ .min(6, 'Неверный номер карты. Введите полный номер карты')
+ .max(20, 'Номер карты не может быть длиннее 20 символов')
+ .trim(),
});
export type LoginFormData = z.infer;
diff --git a/src/features/auth/login-form/ui/login-form.tsx b/src/features/auth/login-form/ui/login-form.tsx
index af41279..808756d 100644
--- a/src/features/auth/login-form/ui/login-form.tsx
+++ b/src/features/auth/login-form/ui/login-form.tsx
@@ -5,7 +5,10 @@ import { useRouter } from 'next/navigation';
import { useForm } from 'react-hook-form';
import { toast } from 'sonner';
-import { Button } from '@/shared/shadcn-ui/button';
+import { useLazyLoginQuery } from '@/entities/auth';
+
+import { SubmitButton } from '@/shared/components/submit-button';
+import { useLanguage } from '@/shared/language';
import {
Form,
FormControl,
@@ -17,17 +20,16 @@ import {
import { Input } from '@/shared/shadcn-ui/input';
import { LoginFormData, loginFormSchema } from '../model/login-form.schema';
-import { useLanguage } from '@/shared/language';
interface LoginFormProps {
- // onSubmit: (data: any) => Promise;
+ type: 'bonus' | 'corporate';
}
-export const LoginForm = ({}: LoginFormProps) => {
- const {t} = useLanguage()
+export const LoginForm = ({ type }: LoginFormProps) => {
+ const { t } = useLanguage();
const router = useRouter();
- // const [login, results] = useLoginMutation();
+ const [login, { isLoading: isLoginLoading }] = useLazyLoginQuery();
const form = useForm({
resolver: zodResolver(loginFormSchema),
@@ -38,34 +40,30 @@ export const LoginForm = ({}: LoginFormProps) => {
});
const onSubmit = async (data: LoginFormData) => {
- // const response = await login(data).unwrap();
- // const user = response.data;
- // dispatch(
- // setCredentials({
- // user: {
- // accessToken: user.accessToken,
- // affiliateId: user.affiliateId,
- // email: user.email,
- // id: user.id,
- // role: user.role,
- // username: user.username,
- // },
- // }),
- // );
- toast.success('Logged in successfully!');
+ try {
+ await login({ ...data, type }).unwrap();
- router.push('/customer-dashboard');
+ toast.success('Logged in successfully!');
+ router.push(
+ type === 'bonus' ? '/customer-dashboard' : '/corporate-dashboard',
+ );
+ } catch (error) {
+ toast.error('An error occured during login');
+ }
};
return (
-
);
diff --git a/src/shared/components/submit-button.tsx b/src/shared/components/submit-button.tsx
new file mode 100644
index 0000000..ef9db2d
--- /dev/null
+++ b/src/shared/components/submit-button.tsx
@@ -0,0 +1,36 @@
+import { Loader2Icon } from 'lucide-react';
+
+import { Button, type ButtonProps } from '@/shared/shadcn-ui/button';
+
+interface SubmitButtonProps extends ButtonProps {
+ title?: string;
+ isLoading: boolean;
+}
+
+export const SubmitButton = ({
+ title = 'Отправить',
+ size = 'default',
+ type = 'submit',
+ className,
+ disabled,
+ isLoading,
+ onClick,
+ ...props
+}: SubmitButtonProps) => {
+ return (
+
+ );
+};
diff --git a/src/shared/store/root-reducer.ts b/src/shared/store/root-reducer.ts
index 27360ad..56b999c 100644
--- a/src/shared/store/root-reducer.ts
+++ b/src/shared/store/root-reducer.ts
@@ -1,6 +1,10 @@
import { combineReducers } from '@reduxjs/toolkit';
+
+import { loginAPI } from '@/entities/auth/api/login.api';
+
import { baseAPI } from '@/shared/api/base-api';
export const rootReducer = combineReducers({
[baseAPI.reducerPath]: baseAPI.reducer,
+ [loginAPI.reducerPath]: loginAPI.reducer,
});