Created
July 22, 2023 00:48
-
-
Save rossnelson/329d2eaec071bea627f969fa4b442840 to your computer and use it in GitHub Desktop.
React Context Api Abstraction
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { createContext, useContext, useReducer } from 'react'; | |
import Log from 'lib/log'; | |
import _ from 'lodash'; | |
import stores from './stores'; | |
const store = createContext(stores.state); | |
const { Provider } = store; | |
const StateProvider = ({ children }) => { | |
const initialState = {}; | |
const storeNames = Object.keys(stores); | |
storeNames.forEach(name => { | |
initialState[name] = stores[name].state; | |
}); | |
const [s, dispatch] = useReducer((state, action) => { | |
try { | |
const { store: storeName, reducer, value } = action; | |
const reducerMethod = _.get(stores, `${storeName}.reducers.${reducer}`); | |
const partialState = _.get(state, storeName); | |
const newPartialState = reducerMethod(partialState, value); | |
const newState = { ...state }; | |
_.set(newState, storeName, newPartialState); | |
return newState; | |
} catch (err) { | |
Log.error(err, state, action); | |
return state; | |
} | |
}, initialState); | |
return <Provider value={{ state: s, dispatch }}>{children}</Provider>; | |
}; | |
function useStore() { | |
const { state, dispatch } = useContext(store); | |
const actions = {}; | |
const storeNames = Object.keys(stores); | |
storeNames.forEach(name => { | |
const storeActions = {}; | |
const actionNames = Object.keys(stores[name].reducers); | |
actionNames.forEach(actionName => { | |
storeActions[actionName] = value => { | |
dispatch({ | |
store: name, | |
reducer: actionName, | |
value | |
}); | |
}; | |
}); | |
actions[name] = storeActions; | |
}); | |
return { state, actions }; | |
} | |
export { store, useStore, StateProvider }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import account from './account'; | |
import impersonate from './impersonate'; | |
import layout from './layout'; | |
const stores = { | |
impersonate, | |
layout, | |
account | |
}; | |
export default stores; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { enUS } from '@mui/material/locale'; | |
const store = { | |
state: { | |
menuOpen: false, | |
alert: {}, | |
isWaiting: null, | |
locale: enUS, | |
section: null | |
}, | |
reducers: { | |
setWaiting(state, isWaiting) { | |
return { ...state, isWaiting }; | |
}, | |
setLocale(state, locale) { | |
return { ...state, locale }; | |
}, | |
setAlert(state, alert = {}) { | |
return { ...state, alert }; | |
}, | |
setMenu(state, menuOpen) { | |
return { ...state, menuOpen }; | |
} | |
} | |
}; | |
export default store; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useEffect, useState } from 'react'; | |
import { Navigate, useLocation } from 'react-router-dom'; | |
import CenteredContent from 'lib/centered-content'; | |
import Session from 'lib/session'; | |
import { useStore } from 'store'; | |
const Protection = ({ children }) => { | |
const { actions } = useStore(); | |
const { pathname } = useLocation(); | |
const [loading, setLoading] = useState(true); | |
const [isValid, setValid] = useState(false); | |
const ifValid = valid => { | |
actions.account.setAccount(Session.account); | |
setValid(valid); | |
setLoading(false); | |
}; | |
useEffect(() => { | |
Session.validate(ifValid); | |
}, [pathname]); // eslint-disable-line | |
if (isValid) { | |
return children; | |
} | |
if (loading) { | |
return <CenteredContent />; | |
} | |
const to = { | |
pathname: '/auth/login', | |
state: { | |
returnurl: pathname | |
} | |
}; | |
return <Navigate to={to} />; | |
}; | |
export default function ProtectedRoute({ component: Component }) { | |
return ( | |
<Protection> | |
<Component /> | |
</Protection> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//import { Link } from 'react-router-dom'; | |
import Container from '@mui/material/Container'; | |
import { ReactComponent as Logo } from 'assets/images/logo.svg'; | |
import Icon from 'lib/icon'; | |
import { useStore } from 'store'; | |
import Right from './right'; | |
import styles from './styles.module.scss'; | |
function TopBar() { | |
const { | |
state: { | |
layout: { menuOpen } | |
}, | |
actions: { layout } | |
} = useStore(); | |
return ( | |
<div className={styles.topbar}> | |
<Container fixed> | |
<div className={styles.appleft}> | |
<Icon | |
className={styles.menutoggle} | |
onClick={() => layout.setMenu(!menuOpen)} | |
icon={['far', 'bars']} | |
/> | |
<a className={styles.logolink} href="/"> | |
<Logo className={styles.logo} /> | |
</a> | |
</div> | |
<Right /> | |
</Container> | |
</div> | |
); | |
} | |
export default TopBar; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment