Daria10 3 anni fa
parent
commit
1fe1bcfa61
6 ha cambiato i file con 336 aggiunte e 29 eliminazioni
  1. 36 0
      package-lock.json
  2. 4 0
      package.json
  3. 30 27
      src/Companents/Header.js
  4. 2 2
      src/Pages/Acc.js
  5. 133 0
      src/Pages/Login.js
  6. 131 0
      src/Reduser.js

+ 36 - 0
package-lock.json

@@ -9574,6 +9574,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",
@@ -12446,6 +12451,18 @@
         "warning": "^4.0.3"
       }
     },
+    "react-redux": {
+      "version": "7.2.2",
+      "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.2.tgz",
+      "integrity": "sha512-8+CQ1EvIVFkYL/vu6Olo7JFLWop1qRUeb46sGtIMDCSpgwPQq8fPLpirIB0iTqFe9XYEFPHssdX8/UwN6pAkEA==",
+      "requires": {
+        "@babel/runtime": "^7.12.1",
+        "hoist-non-react-statics": "^3.3.2",
+        "loose-envify": "^1.4.0",
+        "prop-types": "^15.7.2",
+        "react-is": "^16.13.1"
+      }
+    },
     "react-refresh": {
       "version": "0.8.3",
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@@ -12689,6 +12706,20 @@
         "strip-indent": "^3.0.0"
       }
     },
+    "redux": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz",
+      "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==",
+      "requires": {
+        "loose-envify": "^1.4.0",
+        "symbol-observable": "^1.2.0"
+      }
+    },
+    "redux-thunk": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
+      "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
+    },
     "regenerate": {
       "version": "1.4.2",
       "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -14325,6 +14356,11 @@
         "util.promisify": "~1.0.0"
       }
     },
