Kaynağa Gözat

done without cart and auth

Screamo Violence 3 yıl önce
işleme
12d67a0493
1 değiştirilmiş dosya ile 568 ekleme ve 0 silme
  1. 568 0
      index.html

+ 568 - 0
index.html

@@ -0,0 +1,568 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Magaz</title>
+
+    <style>
+        * *,
+        *::before,
+        *::after {
+            box-sizing: border-box;
+            margin: 0;
+            padding: 0;
+        }
+
+        #page-wrapper {
+            display: flex;
+            flex-direction: column;
+            min-height: 100vh;
+            margin: 0 auto;
+            max-width: 1170px;
+            width: 100%;
+        }
+
+        #mainContainer {
+            display: flex;
+            flex-grow: 1;
+            margin: 20px 0;
+
+        }
+
+        #header {
+            height: 50px;
+            background-color: #FF5319;
+            border: 1px solid gray;
+            padding: 10px 5px;
+            font-size: 26px;
+            display: flex;
+            justify-content: space-between;
+        }
+
+        #userAuth li {
+            list-style-type: none;
+            display: inline-block;
+            font-size: 18px;
+        }
+
+        a {
+            text-decoration: none;
+        }
+
+        #aside {
+            min-width: 25%;
+            font-size: 20px;
+            padding: 0 20px 0px 0;
+        }
+
+        #aside>a {
+            display: block;
+            color: black;
+        }
+
+        #aside>a:hover {
+            color: tomato;
+            font-size: 24px;
+        }
+
+        #main {
+            display: flex;
+            flex-wrap: wrap;
+            width: 100%;
+        }
+
+        #footer {
+            text-align: center;
+            background-color: #FF5319;
+            border: 1px solid gray;
+            height: 40px;
+        }
+
+        #cartImg {
+            height: 30px;
+            width: 30px;
+        }
+
+        #nav {
+            display: flex;
+
+        }
+    </style>
+
+</head>
+
+<body>
+
+    <div id="page-wrapper">
+        <header id="header">
+            <div id="logo">Larek</div>
+
+            <nav id="nav">
+                <ul id="userAuth">
+                    <li>войти</li>
+                    <li>регистрация</li>
+                </ul>
+                <div id="cart">
+                    <a id="cartLink"><img id="cartImg"
+                            src="https://i.pinimg.com/originals/15/4f/df/154fdf2f2759676a96e9aed653082276.png"
+                            alt=""></a>
+                </div>
+            </nav>
+        </header>
+
+        <div id='mainContainer'>
+            <aside id='aside'>
+                Категории
+            </aside>
+            <main id='main'>
+                Контент
+            </main>
+        </div>
+
+        <footer id="footer">КУДА Я ПОПАЛ?2</footer>
+    </div>
+
+    <script>
+        // debugger;
+        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 (state !== newState) {
+                    state = newState
+                    cbs.forEach(cb => cb())
+                }
+            }
+            return {
+                dispatch,
+                subscribe(cb) {
+                    cbs.push(cb)
+                    return () => cbs = cbs.filter(c => c !== cb)
+                },
+                getState() {
+                    return state
+                }
+            }
+        }
+
+        // function reducer(state = {}, { type, status, payload, error, name }) {
+        //     if (type === 'PROMISE') {
+        //         return {
+        //             ...state,
+        //             [name]: { status, payload, error }
+        //         }
+        //     }
+        //     return state
+        // }
+
+
+        /////
+        function promiseReducer(state = {}, { type, status, payload, error, name }) {
+            if (type === 'PROMISE') {
+                return {
+                    ...state,
+                    [name]: { status, payload, error }
+                }
+            }
+            return state
+        }
+
+        function cardReducer(state = {}, { type, count = 1, good }) {
+            //придумать типы CART_ADD, CART_CLEAR, CART_SET, CART_DELETE
+            //{ _id1: {count: 2, good: {....}},
+            //  _id2: 10,}
+            //
+            if (type === 'CART_ADD') { ///где то тут проеб
+                console.log("+1")
+                const _id = good._id
+                return {
+                    ...state,
+                    [_id]: { count: (state[_id]?.count || 0) + count, good }
+                }
+            }
+            if (type === 'CART_DELETE') {
+                console.log("-1")
+                const _id = good._id
+                return {
+                    ...state,
+                    [_id]: { count: (state[_id]?.count || 0) - count, good }
+                }
+            }
+            return state
+        }
+
+        const actionCartAdd = (good, count = 1) => ({ type: 'CART_ADD', count, good })
+        // const actionCartDelete = (good, count = 1) => ({ type: 'CART_DELETE', count, good })
+
+        //под товаром сделать кнопку "купить"
+        // buy.onclick = () => {
+        //     //debugger;
+        //     store.dispatch(actionCartAdd(good))
+        // }
+
+        //отрисовка количество где-то в хидере (на всех страницах)
+        // store.subscribe(() => {
+        //     const cart = store.getState().cart
+        // смочь в цикл/reduce по подсчету суммы количеств товаров и вывести куда-то в дом
+        //(заготовка под кошик с количеством)
+        // })
+
+        function authReducer(state = { name: "Токен и все такое" }, action) { // { type, token }
+            if (state === undefined) {
+                //добавить в action token из localStorage, и проимитировать LOGIN (action.type = 'LOGIN')
+                return {}
+            }
+            if (action.type === 'LOGIN') {
+                console.log('ЛОГИН', action)
+                //+localStorage
+                //jwt_decode: 
+                //достать среднюю часть из токена (между точками)
+                //atob
+                //JSON.parse
+                //            return {token: action.token, payload: jwt_decode(action.jwt)}
+            }
+            if (action.type === 'LOGOUT') {
+                console.log('ЛОГАУТ')
+                //-localStorage
+                //removeItem или clear
+                //вернуть пустой объект
+                return {}
+            }
+            return state
+        }
+
+        const reducers = {
+            promise: promiseReducer,
+            cart: cardReducer,
+            auth: authReducer
+        }
+
+        const combineReducers = reducers => {
+            return (state = {}, action) => {
+                const newState = {}
+                for (const [name, reducer] of Object.entries(reducers)) {
+                    // console.log(name, reducer)
+                    const newSubState = reducer(state[name], action)
+                    if (newSubState !== state[name]) {
+                        newState[name] = newSubState
+                    }
+                }
+                if (Object.keys(newState).length === 0) {
+                    return state
+                }
+
+                // {
+                //   ...
+                //     promise: state.promise,
+                //         cart: state.cart,
+                //             auth: state.auth,
+                //                 promise: newState.promise
+                // }
+
+                return { ...state, ...newState }
+            }
+        }
+
+        const store = createStore(combineReducers(reducers))
+        ////
+
+
+        //const store = createStore(reducer)
+        const unsubscribe1 = store.subscribe(() => console.log(store.getState()))
+
+        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 delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms))
+
+        //store.dispatch(actionPending('delay1000')) 
+        //delay(1000).then(payload => store.dispatch(actionResolved('delay1000', payload)),  
+        //error => store.dispatch(actionRejected('delay1000', 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 getGQL = url =>
+            (query, variables = {}) => fetch(url, {
+                method: 'POST',
+                headers: {
+                    //  Accept: "application/json", 
+                    "Content-Type": "application/json"
+                    //якщо в localStorage.authToken шото есть, то наверное это надо отправить с заголовком Authorization
+                },
+                body: JSON.stringify({ query, variables })
+            }).then(res => res.json())
+
+        let shopGQL = getGQL('http://shop-roles.asmer.fs.a-level.com.ua/graphql')
+
+        const actionRootCategories = () =>
+            actionPromise('rootCategories', shopGQL(` 
+            query cats($query:String){ 
+              CategoryFind(query:$query){ 
+                _id name  
+              } 
+            } 
+        `, { query: JSON.stringify([{ parent: null }]) }))
+
+        const actionCategoryById = (_id) =>
+            actionPromise('catById', shopGQL(`query catById($query:String){ 
+                                          CategoryFindOne(query:$query){ 
+                                            _id name goods{ 
+                                              _id name price description images{ 
+                                                url 
+                                              } 
+                                            } 
+                                          } 
+                                        }`, { query: JSON.stringify([{ _id }]) }))
+
+        const actionGoodById = (_id) =>
+            actionPromise('goodById', shopGQL(`query goodById($query:String){ 
+                                          GoodFindOne(query:$query){ 
+                                            _id name price description images {
+                                                url
+                                            }
+                                          } 
+                                        }`, { query: JSON.stringify([{ _id }]) }))
+
+        const actionGetToken = (login, password) =>
+            actionPromise('getToken', shopGQL(`query login($login:String, $password:String){
+                                            login(login: $login, password: $password)
+                                        }`, { login, password }))
+
+
+        // const actionGetOrders = () =>
+        //     actionPromise('orders', shopGQL(`query orders{
+        //                                     OrderFind(query:"[{}]"){
+        //                                         _id total orderGoods{
+        //                                         count good{
+        //                                             name
+        //                                         }
+        //                                         }
+        //                                     }
+        //                                     }`))
+
+        const actionAuthLogin = token => ({ type: 'LOGIN', token })
+
+        const actionFullLogin = (login, password) =>
+            async dispatch => {
+                let payload = await dispatch(actionGetToken(login, password))
+                if (payload.data.login) {
+                    dispatch(actionAuthLogin(payload.data.login))
+                }
+            }
+
+
+        //НАПИЛИТЬ actionFullRegister:
+        //  - actionRegister, который actionPromise
+        //  - если удачно, делаете сразу же actionFullLogin
+
+        store.dispatch(actionRootCategories())
+        store.dispatch(actionFullLogin('tst123', '123123'))
+
+        function drawCart() {
+            //цикл по отрисовке с картинками и редактирование количества/удалением товара
+            //
+
+            const cart = store.getState().cart
+
+            // if (cart) {
+            //     main.innerText = ''
+            //     for (let {})
+            // }
+            // main.innerHTML = `<pre>${JSON.stringify(cart, null, 4)}</pre>`
+            console.log("kart", cart)
+
+        }
+
+        function loadAnimationFunc() {
+            main.innerHTML = ""
+            let loadAnimationContainer = document.createElement('div')
+            loadAnimationContainer.setAttribute('style', "width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;")
+            main.append(loadAnimationContainer)
+
+            let loadAnimation = document.createElement('img')
+            loadAnimation.src = "https://image.flaticon.com/icons/png/512/2492/2492765.png"
+            loadAnimation.setAttribute("style", "width: 50px; height: 50px; animation: load 1s linear infinite;")
+            loadAnimation.animate([{ transform: 'rotate(360deg)' }], { duration: 1000, iterations: Infinity })
+            loadAnimationContainer.append(loadAnimation)
+        }
+
+        window.onhashchange = () => {
+            let { 1: route, 2: id } = location.hash.split('/')
+            if (route === 'categories') {
+                loadAnimationFunc()
+                store.dispatch(actionCategoryById(id))
+            }
+            if (route === 'good') {
+                loadAnimationFunc()
+                store.dispatch(actionGoodById(id))
+            }
+            if (route === 'login') {
+                // нарисовать форму логина, которая по OK делает 
+                // store.dispatch(actionFullLogin(login, password)) 
+            }
+            if (route === 'register') {
+                // нарисовать форму регистрации, которая по OK делает 
+                // store.dispatch(actionFullRegister(login, password)) 
+            }
+            if (route === 'cart') {
+                loadAnimationFunc()
+                // store.dispatch(actionGetOrders())
+                console.log("страница корзины")
+                drawCart()
+
+                //#/cart/ 
+                //     //нарисовать корзину с кнопочками добавления/удаления товаров
+                //     main.innerHTML = ""
+                //     //const cart = store.getState().cart
+                //     //смочь в цикл / reduce по подсчету суммы количеств товаров и вывести куда - то в дом
+                //     //(заготовка под кошик с количеством)
+            }
+        }
+
+        function drawMainMenu() {
+            //debugger;
+            let cats = store.getState().promise.rootCategories.payload
+            if (cats) { //Каждый раз дорисовываются в body 
+                aside.innerText = ''
+                for (let { _id, name } of cats.data.CategoryFind) {
+                    let catA = document.createElement('a')
+                    catA.href = `#/categories/${_id}`
+                    catA.innerText = name
+
+                    console.log("cart")
+                    cartLink.href = `#/cart/`
+
+                    aside.append(catA)
+                }
+            }
+        }
+
+        store.subscribe(drawMainMenu)
+
+        store.subscribe(() => {
+            //debugger;
+            const { 1: route, 2: id } = location.hash.split('/')
+            if (route === 'categories') {
+                const catById = store.getState().promise.catById?.payload
+                if (catById) {
+                    main.innerText = ""
+                    // Вывести категорию(название)
+                    let h1 = document.createElement('h1')
+                    h1.setAttribute('style', 'width: 100%;')
+                    h1.innerText = catById.data.CategoryFindOne.name
+                    main.append(h1)
+                    // Вывести циклом товары со ссылками вида # / good / АЙДИШНИК
+                    for (let { _id, name, description, price, images } of catById.data.CategoryFindOne.goods) { //тута
+
+                        let divGoodA = document.createElement('div')
+                        divGoodA.setAttribute('style', "margin: 0 10px 10px 0; padding: 20px; width: 400px; border: 2px solid gray; display: flex; flex-direction: column; align-content: stretch ")
+                        divGoodA.onmousemove = () => divGoodA.style.borderColor = "#FF7373"
+                        divGoodA.onmouseout = () => divGoodA.style.borderColor = "gray"
+                        //background - color: #FF5319;
+                        let goodImg = document.createElement('img')
+                        goodImg.src = `http://shop-roles.asmer.fs.a-level.com.ua/${images[0].url}`
+
+                        let goodLink = document.createElement('a')
+                        goodLink.setAttribute('style', "flex: 1 1 auto; text-align: center; font-size: 22px")
+                        goodLink.href = `#/good/${_id}`
+                        goodLink.innerHTML = name
+
+                        let goodPrice = document.createElement('div')
+                        goodPrice.setAttribute('style', "font-size: 20px; font-weight: bold; text-align: center;")
+                        goodPrice.innerText = `Цена: ${price} грн`
+
+                        let goodButton = document.createElement('button')
+                        goodButton.setAttribute('style', "height: 50px;  font-weight: bold; margin: 10px 0 0 0; border-radius: 30px; background-color: white;")
+                        goodButton.innerText = "Купить"
+                        goodButton.onclick = () => window.location.href = `#/good/${_id}`
+                        goodButton.onmousemove = () => goodButton.style.backgroundColor = "#FF5319"
+                        goodButton.onmouseout = () => goodButton.style.backgroundColor = "white"
+
+                        divGoodA.append(goodImg)
+                        divGoodA.append(goodLink)
+                        //divGoodA.append(goodDescription)
+                        divGoodA.append(goodPrice)
+                        divGoodA.append(goodButton)
+                        main.append(divGoodA)
+                    }
+                    // main.innerHTML = `<pre>${JSON.stringify(catById, null, 4)}</pre>`
+                }
+            }
+            if (route === 'cart') {
+                // нарисовать корзину с кнопочками добавления/удаления товаров
+                //
+                //const cart = store.getState().cart
+                drawCart()
+            }
+        })
+
+        store.subscribe(() => {
+            // debugger;
+            //когда появится actionGoodById и ссылки на товары это заработает 
+            const { 1: route, 2: id } = location.hash.split('/')
+            if (route === 'good') {
+                const goodById = store.getState().promise.goodById?.payload
+                if (goodById) {
+                    let main = document.getElementById('main')
+                    main.innerHTML = ""
+
+                    let divGoodB = document.createElement('div')
+                    divGoodB.setAttribute('style', "margin: 0 10px 10px 25px; padding: 20px; display: flex; flex-direction: column;")
+
+                    let goodImg1 = document.createElement('img')
+                    goodImg1.src = `http://shop-roles.asmer.fs.a-level.com.ua/${goodById.data.GoodFindOne.images[0].url}`
+
+                    let goodLink1 = document.createElement('h1')
+                    goodLink1.setAttribute('style', "text-align: center; font-size: 22px")
+                    goodLink1.innerHTML = goodById.data.GoodFindOne.name
+
+                    let goodDescription1 = document.createElement('div')
+                    goodDescription1.setAttribute('style', "margin: 20px; ")
+                    goodDescription1.innerText = goodById.data.GoodFindOne.description
+
+                    let goodPrice1 = document.createElement('h1')
+                    goodPrice1.setAttribute('style', "font-size: 20px; font-weight: bold; text-align: center;")
+                    goodPrice1.innerText = `Цена: ${goodById.data.GoodFindOne.price} грн`
+
+                    let goodButton1 = document.createElement('button')
+                    goodButton1.setAttribute('style', "height: 50px;  font-weight: bold; margin: 10px 0 0 0; border-radius: 30px; background-color: white;")
+                    goodButton1.innerText = "Купить"
+                    goodButton1.onmousemove = () => goodButton1.style.backgroundColor = "#FF5319"
+                    goodButton1.onmouseout = () => goodButton1.style.backgroundColor = "white"
+                    goodButton1.onclick = () => { store.dispatch(actionCartAdd(goodById.data.GoodFindOne)) }
+
+                    divGoodB.append(goodImg1)
+                    divGoodB.append(goodLink1)
+                    divGoodB.append(goodDescription1)
+                    divGoodB.append(goodPrice1)
+                    divGoodB.append(goodButton1)
+                    main.append(divGoodB)
+                    // вывести в main страницу товаров 
+                }
+            }
+        })
+
+    </script>
+
+</body>
+
+</html>