|
@@ -186,6 +186,12 @@ const actionCartRemove = (good) => ({type: 'CART_REMOVE', good})
|
|
|
const actionCartClear = () => ({type: 'CART_CLEAR'})
|
|
|
|
|
|
|
|
|
+function routeReducer(state={}, {type, match}) {
|
|
|
+ if (type === 'ROUTE') {
|
|
|
+ return match
|
|
|
+ }
|
|
|
+ return state
|
|
|
+}
|
|
|
|
|
|
|
|
|
function promiseReducer(state={}, {type, status, payload, error, name}) {
|
|
@@ -397,7 +403,8 @@ const getGQL = url => (
|
|
|
const sagaMiddleware = createSagaMiddleware()
|
|
|
const store = createStore( combineReducers({ promise: promiseReducer,
|
|
|
auth: authReducer,
|
|
|
- cart: cartReducer}),
|
|
|
+ cart: cartReducer,
|
|
|
+ route: routeReducer}),
|
|
|
applyMiddleware(sagaMiddleware))
|
|
|
|
|
|
|
|
@@ -450,8 +457,35 @@ function* registerWatcher() {
|
|
|
yield takeEvery('FULL_REGISTER', registerWorker)
|
|
|
}
|
|
|
|
|
|
+const queries = {
|
|
|
+ "/good/:_id": match => ({ name: 'goodById',
|
|
|
+ query: `query goodById($q: String) {
|
|
|
+ GoodFindOne(query: $q) {
|
|
|
+ _id name price description images {
|
|
|
+ url
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }`,
|
|
|
+ variables: {q: JSON.stringify([{_id: match.params._id}])}
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+function* routeWorker({match}) {
|
|
|
+ console.log(match)
|
|
|
+ if (match.path in queries) {
|
|
|
+ const {name, query, variables} = queries[match.path](match)
|
|
|
+ yield call(promiseWorker, actionPromise(name, gql(query, variables)))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function* routeWatcher() {
|
|
|
+ yield takeEvery('ROUTE', routeWorker)
|
|
|
+}
|
|
|
+
|
|
|
function* rootSaga() {
|
|
|
yield all([
|
|
|
+ routeWatcher(),
|
|
|
promiseWatcher(),
|
|
|
loginWatcher(),
|
|
|
registerWatcher()
|
|
@@ -470,6 +504,79 @@ store.subscribe(() => console.log(store.getState()))
|
|
|
store.dispatch(actionRootCats())
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+const RRoute = ({ action, component:Component, ...routeProps}) => {
|
|
|
+ const WrapperComponent = (componentProps) => {
|
|
|
+ action(componentProps.match)
|
|
|
+ return <Component {...componentProps} />
|
|
|
+ }
|
|
|
+ return <Route {...routeProps} component={WrapperComponent} />
|
|
|
+}
|
|
|
+const CRRoute = connect(null, {action: match => ({type: 'ROUTE', match})})(RRoute)
|
|
|
+
|
|
|
+const ProtectedRoute = ({ fallback='/',
|
|
|
+ roles=["admin"],
|
|
|
+ auth,
|
|
|
+ component:Component,
|
|
|
+ ...routeProps}) => {
|
|
|
+
|
|
|
+ const WrapperComponent = (componentProps) => {
|
|
|
+ let aclArr = auth?.payload?.sub?.acl
|
|
|
+ if (!aclArr) {
|
|
|
+ aclArr = ['anon']
|
|
|
+ }
|
|
|
+ let crossArr = [];
|
|
|
+ for (const role of roles) {
|
|
|
+ crossArr = [...crossArr, ...aclArr.filter(aclItem => aclItem === role)]
|
|
|
+ }
|
|
|
+ if (crossArr.length === 0) {
|
|
|
+ return <Redirect to={fallback} />
|
|
|
+ } else {
|
|
|
+ return <Component {...componentProps} />
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return <CRRoute {...routeProps} component={WrapperComponent} />
|
|
|
+}
|
|
|
+
|
|
|
+const CPRoute = connect(state => ({auth: state.auth}))(ProtectedRoute)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+const useLocalStoredState = (defaultState, localStorageName) => {
|
|
|
+ let inputJson
|
|
|
+ try {
|
|
|
+ inputJson = JSON.parse(localStorage.getItem(localStorageName))
|
|
|
+ } catch(err) {
|
|
|
+ console.error(err)
|
|
|
+ localStorage.removeItem(localStorageName)
|
|
|
+ }
|
|
|
+ const [state, setState] = useState(inputJson || defaultState)
|
|
|
+
|
|
|
+ return [state, newState => {
|
|
|
+ setState(newState)
|
|
|
+ localStorage.setItem(localStorageName, JSON.stringify(newState))
|
|
|
+ }]
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const useProxyState = (defaultState) => {
|
|
|
+ const [state, setState] = useState(defaultState)
|
|
|
+ return new Proxy(state, {
|
|
|
+ get(obj, key) {
|
|
|
+ return obj[key]
|
|
|
+ },
|
|
|
+ set(obj, key, value) {
|
|
|
+ setState({...obj, [key]: value})
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
const Logo = ({logo=logoDefault}) => (
|
|
|
<Link to='/' className="Logo">
|
|
|
<img src={logo} />
|
|
@@ -779,18 +886,25 @@ const CThisGood = connect( state => ({good: state.promise.goodById?.payload}),
|
|
|
{onCartAdd: actionCartAdd})(ThisGood)
|
|
|
|
|
|
|
|
|
-const PageGood = ({match:{params:{_id}}, getData}) => {
|
|
|
- useEffect(() => {
|
|
|
- getData(_id)
|
|
|
- },[_id])
|
|
|
|
|
|
- return (
|
|
|
+const PageGood = ({match:{params:{_id}}}) => (
|
|
|
<>
|
|
|
<CThisGood />
|
|
|
</>
|
|
|
)
|
|
|
-}
|
|
|
-const CPageGood = connect(null, {getData: actionGoodById})(PageGood)
|
|
|
+
|
|
|
+
|
|
|
+// const PageGood = ({match:{params:{_id}}, getData}) => {
|
|
|
+// useEffect(() => {
|
|
|
+// getData(_id)
|
|
|
+// },[_id])
|
|
|
+// return (
|
|
|
+// <>
|
|
|
+// <CThisGood />
|
|
|
+// </>
|
|
|
+// )
|
|
|
+// }
|
|
|
+// const CPageGood = connect(null, {getData: actionGoodById})(PageGood)
|
|
|
|
|
|
|
|
|
// на текущий момент функция отображает только 100 последних заказов
|
|
@@ -861,7 +975,8 @@ const Main = () => (
|
|
|
<Switch>
|
|
|
<Route path="/" component={PageMain} exact />
|
|
|
<Route path="/category/:_id" component={CPageCategory} />
|
|
|
- <Route path="/good/:_id" component={CPageGood} />
|
|
|
+ {/* <Route path="/good/:_id" component={CPageGood} /> */}
|
|
|
+ <CPRoute roles={['anon', 'user', 'admin']} path="/good/:_id" component={PageGood} />
|
|
|
<Route path="/cart" component={CCart} />
|
|
|
<Route path="/login" component={CLoginForm} />
|
|
|
<Route path="/register" component={CRegisterForm} />
|