main.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. function createStore(reducer){
  2. let state = reducer(undefined, {})
  3. let cbs = []
  4. function dispatch(action){
  5. if (typeof action === 'function'){
  6. return action(dispatch)
  7. }
  8. const newState = reducer(state, action)
  9. if (state !== newState){
  10. state = newState
  11. cbs.forEach(cb => cb())
  12. }
  13. }
  14. return {
  15. dispatch,
  16. subscribe(cb){
  17. cbs.push(cb)
  18. return () => cbs = cbs.filter(c => c !== cb)
  19. },
  20. getState(){
  21. return state
  22. }
  23. }
  24. }
  25. function promiseReducer(state={}, {type, status, payload, error, name}){
  26. if (type === 'PROMISE'){
  27. return {
  28. ...state,
  29. [name]:{status, payload, error}
  30. }
  31. }
  32. return state
  33. }
  34. //под товаром сделать кнопку "купить"
  35. const store = createStore(promiseReducer)
  36. const unsubscribe1 = store.subscribe(() => console.log(store.getState()))
  37. const actionPending = name => ({type: 'PROMISE', status: 'PENDING', name})
  38. const actionResolved = (name, payload) => ({type: 'PROMISE', status: 'RESOLVED', name, payload})
  39. const actionRejected = (name, error) => ({type: 'PROMISE', status: 'REJECTED', name, error})
  40. const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms))
  41. const actionPromise = (name, promise) =>
  42. async dispatch => {
  43. dispatch(actionPending(name))
  44. try{
  45. let payload = await promise
  46. dispatch(actionResolved(name, payload))
  47. return payload
  48. }
  49. catch(error){
  50. dispatch(actionRejected(name, error))
  51. }
  52. }
  53. const getGQL = url => {
  54. return function(query, variables={}) {
  55. return fetch(url,
  56. {
  57. method: "POST",
  58. headers:
  59. {"Content-Type": "application/json",
  60. ...(localStorage.authToken ? {Authorization: localStorage.authToken} : {})
  61. },
  62. body: JSON.stringify({query, variables})
  63. }).then(resp => resp.json())
  64. // .then(data => {
  65. // if ("errors" in data) {
  66. // throw new Error('ашипка, угадывай што не так')
  67. // }
  68. // else {
  69. // return data.data[Object.keys(variables)[0]]
  70. // }
  71. // })
  72. }
  73. }
  74. let shopGQL = getGQL('http://shop-roles.asmer.fs.a-level.com.ua/graphql')
  75. const goodById = goodId => {
  76. let id = `[{"_id":"${goodId}"}]`
  77. return shopGQL(`
  78. query good($id:String){
  79. GoodFindOne(query: $id) {
  80. name description price images {
  81. _id text url
  82. }
  83. categories {
  84. _id name
  85. }
  86. }
  87. }`, { id })
  88. }
  89. const actionGoodById = id =>
  90. actionPromise('goodById', goodById(id))
  91. const actionRootCategories = () =>
  92. actionPromise('rootCategories', shopGQL(`
  93. query cats($query:String){
  94. CategoryFind(query:$query){
  95. _id name
  96. }
  97. }
  98. `, {query: JSON.stringify([{parent:null}])}))
  99. const actionCategoryById = (_id) =>
  100. actionPromise('catById', shopGQL(`query catById($query:String){
  101. CategoryFindOne(query:$query){
  102. _id name goods{
  103. _id name price description images{
  104. url
  105. }
  106. }
  107. }
  108. }`, {query: JSON.stringify([{_id}])}))
  109. store.dispatch(actionRootCategories())
  110. window.onhashchange = () => {
  111. let {1: route, 2:id} = location.hash.split('/')
  112. if (route === 'categories'){
  113. store.dispatch(actionCategoryById(id))
  114. }
  115. if (route === 'good'){
  116. store.dispatch(actionGoodById(id))
  117. }
  118. }
  119. function drawMainMenu(){
  120. let cats = store.getState().rootCategories.payload
  121. if (cats){ //каждый раз дорисовываются в body
  122. aside.innerText = ''
  123. for (let {_id, name} of cats.data.CategoryFind){
  124. let catA = document.createElement('a')
  125. catA.href = `#/categories/${_id}`
  126. catA.innerText = name
  127. aside.append(catA)
  128. }
  129. }
  130. }
  131. store.subscribe(drawMainMenu)
  132. store.subscribe(() => {
  133. const {1: route, 2:id} = location.hash.split('/')
  134. if (route === 'categories'){
  135. const catById = store.getState().catById?.payload
  136. if (catById){
  137. main.innerText = ''
  138. let categoryName = document.createElement('div')
  139. categoryName.innerText = catById.data.CategoryFindOne.name
  140. categoryName.style.fontSize = '25px'
  141. categoryName.style.fontWeight = 'bold'
  142. main.append(categoryName)
  143. for (let {_id, name} of catById.data.CategoryFindOne.goods){
  144. let good = document.createElement('a')
  145. good.href = `#/good/${_id}`
  146. good.innerText = name
  147. let btn = document.createElement('button')
  148. btn.style.cursor = 'pointer'
  149. btn.innerText = 'купыть'
  150. main.append(good, btn)
  151. }
  152. }
  153. }
  154. if (route === 'good'){
  155. const goodById = store.getState().goodById?.payload
  156. if (goodById){
  157. main.innerText = ''
  158. let {name, description, price} = goodById.data.GoodFindOne
  159. let goodName = document.createElement('div')
  160. goodName.innerText = name
  161. goodName.style.fontSize = '35px'
  162. goodName.style.fontWeight = 'bold'
  163. goodName.style.marginBottom = '25px'
  164. let goodDescription = document.createElement('div')
  165. goodDescription.innerText = description
  166. goodDescription.style.marginBottom = '25px'
  167. let goodPrice = document.createElement('div')
  168. goodPrice.innerText = 'Цена: ' + price
  169. goodPrice.style.marginBottom = '5px'
  170. let btn = document.createElement('button')
  171. btn.style.cursor = 'pointer'
  172. btn.innerText = 'купыть'
  173. main.append(goodName, goodDescription, goodPrice, btn)
  174. }
  175. }
  176. })