Евгения Акиншина 2 lat temu
commit
f6da242e5e
6 zmienionych plików z 1287 dodań i 0 usunięć
  1. 1 0
      .gitignore
  2. 349 0
      css/normalize.css
  3. 187 0
      css/style.css
  4. BIN
      img/cart.png
  5. 23 0
      index.html
  6. 727 0
      js/main.js

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+.DS_Store

+ 349 - 0
css/normalize.css

@@ -0,0 +1,349 @@
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+
+/* Document
+   ========================================================================== */
+
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+
+html {
+  line-height: 1.15; /* 1 */
+  -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/* Sections
+   ========================================================================== */
+
+/**
+ * Remove the margin in all browsers.
+ */
+
+body {
+  margin: 0;
+}
+
+/**
+ * Render the `main` element consistently in IE.
+ */
+
+main {
+  display: block;
+}
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+
+h1 {
+  font-size: 2em;
+  margin: 0.67em 0;
+}
+
+/* Grouping content
+   ========================================================================== */
+
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+
+hr {
+  box-sizing: content-box; /* 1 */
+  height: 0; /* 1 */
+  overflow: visible; /* 2 */
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+pre {
+  font-family: monospace, monospace; /* 1 */
+  font-size: 1em; /* 2 */
+}
+
+/* Text-level semantics
+   ========================================================================== */
+
+/**
+ * Remove the gray background on active links in IE 10.
+ */
+
+a {
+  background-color: transparent;
+}
+
+/**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+
+abbr[title] {
+  border-bottom: none; /* 1 */
+  text-decoration: underline; /* 2 */
+  text-decoration: underline dotted; /* 2 */
+}
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+
+b,
+strong {
+  font-weight: bolder;
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+code,
+kbd,
+samp {
+  font-family: monospace, monospace; /* 1 */
+  font-size: 1em; /* 2 */
+}
+
+/**
+ * Add the correct font size in all browsers.
+ */
+
+small {
+  font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+
+sub,
+sup {
+  font-size: 75%;
+  line-height: 0;
+  position: relative;
+  vertical-align: baseline;
+}
+
+sub {
+  bottom: -0.25em;
+}
+
+sup {
+  top: -0.5em;
+}
+
+/* Embedded content
+   ========================================================================== */
+
+/**
+ * Remove the border on images inside links in IE 10.
+ */
+
+img {
+  border-style: none;
+}
+
+/* Forms
+   ========================================================================== */
+
+/**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+  font-family: inherit; /* 1 */
+  font-size: 100%; /* 1 */
+  line-height: 1.15; /* 1 */
+  margin: 0; /* 2 */
+}
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+
+button,
+input { /* 1 */
+  overflow: visible;
+}
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+
+button,
+select { /* 1 */
+  text-transform: none;
+}
+
+/**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+  -webkit-appearance: button;
+}
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+  border-style: none;
+  padding: 0;
+}
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+  outline: 1px dotted ButtonText;
+}
+
+/**
+ * Correct the padding in Firefox.
+ */
+
+fieldset {
+  padding: 0.35em 0.75em 0.625em;
+}
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ *    `fieldset` elements in all browsers.
+ */
+
+legend {
+  box-sizing: border-box; /* 1 */
+  color: inherit; /* 2 */
+  display: table; /* 1 */
+  max-width: 100%; /* 1 */
+  padding: 0; /* 3 */
+  white-space: normal; /* 1 */
+}
+
+/**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+
+progress {
+  vertical-align: baseline;
+}
+
+/**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+
+textarea {
+  overflow: auto;
+}
+
+/**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+
+[type="checkbox"],
+[type="radio"] {
+  box-sizing: border-box; /* 1 */
+  padding: 0; /* 2 */
+}
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+  height: auto;
+}
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+
+[type="search"] {
+  -webkit-appearance: textfield; /* 1 */
+  outline-offset: -2px; /* 2 */
+}
+
+/**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+
+[type="search"]::-webkit-search-decoration {
+  -webkit-appearance: none;
+}
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+
+::-webkit-file-upload-button {
+  -webkit-appearance: button; /* 1 */
+  font: inherit; /* 2 */
+}
+
+/* Interactive
+   ========================================================================== */
+
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+
+details {
+  display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+
+summary {
+  display: list-item;
+}
+
+/* Misc
+   ========================================================================== */
+
+/**
+ * Add the correct display in IE 10+.
+ */
+
+template {
+  display: none;
+}
+
+/**
+ * Add the correct display in IE 10.
+ */
+
+[hidden] {
+  display: none;
+}

+ 187 - 0
css/style.css

@@ -0,0 +1,187 @@
+#mainContainer {
+    display: flex;
+    text-align: center;
+    background-color: rgb(236, 235, 233);
+}
+
+#aside {
+    display: flex;
+    flex-direction: column;
+    background-color: #8d9de7;
+    padding: 20px;
+    width: 20%;
+    height: 100vh;
+    font-size: 24px;
+    font-family: 'Courier New', Courier, monospace;
+    border: 2px solid black;
+    margin-right: 20px;
+}
+
+#aside a {
+    color: rgb(53, 115, 185);
+    margin: 15px 0;
+    transition: all 0.5s;
+    color: rgb(73, 80, 165);
+}
+
+#aside a:hover {
+    border: 1px solid black;
+    text-align: center;
+    color: #454747;
+    background-color: rgb(230, 231, 209);
+}
+
+#main {
+    display: flex;
+    flex-wrap: wrap;
+    flex-direction: row;
+    width: 100%;
+    height: 100%;
+}
+
+#main section {
+    display: flex;
+    flex-wrap: wrap;
+    flex-direction: row;
+}
+
+#main div {
+    width: 70%;
+    height: 80%;
+    border: 2px solid rgb(110, 108, 108);
+    border-radius: 20px;
+    margin-bottom: 20px;
+    margin-left: 20px;
+    text-align: center;
+    padding: 20px;
+    margin-top: 80px;
+    background-color: rgb(199, 197, 194);
+    cursor: pointer;
+}
+
+#main div:hover {
+    background-color: rgb(215, 216, 213);
+}
+
+#main a {
+    width: 50%;
+    font-size: 25px;
+    text-decoration: none;
+    font-family: 'Courier New', Courier, monospace;
+    margin-top: 20px;
+    margin-bottom: 20px;
+    color: black;
+}
+
+#main p {
+    padding-left: 25px;
+    padding-right: 25px;
+    font-family: 'Courier New', Courier, monospace;
+}
+
+#main h5 {
+    font-size: 25px;
+    color: rgb(86, 93, 189);
+}
+
+#main span {
+    border: 2px solid rgb(110, 108, 108);
+    border-radius: 20px;
+    padding: 20px;
+    margin-top: 20px;
+    background-color: white;
+}
+
+#main img {
+    margin-top: 20px;
+    background-color: white;
+    border-radius: 20px;
+    width: 350px;
+}
+
+#main button {
+    cursor: pointer;
+    margin-left: 5px;
+    margin-right: 5px;
+    background-color: #4c66af;
+    border: none;
+    color: white;
+    padding: 7px 14px;
+    text-align: center;
+    text-decoration: none;
+    display: inline-block;
+    font-size: 16px;
+}
+
+#main button:hover {
+    background-color: #8ca4e2;
+}
+
+#cart {
+    position: relative;
+    color: #000;
+    margin-right: 20px;
+}
+
+#cart span {
+    position: absolute;
+    top: 0;
+    right: -5px;
+    border: 1px solid #000;
+    background-color: #fff;
+    border-radius: 10px;
+    padding: 0 5px;
+    font-size: 14px;
+    text-align: center;
+}
+
+#thecart {
+    display: flex;
+    align-items: center;
+    position: absolute;
+    right: 10px;
+    justify-content: end;
+    border: 3px solid rgb(77, 86, 170);
+    border-radius: 10px;
+    background-color: rgb(186, 186, 224);
+    padding: 5px;
+}
+
+#thecart a {
+    color: rgb(86, 93, 189);
+    font-size: 18px;
+    margin: 0 5px;
+    transition: all 0.3s;
+}
+
+#thecart a:hover {
+    color: rgb(65, 69, 141);
+}
+
+#thecart button:hover {
+    box-shadow: none;
+    color: rgb(160, 162, 204);
+}
+
+#thecart span {
+    font-weight: 600;
+    text-transform: uppercase;
+}
+
+#thecart p {
+    color: rgb(86, 93, 189);
+    padding-right: 10px;
+    text-transform: uppercase;
+}
+
+div h3{
+    color: rgb(86, 93, 189);
+    font-family: 'Courier New', Courier, monospace;
+    font-size: 22px;
+}
+
+#password {
+    margin-left: 16px;
+    margin-right: 5px;
+}
+

