main.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // функция createStore
  2. function createStore(reducer) {
  3. let state = reducer(undefined, {})
  4. let cbs = []
  5. function dispatch(action) {
  6. if (typeof action === 'function') {
  7. return action(dispatch)
  8. }
  9. const newState = reducer(state, action)
  10. if (newState !== state) {
  11. state = newState
  12. for (let cb of cbs)
  13. cb()
  14. }
  15. }
  16. return {
  17. dispatch,
  18. getState() {
  19. return state
  20. },
  21. subscribe(cb) {
  22. cbs.push(cb)
  23. return () => cbs = cbs.filter(c => c !== cb)
  24. }
  25. }
  26. }
  27. // функция promiseReducer
  28. function promiseReducer(state = {}, { type, status, payload, error, name }) {
  29. if (type === 'PROMISE') {
  30. return {
  31. ...state,
  32. [name]: { status, payload, error }
  33. }
  34. }
  35. return state
  36. }
  37. const store = createStore(promiseReducer)
  38. // actions
  39. const actionPending = name => ({type: 'PROMISE', status: 'PENDING', name})
  40. const actionResolved = (name, payload) => ({type: 'PROMISE', status: 'RESOLVED', name, payload})
  41. const actionRejected = (name, error) => ({type: 'PROMISE', status: 'REJECTED', name, error})
  42. const actionPromise = (name, promise) =>
  43. async dispatch => {
  44. dispatch(actionPending(name))
  45. try{
  46. let payload = await promise
  47. dispatch(actionResolved(name, payload))
  48. return payload
  49. }
  50. catch(error){
  51. dispatch(actionRejected(name, error))
  52. }
  53. }
  54. // функция cartReducer
  55. function cartReducer(state = {}, { type, count = 1, _id, name }) {
  56. if (type === "CART_ADD") {
  57. return {
  58. ...state,
  59. [_id]: {
  60. name: name,
  61. count: state[_id] ? state[_id].count + count : count
  62. }
  63. }
  64. }
  65. if (type === "CART_CHANGE") {
  66. return {
  67. ...state,
  68. [_id]: {
  69. name: name,
  70. count: count
  71. }
  72. }
  73. }
  74. if (type === 'CART_REMOVE') {
  75. let { [_id]: count, ...copyWithout } = state
  76. return copyWithout
  77. }
  78. if (type === 'CART_CLEAR') {
  79. return {}
  80. }
  81. return state
  82. }
  83. // reducers
  84. let reducers = {
  85. promise: promiseReducer,
  86. cart: cartReducer
  87. }
  88. // функция combineReducers
  89. function combineReducers(reducers) {
  90. function commonReducer(state = {}, action) {
  91. let newState = {}
  92. for (let key in reducers) {
  93. let innerState = reducers[key](state[key], action)
  94. innerState === state[key] ? newState[key] = state[key] : newState[key] = innerState
  95. }
  96. return newState
  97. }
  98. return commonReducer
  99. }
  100. // запросы
  101. const getGQL = url =>
  102. (query, variables = {}) => fetch(url, {
  103. method: 'POST',
  104. headers: {
  105. "content-type": "application/json",
  106. ...(localStorage.authToken ? { Authorization: "Bearer " + localStorage.authToken } : {})
  107. },
  108. body: JSON.stringify({ query, variables })
  109. }).then(res => res.json())
  110. let shopGQL = getGQL("http://shop-roles.asmer.fs.a-level.com.ua/graphql")
  111. const actionRootCategories = () =>
  112. actionPromise('rootCategories', shopGQL(`query cats($query:String) {
  113. CategoryFind(query:$query) {
  114. _id name
  115. }
  116. }`, {query: JSON.stringify([{parent:null}])}))
  117. store.dispatch(actionRootCategories())
  118. const actionCategoryById = (_id) =>
  119. actionPromise('catById', shopGQL(`query catById($query:String) {
  120. CategoryFindOne(query:$query) {
  121. _id name goods {
  122. _id name price description images {
  123. url
  124. }
  125. }
  126. }
  127. }`, {query: JSON.stringify([{_id}])}))
  128. const actionGoodById = id =>
  129. actionPromise('goodById', shopGQL(`query GoodFind($id:String) {
  130. GoodFind(query: $id){
  131. name
  132. price
  133. description
  134. images {url}
  135. }
  136. }`, {id: JSON.stringify([{ "_id": id }])}))
  137. window.onhashchange = () => {
  138. let { 1: route, 2: id } = location.hash.split('/')
  139. if (route === 'categories') {
  140. store.dispatch(actionCategoryById(id))
  141. }
  142. if (route === 'good') {
  143. store.dispatch(actionGoodById(id))
  144. }
  145. }
  146. function drawMainMenu() {
  147. let cats = store.getState().rootCategories.payload
  148. if (cats) {
  149. aside.innerText = ''
  150. for (let { _id, name } of cats.data.CategoryFind) {
  151. let catA = document.createElement('a')
  152. catA.href = `#/categories/${_id}`
  153. catA.innerText = name
  154. aside.append(catA)
  155. }
  156. }
  157. }
  158. store.subscribe(drawMainMenu)
  159. store.subscribe(() => console.log(store.getState()))
  160. store.subscribe(() => {
  161. const { 1: route, 2: id } = location.hash.split('/')
  162. if (route === 'categories') {
  163. const catById = store.getState().catById?.payload
  164. if (catById) {
  165. aside.innerText = ''
  166. let cats = document.createElement('p')
  167. cats.innerText = "Вы в категории ==>" + " " + catById.data.CategoryFindOne.name
  168. mainMenu = document.createElement('a')
  169. mainMenu.innerText = "Назад в главное меню"
  170. mainMenu.onclick = () => {
  171. main.innerText = ''
  172. drawMainMenu()
  173. }
  174. aside.append(mainMenu, cats)
  175. let goods = catById.data.CategoryFindOne.goods
  176. for (let {_id, name, price, description, images} of goods) {
  177. let div = document.createElement('div')
  178. div.className = 'goods'
  179. let btnCart = document.createElement('btn')
  180. let btn = document.createElement('button')
  181. btn.textContent = "Добавить в карзину"
  182. let img = document.createElement('img')
  183. img.style.width ='400px'
  184. img.src = `http://shop-roles.asmer.fs.a-level.com.ua/${images[0].url}`
  185. let prices = document.createElement('span')
  186. let descriptions = document.createElement('p')
  187. prices.innerText = `Цена: ${price} грн`
  188. descriptions.innerText = `Описание: ${description}`
  189. let goodA = document.createElement('a')
  190. goodA.href = `#/good/${_id}`
  191. goodA.innerText = name
  192. main.append(div)
  193. btnCart.append(btn)
  194. div.append(goodA, img, prices, descriptions, btnCart)
  195. }
  196. }
  197. }
  198. if (route === 'good') {
  199. const goodById = store.getState().goodById?.payload
  200. const catById = store.getState().catById?.payload
  201. if (goodById) {
  202. aside.innerText = ''
  203. main.innerText = ''
  204. let cats = document.createElement('p')
  205. cats.innerText = "Вы в категории ==>" + " " + catById.data.CategoryFindOne.name
  206. menuGoods = document.createElement('a')
  207. menuGoods.innerText = catById.data.CategoryFindOne.name + " " + "<== Назад в список товаров"
  208. mainMenu = document.createElement('a')
  209. mainMenu.innerText = "Назад в главное меню"
  210. mainMenu.onclick = () => {
  211. main.innerText = ''
  212. drawMainMenu()
  213. }
  214. aside.append(mainMenu, cats)
  215. let good = goodById.data.GoodFind
  216. for (let {name, price, description, images} of good) {
  217. let div = document.createElement('div')
  218. div.className = 'good'
  219. let btn = document.createElement('button')
  220. btn.textContent = "Добавить в карзину"
  221. let img = document.createElement('img')
  222. img.style.width ='400px'
  223. img.src = `http://shop-roles.asmer.fs.a-level.com.ua/${images[0].url}`
  224. let prices = document.createElement('span')
  225. let descriptions = document.createElement('p')
  226. prices.innerText = `Цена: ${price} грн`
  227. descriptions.innerText = `Описание: ${description}`
  228. let goodA = document.createElement('a')
  229. goodA.innerText = name
  230. main.append(div)
  231. div.append(goodA, img, prices, descriptions, btn)
  232. }
  233. }
  234. }
  235. })