Browse Source

search by enter, login

maryluis 4 years ago
parent
commit
40ee3de91a

+ 5 - 0
shop/package-lock.json

@@ -9485,6 +9485,11 @@
         "object.assign": "^4.1.2"
       }
     },
+    "jwt-decode": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz",
+      "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A=="
+    },
     "killable": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",

+ 1 - 0
shop/package.json

@@ -6,6 +6,7 @@
     "@testing-library/jest-dom": "^5.11.9",
     "@testing-library/react": "^11.2.5",
     "@testing-library/user-event": "^12.6.3",
+    "jwt-decode": "^3.1.2",
     "react": "^17.0.1",
     "react-dom": "^17.0.1",
     "react-redux": "^7.2.2",

+ 32 - 0
shop/src/App.css

@@ -4,6 +4,11 @@
   color: rgb(229, 229, 243);
 
 }
+a {
+  text-decoration: none;
+  color: rgb(229, 229, 243);
+}
+
  .links {
    text-decoration: none;
    color: rgb(229, 229, 243);
@@ -154,7 +159,31 @@ content {
   height: 75px;
 }
 
+.loginForm {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 15em;
+}
+
+.loginForm input{
+  color:rgb(58, 58, 65);
+  margin: 10px;
+  
+}
+button {
+  margin: 10px;
+  width: 100px;
+  background-color: rgb(58, 58, 65);
+  border-radius: 15%;
+}
 
+.loginForm button {
+  margin: 10px;
+  width: 100px;
+  background-color: rgb(58, 58, 65);
+  border-radius: 15%;
+}
 
 .About {
 
@@ -197,6 +226,9 @@ content {
     width: 60%;
     align-items: center;
   }
+  .loginForm {
+    flex-direction: column;
+  }
 
   .catalog {
 

+ 2 - 1
shop/src/components/MainImg.js

@@ -7,7 +7,7 @@ import {createStore, combineReducers, applyMiddleware} from 'redux';
 import thunk from 'redux-thunk';
 import store from "../reducers";
 import Catalog from "./catalog";
-import {searchInput, CGoodsCategory, SearchInput, CGoodsSearch} from "./index";
+import {searchInput, CGoodsCategory, SearchInput, CGoodsSearch, LoginForm} from "./index";
 // //import {Goods} from "./index";
 // import  from "./goodsCategory";
 // import  from './searchInput';
@@ -37,6 +37,7 @@ const Main = ({className = "MainImg" }) => {
                         <Route path = "/catalog/" component={MainCatalog} exact/>
                         <Route path = "/catalog/:id" component= {({match}) => <CGoodsCategory id = {match.params.id} /> }/>
                         <Route path = "/search/:name" component = {({match}) => <CGoodsSearch name = {match.params.name}/>}/>
+                        <Route path = "/login" component = {LoginForm}/>
                         <Route path="/about" component = {About} exact/>
                         <Route path = "/post" component = {Post} exact/>
                         <Route path = "/contacts" component = {Contacts} />

+ 1 - 1
shop/src/components/goodsSearch.js

@@ -5,7 +5,7 @@ import {actionPromise} from "./index"
 import {gql, actionGoods, getGoods, actionSearch} from "../reducers/index";
 import { useEffect } from 'react';
 import {OneGood, GoodsList} from "./index";
-import CGoodsListSearch from './goodsListSearch';
+
 
 const mapStateToProps = state => ({
     state: state,

+ 24 - 2
shop/src/components/header.js

@@ -3,6 +3,7 @@ import {Footer, Links} from "./index"
 import {BrowserRouter as Router, Route, Link, Switch, Redirect} from 'react-router-dom';
 import createHistory from "history/createBrowserHistory";
 import {Provider, connect} from 'react-redux';
+import {actionAuthLogout} from "../reducers"
 import {createStore, combineReducers, applyMiddleware} from 'redux';
 import thunk from 'redux-thunk';
 
@@ -49,9 +50,27 @@ const TabletMenu = ({}) => {
     )
 }
 
+const ToLoginPage = ({login, onLogout}) => {
+
+    return(
+        <>
+        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person" viewBox="0 0 16 16">
+        <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z"/>
+        </svg>
+        <Link to = {login ? "/yourPage": "/login"} >
+            <span className = "link">{login ? login : "Вхід"}</span>
+            {login && <button onClick = {onLogout}>Вихід</button>}
+        </Link>
+        </>
+    )
+}
+
+const CToLoginPage =connect(s => ({login: s.auth.payload && s.auth.payload.sub.login}), {onLogout: actionAuthLogout}) (ToLoginPage);
+
 const Header = ({}) => {
     const [basketCount, buyDelete] = useState(0);
     const [wishes, wishesCount] = useState(0);
+    console.log(connect((s) => ({isLoggedIn: s.auth.payload})))
     return(
         <>
             <div className = "header">
@@ -69,10 +88,13 @@ const Header = ({}) => {
                         <span>Хочу({wishes})</span>
                     </div>
                     <div>
-                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person" viewBox="0 0 16 16">
+                        <CToLoginPage/>
+                        {/* <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-person" viewBox="0 0 16 16">
                         <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10z"/>
                         </svg>
-                        <span>Вхід</span>
+                        <Link to = "/login" >
+                            <span className = "link">Вхід</span>
+                        </Link> */}
                     </div>
                     <div>
                         <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-bag" viewBox="0 0 16 16">

+ 3 - 1
shop/src/components/index.js

@@ -14,10 +14,12 @@ import SearchInput from "./searchInput";
 import CGoodsSearch from "./goodsSearch";
 import CGoodsListSearch from "./goodsListSearch";
 import GoodsNotFound from "./goodsNotFound";
+import LoginForm from "./loginOnPage";
 
 
 
-export {Header,Footer, actionCatalogCard, Main, Links, CGoodsCategory, OneGood, GoodsList, SearchInput, CGoodsSearch, CGoodsListSearch, GoodsNotFound};
+export {Header,Footer, actionCatalogCard, Main, Links, CGoodsCategory, OneGood, GoodsList, SearchInput, CGoodsSearch, CGoodsListSearch, GoodsNotFound, 
+LoginForm};
 
 
 

+ 79 - 0
shop/src/components/loginOnPage.js

@@ -0,0 +1,79 @@
+import {BrowserRouter as Router, Route, Link, Switch, Redirect} from 'react-router-dom';
+import {Provider, connect} from 'react-redux';
+import React, {Component, useState, useEffect} from 'react';
+import {createStore, combineReducers, applyMiddleware} from 'redux';
+import thunk from 'redux-thunk';
+import jwt_decode from "jwt-decode"
+import { bindActionCreators } from 'redux';
+import {actionLogin, authReducer, actionAuthLogout} from "../reducers/";
+
+
+
+const ButtonLogout = ({onLogout, isLoggedIn}) => 
+    <button onClick={onLogout}
+        disabled={!isLoggedIn}>Logout</button>
+
+ const CButtonLogout = connect(s => ({isLoggedIn: s.auth.payload}),{onLogout: actionAuthLogout})(ButtonLogout)
+
+const DashboardLink = ({login}) =>{
+console.log(login)
+return(
+<div className = "DashboardLink">{login ? <Link to='/dashboard'>{login}</Link> : <Link to='/login'>Anon</Link>}</div>
+)
+}
+const CDashboardLink = connect(s => ({login: s.auth.payload && s.auth.payload.sub.login}))(DashboardLink)
+
+
+const PasswordConfirm = ({isLoggedIn, onLogin = null }) => {
+    const [pass1, setPass1] = useState("");
+    const [pass2, setPass2] = useState("");
+
+
+    return (
+        <>
+            <div>
+                <input
+                    type="text"
+                    placeholder = "login"
+                    onChange={(e) => {
+                        setPass1(e.target.value);
+                    }}
+                ></input>
+                <input
+                    type="password"
+                    placeholder = "password"
+                    onChange={(e) => {
+                        setPass2(e.target.value);
+                    }}
+                ></input>
+            </div>
+            <div>
+                <button disabled = {isLoggedIn} onClick={() => onLogin(pass1, pass2)}>Login</button>
+                <CButtonLogout />
+            </div>
+
+        </>
+    );
+};
+
+const CFormLogin = connect((s) => ({isLoggedIn: s.auth.payload}), {
+    onLogin:actionLogin,
+})(PasswordConfirm);
+
+
+
+const LoginForm = ({}) => {
+
+    return(
+    <>
+        <div className = "loginForm">
+            {/* <CDashboardLink/> */}
+            <CFormLogin />
+
+        </div>
+    </>
+    )
+}
+
+
+export default LoginForm;

+ 7 - 5
shop/src/components/searchInput.js

@@ -1,19 +1,21 @@
 import {useState} from "react";
 import {store, actionSearch} from "../reducers";
 import {BrowserRouter as Router, Route, Link, Switch, Redirect} from 'react-router-dom';
+import { useHistory } from "react-router-dom";
 
 
 
 
-
-const SearchInput = ({classname = "search"}) => {
-    const [name, changeValue] = useState("posuk");
+const SearchInput = ({ classname = "search", input = "Пошук"}) => {
+    const [name, changeValue] = useState("Пошук");
+    const history = useHistory();
+ 
     return(
       <>
         <div className = {classname}>
-            <input type = "text" plaseholder = "Пошук" onChange = {(e) => changeValue(e.target.value)}/>
+            <input type = "text" placeholder = {input} onChange = {e => changeValue(e.target.value)} onKeyDown = {(e) => e.keyCode == 13 && history.push(`/search/${name}`)}/>
             <Link to = {"/search/" + name}>
-                <button onClick = {() => console.log(store.dispatch(actionSearch(name)))}>пуск</button>
+                <button id = "searchButton">пуск</button>
             </Link>
         </div>
       </>

+ 7 - 0
shop/src/reducers/actionAuthLog.js

@@ -0,0 +1,7 @@
+import jwt_decode from "jwt-decode";
+
+
+const actionAuthLogin = jwt => ({type: 'LOGIN', jwt})
+const actionAuthLogout = () => ({type: 'LOGOUT'})
+
+export {actionAuthLogin, actionAuthLogout};

+ 28 - 0
shop/src/reducers/actionLogin.js

@@ -0,0 +1,28 @@
+import {Provider, connect} from 'react-redux';
+import {createStore, combineReducers, applyMiddleware, bindActionCreators} from 'redux';
+import thunk from 'redux-thunk';
+import {actionPromise, actionAuthLogout, actionAuthLogin} from "./index"
+import gql from "./gql";
+import { useEffect } from 'react';
+
+
+
+const actionLogin = (login, password) => 
+
+async dispatch => {
+
+    const res = gql(
+        `query login($login:String, $password:String){
+          login(login:$login,password:$password)
+        }`, { login, password } );
+
+    let loginData = await dispatch(actionPromise('login', res))
+
+    console.log(loginData);
+
+    if (loginData && loginData.data && loginData.data.login){
+        dispatch(actionAuthLogin(loginData.data.login))
+    }
+}
+
+export default actionLogin;

+ 31 - 0
shop/src/reducers/authReducer.js

@@ -0,0 +1,31 @@
+import jwt_decode from "jwt-decode";
+import {actionLogin, store, actionAuthLogin} from "./index";
+
+
+
+
+function authReducer(state, action){ 
+    if (state === undefined){
+        if(localStorage.authToken && localStorage.authToken !== "null") {
+            return {token: localStorage.authToken, payload: jwt_decode(localStorage.authToken)}
+
+        }
+
+        return {}
+    }
+    if (action.type === 'LOGIN'){
+
+
+         localStorage.authToken = action.jwt;
+
+        return {token: action.jwt, payload: jwt_decode(action.jwt)}
+    }
+    if (action.type === 'LOGOUT'){
+        console.log('ЛОГАУТ')
+        localStorage.authToken = ""
+        return {}
+    }
+    return state
+}
+
+export default authReducer;

+ 1 - 1
shop/src/reducers/gql.js

@@ -5,7 +5,7 @@ const getGQL = url =>
                 headers: {
                   'Accept': 'application/json',
                   'Content-Type': 'application/json',
-                  ...(localStorage.authToken ? {Authorization: `Bearer ${localStorage.authToken}`} : {})
+                  ...(localStorage.authToken && localStorage.authToken != 'null' ? {Authorization: `Bearer ${localStorage.authToken}`} : {})
                 },
                 body: JSON.stringify({query,variables})})
         .then(res => res.json())

+ 7 - 2
shop/src/reducers/index.js

@@ -5,10 +5,14 @@ import gql from "./gql";
 import actionGoods from "./actionGoods"
 import getGoods from "./getGoods";
 import {actionSearch} from "./actionsearch";
+import actionLogin from "./actionLogin";
+import authReducer from "./authReducer";
+import {actionAuthLogin, actionAuthLogout} from "./actionAuthLog"
 
 
 
 function promiseReducer(state={}, action){
+
     if (action.type === 'PROMISE'){
         const { name="default", status, payload, error} = action
         if (status){
@@ -22,10 +26,11 @@ function promiseReducer(state={}, action){
   
   
   const store = createStore(combineReducers({
-    promiseRed: promiseReducer
+    promiseRed: promiseReducer, auth: authReducer
   }), compose(applyMiddleware(thunk)))
 
-export {actionPromise, gql, actionGoods, getGoods, promiseReducer, store, actionSearch};
+export {actionPromise, gql, actionGoods, getGoods, promiseReducer, store, actionSearch,
+   actionLogin, authReducer, actionAuthLogin, actionAuthLogout};
 
 
 

+ 0 - 10
shop/src/reducers/reducerCat.js

@@ -44,15 +44,5 @@ const actionCatalogCard = () => {
 
 
 
-
-// function catalogReducer(state = {}, action) {
-//     if (action.type = "FIRSTVISIT") {
-//         catalogCard();
-//     } 
-//     return state;
-// };
-
-//const store = createStore(reducer, {});
-
 export default actionCatalogCard;