BIN
img/cart.png


+ 23 - 0
index.html

@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=\, initial-scale=1.0">
+    <link rel="stylesheet" href="css/normalize.css">
+    <link rel="stylesheet" href="css/style.css">
+    <title>shopGQL</title>
+</head>
+<body>
+    <div id='mainContainer'>
+        <aside id='aside'></aside>
+        <main id='main'></main>
+        <div id="thecart">
+            <a id="cart" href="#/cart">
+                <img src="img/cart.png" alt="img-cart" width="60">
+            </a>
+        </div>
+    </div>
+    <script src='js/main.js'></script>
+</body>
+</html>

+ 727 - 0
js/main.js

@@ -0,0 +1,727 @@
+// функция createStore
+
+function createStore(reducer) {
+    let state = reducer(undefined, {})
+    let cbs = []
+
+    function dispatch(action) {
+        if (typeof action === 'function') {
+            return action(dispatch)
+        }
+
+        const newState = reducer(state, action)
+        if (newState !== state) {
+            state = newState
+            for (let cb of cbs)
+                cb()
+        }
+    }
+    
+    return {
+        dispatch,
+        getState() {
+            return state
+        },
+        subscribe(cb) {
+            cbs.push(cb)
+            return () => cbs = cbs.filter(c => c !== cb)
+        }
+    }
+}
+
+// функция promiseReducer
+
+function promiseReducer(state = {}, { type, status, payload, error, name }) {
+    
+    if (type === 'PROMISE') {
+        return {
+            ...state,
+            [name]: { status, payload, error }
+        }
+    }
+
+    return state
+}
+
+// функция cartReducer
+
+function cartReducer(state = {}, { type, count = 1, _id, name }) {
+    if (type === "CART_ADD") {
+        return {
+            ...state,
+            [_id]: {
+                name: name,
+                count: state[_id] ? state[_id].count + count : count
+            }
+        }
+    }
+
+    if (type === "CART_CHANGE") {
+        return {
+            ...state,
+            [_id]: {
+                name: name,
+                count: count
+            }
+        }
+    }
+
+    if (type === 'CART_REMOVE') {
+        let { [_id]: count, ...copyWithout } = state
+        return copyWithout
+    }
+
+    if (type === 'CART_CLEAR') {
+        return {}
+    }
+
+    return state
+}
+
+let signatureToken = (token) => JSON.parse(atob(token.split(".")[1]))
+
+function authReducer(state, { type, token }) {
+
+    if (state === undefined) {
+        if (localStorage.authToken) {
+            type = "LOGIN"
+            token = localStorage.authToken
+        } else {
+            return {}
+        }
+    }
+
+    if (type === "LOGIN") {
+        console.log('LOGIN')
+        localStorage.authToken = token
+        return {token, payload: signatureToken(token)}
+    }
+
+    if (type === "LOGOUT") {
+        console.log('LOGOUT')
+        localStorage.removeItem("authToken")
+        return {}
+    }
+
+    return state
+}
+
+//  reducers 
+
+let reducers = {
+    promise: promiseReducer,
+    cart: cartReducer,
+    auth: authReducer
+}
+
+// функция combineReducers
+
+function combineReducers(reducers) {
+    function commonReducer(state = {}, action) {
+        let newState = {}
+
+        for (let key in reducers) {
+            let innerState = reducers[key](state[key], action)
+
+            innerState === state[key] ? newState[key] = state[key] : newState[key] = innerState
+        }
+
+        return newState
+    }
+
+    return commonReducer
+}
+
+const store = createStore(combineReducers(reducers))
+
+// запросы
+
+const getGQL = url =>
+    (query, variables = {}) => fetch(url, {
+        method: 'POST',
+        headers: {
+            "content-type": "application/json",
+            ...(localStorage.authToken ? { Authorization: "Bearer " + localStorage.authToken } : {})
+        },
+        body: JSON.stringify({ query, variables })
+    }).then(res => res.json())
+
+let shopGQL = getGQL("http://shop-roles.asmer.fs.a-level.com.ua/graphql")
+
+let categoryById = async (id) => {
+    let query = `query fndcategory($id: String) {
+        CategoryFind(query: $id){
+          name goods{
+              _id name price images {
+                  url
+              }
+          }
+        }
+      }`
+
+    let variables = {
+        "id": JSON.stringify([{ "_id": id }])
+    }
+
+    let res = await shopGQL(query, variables)
+    console.log(res)
+    return res
+}
+
+let goodById = async (id) => {
+    let query = `query fndgood($id: String) {
+        GoodFind(query: $id){
+          name description price images {
+              url
+          }
+        }
+      }`
+
+    let variables = {
+        "id": JSON.stringify([{ "_id": id }])
+    }
+
+    let res = await shopGQL(query, variables)
+    return res
+}
+
+const actionRootCategories = () =>
+    actionPromise('rootCategories', shopGQL(`query cats($query:String) {
+        CategoryFind(query:$query) {
+            _id name 
+        }
+    }`, {query: JSON.stringify([{parent:null}])}))
+
+//регистрация
+
+let reg = async(login, password) => {
+    let query = `mutation reg($login:String, $password:String) {
+        UserUpsert(user:{
+            login: $login,
+            password: $password
+
+        }){
+           _id
+        }
+    }`
+
+    let variables = {"login":login, "password":password}
+
+    let res = await shopGQL(query, variables)
+    return res
+}
+
+//логин
+
+let log = async(login, password) => {
+    let query = `query login($login:String, $password:String) {
+        login(login: $login, password: $password)
+    }`
+
+    let variables = {"login":login, "password":password}
+
+    let token = await shopGQL(query, variables)
+    return token.data.login
+}
+
+//отправка заказа
+
+let newOrder = async(obj) => {
+    let option = Object.entries(obj)
+    let orderGoods = []
+  
+    for (let key of option) {
+        let i = {
+            "count": key[1],
+            "good": {"_id": key[0]}
+        }
+        orderGoods.push(i)
+    }
+  
+    let query = `mutation newOrder($order:OrderInput) {
+       OrderUpsert(order:$order) {
+         _id 
+       }
+     }`
+  
+    let variables = {
+        "order": {"orderGoods": orderGoods}
+    }
+  
+    let res = await shopGQL(query, variables)
+    console.log(res)
+    return res
+}
+
+// actions
+
+const actionPending = name => ({ type: 'PROMISE', status: 'PENDING', name })
+const actionResolved = (name, payload) => ({ type: 'PROMISE', status: 'RESOLVED', name, payload })
+const actionRejected = (name, error) => ({ type: 'PROMISE', status: 'REJECTED', name, error })
+
+const actionPromise = (name, promise) =>
+    async dispatch => {
+        dispatch(actionPending(name))
+        try {
+            let payload = await promise
+            dispatch(actionResolved(name, payload))
+            return payload
+        }
+        catch (error) {
+            dispatch(actionRejected(name, error))
+        }
+    }
+
+const actionCategoryById = id => actionPromise('catById', categoryById(id))
+const actionGoodById = id => actionPromise('goodById', goodById(id))
+const actionBuyGood = (obj) => actionPromise('newOrder', newOrder(obj))
+
+const actionCartAdd = (n, id, name) => ({ type: "CART_ADD", count: n, _id: id, name })
+const actionCartChange = (n, id, name) => ({ type: "CART_CHANGE", count: n, _id: id, name })
+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("log", log(login, password))
+const actionReg = (login, password) => actionPromise("reg", reg(login, password))
+
+const actionFullLogin = (login, password) => async(dispatch) => {
+    let result = await dispatch(actionLogin(login, password))
+        if (result !== null){
+            dispatch(actionAuthLogin(result))
+        } else {
+            alert ('Такой пользователь не существует!')
+        }
+    }
+
+const actionFullRegister = (login, password) => async(dispatch) => {
+    let result = await dispatch(actionReg(login, password))
+    if(result.data.UserUpsert !==null) {
+        dispatch(actionFullLogin(login, password))
+    } else {
+        alert('Такой пользователь уже существует!')
+    }
+}
+
+store.dispatch(actionRootCategories())
+
+window.onhashchange = () => {
+    let { 1: route, 2: id } = location.hash.split('/')
+    if (route === 'categories') {
+        store.dispatch(actionCategoryById(id))
+    }
+
+    if (route === 'good') {
+        store.dispatch(actionGoodById(id))
+    }
+
+    if (route === 'cart') {
+        cartDraw(store.getState().cart, main)
+    }
+
+    if (route === "login") {
+        drawLog(main)
+    }
+
+    if (route === "registration") {
+        drawReg(main)
+    }
+}
+
+function drawMainMenu() {
+    let cats = store.getState().promise.rootCategories.payload
+    if (cats) {
+        aside.innerText = ''
+        for (let { _id, name } of cats.data.CategoryFind) {
+            let catA = document.createElement('a')
+            catA.href = `#/categories/${_id}`
+            catA.innerText = name
+            aside.append(catA)
+        }
+    }
+}
+
+let goodDraw = (obj, parent, _id) => {
+    let box = document.createElement("div")
+    let goodName = document.createElement("h3")
+    let goodImg = document.createElement("img")
+    let description = document.createElement("p")
+    let price = document.createElement("p")
+    let count = document.createElement("input")
+    let goodBtnBox = document.createElement("p")
+    let btn1 = document.createElement("button")
+    let btn2 = document.createElement("button")
+    price.textContent = "Цена: " + obj.price + "грн"
+    goodImg.src = "http://shop-roles.asmer.fs.a-level.com.ua/" + obj.images[0].url
+    goodName.textContent = obj.name
+    description.textContent = "Описание: " + obj.description
+    count.type = "number"
+    count.min = 1
+    count.value = 1
+    btn1.textContent = "Купить"
+    btn2.textContent = "В корзину"
+    goodBtnBox.append(count, btn2, btn1)
+
+    let order = {
+        [_id]: +count.value
+    }
+
+    count.oninput = () => order[_id] = +count.value
+
+    btn1.onclick = () => {
+        store.dispatch(actionBuyGood(order))
+    }
+    btn2.onclick = () => {
+        store.dispatch(actionCartAdd(+count.value, _id, obj.name))
+    }
+
+    box.append(goodImg, goodName, description, price, goodBtnBox)
+    parent.append(box)
+}
+
+let cardDraw = (obj, parent) => {
+    let box = document.createElement("div")
+    let img = document.createElement("img")
+    img.style.width ='400px'
+    img.src = "http://shop-roles.asmer.fs.a-level.com.ua/" +  obj.images[0].url
+    let price = document.createElement("p")
+    let nameGood = document.createElement("h5")
+    nameGood.textContent = obj.name
+    price.innerText = "Цена:" +  obj.price + "грн"
+    box.append(img, nameGood, price,)
+    let a = document.createElement("a")
+    a.href = "#/good/" + obj._id
+    a.append(box)
+    parent.append(a)
+}
+
+let cartDraw = (obj, parent) => {
+    while (parent.lastChild) {
+        parent.lastChild.remove()
+    }
+    let cartName = document.createElement("h3")
+    cartName.textContent = "Ваши заказы:"
+    parent.append(cartName)
+
+    let order = {}
+
+    for (let key in obj) {
+        order[key] = obj[key].count
+        let cartItem = document.createElement("p")
+        let name = document.createElement("p")
+        let count = document.createElement("input")
+        let btnDelItem = document.createElement("button")
+        btnDelItem .textContent="Удалить"
+        let btnPlus = document.createElement("button")
+        btnPlus.textContent="+"
+        let btnMinus = document.createElement("button")
+        btnMinus.textContent="-"
+        count.min = 1
+        count.value = obj[key].count
+        name.textContent = obj[key].name
+        cartItem.append(btnMinus, count, btnPlus, name, btnDelItem)
+        parent.append(cartItem)
+
+        if (+count.value === 1) {
+            btnMinus.disabled = "true"
+        }
+
+        count.oninput = () => {
+            if (+count.value >= 1) {
+                store.dispatch(actionCartChange(+count.value, key, obj[key].name))
+            }
+        }
+
+        btnPlus.onclick = () => {
+            store.dispatch(actionCartChange(+count.value + 1, key, obj[key].name))
+        }
+
+        btnMinus.onclick = () => {
+            store.dispatch(actionCartChange(+count.value - 1, key, obj[key].name))
+        }
+
+        btnDelItem.onclick = () => {
+            store.dispatch(actionCartRemove(key))
+        }
+    }
+
+    let btnBox = document.createElement("p")
+    let btnOrder = document.createElement("button")
+    let btnClear = document.createElement("button")
+    btnClear.textContent = "ОЧИСТИТЬ КОРЗИНУ"
+    btnOrder.textContent = "КУПИТЬ"
+
+    btnOrder.onclick = () => {
+        store.dispatch(actionBuyGood(order))
+        store.dispatch(actionCartClear())
+    }
+
+    btnClear.onclick = () => {
+        store.dispatch(actionCartClear())
+    }
+
+    btnBox.append(btnOrder, btnClear)
+    parent.append(btnBox)
+}
+
+let statusCart = () => {
+    if (cart.children.length === 1) {
+        let span = document.createElement("span")
+        cart.append(span)
+    }
+
+    let sum = 0
+    let cartState = store.getState().cart
+    for (let key in cartState) {
+        sum += cartState[key].count
+    }
+
+    cart.lastChild.textContent = sum
+}
+
+let checkUser = (parent = thecart) => {
+    if (parent.children.length > 1) {
+        parent.lastChild.remove()
+    }
+
+    let status = store.getState().auth
+    let box = document.createElement("div")
+    let userName = document.createElement("p")
+
+    box.append(userName)
+    parent.append(box)
+
+    if (status.payload) {
+        let btn = document.createElement("button")
+        userName.textContent = status.payload.sub.login
+        btn.textContent = "Выход"
+        btn.style.cursor="pointer"
+        btn.style.color="rgb(86, 93, 189)"
+        btn.onclick = () => {
+            store.dispatch(actionAuthLogout())
+        }
+        box.append(btn)
+    } else {
+        let btn = document.createElement("a")
+        let btnREG = document.createElement("a")
+        btn.textContent = "Вход"
+        btnREG.textContent = "Регистрация"
+        btn.href = "#/login"
+        btnREG.href = "#/registration"
+
+        box.append(btn, btnREG)
+    }
+}
+
+function Reg(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")
+    btn.style.marginRight="10px"
+    let form = document.createElement("span")
+    let box = document.createElement("p")
+    box.append(passwordInput, checkbox)
+    loginInput.id = "login"
+    loginInput.placeholder = "логин"
+    loginInput.style.textAlign="center"
+    passwordInput.id = "password"
+    passwordInput.placeholder = "пароль"
+    passwordInput.style.textAlign="center"
+    btn.id = "btn"
+    checkbox.type = "checkbox"
+    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.style.textAlign="center"
+                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 drawLog = (parent) => {
+    while (parent.lastChild) {
+        parent.lastChild.remove()
+    }
+
+    if (store.getState().auth.payload) {
+        let h2 = document.createElement("h2")
+        h2.textContent = "Вход выполнен успешно!"
+        h2.style.color = "rgb(86, 93, 189)"
+        parent.append(h2)
+    } else {
+        new Reg(parent)
+        btn.onclick = () => {
+            store.dispatch(actionFullLogin(login.value, password.value))
+        }
+    }
+}
+
+let drawReg = (parent) => {
+    while (parent.lastChild) {
+        parent.lastChild.remove()
+    }
+
+    if (store.getState().auth.payload) {
+        let h2 = document.createElement("h2")
+        h2.textContent = "Регистрация прошла успешно!"
+        h2.style.color = "rgb(86, 93, 189)"
+        parent.append(h2)
+    } else {
+        new Reg(parent, "reg")
+
+        btn.onclick = () => {
+            store.dispatch(actionFullRegister(login.value, password.value))
+        }
+    }
+}
+
+//subscribers
+
+store.subscribe(drawMainMenu)
+store.subscribe(() => console.log(store.getState()))
+store.subscribe(statusCart)
+store.subscribe(checkUser)
+
+store.subscribe(() => {
+    const { 1: route, 2: id } = location.hash.split('/')
+    if (route === 'categories') {
+        const catById = store.getState().promise.catById?.payload
+        if (catById) {
+            while (main.lastChild) {
+                main.lastChild.remove()
+            }
+
+            aside.innerText = ''
+            let cats = document.createElement('p')
+            cats.innerText = "Вы в категории ==>" + " " + catById.data.CategoryFind[0].name
+            mainMenu = document.createElement('a')
+            mainMenu.style.cursor = 'pointer'
+            mainMenu.innerText = "<== Назад в главное меню"
+            mainMenu.onclick = () => {
+                main.innerText = ''
+                drawMainMenu()
+            }
+            let cards = document.createElement("section")
+
+            for (let key of catById.data.CategoryFind[0].goods) {
+                cardDraw(key, cards)
+            }
+            main.append(cards)
+            aside.append(mainMenu, cats)
+        }
+    }
+    if (route === 'good') {
+        const goodById = store.getState().promise.goodById?.payload
+        const catById = store.getState().promise.catById?.payload
+        if (goodById) {
+            while (main.lastChild) {
+                main.lastChild.remove()
+            }
+
+            aside.innerText = ''
+            let cats = document.createElement('p')
+            cats.innerText = "Вы в категории ==>" + " " + catById.data.CategoryFind[0].name
+            mainMenu.style.cursor = 'pointer'
+            mainMenu.onclick = () => {
+                main.innerText = ''
+                drawMainMenu()
+            }
+            aside.append(cats, mainMenu)
+
+            goodDraw(goodById.data.GoodFind[0], main, id)
+        }
+    }
+    if (route === 'cart') {
+        cartDraw(store.getState().cart, main)
+    }
+    if (route === 'login') {
+        drawLog(main)
+    }
+    if (route === "registration") {
+        drawReg(main)
+    }
+})