index.js 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. function createStore(reducer){
  2. let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
  3. let cbs = [] //массив подписчиков
  4. const getState = () => state //функция, возвращающая переменную из замыкания
  5. const subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве
  6. () => cbs = cbs.filter(c => c !== cb)) //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
  7. const dispatch = action => {
  8. const newState = reducer(state, action) //пробуем запустить редьюсер
  9. if (newState !== state){ //проверяем, смог ли редьюсер обработать action
  10. state = newState //если смог, то обновляем state
  11. for (let cb of cbs) cb() //и запускаем подписчиков
  12. }
  13. }
  14. return {
  15. getState, //добавление функции getState в результирующий объект
  16. dispatch,
  17. subscribe //добавление subscribe в объект
  18. }
  19. }
  20. function reducer(state, {type, ШО, СКОКА, БАБОС}){ //объект action деструктуризируется на три переменных
  21. if (!state){ //начальная уборка в ларьке:
  22. return {
  23. // пиво: 100, //{count: 100, price: 30}
  24. // чипсы: 100,//{count: 100, price: 25}
  25. пиво: {count: 100, price: 30},
  26. чипсы: {count: 100, price: 25},
  27. сиги: {count: 100, price: 50},
  28. касса: 0, //при покупках увеличивается
  29. }
  30. }
  31. if (type === 'КУПИТЬ' &&
  32. state[ШО] && СКОКА > 0 &&
  33. СКОКА <= state[ШО].count && БАБОС >= state[ШО].price * СКОКА){ //если тип action - КУПИТЬ, то:
  34. //проверить на:
  35. //наличие товара как такового (есть ли ключ в объекте)
  36. //количество денег в action
  37. //наличие нужного количества товара.
  38. //и только при соблюдении этих условий обновлять state.
  39. console.log('bang')
  40. console.log(store.getState())
  41. state.касса += truncateFraction(+БАБОС)
  42. display_hide_error(arguments[1])
  43. return {
  44. ...state, //берем все что было из ассортимента
  45. [ШО]: {count: state[ШО].count - Math.floor(СКОКА), price: state[ШО].price },//и уменьшаем то, что покупается на количество
  46. }
  47. }
  48. display_hide_error(arguments[1])
  49. return state //если мы не поняли, что от нас просят в `action` - оставляем все как есть
  50. }
  51. const store = createStore(reducer)
  52. //надо бы напилить цикл, который в select напихивает ассортимент.
  53. //возможно, если вы собираетесь выводить (и обновлять) количество,
  54. //это надо делать где в subscribe, иначе оно не будет обновлять количество
  55. let select = document.getElementById('goods')
  56. for(let key in store.getState()) {
  57. if (key === 'касса') continue;
  58. let option = document.createElement('option')
  59. option.innerText = key
  60. option.value = key
  61. select.append(option)
  62. }
  63. let quantity = document.getElementById('quantity')
  64. let cash = document.getElementById('cash')
  65. const купи = (ШО, СКОКА, БАБОС) => ({type: 'КУПИТЬ', ШО, СКОКА, БАБОС})
  66. buy.onclick = () => {
  67. //достает выбранный товар и количество из DOM
  68. // store.dispatch(купи(....,....))
  69. store.dispatch(купи(select.value, quantity.value, cash.value))
  70. }
  71. //запомнит функцию во внутреннем массиве cbs.
  72. //она будет запущена при любом успешном dispatch
  73. const unsubscribe = store.subscribe(() => console.log(store.getState()))
  74. //setTimeout(unsubscribe, 10000) //отпишемся через 10 секунд, например
  75. //происходит запуск редьюсера, который создает новый state.
  76. //dispatch запускает всех подписчиков из массива cbs
  77. let errorP = document.createElement('p')
  78. errorP.style.color = 'red'
  79. errorP.style.textAlign = 'center'
  80. shop.append(errorP)
  81. function truncateFraction (number) {
  82. try {
  83. let strNum = String(number).split('.')
  84. if(strNum[1].length > 2) {
  85. strNum[1] = strNum[1].slice(0, 2)
  86. }
  87. return Number(strNum.join('.'))
  88. } catch (e) {
  89. return number
  90. }
  91. }
  92. function display_hide_error(obj) {
  93. errorP.innerText = ''
  94. if (obj.СКОКА === '' && obj.БАБОС === '') {
  95. errorP.innerText = 'Мысли я читать не умeю >:^['
  96. return;
  97. } else if(obj.СКОКА === '' || obj.СКОКА < 0) {
  98. errorP.innerText = 'А единиц товара сколько брать будете?'
  99. return;
  100. }
  101. if (obj.СКОКА > store.getState()[obj.ШО].count) {
  102. errorP.innerText = `У нас нет столько ${obj.ШО}. ${obj.ШО} осталось ${store.getState()[obj.ШО].count}`
  103. return;
  104. } else if (obj.БАБОС < store.getState()[obj.ШО].price * obj.СКОКА) {
  105. errorP.innerText = `Недостаточно денег для покупки ${obj.СКОКА} ед. ${obj.ШО}.
  106. ${obj.ШО} стоит ${store.getState()[obj.ШО].price} денег за 1 ед. товара
  107. Стоимость вашего заказа ${store.getState()[obj.ШО].price * obj.СКОКА}`
  108. return;
  109. }
  110. }
  111. let table = document.createElement('table')
  112. function drawTable(){
  113. table.innerHTML = ''
  114. table.insertAdjacentHTML('afterbegin', `
  115. <tr>
  116. <th>Товар</th>
  117. <th>Кол-во</th>
  118. <th>Стоимость</th>
  119. </tr>
  120. `)
  121. for(let key in store.getState()) {
  122. if(key === 'касса') continue;
  123. let tr = document.createElement('tr')
  124. let tdKey = document.createElement('td')
  125. let tdCount = document.createElement('td')
  126. let tdCost = document.createElement('td')
  127. tdKey.innerText = key
  128. tdCount.innerText = store.getState()[key].count
  129. tdCost.innerText = `${store.getState()[key].price} денег`
  130. tr.append(tdKey, tdCount, tdCost)
  131. table.append(tr)
  132. }
  133. table.insertAdjacentHTML('beforeend', `
  134. <tr>
  135. <th>Касса</th>
  136. <td>${store.getState().касса} денег</td>
  137. </tr>
  138. `)
  139. shop.append(table)
  140. }
  141. drawTable()
  142. store.subscribe(drawTable)
  143. console.log(store.getState())