Selaa lähdekoodia

HW<19(shop_log_reg)> done

Vitalii Polishchuk 2 vuotta sitten
vanhempi
commit
4ffede2e85

+ 64 - 4
js/18-js-redux-combine(cart)/css/main.css

@@ -25,6 +25,7 @@
     flex-direction: column;
     width: 85%;
     margin-left: 20%;
+    margin-top: 20px;
 }
 
 #main h2 {
@@ -99,9 +100,9 @@ input {
 }
 
 #cart {
-    position: absolute;
-    top: 10px;
-    right: 10%;
+    position: relative;
+    color: #000;
+    margin-right: 20px;
 }
 
 #cart span {
@@ -181,8 +182,10 @@ input {
     transform: scale(0.95);
 }
 
-.btn-minus:disabled {
+.btn-minus:disabled,
+.form button:disabled {
     border-color: grey;
+    color: grey;
     cursor: default;
     box-shadow: none;
 }
@@ -204,3 +207,60 @@ input {
 .btn-clear:hover {
     box-shadow: 0 0 40px 40px #706e6e inset;
 }
+
+#userpanel {
+    display: flex;
+    align-items: center;
+    position: absolute;
+    right: 10px;
+    justify-content: space-between;
+    width: 30vw;
+}
+
+#userpanel a {
+    text-decoration: none;
+    color: inherit;
+    margin: 0 10px;
+    transition: all 0.3s;
+}
+
+#userpanel a:hover {
+    color: grey;
+}
+
+#userpanel button {
+    color: #000;
+    border: none;
+    margin-right: 0;
+}
+
+#userpanel button:hover {
+    box-shadow: none;
+    color: grey;
+}
+
+#userpanel span {
+    font-weight: 600;
+    text-transform: uppercase;
+}
+
+.form {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    justify-content: space-around;
+    padding: 5px;
+    color: #424141;
+}
+
+.form input {
+    width: unset;
+    margin: 10px 0;
+}
+
+.form button {
+    order: 1;
+    margin: 0;
+    margin-top: 15px;
+    transition: all 0.3s ease-in-out;
+}

+ 7 - 3
js/18-js-redux-combine(cart)/index.html

@@ -14,9 +14,13 @@
     <div class="main-container">
         <aside id="aside">Категории</aside>
         <main id="main"></main>
-        <a id="cart" href="#/cart">
-            <img src="img/cart.svg" alt="cart">
-        </a>
+
+        <div id="userpanel">
+            <a id="cart" href="#/cart">
+                <img src="img/cart.svg" alt="cart">
+            </a>
+        </div>
+
     </div>
 
     <script src="js/main.js"></script>

+ 288 - 1
js/18-js-redux-combine(cart)/js/main.js

@@ -63,9 +63,37 @@ function cartReducer(state = {}, { type, count = 1, _id, name }) {
     return state
 }
 
