Gql_promis.html 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. <Header>MODULE MARKET</Header>
  2. <body>
  3. <header>
  4. <div>
  5. <a href="?#/login/">Login</a>
  6. </div>
  7. <div>
  8. <a href="?#/logout/">Logout</a>
  9. </div>
  10. <div>
  11. <a href="?#/orders/">Orders History</a>
  12. </div>
  13. <div id='cartIcon'></div>
  14. <div>
  15. <a href="?#/cart">Cart</a>
  16. </div>
  17. </header>
  18. <div id='mainContainer'>
  19. <aside id='aside'>
  20. </aside>
  21. <main id='main'>
  22. </main>
  23. </div>
  24. <script type="text/javascript" src="./login.js"></script>
  25. <script>
  26. function jwtDecode(token) { // расщифровки токена авторизации
  27. if (!token || typeof token != "string")
  28. return undefined;
  29. let tokenArr = token.split(".");
  30. if (tokenArr.length != 3)
  31. return undefined;
  32. try {
  33. let tokenJsonStr = atob(tokenArr[1]);
  34. let tokenJson = JSON.parse(tokenJsonStr);
  35. return tokenJson;
  36. }
  37. catch {
  38. return undefined;
  39. }
  40. }
  41. function combineReducers(reducers) {
  42. function totalReducer(totalState = {}, action) {
  43. const newTotalState = {} //объект, который будет хранить только новые состояния дочерних редьюсеров
  44. //цикл + квадратные скобочки позволяют написать код, который будет работать с любыми количеством дочерных редьюсеров
  45. for (const [reducerName, childReducer] of Object.entries(reducers)) {
  46. const newState = childReducer(totalState[reducerName], action) //запуск дочернего редьюсера
  47. if (newState !== totalState[reducerName]) { //если он отреагировал на action
  48. newTotalState[reducerName] = newState //добавляем его в newTotalState
  49. }
  50. }
  51. //Универсальная проверка на то, что хотя бы один дочерний редьюсер создал новый стейт:
  52. if (Object.values(newTotalState).length) {
  53. return { ...totalState, ...newTotalState } //создаем новый общий стейт, накладывая новый стейты дочерних редьюсеров на старые
  54. }
  55. return totalState //если экшен не был понят ни одним из дочерних редьюсеров, возвращаем общий стейт как был.
  56. }
  57. return totalReducer
  58. }
  59. function cartReducer(state = {}, action) { // диспетчер обработки
  60. switch (action.type) {
  61. case 'CART_ADD':
  62. if (action.count >= 0) {
  63. let newState = { ...state };
  64. let { count } = state[action.good._id] ?? { count: 0 };
  65. newState[action.good._id] = { count: action.count + count, good: { ...action.good } }
  66. return newState;
  67. }
  68. case 'CART_SUB':
  69. if (action.count >= 0) {
  70. let newState = { ...state };
  71. let { count } = state[action.good._id] ?? { count: 0 };
  72. if (count >= action.count) {
  73. newState[action.good._id] = { count: action.count - count, good: { ...action.good } }
  74. return newState;
  75. }
  76. }
  77. break;
  78. case 'CART_DEL':
  79. {
  80. let newState = { ...state };
  81. delete newState[action.good._id];
  82. return newState;
  83. }
  84. case 'CART_SET':
  85. {
  86. let newState = { ...state };
  87. newState[action.good._id] = { count: action.count, good: { ...action.good } };
  88. return newState;
  89. }
  90. case 'CART_SHOW':
  91. {
  92. return newState = { ...state };
  93. }
  94. case 'CART_CLEAR':
  95. return {};
  96. }
  97. return state;
  98. }
  99. function localStoredReducer(originalReducer, localStorageKey) {
  100. function wrapper(state, action) {
  101. if (!state) { /////проверка на первичность запуска !state
  102. try {
  103. return JSON.parse(localStorage[localStorageKey]);
  104. }
  105. catch { }
  106. }
  107. let res = originalReducer(state, action);
  108. localStorage[localStorageKey] = JSON.stringify(res);
  109. return res;
  110. }
  111. return wrapper
  112. }
  113. function promiseReducer(state = {}, action) { // диспетчер обработки
  114. if (action) {
  115. if (action.type === 'PROMISE') {
  116. let newState = { ...state };
  117. newState[action.name] = { status: action.status, payload: action.payload, error: action.error };
  118. return newState;
  119. }
  120. }
  121. return state;
  122. }
  123. function authReducer(state = {}, action) { // диспетчер обработки login
  124. if (action) {
  125. if (action.type === 'AUTH_LOGIN') {
  126. let newState = { ...state };
  127. newState.token = action.token;
  128. newState.payload = jwtDecode(action.token);
  129. if (!newState.payload) {
  130. newState.token = undefined;
  131. }
  132. if (newState.token)
  133. localStorage.authToken = newState.token;
  134. else
  135. delete localStorage.authToken;
  136. window.onhashchange();
  137. return newState;
  138. }
  139. else if (action.type === 'AUTH_LOGOUT') {
  140. let newState = { ...state };
  141. newState.token = undefined;
  142. newState.payload = undefined;
  143. delete localStorage.authToken;
  144. window.onhashchange();
  145. return newState;
  146. }
  147. }
  148. return state;
  149. }
  150. function createStore(reducer) {
  151. let state = reducer(undefined, {}) //стартовая инициализация состояния, запуск редьюсера со state === undefined
  152. let cbs = [] //массив подписчиков
  153. const getState = () => { return state; } //функция, возвращающая переменную из замыкания
  154. const subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве
  155. () => cbs = cbs.filter(c => c !== cb)) //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
  156. function dispatch(action) {
  157. if (typeof action === 'function') { //если action - не объект, а функция
  158. return action(dispatch, getState) //запускаем эту функцию и даем ей dispatch и getState для работы
  159. }
  160. const newState = reducer(state, action) //пробуем запустить редьюсер
  161. if (newState !== state) { //проверяем, смог ли редьюсер обработать action
  162. state = newState //если смог, то обновляем state
  163. for (let cb of cbs) cb() //и запускаем подписчиков
  164. }
  165. }
  166. return {
  167. getState, //добавление функции getState в результирующий объект
  168. dispatch,
  169. subscribe //добавление subscribe в объект
  170. }
  171. }
  172. function getGql(url) {
  173. return function gql(query, vars = undefined) {
  174. let fetchSettings =
  175. {
  176. method: "POST",
  177. headers:
  178. {
  179. "Content-Type": "application/json",
  180. "Accept": "application/json"
  181. },
  182. body: JSON.stringify(
  183. {
  184. query: query,
  185. variables: vars
  186. })
  187. };
  188. let authToken = window.localStorage.authToken;
  189. if (authToken) {
  190. fetchSettings.headers["Authorization"] = `Bearer ${authToken}`;
  191. }
  192. return fetch(url, fetchSettings)
  193. .then(res => {
  194. if (!res.ok) {
  195. throw Error(res.statusText);
  196. }
  197. return res.json();
  198. });
  199. }
  200. }
  201. const gql = getGql("http://shop-roles.node.ed.asmer.org.ua/graphql");
  202. const actionPromise = (name, promise) => {
  203. return actionPromiseInt = async (dispatch) => {
  204. dispatch(actionPending(name)) //сигнализируем redux, что промис начался
  205. try {
  206. let payload = await promise //ожидаем промиса
  207. if (payload && payload.data)
  208. payload = Object.values(payload.data)[0];
  209. dispatch(actionFulfilled(name, payload)) //сигнализируем redux, что промис успешно выполнен
  210. return payload //в месте запуска store.dispatch с этим thunk можно так же получить результат промиса
  211. }
  212. catch (error) {
  213. console.log(error);
  214. dispatch(actionRejected(name, error)) //в случае ошибки - сигнализируем redux, что промис несложился
  215. }
  216. }
  217. }
  218. const actionPending = (name) => ({ type: 'PROMISE', name: name, status: 'PENDING' });
  219. const actionFulfilled = (name, payload) => ({ type: 'PROMISE', name: name, payload: payload, status: 'FULFILLED' });
  220. const actionRejected = (name, error) => ({ type: 'PROMISE', name: name, error: error, status: 'REJECTED' });
  221. const actionAuthLogin = token => ({ type: 'AUTH_LOGIN', token });
  222. const actionAuthLogout = () => ({ type: 'AUTH_LOGOUT' });
  223. const actionCartAdd = (good, count = 1) => ({ type: 'CART_ADD', count: count, good: good });
  224. const actionCartSub = (good, count = 1) => ({ type: 'CART_SUB', count, good }); //Уменьшение количества товара. Должен уменьшать количество товара в state, или удалять его если количество будет 0 или отрицательным
  225. const actionCartDel = (good) => ({ type: 'CART_DEL', good }); //Удаление товара. Должен удалять ключ из state
  226. const actionCartSet = (good, count = 1) => ({ type: 'CART_SET', count, good }); //Задание количества товара. В отличие от добавления и уменьшения, не учитывает того количества, которое уже было в корзине, а тупо назначает количество поверху (или создает новый ключ, если в корзине товара не было). Если count 0 или отрицательное число - удаляем ключ из корзины;
  227. const actionCartShow = (good, count = 1) => ({ type: 'CART_SHOW', count, good }); //Задание количества товара. В отличие от добавления и уменьшения, не учитывает того количества, которое уже было в корзине, а тупо назначает количество поверху (или создает новый ключ, если в корзине товара не было). Если count 0 или отрицательное число - удаляем ключ из корзины;
  228. const actionCartClear = () => ({ type: 'CART_CLEAR' }); //Очистка корзины. state должен стать пустым объектом {}
  229. ///////////////////////////////////////
  230. const gqlRootCats = () => {
  231. const catQuery = `query roots {
  232. CategoryFind(query: "[{\\"parent\\": null }]") {
  233. _id name
  234. }}`;
  235. return gql(catQuery);
  236. }
  237. const actionRootCats = () =>
  238. actionPromise('rootCats', gqlRootCats());
  239. const gqlCategoryFindOne = (id) => {
  240. const catQuery = `query CategoryFindOne($q: String) {
  241. CategoryFindOne(query: $q) {
  242. _id name
  243. parent { _id name }
  244. subCategories { _id name }
  245. goods { _id name price description
  246. images { url }
  247. }
  248. }
  249. }`;
  250. return gql(catQuery, { q: `[{\"_id\": \"${id}\"}]` });
  251. }
  252. const actionCategoryFindOne = (id) =>
  253. actionPromise('catFindOne', gqlCategoryFindOne(id));
  254. const gqlGoodFindOne = (id) => {
  255. const catQuery = `
  256. query GoodFindOne($q: String) {
  257. GoodFindOne(query: $q) {
  258. _id name price description
  259. images { url }
  260. }
  261. }
  262. `;
  263. return gql(catQuery, { q: `[{\"_id\": \"${id}\"}]` });
  264. }
  265. const actionGoodFindOne = (id) =>
  266. actionPromise('goodFindOne', gqlGoodFindOne(id));
  267. //////////////////////////////////
  268. const actionLogin = (login, password) => {
  269. const upsertQuery = `query login($login:String, $password:String){
  270. login(login:$login, password:$password)
  271. }`;
  272. return gql(upsertQuery, { login: login, password: password });
  273. }
  274. const actionFullLogin = (login, password) => {
  275. return gqlFullLogin = async (dispatch) => {
  276. delete localStorage.authToken;
  277. //dispatch возвращает то, что вернул thunk, возвращаемый actionLogin, а там промис,
  278. //так как actionPromise возвращает асинхронную функцию
  279. let promiseResult = dispatch((dispatch) => actionLogin(login, password));
  280. let res = await promiseResult;
  281. if (res && res.data) {
  282. let token = Object.values(res.data)[0];
  283. if (token && typeof token == 'string')
  284. return dispatch(actionAuthLogin(token));
  285. }
  286. //проверьте что token - строка и отдайте его в actionAuthLogin
  287. }
  288. }
  289. ////////////////////////////////////////
  290. const actionAuthUpsert = (login, password) => {
  291. const loginQuery = `mutation UserRegistration($login: String, $password: String) {
  292. UserUpsert(user: {login: $login, password: $password}) {
  293. _id createdAt
  294. }
  295. }`;
  296. return gql(loginQuery, { login: login, password: password });////////
  297. }
  298. const actionFullAuthUpsert = (login, password) => {
  299. return gqlFullAuthUpsert = async (dispatch) => {
  300. //dispatch возвращает то, что вернул thunk, возвращаемый actionLogin, а там промис,
  301. //так как actionPromise возвращает асинхронную функцию
  302. delete localStorage.authToken;
  303. let promiseResult = dispatch(() => actionAuthUpsert(login, password));
  304. let res = await promiseResult;
  305. dispatch(actionFullLogin(login, password));
  306. console.log(res)
  307. //проверьте что token - строка и отдайте его в actionAuthLogin
  308. }
  309. }
  310. ////////////////////////////////////////
  311. const orderUpsert = (order, id = null) => {
  312. const orderUpsertQuery = `mutation OrderUpsert($order: OrderInput) {
  313. OrderUpsert(order: $order) {
  314. _id
  315. }
  316. }`;
  317. return gql(orderUpsertQuery, { order: { "_id": id, "orderGoods": order } });
  318. }
  319. const orderFullUpsert = (then) => {
  320. return gqlFullOrderUpsert = async (dispatch, getState) => {
  321. let state = getState();
  322. let order = [];
  323. for (cartItem of Object.values(state.cartReducer)) {
  324. //{count: 3, good: {_id: "xxxx" }}
  325. order.push({ good: { _id: cartItem.good._id }, count: cartItem.count });
  326. }
  327. if (order.length > 0) {
  328. //dispatch возвращает то, что вернул thunk, возвращаемый actionLogin, а там промис,
  329. //так как actionPromise возвращает асинхронную функцию
  330. let promiseResult = orderUpsert(order);
  331. let res = await promiseResult;
  332. if (res && res.errors && res.errors.length > 0) {
  333. throw res.errors[0];
  334. }
  335. dispatch(actionCartClear());
  336. }
  337. if (then)
  338. then();
  339. //проверьте что token - строка и отдайте его в actionAuthLogin
  340. }
  341. }
  342. const gqlFindOrders = () => {
  343. const findOrdersQuery = `query OrderFind {
  344. OrderFind(query: "[{}]") {
  345. _id total
  346. orderGoods {
  347. _id price count total createdAt
  348. good {
  349. name
  350. images { url }
  351. }
  352. }
  353. }
  354. }`;
  355. return gql(findOrdersQuery);
  356. }
  357. const actionFindOrders = () =>
  358. actionPromise('orders', gqlFindOrders());
  359. ///////////////////////////////////////////////////
  360. const store = createStore(combineReducers({ promiseReducer, authReducer, cartReducer: localStoredReducer(cartReducer, 'cart') }));
  361. const delay = (ms, action) => new Promise(ok => setTimeout(() => {
  362. action();
  363. ok(ms);
  364. }, ms));
  365. store.subscribe(() => {
  366. console.log({ state: store.getState() });
  367. });
  368. //////////////////////////////////////////////
  369. const addToCartBtn = (htmlEl, good) => {
  370. let btn = document.createElement("button");
  371. btn.innerText = "Add to Cart";
  372. btn.onclick = () => {
  373. store.dispatch(actionCartAdd(good));
  374. };
  375. htmlEl.appendChild(btn);
  376. }
  377. const fillRootCategories = (categories, htmlEl) => {
  378. htmlEl.innerText = '';
  379. if (!categories)
  380. return;
  381. for (category of categories) {
  382. let el = document.createElement('a');
  383. el.innerText = `${category.name}`;
  384. el.href = `#/categories/${category._id}`;
  385. htmlEl.appendChild(el);
  386. }
  387. }
  388. store.subscribe(() =>
  389. subscribePromiseItem("rootCats", aside, [], fillRootCategories));
  390. const fillCurrentCategoryContent = (category, htmlEl) => {
  391. htmlEl.innerHTML = '';
  392. const { name, parent, subCategories, goods } = category;
  393. htmlEl.innerHTML = `<h1>Category: ${name}</h1>
  394. <section>Parent: <a href="#/subCategories/${parent?._id}">${parent?.name ?? 'Empty'}</a></section>
  395. `
  396. if (subCategories?.length > 0) {
  397. htmlEl.innerHTML += `<section>Sub Categories:</section><br>`
  398. for (const subCategory of subCategories) {
  399. htmlEl.innerHTML += `<a href="#/subCategories/${subCategory._id}">${subCategory.name}</a><br>`
  400. }
  401. }
  402. htmlEl.innerHTML += `<section>Sub Categories:</section><br>`
  403. for (const good of goods) {
  404. let goodDiv = document.createElement("div");
  405. goodDiv.innerHTML += `<a href="#/goods/${good._id}">${good.name}</a><br>`//вставить css display block
  406. htmlEl.innerHTML += `<img width="50px" src="${"http://shop-roles.node.ed.asmer.org.ua/"}${good?.images[0]?.url}"</img><br>`//вставить css display block
  407. addToCartBtn(goodDiv, good);
  408. htmlEl.appendChild(goodDiv);
  409. }
  410. }
  411. store.subscribe(() =>
  412. subscribePromiseItem(
  413. "catFindOne", main, ["categories", "subCategories"], fillCurrentCategoryContent));
  414. const fillCurrentGoodContent = (good, htmlEl) => {
  415. htmlEl.innerHTML = '';
  416. const { name, _id, price, description, images } = good;
  417. htmlEl.innerHTML = `<h1>Good: ${name}</h1>
  418. <section>Description: ${description}</section>
  419. <section>Price: ${price}</section>
  420. `;
  421. htmlEl.innerHTML += `<section>Images:</section><br>` //вставить css display block
  422. for (const image of images) {
  423. htmlEl.innerHTML += `<img width="170px" src="${"http://shop-roles.node.ed.asmer.org.ua/"}${image.url}"</img><br>`//вставить css display block
  424. }
  425. addToCartBtn(htmlEl, good);
  426. }
  427. store.subscribe(() =>
  428. subscribePromiseItem(
  429. "goodFindOne", main, ["goods"], fillCurrentGoodContent));
  430. const subscribePromiseItem = (promiseName, htmlEl, subscrNames, execFunc) => {
  431. const [, route, _id] = location.hash.split('/');
  432. if ((subscrNames.length > 0 && (!route || !subscrNames.some(v => v == route)))/* || !_id*/)
  433. return;
  434. let reducerData = store.getState().promiseReducer[promiseName];
  435. if (!reducerData)
  436. return;
  437. const { status, payload, error } = reducerData;
  438. if (status === 'PENDING') {
  439. htmlEl.innerHTML = `<img src='https://cdn.dribbble.com/users/63485/screenshots/1309731/infinite-gif-preloader.gif' />`
  440. }
  441. if (status == "FULFILLED") {
  442. execFunc(payload, htmlEl);
  443. }
  444. }
  445. const showCartContent = (cart, htmlEl) => {
  446. htmlEl.innerHTML = '';
  447. htmlEl.innerHTML = `<h1>Cart</h1>
  448. `;
  449. htmlEl.innerHTML += `<section>Items:</section><br>` //вставить css display block
  450. let allCount = 0;
  451. let htmlContent = '';
  452. for (const item of Object.values(cart)) {
  453. let { count, good } = item;
  454. let inpId = `inp_${good._id}`;
  455. let delBtnId = `delBtn_${good._id}`;
  456. htmlContent += `
  457. <div>
  458. <img width="170px" src="${"http://shop-roles.node.ed.asmer.org.ua/"}${good.images[0].url}"</img>
  459. <a href="#/goods/${good._id}">${good.name}</a>
  460. <input type="number" min="1" max="999" id="${inpId}" value="${count}">
  461. <button id="${delBtnId}">Remove</button>
  462. </div>
  463. <br>`//вставить css display block
  464. allCount += count;
  465. }
  466. htmlContent += `<div>Count ${allCount}</div><br>`;
  467. htmlContent += `<button id="btnCheckout">Checkout</button><br>`;
  468. htmlEl.innerHTML += htmlContent;
  469. for (const item of Object.values(cart)) {
  470. let { good } = item;
  471. let inpId = `inp_${good._id}`;
  472. let delBtnId = `delBtn_${good._id}`;
  473. let inp = document.getElementById(inpId);
  474. inp.addEventListener("change", function (e) { store.dispatch(actionCartSet(good, +inp.value)); });
  475. let delBtn = document.getElementById(delBtnId);
  476. delBtn.addEventListener("click", function (e) { store.dispatch(actionCartDel(good)); });
  477. }
  478. let btnCheckout = document.getElementById("btnCheckout");
  479. btnCheckout.addEventListener("click", function (e) {
  480. window.location = "#/checkout/";
  481. });
  482. }
  483. store.subscribe(() =>
  484. subscribeSimple(
  485. "cartReducer", main, ["cart"], showCartContent));
  486. const showOrder = (order, num, htmlEl) => {
  487. let htmlContent = `<h1>Order: #${num}</h1>
  488. <!--<div>Created on: ${order.createdAt}</div>-->
  489. `;
  490. htmlContent += `<section>Items:</section><br>` //вставить css display block
  491. let orderGoods = Object.values(order.orderGoods);
  492. for (let i = 0; i < orderGoods.length; i++) {
  493. let { order, count, price, total, good } = orderGoods[i];
  494. htmlContent += `
  495. <div>
  496. <div>${i}.</div>
  497. <a href="#/goods/${good._id}">${good.name}</a>
  498. <div>Price: ${price}</div>
  499. <div>Count: ${count}</div>
  500. <div>Total: ${total}</div>
  501. <img width="170px" src="${"http://shop-roles.node.ed.asmer.org.ua/"}${good.images[0].url}"</img>
  502. </div>
  503. <br>`//вставить css display block
  504. }
  505. htmlContent += `<div>Total ${order.total}</div><br>`;
  506. htmlEl.innerHTML += htmlContent;
  507. }
  508. const showOrders = (orders, htmlEl) => {
  509. main.innerHTML = "<header>Orders:</header>";
  510. if (!localStorage?.authToken)
  511. return;
  512. if (orders) {
  513. for (let i = 0; i < orders.length; i++) {
  514. let order = orders[i];
  515. showOrder(order, i, htmlEl);
  516. }
  517. }
  518. }
  519. store.subscribe(() =>
  520. subscribePromiseItem(
  521. "orders", main, ["orders"], showOrders));
  522. const subscribeSimple = (reducerName, htmlEl, subscrNames, execFunc) => {
  523. const [, route, _id] = location.hash.split('/');
  524. if (!subscrNames || !subscrNames.some(v => v == route))
  525. return;
  526. let reducerData = store.getState()[reducerName];
  527. execFunc(reducerData, htmlEl);
  528. }
  529. window.onhashchange = () => {
  530. const [, route, _id] = location.hash.split('/')
  531. const routes = {
  532. categories() {
  533. console.log('Category', _id)
  534. store.dispatch(actionCategoryFindOne(_id))
  535. },
  536. subCategories() {
  537. console.log('subCategory', _id)
  538. store.dispatch(actionCategoryFindOne(_id))
  539. },
  540. goods() {
  541. console.log('good', _id)
  542. store.dispatch(actionGoodFindOne(_id))
  543. },
  544. cart() {
  545. console.log('cart')
  546. store.dispatch(actionCartShow())
  547. },
  548. checkout() {
  549. console.log('checkout');
  550. let state = store.getState();
  551. if (routes.login())
  552. store.dispatch(orderFullUpsert(() => window.location = "#/orders/"));
  553. },
  554. orders() {
  555. if (!localStorage.authToken) {
  556. showOrders([], main);
  557. return;
  558. }
  559. console.log('order');
  560. store.dispatch(actionFindOrders());
  561. },
  562. login() {
  563. if (!localStorage.authToken) {
  564. main.innerText = '';
  565. const form = new LoginForm(main);
  566. form.onLogin = (login, password) => {
  567. store.dispatch(actionFullAuthUpsert(login, password));
  568. }
  569. return false;
  570. }
  571. else {
  572. window.location = "#/";
  573. window.location.reload();
  574. return true;
  575. }
  576. },
  577. logout() {
  578. if (localStorage.authToken) {
  579. store.dispatch(actionAuthLogout());
  580. window.location = "#/login/";
  581. window.location.reload();
  582. }
  583. },
  584. //register(){
  585. ////нарисовать форму регистрации, которая по нажатию кнопки Login делает store.dispatch(actionFullRegister(login, password))
  586. //},
  587. }
  588. if (route in routes) {
  589. routes[route]()
  590. }
  591. }
  592. window.onhashchange()
  593. store.dispatch(actionRootCats());
  594. /*store.dispatch(actionCategoryFindOne("6262ca7dbf8b206433f5b3d1"));
  595. store.dispatch(actionGoodFindOne("62d3099ab74e1f5f2ec1a125"));
  596. store.dispatch(actionFullLogin("Berg", "123456789"));
  597. //store.dispatch(actionFullAuthUpsert("Berg1", "12345678911"));
  598. store.dispatch(actionCartAdd({ _id: '62d30938b74e1f5f2ec1a124', price: 50 }));
  599. delay(3000, () => {
  600. store.dispatch(orderFullUpsert());
  601. store.dispatch(actionFindOrders());
  602. });*/
  603. //delay(500, () => store.dispatch(actionFindOrders()));
  604. </script>
  605. </body>