123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- 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 {
- // пиво: 100, //{count: 100, price: 30}
- // чипсы: 100,//{count: 100, price: 25}
- пиво: {count: 100, price: 30},
- чипсы: {count: 100, price: 25},
- сиги: {count: 100, price: 50},
- касса: 0, //при покупках увеличивается
- }
- }
- if (type === 'КУПИТЬ' &&
- state[ШО] && СКОКА > 0 &&
- СКОКА <= state[ШО].count && БАБОС >= state[ШО].price * СКОКА){ //если тип action - КУПИТЬ, то:
- //проверить на:
- //наличие товара как такового (есть ли ключ в объекте)
- //количество денег в action
- //наличие нужного количества товара.
- //и только при соблюдении этих условий обновлять state.
- console.log('bang')
- console.log(store.getState())
- state.касса += truncateFraction(+БАБОС)
- display_hide_error(arguments[1])
- return {
- ...state, //берем все что было из ассортимента
- [ШО]: {count: state[ШО].count - Math.floor(СКОКА), price: state[ШО].price },//и уменьшаем то, что покупается на количество
- }
- }
- display_hide_error(arguments[1])
- return state //если мы не поняли, что от нас просят в `action` - оставляем все как есть
- }
- const store = createStore(reducer)
- //надо бы напилить цикл, который в select напихивает ассортимент.
- //возможно, если вы собираетесь выводить (и обновлять) количество,
- //это надо делать где в subscribe, иначе оно не будет обновлять количество
- let select = document.getElementById('goods')
- for(let key in store.getState()) {
- if (key === 'касса') continue;
- let option = document.createElement('option')
- option.innerText = key
- option.value = key
- select.append(option)
- }
- let quantity = document.getElementById('quantity')
- let cash = document.getElementById('cash')
- const купи = (ШО, СКОКА, БАБОС) => ({type: 'КУПИТЬ', ШО, СКОКА, БАБОС})
- buy.onclick = () => {
- //достает выбранный товар и количество из DOM
- // store.dispatch(купи(....,....))
- store.dispatch(купи(select.value, quantity.value, cash.value))
- }
- //запомнит функцию во внутреннем массиве cbs.
- //она будет запущена при любом успешном dispatch
- const unsubscribe = store.subscribe(() => console.log(store.getState()))
- //setTimeout(unsubscribe, 10000) //отпишемся через 10 секунд, например
- //происходит запуск редьюсера, который создает новый state.
- //dispatch запускает всех подписчиков из массива cbs
- let errorP = document.createElement('p')
- errorP.style.color = 'red'
- errorP.style.textAlign = 'center'
- shop.append(errorP)
- function truncateFraction (number) {
- try {
- let strNum = String(number).split('.')
- if(strNum[1].length > 2) {
- strNum[1] = strNum[1].slice(0, 2)
- }
- return Number(strNum.join('.'))
- } catch (e) {
- return number
- }
- }
- function display_hide_error(obj) {
- errorP.innerText = ''
- if (obj.СКОКА === '' && obj.БАБОС === '') {
- errorP.innerText = 'Мысли я читать не умeю >:^['
- return;
- } else if(obj.СКОКА === '' || obj.СКОКА < 0) {
- errorP.innerText = 'А единиц товара сколько брать будете?'
- return;
- }
- if (obj.СКОКА > store.getState()[obj.ШО].count) {
- errorP.innerText = `У нас нет столько ${obj.ШО}. ${obj.ШО} осталось ${store.getState()[obj.ШО].count}`
- return;
- } else if (obj.БАБОС < store.getState()[obj.ШО].price * obj.СКОКА) {
- errorP.innerText = `Недостаточно денег для покупки ${obj.СКОКА} ед. ${obj.ШО}.
- ${obj.ШО} стоит ${store.getState()[obj.ШО].price} денег за 1 ед. товара
- Стоимость вашего заказа ${store.getState()[obj.ШО].price * obj.СКОКА}`
- return;
- }
- }
- let table = document.createElement('table')
- function drawTable(){
- table.innerHTML = ''
- table.insertAdjacentHTML('afterbegin', `
- <tr>
- <th>Товар</th>
- <th>Кол-во</th>
- <th>Стоимость</th>
- </tr>
- `)
-
- for(let key in store.getState()) {
- if(key === 'касса') continue;
- let tr = document.createElement('tr')
- let tdKey = document.createElement('td')
- let tdCount = document.createElement('td')
- let tdCost = document.createElement('td')
- tdKey.innerText = key
- tdCount.innerText = store.getState()[key].count
- tdCost.innerText = `${store.getState()[key].price} денег`
- tr.append(tdKey, tdCount, tdCost)
- table.append(tr)
- }
- table.insertAdjacentHTML('beforeend', `
- <tr>
- <th>Касса</th>
- <td>${store.getState().касса} денег</td>
- </tr>
- `)
- shop.append(table)
- }
- drawTable()
- store.subscribe(drawTable)
- console.log(store.getState())
|