main.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. function createStore(reducer) {
  2. let state = reducer(undefined, {}); //стартовая инициализация состояния, запуск редьюсера со state === undefined
  3. let cbs = []; //массив подписчиков
  4. const getState = () => state; //функция, возвращающая переменную из замыкания
  5. const subscribe = cb => (cbs.push(cb), //запоминаем подписчиков в массиве
  6. () => cbs = cbs.filter(c => c !== cb)); //возвращаем функцию unsubscribe, которая удаляет подписчика из списка
  7. const dispatch = action => {
  8. if (typeof action === 'function') { //если action - не объект, а функция
  9. return action(dispatch, getState); //запускаем эту функцию и даем ей dispatch и getState для работы
  10. }
  11. const newState = reducer(state, action); //пробуем запустить редьюсер
  12. if (newState !== state) { //проверяем, смог ли редьюсер обработать action
  13. state = newState; //если смог, то обновляем state
  14. for (let cb of cbs) cb(); //и запускаем подписчиков
  15. }
  16. };
  17. return {
  18. getState, //добавление функции getState в результирующий объект
  19. dispatch,
  20. subscribe //добавление subscribe в объект
  21. };
  22. }
  23. function promiseReducer(state = {}, {type, name, status, payload, error}) {
  24. if (type === 'PROMISE') {
  25. return {
  26. ...state,
  27. [name]: {status, payload, error}
  28. };
  29. }
  30. return state;
  31. }
  32. function jwtDecode(token) {
  33. try {
  34. let newToken = token.split('.')[1];
  35. return JSON.parse(atob(newToken));
  36. } catch (e) {
  37. console.error(e);
  38. }
  39. //раскодировать токен:
  40. //выкусить середочку
  41. //atob
  42. //JSON.parse
  43. //на любом этапе могут быть исключения
  44. }
  45. function getTokenFromLS() {
  46. const token = localStorage.getItem('auth');
  47. return !!token && token !== 'undefined' ? {token} : {};
  48. }
  49. function authReducer(state = getTokenFromLS(), {type, token}) {
  50. if (!state) {
  51. if (localStorage.getItem('auth')) {
  52. type = 'AUTH_LOGIN';
  53. token = localStorage.getItem('auth');
  54. } else {
  55. return {};
  56. }
  57. //проверить localStorage.authToken на наличие
  58. //если есть - сделать так, что бы следующий if сработал
  59. //если нет - вернуть {}
  60. }
  61. if (type === 'AUTH_LOGIN') {
  62. // token = localStorage.getItem('authToken');
  63. let decodeToken = jwtDecode(token);
  64. //взять токен из action
  65. //попытаться его jwtDecode
  66. //если удалось, то:
  67. //сохранить токен в localStorage
  68. //вернуть объект вида {токен, payload: раскодированный токен}
  69. return {
  70. token,
  71. payload: decodeToken,
  72. };
  73. }
  74. if (type === 'AUTH_LOGOUT') {
  75. localStorage.removeItem('auth');
  76. return {};
  77. //почистить localStorage
  78. //вернуть пустой объект
  79. }
  80. console.log(state);
  81. return state;
  82. }
  83. function combineReducers(reducers) {
  84. return (state = {}, action) => {
  85. const newState = {};
  86. for (const [reducerName, reducer] of Object.entries(reducers)) {
  87. const newSubState = reducer(state[reducerName], action);
  88. if (newSubState !== state[reducerName]) {
  89. newState[reducerName] = newSubState;
  90. }
  91. }
  92. if (Object.keys(newState).length !== 0) {
  93. return {...state, ...newState};
  94. } else {
  95. return state;
  96. }
  97. //перебрать все редьюсеры
  98. //запустить каждый их них
  99. //передать при этом в него ЕГО ВЕТВЬ общего state, и action как есть
  100. //получить newSubState
  101. //если newSubState отличается от входящего, то записать newSubState в newState
  102. //после цикла, если newState не пуст, то вернуть {...state, ...newState}
  103. //иначе вернуть state
  104. };
  105. }
  106. const combinedReducer = combineReducers({promise: promiseReducer, auth: authReducer, cart: cartReducer});
  107. const store = createStore(combinedReducer);
  108. const actionAuthLogin = (token) => ({type: 'AUTH_LOGIN', token});
  109. const actionAuthLogout = () => ({type: 'AUTH_LOGOUT'});
  110. function getCartFromLS() {
  111. const cart = JSON.parse(localStorage.getItem('cart'));
  112. return !!cart ? cart : {};
  113. }//??
  114. function cartReducer(state = getCartFromLS(), {type, good = {}, count = 1}) {
  115. const {_id} = good;
  116. // const {count} = good;
  117. // {
  118. // _id1: {good, count}
  119. // _id2: {good, count}
  120. // }
  121. const types = {
  122. CART_ADD() { //как CHANGE, только если ключ раньше был, то достать из count и добавить
  123. //к count из action. Если не было, достать 0 и добавить к count из action
  124. return {
  125. ...state, //по аналогии с promiseReducer дописать
  126. [_id]: {good, count: count + (state[_id]?.count || 0)}
  127. };
  128. },
  129. CART_REMOVE() { //смочь скопировать объект и выкинуть ключ. как вариант через
  130. //деструктуризацию
  131. return Object.fromEntries(Object.entries(state).filter(([key, value]) => {
  132. return key !== _id;
  133. }));
  134. },
  135. CART_CHANGE() {
  136. return {
  137. ...state, //по аналогии с promiseReducer дописать
  138. [_id]: {good, count}
  139. };
  140. },
  141. CART_CLEAR() {
  142. return {};
  143. },
  144. };
  145. if (type in types) {
  146. return types[type]();
  147. }
  148. return state;
  149. }
  150. //понаписывать action
  151. //прикрутить к товару кнопку которая делает store.dispatch(actionCartAdd(good))
  152. // store.dispatch({type: 'CART_CHANGE', good: {_id: 'пиво', name: 'пиво'}, count: 10});
  153. // console.log(store.dispatch({type: 'CART_CHANGE', good: {_id: 'пиво', name: 'пиво'}, count: 10}));
  154. // store.dispatch({type: 'CART_CHANGE', good: {_id: 'вода', name: 'вода'}, count: 10});
  155. // store.dispatch({type: 'CART_ADD', good: {_id: 'вода', name: 'вода'}, count: 6});
  156. // store.dispatch({type: 'CART_ADD', good: {_id: 'вода', name: 'вода'}, count: 12});
  157. // store.dispatch({type: 'CART_CHANGE', good: {_id: 'сок', name: 'сок'}, count: 10});
  158. // store.dispatch({type: 'CART_REMOVE', good: {_id: 'вода', name: 'вода'}, count: 9});
  159. //ПЕРЕДЕЛАТЬ ОТОБРАЖЕНИЕ с поправкой на то, что теперь промисы не в корне state а в state.promise
  160. const actionLogin = (login, password) =>
  161. actionPromise('login', gql(`query find($login: String, $password: String){
  162. login(login:$login, password: $password)
  163. }`, {login: login, password: password}));
  164. const actionFullLogin = (login, password) =>
  165. async dispatch => {
  166. const token = await dispatch(actionLogin(login, password));
  167. if (token) {
  168. await dispatch(actionAuthLogin(token));
  169. await dispatch(actionMyOrders());
  170. }
  171. };
  172. const actionRegister = (login, password) =>
  173. actionPromise('register', gql(`mutation reg($login: String, $password: String){
  174. UserUpsert(user:{login:$login,
  175. password: $password,
  176. nick:$login}){
  177. _id login
  178. }
  179. }`, {login: login, password: password}));//actionPromise
  180. const actionFullRegister = (login, password) => //actionRegister + actionFullLogin
  181. async dispatch => {
  182. try {
  183. await dispatch(actionRegister(login, password));
  184. } catch (e) {
  185. return console.log(e);
  186. }
  187. await dispatch(actionFullLogin(login, password));
  188. };
  189. // + интерфейс к этому - форму логина, регистрации, может повесить это на #/login #/register
  190. // + #/orders показывает ваши бывшие заказы:
  191. // сделать actionMyOrders
  192. const actionCartAdd = (good, count = 1) => ({type: 'CART_ADD', good, count});
  193. const actionCartChange = (good, count = 1) => ({type: 'CART_CHANGE', good, count});
  194. const actionCartDelete = (good, count = 0) => ({type: 'CART_REMOVE', good, count});
  195. const actionCartClear = () => ({type: 'CART_CLEAR'});
  196. store.subscribe(() => console.log(store.getState()));
  197. //проверить:
  198. //поделать store.dispatch с разными action. Скопипастить токен
  199. //проверить перезагрузку страницы.
  200. const actionPending = name => ({type: 'PROMISE', status: 'PENDING', name});
  201. const actionResolved = (name, payload) => ({type: 'PROMISE', status: 'RESOLVED', name, payload});
  202. const actionRejected = (name, error) => ({type: 'PROMISE', status: 'REJECTED', name, error});
  203. const actionPromise = (name, promise) =>
  204. async dispatch => {
  205. dispatch(actionPending(name)); // 1. {delay1000: {status: 'PENDING'}}
  206. try {
  207. let payload = await promise;
  208. dispatch(actionResolved(name, payload));
  209. return payload;
  210. } catch (error) {
  211. dispatch(actionRejected(name, error));
  212. }
  213. };
  214. const getGQL = url =>
  215. (query, variables = {}) =>
  216. fetch(url, {
  217. //метод
  218. method: 'POST',
  219. headers: {
  220. //заголовок content-type
  221. 'Content-Type': 'application/json',
  222. ...(localStorage.getItem('auth') ? {'Authorization': 'Bearer ' + localStorage.getItem('auth')} : {})
  223. },
  224. //body с ключами query и variables
  225. body: JSON.stringify({query, variables})
  226. })
  227. .then(res => res.json())
  228. .then(data => {
  229. if (data.errors && !data.data)
  230. throw new Error(JSON.stringify(data.errors));
  231. return data.data[Object.keys(data.data)[0]];
  232. });
  233. const backURL = 'http://shop-roles.asmer.fs.a-level.com.ua';
  234. const gql = getGQL(`${backURL}/graphql`);
  235. const actionRootCats = () =>
  236. actionPromise('rootCats', gql(`query {
  237. CategoryFind(query: "[{\\"parent\\":null}]"){
  238. _id name
  239. }
  240. }`));
  241. const actionCatById = (_id) => //добавить подкатегории
  242. actionPromise('catById', gql(`query catById($q: String){
  243. CategoryFindOne(query: $q){
  244. _id name goods {
  245. _id name price description images {
  246. url _id good{
  247. _id name description images{
  248. _id url
  249. }
  250. }
  251. }
  252. } subCategories{
  253. _id name image{
  254. url
  255. }
  256. }
  257. }
  258. }`, {q: JSON.stringify([{_id}])}));
  259. const actionGoodById = (_id) =>
  260. actionPromise('goodById', gql(`
  261. query goodById ($good:String) {
  262. GoodFindOne(query: $good) {
  263. name
  264. description
  265. price
  266. categories {
  267. name
  268. }
  269. images {
  270. url
  271. }
  272. }
  273. }`, {good: JSON.stringify([{_id}])}));
  274. store.dispatch(actionRootCats());
  275. const actionOrder = () =>
  276. async (dispatch, getState) => {
  277. let {cart} = getState();
  278. const orderGoods = Object.entries(cart)
  279. .map(([_id, {...key}]) => ({good: {_id}, count: key.count}));
  280. let result = await dispatch(actionPromise('order', gql(`
  281. mutation newOrder($order:OrderInput){
  282. OrderUpsert(order:$order)
  283. { _id total orderGoods{
  284. price count good{
  285. name createdAt price images{
  286. url
  287. }
  288. }
  289. }
  290. }
  291. }
  292. `, {order: {orderGoods}})));
  293. if (result?._id) {
  294. dispatch(actionCartClear());
  295. }
  296. };
  297. actionMyOrders = () =>
  298. actionPromise('myOrders', gql(
  299. `query o{
  300. OrderFind(query:"[{}]"){
  301. _id total orderGoods{
  302. price count total
  303. good{
  304. createdAt name price images{
  305. url text
  306. }
  307. }
  308. }
  309. }
  310. }`));
  311. store.subscribe(() => {
  312. const {rootCats} = store.getState().promise;
  313. if (rootCats?.payload) {
  314. aside.innerHTML = '';
  315. for (const {_id, name} of rootCats?.payload) {
  316. const link = document.createElement('a');
  317. link.href = `#/category/${_id}`;
  318. link.innerText = name;
  319. aside.append(link);
  320. }
  321. }
  322. });
  323. window.onhashchange = () => {
  324. const [, route, _id] = location.hash.split('/');
  325. const routes = {
  326. category() {
  327. store.dispatch(actionCatById(_id));
  328. console.log('КАТЕГОРИИСТРАНИЦА');
  329. },
  330. good() { //задиспатчить actionGoodById
  331. store.dispatch(actionGoodById(_id));
  332. console.log('ТОВАРОСТРАНИЦА');
  333. },
  334. login() {
  335. console.log('LOGIN');
  336. main.innerHTML = '';
  337. const token = localStorage.getItem('auth');
  338. if (!token || token === 'undefined') {
  339. const h2Greeting = document.createElement('h2');
  340. h2Greeting.textContent = 'Вход в личный кабинет';
  341. const loginInput = document.createElement('input');
  342. loginInput.type = 'login';
  343. loginInput.className = 'loginInput';
  344. loginInput.placeholder = 'Логин';
  345. const pswInput = document.createElement('input');
  346. pswInput.type = 'password';
  347. pswInput.className = 'pswInput';
  348. pswInput.placeholder = 'Пароль';
  349. const buttonSend = document.createElement('button');
  350. buttonSend.className = 'buttonSend';
  351. buttonSend.textContent = 'Войти';
  352. buttonSend.onclick = () => {
  353. if (loginInput.value !== '' && pswInput.value !== '') {
  354. loginInput.style.borderColor = '#ccc';
  355. pswInput.style.borderColor = '#ccc';
  356. store.dispatch(actionFullLogin(loginInput.value, pswInput.value));
  357. console.log('нажала на логин');
  358. location.href = `#/dashboard/${_id}`;
  359. } else {
  360. loginInput.style.borderColor = 'red';
  361. pswInput.style.borderColor = 'red';
  362. loginInput.placeholder = 'Введите логин!';
  363. pswInput.placeholder = 'Введите пароль!';
  364. }
  365. };
  366. main.appendChild(h2Greeting);
  367. main.appendChild(loginInput);
  368. main.appendChild(pswInput);
  369. main.appendChild(buttonSend);
  370. const divQuestion = document.createElement('div');
  371. divQuestion.textContent = 'Вы еще не зарегистрированы?';
  372. divQuestion.className = 'divQuestion';
  373. const a = document.createElement('a');
  374. a.className = 'link';
  375. a.href = `#/register/${_id}`;
  376. a.textContent = 'Регистрация';
  377. main.appendChild(divQuestion);
  378. main.appendChild(a);
  379. console.log('Задиспатчила логин и пароль по клику');
  380. } else {
  381. location.href = `#/dashboard/${_id}`; //??
  382. console.log('перехожу в доску заказов, птмш уже авторизована');
  383. }
  384. },
  385. register() {
  386. console.log('я в форме регистрации');
  387. main.innerHTML = '';
  388. const h2Greeting = document.createElement('h2');
  389. h2Greeting.textContent = 'Регистрация нового пользователя';
  390. const loginInputForName = document.createElement('input');
  391. loginInputForName.type = 'text';
  392. loginInputForName.className = 'loginInput';
  393. loginInputForName.placeholder = 'Ваше имя';
  394. const loginInputForSurname = document.createElement('input');
  395. loginInputForSurname.type = 'text';
  396. loginInputForSurname.className = 'loginInput';
  397. loginInputForSurname.placeholder = 'Ваша фамилия';
  398. const loginInput = document.createElement('input');
  399. loginInput.type = 'text';
  400. loginInput.className = 'loginInput';
  401. loginInput.placeholder = 'Логин*';
  402. const pswInput = document.createElement('input');
  403. pswInput.type = 'password';
  404. pswInput.className = 'pswInput';
  405. pswInput.placeholder = 'Пароль*';
  406. const buttonSend = document.createElement('button');
  407. buttonSend.className = 'buttonSend';
  408. buttonSend.textContent = 'Зарегистрироваться';
  409. main.appendChild(h2Greeting);
  410. main.appendChild(loginInputForName);
  411. main.appendChild(loginInputForSurname);
  412. main.appendChild(loginInput);
  413. main.appendChild(pswInput);
  414. main.appendChild(buttonSend);
  415. buttonSend.onclick = function register(e) {
  416. store.dispatch(actionFullRegister(loginInput.value, pswInput.value));
  417. const a = document.createElement('a');
  418. a.href = `#/login/${_id}`;
  419. a.textContent = 'Войти в личный кабинет';
  420. main.appendChild(a);
  421. };
  422. console.log('передаю данные на регистрацию');
  423. },
  424. cart() {
  425. if (Object.keys(store.getState().cart).length !== 0) {
  426. main.innerHTML = '';
  427. for (const key in store.getState().cart) {
  428. const {good} = store.getState().cart[key];
  429. let {count} = store.getState().cart[key];
  430. let {name, price, images} = good;
  431. const headerName = document.createElement('h2');
  432. headerName.innerHTML = name;
  433. main.appendChild(headerName);
  434. const img = document.createElement('img');
  435. img.src = `${backURL}/${images[0].url}`;
  436. main.appendChild(img);
  437. let currentPrice = price * count;
  438. const divPrice = document.createElement('div');
  439. divPrice.innerHTML = `${currentPrice}грн`;
  440. main.appendChild(divPrice);
  441. const wrapperForCounter = document.createElement('div');
  442. wrapperForCounter.className = 'wrapperForCounter';
  443. const inputChangeNumber = document.createElement('input');
  444. inputChangeNumber.className = 'inputChangeNumber';
  445. inputChangeNumber.type = 'number';
  446. inputChangeNumber.value = count;
  447. inputChangeNumber.onclick = () => {
  448. const inputValue = inputChangeNumber.value;
  449. divPrice.innerHTML = `${price * +inputValue}грн`;
  450. store.dispatch(actionCartChange(good, +inputValue));
  451. };
  452. wrapperForCounter.appendChild(inputChangeNumber);
  453. const buttonDeleteGood = document.createElement('input');
  454. buttonDeleteGood.type = 'button';
  455. buttonDeleteGood.className = 'buttonDeleteGood';
  456. buttonDeleteGood.value = 'х';
  457. buttonDeleteGood.onclick = () => {
  458. store.dispatch(actionCartDelete(good, inputChangeNumber.value));
  459. window.location.reload()
  460. };
  461. wrapperForCounter.appendChild(buttonDeleteGood);
  462. main.appendChild(wrapperForCounter);
  463. }
  464. const buttonSend = document.createElement('button');
  465. buttonSend.className = 'buttonSend';
  466. buttonSend.textContent = 'Оформить заказ';
  467. main.appendChild(buttonSend);
  468. buttonSend.onclick = () => {
  469. store.dispatch(actionOrder(_id));
  470. location.href = `#/dashboard/${_id}`;
  471. };
  472. console.log('СТРАНИЦА КОРЗИНЫ');
  473. } else {
  474. main.innerHTML = 'Ваша корзина пуста :(';
  475. }
  476. },
  477. dashboard() {
  478. store.dispatch(actionMyOrders());
  479. main.innerHTML = '';
  480. const wrapperForPrivate = document.createElement('div');
  481. wrapperForPrivate.className = 'wrapperForPrivate';
  482. const divNameofPage = document.createElement('h2');
  483. divNameofPage.className = 'divNameofPage';
  484. divNameofPage.textContent = 'Личный кабинет';
  485. wrapperForPrivate.appendChild(divNameofPage);
  486. const buttonLogOff = document.createElement('button');
  487. buttonLogOff.className = 'buttonLogOff';
  488. buttonLogOff.textContent = 'Выход';
  489. wrapperForPrivate.appendChild(buttonLogOff);
  490. buttonLogOff.onclick = () => {
  491. store.dispatch(actionAuthLogout());
  492. main.innerHTML = 'Вы вышли с личного кабинета! До новых встреч :)'; //??
  493. };
  494. main.appendChild(wrapperForPrivate);
  495. const headerOrders = document.createElement('div');
  496. headerOrders.style.fontSize = '20px';
  497. headerOrders.textContent = 'История заказов';
  498. main.appendChild(headerOrders);
  499. console.log('СТОРЕ ДИСПАТЧ ПРОЧИТАТЬ БЫВШИЕ ЗАКАЗЫ');
  500. }
  501. };
  502. if (route in routes) {
  503. routes[route]();
  504. }
  505. };
  506. window.onhashchange();
  507. store.subscribe(() => {
  508. const [, route, _id] = location.hash.split('/');
  509. console.log(route);
  510. if (route === 'dashboard') {
  511. console.log('ДОСКА ЗАКАЗОВ');
  512. const auth = store.getState().auth;
  513. if (Object.keys(auth).length !== 0) {
  514. localStorage.setItem('auth', auth.token);
  515. const myOrders = store.getState().promise?.myOrders;
  516. if (myOrders?.payload) {
  517. myOrders?.payload.filter(order => {
  518. const {total, orderGoods} = order;
  519. if (total !== null) {
  520. const divDashboardOrders = document.createElement('h2');
  521. divDashboardOrders.className = 'divDashboardOrders';
  522. main.appendChild(divDashboardOrders);
  523. const divDescriptionOrder = document.createElement('div');
  524. divDescriptionOrder.className = 'divDescriptionOrder';
  525. const img = document.createElement('img');
  526. img.src = `${backURL}/${orderGoods[0].good.images[0].url}`;
  527. img.className = 'imgGood';
  528. divDashboardOrders.appendChild(img);
  529. const divName = document.createElement('div');
  530. divName.className = 'divName';
  531. divName.textContent = `${orderGoods[0].good.name}`;
  532. divDescriptionOrder.appendChild(divName);
  533. const wrapperForCharacteristicGood = document.createElement('div');
  534. wrapperForCharacteristicGood.className = 'wrapperForCharacteristicGood';
  535. const quantityDiv = document.createElement('div');
  536. quantityDiv.textContent = `${orderGoods[0]['count']}шт`;
  537. wrapperForCharacteristicGood.appendChild(quantityDiv);
  538. const totalDiv = document.createElement('div');
  539. totalDiv.textContent = `${order.total} грн`;
  540. totalDiv.className = 'totalDiv';
  541. wrapperForCharacteristicGood.appendChild(totalDiv);
  542. divDashboardOrders.appendChild(divDescriptionOrder);
  543. divDescriptionOrder.appendChild(wrapperForCharacteristicGood);
  544. }
  545. });
  546. }
  547. }
  548. }
  549. });
  550. store.subscribe(() => {
  551. const [, , _id] = location.hash.split('/');
  552. header.innerHTML = '';
  553. const namCat = document.createElement('div');
  554. namCat.className = 'nameGategory';
  555. namCat.textContent = 'Категории';
  556. const enter = document.createElement('a');
  557. enter.className = 'enterToPrivate';
  558. enter.textContent = 'Вход в кабинет';
  559. enter.href = `#/login/${_id}`;
  560. header.appendChild(namCat);
  561. header.appendChild(enter);
  562. }
  563. );
  564. store.subscribe(() => {
  565. const [, , _id] = location.hash.split('/');
  566. let wrapperForCart = document.createElement('div');
  567. wrapperForCart.className = 'wrapperForCart';
  568. const link = document.createElement('a');
  569. link.className = 'cart';
  570. header.appendChild(wrapperForCart);
  571. wrapperForCart.innerHTML = `
  572. <a href="#/cart/${_id}">Корзина</a>
  573. <img src="cart.png" class="cartImg">`;
  574. const cartArr = Object.values(store.getState().cart);
  575. const counter = cartArr.length === 0 ? 0 : cartArr.reduce((accum, {count}) => accum + count, 0);
  576. wrapperForCart.innerHTML = `<a href="#/cart/${_id}">Корзина ${counter}</a>
  577. <img src="cart.png" class="cartImg">`;
  578. }
  579. );
  580. store.subscribe(() => {
  581. const {catById} = store.getState().promise;
  582. const [, route, _id] = location.hash.split('/');
  583. if (catById?.payload && route === 'category') {
  584. const {name} = catById.payload;
  585. main.innerHTML = `<h1>${name}</h1> `;
  586. if (catById.payload.subCategories) {
  587. console.log('тут подкатегории');
  588. for (let good of catById.payload.subCategories) {
  589. main.innerHTML += `<h2>${good.name}</h2>`;
  590. main.innerHTML += `<a href="#/category/${good._id}">Подробнее</a>`;
  591. }
  592. }
  593. if (catById.payload.goods) {
  594. for (const good of catById.payload.goods) {
  595. const {_id, name, price, images} = good;
  596. const card = document.createElement('div');
  597. card.className = 'card';
  598. const link = document.createElement('a');
  599. card.innerHTML = `<h2>${name}</h2>
  600. <img src="${backURL}/${images[0].url}" />
  601. <strong>${price} грн</strong>
  602. <a href="#/good/${_id}">Подробнее</a>
  603. `;
  604. const buttonBuy = document.createElement('button');
  605. buttonBuy.className = 'buttonBuy';
  606. buttonBuy.textContent = 'Купить';
  607. buttonBuy.onclick = () => {
  608. store.dispatch(actionCartAdd(good, 1));
  609. };
  610. card.appendChild(buttonBuy);
  611. aside.append(link);
  612. main.append(card);
  613. }
  614. }
  615. }
  616. }
  617. );
  618. store.subscribe(() => {
  619. const {goodById} = store.getState().promise;
  620. const [, route, _id] = location.hash.split('/');
  621. if (goodById?.payload && route === 'good') {
  622. console.log('я на странице описания товара');
  623. if (location.hash.indexOf(`#/good/${_id}`) !== -1) {
  624. main.innerHTML = '';
  625. const {name, price, images, description} = goodById.payload;
  626. const card = document.createElement('div');
  627. card.innerHTML = `<h2>${name}</h2>
  628. <img src="${backURL}/${images[0].url}" />
  629. <strong>${price}</strong>
  630. <div>${description}</div>
  631. `;
  632. main.append(card);
  633. }
  634. }
  635. }
  636. );
  637. store.subscribe(() => {
  638. localStorage.setItem('cart', JSON.stringify(store.getState().cart));
  639. });