Переглянути джерело

routing added for: register, login, cart and item pages. Login, logout, reistration and fullRegistration funtionality added

miskson 3 роки тому
батько
коміт
a70046b572
2 змінених файлів з 147 додано та 82 видалено
  1. 141 82
      hw18-react-store/src/App.js
  2. 6 0
      hw18-react-store/src/App.scss

+ 141 - 82
hw18-react-store/src/App.js

@@ -142,8 +142,11 @@ function promiseReducer(state={}, {type, name, status, payload, error}){
 const actionAuthLogin = (token) => ({ type: 'AUTH_LOGIN', token })
 const actionAuthLogout = () => ({ type: 'AUTH_LOGOUT' })
 
-const actionLogin = (login = 'tst', password = '123') =>
-    actionPromise('login', gql(`query ($login:String, $password:String){ login(login:$login, password:$password)}`, { 'login': login, 'password': password }))
+const actionLogin = (login, password) =>
+    actionPromise('login', gql(`
+    query log($login:String, $password:String) {
+        login(login: $login, password: $password)
+      }`, { login, password }))
 
 const actionFullLogin = (login = 'tst', password = '123') =>
     async dispatch => {
@@ -153,12 +156,18 @@ const actionFullLogin = (login = 'tst', password = '123') =>
         }
     }
 
