index.html 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>Magaz</title>
  8. <style>
  9. * *,
  10. *::before,
  11. *::after {
  12. box-sizing: border-box;
  13. margin: 0;
  14. padding: 0;
  15. }
  16. #page-wrapper {
  17. display: flex;
  18. flex-direction: column;
  19. min-height: 100vh;
  20. margin: 0 auto;
  21. max-width: 1170px;
  22. width: 100%;
  23. }
  24. #mainContainer {
  25. display: flex;
  26. flex-grow: 1;
  27. margin: 20px 0;
  28. }
  29. #header {
  30. height: 50px;
  31. background-color: #ff5319;
  32. border: 1px solid gray;
  33. padding: 10px 5px;
  34. font-size: 26px;
  35. display: flex;
  36. justify-content: space-between;
  37. }
  38. a {
  39. text-decoration: none;
  40. }
  41. #aside {
  42. min-width: 25%;
  43. font-size: 20px;
  44. padding: 0 20px 0px 0;
  45. }
  46. #aside > a {
  47. display: block;
  48. color: black;
  49. }
  50. #aside > a:hover {
  51. color: tomato;
  52. font-size: 24px;
  53. }
  54. #main {
  55. display: flex;
  56. flex-wrap: wrap;
  57. width: 100%;
  58. }
  59. #footer {
  60. text-align: center;
  61. background-color: #ff5319;
  62. border: 1px solid gray;
  63. height: 40px;
  64. }
  65. #cartImg {
  66. height: 30px;
  67. width: 30px;
  68. }
  69. #nav {
  70. display: flex;
  71. }
  72. .larekBtn {
  73. height: 50px;
  74. font-weight: bold;
  75. margin: 10px 0 0 0;
  76. border-radius: 30px;
  77. background-color: white;
  78. color: black;
  79. }
  80. .larekBtn:hover {
  81. background-color: tomato;
  82. }
  83. </style>
  84. </head>
  85. <body>
  86. <div id="page-wrapper">
  87. <header id="header">
  88. <div id="logo">Larek</div>
  89. <nav id="nav">
  90. <ul id="userAuth"></ul>
  91. <div id="cart">
  92. <a href="#/cart/" id="cartLink"
  93. ><img
  94. id="cartImg"
  95. src="https://i.pinimg.com/originals/15/4f/df/154fdf2f2759676a96e9aed653082276.png"
  96. alt=""
  97. /></a>
  98. </div>
  99. </nav>
  100. </header>
  101. <div id="mainContainer">
  102. <aside id="aside">Категории</aside>
  103. <main id="main">Контент</main>
  104. </div>
  105. <footer id="footer"></footer>
  106. </div>
  107. <script>
  108. // debugger;
  109. function createStore(reducer) {
  110. let state = reducer(undefined, {});
  111. let cbs = [];
  112. function dispatch(action) {
  113. if (typeof action === "function") {
  114. return action(dispatch);
  115. }
  116. const newState = reducer(state, action);
  117. if (state !== newState) {
  118. state = newState;
  119. cbs.forEach((cb) => cb());
  120. }
  121. }
  122. return {
  123. dispatch,
  124. subscribe(cb) {
  125. cbs.push(cb);
  126. return () => (cbs = cbs.filter((c) => c !== cb));
  127. },
  128. getState() {
  129. return state;
  130. },
  131. };
  132. }
  133. function promiseReducer(
  134. state = {},
  135. { type, status, payload, error, name }
  136. ) {
  137. if (type === "PROMISE") {
  138. return {
  139. ...state,
  140. [name]: { status, payload, error },
  141. };
  142. }
  143. return state;
  144. }
  145. function cardReducer(state = {}, { type, count = 1, good }) {
  146. if (type === "CART_ADD") {
  147. console.log("+1");
  148. const _id = good._id;
  149. return {
  150. ...state,
  151. [_id]: { count: (state[_id]?.count || 0) + count, good },
  152. };
  153. }
  154. if (type === "CART_CLEAR") {
  155. return {};
  156. }
  157. if (type === "CART_SET") {
  158. const _id = good._id;
  159. if (count == 0) {
  160. delete state[_id];
  161. } else {
  162. return {
  163. ...state,
  164. [_id]: { count, good },
  165. };
  166. }
  167. }
  168. if (type === "CART_DELETE") {
  169. const _id = good._id;
  170. if (state[_id].count - 1 === 0) {
  171. delete state[_id];
  172. return state;
  173. } else {
  174. return {
  175. ...state,
  176. [_id]: { count: state[_id]?.count - count, good },
  177. };
  178. }
  179. }
  180. return state;
  181. }
  182. function authReducer(state, action) {
  183. // { type, token }
  184. if (state === undefined) {
  185. if (localStorage.token) {
  186. //добавить в action token из localStorage,
  187. action.token = localStorage.token; //и проимитировать LOGIN (action.type = 'LOGIN')
  188. action.type = "LOGIN";
  189. } else {
  190. return {};
  191. }
  192. }
  193. if (action.type === "LOGIN") {
  194. localStorage.token = action.token; //+localStorage
  195. let { 1: tokenAverage } = action.token.split("."); //достать среднюю часть из токена (между точками)
  196. let decodedToken = atob(tokenAverage); //jwt_decode: //atob
  197. let parsedToken = JSON.parse(decodedToken); //JSON.parse
  198. return { token: action.token, payload: parsedToken }; //return {token: action.token, payload: jwt_decode(action.jwt)}
  199. }
  200. if (action.type === "LOGOUT") {
  201. console.log("ЛОГАУТ");
  202. localStorage.removeItem("token"); //-localStorage //removeItem или clear
  203. return {}; //вернуть пустой объект
  204. }
  205. return state;
  206. }
  207. const reducers = {
  208. promise: promiseReducer,
  209. cart: cardReducer,
  210. auth: authReducer,
  211. };
  212. const combineReducers = (reducers) => {
  213. return (state = {}, action) => {
  214. const newState = {};
  215. for (const [name, reducer] of Object.entries(reducers)) {
  216. // console.log(name, reducer)
  217. const newSubState = reducer(state[name], action);
  218. if (newSubState !== state[name]) {
  219. newState[name] = newSubState;
  220. }
  221. }
  222. // if (Object.keys(newState).length === 0) {
  223. // return state;
  224. // }
  225. return { ...state, ...newState };
  226. };
  227. };
  228. const store = createStore(combineReducers(reducers));
  229. const unsubscribe1 = store.subscribe(() => console.log(store.getState()));
  230. const actionPending = (name) => ({
  231. type: "PROMISE",
  232. status: "PENDING",
  233. name,
  234. });
  235. const actionResolved = (name, payload) => ({
  236. type: "PROMISE",
  237. status: "RESOLVED",
  238. name,
  239. payload,
  240. });
  241. const actionRejected = (name, error) => ({
  242. type: "PROMISE",
  243. status: "REJECTED",
  244. name,
  245. error,
  246. });
  247. const delay = (ms) => new Promise((ok) => setTimeout(() => ok(ms), ms));
  248. //store.dispatch(actionPending('delay1000'))
  249. //delay(1000).then(payload => store.dispatch(actionResolved('delay1000', payload)),
  250. //error => store.dispatch(actionRejected('delay1000', error)))
  251. const actionPromise = (name, promise) => async (dispatch) => {
  252. dispatch(actionPending(name));
  253. try {
  254. let payload = await promise;
  255. dispatch(actionResolved(name, payload));
  256. return payload;
  257. } catch (error) {
  258. dispatch(actionRejected(name, error));
  259. }
  260. };
  261. const getGQL =
  262. (url) =>
  263. (query, variables = {}) => {
  264. let headers;
  265. if (localStorage.token) {
  266. //якщо в localStorage.authToken шото есть, то наверное это надо отправить с заголовком Authorization
  267. headers = {
  268. // Accept: "application/json",
  269. "Content-Type": "application/json",
  270. Authorization: "Bearer " + localStorage.token,
  271. };
  272. } else {
  273. headers = {
  274. "Content-Type": "application/json",
  275. };
  276. }
  277. return fetch(url, {
  278. method: "POST",
  279. headers,
  280. body: JSON.stringify({ query, variables }),
  281. }).then((res) => res.json());
  282. };
  283. let shopGQL = getGQL("http://shop-roles.asmer.fs.a-level.com.ua/graphql");
  284. const actionRootCategories = () =>
  285. actionPromise(
  286. "rootCategories",
  287. shopGQL(
  288. `
  289. query cats($query:String){
  290. CategoryFind(query:$query){
  291. _id name
  292. }
  293. }
  294. `,
  295. { query: JSON.stringify([{ parent: null }]) }
  296. )
  297. );
  298. const actionCategoryById = (_id) =>
  299. actionPromise(
  300. "catById",
  301. shopGQL(
  302. `query catById($query:String){
  303. CategoryFindOne(query:$query){
  304. _id name goods{
  305. _id name price description images{
  306. url
  307. }
  308. }
  309. }
  310. }`,
  311. { query: JSON.stringify([{ _id }]) }
  312. )
  313. );
  314. const actionGoodById = (_id) =>
  315. actionPromise(
  316. "goodById",
  317. shopGQL(
  318. `query goodById($query:String){
  319. GoodFindOne(query:$query){
  320. _id name price description images {
  321. url
  322. }
  323. }
  324. }`,
  325. { query: JSON.stringify([{ _id }]) }
  326. )
  327. );
  328. //auth************************
  329. const actionGetToken = (login, password) =>
  330. actionPromise(
  331. "getToken",
  332. shopGQL(
  333. `query login($login:String, $password:String){
  334. login(login: $login, password: $password)
  335. }`,
  336. { login, password }
  337. )
  338. );
  339. const actionAuthLogin = (token) => ({ type: "LOGIN", token });
  340. const actionFullLogin = (login, password) => async (dispatch) => {
  341. let payload = await dispatch(actionGetToken(login, password));
  342. if (payload.data.login) {
  343. dispatch(actionAuthLogin(payload.data.login));
  344. }
  345. };
  346. //registration****************
  347. const actionRegister = (login, password) =>
  348. actionPromise(
  349. "register",
  350. shopGQL(
  351. `mutation reg($query:UserInput){
  352. UserUpsert(user:$query){
  353. _id login
  354. }
  355. }`,
  356. { query: { login, password } }
  357. )
  358. );
  359. const actionFullRegister = (login, password) => async (dispatch) => {
  360. let payload = await dispatch(actionRegister(login, password)); //actionRegister, который actionPromise
  361. if (payload.data.UserUpsert != null) {
  362. await dispatch(actionFullLogin(login, password)); //если удачно, делаете сразу же actionFullLogin
  363. }
  364. };
  365. //order
  366. const actionCreateOrder = (_id, count) =>
  367. actionPromise(
  368. "createdOrder",
  369. shopGQL(
  370. `mutation createOrder($order:OrderInput){
  371. OrderUpsert(order:$order){
  372. _id
  373. }
  374. }`,
  375. {
  376. order: {
  377. orderGoods: [{ count: count, good: { _id: _id } }],
  378. },
  379. }
  380. )
  381. );
  382. const actionCartAdd = (good, count = 1) => ({
  383. type: "CART_ADD",
  384. count,
  385. good,
  386. });
  387. const actionCartDelete = (good, count = 1) => ({
  388. type: "CART_DELETE",
  389. count,
  390. good,
  391. });
  392. const actionCartClear = (good, count = 1) => ({
  393. type: "CART_CLEAR",
  394. count,
  395. good,
  396. });
  397. store.dispatch(actionRootCategories());
  398. //store.dispatch(actionFullLogin("tst123", "123123"));
  399. function drawCart() {
  400. //цикл по отрисовке с картинками и редактирование количества/удалением товара
  401. //
  402. const cart = store.getState().cart;
  403. console.log("kart", cart);
  404. }
  405. window.onhashchange = () => {
  406. let { 1: route, 2: id } = location.hash.split("/");
  407. if (route === "categories") {
  408. loadAnimationFunc();
  409. store.dispatch(actionCategoryById(id));
  410. }
  411. if (route === "good") {
  412. loadAnimationFunc();
  413. store.dispatch(actionGoodById(id));
  414. }
  415. if (route === "login") {
  416. // нарисовать форму логина, которая по OK делает
  417. drawLogin();
  418. }
  419. if (route === "register") {
  420. // нарисовать форму регистрации, которая по OK делает
  421. // store.dispatch(actionFullRegister(login, password))
  422. drawRegister();
  423. }
  424. if (route === "cart") {
  425. loadAnimationFunc();
  426. drawCart();
  427. //#/cart/
  428. // //нарисовать корзину с кнопочками добавления/удаления товаров
  429. // main.innerHTML = ""
  430. // //const cart = store.getState().cart
  431. // //смочь в цикл / reduce по подсчету суммы количеств товаров и вывести куда - то в дом
  432. // //(заготовка под кошик с количеством)
  433. }
  434. };
  435. store.subscribe(drawMainMenu);
  436. store.subscribe(drawCategories);
  437. store.subscribe(drawGood);
  438. //store.subscribe(drawLogin);
  439. // store.subscribe(drawRegistration);
  440. //store.subscribe(drawCart);
  441. store.subscribe(loggedIn);
  442. function loggedIn() {
  443. const loggedIn = store.getState().auth.token;
  444. if (loggedIn) {
  445. userAuth.innerText = "";
  446. let logout = document.createElement("button");
  447. logout.innerText = "выйти";
  448. logout.onclick = () => {
  449. store.dispatch({ type: "LOGOUT" });
  450. };
  451. userAuth.appendChild(logout);
  452. } else {
  453. userAuth.innerText = "";
  454. let loginButton = document.createElement("a");
  455. loginButton.setAttribute("style", "margin-right: 10px; color:black;");
  456. loginButton.innerText = "войти";
  457. loginButton.href = "#/login/";
  458. userAuth.appendChild(loginButton);
  459. let registerButton = document.createElement("a");
  460. registerButton.setAttribute(
  461. "style",
  462. "margin-left: 10px; color:black;"
  463. );
  464. registerButton.innerText = "регистрация";
  465. registerButton.href = "#/register/";
  466. userAuth.appendChild(registerButton);
  467. }
  468. }
  469. function drawCart() {
  470. //цикл по отрисовке с картинками и редактирование количества/удалением товара
  471. //
  472. const cart = store.getState().cart;
  473. main.innerHTML = "";
  474. let divWrapper = document.createElement("div");
  475. divWrapper.setAttribute("style", "width: 100%;");
  476. let header1 = document.createElement("h1");
  477. header1.innerText = "Корзина";
  478. divWrapper.append(header1);
  479. let buttonClear = document.createElement("button");
  480. buttonClear.setAttribute(
  481. "style",
  482. "height: 30px; font-weight: bold; margin: 0 auto; border-radius: 30px; background-color: white;"
  483. );
  484. buttonClear.innerText = "Очистить";
  485. buttonClear.onclick = () => {
  486. store.dispatch(actionCartClear());
  487. };
  488. divWrapper.append(buttonClear);
  489. main.append(divWrapper);
  490. for (let key in cart) {
  491. let divCartA = document.createElement("div");
  492. divCartA.setAttribute(
  493. "style",
  494. "margin: 0 10px 10px 0; padding: 20px; width: 400px; border: 2px solid gray; display: flex; flex-direction: column; align-content: stretch "
  495. );
  496. let cartImg = document.createElement("img");
  497. cartImg.src = `http://shop-roles.asmer.fs.a-level.com.ua/${
  498. cart[`${key}`].good.images[0].url
  499. }`;
  500. let cartButtons = document.createElement("div");
  501. cartButtons.setAttribute(
  502. "style",
  503. "text-align: center; margin: 10px;"
  504. );
  505. let cartButtonAdd = document.createElement("button");
  506. let cartButtonMinus = document.createElement("button");
  507. cartButtonAdd.innerText = "+";
  508. cartButtonAdd.setAttribute(
  509. "style",
  510. "text-align: center; font-size: 22px; padding: 5px"
  511. );
  512. cartButtonMinus.innerText = "-";
  513. cartButtonMinus.setAttribute(
  514. "style",
  515. "text-align: center; font-size: 22px; padding: 5px"
  516. );
  517. cartButtonAdd.onclick = () => {
  518. store.dispatch(actionCartAdd(cart[key].good, 1));
  519. };
  520. cartButtonMinus.onclick = () => {
  521. store.dispatch(actionCartDelete(cart[key]?.good, 1));
  522. };
  523. cartButtons.append(cartButtonAdd);
  524. cartButtons.append(cartButtonMinus);
  525. let cartText = document.createElement("p");
  526. cartText.setAttribute(
  527. "style",
  528. "flex: 1 1 auto; text-align: center; font-size: 22px"
  529. );
  530. cartText.innerHTML = cart[`${key}`].good.name;
  531. let cartCountPrice = document.createElement("div");
  532. cartCountPrice.setAttribute(
  533. "style",
  534. "font-size: 20px; font-weight: bold; text-align: center;"
  535. );
  536. cartCountPrice.innerText = `Кол-во: ${cart[`${key}`].count} Цена: ${
  537. cart[`${key}`].good.price * cart[`${key}`].count
  538. } грн`;
  539. let cartButton = document.createElement("button");
  540. cartButton.classList = "larekBtn";
  541. cartButton.onclick = () => {
  542. store.dispatch(
  543. actionCreateOrder(cart[key].good._id, cart[key].count)
  544. );
  545. };
  546. cartButton.innerText = "Оплатить";
  547. divCartA.append(cartImg);
  548. divCartA.append(cartText);
  549. divCartA.append(cartCountPrice);
  550. divCartA.append(cartButtons);
  551. divCartA.append(cartButton);
  552. main.append(divCartA);
  553. }
  554. }
  555. function drawRegister() {
  556. main.innerText = "";
  557. let divLoginHolder = document.createElement("div");
  558. divLoginHolder.setAttribute("style", "margin: 0 auto;");
  559. let divLogin = document.createElement("div");
  560. divLogin.setAttribute(
  561. "style",
  562. "margin: 0 auto; padding: 20px; width: 400px; display: flex; flex-direction: column;"
  563. );
  564. let textLogin = document.createElement("p");
  565. let loginInput = document.createElement("input");
  566. textLogin.innerText = "Login";
  567. let textPassword = document.createElement("p");
  568. let passwordInput = document.createElement("input");
  569. textPassword.innerText = "Password";
  570. let authButton = document.createElement("button");
  571. authButton.innerText = "Зарегистрироваться";
  572. authButton.classList = "larekBtn";
  573. let authHeading = document.createElement("h1");
  574. authHeading.innerText = "Регистрация";
  575. divLogin.append(authHeading);
  576. divLogin.append(textLogin);
  577. divLogin.append(loginInput);
  578. divLogin.append(textPassword);
  579. divLogin.append(passwordInput);
  580. divLogin.append(authButton);
  581. authButton.onclick = async () => {
  582. if (loginInput.value && passwordInput.value) {
  583. payload = await store.dispatch(
  584. actionFullRegister(loginInput.value, passwordInput.value)
  585. );
  586. if (store.getState().auth.token) {
  587. divLogin.innerText = "";
  588. authHeading.innerText = "Welcome";
  589. authHeading.style.fontSize = "30px";
  590. divLogin.append(authHeading);
  591. divLoginHolder.append(divLogin);
  592. main.append(divLoginHolder);
  593. } else {
  594. let error = document.createElement("p");
  595. error.innerText = "Такой логин уже занят";
  596. divLogin.append(error);
  597. }
  598. }
  599. };
  600. divLoginHolder.append(divLogin);
  601. main.append(divLoginHolder);
  602. }
  603. function drawLogin() {
  604. main.innerText = "";
  605. let divLoginHolder = document.createElement("div");
  606. divLoginHolder.setAttribute("style", "margin: 0 auto;");
  607. let divLogin = document.createElement("div");
  608. divLogin.setAttribute(
  609. "style",
  610. "margin: 0 auto; padding: 20px; width: 400px; display: flex; flex-direction: column;"
  611. );
  612. let textLogin = document.createElement("p");
  613. let loginInput = document.createElement("input");
  614. textLogin.innerText = "Login";
  615. let textPassword = document.createElement("p");
  616. let passwordInput = document.createElement("input");
  617. textPassword.innerText = "Password";
  618. let authButton = document.createElement("button");
  619. authButton.innerText = "Войти";
  620. authButton.classList = "larekBtn";
  621. let authHeading = document.createElement("h1");
  622. authHeading.innerText = "Авторизация";
  623. divLogin.append(authHeading);
  624. divLogin.append(textLogin);
  625. divLogin.append(loginInput);
  626. divLogin.append(textPassword);
  627. divLogin.append(passwordInput);
  628. divLogin.append(authButton);
  629. authButton.onclick = async () => {
  630. if (loginInput.value && passwordInput.value) {
  631. payload = await store.dispatch(
  632. actionFullLogin(loginInput.value, passwordInput.value)
  633. );
  634. if (store.getState().auth.token) {
  635. divLogin.innerText = "";
  636. authHeading.innerText = "Welcome";
  637. authHeading.style.fontSize = "30px";
  638. divLogin.append(authHeading);
  639. divLoginHolder.append(divLogin);
  640. main.append(divLoginHolder);
  641. } else {
  642. let error = document.createElement("p");
  643. error.innerText = "Неверный логин или пароль";
  644. divLogin.append(error);
  645. }
  646. }
  647. };
  648. divLoginHolder.append(divLogin);
  649. main.append(divLoginHolder);
  650. }
  651. function drawMainMenu() {
  652. //debugger;
  653. let cats = store.getState().promise.rootCategories.payload;
  654. if (cats) {
  655. //Каждый раз дорисовываются в body
  656. aside.innerText = "";
  657. for (let { _id, name } of cats.data.CategoryFind) {
  658. let catA = document.createElement("a");
  659. catA.href = `#/categories/${_id}`;
  660. catA.innerText = name;
  661. aside.append(catA);
  662. }
  663. }
  664. }
  665. function drawCategories() {
  666. //debugger;
  667. const { 1: route, 2: id } = location.hash.split("/");
  668. if (route === "categories") {
  669. const catById = store.getState().promise.catById?.payload;
  670. if (catById) {
  671. main.innerText = "";
  672. // Вывести категорию(название)
  673. let h1 = document.createElement("h1");
  674. h1.setAttribute("style", "width: 100%;");
  675. h1.innerText = catById.data.CategoryFindOne.name;
  676. main.append(h1);
  677. // Вывести циклом товары со ссылками вида # / good / АЙДИШНИК
  678. for (let { _id, name, description, price, images } of catById.data
  679. .CategoryFindOne.goods) {
  680. //тута
  681. let divGoodA = document.createElement("div");
  682. divGoodA.setAttribute(
  683. "style",
  684. "margin: 0 10px 10px 0; padding: 20px; width: 400px; border: 2px solid gray; display: flex; flex-direction: column; align-content: stretch "
  685. );
  686. divGoodA.onmousemove = () =>
  687. (divGoodA.style.borderColor = "#FF7373");
  688. divGoodA.onmouseout = () => (divGoodA.style.borderColor = "gray");
  689. //background - color: #FF5319;
  690. let goodImg = document.createElement("img");
  691. goodImg.src = `http://shop-roles.asmer.fs.a-level.com.ua/${images[0].url}`;
  692. let goodLink = document.createElement("a");
  693. goodLink.setAttribute(
  694. "style",
  695. "flex: 1 1 auto; text-align: center; font-size: 22px"
  696. );
  697. goodLink.href = `#/good/${_id}`;
  698. goodLink.innerHTML = name;
  699. let goodPrice = document.createElement("div");
  700. goodPrice.setAttribute(
  701. "style",
  702. "font-size: 20px; font-weight: bold; text-align: center;"
  703. );
  704. goodPrice.innerText = `Цена: ${price} грн`;
  705. let goodButton = document.createElement("button");
  706. goodButton.classList = "larekBtn";
  707. goodButton.innerText = "Купить";
  708. goodButton.onclick = () =>
  709. (window.location.href = `#/good/${_id}`);
  710. divGoodA.append(goodImg);
  711. divGoodA.append(goodLink);
  712. divGoodA.append(goodPrice);
  713. divGoodA.append(goodButton);
  714. main.append(divGoodA);
  715. }
  716. // main.innerHTML = `<pre>${JSON.stringify(catById, null, 4)}</pre>`
  717. }
  718. }
  719. if (route === "cart") {
  720. // нарисовать корзину с кнопочками добавления/удаления товаров
  721. //
  722. //const cart = store.getState().cart
  723. drawCart();
  724. }
  725. }
  726. function drawGood() {
  727. // debugger;
  728. //когда появится actionGoodById и ссылки на товары это заработает
  729. const { 1: route, 2: id } = location.hash.split("/");
  730. if (route === "good") {
  731. const goodById = store.getState().promise.goodById?.payload;
  732. if (goodById) {
  733. let main = document.getElementById("main");
  734. main.innerHTML = "";
  735. let divGoodB = document.createElement("div");
  736. divGoodB.setAttribute(
  737. "style",
  738. "margin: 0 10px 10px 25px; padding: 20px; display: flex; flex-direction: column;"
  739. );
  740. let goodImg1 = document.createElement("img");
  741. goodImg1.src = `http://shop-roles.asmer.fs.a-level.com.ua/${goodById.data.GoodFindOne.images[0].url}`;
  742. let goodLink1 = document.createElement("h1");
  743. goodLink1.setAttribute(
  744. "style",
  745. "text-align: center; font-size: 22px"
  746. );
  747. goodLink1.innerHTML = goodById.data.GoodFindOne.name;
  748. let goodDescription1 = document.createElement("div");
  749. goodDescription1.setAttribute("style", "margin: 20px; ");
  750. goodDescription1.innerText = goodById.data.GoodFindOne.description;
  751. let goodPrice1 = document.createElement("h1");
  752. goodPrice1.setAttribute(
  753. "style",
  754. "font-size: 20px; font-weight: bold; text-align: center;"
  755. );
  756. goodPrice1.innerText = `Цена: ${goodById.data.GoodFindOne.price} грн`;
  757. let goodButton1 = document.createElement("button");
  758. goodButton1.classList = "larekBtn";
  759. goodButton1.innerText = "Купить";
  760. goodButton1.onclick = () => {
  761. store.dispatch(actionCartAdd(goodById.data.GoodFindOne));
  762. };
  763. divGoodB.append(goodImg1);
  764. divGoodB.append(goodLink1);
  765. divGoodB.append(goodDescription1);
  766. divGoodB.append(goodPrice1);
  767. divGoodB.append(goodButton1);
  768. main.append(divGoodB);
  769. // вывести в main страницу товаров
  770. }
  771. }
  772. }
  773. function loadAnimationFunc() {
  774. main.innerHTML = "";
  775. let loadAnimationContainer = document.createElement("div");
  776. loadAnimationContainer.setAttribute(
  777. "style",
  778. "width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;"
  779. );
  780. main.append(loadAnimationContainer);
  781. let loadAnimation = document.createElement("img");
  782. loadAnimation.src =
  783. "https://image.flaticon.com/icons/png/512/2492/2492765.png";
  784. loadAnimation.setAttribute(
  785. "style",
  786. "width: 50px; height: 50px; animation: load 1s linear infinite;"
  787. );
  788. loadAnimation.animate([{ transform: "rotate(360deg)" }], {
  789. duration: 1000,
  790. iterations: Infinity,
  791. });
  792. loadAnimationContainer.append(loadAnimation);
  793. }
  794. </script>
  795. </body>
  796. </html>