Browse Source

HW17 done

Alyona Brytvina 2 years ago
parent
commit
b28fdcd5bd
3 changed files with 275 additions and 0 deletions
  1. 20 0
      HW17/index.html
  2. 246 0
      HW17/main.js
  3. 9 0
      HW17/style.css

+ 20 - 0
HW17/index.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>HW17</title>
+    <link rel="stylesheet" href="style.css">
+</head>
+<body>
+<header>КУДА Я ПОПАЛ?</header>
+<div id='mainContainer'>
+    <aside id='aside'>
+        Категории
+    </aside>
+    <main id='main'>
+        Контент
+    </main>
+</div>
+<script src="main.js"></script>
+</body>
+</html>

+ 246 - 0
HW17/main.js

@@ -0,0 +1,246 @@
+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}) {
+    //{
+    //    login: {status, payload, error}
+    //    catById: {status, payload, error}
+    //}
+    if (type === 'PROMISE') {
+        return {
+            ...state,
+            [name]: {status, payload, error}
+        };
+    }
+    return state;
+}
+
+const store = createStore(promiseReducer);
+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 actionPromise = (name, promise) =>
+
+    async dispatch => {
+        dispatch(actionPending(name)); // 1. {delay1000: {status: 'PENDING'}}
+        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: {
+                //заголовок content-type
+                'Content-Type': 'application/json',
+                ...(localStorage.authToken ? {'Authorization': 'Bearer ' + localStorage.authToken} :
+                    {})
+            },
+            //body с ключами query и variables
+            body: JSON.stringify({query, variables})
+        })
+            .then(res => res.json())
+            .then(data => {
+                if (data.errors && !data.data)
+                    throw new Error(JSON.stringify(data.errors));
+                return data.data[Object.keys(data.data)[0]];
+            });
+
+const backURL = 'http://shop-roles.asmer.fs.a-level.com.ua';
+
+const gql = getGQL(`${backURL}/graphql`);
+
+const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms));
+
+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 description images {
+                    url
+                }
+            } subCategories{
+      _id name image{
+        url _id text
+      }
+    }
+        }
+    }`, {q: JSON.stringify([{_id}])}));
+// console.log(store.dispatch(actionCatById()))
+
+
+const actionGoodById = (_id) =>  //добавить подкатегории
+    actionPromise('goodById', gql(`query goodById($q: String){
+     CategoryFind(query: $q){
+            _id name image{
+              url text _id
+            } subCategories{
+              _id name image{
+                url _id text
+              } subCategories{
+                _id name image{
+                  url text _id
+                }
+              }
+            }
+        }
+    } `, {q: JSON.stringify([{_id}])}));
+
+// store.dispatch(actionGoodById());
+
+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('/');
+    store.dispatch(actionGoodById(_id));
+
+    const routes = {
+
+        category() {
+            store.dispatch(actionCatById(_id));
+            console.log('ltjjj');
+        },
+        good() { //задиспатчить actionGoodById
+            store.dispatch(actionGoodById(_id));
+            console.log('ТОВАРОСТРАНИЦА');
+        },
+    };
+
+    if (route in routes) {
+        routes[route]();
+        console.log(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> `;
+
+        if (catById.payload.subCategories) {
+            for (let good of catById.payload.subCategories) {
+                const magic = `#/good/${good._id}`;
+                console.log(magic)
+                main.innerHTML += `<h2>${good.name}</h2>`;
+                main.innerHTML += `<a href="${magic}">${magic}</a>`;
+
+            }
+        } else {
+
+            for (const {_id, name, price, images} of catById.payload.goods) {
+                const card = document.createElement('div');
+
+                const link = document.createElement('a');
+                const magic = `#/good/${_id}`;
+
+                card.innerHTML = `<h2>${name}</h2>
+                              <img src="${backURL}/${images[0].url}" />
+                              <strong>${price}</strong>
+                              <a href="${magic}">${magic}</a>
+                                `;
+                aside.append(link);
+                main.append(card);
+            }
+        }
+    }
+})
+;
+
+store.subscribe(() => {
+    const {catById, goodById} = store.getState();
+    const [, route, idGood] = location.hash.split('/');
+    if (goodById?.payload && route === 'good'){
+        if (location.hash.indexOf(`#/good/${idGood}`) !== -1) {
+            console.log('нужная адресная строка');
+            main.innerHTML = '';
+            if(catById.payload?.subCategories){
+                let searchGood = catById.payload.subCategories.find(good => good._id === idGood);
+                const card = document.createElement('div');
+                console.log(goodById.payload[0].subCategories)
+                card.innerHTML = `<h2>${searchGood.name}</h2>`;
+                goodById.payload[0].subCategories.forEach(good => {
+                    card.innerHTML += `<h2>${good.name}</h2>`
+                    main.append(card);
+                })
+                main.append(card);
+            }else{
+                let searchGood = catById.payload?.goods.find(good => good._id === idGood);
+                const card = document.createElement('div');
+                card.innerHTML = `<h2>${searchGood.name}</h2>
+                      <img src="${backURL}/${searchGood.images[0].url}" />
+                       <strong>${searchGood.price}</strong>
+                       <div>${searchGood.description}</div>
+                 `;
+                main.append(card);
+            }
+        }
+    }
+
+
+});
+
+//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())))

+ 9 - 0
HW17/style.css

@@ -0,0 +1,9 @@
+#mainContainer {
+    display: flex;
+}
+#aside {
+    width: 30%;
+}
+#aside > a{
+    display: block;
+}