Vika 2 years ago
parent
commit
574acf7a0f
3 changed files with 220 additions and 0 deletions
  1. 20 0
      js11/index.html
  2. 170 0
      js11/main.js
  3. 30 0
      js11/style.css

+ 20 - 0
js11/index.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width">
+        <title>Change Me</title>
+        <link href="style.css" rel="stylesheet" type="text/css" />
+    </head>
+    <body>
+        <div id='shop'>
+            <select id='goods'>
+            </select>
+            <input type='number' id='quantity' min="0"/>
+            <input type="text" id='cash' placeholder="ДЕНЬГИ ПОЖАЛУЙСТА">
+            <button id='buy'>Купить</button>
+        </div>
+        <div id='message'></div>
+        <script src="main.js"></script>
+    </body>
+</html>

+ 170 - 0
js11/main.js

@@ -0,0 +1,170 @@
+//debugger;
+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: 30},
+          чипсы:{count: 100, price: 25},
+          сиги: {count: 100, price: 35},
+          касса:{count: 0, change: 0},                              //            касса: 0, при покупках увеличивается
+      }
+  }
+  if (type === 'КУПИТЬ'){ //если тип action - КУПИТЬ, то:
+      //проверить на:
+      //наличие товара как такового (есть ли ключ в объекте)
+      //количество денег в action
+      //наличие нужного количества товара.
+      //и только при соблюдении этих условий обновлять state. 
+      if((state[ШО]['count'] - СКОКА)  < 0 ) {
+        const div = document.getElementById('message');
+        div.innerText = `столько ${ШО} нет в наличии, есть ${state[ШО]['count']}`;
+        setTimeout( () => div.innerText = '', 2500);
+        return state;
+      }
+
+      if ((БАБЛО - СКОКА* state[ШО]['price']) < 0) {
+        const div = document.getElementById('message');
+        div.innerText = `надо добавитть ${СКОКА * state[ШО]['price'] - БАБЛО} грн.`;
+        setTimeout( () => div.innerText = '', 2500);
+        return state;
+      }
+
+      if (state[ШО]) {
+        return {
+          ...state, //берем все что было из ассортимента
+          [ШО]: {
+            ...state[ШО],
+            count: state[ШО]['count'] - СКОКА,
+          } ,
+          ['касса']: {
+            ...state['касса'],
+            count: state['касса']['count'] + (СКОКА * state[ШО]['price']),
+            change: БАБЛО -  СКОКА * state[ШО]['price'],   
+          }                         //и уменьшаем то, что покупается на количество
+        }
+      }  
+  }
+
+
+  return state //если мы не поняли, что от нас просят в `action` - оставляем все как есть
+}
+
+const store = createStore(reducer); 
+
+for (let [key, value] of Object.entries(store.getState())) {
+  if(key === 'касса') {
+    continue;
+  }
+  let option = document.createElement('option');
+  option.innerHTML = `${key}`;
+  goods.append(option);
+
+}
+
+function viewStore () {
+  const table = document.createElement('table');
+  table.id = 'table';
+  document.body.prepend(table);
+  const tr = document.createElement('tr');
+  table.append(tr);
+  const th1 = document.createElement('th');
+  th1.innerText = 'Товар';
+  tr.append(th1);
+  const th2 = document.createElement('th');
+  th2.innerText = 'Количество товара';
+  tr.append(th2);
+  const th3 = document.createElement('th');
+  th3.innerText = 'Цена';
+  tr.append(th3);
+
+  for (let [key, value] of Object.entries(store.getState())) {
+   
+    const tr = document.createElement('tr');
+    const th = document.createElement('th');
+    th.style.width = '150px';
+    table.append(tr);
+    tr.appendChild(th).innerHTML = `${key}`;
+
+    for (let [key1, value1] of Object.entries(value)) {
+
+      const td = document.createElement('td');
+      td.style.width = '70px';
+      tr.appendChild(td).innerHTML =`${value1}`;
+    }
+  }
+}
+viewStore();
+
+function deleteTable () {
+  const table = document.getElementById('table');
+  table.remove();
+}
+
+store.subscribe(deleteTable);
+store.subscribe(viewStore);
+//надо бы напилить цикл, который в select напихивает ассортимент. 
+//возможно, если вы собираетесь выводить (и обновлять) количество,
+//это надо делать где в subscribe, иначе оно не будет обновлять количество
+
+const купи = (ШО, СКОКА, БАБЛО) => ({type: 'КУПИТЬ', ШО, СКОКА, БАБЛО});
+
+buy.onclick = () => { 
+  let select = document.getElementById('goods');
+  let valueSelect = select.options[select.selectedIndex].text;
+  let input = document.getElementById('quantity');
+  let valueInput = input.value;
+  let cash = document.getElementById('cash').value;
+
+  store.dispatch({type:'КУПИТЬ', ШО: `${valueSelect}`, СКОКА: `${valueInput}`, БАБЛО: `${cash}`});
+  setTimeout(() => document.getElementById('quantity').value = '', 2500);
+  setTimeout(() => document.getElementById('cash').value = '', 2500);
+};
+
+  
+//достает выбранный товар и количество из DOM +
+//    store.dispatch(купи(....,....)) +
+//запомнит функцию во внутреннем массиве cbs. 
+//она будет запущена при любом успешном dispatch 
+const unsubscribe = store.subscribe(() => console.log(store.getState())) 
+
+//setTimeout(unsubscribe, 10000) //отпишемся через 10 секунд, например
+
+//происходит запуск редьюсера, который создает новый state. 
+//dispatch запускает всех подписчиков из массива cbs
+
+// function smth(){
+//   const h1 = document.createElement('h1')
+//   shop.append(h1)
+//   store.subscribe(() => h1.innerText = store.getState().пиво)
+//   h1.innerText = store.getState().пиво
+// }
+// smth()
+// smth()
+
+//setTimeout(() => store.dispatch({type: 'КУПИТЬ', ШО: 'пиво', СКОКА: 3}), 5000)
+
+
+
+

+ 30 - 0
js11/style.css

@@ -0,0 +1,30 @@
+* {
+  box-sizing: border-box;   
+}
+
+button{
+  width: 100%;
+  font-size: 2em;
+}
+input, button, select{
+  width: 100%;
+  font-size: 2em;
+}
+
+table {
+  border: 1px;
+  border-collapse: collapse;
+}
+
+td,th {
+  border: 1px solid black;
+}
+
+#message {
+  color:red;
+  font-size: 30px;
+}
+
+/*div#content {*/
+  /*display: none;*/
+/*}*/