+function authReducer(state, { type, token }) {
+
+    if (state === undefined) {
+        if (localStorage.authToken) {
+            type = "LOGIN"
+            token = localStorage.authToken
+        } else {
+            return {}
+        }
+    }
+
+    if (type === "LOGIN") {
+        localStorage.authToken = token
+        return { token, payload: jwt_decode(token) }
+    }
+    if (type === "LOGOUT") {
+        localStorage.removeItem("authToken")
+        return {}
+    }
+    return state
+}
+
 let reducers = {
     promise: promiseReducer,
-    cart: cartReducer
+    cart: cartReducer,
+    auth: authReducer
+}
+
+let jwt_decode = (token) => {
+    let result = JSON.parse(atob(token.split(".")[1]))
+    return result
 }
 
 function combineReducers(reducers) {
@@ -168,6 +196,40 @@ let newOrder = async (obj) => {
     return res
 }
 
+let log = async (login, password) => {
+    let query = `query log($l: String, $p: String) {
+          login(login: $l, password: $p)
+        }`
+
+    let qVariables = {
+        "l": login,
+        "p": password
+    }
+
+    let token = await shopGQL(query, qVariables)
+    console.log(token)
+    return token.data.login
+}
+
+let reg = async (login, password) => {
+    let query = `mutation reg($l: String, $p: String) {
+          UserUpsert(user:  {
+              login: $l,
+              password: $p
+            } ) {
+              _id
+            }
+        }`
+
+    let qVariables = {
+        "l": login,
+        "p": password
+    }
+
+    let res = await shopGQL(query, qVariables)
+    return res
+}
+
 //actions
 const actionPending = name => ({ type: 'PROMISE', status: 'PENDING', name })
 const actionResolved = (name, payload) => ({ type: 'PROMISE', status: 'RESOLVED', name, payload })
@@ -209,6 +271,32 @@ const actionCartRemove = id => ({ type: "CART_REMOVE", _id: id })
 
 const actionCartClear = () => ({ type: "CART_CLEAR" })
 
+const actionAuthLogin = token => ({ type: "LOGIN", token })
+
+const actionAuthLogout = () => ({ type: "LOGOUT" })
+
+const actionLogin = (login, password) => actionPromise("login", log(login, password))
+
+const actionFullLogin = (login, password) => {
+    return async (dispatch) => {
+        let result = await dispatch(actionLogin(login, password))
+
+        dispatch(actionAuthLogin(result))
+    }
+}
+
+const actionRegister = (login, password) => actionPromise("register", reg(login, password))
+
+const actionFullRegister = (login, password) => {
+    return async (dispatch) => {
+        let result = await dispatch(actionRegister(login, password))
+
+        if (result.data.UserUpsert !== null) {
+            dispatch(actionFullLogin(login, password))
+        }
+    }
+}
+
 store.dispatch(actionRootCategories())
 
 window.onhashchange = () => {
@@ -224,6 +312,14 @@ window.onhashchange = () => {
     if (route === 'cart') {
         cartDraw(store.getState().cart, main)
     }
+
+    if (route === "login") {
+        loginDraw(main)
+    }
+
+    if (route === "registration") {
+        registrationDraw(main)
+    }
 }
 
 //рисовашки
@@ -389,10 +485,195 @@ let cartValueDraw = () => {
     cart.lastChild.textContent = sum
 }
 
+let userStatus = (parent = userpanel) => {
+    if (parent.children.length > 1) {
+        parent.lastChild.remove()
+    }
+
+    let status = store.getState().auth
+    let box = document.createElement("div")
+    box.style.display = "flex"
+    box.style.alignItems = "center"
+    let userName = document.createElement("span")
+
+    box.append(userName)
+    parent.append(box)
+
+    if (status.payload) {
+        let btn = document.createElement("button")
+        userName.textContent = status.payload.sub.login
+        btn.textContent = "Выход"
+        btn.onclick = () => {
+            store.dispatch(actionAuthLogout())
+        }
+        box.append(btn)
+    } else {
+        let btn = document.createElement("a")
+        let btnREG = document.createElement("a")
+        userName.textContent = "Гость"
+        btn.textContent = "Вход"
+        btnREG.textContent = "Регистрация"
+        btn.href = "#/login"
+        btnREG.href = "#/registration"
+
+        box.append(btn, btnREG)
+    }
+}
+
+function Form(parent, type, open) {
+    let h3 = document.createElement("h3");
+    let loginInput = document.createElement("input");
+    let passwordInput = document.createElement("input");
+    let checkbox = document.createElement("input");
+    let btn = document.createElement("button");
+    let form = document.createElement("div");
+    let box = document.createElement("div")
+    box.style.display = "flex"
+    box.style.alignItems = "center"
+    box.append(passwordInput, checkbox)
+    loginInput.id = "login"
+    loginInput.placeholder = "логин"
+    passwordInput.id = "password"
+    passwordInput.placeholder = "пароль"
+    btn.id = "btn"
+    checkbox.type = "checkbox";
+    checkbox.style.marginLeft = "5px"
+    btn.disabled = true;
+
+    if (type === "reg") {
+        h3.textContent = "РЕГИСТРАЦИЯ"
+        btn.textContent = "ЗАРЕГИСТРИРОВАТЬСЯ";
+    } else {
+        h3.textContent = "ВХОД"
+        btn.textContent = "Войти";
+    }
+
+    form.append(h3, loginInput, box, btn)
+    form.className = "form"
+    parent.append(form)
+
+    let btnOpen = () => {
+        if (type === "reg" && checkbox.checked === false) {
+            passwordInput.value !== "" && password.value === passwordVerify.value ? btn.disabled = false : btn.disabled = true;
+        } else {
+            (loginInput.value != "" && passwordInput.value != "") ? btn.disabled = false : btn.disabled = true;
+        }
+    }
+
+    let checker = (check) => {
+        if (check) {
+            passwordInput.type = "text";
+            checkbox.checked = true;
+
+            if (type === "reg" && passwordVerify) {
+                passwordVerify.remove()
+            }
+        } else {
+            passwordInput.type = "password";
+            checkbox.checked = false;
+
+            if (type === "reg") {
+                let passwordInput2 = document.createElement("input");
+                passwordInput2.placeholder = "повторите пароль"
+                passwordInput2.id = "passwordVerify"
+                passwordInput2.type = "password"
+
+                passwordInput2.oninput = () => {
+                    btnOpen();
+                }
+                form.append(passwordInput2)
+            }
+        }
+    }
+    checker(open);
+
+    loginInput.oninput = () => {
+        btnOpen();
+
+        if (typeof this.onChange === "function") {
+            this.onChange([loginInput.value, passwordInput.value]);
+        }
+    }
+
+    passwordInput.oninput = () => {
+        btnOpen();
+
+        if (typeof this.onChange === "function") {
+            this.onChange([loginInput.value, passwordInput.value]);
+        }
+    }
+
+    checkbox.onchange = () => {
+        checker(checkbox.checked)
+        btnOpen()
+
+        if (typeof this.onOpenChange === "function") {
+            this.onOpenChange(checkbox.checked);
+        }
+    }
+
+    this.getValue = () => [loginInput.value, passwordInput.value];
+
+    this.setValue = (valueLogin, valuePassword) => {
+        loginInput.value = valueLogin;
+        passwordInput.value = valuePassword;
+        btnOpen();
+    }
+
+    this.getOpen = () => checkbox.checked;
+
+    this.setOpen = (open) => {
+        checker(open);
+    }
+}
+
+let loginDraw = (parent) => {
+    while (parent.lastChild) {
+        parent.lastChild.remove()
+    }
+
+    if (store.getState().auth.payload) {
+        let h2 = document.createElement("h2")
+        h2.textContent = "ВЫ ВОШЛИ"
+        h2.style.color = "grey"
+        parent.append(h2)
+    } else {
+        let form = new Form(parent)
+        btn.onclick = () => {
+            store.dispatch(actionFullLogin(login.value, password.value))
+        }
+    }
+}
+
+let registrationDraw = (parent) => {
+    while (parent.lastChild) {
+        parent.lastChild.remove()
+    }
+
+    if (store.getState().auth.payload) {
+        let h2 = document.createElement("h2")
+        h2.textContent = "ВЫ УСПЕШНО ЗАРЕГИСТРИРОВАЛИСЬ"
+        h2.style.color = "grey"
+        parent.append(h2)
+    } else if (store.getState().promise.register && store.getState().promise.register.status === "RESOLVED") {
+        let h3 = document.createElement("h3")
+        h3.textContent = "Error: " + store.getState().promise.register.payload.errors[0].message
+        h3.style.color = "red"
+        parent.append(h3)
+    } else {
+        let form = new Form(parent, "reg")
+
+        btn.onclick = () => {
+            store.dispatch(actionFullRegister(login.value, password.value))
+        }
+    }
+}
+
 //subscribers
 const unsubscribe1 = store.subscribe(() => console.log(store.getState()))
 store.subscribe(drawMainMenu)
 store.subscribe(cartValueDraw)
+store.subscribe(userStatus)
 
 store.subscribe(() => {
     const { 1: route, 2: id } = location.hash.split('/')
@@ -426,4 +707,10 @@ store.subscribe(() => {
     if (route === 'cart') {
         cartDraw(store.getState().cart, main)
     }
+    if (route === 'login') {
+        loginDraw(main)
+    }
+    if (route === "registration") {
+        registrationDraw(main)
+    }
 })