Browse Source

Add routing

DeJaVu 2 years ago
parent
commit
a579416130

+ 30 - 0
package-lock.json

@@ -3358,6 +3358,11 @@
       "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
       "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
     },
+    "attr-accept": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz",
+      "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg=="
+    },
     "autoprefixer": {
       "version": "9.8.6",
       "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz",
@@ -6913,6 +6918,21 @@
         }
       }
     },
+    "file-selector": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.2.4.tgz",
+      "integrity": "sha512-ZDsQNbrv6qRi1YTDOEWzf5J2KjZ9KMI1Q2SGeTkCJmNNW25Jg4TW4UMcmoqcg4WrAyKRcpBXdbWRxkfrOzVRbA==",
+      "requires": {
+        "tslib": "^2.0.3"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.3.1",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
+          "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
+        }
+      }
+    },
     "filesize": {
       "version": "6.1.0",
       "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@@ -13301,6 +13321,16 @@
         "scheduler": "^0.20.2"
       }
     },
+    "react-dropzone": {
+      "version": "11.4.2",
+      "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-11.4.2.tgz",
+      "integrity": "sha512-ocYzYn7Qgp0tFc1gQtUTOaHHSzVTwhWHxxY+r7cj2jJTPfMTZB5GWSJHdIVoxsl+EQENpjJ/6Zvcw0BqKZQ+Eg==",
+      "requires": {
+        "attr-accept": "^2.2.1",
+        "file-selector": "^0.2.2",
+        "prop-types": "^15.7.2"
+      }
+    },
     "react-error-overlay": {
       "version": "6.0.9",
       "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz",

+ 1 - 0
package.json

@@ -12,6 +12,7 @@
     "react": "^17.0.2",
     "react-bootstrap": "^2.0.0-beta.6",
     "react-dom": "^17.0.2",
+    "react-dropzone": "^11.4.2",
     "react-redux": "^7.2.5",
     "react-router-dom": "^5.3.0",
     "react-scripts": "4.0.3",

+ 12 - 8
src/App.js

@@ -1,27 +1,30 @@
-import React from 'react';
+import React, { useEffect } from 'react';
 import './App.scss';
-import createHistory from "history/createBrowserHistory";
 import {Provider, connect}   from 'react-redux';
 import thunk from 'redux-thunk';
 import {createStore, combineReducers, applyMiddleware} from 'redux';
 import Navibar from './Components/NaviBar';
 import Footer from './Components/Footer';
+import { createBrowserHistory } from "history";
 
 import store from './reducers';
 import ConnectLog from './pages/Login';
 
 import {
-  BrowserRouter as Router,
+  Router,
   Switch,
   Route, 
-  Link
+  Link,
+  useHistory
 } from "react-router-dom";
 
 import TypeAd, {Home} from "./pages/Home";
+import TypeAdOne from './pages/AdOne';
 import ConnectSign from './pages/Sign';
 import {Login} from "./pages/Login";
 import {Instruction} from "./pages/Instriction";
 import {Advertisment} from "./pages/Advertisment";
+import {useDropzone} from 'react-dropzone'
 
 
 // const ConnectLogout = connect(state => ({children: 'logout'}),{onClick: actionAuthLogout})('button')
@@ -30,17 +33,18 @@ function App() {
   return (
     <>
       <Provider store={store}>
-        <Router history = {createHistory()}>
+      <Router history = {createBrowserHistory()}>
           <Navibar />
-          <Footer />
           <Switch>
             <Route exact path='/' component={TypeAd}/>
-            <Route path='/sign' component={ConnectSign}/>
+            <Route exact path='/:id' component={TypeAdOne} />
             <Route path='/login' component={ConnectLog}/>
+            <Route path='/sign' component={ConnectSign}/>
             <Route path='/instruction' component={Instruction} />
             <Route path='/advertisment' component={Advertisment} />
           </Switch>
-        </Router>
+          <Footer />
+      </Router>
       </Provider>
     </>
   );

+ 25 - 3
src/App.scss

@@ -1,4 +1,9 @@
 @import "~bootstrap/scss/bootstrap";
+body {
+    width: 100%;
+    max-width: 100%;
+    overflow-x: hidden;
+}
 
 .Navbar {
     background: #002f34;
@@ -82,10 +87,27 @@
 
 .ad {
     display: flex;
-    flex-direction: column;
+    flex-direction: row;
     align-items: center;
-    width: 30%;
-    margin: 0 auto;
+    width: 60%;
+    margin: 10px auto;
+    border : 1px solid white;
+    background-color: whitesmoke;
+    padding: 10px;
+    img {
+        max-width: 250px;
+        padding-left: 0px;
+    }
+
+    a {
+        text-decoration: none;
+        color:black;
+        font-size: 25px;
+    }
+    a:hover {
+        background-color: #002f34;
+        color: white;
+    }
 }
 
 

+ 13 - 0
src/Components/AdOne.js

@@ -0,0 +1,13 @@
+import React from "react"; 
+
+export const AdOne=({_id, price, title,description,images}) => {
+    return (
+        <div className="aaa">
+            <img src = {`http://marketplace.asmer.fs.a-level.com.ua/${images ? images[0]?.url : ''}`} />
+            <p>{title}</p>
+            <p>{description}</p>
+            <p>{`${price ? price : "0"} грн.`}</p>
+        </div>
+        
+    )
+}

+ 17 - 0
src/Components/Button.js

@@ -0,0 +1,17 @@
+import React from 'react';
+
+const Button = (props) => {
+    return(
+        <button
+            onClick={(e) => {
+               props.callback(e)
+        
+            }}
+            className={props.disabled ? 'button-active': 'button-disabled'} 
+            >
+            {props.name}
+        </button>
+    )
+}
+
+export default Button;

+ 13 - 6
src/Components/CAdFeed.js

@@ -6,13 +6,20 @@ import {Link} from 'react-router-dom';
 
 export const AdFeed=({_id, price, owner,title,description,images}) => {
     return (
-        <div className="ad">
-            <Link to={ `/${_id}`}>{title}</Link>
-            <img src = {`http://marketplace.fs.a-level.com.ua/${Ad.images[0].url}`} />
-            <p>{description}</p>
-            <p>{owner}</p>
-            <p>{price}</p>
+        <div className="row ad">
+            <div className="col img">
+                <img src = {`http://marketplace.asmer.fs.a-level.com.ua/${images ? images[0]?.url : ''}`} />
+            </div> 
+            <div className="col-6" info>   
+                <Link to={ `/${_id}`}>{title}</Link>
+                <p>{description}</p>
+            </div>
+            <div className="col price">   
+                <p>{owner}</p>
+                <p>{`${price ? price : "0"} грн.`}</p>
+            </div>    
         </div>
+        
     )
 }
 

+ 23 - 0
src/Components/DropZone.js

@@ -0,0 +1,23 @@
+import React, { useState, useEffect, useRef, useCallback, MyContext} from "react";
+
+import { connect } from "react-redux";
+import {useDropzone} from 'react-dropzone'
+
+export function MyDropzone({getData,onSend,todo}) {
+    console.log(todo)
+    const {acceptedFiles, getRootProps, getInputProps} = useDropzone({onDrop: files => files.map(x=> onSend(x,todo))});
+    const files = acceptedFiles.map(file => <li key={file.path}>{file.path}</li>);
+  
+    return (
+      <section className="container">
+        <div {...getRootProps({className: 'dropzone'})}>
+          <input {...getInputProps() }/>
+          <p>Drag 'n' drop some files here, or click to select files</p>
+        </div>
+        <aside>
+          <h4>Files</h4>
+          <ul> {files} </ul>
+        </aside>
+      </section>
+    );
+  }

+ 0 - 2
src/Components/Footer.js

@@ -9,8 +9,6 @@ const Footer = () => <footer className="page-footer  fixed-bottom">
                 <p>будет</p>
             </div>
 
-            {/* <hr className="clearfix w-100 d-md-none pb-0"/> */}
-
             <div className="col-md-6 mb-md-0 mb-3">
                 <ul className="list-unstyled">
                     <li><Link to="/instruction">Инструкция</Link></li>

+ 2 - 2
src/Components/NaviBar.js

@@ -3,7 +3,7 @@ import React from "react";
 import { Navbar, Nav, NavDropdown, Container } from 'react-bootstrap';
 import {Link} from "react-router-dom";
 
-export default function Navibar(){
+export default function Navibar({}){
     return(
     <>
         <Navbar className='Navbar'>
@@ -27,4 +27,4 @@ export default function Navibar(){
         </Navbar>
     </>
     )
-  }
+  }

+ 11 - 0
src/Components/RegErrors/LoginError.js

@@ -0,0 +1,11 @@
+import React from 'react';
+
+const LoginError = () => {
+    return (
+        <div className='registration-error__wrapper'>
+            <p>Заполните все поля</p>
+        </div>
+    )
+}
+
+export default LoginError;

+ 11 - 0
src/Components/RegErrors/MinPass.js

@@ -0,0 +1,11 @@
+import React from 'react';
+
+const MinPass = () => {
+    return (
+        <div className='registration-error__wrapper'>
+            <p>Заполните все поля! Пароль должен содержать не меньше 3 символов </p>
+        </div>
+    )
+}
+
+export default MinPass;

+ 0 - 11
src/Components/RegErrors/exicitingLogin.js

@@ -1,11 +0,0 @@
-import React from 'react';
-
-const ExistingLogin = () => {
-    return (
-        <div className='registration-error__wrapper'>
-            <p>Данный пользователь уже зарегистрирован</p>
-        </div>
-    )
-}
-
-export default ExistingLogin;

+ 54 - 7
src/actions/index.js

@@ -53,9 +53,10 @@ export const actionFullLogin = (login, password) => {
       let result = await dispatch(actionLogin(login, password))
       if(result)
           dispatch(actionAuthLogin(result))
+          window.location.reload();
   }
 }
-//dsfsdfsd
+
 const actionRegister = (login,password) =>
     actionPromise('reg',shopGQL(`mutation reg($login: String!, $password: String!){
         createUser(login:$login, password: $password){
@@ -63,11 +64,23 @@ 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}))
+
+
 export const actionFullRegister = (login,password) => 
   async dispatch => {
     let payload = await dispatch(actionRegister(login,password))
     if(payload.data.createUser != null){
       await dispatch(actionFullLogin(login,password))
+      // await dispatch(actionAvaAdd(avatar,_id))
     }
     else {
       console.log("exiciting user")
@@ -89,9 +102,43 @@ export const actionTypeAd = () =>
             }
         `, {query: JSON.stringify([{}])}))
 
-        // tags
-        // address
-        // images
-        // comments
-        // createdAt
-        //img
+export const actionTypeAdOne = (id) => 
+          actionPromise('AdFindOne',shopGQL(`
+            query Ad($query:String){
+              AdFindOne(query:$query){
+                _id
+                title
+                description
+                price
+                images {
+                  url
+                }
+              }
+            }`,{query: JSON.stringify([{_id:id}])}))
+
+// export const actionUploadFile = (file) =>{  
+// let fd = new FormData
+// fd.append('photo', file)
+
+// return actionPromise('forma', fetch('/upload', {
+//   method: "POST",
+//   headers: localStorage.authToken ? {Authorization: 'Bearer ' + localStorage.authToken} : {},
+//   body: fd
+// }).then(res => res.json()))
+// }
+
+export const actionUpLoadAva = (ava,user) =>
+    async dispatch => {
+        const formData = new FormData();
+        formData.set("avatar", ava);
+        let sendData = await dispatch(actionPromise('send', fetch(`/upload`,
+            {
+                method: 'POST',
+                headers: localStorage.authToken ? { Authorization: 'Bearer ' + localStorage.authToken } : {},
+                body: formData
+            })))
+        let responce = await dispatch(actionPromise('sendData', sendData.json()))
+        console.log(user)
+        let AddAva = dispatch(actionFullRegister(responce._id,user))
+        console.log(AddAva)
+    }

+ 20 - 0
src/pages/AdOne.js

@@ -0,0 +1,20 @@
+import React, {useEffect} from "react";
+import {connect}   from 'react-redux';
+import {AdOne} from "../Components/AdOne";
+import {actionTypeAdOne} from "../actions";
+import {useHistory} from 'react-router-dom';
+
+export const Ad = ({getData3,data3, match:{params:{id}}}) => {
+    useEffect(()=>getData3(id),[id])
+
+    if(data3){
+        return (
+            <div>
+                {(ad) =><AdOne key={ad._id} price = {ad.price} title = {ad.title} description={ad.description}  images={ad.images} /> }
+            </div>
+        )
+    }
+}
+
+const TypeAdOne = connect((state) => ({data3: state.promiseReducer.AdFindOne?.payload?.data?.AdFindOne || []}),{getData3: actionTypeAdOne})(Ad)
+export default TypeAdOne

+ 9 - 3
src/pages/Home.js

@@ -1,15 +1,21 @@
 import React, {useEffect} from "react";
 import {connect}   from 'react-redux';
 import {AdFeed} from "../Components/CAdFeed";
-import { actionTypeAd } from "../actions";
-
+import {AdOne} from "../Components/AdOne";
+import { actionTypeAd ,actionTypeAdOne} from "../actions";
+import { Redirect } from "react-router";
+import {useHistory} from 'react-router-dom';
 
 export const Home = ({getData,data2}) => {
     useEffect(()=>getData(),[])
+    let history = useHistory()
+    if(!localStorage.authToken) {
+        history.push("/login") 
+    }
     if(data2){
         return (
             <div>
-                {data2.map(ad => <AdFeed key={ad._id} _id = {ad. _id} price = {ad.price} title = {ad.title} description={ad.description} owner={ad.owner} images={ad.images}/>)}
+                {data2.map(ad => <AdFeed key={ad._id} _id = {ad. _id} price = {ad.price} title = {ad.title} description={ad.description} owner={ad.owner} images={ad.images} />)}
             </div>
         )
     }

+ 36 - 5
src/pages/Login.js

@@ -2,14 +2,43 @@ import React from "react";
 import {connect}   from 'react-redux';
 import {useState} from "react";
 import {actionFullLogin} from '../actions'
-
+import Button from "../Components/Button";
+import LoginError from "../Components/RegErrors/LoginError";
 import showPwdImg from '../images/3844476-eye-see-show-view-watch_110339.svg';
 import hidePwdImg from '../images/3844477-disable-eye-inactive-see-show-view-watch_110343.svg';
+import {Link, useHistory} from 'react-router-dom';
+import { authReducer } from "../reducers/authReducer";
+import { Redirect } from "react-router";
+import { Nav } from "react-bootstrap";
 
-const LoginForm = ({onLogin}) => {
+const LoginForm = ({onLogin,loggedIn}) => {
   const [login,setLogin] = useState('')
   const [password,setPassword] = useState('')
   const [open,setOpen] = useState(false)
+  const[show,setShow]=useState(false)
+
+  let history = useHistory()
+
+  if(localStorage.authToken) {
+        history.push('/')
+  }
+
+  const isLoginValid = () => {
+    if(!login || !password) {
+        return false 
+    }
+    else return true
+}
+
+const loginCallback = () => {
+    if(isLoginValid()) {
+        onLogin(login, password)
+    }
+    else {
+        setShow(true)
+    }
+}
+
   return (
     <div className="divLogin">
         <h4>Войти</h4>
@@ -22,10 +51,12 @@ const LoginForm = ({onLogin}) => {
             <input value={password} type={open ? "text" : "password"} onChange={e => setPassword(e.target.value)} placeholder="Пароль"  />
             <img src={open ? hidePwdImg : showPwdImg} onClick={() => setOpen(!open)}/>
         </div>
-            <button onClick={() => onLogin(login,password)}>Send</button>  
+            <Link to='sign'>Зарегистрироваться</Link>
+            <Button name='login' isValid={isLoginValid()} callback={loginCallback} />  
+            {show && (!login || !password) && <LoginError />}
     </div>
   )
 }
-///
-const ConnectLog = connect(null, {onLogin: actionFullLogin})(LoginForm)
+
+const ConnectLog = connect(state => ({loggedIn: state.authReducer.login}), {onLogin: actionFullLogin})(LoginForm)
 export default ConnectLog

+ 49 - 8
src/pages/Sign.js

@@ -4,37 +4,78 @@ import {useState} from "react";
 import {actionFullRegister} from '../actions'
 import {Redirect} from 'react-router-dom';
 import ConfirmPass from "../Components/RegErrors/Confirmpass";
-import ExistingLogin from "../Components/RegErrors/exicitingLogin";
+import MinPass from "../Components/RegErrors/MinPass";
 import NumberCheckPass from "../Components/RegErrors/numberCheckPass";
 import showPwdImg from '../images/3844476-eye-see-show-view-watch_110339.svg';
 import hidePwdImg from '../images/3844477-disable-eye-inactive-see-show-view-watch_110343.svg';
+import Button from "../Components/Button";
+import { MyDropzone } from "../Components/DropZone";
 
-
-const Sign = ({onSign,loggedIn,confirmError, numberError}) => {
+const Sign = ({onSign,loggedIn}) => {
     const [login,setLogin] = useState('')
     const [password,setPassword] = useState('')
     const [password2,setPassword2] = useState('')
+    const[show,setShow]=useState(false)
+    const[show2,setShow2]=useState(false)
+    const[show3,setShow3]=useState(false)
+
     const [open,setOpen] = useState(false)
     const [open2,setOpen2] = useState(false)
+   
+
+    const isRegistrationValid = () => {
+        if(!login || password.length<3 || password2.length<3) {
+            return false 
+        }
+        if(!password.match(/\d/)){
+            return false
+        }
+        if(password !== password2) {
+            return false
+        }   
+        else return true
+    }
+
+    const registrationCallback = () => {
+        if(isRegistrationValid()) {
+            onSign(login, password)
+        }
+        else {
+            setShow(true)
+            setShow2(true)
+            setShow3(true)
+        }
+    }
+
+   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="Nickname"></input>
           </div>
           <div className='pwd-container1'>
               <label>Придумайте пароль</label>
-              <input value={password} type={open ? "text" : "password"} onChange={e => setPassword(e.target.value)} placeholder="Пароль"  />
+              <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='pwd-container2'>
               <label>Повторите пароль</label>
-              <input value={password2} type={open2 ? "text" : "password"} onChange={e => setPassword2(e.target.value)} placeholder="Пароль"  />
+              <input value={password2} type={open2 ? "text" : "password"} onChange={e => setPassword2(e.target.value)}  placeholder="Пароль"  />
               <img src={open2 ? hidePwdImg : showPwdImg} onClick={() => setOpen2(!open2)}/>
           </div>
-              <button onClick={() => {onSign(login,password)}}>Send</button>  
-              {loggedIn && <Redirect from="/sign" to="/" /> || numberError && (!password.match(/\d/)) ? <NumberCheckPass /> : (password !== password2) ? <ConfirmPass /> : console.log("poshel nahoi")}
+          <MyDropzone />
+          <Button
+                name='sign'
+                isValid={isRegistrationValid()}
+                callback={registrationCallback}
+            />
+                {show && (!login || password.length<3 || password2.length<3) && <MinPass/>}
+                {show2 && (!password.match(/\d/)) && <NumberCheckPass />}
+                {show3 && (password !== password2) && <ConfirmPass />}
+                {loggedIn && <Redirect push to='/login'/>}
       </div>
 
     )