浏览代码

Make some fixes with login and registration

Bonyant 2 年之前
父节点
当前提交
730d0bb4e4
共有 3 个文件被更改,包括 264 次插入111 次删除
  1. 3 1
      15/index.html
  2. 257 110
      15/index.js
  3. 4 0
      15/styles.css

+ 3 - 1
15/index.html

@@ -17,7 +17,9 @@
     <nav class="navbar navbar-dark bg-dark">
       <div class="container-fluid">
         <a class="navbar-brand" href="#">Piece of shit</a>
-        <form class="d-flex" id="authnav"></form>
+        <form class="d-flex" id="authnav">
+          <button id="cartIcon" class="btn btn-link"></button>
+        </form>
       </div>
     </nav>
     <div id="mainContainer">

+ 257 - 110
15/index.js

@@ -58,11 +58,52 @@ const actionAuthLogin = (token) => ({
 });
 const actionAuthLogout = () => ({ type: "AUTH_LOGOUT" });
 
-function promiseReducer(state = {}, { type, status, payload, error, name }) {
+function cartReducer(state = {}, { type, good = {}, count }) {
+  const { _id } = good;
+
+  const types = {
+    CART_ADD() {
+      count = +count;
+      if (!count) {
+        return state;
+      }
+      return {
+        ...state,
+        [_id]: { good, count: count + (state[_id]?.count || 0) },
+      };
+    },
+    CART_CHANGE() {
+      count = +count;
+      if (!count) {
+        return state;
+      }
+      return {
+        ...state,
+        [_id]: { good, count },
+      };
+    },
+    CART_REMOVE() {
+      let { [_id]: remove, ...goods } = state;
+      return goods;
+    },
+    CART_CLEAR() {
+      return {};
+    },
+  };
+  if (type in types) {
+    return types[type]();
+  }
+  return state;
+}
+
+function promiseReducer(state = {}, { type, status, payload, errors, name }) {
+  if (!state) {
+    return {};
+  }
   if (type === "PROMISE") {
     return {
       ...state,
-      [name]: { status, payload, error },
+      [name]: { status, payload, errors },
     };
   }
   return state;
@@ -74,11 +115,11 @@ const actionResolved = (name, payload) => ({
   name,
   payload,
 });
-const actionRejected = (name, error) => ({
+const actionRejected = (name, errors) => ({
   type: "PROMISE",
   status: "REJECTED",
   name,
-  error,
+  errors,
 });
 const actionPromise = (name, promise) => async (dispatch) => {
   dispatch(actionPending(name));
@@ -112,9 +153,48 @@ function combineReducers(reducers) {
 const combinedReducer = combineReducers({
   promise: promiseReducer,
   auth: authReducer,
+  cart: cartReducer,
 });
 const store = createStore(combinedReducer);
 
+const actionCartAdd = (good, count) => ({
+  type: "CART_ADD",
+  good,
+  count,
+});
+const actionCartChange = (good, count) => ({
+  type: "CART_CHANGE",
+  good,
+  count,
+});
+const actionCartRemove = (good) => ({ type: "CART_REMOVE", good });
+const actionCartClear = () => ({ type: "CART_CLEAR" });
+
+const actionOrder = () => async (dispatch, getState) => {
+  let { cart } = getState();
+  let orderGoods = Object.entries(cart).map(([, { _id, count }]) => ({
+    good: { _id, count },
+  }));
+  dispatch(
+    actionPromise(
+      "order",
+      gql(`
+      mutation newOrder($order:OrderInput){
+        OrderUpsert(order:$order)
+        { _id total }
+      }
+    `),
+      { order: { orderGoods } }
+    )
+  );
+};
+
+// store.dispatch(actionCartAdd({ _id: "beer" }, 1));
+// store.dispatch(actionCartAdd({ _id: "vodka" }, 1));
+// store.dispatch(actionCartChange({ _id: "beer" }, 10));
+// store.dispatch(actionCartRemove({ _id: "vodka" }));
+// console.log(store.getState());
+
 const getGQL =
   (url) =>
   async (query, variables = {}) => {
@@ -182,6 +262,45 @@ const actionGoodById = (_id) =>
     )
   );
 
+const actionLogin = (login, password) =>
+  actionPromise(
+    "login",
+    gql(
+      `query log($login: String, $password: String) {
+      login(login: $login, password: $password)
+  }`,
+      { login: login, password: password }
+    )
+  );
+
+const actionFullLogin = (login, password) => async (dispatch) => {
+  let token = await dispatch(actionLogin(login, password));
+  if (token) {
+    dispatch(actionAuthLogin(token));
+  }
+};
+
+const actionRegister = (login, password) =>
+  actionPromise(
+    "register",
+    gql(
+      `mutation reg($user:UserInput) {
+      UserUpsert(user:$user) {
+      _id 
+      }
+  }
+  `,
+      { user: { login: login, password: password } }
+    )
+  );
+
+const actionFullRegister = (login, password) => async (dispatch) => {
+  let check = await dispatch(actionRegister(login, password));
+  if (check) {
+    dispatch(actionFullLogin(login, password));
+  }
+};
+
 store.dispatch(actionRootCats());
 store.dispatch(actionGoodById());
 
@@ -204,6 +323,10 @@ store.subscribe(() => {
 
 window.onhashchange = () => {
   const [, route, _id] = location.hash.split("/");
+  let signOut = document.createElement("button");
+  signOut.innerText = "Sign Out";
+  signOut.id = "signoutBtn";
+  signOut.className = "btn btn-secondary";
   const routes = {
     category() {
       store.dispatch(actionCatById(_id));
@@ -211,6 +334,42 @@ window.onhashchange = () => {
     good() {
       store.dispatch(actionGoodById(_id));
     },
+    login() {
+      let loginInput = document.getElementById("loginInput");
+      let passwordInput = document.getElementById("pass1Input");
+      if (
+        loginInput &&
+        passwordInput &&
+        loginInput.value &&
+        passwordInput.value
+      ) {
+        store.dispatch(
+          actionFullLogin(
+            loginInput.value.slice(0, loginInput.value.indexOf("@")),
+            passwordInput.value
+          )
+        );
+      } else {
+        throw new Error("Error login");
+      }
+    },
+    register() {
+      let regInput = document.getElementById("regInput");
+      let passwordInput = document.getElementById("pass2Input");
+      if (regInput && passwordInput && regInput.value && passwordInput.value) {
+        store.dispatch(
+          actionFullRegister(
+            regInput.value.slice(0, regInput.value.indexOf("@")),
+            passwordInput.value
+          )
+        );
+      } else {
+        throw new Error("Error register");
+      }
+    },
+    cart() {
+      // Сделать страницу с позициями, полями ввода количества, картинками
+    },
   };
   if (route in routes) routes[route]();
 };
@@ -239,8 +398,8 @@ store.subscribe(() => {
       }
     }
     if (promise.catById.payload?.goods) {
-      for (const { _id, name, price, images } of promise.catById.payload
-        .goods) {
+      for (const good of promise.catById.payload.goods) {
+        const { _id, name, price, images } = good;
         const card = document.createElement("div");
         const link = document.createElement("a");
         card.innerHTML = `<h2>${name}</h2>
@@ -250,14 +409,33 @@ store.subscribe(() => {
         link.innerText = name;
         link.href = `#/good/${_id}`;
         card.appendChild(link);
+
+        let buyBtn = document.createElement("button");
+        buyBtn.className = "btn btn-success";
+        buyBtn.textContent = "Buy";
+        buyBtn.onclick = () => {
+          store.dispatch(actionCartAdd(good, 1));
+        };
+        card.appendChild(buyBtn);
         main.append(card);
       }
     }
   }
 });
 
+store.subscribe(() => {
+  const { cart } = store.getState();
+  let countGoods = 0;
+
+  for (let good of Object.keys(cart)) {
+    countGoods += cart[good].count;
+  }
+  cartIcon.innerText = `Товаров в корзине: ${countGoods}`;
+});
+
 store.subscribe(() => {
   const { promise } = store.getState();
+
   const [, route, _id] = location.hash.split("/");
   if (promise?.goodById?.payload && route === "good") {
     main.innerHTML = "";
@@ -286,85 +464,42 @@ function jwtDecode(token) {
   }
 }
 
-const actionLogin = (login, password) =>
-  actionPromise(
-    "login",
-    gql(
-      `query login($login: String, $password: String){
-      login(login: $login, password: $password)
-    }`,
-      { login: login, password: password }
-    )
-  );
-
-const actionFullLogin = (login, password) => {
-  async (dispatch) => {
-    let token = await dispatch(actionLogin(login, password));
-    if (token) {
-      dispatch(actionAuthLogin(token));
-    }
-    return token;
-  };
-};
-
-const actionRegister = (login, password) =>
-  actionPromise(
-    "register",
-    gql(
-      `mutation register($login:String, $password: String){
-      UserUpsert(user:{
-                 login: $login, 
-                 password: $password, 
-                 nick: $login}){
-        _id login
-      }
-    }`,
-      { login: login, password: password }
-    )
-  );
-
-const actionFullRegister = (login, password) => async (dispatch) => {
-  let check = await dispatch(actionRegister(login, password));
-  if (check) {
-    let token = await dispatch(actionLogin(login, password));
-    if (token) {
-      dispatch(actionAuthLogin(token));
-    }
-  }
-};
+store.subscribe(async () => {
+  const { promise } = store.getState();
 
-let count = 0;
+  let signinBtn = document.getElementById("signinBtn");
+  let signupBtn = document.getElementById("signupBtn");
 
-store.subscribe(() => {
-  const { auth, promise } = store.getState();
-  count++;
-  if (!auth?.payload && count === 1) {
+  if (promise?.rootCats?.payload && !signinBtn && !signupBtn) {
     let signIn = document.createElement("button");
     signIn.innerText = "Sign In";
     signIn.id = "signinBtn";
+    signIn.type = "button";
     signIn.className = "btn btn-light";
     let signUp = document.createElement("button");
     signUp.innerText = "Sign Up";
     signUp.id = "signupBtn";
+    signUp.type = "button";
     signUp.className = "btn btn-light";
     let authBlock = document.createElement("div");
     authBlock.id = "authBlock";
     authBlock.appendChild(signIn);
     authBlock.appendChild(signUp);
     authnav.appendChild(authBlock);
-    let signOut = document.createElement("button");
-    signOut.innerText = "Sign Out";
-    signOut.id = "signoutBtn";
-    signOut.className = "btn btn-secondary";
+  }
+});
 
-    signIn.onclick = () => {
+store.subscribe(async () => {
+  let signinBtn = document.getElementById("signinBtn");
+  if (signinBtn) {
+    signinBtn.onclick = () => {
       try {
         let registerFields = document.getElementById("registerFields");
         if (registerFields !== null) {
           registerFields.style.display = "none";
         }
-        signIn.style.display = "none";
-        signUp.style.display = "inline";
+        signinBtn.style.display = "none";
+        signupBtn.style.display = "inline";
 
         let fieldsBlock = document.createElement("div");
         fieldsBlock.className = "fields";
@@ -388,36 +523,29 @@ store.subscribe(() => {
         fieldsBlock.appendChild(login);
         authBlock.prepend(fieldsBlock);
 
-        let loginBtn = document.getElementById("loginBtn");
-        loginBtn.onclick = async () => {
-          let loginInput = document.getElementById("loginInput");
-          let passwordInput = document.getElementById("pass1Input");
-          if (loginInput.value && passwordInput.value) {
-            store.dispatch(
-              actionFullLogin(loginInput.value, passwordInput.value)
-            );
-            if (actionFullLogin(loginInput.value, passwordInput.value)) {
-              let loginBlock = document.getElementById("loginFields");
-              loginBlock.style.display = "none";
-              signupBtn.style.display = "none";
-              authBlock.appendChild(signOut);
-            }
-          }
+        loginBtn.onclick = () => {
+          window.location.href = "#/login";
           console.log(store.getState());
         };
       } catch (error) {
         console.log(error);
       }
     };
+  }
+});
 
-    signUp.onclick = () => {
+store.subscribe(async () => {
+  let signupBtn = document.getElementById("signupBtn");
+  if (signupBtn) {
+    signupBtn.onclick = () => {
       try {
         let loginFields = document.getElementById("loginFields");
         if (loginFields !== null) {
           loginFields.style.display = "none";
         }
-        signIn.style.display = "inline";
-        signUp.style.display = "none";
+        signinBtn.style.display = "inline";
+        signupBtn.style.display = "none";
+
         let fieldsBlock = document.createElement("div");
         fieldsBlock.className = "fields";
         fieldsBlock.id = "registerFields";
@@ -440,44 +568,63 @@ store.subscribe(() => {
         fieldsBlock.appendChild(register);
         authBlock.prepend(fieldsBlock);
 
-        let regBtn = document.getElementById("regBtn");
-        regBtn.onclick = async () => {
-          let regInput = document.getElementById("regInput");
-          let passwordInput = document.getElementById("pass2Input");
-          if (regInput.value && passwordInput.value) {
-            store.dispatch(
-              actionFullRegister(regInput.value, passwordInput.value)
-            );
-            if (actionFullRegister(regInput.value, passwordInput.value)) {
-              let registerBlock = document.getElementById("registerFields");
-              registerBlock.style.display = "none";
-              signinBtn.style.display = "none";
-              authBlock.appendChild(signOut);
-              let nickname = regInput.value.slice(
-                0,
-                regInput.value.indexOf("@")
-              );
-              let account = document.createElement("button");
-              account.textContent = nickname;
-              account.type = "button";
-              account.id = "accountLink";
-              account.className = "btn btn-success";
-              authBlock.prepend(account);
-            }
-          }
+        regBtn.onclick = () => {
+          window.location.href = "#/register";
           console.log(store.getState());
         };
       } catch (error) {
         console.log(error);
       }
     };
+  }
+});
 
+store.subscribe(async () => {
+  const { promise, auth } = store.getState();
+  let accountLink = document.getElementById("accountLink");
+  let signoutBtn = document.getElementById("signoutBtn");
+  let signinBtn = document.getElementById("signinBtn");
+  let signupBtn = document.getElementById("signupBtn");
+
+  if (auth?.token && !signoutBtn && !accountLink) {
+    signinBtn.style.display = "none";
+    signupBtn.style.display = "none";
+
+    if (promise?.register?.status === "RESOLVED") {
+      let registerBlock = document.getElementById("registerFields");
+      registerBlock.style.display = "none";
+      signupBtn.style.display = "none";
+      window.location.href = window.location.href.replace("#/register", "");
+      console.log(store.getState());
+    }
+    if (promise?.login?.status === "RESOLVED") {
+      let loginBlock = document.getElementById("loginFields");
+      loginBlock.style.display = "none";
+      signinBtn.style.display = "none";
+      window.location.href = window.location.href.replace("#/login", "");
+      console.log(store.getState());
+    }
+    let signOut = document.createElement("button");
+    signOut.innerText = "Sign Out";
+    signOut.id = "signoutBtn";
+    signOut.className = "btn btn-secondary";
+    let authBlock = document.createElement("div");
+    authBlock.id = "authBlock";
+    authBlock.appendChild(signOut);
+    let nickname = auth.payload.sub.login;
+    let account = document.createElement("button");
+    account.textContent = nickname;
+    account.type = "button";
+    account.id = "accountLink";
+    account.className = "btn btn-success";
+    authBlock.prepend(account);
+    authnav.appendChild(authBlock);
     signOut.onclick = () => {
       signOut.style.display = "none";
       store.dispatch(actionAuthLogout());
-      signIn.style.display = "inline";
-      signUp.style.display = "inline";
-      accountLink.remove();
+      signinBtn.style.display = "inline";
+      signupBtn.style.display = "inline";
+      account.remove();
     };
   }
 });

+ 4 - 0
15/styles.css

@@ -24,3 +24,7 @@ button {
 #authBlock {
   display: flex;
 }
+
+#cartIcon {
+  color: white;
+}