DeJaVu 2 years ago
parent
commit
e95b489056

+ 12 - 16
src/App.js

@@ -6,19 +6,12 @@ import {createStore, combineReducers, applyMiddleware} from 'redux';
 import {Navibar} from './Components/NaviBar';
 import Footer from './Components/Footer';
 import { createBrowserHistory } from "history";
-import { Redirect } from 'react-router-dom';
 import { actionAuthLogout } from './actions';
 
 import store from './reducers';
 import ConnectLog from './pages/Login';
 
-import {
-  Router,
-  Switch,
-  Route, 
-  Link,
-  useHistory
-} from "react-router-dom";
+import { Router,Switch, Route, Link, useHistory } from "react-router-dom";
 
 import TypeAd, {Home} from "./pages/Home";
 import TypeAdOne from './pages/AdOne';
@@ -29,7 +22,9 @@ import {Advertisment} from "./pages/Advertisment";
 import {useDropzone} from 'react-dropzone'
 import RoleRoute from './Components/PrivateRoute';
 import ConnectNav from './Components/NaviBar';
-
+import CProfile from './Components/Profile';
+import CPromiseComponent from './Components/PromiseComponent';
+import CPost from './pages/PostAd';
 
 function App() {
   return (
@@ -38,13 +33,14 @@ function App() {
       <Router history = {createBrowserHistory()}>
           <ConnectNav />
           <Switch>
-            <RoleRoute exact path='/' roles ={["user"]} component = {TypeAd} />
-            <RoleRoute path='/home/:id' roles={['user']}component={TypeAdOne} />
-            <Route path='/login' component={ConnectLog}/>
-            {/* <RoleRoute roles={['unknown']} path='/login' component={ConnectLog}/> */}
-            <Route path='/sign' component={ConnectSign}/>
-            <Route path='/instruction' component={Instruction} />
-            <Route path='/advertisment' component={Advertisment} />
+            <RoleRoute exact path='/' roles ={['user']} component = {TypeAd}  />
+            <RoleRoute path='/home/:id' roles={['user']} component={TypeAdOne} />
+            <RoleRoute path='/login' roles={['unknown']} component={ConnectLog}/>
+            <RoleRoute path='/sign' roles={['unknown']} component={ConnectSign}/>
+            <RoleRoute path='/profile' roles={['user']} component={CProfile} />
+            <RoleRoute path='/post-ad' roles={['user']} component={CPost} />
+            <RoleRoute path='/instruction' roles={['unknown']} component={Instruction} />
+            <RoleRoute path='/advertisment' roles={['unknown']} component={Advertisment} />
           </Switch>
           <Footer />
       </Router>

+ 67 - 2
src/App.scss

@@ -4,6 +4,19 @@ html,body {
     max-width: 100%;
     overflow-x: hidden;
     height: 100%;
+
+    button {
+        background: #002f34;
+        color: white;
+        font-weight: 500;
+        border: 2px solid #002f34;
+        border-radius: 5px;
+        padding: 10px 30px;
+    }
+    button:hover {
+        color: #002f34;
+        background: white;
+    }
 }
 
 .Navbar {
@@ -38,10 +51,14 @@ html,body {
     flex-direction: column;
     justify-content: center;
     align-items: center;
-
+    margin-top: 20px;
+    input {
+        width: 200px;
+    }
     .login-container {
         display: flex;
         flex-direction: column;
+        position: relative;
     }
     .pwd-container {
         display: flex;
@@ -90,15 +107,17 @@ html,body {
     display: flex;
     flex-direction: row;
     align-items: center;
-    width: 60%;
     margin: 10px auto;
     border : 1px solid white;
+    border-radius: 15px;
     background-color: whitesmoke;
     padding: 10px;
     overflow-x: hidden;
     img {
         max-width: 200px;
         min-width: 200px;
+        max-height: 300px;
+        min-height: 150px;
         padding-left: 0px;
         border: 0;
     }
@@ -121,6 +140,52 @@ html,body {
     align-items: center;
 }
 
+.post {
+    margin-top: 25px;
+    padding: 25px 15px;
+    background-color: whitesmoke;
+    border-radius: 15px;
+}
+
+.lds-ring {
+    display: inline-block;
+    position: relative;
+    width: 80px;
+    height: 80px;
+  }
+  .lds-ring div {
+    box-sizing: border-box;
+    display: block;
+    position: absolute;
+    width: 64px;
+    height: 64px;
+    margin: 8px;
+    border: 8px solid #cef;
+    border-radius: 50%;
+    animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
+    border-color: #cef transparent transparent transparent;
+  }
+  .lds-ring div:nth-child(1) {
+    animation-delay: -0.45s;
+  }
+  .lds-ring div:nth-child(2) {
+    animation-delay: -0.3s;
+  }
+  .lds-ring div:nth-child(3) {
+    animation-delay: -0.15s;
+  }
+  @keyframes lds-ring {
+    0% {
+      transform: rotate(0deg);
+    }
+    100% {
+      transform: rotate(360deg);
+    }
+  }
+
+.foter__indent {
+    min-height: 150px;
+}
 
 footer {
     background: #002f34;

+ 1 - 1
src/Components/AdOne.js

@@ -1,4 +1,5 @@
 import React from "react"; 
+import { Container } from "react-bootstrap";
 
 export const AdOne=({_id, price, title,description,images}) => {
     return (
@@ -8,6 +9,5 @@ export const AdOne=({_id, price, title,description,images}) => {
             <p>{description}</p>
             <p>{`${price ? price : "0"} грн.`}</p>
         </div>
-        
     )
 }

+ 9 - 7
src/Components/CAdFeed.js

@@ -2,10 +2,11 @@ import React from "react";
 import { actionTypeAd } from "../actions";
 import {connect} from 'react-redux';
 import {Link} from 'react-router-dom';
+import { Container } from "react-bootstrap";
 
-
-export const AdFeed=({_id, price, owner,title,description,images}) => {
+export const AdFeed=({_id, price, owner,title,description,images,comments}) => {
     return (
+        <Container>
         <div className="row ad">
             <div className="col img">
                 <img src = {`http://marketplace.asmer.fs.a-level.com.ua/${images ? images[0]?.url : ''}`} />
@@ -17,11 +18,12 @@ export const AdFeed=({_id, price, owner,title,description,images}) => {
             <div className="col price">   
                 <p>{owner}</p>
                 <p>{`${price ? price : "0"} грн.`}</p>
-            </div>    
+            </div> 
+            <div>
+                <p>{comments || null}</p>
+            </div>   
         </div>
-        
+        </Container> 
     )
 }
-
-// const CAdFeed = connect(state =>({listAd: state.promiseReducer?.AdFind?.payload?.data?.AdFind || []}),{listAd: actionTypeAd})(AdFeed)
-// export default CAdFeed
+export const CAdfeed = connect(state=>({comments: state.promiseReducer.AdFind?.payload?.data?.AdFind.comments[0]?.owner}))(AdFeed)

+ 2 - 0
src/Components/DropZone.js

@@ -21,3 +21,5 @@ export function MyDropzone({getData,onSend,todo}) {
       </section>
     );
   }
+
+connect()(MyDropzone)

+ 19 - 15
src/Components/Footer.js

@@ -1,25 +1,29 @@
 import React from "react";
 import {Link} from "react-router-dom";
 
-const Footer = () => <footer className="page-footer fixed-bottom">
-    <div className="container text-center ">
-        <div className="row">
-            <div className="col-md-6 mt-md-0 mt-3">
-                <h5 className="text-uppercase">Что-то</h5>
-                <p>будет</p>
-            </div>
+const Footer = () => 
+<>
+    <div className='foter__indent'/>
+    <footer className="page-footer fixed-bottom">
+        <div className="container text-center ">
+            <div className="row">
+                <div className="col-md-6 mt-md-0 mt-3">
+                    <h5 className="text-uppercase">Что-то</h5>
+                    <p>будет</p>
+                </div>
 
-            <div className="col-md-6 mb-md-0 mb-3">
-                <ul className="list-unstyled">
-                    <li><Link to="/instruction">Инструкция</Link></li>
-                    <li><Link to="/advertisment">Реклама</Link></li>
-                </ul>
+                <div className="col-md-6 mb-md-0 mb-3">
+                    <ul className="list-unstyled">
+                        <li><Link to="/instruction">Инструкция</Link></li>
+                        <li><Link to="/advertisment">Реклама</Link></li>
+                    </ul>
+                </div>
             </div>
         </div>
-    </div>
 
-    <div className="footer-copyright text-center py-3">© 2021 Copyright</div>
+        <div className="footer-copyright text-center py-3">© 2021 Copyright</div>
 
-</footer>
+    </footer>
+</>
 
 export default Footer

+ 11 - 0
src/Components/Logout.js

@@ -0,0 +1,11 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { actionAuthLogout } from '../actions';
+const ButtonLogout = ({onLogout, isLoggedIn}) => {
+return(
+    <a className="adada" onClick={()=>onLogout()}
+        >Выйти</a>
+)
+}
+const CButtonLogout = connect(state => ({isLoggedIn: state.authReducer.payload}),{onLogout: actionAuthLogout})(ButtonLogout)
+export default CButtonLogout

+ 4 - 7
src/Components/NaviBar.js

@@ -9,7 +9,6 @@ import { useState } from 'react';
 import CButtonLogout from './Logout';
 
 export function Navibar({isLogin}){
-  // let [isLogout, setIsLogout] = useState(false)
     return(
     <>
         <Navbar className='Navbar'>
@@ -19,8 +18,10 @@ export function Navibar({isLogin}){
               <Navbar.Collapse id="basic-navbar-nav">
                 <Nav>
                   {isLogin ? (
-                    <>
-                      <CButtonLogout />
+                    <>  
+                      <Nav.Link><Link to='/post-ad'>Добавить товар</Link></Nav.Link>
+                      <Nav.Link><Link to='/profile'>Профиль</Link></Nav.Link>
+                      <Nav.Link><CButtonLogout /></Nav.Link>
                     </>
                   ):(
                       <>
@@ -28,10 +29,6 @@ export function Navibar({isLogin}){
                         <Nav.Link><Link to="/sign">Зарегистрироваться</Link></Nav.Link>
                       </> 
                     )}
-                  {/* <Nav.Link><Link to="/login">Войти</Link></Nav.Link>
-                  <Nav.Link><Link to="/sign">Зарегистрироваться</Link></Nav.Link> */}
-
-                  {/* {isLogout && <Logout onClick={() =>{onLogout();setIsLogout(false)}} />} */}
                 </Nav>
               </Navbar.Collapse>
             </Container>

+ 9 - 0
src/Components/PreLoader.js

@@ -0,0 +1,9 @@
+import React from "react";
+
+const Loader = ({}) => {
+    return (
+        <div className="lds-ring"><div></div><div></div><div></div><div></div></div>
+    )
+}   
+
+export default Loader

+ 26 - 0
src/Components/PrivateRoute.js

@@ -0,0 +1,26 @@
+import React from "react"
+import { connect } from "react-redux"
+import { Redirect,Route } from "react-router"
+
+const PrivateRoute = ({component,roles,auth, fallback='/login',...originProps}) => {
+    const PageWrapper = (pageProps) => {
+      const OriginalPage = component
+      console.log(auth)
+      if(roles.includes('unknown')){
+        return <OriginalPage {...pageProps} />
+      }
+      if(auth === undefined) {
+        return <Redirect to={fallback} />
+      }
+      let userL = roles.filter(item => auth.includes(item))
+      if(userL){
+        return <OriginalPage {...pageProps} />
+      }
+      return <Redirect to={fallback} />
+    }
+    return (
+      <Route component={PageWrapper} {...originProps} />
+    )
+  }
+const RoleRoute = connect(state => ({auth: state.authReducer?.payload?.sub.acl[1]}))(PrivateRoute)
+export default RoleRoute

+ 13 - 0
src/Components/Profile.js

@@ -0,0 +1,13 @@
+import React from "react";
+import { connect } from "react-redux";
+
+const Profile = ({login}) => {
+    return (
+        <div>
+            <p>{login}</p>
+        </div>
+    )
+}
+
+const CProfile = connect(state => ({login: state.authReducer.payload.sub.login}))(Profile)
+export default CProfile

+ 27 - 0
src/Components/PromiseComponent.js

@@ -0,0 +1,27 @@
+import React, { useState } from "react";
+import { connect } from "react-redux";
+import TypeAd from "../pages/Home";
+import Loader from "./PreLoader";
+
+const PromiseComponent = ({component,promiseName,pending,resolved}) => {
+    // const PromiseWrapper = ({}) => {
+        // const OriginalComp = component
+        // let [error,setError] = useState()
+        // if(promiseName ==='PENDING') {
+        //     return <Loader />
+        // }
+        // if(promiseName === 'RESOLVED') {
+        //     return <OriginalComp />
+        // }
+        return (
+           <div>
+               {pending && <Loader />}
+               {resolved && <TypeAd /> }
+           </div>
+        )
+    // }
+    // return <PromiseWrapper component={OriginalComp} />
+}
+
+const CPromiseComponent = connect(state => ({pending: state.promiseReducer?.AdFind?.status.includes('PENDING')}, {resolved: state.promiseReducer?.AdFind?.status.includes('RESOLVED') }))(PromiseComponent)
+export default CPromiseComponent

+ 27 - 11
src/actions/index.js

@@ -2,7 +2,6 @@ const getGQL = url =>
     (query, variables={}) => fetch(url, {
         method: 'POST',
         headers: {
-            //Accept: "application/json",
             "Content-Type": "application/json",
             ...(localStorage.authToken ? {Authorization: "Bearer " + localStorage.authToken } : {})
         },
@@ -65,14 +64,14 @@ const actionRegister = (login,password) =>
 }`,{login,password}))
 
 
-const actionAvaAdd = (ava,user) =>
-actionPromise('ava',shopGQL(`mutation setAvatar{
-  UserUpsert(user:{_id: "myid", avatar: {_id: "image id from fetch"}}){
-      _id, avatar{
-          _id
-      }
-  }
-}`,{ava,user}))
+// const actionAvaAdd = (ava,user) =>
+// actionPromise('ava',shopGQL(`mutation setAvatar{
+//   UserUpsert(user:{_id: "myid", avatar: {_id: "image id from fetch"}}){
+//       _id, avatar{
+//           _id
+//       }
+//   }
+// }`,{ava,user}))
 
 
 export const actionFullRegister = (login,password) => 
@@ -87,7 +86,7 @@ export const actionFullRegister = (login,password) =>
     }
   }
 
-export const actionTypeAd = () =>
+export const actionTypeAd = (_id,title) =>
     actionPromise('AdFind', shopGQL(`
             query Ad($query:String){
               AdFind(query:$query){
@@ -98,9 +97,12 @@ export const actionTypeAd = () =>
                 images {
                   url
                 }
+                comments {
+                  _id text owner { login} 
+                }
               }
             }
-        `, {query: JSON.stringify([{}])}))
+        `, {query: JSON.stringify([{field: title},{sort: [{_id: -1}]}])}))
 
 export const actionTypeAdOne = (id) => 
           actionPromise('AdFindOne',shopGQL(`
@@ -116,6 +118,20 @@ export const actionTypeAdOne = (id) =>
               }
             }`,{query: JSON.stringify([{_id:id}])}))
 
+export const actionPostAd = (title,description,price) =>
+            actionPromise('PostAd',shopGQL(`
+            mutation Post($ad: AdInput){
+              AdUpsert(ad: $ad) {
+                  _id
+                  title
+                  description
+                  price
+                  images {
+                    url
+                  }
+                }
+              }`,{ad: {title,description,price}}))
+
 // export const actionUploadFile = (file) =>{  
 // let fd = new FormData
 // fd.append('photo', file)

+ 3 - 5
src/pages/Home.js

@@ -5,13 +5,11 @@ import {AdOne} from "../Components/AdOne";
 import { actionTypeAd ,actionTypeAdOne} from "../actions";
 import { Redirect } from "react-router";
 import {useHistory} from 'react-router-dom';
-
+import Loader from "../Components/PreLoader";
+import { CAdfeed } from "../Components/CAdFeed";
 export const Home = ({getData,data2}) => {
     useEffect(()=>getData(),[])
-    // let history = useHistory()
-    // if(!localStorage.authToken) {
-    //     history.push("/login") 
-    // }
+   
     if(data2){
         return (
             <div>

+ 6 - 3
src/pages/Login.js

@@ -43,18 +43,21 @@ const loginCallback = () => {
     <div className="divLogin">
         <h4>Войти</h4>
         <div className="login-container">
-            <label>Nickname</label>
-            <input value={login} onChange={e => setLogin(e.target.value)} placeholder="Nickname"></input>
+            <label>Логин</label>
+            <input value={login} onChange={e => setLogin(e.target.value)} placeholder="Логин"></input>
         </div>
         <div className='pwd-container'>
             <label>Ваш текущий пароль от olx</label>
             <input value={password} type={open ? "text" : "password"} onChange={e => setPassword(e.target.value)} placeholder="Пароль"  />
             <img src={open ? hidePwdImg : showPwdImg} onClick={() => setOpen(!open)}/>
         </div>
+        <div className='login-container'>
             <Link to='sign'>Зарегистрироваться</Link>
-            <Button name='login' isValid={isLoginValid()} callback={loginCallback} />  
+            <Button name='Войти' isValid={isLoginValid()} callback={loginCallback} /> 
+        </div> 
             {show && (!login || !password) && <LoginError />}
     </div>
+    
   )
 }
 

+ 33 - 0
src/pages/PostAd.js

@@ -0,0 +1,33 @@
+import React ,{useState} from "react";
+import { connect } from "react-redux";
+import { actionPostAd } from "../actions";
+import { Container } from "react-bootstrap";
+
+
+const Post = ({onPost}) => {
+    let [title,setTitle] = useState('')
+    let [description,setDescription] = useState('')
+    let [price,setPrice] = useState(0)
+    return (
+        <Container >
+            <div className='d-flex flex-column align-items-start post'>
+                <label>Введите название</label>
+                <input value={title} onChange={e => setTitle(e.target.value)} placeholder='Например,Iphone 8'></input>
+            </div>
+            <div className='d-flex flex-column align-items-start post'>
+                <label>Описание</label>
+                <textarea rows="5" cols="75" value={description} onChange={e => setDescription(e.target.value)} placeholder='Подумайте,какие подробности вы бы хотели узнать из объявления. И добавьте их в описание'></textarea>
+            </div>
+            <div className='d-flex flex-column align-items-start post'>
+                <label>Введите цену</label>
+                <input type={"number"} value={price} onChange={e => e.target.value>0 ? setPrice(+e.target.value) : ""} placeholder='Цена' ></input>
+            </div>
+            <div className="d-flex flex-column align-items-end post">
+                <button onClick={()=> onPost(title,description,price)}>Опубликовать</button>
+            </div>
+        </Container>
+    )
+}
+
+const CPost = connect(null,{onPost: actionPostAd})(Post)
+export default CPost

+ 3 - 5
src/pages/Sign.js

@@ -47,14 +47,12 @@ const Sign = ({onSign,loggedIn}) => {
         }
     }
 
-   loggedIn = localStorage.authToken
-
     return (
       <div className="divSign">
           <h4>Регистрация</h4>
           <div className="login-container">
               <label>Придумайте логин</label>
-              <input value={login} onChange={e => setLogin(e.target.value)}  placeholder="Nickname"></input>
+              <input value={login} onChange={e => setLogin(e.target.value)}  placeholder="Логин"></input>
           </div>
           <div className='pwd-container1'>
               <label>Придумайте пароль</label>
@@ -68,7 +66,7 @@ const Sign = ({onSign,loggedIn}) => {
           </div>
           <MyDropzone />
           <Button
-                name='sign'
+                name='Зарегистрироваться'
                 isValid={isRegistrationValid()}
                 callback={registrationCallback}
             />
@@ -81,5 +79,5 @@ const Sign = ({onSign,loggedIn}) => {
     )
 }
 
-const ConnectSign = connect(state=> ({loggedIn:state.authReducer.login}),{onSign: actionFullRegister})(Sign)
+const ConnectSign = connect(state=> ({loggedIn:state.authReducer.payload}),{onSign: actionFullRegister})(Sign)
 export default ConnectSign