123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- <head>
- <Header>MODULE MARKET</Header>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1" />
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
- integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous" />
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
- integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
- crossorigin="anonymous"></script>
- <link rel="stylesheet" href="https://cdn.reflowhq.com/v2/toolkit.min.css">
- <link rel="stylesheet" href="index.css">
- <style>
- .alert-fixed {
- position: fixed;
- top: 0px;
- left: 0px;
- width: 100%;
- z-index: 9999;
- border-radius: 0px;
- }
- </style>
- <div class="alert-fixed" id="alertsZone"></div>
- </head>
- <body>
- <div class="container-fluid">
- <nav class="navbar navbar-expand-md">
- <a class="navbar-brand" href="?#"><img src="./Img/Logo.png" width="140px"></a>
- <div class="collapse navbar-collapse" id="main-navigation">
- <ul class="navbar-nav align-items-center h3">
- <li id="loginLink" class="nav-item d-none">
- <a class="nav-link" href="?#/login/">Login</a>
- </li>
- <li id="regLink" class="nav-item d-none">
- <a class="nav-link" href="?#/register/">Register</a>
- </li>
- <li id="logoutLink" class="nav-item d-none">
- <a class="nav-link" href="?#/logout/">Logout</a>
- </li>
- <li id="cartLink" class="nav-item">
- <a class="nav-link" href="?#/cart/">
- <i class="fa badge fa-lg" id="cartCountBadge" value=0>
- <img src="./Img/корзина.png" width="60px">
- <!--<span class="badge badge-light" id="cartCountBadge">0</span>-->
- </i>
- </a>
- </li>
- <li id="historyLink" class="nav-item d-none">
- <a class="nav-link" href="#/orders/">History</a>
- </li>
- </ul>
- </div>
- </nav>
- </div>
- <div class="container-fluid">
- <div class="row">
- <div class="col-2 left">
- <div style="background-color: wheat;" class="d-flex flex-column flex-shrink-0 p-3 text-dark">
- <ul id="categoriesList" class="nav nav-pills flex-column mb-auto">
- </ul>
- </div>
- </div>
- <div class="col-8">
- <div id="main">
- </div>
- </div>
- </div>
- </div>
- <!--<header>
- <div>
- <a href="#/login/">Login</a>
- </div>
- <div>
- <a href="#/logout/">Logout</a>
- </div>
- <div>
- <a href="#/orders/">Orders History</a>
- </div>
- <div id='cartIcon'></div>
- <div>
- <a href="#/cart">Cart</a>
- </div>
- </header>
- <div id='mainContainer'>
- <aside id='aside'>
- </aside>
- <main id='main'>
- </main>
- </div>-->
- <script type="text/javascript" src="./login.js"></script>
- <script type="text/javascript" src="./alerts.js"></script>
- <script type="text/javascript" src="./pagination.js"></script>
- <script type="module" src="./src/store.js"></script>
- <script type="module" src="./src/reducers/localStoredReducer.js"></script>
- <script type="module" src="./src/utills/gql.js"></script>
- <script type="module" >
- import {createStore} from "./src/store.js";
- const addErrorAlert = (error) => {
- alert(error);
- }
- const store = createStore(combineReducers({ promiseReducer, authReducer, cartReducer: localStoredReducer(cartReducer, 'cart') }));
- const delay = (ms, action) => new Promise(ok => setTimeout(() => {
- action();
- ok(ms);
- }, ms));
- store.subscribe(() => {
- let state = store.getState();
- let cartItemsCount = 0;
- if (state.cartReducer) {
- let cartItems = Object.values(state.cartReducer);
- for (item of Object.values(state.cartReducer))
- cartItemsCount += item.count;
- }
- cartCountBadge.setAttribute("value", cartItemsCount);
- console.log({ state: store.getState() });
- });
- //////////////////////////////////////////////
- const addToCartBtn = (htmlEl, good) => {
- let btn = document.createElement("button");
- btn.innerText = "Add to Cart";
- btn.classList.add("ref-button");
- btn.classList.add("preview-toggle");
- btn.onclick = () => {
- store.dispatch(actionCartAdd(good));
- };
- htmlEl.appendChild(btn);
- return btn;
- }
- const fillRootCategories = (categories, htmlEl) => {
- htmlEl.innerText = '';
- if (!categories)
- return;
- let innerHtml = '';
- for (category of categories) {
- innerHtml += `<li class="h3"><a href="#/categories/${category._id}" class="nav-link text-dark">${category.name}</a></li>`;
- }
- htmlEl.innerHTML = innerHtml;
- }
- store.subscribe(() =>
- subscribePromiseItem("rootCats", categoriesList, [], fillRootCategories));
- const fillCurrentCategoryContent = (category, htmlEl) => {
- htmlEl.innerHTML = '';
- const { name, parent, subCategories, goods } = category;
- htmlEl.innerHTML = `<h1>${name}</h1>
- ${parent?.name ? `<section>Parent: <a href="#/subCategories/${parent?._id}">${parent.name}</a></section>` : ''}
- `
- if (subCategories?.length > 0) {
- htmlEl.innerHTML += '';//`<h3>Sub Categories:</h3><br>`
- for (const subCategory of subCategories) {
- htmlEl.innerHTML += `<h4><a href="#/subCategories/${subCategory._id}">${subCategory.name}</a><h4><hr/>`
- }
- }
- htmlEl.innerHTML += '';//`<section>Products:</section><br>`;
- addProductsList(goods, htmlEl)
- }
- store.subscribe(() =>
- subscribePromiseItem(
- "catFindOne", main, ["categories", "subCategories"], fillCurrentCategoryContent));
- const addProductsList = (goods, htmlEl) => {
- let outerDiv = document.createElement("div");
- outerDiv.innerHTML =
- `
- <div class="reflow-product-list">
- <div id="productsList" class="ref-products">
- </div>
- <div id="productsListPagination">
- </div>
- </div>
- `;
- htmlEl.appendChild(outerDiv);
- for (good of goods) {
- addProductToList(good, productsList);
- }
- new Pagination(productsList, productsListPagination, 5, listItemTag = 'div.ref-product')
- }
- const addProductToList = (good, htmlEl) => {
- let outerDiv = document.createElement('div');
- const { name, _id, price, description, images } = good;
- outerDiv.innerHTML =
- `
- <div id="good_${_id}" class="ref-product d-none">
- <div class="ref-media"><img class="ref-image"
- src="${getFullImageUrl(good.images[0])}" loading="lazy" /></div>
- <div class="ref-product-data">
- <div class="ref-product-info">
- <h5 class="ref-name"><a href="#/goods/${_id}">${name}</a></h5>
- <p class="ref-excerpt">${description}</p>
- </div><strong class="ref-price">$${price}</strong>
- </div>
- <div id="addCartDiv_${_id}" class="ref-addons"></div>
- </div>
- `;
- htmlEl.appendChild(outerDiv);
- let addCartDiv = document.getElementById(`addCartDiv_${_id}`);
- addToCartBtn(addCartDiv, good);
- }
- const fillCurrentGoodContent = (good, htmlEl) => {
- htmlEl.innerHTML = '';
- const { name, _id, price, description, images } = good;
- htmlEl.innerHTML = `<h1>${name}</h1>
- <section>Description: ${description}</section>
- <section>Price: ${price}</section>
- `;
- htmlEl.innerHTML += `<section>Images:</section><br>` //вставить css display block
- for (const image of images) {
- htmlEl.innerHTML += `<img width="170px" src="${"http://shop-roles.node.ed.asmer.org.ua/"}${image.url}"</img><br>`//вставить css display block
- }
- addToCartBtn(htmlEl, good);
- }
- store.subscribe(() =>
- subscribePromiseItem(
- "goodFindOne", main, ["goods"], fillCurrentGoodContent));
- const subscribePromiseItem = (promiseName, htmlEl, subscrNames, execFunc) => {
- const [, route, _id] = location.hash.split('/');
- if ((subscrNames.length > 0 && (!route || !subscrNames.some(v => v == route)))/* || !_id*/)
- return;
- let reducerData = store.getState().promiseReducer[promiseName];
- if (!reducerData)
- return;
- const { status, payload, error } = reducerData;
- if (status === 'PENDING') {
- htmlEl.innerHTML = `<img src='https://cdn.dribbble.com/users/63485/screenshots/1309731/infinite-gif-preloader.gif' />`
- }
- else if (status == "FULFILLED") {
- execFunc(payload, htmlEl);
- }
- else if (status == "FULFILLED") {
- addErrorAlert(error.message);
- }
- }
- const getFullImageUrl = (image) =>
- `http://shop-roles.node.ed.asmer.org.ua/${image?.url}`;
- const showCartContent = (cart, htmlEl) => {
- htmlEl.innerHTML = '';
- htmlEl.innerHTML = `<h1>Cart</h1>
- `;
- htmlEl.innerHTML += '';//`<section>Items:</section><br>` //вставить css display block
- let allCount = 0;
- let htmlContent = '';
- for (const item of Object.values(cart)) {
- let { count, good } = item;
- let inpId = `inp_${good._id}`;
- let delBtnId = `delBtn_${good._id}`;
- htmlContent += `
- <div>
- <img width="170px" src="${getFullImageUrl(good.images[0])}"</img>
- <a href="#/goods/${good._id}">${good.name}</a>
- <input type="number" min="1" max="999" id="${inpId}" value="${count}">
- <button class="ref-button preview-toggle" id="${delBtnId}">Remove</button>
- </div>
- <br>`//вставить css display block
- allCount += count;
- }
- htmlContent += `<div>Count ${allCount}</div><br>`;
- htmlContent += `<button class="ref-button preview-toggle" id="btnCheckout">Checkout</button><br>`;
- htmlEl.innerHTML += htmlContent;
- for (const item of Object.values(cart)) {
- let { good } = item;
- let inpId = `inp_${good._id}`;
- let delBtnId = `delBtn_${good._id}`;
- let inp = document.getElementById(inpId);
- inp.addEventListener("change", function (e) { store.dispatch(actionCartSet(good, +inp.value)); });
- let delBtn = document.getElementById(delBtnId);
- delBtn.addEventListener("click", function (e) { store.dispatch(actionCartDel(good)); });
- }
- let btnCheckout = document.getElementById("btnCheckout");
- btnCheckout.addEventListener("click", function (e) {
- window.location = "#/checkout/";
- });
- }
- store.subscribe(() =>
- subscribeSimple(
- "cartReducer", main, ["cart"], showCartContent));
- const showOrder = (order, num, htmlEl) => {
- let htmlContent = `<div class="order d-none"><h2>Order: #${num}</h2>
- <!--<div>Created on: ${order.createdAt}</div>-->
- `;
- htmlContent += `<h3>Items:</h3>` //вставить css display block
- let orderGoods = Object.values(order.orderGoods);
- for (let i = 0; i < orderGoods.length; i++) {
- let { order, count, price, total, good } = orderGoods[i];
- htmlContent +=
- `
- <div class="ref-product align-items-center">
- <strong class="ref-count">${i}. </strong>
- <div class="ref-media"><img class="ref-image" width="170px" src="${getFullImageUrl(good.images[0])}"</img></div>
- <div class="ref-product-data">
- <div class="ref-product-info">
- <h5 class="ref-name"><a href="#/goods/${good._id}">${good.name}</a></h5>
- </div>
- <strong class="ref-price">Price: ${price}</strong>
- <strong class="ref-count">Count: ${count}</strong>
- <strong class="ref-price">Total: ${total}</strong>
- </div>
- </div>
- `//вставить css display block
- }
- htmlContent += `<h3 class="ref-count">Total ${order.total}</h3><hr/></div>`;
- htmlEl.innerHTML += htmlContent;
- }
- const showOrders = (orders, htmlEl) => {
- htmlEl.innerHTML = "<header>Orders:</header>";
- if (!localStorage?.authToken)
- return;
- if (orders) {
- let ordersContainerDiv = document.createElement("div");
- ordersContainerDiv.classList.add("container", "reflow-product-list");
- let ordersDiv = document.createElement("div");
- ordersContainerDiv.appendChild(ordersDiv);
- ordersDiv.classList.add("ref-products");
- for (let i = orders.length; i > 0; i--) {
- let order = orders[i - 1];
- showOrder(order, i, ordersDiv);
- }
- let paginationDiv = document.createElement("div");
- htmlEl.append(ordersContainerDiv, paginationDiv);
- new Pagination(ordersDiv, paginationDiv, 5, listItemTag = 'div.order')
- }
- }
- store.subscribe(() =>
- subscribePromiseItem(
- "orders", main, ["orders"], showOrders));
- const subscribeSimple = (reducerName, htmlEl, subscrNames, execFunc) => {
- const [, route, _id] = location.hash.split('/');
- if (!subscrNames || !subscrNames.some(v => v == route))
- return;
- let reducerData = store.getState()[reducerName];
- execFunc(reducerData, htmlEl);
- }
- window.onhashchange = () => {
- const [, route, _id] = location.hash.split('/')
- const routes = {
- categories() {
- console.log('Category', _id)
- store.dispatch(actionCategoryFindOne(_id))
- },
- subCategories() {
- console.log('subCategory', _id)
- store.dispatch(actionCategoryFindOne(_id))
- },
- goods() {
- console.log('good', _id)
- store.dispatch(actionGoodFindOne(_id))
- },
- cart() {
- console.log('cart')
- store.dispatch(actionCartShow())
- },
- checkout() {
- console.log('checkout');
- let state = store.getState();
- if (routes.login())
- store.dispatch(orderFullUpsert(() => window.location = "#/orders/"));
- },
- orders() {
- if (!localStorage.authToken) {
- showOrders([], main);
- return;
- }
- console.log('order');
- store.dispatch(actionFindOrders());
- },
- login() {
- if (!localStorage.authToken) {
- main.innerText = '';
- const form = new LoginForm(main);
- form.onLogin = (login, password) => {
- store.dispatch(actionFullLogin(login, password));
- }
- return false;
- }
- else if (route == "login") {
- window.location = "#/";
- window.location.reload();
- }
- return true;
- },
- register() {
- if (!localStorage.authToken) {
- main.innerText = '';
- const form = new LoginForm(main);
- form.onLogin = (login, password) => {
- store.dispatch(actionFullAuthUpsert(login, password));
- }
- return false;
- }
- else if (route == "register") {
- window.location = "#/";
- window.location.reload();
- }
- return true;
- },
- logout() {
- if (localStorage.authToken) {
- store.dispatch(actionAuthLogout());
- window.location = "#/login/";
- window.location.reload();
- }
- },
- //register(){
- ////нарисовать форму регистрации, которая по нажатию кнопки Login делает store.dispatch(actionFullRegister(login, password))
- //},
- }
- if (localStorage.authToken) {
- loginLink.classList.add('d-none');
- regLink.classList.add('d-none');
- historyLink.classList.remove('d-none');
- logoutLink.classList.remove('d-none');
- }
- else {
- loginLink.classList.remove('d-none');
- regLink.classList.remove('d-none');
- historyLink.classList.add('d-none');
- logoutLink.classList.add('d-none');
- }
- if (route in routes) {
- routes[route]()
- }
- }
- window.onhashchange()
- store.dispatch(actionRootCats());
- /*store.dispatch(actionCategoryFindOne("6262ca7dbf8b206433f5b3d1"));
- store.dispatch(actionGoodFindOne("62d3099ab74e1f5f2ec1a125"));
- store.dispatch(actionFullLogin("Berg", "123456789"));
- //store.dispatch(actionFullAuthUpsert("Berg1", "12345678911"));
- store.dispatch(actionCartAdd({ _id: '62d30938b74e1f5f2ec1a124', price: 50 }));
- delay(3000, () => {
- store.dispatch(orderFullUpsert());
- store.dispatch(actionFindOrders());
- });*/
- //delay(500, () => store.dispatch(actionFindOrders()));
- </script>
- </body>
|