Ivan Asmer %!s(int64=5) %!d(string=hai) anos
pai
achega
6a09f25c27
Modificáronse 3 ficheiros con 93 adicións e 63 borrados
  1. 37 0
      src/App.js
  2. 39 0
      src/actions/index.js
  3. 17 63
      src/reducers/index.js

+ 37 - 0
src/App.js

@@ -8,6 +8,8 @@ import store from './reducers'
 import {Router, Route, Link, Switch, Redirect} from 'react-router-dom';
 import createHistory from "history/createBrowserHistory";
 
+import {actionPosts, actionLogin} from './actions'
+
 
 const history = createHistory()
 
@@ -18,17 +20,52 @@ const SearchField = connect(null, {onChange: actionSearch})(({onChange}) => {
     )
 })
 
+const Post = ({post}) =>
+<div>
+    <h2>{post.title}</h2>
+    <p>{post.text}</p>
+</div>
+
+const PostFeed = ({posts=[]}) =>
+<div>
+    {posts && posts.map(p => <Post post={p}/>)}
+</div>
+
+const CPostFeed = connect(s => ({posts:s.promise.posts && 
+                                       s.promise.posts.payload && 
+                                       s.promise.posts.payload.getPosts}))(PostFeed)
+
+const PageMain = () =>
+<>
+    <CPostFeed />
+</>
+
+const LoginForm = ({onLogin}) =>
+<>
+    <input type='text' />
+    <input type='password' />
+    <button onClick={() => onLogin('admin', '123')}>Login</button>
+</>
+
+const CLoginForm = connect(null, {onLogin: actionLogin})(LoginForm)
+
+
+
 const SearchResult = connect(s => (console.log(s), ({payload: s.searchResult && 
                                                               s.searchResult.payload && 
                                                               s.searchResult.payload.payload && 
                                                               s.searchResult.payload.payload.GoodFind})))(({payload}) => <h1>{console.log(payload)}{payload && payload.map(({_id, name}) => <div>{name}</div>)}</h1>)
 
+store.dispatch(actionPosts())
+
 export default () => {
     return (
         <Provider store={store}>
             <SearchField />
             <SearchResult />
+            <CLoginForm />
             <Router history={history}>
+                <Route path="/" component={PageMain} />
             </Router>
         </Provider>
     )

+ 39 - 0
src/actions/index.js

@@ -1,2 +1,41 @@
+import { GraphQLClient } from 'graphql-request';
+
+//const gql = new GraphQLClient('/graphql', {headers: {Authorization: 'Bearer ' + ... }})
+const gql = new GraphQLClient('/graphql')
+
 export const actionSearch = text => ({type: 'SEARCH', text})
 export const actionSearchResult = payload => ({type: 'SEARCH_RESULT', payload})
+
+export const actionPromise = (name, promise) => {
+    const actionPending = () => ({type: 'PROMISE', name, status: 'PENDING', payload: null, error: null})
+    const actionResolved = payload => ({type: 'PROMISE', name, status: 'RESOLVED', payload, error: null})
+    const actionRejected = error => ({type: 'PROMISE', name, status: 'REJECTED', payload:null, error})
+
+
+    return async dispatch => {
+        dispatch(actionPending())
+        try {
+            let payload = await promise
+            dispatch(actionResolved(payload))
+        }
+        catch (e){
+            dispatch(actionRejected(e))
+        }
+    }
+}
+
+export const actionPosts = () => {
+    return actionPromise('posts', gql.request(`query psts{
+          getPosts{
+            id, title, text    
+          }
+        }`))
+}
+
+
+export const actionLogin = (login,password) => {
+    console.log(login, password)
+    return actionPromise('posts', gql.request(`query login($login: String!, $password: String!){
+          login(username: $login, password: $password)
+        }`, {login, password}))
+}

+ 17 - 63
src/reducers/index.js

@@ -1,75 +1,29 @@
 import {createStore, applyMiddleware, combineReducers} from 'redux';
-//import thunk from 'redux-thunk';
-import createSagaMiddleware from  'redux-saga';
-import { all, takeLatest, takeLeading, takeEvery, put } from 'redux-saga/effects';
-import {actionSearchResult} from '../actions';
-import { GraphQLClient } from 'graphql-request';
+import thunk from 'redux-thunk';
 
-const gql = new GraphQLClient('http://shop-roles.asmer.fs.a-level.com.ua/graphql')
 
-const sagaMiddleware = createSagaMiddleware()
-
-
-let store = createStore((state={}, {type, ...params}) => { //единственный редьюсер данного хранилища
-    if (type === 'SEARCH_RESULT'){
-        return {searchResult: {...params}}
-    }
-    return state//, в таком случае вызываются все редьюсеры, но далеко не всегда action.type будет относится к этому редьюсеру. Тогда редьюсер должен вернуть state как есть. 
-}, applyMiddleware(sagaMiddleware))
-
-const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms))
-
-function* aWorker({timeout, message}){
-    yield put({type: 'LOG', text: `aWorker started with ${timeout}`})
-    yield delay(timeout)
-    console.log(message)
-}
-
-function* actionCheck(){
-    yield takeLeading('ACTION_A', aWorker)
-}
-
-function* searchWorker({text}){
-    yield put(actionSearchResult({payload: null}))
-    yield delay(2000)
-//    let payload = yield delay(2000) //типа fetch
-    let payload = yield gql.request(`
-            query gf($query: String){
-                GoodFind(query: $query){
-                    _id, name, description, price, images{
-                        _id, url
-                    }
+const reducers = {
+    promise(state={}, action){
+        if (['LOGOUT', 'LOGIN'].includes(action.type)) return {}
+        if (action.type === 'PROMISE'){
+            const { name="default", status, payload, error} = action
+            if (status){
+                return {
+                    ...state, [name]: {status, payload: (status === 'PENDING' && state[name] && state[name].payload) || payload, error}
                 }
-            }`, {query: JSON.stringify([
-                        {
-                            $or: [{name: `/${text}/`}, {description: `/${text}/`}] //регулярки пишутся в строках
-                        },
-                        {
-                            sort: [{name: 1}]} //сортируем по title алфавитно
-                        ])
-            }) 
-    yield put(actionSearchResult({payload}))
-    console.log('search end' , text)
-}
+            }
+        }
+        return state;
+    },
+    //auth(){ //....
 
-function* searchCheck(){
-    yield takeLatest('SEARCH', searchWorker)
+    //}
 }
 
+let store = createStore(combineReducers(reducers), applyMiddleware(thunk))
 
-function* rootSaga(){
-    yield all([
-        actionCheck(),
-        searchCheck()
-    ])
-}
-
-sagaMiddleware.run(rootSaga)
-
-//store.subscribe(()=> console.log(store.getState())) // подписка на обновления store
+const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms))
 
-store.dispatch({type: 'ACTION_A', timeout: 5000, message: 'HELLO WORLD 5sec'})
-store.dispatch({type: 'ACTION_A', timeout: 2000, message: 'WORLD HELLO 2sec'})
 
 export default store