diff --git a/frontend/admin-web/package-lock.json b/frontend/admin-web/package-lock.json index 04f75e2b..8493706a 100644 --- a/frontend/admin-web/package-lock.json +++ b/frontend/admin-web/package-lock.json @@ -18,6 +18,7 @@ "react-dom": "^18.3.1", "react-redux": "^9.2.0", "recharts": "^2.15.0", + "redux-persist": "^6.0.0", "xlsx": "^0.18.5", "zustand": "^5.0.3" }, @@ -5346,6 +5347,15 @@ "license": "MIT", "peer": true }, + "node_modules/redux-persist": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-6.0.0.tgz", + "integrity": "sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==", + "license": "MIT", + "peerDependencies": { + "redux": ">4.0.0" + } + }, "node_modules/redux-thunk": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", diff --git a/frontend/admin-web/package.json b/frontend/admin-web/package.json index 396f7dbc..33a11502 100644 --- a/frontend/admin-web/package.json +++ b/frontend/admin-web/package.json @@ -24,6 +24,7 @@ "react-dom": "^18.3.1", "react-redux": "^9.2.0", "recharts": "^2.15.0", + "redux-persist": "^6.0.0", "xlsx": "^0.18.5", "zustand": "^5.0.3" }, diff --git a/frontend/admin-web/src/app/providers.tsx b/frontend/admin-web/src/app/providers.tsx index 1e802eca..e47f00d6 100644 --- a/frontend/admin-web/src/app/providers.tsx +++ b/frontend/admin-web/src/app/providers.tsx @@ -1,9 +1,10 @@ 'use client'; import { Provider } from 'react-redux'; +import { PersistGate } from 'redux-persist/integration/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { useState } from 'react'; -import { store } from '@/store/redux/store'; +import { store, persistor } from '@/store/redux/store'; export function Providers({ children }: { children: React.ReactNode }) { const [queryClient] = useState( @@ -20,7 +21,9 @@ export function Providers({ children }: { children: React.ReactNode }) { return ( - {children} + + {children} + ); } diff --git a/frontend/admin-web/src/store/redux/slices/authSlice.ts b/frontend/admin-web/src/store/redux/slices/authSlice.ts index 4ab72395..8d4c615f 100644 --- a/frontend/admin-web/src/store/redux/slices/authSlice.ts +++ b/frontend/admin-web/src/store/redux/slices/authSlice.ts @@ -1,4 +1,5 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { REHYDRATE } from 'redux-persist'; import type { User } from '@/types/user.types'; interface AuthState { @@ -51,6 +52,19 @@ const authSlice = createSlice({ } }, }, + extraReducers: (builder) => { + builder.addCase(REHYDRATE, (state, action: PayloadAction<{ auth?: AuthState } | undefined>) => { + if (action.payload?.auth) { + const rehydratedAuth = action.payload.auth; + state.user = rehydratedAuth.user; + state.token = rehydratedAuth.token; + state.refreshToken = rehydratedAuth.refreshToken; + state.permissions = rehydratedAuth.permissions; + state.isAuthenticated = rehydratedAuth.isAuthenticated; + } + state.loading = false; + }); + }, }); export const { setCredentials, logout, setLoading, updateUser } = authSlice.actions; diff --git a/frontend/admin-web/src/store/redux/store.ts b/frontend/admin-web/src/store/redux/store.ts index 9a6350dd..9659a673 100644 --- a/frontend/admin-web/src/store/redux/store.ts +++ b/frontend/admin-web/src/store/redux/store.ts @@ -1,16 +1,46 @@ -import { configureStore } from '@reduxjs/toolkit'; +import { configureStore, combineReducers } from '@reduxjs/toolkit'; +import { + persistStore, + persistReducer, + FLUSH, + REHYDRATE, + PAUSE, + PERSIST, + PURGE, + REGISTER, +} from 'redux-persist'; +import storage from 'redux-persist/lib/storage'; import authReducer from './slices/authSlice'; import settingsReducer from './slices/settingsSlice'; import notificationReducer from './slices/notificationSlice'; +const rootReducer = combineReducers({ + auth: authReducer, + settings: settingsReducer, + notification: notificationReducer, +}); + +const persistConfig = { + key: 'rwadurian-admin', + version: 1, + storage, + whitelist: ['auth'], // εͺζŒδΉ…εŒ– auth slice +}; + +const persistedReducer = persistReducer(persistConfig, rootReducer); + export const store = configureStore({ - reducer: { - auth: authReducer, - settings: settingsReducer, - notification: notificationReducer, - }, + reducer: persistedReducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + serializableCheck: { + ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], + }, + }), devTools: process.env.NODE_ENV !== 'production', }); +export const persistor = persistStore(store); + export type RootState = ReturnType; export type AppDispatch = typeof store.dispatch;