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 в объект } } function reducer(state, { type, ГДЕ, ШО, СКОКА, БАБЛО }) { //объект action деструктуризируется на три переменных if (!state) { //начальная уборка в ларьке: return { бухло: { пиво: { count: 100, price: 25 }, святая: { count: 100, price: 35 }, ректификат: { count: 30, price: 50 }, }, загрызнуть: { камса: { count: 80, price: 15 }, чипсы: { count: 100, price: 20 }, огурчик: { count: 35, price: 5 }, раки: { count: 15, price: 100 }, }, остальное: { сиги: { count: 100, price: 35 }, 'Даме шоколад': { count: 100, price: 35 }, }, касса: 0, 'Моя заначка': 1500//при покупках увеличивается } } if (type === 'КУПИТЬ') { if ((state[ГДЕ][ШО].count - СКОКА) < 0 || (state['Моя заначка'] - БАБЛО) < 0) { return state } else { return { ...state, //берем все что было из ассортимента [ГДЕ]: { ...state[ГДЕ], [ШО]: { ...state[ГДЕ][ШО], count: state[ГДЕ][ШО].count - СКОКА } }, касса: state.касса + БАБЛО, 'Моя заначка': state['Моя заначка'] - БАБЛО //и уменьшаем то, что покупается на количество } } } else if (type === 'ЗАТАРИТЬ') { if ((state[ГДЕ][ШО].count + СКОКА) <= 100 || (state.касса - БАБЛО) < 0) { return state } else { return { ...state, //берем все что было из ассортимента [ГДЕ]: { ...state[ГДЕ], [ШО]: { ...state[ГДЕ][ШО], count: state[ГДЕ][ШО].count + +СКОКА } }, касса: state.касса - БАБЛО, //и уменьшаем то, что покупается на количество } } } return state //если мы не поняли, что от нас просят в `action` - оставляем все как есть } const store = createStore(reducer) const table = document.createElement('table') let flag = true for (const key in store.getState()) { let optgroup = document.createElement('optgroup') optgroup.label = key for (const deepkey in store.getState()[key]) { let option = document.createElement('option') option.setAttribute('name', key) option.innerText = deepkey optgroup.append(option) createTable(key, deepkey, flag) flag = false } if (key === 'касса') createCasaCash(kassa, key) else if (key === 'Моя заначка') createCasaCash(myCash, key) else { goods.append(optgroup) flag = true } } function createTable(key, deepkey, flag) { table.setAttribute('border', '1') const tr = document.createElement('tr') const th = document.createElement('th') const tdName = document.createElement('td') const tdCount = document.createElement('td') const tdPrice = document.createElement('td') flag ? th.innerText = key : th.innerText = '' tdName.innerText = deepkey tdPrice.innerText = `Цена ${store.getState()[key][deepkey].price} грн` tdCount.innerText = ` ${store.getState()[key][deepkey].count} шт` store.subscribe(() => tdCount.innerText = store.getState()[key][deepkey].count) tr.append(th) tr.append(tdName) tr.append(tdPrice) tr.append(tdCount) table.append(tr) products.append(table) } function createCasaCash(el, key) { const tableCasa = document.createElement('table') tableCasa.setAttribute('border', '1') const tr = document.createElement('tr') const th = document.createElement('th') const td = document.createElement('td') th.innerText = key td.innerText = store.getState()[key] store.subscribe(() => td.innerText = store.getState()[key]) tr.append(th) tr.append(td) tableCasa.append(tr) el.append(tableCasa) } const findSelectedOption = (el) => el.options[el.selectedIndex].getAttribute('name') const купи = (ГДЕ, ШО, СКОКА, БАБЛО) => ({ type: 'КУПИТЬ', ГДЕ, ШО, СКОКА, БАБЛО }) const затарить = (ГДЕ, ШО, СКОКА, БАБЛО) => ({ type: 'ЗАТАРИТЬ', ГДЕ, ШО, СКОКА, БАБЛО }) buy.onclick = () => { store.dispatch(купи(findSelectedOption(goods), goods.value, quantity.value, store.getState()[findSelectedOption(goods)][goods.value].price * quantity.value)) } buyShop.onclick = () => { store.dispatch(затарить(findSelectedOption(goods), goods.value, quantity.value, store.getState()[findSelectedOption(goods)][goods.value].price * quantity.value)) } const unsubscribe = store.subscribe(() => console.log(store.getState()))