-const actionRegister = (login = 'tst', password = '123') =>
-    actionPromise('login', gql(`mutation reg($login:String, $password:String) {
-        UserUpsert(user:{login:$login, password:$password, nick:$login}){
-          _id login
+const actionRegister = (login, password) =>
+    actionPromise('registration', gql(`
+        mutation register($login:String, $password:String) {
+            UserUpsert(
+            user: {
+                login: $login,
+                password: $password,
+            }){
+                login _id 
+            }
         }
-      }`, { 'login': login, 'password': password }))
+      `, { login, password }))
 
 const actionFullRegister = (login = 'tst', password = '123') =>
     async dispatch => {
@@ -181,13 +190,20 @@ const actionCatById = (_id) =>
     }`, { q: JSON.stringify([{ _id }]) }))
 
 const actionGoodById = (_id) =>
-    actionPromise('goodById', gql(`query ($good:String) {
-        GoodFindOne(query:$good) {
-          _id name price images {
-              url
-          }
-        }
-      }`, { good: JSON.stringify([{ _id }]) }))
+    actionPromise('goodById', gql(`
+        query goodById ($good:String) {
+            GoodFindOne(query: $good) {
+                name 
+                description 
+                price
+                categories {
+                    name
+                } 
+                images {
+                    url
+                }
+            }
+        }`, { good: JSON.stringify([{ _id }]) }))
 
 
 const store = createStore(combineReducers({promise: promiseReducer, 
@@ -195,7 +211,6 @@ const store = createStore(combineReducers({promise: promiseReducer,
                                             cart: cartReducer}), applyMiddleware(thunk)) 
 store.subscribe(() => console.log(store.getState()))
 store.dispatch(actionRootCats())
-//store.dispatch(actionCatById('5dc458985df9d670df48cc47'))
 
 
 const Logo = () =>
@@ -212,12 +227,13 @@ const Navbar = () =>
     <nav className='Navbar'>
         <CKoshik/>
         <LogBtn />
+        <RegBtn />
     </nav>
-
+//--------------------------------------------------------------------------------------------------------------------------------
 const CategoryListItem = ({_id, name}) =>
-    <li className='CatLink'>
-        <Link to={`/category/:${_id}`}>{name}</Link>
-    </li>
+    <Link to={`/category/:${_id}`}>
+        <li className='CatLink' style={{color:'dodgerblue'}}>{name}</li>
+    </Link>
 
 const CategoryList = ({cats}) =>
     <ul>{cats.map((item) => <CategoryListItem {...item}/>)}</ul>
@@ -226,13 +242,13 @@ const CCategoryList = connect(state => ({cats:state.promise.rootCats?.payload ||
 
 const Aside = () =>
     <aside><CCategoryList /></aside>
-
+//--------------------------------------------------------------------------------------------------------------------------------
 const GoodCard = ({good:{_id, name, price, images}, onAdd}) =>
     <li className='GoodCard'> 
         <h2>{name}</h2>
-        {images && images[0] && images[0].url && <img className='GoodImg' alt='img' src={backendURL + '/' + images[0].url} />}
+        <Link to={`/good/:${_id}`}>На страницу товара</Link>
         <br/>
-        <button>На страницу товара</button>
+        {images && images[0] && images[0].url && <img className='GoodImg' alt='img' src={backendURL + '/' + images[0].url} />}
         <br/>
         <strong>Цена: {price}</strong>
         <br/>
@@ -240,11 +256,45 @@ const GoodCard = ({good:{_id, name, price, images}, onAdd}) =>
     </li>
 
 const CGoodCard = connect(null, {onAdd: actionCartAdd})(GoodCard)
+//--------------------------------------------------------------------------------------------------------------------------------
+const GoodPg = ({good:{_id, name, price, images, description}, onAdd}) =>
+    <div className='GoodCard'> 
+        <h2>{name}</h2>
+        <br/>
+        {images && images[0] && images[0].url && <img className='GoodImg' alt='img' src={backendURL + '/' + images[0].url} />}
+        <br/>
+        <strong>Цена: {price}</strong>
+        <br/>
+        <p>{description}</p>
+        <br />
+        <button onClick={() => onAdd({_id, name, price, images})}>Добавить в корзину</button>
+    </div>
+
+const CGoodPg = connect(state => ({good:state.promise.goodById?.payload || {}}),{onAdd: actionCartAdd})(GoodPg)
+
+const PageGood = ({match: {params: {_id}}, getData}) => {
+    useEffect(() => {
+        getData(_id.substring(1))
+        console.log('get', _id,typeof _id)
+    },[_id])
+    return (
+        <CGoodPg />
+    )
 
+}
+
+const CPageGood = connect(null, {getData: actionGoodById})(PageGood)
+//--------------------------------------------------------------------------------------------------------------------------------
 const LogBtn = () =>
-    <div className='KoshikCnt item'>
-        <Link to="/login" style={{color:'white', textDecoration:'none'}}>Войти</Link>
-    </div>
+    <Link to="/login" style={{color:'white', textDecoration:'none'}}>
+        <div className='KoshikCnt item'>Войти / Выйти</div>
+    </Link>
+
+const RegBtn = () =>
+    <Link to="/registration" style={{color:'white', textDecoration:'none'}}>
+        <div className='KoshikCnt item'>Зарегистрироваться</div>
+    </Link>
+
 
 const Koshik = ({cart}) => {
     let goodsInCart = cart
@@ -253,37 +303,53 @@ const Koshik = ({cart}) => {
         allGoodsInCart += goodsInCart[key].count
     }
     return (
-        <div className='KoshikCnt item'>
-            <Link to="/cart" style={{color:'white', textDecoration:'none'}}>Корзина: {allGoodsInCart}</Link>
-        </div>
+        <Link to="/cart" style={{color:'white', textDecoration:'none'}}>
+            <div className='KoshikCnt item'>
+                Корзина: {allGoodsInCart}
+            </div>
+        </Link>
     )
 }
 
 const CKoshik = connect(({cart}) => ({cart}))(Koshik)
-
+//--------------------------------------------------------------------------------------------------------------------------------
 const Category = ({cat:{name, goods=[]}={}}) => 
-<div className='Category'>
-    <h1>{name}</h1>
-    <ul>
-        {(goods || []).map(good => <CGoodCard good={good} />)}
-    </ul>
-</div>
+    <div className='Category'>
+        <h1>{name}</h1>
+        <ul>
+            {(goods || []).map(good => <CGoodCard good={good} />)}
+        </ul>
+    </div>
+
+const CCategory = connect(state => ({cat:state.promise.catById?.payload || {}}))(Category)
+
+const PageCategory = ({match: {params: {_id}}, getData}) => {
+    useEffect(() => {
+        getData(_id.substring(1))
+        console.log('get', _id,typeof _id)
+    },[_id])
+    return (
+        <CCategory />
+    )
 
-const CCategory = connect(state => ({cat:state.promise.catById?.payload || {}}))
-                              (Category)
+}
 
+const CPageCategory = connect(null, {getData: actionCatById})(PageCategory)
+//--------------------------------------------------------------------------------------------------------------------------------
 const CartItem = ({cart:{_id, name, price, images}, count: {count}, onChange, onRemove}) => {
     console.log('good', _id)
     return(
         <li className='GoodCard'> 
             <h2>{name}</h2>
+            <Link to={`/good/:${_id}`}>На страницу товара</Link>
+            <br/>
             {images && images[0] && images[0].url && <img className='GoodImg' alt='img' src={backendURL + '/' + images[0].url} />}
             <br/>
             <strong>Цена: {price * count}</strong>
             <br/>
             <label>Кол-во покупки: <input type="number" value={count} min="1" onInput={(e) => onChange({_id, name, price, images}, e.target.value)}/></label>
             <br/>
-            <button>Заказать</button>
+            <button disabled={!localStorage.authToken}>{localStorage.authToken? 'Заказать' : 'Авторизуйтесть чтобы заказать'}</button>
             <button onClick={() => onRemove({_id, name, price, images})}>Удалить заказ[X]</button>
         </li>
     )
@@ -296,8 +362,6 @@ const Cart = ({cart}) => {
     for(let item in cart) {
         cartArr.push(cart[item])
     }
-    console.log('cartarr',cartArr)
-    
     return(
         <div>
             <h1 style={{marginLeft:'30px'}}>Корзина</h1>
@@ -307,72 +371,67 @@ const Cart = ({cart}) => {
 }
 
 const CCart = connect(state => ({cart:state.cart}))(Cart)
-
-const PageCart = ({match: {params: {_id}}, getData}) => {
-    useEffect(() => {
-        getData(_id.substring(1))
-        console.log('get', _id,typeof _id)
-    },[_id])
+//--------------------------------------------------------------------------------------------------------------------------------
+const LoginForm = ({log:{sub}, onLogin, onLogout}) => {
+    let [pass, setPass] = useState()
+    let [login, setLogin] = useState()
     return (
-        <CCart />
+        <div className='form' style={{margin: '0 auto'}}>
+            <h3>Войти</h3>
+            <input placeholder='Логин' style={{outlineColor: login? 'black' : 'firebrick'}} onChange={(e) => setLogin(e.target.value)}/>
+            <br/>
+            <input placeholder='Пароль' type="password" style={{outlineColor: pass? 'black' : 'firebrick'}} onChange={(e) => setPass(e.target.value)}/>
+            <br/>
+            <button disabled={!pass || !login || localStorage.authToken} onClick={() => onLogin(login, pass)}>{localStorage.authToken? 'Авторизация была выполнена.' : 'Войти'}</button>
+            {localStorage.authToken && <button onClick={() => onLogout()}>Выйти</button>}
+            <br/>
+            {sub && <small>Пользователь {sub.login} авторизован</small>}
+        </div>
     )
-
 }
 
-const CPageCart= connect(null, {getData: actionCatById})(PageCart)
-//const CCart = connect(забрать из редакса корзину положить в пропс cart, 
-                       //дать компоненту onCartChange и onCartRemove с соответствующими actionCreator)(Cart)
-
-
-const LoginForm = ({onLogin}) => {
+const CLoginForm = connect(state => ({log: state.auth?.payload || {}}), {onLogin: actionFullLogin, onLogout: actionAuthLogout})(LoginForm)
+//--------------------------------------------------------------------------------------------------------------------------------
+const RegForm = ({reg:{login}, loged: {sub}, onRegister, onFullRegister}) => {
     let [pass, setPass] = useState()
-    let [login, setLogin] = useState()
+    let [log, setLog] = useState()
     return (
-        <div className='form'>
-            <h3>Login Form</h3>
-            <input placeholder='login' style={{outlineColor: login? 'black' : 'firebrick'}} onChange={(e) => setLogin(e.target.value)}/>
+        <div className='form' style={{margin: '0 auto'}}>
+            <h3>Зарегистрироваться</h3>
+            <input placeholder='Логин' style={{outlineColor: log? 'black' : 'firebrick'}} onChange={(e) => setLog(e.target.value)}/>
+            <br/>
+            <input placeholder='Пароль' type="password" style={{outlineColor: pass? 'black' : 'firebrick'}} onChange={(e) => setPass(e.target.value)}/>
             <br/>
-            <input placeholder='password' type="password" style={{outlineColor: pass? 'black' : 'firebrick'}} onChange={(e) => setPass(e.target.value)}/>
+            <button disabled={!pass || !log || localStorage.authToken} onClick={() => onRegister(log, pass)}>{localStorage.authToken? 'Авторизация была выполнена' : 'Зарегистрироваться'}</button>
             <br/>
-            <button disabled={!pass || !login} onClick={() => onLogin(login, pass)}>Login</button>            
+            {!localStorage.authToken && <button disabled={!pass || !log} onClick={() => {onFullRegister(log, pass); }}>Зарегистрироваться и Войти</button>}
+            <br/>
+            {login && `Пользователь ${login} зарегистрирован ${sub && 'и авторизован'}!`}
         </div>
     )
 }
 
-const CLoginForm = connect(null, {onLogin: actionFullLogin})(LoginForm)
+const CRegForm = connect(state => ({reg: state.promise.registration?.payload || {}, loged: state.auth?.payload || {}}), {onRegister: actionRegister, onFullRegister: actionFullRegister})(RegForm)
+//--------------------------------------------------------------------------------------------------------------------------------
 
-const PageMain = () => <h1>MAIN PAGE</h1>
 
-const PageCategory = ({match: {params: {_id}}, getData}) => {
-    useEffect(() => {
-        getData(_id.substring(1))
-        console.log('get', _id,typeof _id)
-    },[_id])
-    return (
-        <CCategory />
-    )
-
-}
-
-const CPageCategory = connect(null, {getData: actionCatById})(PageCategory)
+const PageMain = () => <h1>MAIN PAGE</h1>
 
 const Page404 = () => <h1> 404 </h1>
 
 const Main = () =>
     <main>
         <Aside />
-        <Content>
+        <Content style={{border:'1px solid black'}}>
             <Switch>
                 <Redirect from='/main' to='/' />
                 <Route path="/" component={PageMain} exact/>
                 <Route path="/category/:_id" component={CPageCategory}/>
+                <Route path="/good/:_id" component={CPageGood}/>
                 <Route path="/cart" component={CCart} />
+                <Route path="/login" component={CLoginForm} />
+                <Route path="/registration" component={CRegForm} />
                 <Route path="*" component={Page404} />
-                
-                {/* <CCategory /> */}
-                {/* <LoginForm onLogin={(l, p) => actionFullLogin(l, p)}/> */}
-                {/* <CLoginForm /> */}
-                {/* <CCart /> */}
             </Switch>
         </Content>
     </main>
@@ -380,11 +439,12 @@ const Main = () =>
 const Content = ({children}) =>
     <div className="Content">{children}</div>
 
+
 const Footer = () =>
     <footer><Logo /></footer>
 
-const history = createHistory()
 
+const history = createHistory()
 
 
 function App() {
@@ -396,7 +456,6 @@ function App() {
                     <Navbar />
                     <Main />
                     <Footer />
-                    {/* <CCart /> */}
                 </div>
             </Provider>
         </Router>

+ 6 - 0
hw18-react-store/src/App.scss

@@ -118,4 +118,10 @@ li {
   text-align: center;
   border: 5px solid rgb(47, 121, 170);
   padding: 5px;
+  margin-left: 30px;
 }
+
+.Content {
+  padding: 10px;
+  margin: 0 auto;
+}