123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- // функция 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
- }
- const store = createStore(promiseReducer)
- // 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))
- }
- }
- // функция 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
- }
- // reducers
- let reducers = {
- promise: promiseReducer,
- cart: cartReducer
- }
- // функция 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 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")
- const actionRootCategories = () =>
- actionPromise('rootCategories', shopGQL(`query cats($query:String) {
- CategoryFind(query:$query) {
- _id name
- }
- }`, {query: JSON.stringify([{parent:null}])}))
- store.dispatch(actionRootCategories())
- 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 GoodFind($id:String) {
- GoodFind(query: $id){
- name
- price
- description
- images {url}
- }
- }`, {id: JSON.stringify([{ "_id": id }])}))
- 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) {
- 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(() => console.log(store.getState()))
- store.subscribe(() => {
- const { 1: route, 2: id } = location.hash.split('/')
- if (route === 'categories') {
- const catById = store.getState().catById?.payload
- if (catById) {
- aside.innerText = ''
- let cats = document.createElement('p')
- cats.innerText = "Вы в категории ==>" + " " + catById.data.CategoryFindOne.name
- mainMenu = document.createElement('a')
- mainMenu.innerText = "Назад в главное меню"
- mainMenu.onclick = () => {
- main.innerText = ''
- drawMainMenu()
- }
- aside.append(mainMenu, cats)
- let goods = catById.data.CategoryFindOne.goods
- for (let {_id, name, price, description, images} of goods) {
- let div = document.createElement('div')
- div.className = 'goods'
- let btnCart = document.createElement('btn')
- let btn = document.createElement('button')
- btn.textContent = "Добавить в карзину"
- let img = document.createElement('img')
- img.style.width ='400px'
- img.src = `http://shop-roles.asmer.fs.a-level.com.ua/${images[0].url}`
- let prices = document.createElement('span')
- let descriptions = document.createElement('p')
- prices.innerText = `Цена: ${price} грн`
- descriptions.innerText = `Описание: ${description}`
- let goodA = document.createElement('a')
- goodA.href = `#/good/${_id}`
- goodA.innerText = name
- main.append(div)
- btnCart.append(btn)
- div.append(goodA, img, prices, descriptions, btnCart)
- }
- }
- }
- if (route === 'good') {
- const goodById = store.getState().goodById?.payload
- const catById = store.getState().catById?.payload
- if (goodById) {
- aside.innerText = ''
- main.innerText = ''
- let cats = document.createElement('p')
- cats.innerText = "Вы в категории ==>" + " " + catById.data.CategoryFindOne.name
- menuGoods = document.createElement('a')
- menuGoods.innerText = catById.data.CategoryFindOne.name + " " + "<== Назад в список товаров"
- mainMenu = document.createElement('a')
- mainMenu.innerText = "Назад в главное меню"
- mainMenu.onclick = () => {
- main.innerText = ''
- drawMainMenu()
- }
- aside.append(mainMenu, cats)
- let good = goodById.data.GoodFind
- for (let {name, price, description, images} of good) {
- let div = document.createElement('div')
- div.className = 'good'
- let btn = document.createElement('button')
- btn.textContent = "Добавить в карзину"
- let img = document.createElement('img')
- img.style.width ='400px'
- img.src = `http://shop-roles.asmer.fs.a-level.com.ua/${images[0].url}`
- let prices = document.createElement('span')
- let descriptions = document.createElement('p')
- prices.innerText = `Цена: ${price} грн`
- descriptions.innerText = `Описание: ${description}`
- let goodA = document.createElement('a')
- goodA.innerText = name
- main.append(div)
- div.append(goodA, img, prices, descriptions, btn)
- }
- }
- }
- })
|