script.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // function promiseReducer(state={}, {type, name, status, payload, error}){
  2. // if (type === 'PROMISE'){
  3. // return {
  4. // ...state, [name]: {status, payload, error}
  5. // }
  6. // }
  7. // return state
  8. // }
  9. // const actionPending = name => ({type:'PROMISE',name, status: 'PENDING'})
  10. // const actionFulfilled = (name,payload) => ({type:'PROMISE',name, status: 'FULFILLED', payload})
  11. // const actionRejected = (name,error) => ({type:'PROMISE',name, status: 'REJECTED', error})
  12. // const delay = ms => new Promise(ok => setTimeout(() => ok(ms), ms))
  13. // function createStore(reducer){
  14. // let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
  15. // let cbs = [] //массив подписчиков
  16. // const getState = () => state //функция, возвращающая переменную из замыкания
  17. // const subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве
  18. // () => cbs = cbs.filter(c => c !== cb)) //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
  19. // const dispatch = action => {
  20. // if (typeof action === 'function'){ //если action - не объект, а функция
  21. // return action(dispatch, getState) //запускаем эту функцию и даем ей dispatch и getState для работы
  22. // }
  23. // const newState = reducer(state, action) //пробуем запустить редьюсер
  24. // if (newState !== state){ //проверяем, смог ли редьюсер обработать action
  25. // state = newState //если смог, то обновляем state
  26. // for (let cb of cbs) cb() //и запускаем подписчиков
  27. // }
  28. // }
  29. // return {
  30. // getState, //добавление функции getState в результирующий объект
  31. // dispatch,
  32. // subscribe //добавление subscribe в объект
  33. // }
  34. // }
  35. // let store = createStore(promiseReducer);
  36. // store.subscribe(() => console.log(store.getState()))
  37. // // store.dispatch(actionPending('delay1000'))
  38. // // delay(1000).then(result => store.dispatch(actionFulfilled('delay1000', result)))
  39. // // store.dispatch(actionPending('delay2000'))
  40. // // delay(2000).then(result => store.dispatch(actionFulfilled('delay2000', result)))
  41. // const actionPromise = (name, promise) =>
  42. // async dispatch => {
  43. // dispatch(actionPending(name))
  44. // try {
  45. // let payload = await promise
  46. // dispatch(actionFulfilled(name, payload))
  47. // return payload
  48. // }
  49. // catch(error){
  50. // dispatch(actionRejected(name, error))
  51. // }
  52. // }
  53. // store.dispatch(actionPromise('delay1000', delay(1000)))
  54. // store.dispatch(actionPromise('delay2000', delay(2000)))
  55. // const actionLuke = () => actionPromise('luke',
  56. // fetch('https://swapi.dev/api/people/1')
  57. // .then(res => res.json()))
  58. // store.dispatch(actionLuke())
  59. // // const actionRegister = (login, password) =>
  60. // // actionPromise('register', gql(`mutation ......
  61. // // ......
  62. // // ....`, {login, password}))
  63. // // store.dispatch(actionRegister('anon100500', '123123'))
  64. // // const actionCategoryById = _id =>
  65. // // actionPromise('catById', gql(`aaaaaaaa $query.....`, {query: JSON.stringify([{_id}])}))
  66. // // store.dispatch(actionCategoryById('АЙДИКАТЕГОРИИ НАТЫРИТЬ В GRAPHQL'))
  67. // // const actionGoodById = _id =>
  68. // // actionPromise('goodById', gql(`aaaaaaaa $query.....`, {query: JSON.stringify([{_id}])}))
  69. // // const actionRootCategories = () =>
  70. // // actionPromise('rootCats', gql(`CategoryFind так, что бы parent: null`)}))
  71. // // //сделать const actionOrders для истории заказов (нужен токен в localStorage)
  72. // // //шобы сработало, надо добавить в createStore в dispatch один if:
  73. // // //if (typeof action === 'function'){ //если action - не объект, а функция
  74. // // //return action(dispatch, getState) //запускаем эту функцию и даем ей dispatch и getState для работы
  75. // // //}
  76. // // //надо const newState
  77. function createStore(reducer){
  78. let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
  79. let cbs = [] //массив подписчиков
  80. const getState = () => state //функция, возвращающая переменную из замыкания
  81. const subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве
  82. () => cbs = cbs.filter(c => c !== cb)) //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
  83. const dispatch = action => {
  84. if (typeof action === 'function'){ //если action - не объект, а функция
  85. return action(dispatch, getState) //запускаем эту функцию и даем ей dispatch и getState для работы
  86. }
  87. const newState = reducer(state, action) //пробуем запустить редьюсер
  88. if (newState !== state){ //проверяем, смог ли редьюсер обработать action
  89. state = newState //если смог, то обновляем state
  90. for (let cb of cbs) cb() //и запускаем подписчиков
  91. }
  92. }
  93. return {
  94. getState, //добавление функции getState в результирующий объект
  95. dispatch,
  96. subscribe //добавление subscribe в объект
  97. }
  98. }
  99. function promiseReducer(state={}, {type, name, status, payload, error}){
  100. if (type === 'PROMISE'){
  101. return {
  102. ...state,
  103. [name]:{status, payload, error}
  104. }
  105. }
  106. return state
  107. }
  108. const store = createStore(promiseReducer)
  109. //не забудьте combineReducers если он у вас уже есть
  110. //const store = createStore(combineReducers({promise: promiseReducer, auth: authReducer}))
  111. store.subscribe(() => console.log(store.getState()))
  112. const actionPending = name => ({type:'PROMISE',name, status: 'PENDING'})
  113. const actionFulfilled = (name,payload) => ({type:'PROMISE',name, status: 'FULFILLED', payload})
  114. const actionRejected = (name,error) => ({type:'PROMISE',name, status: 'REJECTED', error})
  115. const actionPromise = (name, promise) =>
  116. async dispatch => {
  117. dispatch(actionPending(name))
  118. try {
  119. let payload = await promise
  120. dispatch(actionFulfilled(name, payload))
  121. return payload
  122. }
  123. catch(error){
  124. dispatch(actionRejected(name, error))
  125. }
  126. }
  127. const getGQL = url =>
  128. (query, variables) => fetch(url, {
  129. method: 'POST',
  130. headers: {
  131. "Content-Type": "application/json",
  132. ...(localStorage.authToken ? {"Authorization": "Bearer " + localStorage.authToken} : {})
  133. },
  134. body: JSON.stringify({query, variables})
  135. }).then(res => res.json())
  136. .then(data => {
  137. if (data.data){
  138. return Object.values(data.data)[0]
  139. }
  140. else throw new Error(JSON.stringify(data.errors))
  141. })
  142. const backendURL = 'http://shop-roles.asmer.fs.a-level.com.ua'
  143. const gql = getGQL(backendURL + '/graphql')
  144. const actionRootCats = () =>
  145. actionPromise('rootCats', gql(`query {
  146. CategoryFind(query: "[{\\"parent\\":null}]"){
  147. _id name
  148. }
  149. }`))
  150. const actionCatById = (_id) =>
  151. //добавить подкатегории
  152. actionPromise('catById', gql(`query catById($q: String){
  153. CategoryFindOne(query: $q){
  154. _id subCategories{
  155. name _id
  156. } name goods {
  157. _id name price images {
  158. url
  159. }
  160. }
  161. }
  162. }`, {q: JSON.stringify([{_id}])}))
  163. const actionGoodById = (_id) =>
  164. actionPromise('goodById', gql(`query findGoodById($q: String) {
  165. GoodFindOne(query: $q) {
  166. _id
  167. name
  168. description
  169. price
  170. images{
  171. url
  172. }
  173. }
  174. }`, {q: JSON.stringify([{_id}])}))
  175. store.dispatch(actionRootCats())
  176. store.subscribe(() => {
  177. const {rootCats} = store.getState()
  178. if (rootCats?.payload){
  179. aside.innerHTML = ''
  180. for (const {_id, name} of rootCats?.payload){
  181. const link = document.createElement('a')
  182. link.href = `#/category/${_id}`
  183. link.innerText = name
  184. aside.append(link)
  185. }
  186. }
  187. })
  188. window.onhashchange = () => {
  189. const [, route, _id] = location.hash.split('/')
  190. const routes = {
  191. category(){
  192. store.dispatch(actionCatById(_id))
  193. },
  194. good(){
  195. store.dispatch(actionGoodById(_id))
  196. },
  197. login(){
  198. //отрисовка тут
  199. //по кнопке - store.dispatch(actionFullLogin(login, password))
  200. },
  201. register(){
  202. //отрисовка тут
  203. //по кнопке - store.dispatch(actionFullRegister(login, password))
  204. },
  205. }
  206. if (route in routes)
  207. routes[route]()
  208. }
  209. window.onhashchange()
  210. store.subscribe(() => {
  211. const {catById} = store.getState()
  212. const [,route, _id] = location.hash.split('/')
  213. if (catById?.payload && route === 'category'){
  214. const {name, subCategories} = catById.payload
  215. main.innerHTML = `<h1>${name}</h1>
  216. ${(subCategories ? subCategories.map(item => {
  217. return `<a href='#/category/${item._id}'>${item.name}</a>`} ) : '')}
  218. `
  219. for (const {_id, name, price, images} of catById.payload.goods){
  220. const card = document.createElement('div');
  221. card.innerHTML = `<h2>${name}</h2>
  222. <img src="${backendURL}/${images[0].url}" width="380"/>
  223. <div><strong>${price}грн</strong></div>
  224. <a href= '#/good/${_id}'> Купить </a>
  225. `
  226. main.append(card)
  227. }
  228. }
  229. })
  230. store.subscribe(() => {
  231. const {goodById} = store.getState()
  232. const [,route, _id] = location.hash.split('/')
  233. console.log(goodById)
  234. if (goodById?.payload && route === 'good'){
  235. const {name, description, price, images} = goodById.payload
  236. main.innerHTML = ``
  237. console.log(goodById.payload)
  238. const card = document.createElement('div');
  239. card.innerHTML = `<h2>${name}</h2>
  240. <div> <strong>${price}грн</strong></div>
  241. <img src="${backendURL}/${images[0].url}"/>
  242. <p>${description} </p> `
  243. main.append(card)
  244. }
  245. })
  246. console.log(JSON.stringify([{_id:'5e1f396856d8f720513e6cae'}]))