|
@@ -0,0 +1,118 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="en">
|
|
|
+ <head>
|
|
|
+ <meta charset="UTF-8" />
|
|
|
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
|
+ <title>Document</title>
|
|
|
+ </head>
|
|
|
+ <body>
|
|
|
+ <select name="" id="selectItems"></select>
|
|
|
+ <input type="number" name="" id="inputAmountToBuy" />
|
|
|
+ <button type="button" id="buyBtn">Buy</button>
|
|
|
+
|
|
|
+ <div id="container">
|
|
|
+ <table id="stateTable" border="1"></table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <script>
|
|
|
+ const store = createStore(reducer);
|
|
|
+
|
|
|
+ for ([key, value] of Object.entries(store.getState()["продукты"])) {
|
|
|
+ let option = document.createElement("option");
|
|
|
+ option.innerText = key;
|
|
|
+ option.value = key;
|
|
|
+ selectItems.append(option);
|
|
|
+ }
|
|
|
+
|
|
|
+ const buyItem = (amount, item) => ({
|
|
|
+ type: "КУПИТЬ",
|
|
|
+ ШО: item,
|
|
|
+ СКОКА: amount,
|
|
|
+ });
|
|
|
+
|
|
|
+ buyBtn.onclick = () => {
|
|
|
+ let amount = inputAmountToBuy.value;
|
|
|
+ let item = selectItems.value;
|
|
|
+ store.dispatch(buyItem(amount, item));
|
|
|
+
|
|
|
+ console.log(amount);
|
|
|
+ };
|
|
|
+
|
|
|
+ const updateTable = () => {
|
|
|
+ let str = "<tr><th>Название</th><th>Количество</th><th>Цена</th></tr>";
|
|
|
+ let state = store.getState();
|
|
|
+ for ([key, value] of Object.entries(state["продукты"])) {
|
|
|
+ str += `<tr><th>${key}</th><td>${value.amount}</td><td>${value.cost}</td></tr>`;
|
|
|
+ }
|
|
|
+ str += `<th>касса</th><td colspan = "2">${state["касса"]}</td></tr>`;
|
|
|
+ stateTable.innerHTML = str;
|
|
|
+ };
|
|
|
+
|
|
|
+ store.subscribe(updateTable);
|
|
|
+ store.subscribe(() => console.log(store.getState()));
|
|
|
+ updateTable();
|
|
|
+
|
|
|
+ function reducer(state, { type, ШО, СКОКА }) {
|
|
|
+ //объект action деструктуризируется на три переменных
|
|
|
+ if (!state) {
|
|
|
+ //начальная уборка в ларьке:
|
|
|
+ return {
|
|
|
+ продукты: {
|
|
|
+ пиво: { amount: 100, cost: 33 },
|
|
|
+ чипсы: { amount: 100, cost: 13 },
|
|
|
+ сиги: { amount: 100, cost: 43 },
|
|
|
+ },
|
|
|
+
|
|
|
+ касса: 0,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ if (type.toUpperCase() === "КУПИТЬ") {
|
|
|
+ let products = state["продукты"];
|
|
|
+ if (СКОКА <= 0 || СКОКА > state["продукты"][ШО]["amount"]) {
|
|
|
+ return state;
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...state, //берем все что было из ассортимента
|
|
|
+ ["продукты"]: {
|
|
|
+ ...products,
|
|
|
+ [ШО]: {
|
|
|
+ ...products[ШО],
|
|
|
+ amount: products[ШО]["amount"] - СКОКА,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ касса: +state["касса"] + +products[ШО]["cost"] * +СКОКА, //и уменьшаем то, что покупается на количество
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return state; //если мы не поняли, что от нас просят в `action` - оставляем все как есть
|
|
|
+ }
|
|
|
+
|
|
|
+ function createStore(reducer) {
|
|
|
+ let state = reducer(undefined, {}); //стартовая инициализация состояния, запуск редьюсера со state === undefined
|
|
|
+ let cbs = []; //массив подписчиков
|
|
|
+
|
|
|
+ const getState = () => state; //функция, возвращающая переменную из замыкания
|
|
|
+ const subscribe = (cb) => (
|
|
|
+ cbs.push(cb), //запоминаем подписчиков в массиве
|
|
|
+ () => (cbs = cbs.filter((c) => c !== cb))
|
|
|
+ ); //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
|
|
|
+
|
|
|
+ const dispatch = (action) => {
|
|
|
+ const newState = reducer(state, action); //пробуем запустить редьюсер
|
|
|
+ if (newState !== state) {
|
|
|
+ //проверяем, смог ли редьюсер обработать action
|
|
|
+ state = newState; //если смог, то обновляем state
|
|
|
+ for (let cb of cbs) cb(); //и запускаем подписчиков
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ return {
|
|
|
+ getState, //добавление функции getState в результирующий объект
|
|
|
+ dispatch,
|
|
|
+ subscribe, //добавление subscribe в объект
|
|
|
+ };
|
|
|
+ }
|
|
|
+ </script>
|
|
|
+ </body>
|
|
|
+</html>
|