+    "symbol-observable": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
+      "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
+    },
     "symbol-tree": {
       "version": "3.2.4",
       "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",

+ 4 - 0
package.json

@@ -7,11 +7,15 @@
     "@testing-library/react": "^11.2.5",
     "@testing-library/user-event": "^12.6.3",
     "bootstrap": "^4.6.0",
+    "jwt-decode": "^3.1.2",
     "react": "^17.0.1",
     "react-bootstrap": "^1.4.3",
     "react-dom": "^17.0.1",
+    "react-redux": "^7.2.2",
     "react-router-dom": "^5.2.0",
     "react-scripts": "4.0.2",
+    "redux": "^4.0.5",
+    "redux-thunk": "^2.3.0",
     "web-vitals": "^1.1.0"
   },
   "scripts": {

+ 30 - 27
src/Companents/Header.js

@@ -2,31 +2,35 @@ import React, { useState,Component } from 'react';
 import { Container, FormControl, Nav, Navbar, Form, Button } from 'react-bootstrap';
 import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
 import logoPhoto from '../assets/photo_logo.jpg';
-// import PageAuth from "../Companents/auth"
-// import { store } from "../store";
+import { store } from "../Reduser";
+import { Provider, connect } from "react-redux";
+
+
+
 
 import Home from "../Pages/Home"
-// import Acc from "../Pages/Acc"
+import Acc from "../Pages/Acc"
 import Top from "../Pages/Top"
 import New from "../Pages/New"
-import Acc from '../Pages/Acc';
-
-const Playllists = (props) => {
-  return (
-    <>
-      <div> wertyuio</div>
-      <div>{console.log(props)}</div>
-    </>
-  )
-}
-const Search = ({ history }) => {
-  const onClick = () => history.push(`/search/${value}`)
-  let [value, setValue] = useState('')
-  return (
-    <div class="form-inline my-2 my-lg-0">
-      <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" value={value} onChange={e => setValue(e.target.value)} onKeyDown={e => e.keyCode === 13 && onClick()} />
-    </div>
-  )}
+// import Acc from '../Pages/Acc'
+import {Login} from "../Pages/Login"
+
+// const Playllists = (props) => {
+//   return (
+//     <>
+//       <div> wertyuio</div>
+//       <div>{console.log(props)}</div>
+//     </>
+//   )
+// }
+// const Search = ({ history }) => {
+//   const onClick = () => history.push(`/search/${value}`)
+//   let [value, setValue] = useState('')
+//   return (
+//     <div class="form-inline my-2 my-lg-0">
+//       <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" value={value} onChange={e => setValue(e.target.value)} onKeyDown={e => e.keyCode === 13 && onClick()} />
+//     </div>
+//   )}
 
 
   // console.log(PagePlaylist)
@@ -55,10 +59,8 @@ const Search = ({ history }) => {
                   <Nav.Link href="/acc">Acc</Nav.Link>
                   <Nav.Link href="/top">Top</Nav.Link>
                   <Nav.Link href="/new">New</Nav.Link>
-                  <Nav.Link href="/auth">Pages</Nav.Link>
-                  {/* <Nav.Link href="/new">New</Nav.Link> */}
-                  {/* <Nav.Link href="/playlists">Playlists</Nav.Link> */}
-                  {/* <Nav.Link href="/playllists/:_id">Playllists</Nav.Link> */}
+                  <Nav.Link href="/log">Login</Nav.Link>
+
                 </Nav>
 
                 <Form inline>
@@ -78,18 +80,19 @@ const Search = ({ history }) => {
               </Navbar.Collapse>
             </Container>
           </Navbar>
-
+          <Provider store={store}>
           <Router>
             <Switch>
               <Route exact path="/" component={Home} />
               <Route exact path="/acc" component= {Acc} />
               <Route exact path="/top" component={Top} />
               <Route exact path="/new" component={New} />
+              <Route exact path="/log" component={Login} />
  
               {/* <Route exact path="/playlists" component={Playllists} /> */}
             </Switch>
           </Router>
-
+</Provider>
 
 
         </>

+ 2 - 2
src/Pages/Acc.js

@@ -15,11 +15,11 @@ import { Form, Button, Container, FormCheck } from 'react-bootstrap'
                     Your accaunt
                 </h1>
                 <Form>
-                    <Form.Group controlId="formBasicEmail">
+                   
                     <Form.Label> Login</Form.Label>
                         <Form.Control type="login" value={login} placeholder="Enter login" onChange={({ target: { value } }) => setLogin(value)} />
 
-                    </Form.Group>
+   
                     <Form.Group controlId="formBasicPassword">
                         <Form.Label> Password</Form.Label>
                         <Form.Control type="password" placeholder="Enter password" value={password1} onChange={({ target: { value } }) => setPassword1(value)} />

+ 133 - 0
src/Pages/Login.js

@@ -0,0 +1,133 @@
+import React, { useState, useRef, } from "react";
+import { connect } from "react-redux";
+// import { actionLogin } from "../Actions";
+// import history from "../history";
+import { actionLogin, store } from "../Reduser";
+import { Container, FormControl, Nav, Navbar, Form, Button } from 'react-bootstrap';
+const LoginForm = ({ onLogin = null, isLoggedIn, mode = "Login" }) => {
+    const [login, setLogin] = useState("");
+    const [pass, setPass] = useState("");
+    const [nick, setNick] = useState("");
+    const input_ref = useRef(null);
+    const pass_ref = useRef(null);
+    const nick_ref = useRef(null);
+    const btn_ref = useRef(null);
+
+
+
+
+
+
+
+
+    return (
+        <>
+            <Container style={{ width: "500px" }}>
+                <h1 className="text-center">
+                    Your accaunt
+                </h1>
+                <Form>
+                    <Form.Label> Login</Form.Label>
+                    <Form.Control
+                        type="login"
+
+                        placeholder="Enter login"
+
+                        ref={input_ref}
+                        readOnly={isLoggedIn}
+
+
+
+                        onChange={(e) => {
+                            setLogin(e.target.value);
+                        }} />
+                    <Form.Group controlId="formBasicPassword">
+                        <Form.Label> Password</Form.Label>
+                        <Form.Control
+                            type="password"
+                            placeholder="Enter password"
+                            ref={pass_ref}
+                            readOnly={isLoggedIn}
+
+                            onChange={(e) => {
+                                setPass(e.target.value)
+                            }
+                            } />
+
+                    </Form.Group>
+                    <Form.Group controlId="formBasicPassword">
+                        <Form.Label> Confirm Password</Form.Label>
+                        <Form.Control
+                            type="password"
+                            placeholder="Confirm password"
+
+                            ref={pass_ref}
+                            readOnly={isLoggedIn}
+                            type="password"
+
+                            onChange={(e) => {
+                                setPass(e.target.value);
+                            }} />
+                    </Form.Group>
+                    <Button 
+                    variant="secondary" 
+                    type="submit" 
+                    ref={btn_ref}
+                    onClick={() => {
+                        onLogin(login, pass);
+                        console.log("кнопка лагин нажата");
+                    }}
+                    disabled={isLoggedIn || !login || !pass || (mode !== "Login" && !nick)} 
+                    > {mode} </Button>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                </Form>
+            </Container>
+            {/* <input
+                ref={pass_ref}
+                readOnly={isLoggedIn}
+                type="password"
+                placeholder="Password"
+                onChange={(e) => {
+                    setPass(e.target.value);
+                }}
+            ></input> */}
+
+            {/* <button
+                ref={btn_ref}
+                onClick={() => {
+                    onLogin(login, pass);
+                    console.log("кнопка лагин нажата");
+                }}
+                disabled={isLoggedIn || !login || !pass || (mode !== "Login" && !nick)}
+            >
+                {mode}
+            </button> */}
+        </>
+    );
+};
+
+const CLoginForm = connect((s) => ({ isLoggedIn: s.auth.login, mode: "Login" }), { onLogin: actionLogin })(LoginForm);
+
+export const Login = () => {
+    return (
+        <>
+            <div>PageLogin</div>
+            <CLoginForm />
+        </>
+    );
+};

+ 131 - 0
src/Reduser.js

@@ -0,0 +1,131 @@
+import { createStore, combineReducers, applyMiddleware } from "redux";
+import thunk from "redux-thunk";
+import jwt_decode from "jwt-decode";
+
+const getGQL = (url) => (query, variables = {}) => {
+    return fetch(url, {
+        method: "POST",
+        headers: {
+            Accept: "application/json",
+            "Content-Type": "application/json",
+            ...(localStorage.authToken ? { Authorization: `Bearer ${localStorage.authToken}` } : {}),
+        },
+        body: JSON.stringify({ query, variables }),
+    }).then((res) => res.json());
+};
+
+export const gql = getGQL("http://player.asmer.fs.a-level.com.ua/graphql");
+//формуляр отправляеться к ларьку и дает ,бумашку 
+
+
+
+export const actionAuthLogin = (jwt) => ({ type: "LOGIN", jwt })
+
+
+export const actionAuthLogout = () => {
+   
+    return { type: "LOGOUT" };//бегунок умеет разлогиневать берет бумажку и несет  в ларек что б разлогинили
+};
+//экш тип действия !
+
+export const actionLogin = (login, password) => async (dispatch) => {// бегунок он берет функцию которая умеет в ларек подавать команды
+    let loginData = await dispatch(//бегунок окторый логинит
+        actionPromise(
+            "login",
+            gql(
+                `query login($login:String, $password:String){
+              login(login:$login,password:$password)
+            }`,
+                { login, password }
+            )
+        )
+    );
+
+    if (loginData && loginData.data.login) {
+        dispatch(actionAuthLogin(loginData.data.login));
+        // history.push(`/main/${store.getState().auth.payloadId}`);
+    }
+};
+
+
+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());
+        let payload;
+        try {
+            payload = await promise;
+            dispatch(actionResolved(payload));
+        } catch (e) {
+            dispatch(actionRejected(e));
+        }
+        return payload;
+    };
+};
+
+
+
+
+function authReducer(state, action) {
+    if (state === undefined) {//смотрит есть ли стейт
+        if (!localStorage.authToken) {//есть ли ключ от прошло авторизации
+            return {};//пустой ларек
+        } else {
+            action.type = "LOGIN";//делаем логиню действие логин
+            action.jwt = localStorage.authToken;//занесли токен
+        }
+    }
+
+    if (action.type === "LOGIN") {//действие логин
+        try {
+            localStorage.authToken = action.jwt;//на тот случай когда не из локалстореджа взяли информацию а пошли на сервере залогинились
+            console.log("ЛОГИН", jwt_decode(action.jwt).sub.login);//раскодироват
+            return {
+                login: true,//залогинились
+                token: action.jwt,
+                payload: jwt_decode(action.jwt).sub.login,//декодируем токен 
+                payloadId: jwt_decode(action.jwt).sub.id,
+            };//это все в лорьке который отвечает за логин
+        } catch (error) {
+            localStorage.removeItem("authToken");
+            return {};
+        }
+    }
+
+    if (action.type === "LOGOUT") {
+        console.log("ЛОГАУТ");
+        localStorage.removeItem("authToken");//и локалстореджа удаляем наш токен
+        return {};
+    }
+    return state;//возвращаем пустой стейт
+}
+
+function promiseReducer(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,
+                },
+            };
+        }
+    }
+    return state;
+}
+
+
+
+export const store = createStore(//хранилище создаем комбинируем из нескольких хранилищ
+    combineReducers({ auth: authReducer, promise: promiseReducer }),
+    applyMiddleware(thunk)//позволяет обробатівать я хочу пива но если пива нет я его подождую инструкция
+);//после команды стор появился гетстор субскрайб диспач
+
+store.subscribe(() => console.log(store.getState()));// при любом измении магазина в консоль вывести состояние магазина//