init: add fuse-react v8.3.5 skeleton
This commit is contained in:
28
src/app/store/fuse/dialogSlice.js
Normal file
28
src/app/store/fuse/dialogSlice.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
const dialogSlice = createSlice({
|
||||
name: 'dialog',
|
||||
initialState: {
|
||||
state: false,
|
||||
options: {
|
||||
children: 'Hi',
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
openDialog: (state, action) => {
|
||||
state.state = true;
|
||||
state.options = action.payload;
|
||||
},
|
||||
closeDialog: (state, action) => {
|
||||
state.state = false;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { openDialog, closeDialog } = dialogSlice.actions;
|
||||
|
||||
export const selectFuseDialogState = ({ fuse }) => fuse.dialog.state;
|
||||
|
||||
export const selectFuseDialogOptions = ({ fuse }) => fuse.dialog.options;
|
||||
|
||||
export default dialogSlice.reducer;
|
||||
16
src/app/store/fuse/index.js
Normal file
16
src/app/store/fuse/index.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { combineReducers } from '@reduxjs/toolkit';
|
||||
import dialog from './dialogSlice';
|
||||
import message from './messageSlice';
|
||||
import navbar from './navbarSlice';
|
||||
import navigation from './navigationSlice';
|
||||
import settings from './settingsSlice';
|
||||
|
||||
const fuseReducers = combineReducers({
|
||||
navigation,
|
||||
settings,
|
||||
navbar,
|
||||
message,
|
||||
dialog,
|
||||
});
|
||||
|
||||
export default fuseReducers;
|
||||
38
src/app/store/fuse/messageSlice.js
Normal file
38
src/app/store/fuse/messageSlice.js
Normal file
@@ -0,0 +1,38 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
const initialState = {
|
||||
state: null,
|
||||
options: {
|
||||
anchorOrigin: {
|
||||
vertical: 'top',
|
||||
horizontal: 'center',
|
||||
},
|
||||
autoHideDuration: 2000,
|
||||
message: 'Hi',
|
||||
variant: null,
|
||||
},
|
||||
};
|
||||
const messageSlice = createSlice({
|
||||
name: 'message',
|
||||
initialState,
|
||||
reducers: {
|
||||
showMessage: (state, action) => {
|
||||
state.state = true;
|
||||
state.options = {
|
||||
...initialState.options,
|
||||
...action.payload,
|
||||
};
|
||||
},
|
||||
hideMessage: (state, action) => {
|
||||
state.state = null;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { hideMessage, showMessage } = messageSlice.actions;
|
||||
|
||||
export const selectFuseMessageState = ({ fuse }) => fuse.message.state;
|
||||
|
||||
export const selectFuseMessageOptions = ({ fuse }) => fuse.message.options;
|
||||
|
||||
export default messageSlice.reducer;
|
||||
54
src/app/store/fuse/navbarSlice.js
Normal file
54
src/app/store/fuse/navbarSlice.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
const navbarSlice = createSlice({
|
||||
name: 'navbar',
|
||||
initialState: {
|
||||
open: true,
|
||||
mobileOpen: false,
|
||||
},
|
||||
reducers: {
|
||||
navbarToggleFolded: (state, action) => {
|
||||
state.foldedOpen = !state.foldedOpen;
|
||||
},
|
||||
navbarOpenFolded: (state, action) => {
|
||||
state.foldedOpen = true;
|
||||
},
|
||||
navbarCloseFolded: (state, action) => {
|
||||
state.foldedOpen = false;
|
||||
},
|
||||
navbarToggleMobile: (state, action) => {
|
||||
state.mobileOpen = !state.mobileOpen;
|
||||
},
|
||||
navbarOpenMobile: (state, action) => {
|
||||
state.mobileOpen = true;
|
||||
},
|
||||
navbarCloseMobile: (state, action) => {
|
||||
state.mobileOpen = false;
|
||||
},
|
||||
navbarClose: (state, action) => {
|
||||
state.open = false;
|
||||
},
|
||||
navbarOpen: (state, action) => {
|
||||
state.open = true;
|
||||
},
|
||||
navbarToggle: (state, action) => {
|
||||
state.open = !state.open;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
navbarToggleFolded,
|
||||
navbarOpenFolded,
|
||||
navbarCloseFolded,
|
||||
navbarOpen,
|
||||
navbarClose,
|
||||
navbarToggle,
|
||||
navbarOpenMobile,
|
||||
navbarCloseMobile,
|
||||
navbarToggleMobile,
|
||||
} = navbarSlice.actions;
|
||||
|
||||
export const selectFuseNavbar = ({ fuse }) => fuse.navbar;
|
||||
|
||||
export default navbarSlice.reducer;
|
||||
96
src/app/store/fuse/navigationSlice.js
Normal file
96
src/app/store/fuse/navigationSlice.js
Normal file
@@ -0,0 +1,96 @@
|
||||
import { createEntityAdapter, createSelector, createSlice } from '@reduxjs/toolkit';
|
||||
import navigationConfig from 'app/configs/navigationConfig';
|
||||
import FuseUtils from '@fuse/utils';
|
||||
import i18next from 'i18next';
|
||||
import _ from '@lodash';
|
||||
|
||||
const navigationAdapter = createEntityAdapter();
|
||||
const emptyInitialState = navigationAdapter.getInitialState();
|
||||
const initialState = navigationAdapter.upsertMany(emptyInitialState, navigationConfig);
|
||||
|
||||
export const appendNavigationItem = (item, parentId) => (dispatch, getState) => {
|
||||
const navigation = selectNavigationAll(getState());
|
||||
|
||||
return dispatch(setNavigation(FuseUtils.appendNavItem(navigation, item, parentId)));
|
||||
};
|
||||
|
||||
export const prependNavigationItem = (item, parentId) => (dispatch, getState) => {
|
||||
const navigation = selectNavigationAll(getState());
|
||||
|
||||
return dispatch(setNavigation(FuseUtils.prependNavItem(navigation, item, parentId)));
|
||||
};
|
||||
|
||||
export const updateNavigationItem = (id, item) => (dispatch, getState) => {
|
||||
const navigation = selectNavigationAll(getState());
|
||||
|
||||
return dispatch(setNavigation(FuseUtils.updateNavItem(navigation, id, item)));
|
||||
};
|
||||
|
||||
export const removeNavigationItem = (id) => (dispatch, getState) => {
|
||||
const navigation = selectNavigationAll(getState());
|
||||
|
||||
return dispatch(setNavigation(FuseUtils.removeNavItem(navigation, id)));
|
||||
};
|
||||
|
||||
export const {
|
||||
selectAll: selectNavigationAll,
|
||||
selectIds: selectNavigationIds,
|
||||
selectById: selectNavigationItemById,
|
||||
} = navigationAdapter.getSelectors((state) => state.fuse.navigation);
|
||||
|
||||
const navigationSlice = createSlice({
|
||||
name: 'navigation',
|
||||
initialState,
|
||||
reducers: {
|
||||
setNavigation: navigationAdapter.setAll,
|
||||
resetNavigation: (state, action) => initialState,
|
||||
},
|
||||
});
|
||||
|
||||
export const { setNavigation, resetNavigation } = navigationSlice.actions;
|
||||
|
||||
const getUserRole = (state) => state.user.role;
|
||||
|
||||
export const selectNavigation = createSelector(
|
||||
[selectNavigationAll, ({ i18n }) => i18n.language, getUserRole],
|
||||
(navigation, language, userRole) => {
|
||||
function setTranslationValues(data) {
|
||||
// loop through every object in the array
|
||||
return data.map((item) => {
|
||||
if (item.translate && item.title) {
|
||||
item.title = i18next.t(`navigation:${item.translate}`);
|
||||
}
|
||||
|
||||
// see if there is a children node
|
||||
if (item.children) {
|
||||
// run this function recursively on the children array
|
||||
item.children = setTranslationValues(item.children);
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
|
||||
return setTranslationValues(
|
||||
_.merge(
|
||||
[],
|
||||
filterRecursively(navigation, (item) => FuseUtils.hasPermission(item.auth, userRole))
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function filterRecursively(arr, predicate) {
|
||||
return arr.filter(predicate).map((item) => {
|
||||
item = { ...item };
|
||||
if (item.children) {
|
||||
item.children = filterRecursively(item.children, predicate);
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
|
||||
export const selectFlatNavigation = createSelector([selectNavigation], (navigation) =>
|
||||
FuseUtils.getFlatNavigation(navigation)
|
||||
);
|
||||
|
||||
export default navigationSlice.reducer;
|
||||
239
src/app/store/fuse/settingsSlice.js
Normal file
239
src/app/store/fuse/settingsSlice.js
Normal file
@@ -0,0 +1,239 @@
|
||||
import { createTheme, getContrastRatio } from '@mui/material/styles';
|
||||
import { createAsyncThunk, createSelector, createSlice } from '@reduxjs/toolkit';
|
||||
import _ from '@lodash';
|
||||
import {
|
||||
defaultSettings,
|
||||
defaultThemeOptions,
|
||||
extendThemeWithMixins,
|
||||
getParsedQuerySettings,
|
||||
mustHaveThemeOptions,
|
||||
} from '@fuse/default-settings';
|
||||
import settingsConfig from 'app/configs/settingsConfig';
|
||||
import themeLayoutConfigs from 'app/theme-layouts/themeLayoutConfigs';
|
||||
import { setUser, updateUserSettings } from 'app/store/userSlice';
|
||||
import { darkPaletteText, lightPaletteText } from 'app/configs/themesConfig';
|
||||
|
||||
export const changeFuseTheme = (theme) => (dispatch, getState) => {
|
||||
const { fuse } = getState();
|
||||
const { settings } = fuse;
|
||||
|
||||
const newSettings = {
|
||||
...settings.current,
|
||||
theme: {
|
||||
main: theme,
|
||||
navbar: theme,
|
||||
toolbar: theme,
|
||||
footer: theme,
|
||||
},
|
||||
};
|
||||
|
||||
dispatch(setDefaultSettings(newSettings));
|
||||
};
|
||||
|
||||
function getInitialSettings() {
|
||||
const defaultLayoutStyle =
|
||||
settingsConfig.layout && settingsConfig.layout.style ? settingsConfig.layout.style : 'layout1';
|
||||
const layout = {
|
||||
style: defaultLayoutStyle,
|
||||
config: themeLayoutConfigs[defaultLayoutStyle].defaults,
|
||||
};
|
||||
return _.merge({}, defaultSettings, { layout }, settingsConfig, getParsedQuerySettings());
|
||||
}
|
||||
|
||||
export function generateSettings(_defaultSettings, _newSettings) {
|
||||
const response = _.merge(
|
||||
{},
|
||||
_defaultSettings,
|
||||
{ layout: { config: themeLayoutConfigs[_newSettings?.layout?.style]?.defaults } },
|
||||
_newSettings
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
const initialSettings = getInitialSettings();
|
||||
|
||||
const initialState = {
|
||||
initial: initialSettings,
|
||||
defaults: _.merge({}, initialSettings),
|
||||
current: _.merge({}, initialSettings),
|
||||
};
|
||||
|
||||
export const setDefaultSettings = createAsyncThunk(
|
||||
'fuse/settings/setDefaultSettings',
|
||||
async (val, { dispatch, getState }) => {
|
||||
const { fuse } = getState();
|
||||
const { settings } = fuse;
|
||||
const defaults = generateSettings(settings.defaults, val);
|
||||
|
||||
dispatch(updateUserSettings(defaults));
|
||||
|
||||
return {
|
||||
...settings,
|
||||
defaults: _.merge({}, defaults),
|
||||
current: _.merge({}, defaults),
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const settingsSlice = createSlice({
|
||||
name: 'settings',
|
||||
initialState,
|
||||
reducers: {
|
||||
setSettings: (state, action) => {
|
||||
const current = generateSettings(state.defaults, action.payload);
|
||||
|
||||
return {
|
||||
...state,
|
||||
current,
|
||||
};
|
||||
},
|
||||
|
||||
setInitialSettings: (state, action) => {
|
||||
return _.merge({}, initialState);
|
||||
},
|
||||
resetSettings: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
defaults: _.merge({}, state.defaults),
|
||||
current: _.merge({}, state.defaults),
|
||||
};
|
||||
},
|
||||
},
|
||||
extraReducers: {
|
||||
[setDefaultSettings.fulfilled]: (state, action) => action.payload,
|
||||
[setUser.fulfilled]: (state, action) => {
|
||||
const defaults = generateSettings(state.defaults, action.payload?.data?.settings);
|
||||
return {
|
||||
...state,
|
||||
defaults: _.merge({}, defaults),
|
||||
current: _.merge({}, defaults),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const getDirection = (state) => state.fuse.settings.current.direction;
|
||||
const getMainTheme = (state) => state.fuse.settings.current.theme.main;
|
||||
const getNavbarTheme = (state) => state.fuse.settings.current.theme.navbar;
|
||||
const getToolbarTheme = (state) => state.fuse.settings.current.theme.toolbar;
|
||||
const getFooterTheme = (state) => state.fuse.settings.current.theme.footer;
|
||||
|
||||
function generateMuiTheme(theme, direction) {
|
||||
const data = _.merge({}, defaultThemeOptions, theme, mustHaveThemeOptions);
|
||||
const response = createTheme(
|
||||
_.merge({}, data, {
|
||||
mixins: extendThemeWithMixins(data),
|
||||
direction,
|
||||
})
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
export const selectContrastMainTheme = (bgColor) => {
|
||||
function isDark(color) {
|
||||
return getContrastRatio(color, '#ffffff') >= 3;
|
||||
}
|
||||
return isDark(bgColor) ? selectMainThemeDark : selectMainThemeLight;
|
||||
};
|
||||
|
||||
function changeThemeMode(theme, mode) {
|
||||
const modes = {
|
||||
dark: {
|
||||
palette: {
|
||||
mode: 'dark',
|
||||
divider: 'rgba(241,245,249,.12)',
|
||||
background: {
|
||||
paper: '#1E2125',
|
||||
default: '#121212',
|
||||
},
|
||||
text: darkPaletteText,
|
||||
},
|
||||
},
|
||||
light: {
|
||||
palette: {
|
||||
mode: 'light',
|
||||
divider: '#e2e8f0',
|
||||
background: {
|
||||
paper: '#FFFFFF',
|
||||
default: '#F7F7F7',
|
||||
},
|
||||
text: lightPaletteText,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return _.merge({}, theme, modes[mode]);
|
||||
}
|
||||
|
||||
export const selectMainTheme = createSelector(
|
||||
[getMainTheme, getDirection],
|
||||
(theme, direction, id) => generateMuiTheme(theme, direction)
|
||||
);
|
||||
|
||||
export const selectMainThemeDark = createSelector(
|
||||
[getMainTheme, getDirection],
|
||||
(theme, direction) => generateMuiTheme(changeThemeMode(theme, 'dark'), direction)
|
||||
);
|
||||
|
||||
export const selectMainThemeLight = createSelector(
|
||||
[getMainTheme, getDirection],
|
||||
(theme, direction) => generateMuiTheme(changeThemeMode(theme, 'light'), direction)
|
||||
);
|
||||
|
||||
export const selectNavbarTheme = createSelector(
|
||||
[getNavbarTheme, getDirection],
|
||||
(theme, direction) => generateMuiTheme(theme, direction)
|
||||
);
|
||||
|
||||
export const selectNavbarThemeDark = createSelector(
|
||||
[getNavbarTheme, getDirection],
|
||||
(theme, direction) => generateMuiTheme(changeThemeMode(theme, 'dark'), direction)
|
||||
);
|
||||
|
||||
export const selectNavbarThemeLight = createSelector(
|
||||
[getNavbarTheme, getDirection],
|
||||
(theme, direction) => generateMuiTheme(changeThemeMode(theme, 'light'), direction)
|
||||
);
|
||||
|
||||
export const selectToolbarTheme = createSelector(
|
||||
[getToolbarTheme, getDirection],
|
||||
(theme, direction) => generateMuiTheme(theme, direction)
|
||||
);
|
||||
|
||||
export const selectToolbarThemeDark = createSelector(
|
||||
[getToolbarTheme, getDirection],
|
||||
(theme, direction) => generateMuiTheme(changeThemeMode(theme, 'dark'), direction)
|
||||
);
|
||||
|
||||
export const selectToolbarThemeLight = createSelector(
|
||||
[getToolbarTheme, getDirection],
|
||||
(theme, direction) => generateMuiTheme(changeThemeMode(theme, 'light'), direction)
|
||||
);
|
||||
|
||||
export const selectFooterTheme = createSelector(
|
||||
[getFooterTheme, getDirection],
|
||||
(theme, direction) => generateMuiTheme(theme, direction)
|
||||
);
|
||||
|
||||
export const selectFooterThemeDark = createSelector(
|
||||
[getFooterTheme, getDirection],
|
||||
(theme, direction) => generateMuiTheme(changeThemeMode(theme, 'dark'), direction)
|
||||
);
|
||||
|
||||
export const selectFooterThemeLight = createSelector(
|
||||
[getFooterTheme, getDirection],
|
||||
(theme, direction) => generateMuiTheme(changeThemeMode(theme, 'light'), direction)
|
||||
);
|
||||
|
||||
export const selectFuseCurrentSettings = ({ fuse }) => fuse.settings.current;
|
||||
|
||||
export const selectFuseCurrentLayoutConfig = ({ fuse }) => fuse.settings.current.layout.config;
|
||||
|
||||
export const selectFuseDefaultSettings = ({ fuse }) => fuse.settings.defaults;
|
||||
|
||||
export const selectFuseThemesSettings = ({ fuse }) => fuse.settings.themes;
|
||||
|
||||
export const { resetSettings, setInitialSettings, setSettings } = settingsSlice.actions;
|
||||
|
||||
export default settingsSlice.reducer;
|
||||
57
src/app/store/i18nSlice.js
Normal file
57
src/app/store/i18nSlice.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { createSelector, createSlice } from '@reduxjs/toolkit';
|
||||
import i18n from 'src/i18n';
|
||||
import { setDefaultSettings } from './fuse/settingsSlice';
|
||||
|
||||
export const changeLanguage = (languageId) => (dispatch, getState) => {
|
||||
const { direction } = getState().fuse.settings.defaults;
|
||||
|
||||
const newLangDirection = i18n.dir(languageId);
|
||||
|
||||
/*
|
||||
If necessary, change theme direction
|
||||
*/
|
||||
if (newLangDirection !== direction) {
|
||||
dispatch(setDefaultSettings({ direction: newLangDirection }));
|
||||
}
|
||||
|
||||
/*
|
||||
Change Language
|
||||
*/
|
||||
return i18n.changeLanguage(languageId).then(() => {
|
||||
dispatch(i18nSlice.actions.languageChanged(languageId));
|
||||
});
|
||||
};
|
||||
|
||||
const i18nSlice = createSlice({
|
||||
name: 'i18n',
|
||||
initialState: {
|
||||
language: i18n.options.lng,
|
||||
languages: [
|
||||
{ id: 'en', title: 'English', flag: 'US' },
|
||||
{ id: 'tr', title: 'Turkish', flag: 'TR' },
|
||||
{ id: 'ar', title: 'Arabic', flag: 'SA' },
|
||||
],
|
||||
},
|
||||
reducers: {
|
||||
languageChanged: (state, action) => {
|
||||
state.language = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const selectCurrentLanguageId = ({ i18n: _i18n }) => _i18n.language;
|
||||
|
||||
export const selectLanguages = ({ i18n: _i18n }) => _i18n.languages;
|
||||
|
||||
export const selectCurrentLanguageDirection = createSelector([selectCurrentLanguageId], (id) => {
|
||||
return i18n.dir(id);
|
||||
});
|
||||
|
||||
export const selectCurrentLanguage = createSelector(
|
||||
[selectCurrentLanguageId, selectLanguages],
|
||||
(id, languages) => {
|
||||
return languages.find((lng) => lng.id === id);
|
||||
}
|
||||
);
|
||||
|
||||
export default i18nSlice.reducer;
|
||||
41
src/app/store/index.js
Normal file
41
src/app/store/index.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import createReducer from './rootReducer';
|
||||
|
||||
if (process.env.NODE_ENV === 'development' && module.hot) {
|
||||
module.hot.accept('./rootReducer', () => {
|
||||
const newRootReducer = require('./rootReducer').default;
|
||||
store.replaceReducer(newRootReducer.createReducer());
|
||||
});
|
||||
}
|
||||
|
||||
const middlewares = [];
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
const { createLogger } = require(`redux-logger`);
|
||||
const logger = createLogger({ collapsed: (getState, action, logEntry) => !logEntry.error });
|
||||
|
||||
middlewares.push(logger);
|
||||
}
|
||||
|
||||
const store = configureStore({
|
||||
reducer: createReducer(),
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware({
|
||||
immutableCheck: false,
|
||||
serializableCheck: false,
|
||||
}).concat(middlewares),
|
||||
devTools: process.env.NODE_ENV === 'development',
|
||||
});
|
||||
|
||||
store.asyncReducers = {};
|
||||
|
||||
export const injectReducer = (key, reducer) => {
|
||||
if (store.asyncReducers[key]) {
|
||||
return false;
|
||||
}
|
||||
store.asyncReducers[key] = reducer;
|
||||
store.replaceReducer(createReducer(store.asyncReducers));
|
||||
return store;
|
||||
};
|
||||
|
||||
export default store;
|
||||
24
src/app/store/rootReducer.js
Normal file
24
src/app/store/rootReducer.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { combineReducers } from '@reduxjs/toolkit';
|
||||
import fuse from './fuse';
|
||||
import i18n from './i18nSlice';
|
||||
import user from './userSlice';
|
||||
|
||||
const createReducer = (asyncReducers) => (state, action) => {
|
||||
const combinedReducer = combineReducers({
|
||||
fuse,
|
||||
i18n,
|
||||
user,
|
||||
...asyncReducers,
|
||||
});
|
||||
|
||||
/*
|
||||
Reset the redux store when user logged out
|
||||
*/
|
||||
if (action.type === 'user/userLoggedOut') {
|
||||
// state = undefined;
|
||||
}
|
||||
|
||||
return combinedReducer(state, action);
|
||||
};
|
||||
|
||||
export default createReducer;
|
||||
113
src/app/store/userSlice.js
Normal file
113
src/app/store/userSlice.js
Normal file
@@ -0,0 +1,113 @@
|
||||
/* eslint import/no-extraneous-dependencies: off */
|
||||
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
|
||||
import history from '@history';
|
||||
import _ from '@lodash';
|
||||
import { setInitialSettings } from 'app/store/fuse/settingsSlice';
|
||||
import { showMessage } from 'app/store/fuse/messageSlice';
|
||||
import settingsConfig from 'app/configs/settingsConfig';
|
||||
import jwtService from '../auth/services/jwtService';
|
||||
|
||||
export const setUser = createAsyncThunk('user/setUser', async (user, { dispatch, getState }) => {
|
||||
/*
|
||||
You can redirect the logged-in user to a specific route depending on his role
|
||||
*/
|
||||
if (user.loginRedirectUrl) {
|
||||
settingsConfig.loginRedirectUrl = user.loginRedirectUrl; // for example 'apps/academy'
|
||||
}
|
||||
|
||||
return user;
|
||||
});
|
||||
|
||||
export const updateUserSettings = createAsyncThunk(
|
||||
'user/updateSettings',
|
||||
async (settings, { dispatch, getState }) => {
|
||||
const { user } = getState();
|
||||
const newUser = _.merge({}, user, { data: { settings } });
|
||||
|
||||
dispatch(updateUserData(newUser));
|
||||
|
||||
return newUser;
|
||||
}
|
||||
);
|
||||
|
||||
export const updateUserShortcuts = createAsyncThunk(
|
||||
'user/updateShortucts',
|
||||
async (shortcuts, { dispatch, getState }) => {
|
||||
const { user } = getState();
|
||||
const newUser = {
|
||||
...user,
|
||||
data: {
|
||||
...user.data,
|
||||
shortcuts,
|
||||
},
|
||||
};
|
||||
|
||||
dispatch(updateUserData(newUser));
|
||||
|
||||
return newUser;
|
||||
}
|
||||
);
|
||||
|
||||
export const logoutUser = () => async (dispatch, getState) => {
|
||||
const { user } = getState();
|
||||
|
||||
if (!user.role || user.role.length === 0) {
|
||||
// is guest
|
||||
return null;
|
||||
}
|
||||
|
||||
history.push({
|
||||
pathname: '/',
|
||||
});
|
||||
|
||||
dispatch(setInitialSettings());
|
||||
|
||||
return dispatch(userLoggedOut());
|
||||
};
|
||||
|
||||
export const updateUserData = (user) => async (dispatch, getState) => {
|
||||
if (!user.role || user.role.length === 0) {
|
||||
// is guest
|
||||
return;
|
||||
}
|
||||
|
||||
jwtService
|
||||
.updateUserData(user)
|
||||
.then(() => {
|
||||
dispatch(showMessage({ message: 'User data saved with api' }));
|
||||
})
|
||||
.catch((error) => {
|
||||
dispatch(showMessage({ message: error.message }));
|
||||
});
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
role: [], // guest
|
||||
data: {
|
||||
displayName: 'John Doe',
|
||||
photoURL: 'assets/images/avatars/brian-hughes.jpg',
|
||||
email: 'johndoe@withinpixels.com',
|
||||
shortcuts: ['apps.calendar', 'apps.mailbox', 'apps.contacts', 'apps.tasks'],
|
||||
},
|
||||
};
|
||||
|
||||
const userSlice = createSlice({
|
||||
name: 'user',
|
||||
initialState,
|
||||
reducers: {
|
||||
userLoggedOut: (state, action) => initialState,
|
||||
},
|
||||
extraReducers: {
|
||||
[updateUserSettings.fulfilled]: (state, action) => action.payload,
|
||||
[updateUserShortcuts.fulfilled]: (state, action) => action.payload,
|
||||
[setUser.fulfilled]: (state, action) => action.payload,
|
||||
},
|
||||
});
|
||||
|
||||
export const { userLoggedOut } = userSlice.actions;
|
||||
|
||||
export const selectUser = ({ user }) => user;
|
||||
|
||||
export const selectUserShortcuts = ({ user }) => user.data.shortcuts;
|
||||
|
||||
export default userSlice.reducer;
|
||||
9
src/app/store/withReducer.js
Normal file
9
src/app/store/withReducer.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { injectReducer } from 'app/store/index';
|
||||
|
||||
const withReducer = (key, reducer) => (WrappedComponent) => {
|
||||
injectReducer(key, reducer);
|
||||
|
||||
return (props) => <WrappedComponent {...props} />;
|
||||
};
|
||||
|
||||
export default withReducer;
|
||||
Reference in New Issue
Block a user