| "react-scripts": "4.0.3", | "react-scripts": "4.0.3", | ||||
| "react-select": "^4.3.1", | "react-select": "^4.3.1", | ||||
| "redux": "^4.1.0", | "redux": "^4.1.0", | ||||
| "redux-persist": "^6.0.0", | |||||
| "redux-persist-transform-filter": "0.0.20", | |||||
| "redux-saga": "^1.1.3", | "redux-saga": "^1.1.3", | ||||
| "sass": "^1.34.1", | "sass": "^1.34.1", | ||||
| "web-vitals": "^1.1.2", | "web-vitals": "^1.1.2", |
| import React from 'react'; | |||||
| import ReactDOM from 'react-dom'; | |||||
| import { Provider } from 'react-redux'; | |||||
| import { HelmetProvider } from 'react-helmet-async'; | |||||
| import React from "react"; | |||||
| import ReactDOM from "react-dom"; | |||||
| import { Provider } from "react-redux"; | |||||
| import { HelmetProvider } from "react-helmet-async"; | |||||
| import './main.scss'; | |||||
| import App from './App'; | |||||
| import store from './store'; | |||||
| import "./main.scss"; | |||||
| import App from "./App"; | |||||
| import { store, persistor } from "./store"; | |||||
| import './i18n'; | |||||
| import ColorModeProvider from './context/ColorModeContext'; | |||||
| import "./i18n"; | |||||
| import ColorModeProvider from "./context/ColorModeContext"; | |||||
| import { PersistGate } from "redux-persist/integration/react"; | |||||
| ReactDOM.render( | ReactDOM.render( | ||||
| <HelmetProvider> | <HelmetProvider> | ||||
| <React.StrictMode> | <React.StrictMode> | ||||
| <Provider store={store}> | <Provider store={store}> | ||||
| <ColorModeProvider> | <ColorModeProvider> | ||||
| <PersistGate loading={null} persistor={persistor}> | |||||
| <button onClick={() => console.log(store.getState())}>Dugme</button> | |||||
| <App /> | <App /> | ||||
| </PersistGate> | |||||
| </ColorModeProvider> | </ColorModeProvider> | ||||
| </Provider> | </Provider> | ||||
| </React.StrictMode> | </React.StrictMode> | ||||
| </HelmetProvider>, | </HelmetProvider>, | ||||
| document.getElementById('root'), | |||||
| document.getElementById("root") | |||||
| ); | ); |
| import { createLoadingType } from '../actionHelpers'; | import { createLoadingType } from '../actionHelpers'; | ||||
| export const APP_LOADING = createLoadingType('APP_LOADING'); | export const APP_LOADING = createLoadingType('APP_LOADING'); | ||||
| export const UPDATE_LOADER = createLoadingType("UPDATE_LOADER") |
| import loadingMiddleware from './middleware/loadingMiddleware'; | import loadingMiddleware from './middleware/loadingMiddleware'; | ||||
| import requestStatusMiddleware from './middleware/requestStatusMiddleware'; | import requestStatusMiddleware from './middleware/requestStatusMiddleware'; | ||||
| import internalServerErrorMiddleware from './middleware/internalServerErrorMiddleware'; | import internalServerErrorMiddleware from './middleware/internalServerErrorMiddleware'; | ||||
| import persistStore from 'redux-persist/es/persistStore'; | |||||
| const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; | ||||
| const sagaMiddleware = createSagaMiddleware(); | const sagaMiddleware = createSagaMiddleware(); | ||||
| export default createStore( | |||||
| export const store = createStore( | |||||
| rootReducer, | rootReducer, | ||||
| composeEnhancers( | composeEnhancers( | ||||
| applyMiddleware( | applyMiddleware( | ||||
| ), | ), | ||||
| ), | ), | ||||
| ); | ); | ||||
| export const persistor = persistStore(store); | |||||
| sagaMiddleware.run(rootSaga); | sagaMiddleware.run(rootSaga); |
| import { combineReducers } from 'redux'; | |||||
| import loginReducer from './login/loginReducer'; | |||||
| import loadingReducer from './loading/loadingReducer'; | |||||
| import userReducer from './user/userReducer'; | |||||
| import randomDataReducer from './randomData/randomDataReducer'; | |||||
| import { combineReducers } from "redux"; | |||||
| import loginReducer from "./login/loginReducer"; | |||||
| import loadingReducer from "./loading/loadingReducer"; | |||||
| import userReducer from "./user/userReducer"; | |||||
| import randomDataReducer from "./randomData/randomDataReducer"; | |||||
| import storage from "redux-persist/lib/storage"; | |||||
| import createFilter from "redux-persist-transform-filter"; | |||||
| import persistReducer from "redux-persist/es/persistReducer"; | |||||
| const loginPersistConfig = { | |||||
| key: "login", | |||||
| storage: storage, | |||||
| transform: [createFilter("login", ["email", "token", "errorMessage"])], | |||||
| }; | |||||
| const userPersistConfig = { | |||||
| key: "user", | |||||
| storage: storage, | |||||
| transform: [createFilter("user", ["user"])], | |||||
| }; | |||||
| const randomDataPersistConfig = { | |||||
| key: "randomData", | |||||
| storage: storage, | |||||
| transform: [ | |||||
| createFilter("randomData", [ | |||||
| "items", | |||||
| "filteredItems", | |||||
| "count", | |||||
| "page", | |||||
| "itemsPerPage", | |||||
| "filter", | |||||
| "sort", | |||||
| ]), | |||||
| ], | |||||
| }; | |||||
| export default combineReducers({ | export default combineReducers({ | ||||
| login: loginReducer, | |||||
| user: userReducer, | |||||
| loading:loadingReducer, | |||||
| randomData: randomDataReducer | |||||
| login: persistReducer(loginPersistConfig, loginReducer), | |||||
| user: persistReducer(userPersistConfig, userReducer), | |||||
| loading: loadingReducer, | |||||
| randomData: persistReducer(randomDataPersistConfig, randomDataReducer), | |||||
| }); | }); |
| import createReducer from '../../utils/createReducer'; | |||||
| import { APP_LOADING } from '../../actions/app/appActionConstants'; | |||||
| import { RESET_LOGIN_STATE } from '../../actions/login/loginActionConstants'; | |||||
| import createReducer from "../../utils/createReducer"; | |||||
| import { | |||||
| APP_LOADING, | |||||
| UPDATE_LOADER, | |||||
| } from "../../actions/app/appActionConstants"; | |||||
| import { RESET_LOGIN_STATE } from "../../actions/login/loginActionConstants"; | |||||
| const initialState = { | const initialState = { | ||||
| [APP_LOADING]: true, | [APP_LOADING]: true, | ||||
| }; | }; | ||||
| export default createReducer( | export default createReducer( | ||||
| { | { | ||||
| UPDATE_LOADER: updateLoader, | |||||
| [UPDATE_LOADER]: updateLoader, | |||||
| [APP_LOADING]: updateAppReadyLoader, | [APP_LOADING]: updateAppReadyLoader, | ||||
| [RESET_LOGIN_STATE]: setAppNotReady, | [RESET_LOGIN_STATE]: setAppNotReady, | ||||
| }, | }, | ||||
| initialState, | |||||
| initialState | |||||
| ); | ); | ||||
| function updateLoader(state, action) { | function updateLoader(state, action) { |
| import storage from "redux-persist/lib/storage"; | |||||
| const createStorageKey = (key) => `persist:${key}`; | |||||
| export const LOGIN_KEY = createStorageKey(`login`); | |||||
| export const USER_KEY = createStorageKey(`user`); | |||||
| export const RANDOM_DATA_KEY = createStorageKey(`randomData`); | |||||
| export const getFromStorage = async (key) => { | |||||
| const item = await storage.getItem(key); | |||||
| if (!item) { | |||||
| return Promise.reject("Item is not found!"); | |||||
| } | |||||
| //Deserialization of whole item | |||||
| const itemJson = JSON.parse(item); | |||||
| //Deserialization of each property (it must be done when dealing with persistor) | |||||
| const itemProperties = Object.getOwnPropertyNames(itemJson); | |||||
| itemProperties.forEach((property) => { | |||||
| itemJson[property] = JSON.parse(itemJson[property]); | |||||
| }); | |||||
| return Promise.resolve(itemJson); | |||||
| }; |