diff --git a/frontend/app/package-lock.json b/frontend/app/package-lock.json
index e8441e0..b92bd66 100644
--- a/frontend/app/package-lock.json
+++ b/frontend/app/package-lock.json
@@ -9,6 +9,7 @@
"version": "1.0.0",
"dependencies": {
"@ant-design/icons": "^5.3.5",
+ "@reduxjs/toolkit": "^2.2.2",
"antd": "^5.15.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -400,6 +401,29 @@
"react-dom": ">=16.9.0"
}
},
+ "node_modules/@reduxjs/toolkit": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.2.tgz",
+ "integrity": "sha512-454GZrEx3G6QSYwIx9ROaso1HR6sTH8qyZBe3KEsdWVGU3ayV8jYCwdaEJV3vl9V6+pi3GRl+7Xl7AeDna6qwQ==",
+ "dependencies": {
+ "immer": "^10.0.3",
+ "redux": "^5.0.1",
+ "redux-thunk": "^3.1.0",
+ "reselect": "^5.0.1"
+ },
+ "peerDependencies": {
+ "react": "^16.9.0 || ^17.0.0 || ^18",
+ "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "react": {
+ "optional": true
+ },
+ "react-redux": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rsbuild/core": {
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-0.5.4.tgz",
@@ -2364,6 +2388,15 @@
"node": ">= 4"
}
},
+ "node_modules/immer": {
+ "version": "10.0.4",
+ "resolved": "https://registry.npmjs.org/immer/-/immer-10.0.4.tgz",
+ "integrity": "sha512-cuBuGK40P/sk5IzWa9QPUaAdvPHjkk1c+xYsd9oZw+YQQEV+10G0P5uMpGctZZKnyQ+ibRO08bD25nWLmYi2pw==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/immer"
+ }
+ },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -3979,6 +4012,19 @@
"node": ">=0.10.0"
}
},
+ "node_modules/redux": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
+ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="
+ },
+ "node_modules/redux-thunk": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
+ "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
+ "peerDependencies": {
+ "redux": "^5.0.0"
+ }
+ },
"node_modules/reflect.getprototypeof": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
@@ -4023,6 +4069,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/reselect": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz",
+ "integrity": "sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg=="
+ },
"node_modules/resize-observer-polyfill": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
diff --git a/frontend/app/package.json b/frontend/app/package.json
index 7d7b8f4..1a0092f 100644
--- a/frontend/app/package.json
+++ b/frontend/app/package.json
@@ -9,6 +9,7 @@
},
"dependencies": {
"@ant-design/icons": "^5.3.5",
+ "@reduxjs/toolkit": "^2.2.2",
"antd": "^5.15.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
diff --git a/frontend/app/src/App.tsx b/frontend/app/src/App.tsx
index 3b1b482..24f06dc 100644
--- a/frontend/app/src/App.tsx
+++ b/frontend/app/src/App.tsx
@@ -1,15 +1,20 @@
-import { ConfigProvider } from 'antd';
-import './App.css';
-import HeaderComponent from './components/HeaderComponent';
-import { theme } from './config/style';
+import React from "react";
+import { ConfigProvider } from "antd";
+import "./App.css";
+import HeaderComponent from "./components/HeaderComponent";
+import { theme } from "./config/style";
+import { Provider } from "react-redux";
+import { store } from "./config/store";
const App = () => {
return (
-
-
-
-
-
+
+
+
+
+
+
+
);
};
diff --git a/frontend/app/src/config/baseUrl.ts b/frontend/app/src/config/baseUrl.ts
new file mode 100644
index 0000000..331e71a
--- /dev/null
+++ b/frontend/app/src/config/baseUrl.ts
@@ -0,0 +1 @@
+export const baseUrl = "http://localhost/api/"
\ No newline at end of file
diff --git a/frontend/app/src/config/store.ts b/frontend/app/src/config/store.ts
new file mode 100644
index 0000000..44a211b
--- /dev/null
+++ b/frontend/app/src/config/store.ts
@@ -0,0 +1,18 @@
+import { configureStore } from '@reduxjs/toolkit'
+import { setupListeners } from '@reduxjs/toolkit/query'
+import { AuthApi } from '../slice/AuthApi'
+
+export const store = configureStore({
+ reducer: {
+ // Add the generated reducer as a specific top-level slice
+ [AuthApi.reducerPath]: AuthApi.reducer,
+ },
+ // Adding the api middleware enables caching, invalidation, polling,
+ // and other useful features of `rtk-query`.
+ middleware: (getDefaultMiddleware) =>
+ getDefaultMiddleware().concat(AuthApi.middleware),
+})
+
+// optional, but required for refetchOnFocus/refetchOnReconnect behaviors
+// see `setupListeners` docs - takes an optional callback as the 2nd arg for customization
+setupListeners(store.dispatch)
\ No newline at end of file
diff --git a/frontend/app/src/slice/AuthApi.ts b/frontend/app/src/slice/AuthApi.ts
new file mode 100644
index 0000000..cb9d6d7
--- /dev/null
+++ b/frontend/app/src/slice/AuthApi.ts
@@ -0,0 +1,14 @@
+import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
+import { baseUrl } from '../config/baseUrl'
+
+export const AuthApi = createApi({
+ reducerPath: 'AuthApi',
+ baseQuery: fetchBaseQuery({ baseUrl: `${baseUrl}auth/` }),
+ endpoints: (builder) => ({
+ getUser: builder.query({
+ query: () => 'me/',
+ }),
+ }),
+})
+
+export const { useGetUserQuery } = AuthApi
\ No newline at end of file
diff --git a/frontend/app/src/slice/UserApi.ts b/frontend/app/src/slice/UserApi.ts
deleted file mode 100644
index e69de29..0000000