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 promiseReducer(state = {}, { type, status, payload, error, name }) { if (type === 'PROMISE') { return { ...state, [name]: { status, payload, error } } } return state } const store = createStore(promiseReducer) 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)) 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 => { return (query, variables) => { return 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 qVariables = { "id": JSON.stringify([{ "_id": id }]) } let res = await shopGQL(query, qVariables) console.log(res) return res } let goodById = async (id) => { let query = `query fndgood($id: String) { GoodFind(query: $id){ name description price images { url } } }` let qVariables = { "id": JSON.stringify([{ "_id": id }]) } let res = await shopGQL(query, qVariables) return res } 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 sndOrder($order: OrderInput) { OrderUpsert(order: $order) { _id createdAt total } }` let qVariables = { "order": { "orderGoods": orderGoods } } let res = await shopGQL(query, qVariables) console.log(res) return res } const actionRootCategories = () => actionPromise('rootCategories', shopGQL(` query cats($query:String){ CategoryFind(query:$query){ _id name } } `, { query: JSON.stringify([{ parent: null }]) })) const actionCategoryById = id => actionPromise('catById', categoryById(id)) const actionGoodById = id => actionPromise('goodById', goodById(id)) const actionBuyGood = (obj) => actionPromise('newOrder', newOrder(obj)) // const actionGoodOrder = (obj) => actionPromise('newOrderGood', newOrderGood(obj)) 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)) } } function drawMainMenu() { let cats = store.getState().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 aside.append(catA) } } } store.subscribe(drawMainMenu) store.subscribe(() => { const { 1: route, 2: id } = location.hash.split('/') if (route === 'categories') { const catById = store.getState().catById?.payload if (catById) { while (main.lastChild) { main.lastChild.remove() } let categoryName = document.createElement("h2") let cards = document.createElement("div") cards.className = "cards" categoryName.textContent = catById.data.CategoryFind[0].name for (let key of catById.data.CategoryFind[0].goods) { cardDraw(key, cards) } main.append(categoryName, cards) } } if (route === 'good') { const goodById = store.getState().goodById?.payload if (goodById) { //вывести в main страницу товара while (main.lastChild) { main.lastChild.remove() } goodDraw(goodById.data.GoodFind[0], main) let count = document.createElement("input") count.type = "number" count.min = 1 count.value = 1 let goodBtnBox = document.createElement("div") let btn1 = document.createElement("button") let btn2 = document.createElement("button") goodBtnBox.style.display = "flex" goodBtnBox.style.alignItems = "center" btn1.textContent = "Купить" btn2.textContent = "В корзину" goodBtnBox.append(count, btn2, btn1) main.lastChild.append(goodBtnBox) let value = 1; count.oninput = () => value = +count.value let order = { [id]: value } btn1.onclick = () => { store.dispatch(actionBuyGood(order)) } /* btn2.onclick = () => { store.dispatch(actionGoodOrder(order)) } */ } } }) let goodDraw = (obj, parent) => { let box = document.createElement("div") let goodName = document.createElement("h2") let goodIMG = document.createElement("img") let description = document.createElement("p") let price = document.createElement("span") price.textContent = "Цена: " + obj.price + "грн" goodIMG.src = "http://shop-roles.asmer.fs.a-level.com.ua/" + obj.images[0].url box.style.width = "40%" box.style.margin = "20px" box.style.display = "flex" box.style.flexDirection = "column" goodName.textContent = obj.name description.textContent = obj.description box.append(goodIMG, goodName, description, price) parent.append(box) } let cardDraw = (obj, parent) => { let box = document.createElement("div"); let img = document.createElement("img"); let price = document.createElement("span"); let productName = document.createElement("h5"); img.src = "http://shop-roles.asmer.fs.a-level.com.ua/" + obj.images[0].url; productName.textContent = obj.name price.textContent = "Цена: " + obj.price + " грн" let productBody = document.createElement("div") box.className = "card" productBody.append(productName, price) box.append(img, productBody) let a = document.createElement("a") a.href = "#/good/" + obj._id a.append(box) parent.append(a) }