diff --git a/package.json b/package.json index aa35261..eadb499 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@mui/icons-material": "^5.16.6", "@mui/material": "^5.16.6", "@mui/material-nextjs": "^5.16.6", + "@reduxjs/toolkit": "^2.2.7", "@tanstack/react-table": "^8.20.1", "axios": "^1.7.3", "moment": "^2.30.1", @@ -23,6 +24,7 @@ "react": "^18", "react-dom": "^18", "react-hook-form": "^7.52.2", + "react-redux": "^9.1.2", "sass": "^1.77.8", "zod": "^3.23.8" }, diff --git a/src/app/(auth)/log-in/page.tsx b/src/app/(auth)/log-in/page.tsx index 5116a68..01b1cbf 100644 --- a/src/app/(auth)/log-in/page.tsx +++ b/src/app/(auth)/log-in/page.tsx @@ -16,6 +16,9 @@ import { loginApi } from "@/services/api/loginApi"; import { FormControl } from '@mui/material'; import CustomTextField from "@/ui/CustomTextField"; import { useRouter } from "next/navigation"; +import { useDispatch, useSelector } from "react-redux"; +import { RootState } from "@/services/store"; +import { setAuthTokens, setUserDetails } from "@/services/store/authSlice"; const loginSchema = z.object({ username: z.string(), @@ -29,14 +32,15 @@ export default function LoginPage() { const { register, handleSubmit, formState: { errors }, control } = useForm({ resolver: zodResolver(loginSchema), }); - console.log("errors", errors) const [error, setError] = useState(''); - + const dispatch = useDispatch(); const onSubmit = async (data: LoginFormValues) => { try { const response = await loginApi(data); localStorage.setItem('token', response.token); localStorage.setItem('refreshToken', response.refreshToken); + dispatch(setAuthTokens({ token: response.token, refreshToken: response.refreshToken })); + dispatch(setUserDetails(response)); router.push('/home'); } catch (err) { diff --git a/src/app/layout.tsx b/src/app/layout.tsx index a6980ec..9c4b1a8 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,7 +1,10 @@ +"use client" import { AppRouterCacheProvider } from "@mui/material-nextjs/v13-appRouter"; import { ThemeProvider } from "@mui/material/styles"; import theme from "../theme"; import "./globals.scss"; +import { Provider } from 'react-redux'; +import store from "@/services/store"; interface RootLayoutProps { children: React.ReactNode; @@ -12,9 +15,11 @@ export default function RootLayout(props: RootLayoutProps): JSX.Element { return ( - - {children} - + + + {children} + + ); diff --git a/src/services/api/loginApi.ts b/src/services/api/loginApi.ts index 7837ff9..59bb92e 100644 --- a/src/services/api/loginApi.ts +++ b/src/services/api/loginApi.ts @@ -1,7 +1,7 @@ // api.ts import axiosInstance from '../axios/axiosInstance'; -interface LoginResponse { +export interface LoginResponse { id: number; username: string; email: string; diff --git a/src/services/store/authSlice.ts b/src/services/store/authSlice.ts new file mode 100644 index 0000000..e5511b1 --- /dev/null +++ b/src/services/store/authSlice.ts @@ -0,0 +1,57 @@ +// store/slices/authSlice.ts +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { LoginResponse } from '../api/loginApi'; + +interface AuthState { + token: string | null; + refreshToken: string | null; + id: number; + username: string; + email: string; + firstName: string; + lastName: string; + gender: string; + image: string; +} + +const initialState: AuthState = { + token: null, + refreshToken: null, + id: 0, + username: '', + email: '', + firstName: '', + lastName: '', + gender: '', + image: '', +}; + +const authSlice = createSlice({ + name: 'auth', + initialState, + reducers: { + setAuthTokens: ( + state, + action: PayloadAction<{ token: string; refreshToken: string }> + ) => { + state.token = action.payload.token; + state.refreshToken = action.payload.refreshToken; + localStorage.setItem('token', action.payload.token); + localStorage.setItem('refreshToken', action.payload.refreshToken); + }, + clearAuthTokens: (state) => { + state.token = null; + state.refreshToken = null; + localStorage.removeItem('token'); + localStorage.removeItem('refreshToken'); + }, + setUserDetails: (state, action: PayloadAction) => { + state = action.payload; + }, + }, +}); + +export const { setAuthTokens, clearAuthTokens, setUserDetails } = + authSlice.actions; + +export default authSlice.reducer; diff --git a/src/services/store/index.tsx b/src/services/store/index.tsx new file mode 100644 index 0000000..b3f906d --- /dev/null +++ b/src/services/store/index.tsx @@ -0,0 +1,15 @@ + +// store/index.ts +import { configureStore } from '@reduxjs/toolkit'; +import authReducer from './authSlice'; + +const store = configureStore({ + reducer: { + auth: authReducer, + }, +}); + +export type RootState = ReturnType; +export type AppDispatch = typeof store.dispatch; + +export default store;