Browse Source

e-store add good page

serg155alternate 2 years ago
parent
commit
556e7409bf

+ 24 - 19
HW17 try-catch, redux-thunk/index.html

@@ -1,20 +1,25 @@
-<!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>HW17 Try catch
-    </title>
-    <link rel="stylesheet" href="style.css">
-</head>
-
-<body>
-    <div class="container">
-       
-    </div>
-    <script src="script.js"></script>
-</body>
-
+<!DOCTYPE HTML>
+<html>
+    <head>
+        <title>GQL</title>
+        <meta charset='utf8' />
+     <link rel="stylesheet" href="style.css">
+    </head>
+    <body>
+        <div class="container">
+            <header>
+                <div id='cartIcon'></div>
+            </header>
+            <div id='mainContainer'>
+                <aside id='aside'>
+                    Категории
+                </aside>
+                <main id='main'>
+                    Контент
+                </main>
+            </div>
+        </div>
+   
+        <script src='script.js'></script>
+    </body>
 </html>

+ 202 - 0
HW17 try-catch, redux-thunk/script.js

@@ -98,10 +98,212 @@
 // // //надо const newState
 
 
+function createStore(reducer){
+    let state       = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
+    let cbs         = []                     //массив подписчиков
+    
+    const getState  = () => state            //функция, возвращающая переменную из замыкания
+    const subscribe = cb => (cbs.push(cb),   //запоминаем подписчиков в массиве
+                             () => cbs = cbs.filter(c => c !== cb)) //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
+                             
+    const dispatch  = action => { 
+        if (typeof action === 'function'){ //если action - не объект, а функция
+            return action(dispatch, getState) //запускаем эту функцию и даем ей dispatch и getState для работы
+        }
+        const newState = reducer(state, action) //пробуем запустить редьюсер
+        if (newState !== state){ //проверяем, смог ли редьюсер обработать action
+            state = newState //если смог, то обновляем state 
+            for (let cb of cbs)  cb() //и запускаем подписчиков
+        }
+    }
+    
+    return {
+        getState, //добавление функции getState в результирующий объект
+        dispatch,
+        subscribe //добавление subscribe в объект
+    }
+}
+
+function promiseReducer(state={}, {type, name, status, payload, error}){
+    if (type === 'PROMISE'){
+        return {
+            ...state,
+            [name]:{status, payload, error}
+        }
+    }
+    return state
+}
+
+const store = createStore(promiseReducer) //не забудьте combineReducers если он у вас уже есть
+//const store = createStore(combineReducers({promise: promiseReducer, auth: authReducer}))
+store.subscribe(() => console.log(store.getState()))
+
+
+const actionPending             = name => ({type:'PROMISE',name, status: 'PENDING'})
+const actionFulfilled = (name,payload) => ({type:'PROMISE',name, status: 'FULFILLED', payload})
+const actionRejected  = (name,error)   => ({type:'PROMISE',name, status: 'REJECTED', error})
+const actionPromise = (name, promise) =>
+    async dispatch => {
+        dispatch(actionPending(name))
+        try {
+            let payload = await promise
+            dispatch(actionFulfilled(name, payload))
+            return payload
+        }
+        catch(error){
+            dispatch(actionRejected(name, error))
+        }
+    }
+
+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())
+        .then(data => {
+            if (data.data){
+                return Object.values(data.data)[0] 
+            } 
+            else throw new Error(JSON.stringify(data.errors))
+        })
+
+const backendURL = 'http://shop-roles.asmer.fs.a-level.com.ua'
+
+const gql = getGQL(backendURL + '/graphql')
+
+const actionRootCats = () => 
+    actionPromise('rootCats', gql(`query {
+        CategoryFind(query: "[{\\"parent\\":null}]"){
+            _id name
+        }
+    }`))
+
+const actionCatById = (_id) =>  //добавить подкатегории
+    actionPromise('catById', gql(`query catById($q: String){
+        CategoryFindOne(query: $q){
+            _id name goods {
+                _id name price images {
+                    url
+                }
+            }
+        }
+    }`, {q: JSON.stringify([{_id}])}))
+
+
+
+const actionGoodById = (_id) =>  
+    actionPromise('goodById', gql(`query findGoodById($q: String) {
+        GoodFindOne(query: $q) {
+          _id
+          name
+          description
+          price
+          images{
+              url
+            }
+        }
+      }`, {q: JSON.stringify([{_id}])}))
+
+
+store.dispatch(actionRootCats())
+
+store.subscribe(() => {
+    const {rootCats} = store.getState()
+    if (rootCats?.payload){
+        aside.innerHTML = ''
+        for (const {_id, name} of rootCats?.payload){
+            const link      = document.createElement('a')
+            link.href       = `#/category/${_id}`
+            link.innerText  = name
+            aside.append(link)
+        }
+    }
+})
+
+window.onhashchange = () => {
+    const [, route, _id] = location.hash.split('/')
+
+    const routes = {
+        category(){
+            store.dispatch(actionCatById(_id))
+        },
+        good(){ //задиспатчить actionGoodById
+            console.log('ТОВАРОСТРАНИЦА')
+            store.dispatch(actionGoodById(_id))
+        },
+        login(){
+            //отрисовка тут
+            //по кнопке - store.dispatch(actionFullLogin(login, password))
+        },
+        register(){
+            //отрисовка тут
+            //по кнопке - store.dispatch(actionFullRegister(login, password))
+        },
+    }
+    if (route in routes)
+        routes[route]()
+}
+window.onhashchange()
+
+
+store.subscribe(() => {
+    const {catById} = store.getState()
+    const [,route, _id] = location.hash.split('/')
+    if (catById?.payload && route === 'category'){
+        const {name} = catById.payload 
+        main.innerHTML = `<h1>${name}</h1> ТУТ ДОЛЖНЫ БЫТЬ ПОДКАТЕГОРИИ`
+        for (const {_id, name, price, images} of catById.payload.goods){
+            const card      = document.createElement('div');
+            card.innerHTML = `<h2>${name}</h2>
+                              <img src="${backendURL}/${images[0].url}" width="380"/>
+                              <div><strong>${price}грн</strong></div>
+                              <a href= '#/good/${_id}'> Купить </a>
+                                `
+            main.append(card)
+        }
+    }
+})
+
+store.subscribe(() => {
+    const {goodById} = store.getState()
+   const [,route, _id] = location.hash.split('/')
+   console.log(goodById)
+    
+     if (goodById?.payload && route === 'good'){
+        const {name, description, price, images} = goodById.payload 
+         main.innerHTML = ``
+         console.log(goodById.payload)
+            const card      = document.createElement('div');
+            card.innerHTML = `<h2>${name}</h2>  
+                               <div> <strong>${price}грн</strong></div>
+                               <img src="${backendURL}/${images[0].url}"/>
+                               <p>${description} </p>
+                              
+                            
+                                 `
+          main.append(card)
+    //     
+     }
+
+
+//     //ТУТ ДОЛЖНА БЫТЬ ПРОВЕРКА НА НАЛИЧИЕ goodById в редакс
+//     //и проверка на то, что сейчас в адресной строке адрес ВИДА #/good/АЙДИ
+//     //в таком случае очищаем main и рисуем информацию про товар с подробностями
+ })
+
 
+//store.dispatch(actionPromise('delay1000', delay(1000)))
+//store.dispatch(actionPromise('delay2000', delay(2000)))
+//store.dispatch(actionPromise('failedfetch', fetch('https://swapi.dev/api/people/1/')
+  //.then(res => res.json())))
 
 
 
 
 
+console.log(JSON.stringify([{_id:'5e1f396856d8f720513e6cae'}]))
 

+ 24 - 1
HW17 try-catch, redux-thunk/style.css

@@ -4,7 +4,30 @@
 }
 .container {
     position: relative;
-    max-width: 1140px;
+    max-width: 1240px;
     margin: 0 auto;
     padding: 50px;
 }
+
+#mainContainer {
+    display: flex;
+    background-color:cornsilk;
+}
+#aside {
+    padding: 10px;
+    width: 30%;
+    background-color: rgb(124, 124, 224);
+    margin-right: 35px;
+
+}
+#aside > a{
+    display: block;
+    border: 1px solid blue;
+    border-radius: 10px;
+    color: blanchedalmond;
+    text-decoration: none;
+    text-transform: uppercase;
+    margin-bottom: 10px;
+    
+}
+