hw14_03_store.html 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. <header>KIOSK</header>
  2. <body>
  3. <script>
  4. const addCell = (row, value) => {
  5. let cell = document.createElement("td");
  6. cell.innerText = value;
  7. row.append(cell);
  8. return cell;
  9. }
  10. const createAssortTable = (store) => {
  11. let state = store.getState();
  12. let table = document.createElement("table");
  13. let row = document.createElement("tr");
  14. table.append(row);
  15. addCell(row, "NAME");
  16. addCell(row, "PRICE");
  17. addCell(row, "AMOUNT");
  18. for (const itemKey in state) {
  19. if (itemKey == "cashbox")
  20. continue;
  21. let item = state[itemKey];
  22. let row = document.createElement("tr");
  23. table.append(row);
  24. addCell(row, itemKey);
  25. addCell(row, item.price);
  26. let amountVal = addCell(row, item.amount);
  27. store.subscribe(() => {
  28. const state = store.getState();
  29. const item = state[itemKey];
  30. const amount = item.amount;
  31. amountVal.innerText = amount;
  32. });
  33. //store.getState()[itemKey].amount);
  34. }
  35. return table;
  36. }
  37. const addLabel = (element, value) => {
  38. let label = document.createElement("label");
  39. label.htmlFor = element.id;
  40. label.innerText = value + ": ";
  41. element.parentElement.insertBefore(label, element);
  42. }
  43. const addBr = (element) => element.append(document.createElement("br"));
  44. const createSale = (store) => {
  45. let state = store.getState();
  46. let resDiv = document.createElement("div")
  47. let select = document.createElement("select");
  48. resDiv.append(select);
  49. for (itemKey in state) {
  50. if (itemKey == "cashbox")
  51. continue;
  52. let option = document.createElement("option");
  53. option.value = itemKey;
  54. option.text = itemKey;
  55. select.append(option);
  56. }
  57. select.onchange = () => {
  58. priceDiv.innerText = state[select.value].price;
  59. }
  60. addLabel(select, "NAME");
  61. addBr(resDiv);
  62. let priceDiv = document.createElement("a");
  63. priceDiv.innerText = state[select.value].price;
  64. priceDiv.id = "priceId";
  65. resDiv.append(priceDiv);
  66. addLabel(priceDiv, "price");
  67. addBr(resDiv);
  68. let amountInp = document.createElement("input");
  69. amountInp.id = "amountId";
  70. amountInp.value = 0;
  71. resDiv.append(amountInp);
  72. addLabel(amountInp, "amount");
  73. addBr(resDiv);
  74. let cashInp = document.createElement("input");
  75. cashInp.id = "cashId";
  76. cashInp.value = 0;
  77. resDiv.append(cashInp);
  78. addLabel(cashInp, "cash");
  79. addBr(resDiv);
  80. let buyBtn = document.createElement("button");
  81. buyBtn.innerText = "BUY";
  82. buyBtn.onclick = () => {
  83. store.dispatch({ type: 'BUY', item: select.value, amount: +amountInp.value, cash: +cashInp.value });
  84. }
  85. resDiv.append(buyBtn);
  86. return resDiv;
  87. }
  88. function CreateStore(reducer) {
  89. let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
  90. let cbs = [] //массив подписчиков
  91. this.getState = () => state //функция, возвращающая переменную из замыкания
  92. this.subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве
  93. () => cbs = cbs.filter(c => c !== cb)) //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
  94. this.dispatch = action => {
  95. const newState = reducer(state, action) //пробуем запустить редьюсер
  96. if (newState !== state) { //проверяем, смог ли редьюсер обработать action
  97. state = newState //если смог, то обновляем state
  98. for (let cb of cbs) cb() //и запускаем подписчиков
  99. }
  100. }
  101. }
  102. const seller = (state, { type, item, amount, cash, price }) => {
  103. if (state === undefined) {
  104. state = {
  105. beer: { amount: 20, price: 10 },
  106. vodka: { amount: 10, price: 30 },
  107. cigars: { amount: 100, price: 20 },
  108. cashbox: 0,
  109. }
  110. }
  111. if (type === 'BUY' &&
  112. item in state &&
  113. typeof amount == "number" &&
  114. typeof cash == "number" &&
  115. state[item].amount >= amount &&
  116. amount > 0 &&
  117. cash > 0 &&
  118. state[item].price <= cash / amount) { //если тип action - КУПИТЬ, то:
  119. return {
  120. ...state, //берем все что было из ассортимента
  121. [item]: { amount: state[item].amount - amount, price: state[item].price }, //и уменьшаем то, что покупается на количество
  122. cashbox: state.cashbox + amount * state[item].price,
  123. }
  124. }
  125. return state;
  126. }
  127. let store = new CreateStore(seller);
  128. const unsubscribe = store.subscribe(() => console.log(store.getState()))
  129. document.body.append(createAssortTable(store));
  130. document.body.append(document.createElement("br"));
  131. document.body.append(createSale(store));
  132. </script>
  133. </body>
  134. <footer>
  135. </footer>