script.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. function reducer(state, { type, name, amount, money }) { //объект action деструктуризируется на три переменных
  2. if (!state) { //начальная уборка в ларьке:
  3. return {
  4. products: {
  5. пиво: {
  6. amount: 100,
  7. price: 30,
  8. },
  9. чипсы: {
  10. amount: 100,
  11. price: 25,
  12. },
  13. сиги: {
  14. amount: 100,
  15. price: 35,
  16. }
  17. },
  18. balance: {
  19. amount: 0
  20. }
  21. }
  22. }
  23. if (type === 'buy') { //если тип action - КУПИТЬ, то:
  24. if (amount > state.products[name].amount) {
  25. alert('You have entered more quantity than is available');
  26. return {
  27. ...state,
  28. }
  29. }
  30. if (money < amount * state.products[name].price) {
  31. alert('You don`t have enought money');
  32. return {
  33. ...state,
  34. }
  35. }
  36. if (money > amount * state.products[name].price) {
  37. alert('You gave more money');
  38. return {
  39. ...state,
  40. }
  41. }
  42. let updatedProducts = state.products
  43. let updatedField = updatedProducts[name];
  44. updatedField.amount -= amount;
  45. let updatedBalance = state.balance;
  46. updatedBalance.amount += +money;
  47. return {
  48. ...state, //берем все что было из ассортимента
  49. products: updatedProducts, //и уменьшаем то, что покупается на количество
  50. balance: updatedBalance,
  51. }
  52. }
  53. return state; //если мы не поняли, что от нас просят в `action` - оставляем все как есть
  54. }
  55. function createStore(reducer) {
  56. let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
  57. let cbs = []; //массив подписчиков
  58. const getState = () => state; //функция, возвращающая переменную из замыкания
  59. const subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве
  60. () => cbs = cbs.filter(c => c !== cb)); //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
  61. const dispatch = action => {
  62. const newState = reducer(state, action); //пробуем запустить редьюсер
  63. if (newState !== state) { //проверяем, смог ли редьюсер обработать action
  64. state = newState; //если смог, то обновляем state
  65. for (let cb of cbs) cb(); //и запускаем подписчиков
  66. }
  67. }
  68. return {
  69. getState, //добавление функции getState в результирующий объект
  70. dispatch,
  71. subscribe //добавление subscribe в объект
  72. }
  73. }
  74. const store = createStore(reducer);
  75. //запомнит функцию во внутреннем массиве cbs.
  76. //она будет запущена при любом успешном dispatch
  77. const unsubscribe = store.subscribe(() => console.log(store.getState()));
  78. setTimeout(unsubscribe, 10000); //отпишемся через 10 секунд, например
  79. const buyAction = (name, amount, money) => ({ type: 'buy', name, amount, money });
  80. //происходит запуск редьюсера, который создает новый state.
  81. //dispatch запускает всех подписчиков из массива cbs
  82. function createTable() {
  83. let state = store.getState();
  84. let table = document.getElementById('table');
  85. table.innerHTML = '';
  86. let headerRow = document.createElement('tr');
  87. table.append(headerRow);
  88. let headerName = document.createElement('th');
  89. headerName.innerText = 'Name';
  90. headerRow.append(headerName);
  91. let headerAmount = document.createElement('th');
  92. headerAmount.innerText = 'Amount';
  93. headerRow.append(headerAmount);
  94. let headerPrice = document.createElement('th');
  95. headerPrice.innerText = 'Price';
  96. headerRow.append(headerPrice);
  97. Object.keys(state.products).forEach(key => {
  98. let row = document.createElement('tr');
  99. table.append(row);
  100. let name = document.createElement('td');
  101. name.innerText = key;
  102. row.append(name);
  103. let amount = document.createElement('td');
  104. amount.innerText = state.products[key].amount;
  105. row.append(amount);
  106. let price = document.createElement('td');
  107. price.innerText = state.products[key].price;
  108. row.append(price);
  109. });
  110. }
  111. function createBalance() {
  112. let state = store.getState();
  113. let balance = document.getElementById('balance');
  114. balance.innerHTML = '';
  115. balance.innerText = `Balance: ${state.balance.amount}`;
  116. }
  117. function createForm() {
  118. let state = store.getState();
  119. let form = document.getElementById('form');
  120. form.innerHTML = '';
  121. let selectLabel = document.createElement('label');
  122. selectLabel.innerText = 'Select a product:';
  123. form.append(selectLabel);
  124. let select = document.createElement('select');
  125. form.append(select);
  126. Object.keys(state.products).forEach(key => {
  127. let option = document.createElement('option');
  128. option.innerHTML = key;
  129. select.append(option);
  130. });
  131. let inputLabel = document.createElement('label');
  132. inputLabel.innerText = 'Enter quantity:';
  133. form.append(inputLabel);
  134. let amountInput = document.createElement('input');
  135. form.append(amountInput);
  136. let moneyInputLabel = document.createElement('label');
  137. moneyInputLabel.innerText = 'Enter amount:';
  138. form.append(moneyInputLabel);
  139. let moneyInput = document.createElement('input');
  140. form.append(moneyInput);
  141. let submitButton = document.createElement('button');
  142. submitButton.innerText = 'Buy';
  143. form.append(submitButton);
  144. submitButton.addEventListener('click', () => {
  145. store.dispatch(buyAction(select.value, amountInput.value, moneyInput.value));
  146. init();
  147. })
  148. }
  149. function init() {
  150. createTable();
  151. createBalance();
  152. createForm();
  153. }
  154. init();