From e8310ae78b2cfd33265a41af21668e7deb66a3ed Mon Sep 17 00:00:00 2001 From: Chuzhikov Danil Date: Thu, 11 Mar 2021 19:44:58 +0300 Subject: [PATCH 1/5] hw2 --- index.html | 16 ++++++++++++ script.js | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 index.html create mode 100644 script.js diff --git a/index.html b/index.html new file mode 100644 index 0000000..dd40b1b --- /dev/null +++ b/index.html @@ -0,0 +1,16 @@ + + + + eShop + + +
+ +
+
+
+
+ + + + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..678fa9c --- /dev/null +++ b/script.js @@ -0,0 +1,75 @@ +class ApiMock { + constructor() { + + } + + fetch() { + return [{ + title: 'Shirt', + price: 150 + }, + { + title: 'Socks', + price: 50 + }, + { + title: 'Jacket', + price: 350 + }, + { + title: 'Shoes', + price: 250 + }, + ]; + } +} + +class GoodsItem { + constructor(title, price) { + this.title = title; + this.price = price; + } + + getHtml() { + return `

${this.title}

${this.price}

`; + } +} + +class GoodsList { + constructor() { + this.api = new ApiMock(); + this.$goodsList = document.querySelector('.goods-list'); + this.goods = []; + } + + fetchGoods() { + this.goods = this.api.fetch().map(({ + title, + price + }) => new GoodsItem(title, price)); + } + + render() { + this.$goodsList.textContent = ''; + this.goods.forEach((good) => { + this.$goodsList.insertAdjacentHTML('beforeend', good.getHtml()); + }) + } + + goodsPrice() { + return this.goods.reduce((sum, { + price + }) => sum + price, 0); + } + +} + +class Basket {} + +class ProductsInBasket {} + +const goodsList = new GoodsList(); + +goodsList.fetchGoods(); +goodsList.render(); +goodsList.goodsPrice(); \ No newline at end of file From 84933910d9dc357452e12093e0d095bb2439bd6d Mon Sep 17 00:00:00 2001 From: Chuzhikov Danil Date: Mon, 15 Mar 2021 19:30:16 +0300 Subject: [PATCH 2/5] hw3 --- css/normalize.css | 349 ++++++++++++++++++++++++++++++++++++++++++++++ css/style.css | 171 +++++++++++++++++++++++ index.html | 30 +++- js/script.js | 218 +++++++++++++++++++++++++++++ script.js | 75 ---------- 5 files changed, 762 insertions(+), 81 deletions(-) create mode 100644 css/normalize.css create mode 100644 css/style.css create mode 100644 js/script.js delete mode 100644 script.js diff --git a/css/normalize.css b/css/normalize.css new file mode 100644 index 0000000..192eb9c --- /dev/null +++ b/css/normalize.css @@ -0,0 +1,349 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Render the `main` element consistently in IE. + */ + +main { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; +} diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..801db80 --- /dev/null +++ b/css/style.css @@ -0,0 +1,171 @@ +body{ + font-family: 'SF Pro Display', sans-serif; +} +header{ + display: flex; + background-color: #2f2a2d; + justify-content: space-between; + color: #fafafa; + padding: 30px 80px; +} +button:focus{ + outline: none; +} +.logo{ + + text-transform: uppercase; + font-weight: bold; +} +.btn-cart{ + background-color: #fafafa; + padding: 10px 20px; + border: 1px solid transparent; + color: #2f2a2d; + border-radius: 5px; + transition: all ease-in-out .4s; + cursor: pointer; +} +.btn-cart:hover{ + background-color: transparent; + border-color: #fafafa; + color: #fafafa; +} +.btn-cart, .logo{ + align-self: center; +} +/*.products {*/ +/*display: flex;*/ +/*justify-content: space-between;*/ +/*flex-wrap: wrap;*/ +/*padding: 40px 80px;*/ +/*}*/ +.products{ + column-gap: 30px; + display: grid; + grid-template-columns: repeat(auto-fit, 200px); + grid-template-rows: 1fr; + padding: 40px 80px; + justify-content: space-between; +} +p { + margin: 0 0 5px 0; +} +.product-item{ + display: flex; + flex-direction: column; + width: 200px; + border-radius: 5px; + overflow: hidden; + margin: 20px 0; +} +img { + max-width: 100%; + height: auto +} +.desc { + border: 1px solid #c0c0c040; + padding: 15px +} +.cart{ + position: relative; +} +.cart-block{ + box-shadow: 0 0 5px rgba(0, 0, 0, 0.62); + border-radius: 5px; + box-sizing: border-box; + right: 0; + top: 130%; + position: absolute; + background-color: white; + padding: 20px; + color: black; + width: 300px; +} + +.invisible{ + display: none; +} +.cart-block:before{ + content: ''; + width: 0; + height: 0; + position: absolute; + top: -10px; + right: 35px; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-bottom: 10px solid white; +} + +.buy-btn, .del-btn{ + margin-top: 5px; + background-color: #2f2a2d; + padding: 5px 15px; + border: 1px solid transparent; + color: #fafafa; + border-radius: 5px; + transition: all ease-in-out .4s; + cursor: pointer; +} +.buy-btn:hover, .del-btn:hover{ + background-color: #fafafa; + color: #2f2a2d; + border: 1px solid #2f2a2d; +} +.cart-item { + display: flex; + justify-content: space-between; +} +.cart-item:not(:last-child){ + margin-bottom: 20px; +} +.product-bio{ + display: flex; +} +.cart-item img{ + align-self: flex-start; + margin-right: 15px; +} +.product-single-price{ + color: #474747; + font-size: 0.5em; +} +.product-price{ + margin-left: 30px; +} +.product-desc{ + max-width: 150px; +} +.product-quantity { + margin-top: 15px; + font-size: 0.75em; +} +.right-block{ + text-align: right; +} +.btn-search { + background-color: transparent; + border: none; + color: #fafafa; + font-size: 1.2em; + position: absolute; + bottom: 5px; + right: 0; +} +.search-form{ + position: relative; + margin-right: 50px; + display: inline-block; +} +.search-field:focus{ + outline: none; +} +.search-field { + box-sizing: border-box; + width: 200px; + color: #fafafa; + padding: 10px; + background-color: transparent; + border: none; + border-bottom: 2px solid #fafafa; +} diff --git a/index.html b/index.html index dd40b1b..6623e74 100644 --- a/index.html +++ b/index.html @@ -1,16 +1,34 @@ - + + - eShop + + Интернет-магазин + + +
- + +
+
+ + +
+ + +
-
+
- - + + + \ No newline at end of file diff --git a/js/script.js b/js/script.js new file mode 100644 index 0000000..34762fe --- /dev/null +++ b/js/script.js @@ -0,0 +1,218 @@ +const API = + "https://raw.githubusercontent.com/GeekBrainsTutorial/online-store-api/master/responses"; + +class List { + constructor(url, container, list = listContext) { + this.container = container; + this.list = list; + this.url = url; + this.goods = []; + this.allProducts = []; + this.filtered = []; + this._init(); + } + + getJson(url) { + return fetch(url ? url : `${API + this.url}`) + .then((result) => result.json()) + .catch((error) => { + console.log(error); + }); + } + + handleData(data) { + this.goods = [...data]; + this.render(); + } + + calcSum() { + return this.allProducts.reduce((accum, item) => (accum += item.price), 0); + } + render() { + const block = document.querySelector(this.container); + for (let product of this.goods) { + console.log(this.constructor.name); + const productObj = new this.list[this.constructor.name](product); + console.log(productObj); + this.allProducts.push(productObj); + block.insertAdjacentHTML("beforeend", productObj.render()); + } + } + + filter(value) { + const regexp = new RegExp(value, "i"); + this.filtered = this.allProducts.filter((product) => + regexp.test(product.product_name) + ); + this.allProducts.forEach((el) => { + const block = document.querySelector( + `.product-item[data-id="${el.id_product}"]` + ); + if (!this.filtered.includes(el)) { + block.classList.add("invisible"); + } else { + block.classList.remove("invisible"); + } + }); + } + _init() { + return false; + } +} + +class Item { + constructor(el, img = "https://placehold.it/200x150") { + this.product_name = el.product_name; + this.price = el.price; + this.id_product = el.id_product; + this.img = img; + } + render() { + return ``; + } +} + +class ProductsList extends List { + constructor(cart, container = ".products", url = "/catalogData.json") { + super(url, container); + this.cart = cart; + this.getJson().then((data) => this.handleData(data)); + } + + _init() { + document.querySelector(this.container).addEventListener("click", (e) => { + if (e.target.classList.contains("buy-btn")) { + this.cart.addProduct(e.target); + } + }); + document.querySelector(".search-form").addEventListener("submit", (e) => { + e.preventDefault(); + this.filter(document.querySelector(".search-field").value); + }); + } +} + +class ProductItem extends Item { + render() { + return `
+ Some img +
+

${this.product_name}

+

${this.price} ₽

+ +
+
`; + } +} + +class Cart extends List { + constructor(container = ".cart-block", url = "/getBasket.json") { + super(url, container); + this.getJson().then((data) => { + this.handleData(data.contents); + }); + } + + addProduct(element) { + this.getJson(`${API}/addToBasket.json`).then((data) => { + if (data.result === 1) { + let productId = +element.dataset["id"]; + let find = this.allProducts.find( + (product) => product.id_product === productId + ); + if (find) { + find.quantity++; + this._updateCart(find); + } else { + let product = { + id_product: productId, + price: +element.dataset["price"], + product_name: element.dataset["name"], + quantity: 1, + }; + + this.goods = [product]; + this.render(); + } + } else { + alert("Error"); + } + }); + } + + removeProduct(element) { + this.getJson(`${API}/deleteFromBasket.json`).then((data) => { + if (data.result === 1) { + let productId = +element.dataset["id"]; + let find = this.allProducts.find( + (product) => product.id_product === productId + ); + if (find.quantity > 1) { + find.quantity--; + this._updateCart(find); + } else { + this.allProducts.splice(this.allProducts.indexOf(find), 1); + document.querySelector(`.cart-item[data-id="${productId}"]`).remove(); + } + } else { + alert("Error"); + } + }); + } + + _updateCart(product) { + let block = document.querySelector( + `.cart-item[data-id="${product.id_product}"]` + ); + block.querySelector( + ".product-quantity" + ).textContent = `Количество: ${product.quantity}`; + block.querySelector(".product-price").textContent = `${product.quantity * product.price + } ₽`; + } + _init() { + document.querySelector(".btn-cart").addEventListener("click", () => { + document.querySelector(this.container).classList.toggle("invisible"); + }); + document.querySelector(this.container).addEventListener("click", (e) => { + if (e.target.classList.contains("del-btn")) { + this.removeProduct(e.target); + } + }); + } +} + +class CartItem extends Item { + constructor(el, img = "https://placehold.it/50x100") { + super(el, img); + this.quantity = el.quantity; + } + render() { + return `
+
+ Some image +
+

${this.product_name}

+

Количество: ${this.quantity}

+

${this.price} за ед.

+
+
+
+

${this.quantity * this.price} ₽

+ +
+
`; + } +} + +const listContext = { + ProductsList: ProductItem, + Cart: CartItem, +}; + +let cart = new Cart(); +let products = new ProductsList(cart); \ No newline at end of file diff --git a/script.js b/script.js deleted file mode 100644 index 678fa9c..0000000 --- a/script.js +++ /dev/null @@ -1,75 +0,0 @@ -class ApiMock { - constructor() { - - } - - fetch() { - return [{ - title: 'Shirt', - price: 150 - }, - { - title: 'Socks', - price: 50 - }, - { - title: 'Jacket', - price: 350 - }, - { - title: 'Shoes', - price: 250 - }, - ]; - } -} - -class GoodsItem { - constructor(title, price) { - this.title = title; - this.price = price; - } - - getHtml() { - return `

${this.title}

${this.price}

`; - } -} - -class GoodsList { - constructor() { - this.api = new ApiMock(); - this.$goodsList = document.querySelector('.goods-list'); - this.goods = []; - } - - fetchGoods() { - this.goods = this.api.fetch().map(({ - title, - price - }) => new GoodsItem(title, price)); - } - - render() { - this.$goodsList.textContent = ''; - this.goods.forEach((good) => { - this.$goodsList.insertAdjacentHTML('beforeend', good.getHtml()); - }) - } - - goodsPrice() { - return this.goods.reduce((sum, { - price - }) => sum + price, 0); - } - -} - -class Basket {} - -class ProductsInBasket {} - -const goodsList = new GoodsList(); - -goodsList.fetchGoods(); -goodsList.render(); -goodsList.goodsPrice(); \ No newline at end of file From cb48d32767bc05be1c619817489b11a0bb7ba358 Mon Sep 17 00:00:00 2001 From: Chuzhikov Danil Date: Thu, 18 Mar 2021 18:25:22 +0300 Subject: [PATCH 3/5] homework_4 without * --- regex_replace/replace.js | 4 ++++ regex_replace/replace_quotes.html | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 regex_replace/replace.js create mode 100644 regex_replace/replace_quotes.html diff --git a/regex_replace/replace.js b/regex_replace/replace.js new file mode 100644 index 0000000..1ef53f8 --- /dev/null +++ b/regex_replace/replace.js @@ -0,0 +1,4 @@ +let text = document.getElementById('text'); +document.getElementById('replace').addEventListener('click', ()=>{ + text.textContent = text.textContent.replace(/\B'|'\B/g, '"'); +}); \ No newline at end of file diff --git a/regex_replace/replace_quotes.html b/regex_replace/replace_quotes.html new file mode 100644 index 0000000..119da32 --- /dev/null +++ b/regex_replace/replace_quotes.html @@ -0,0 +1,31 @@ + + + + + + + + Document + + + +

Lorem ipsum dolor sit amet consectetur adipisicing elit. Architecto 'possimus suscipit delectus illo' cupiditate. + Iste inventore at culpa nulla! Praesentium veritatis molestiae neque possimus modi iusto dolorum soluta + reprehenderit excepturi deserunt, blanditiis, quidem omnis. Ipsam eligendi, vitae expedita laborum, unde tenetur + sed ullam, dolore nihil illo blanditiis ad consectetur provident beatae eius quod deserunt. Id quae, mollitia + illo repellat deleniti officiis inventore numquam beatae ab 'debitis', recusandae, ut voluptas optio adipisci + accusantium. Ducimus, officiis provident, ratione saepe suscipit velit illo soluta aspernatur aliquam atque eos + nisi iure dolorum don't dignissimos in. Accusamus nulla, atque perferendis iusto nemo numquam doloremque + error molestiae voluptatem corporis sit quisquam minus neque recusandae aliquid harum. 'Facilis fugiat eaque + perferendis quam explicabo! Harum numquam porro placeat, explicabo perspiciatis similique doloribus', saepe + facere dignissimos quia odit architecto rem, isn't aut omnis optio earum perferendis cupiditate eaque dolore + nobis. Ab pariatur quod ut perspiciatis expedita quasi. Magnam repellendus sapiente fugit officiis? Odio, in + optio eaque ipsa alias magnam et repellat molestias aren't eum amet, tempora, voluptatem itaque? Architecto, + asperiores doloremque ad culpa nobis libero! 'Ducimus error asperiores sapiente nesciunt earum non cupiditate + eveniet impedit assumenda' ratione libero aut atque odit, eaque provident tempore inventore doloremque est quos + sint?

+ + + + + \ No newline at end of file From de09255216d96371456aa9c3a73cce104decd418 Mon Sep 17 00:00:00 2001 From: Chuzhikov Danil Date: Mon, 29 Mar 2021 15:47:22 +0300 Subject: [PATCH 4/5] gitignore --- .gitignore | 116 ++++++++++ README.md | 1 - css/normalize.css | 349 ------------------------------ css/style.css | 171 --------------- index.html | 34 --- js/script.js | 218 ------------------- regex_replace/replace.js | 4 - regex_replace/replace_quotes.html | 31 --- 8 files changed, 116 insertions(+), 808 deletions(-) create mode 100644 .gitignore delete mode 100644 README.md delete mode 100644 css/normalize.css delete mode 100644 css/style.css delete mode 100644 index.html delete mode 100644 js/script.js delete mode 100644 regex_replace/replace.js delete mode 100644 regex_replace/replace_quotes.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f22b9c --- /dev/null +++ b/.gitignore @@ -0,0 +1,116 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* diff --git a/README.md b/README.md deleted file mode 100644 index fc9fd69..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# JS_Advanced \ No newline at end of file diff --git a/css/normalize.css b/css/normalize.css deleted file mode 100644 index 192eb9c..0000000 --- a/css/normalize.css +++ /dev/null @@ -1,349 +0,0 @@ -/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ - -/* Document - ========================================================================== */ - -/** - * 1. Correct the line height in all browsers. - * 2. Prevent adjustments of font size after orientation changes in iOS. - */ - -html { - line-height: 1.15; /* 1 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/* Sections - ========================================================================== */ - -/** - * Remove the margin in all browsers. - */ - -body { - margin: 0; -} - -/** - * Render the `main` element consistently in IE. - */ - -main { - display: block; -} - -/** - * Correct the font size and margin on `h1` elements within `section` and - * `article` contexts in Chrome, Firefox, and Safari. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/* Grouping content - ========================================================================== */ - -/** - * 1. Add the correct box sizing in Firefox. - * 2. Show the overflow in Edge and IE. - */ - -hr { - box-sizing: content-box; /* 1 */ - height: 0; /* 1 */ - overflow: visible; /* 2 */ -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -pre { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/* Text-level semantics - ========================================================================== */ - -/** - * Remove the gray background on active links in IE 10. - */ - -a { - background-color: transparent; -} - -/** - * 1. Remove the bottom border in Chrome 57- - * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. - */ - -abbr[title] { - border-bottom: none; /* 1 */ - text-decoration: underline; /* 2 */ - text-decoration: underline dotted; /* 2 */ -} - -/** - * Add the correct font weight in Chrome, Edge, and Safari. - */ - -b, -strong { - font-weight: bolder; -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -code, -kbd, -samp { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/** - * Add the correct font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` elements from affecting the line height in - * all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Remove the border on images inside links in IE 10. - */ - -img { - border-style: none; -} - -/* Forms - ========================================================================== */ - -/** - * 1. Change the font styles in all browsers. - * 2. Remove the margin in Firefox and Safari. - */ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; /* 1 */ - font-size: 100%; /* 1 */ - line-height: 1.15; /* 1 */ - margin: 0; /* 2 */ -} - -/** - * Show the overflow in IE. - * 1. Show the overflow in Edge. - */ - -button, -input { /* 1 */ - overflow: visible; -} - -/** - * Remove the inheritance of text transform in Edge, Firefox, and IE. - * 1. Remove the inheritance of text transform in Firefox. - */ - -button, -select { /* 1 */ - text-transform: none; -} - -/** - * Correct the inability to style clickable types in iOS and Safari. - */ - -button, -[type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; -} - -/** - * Remove the inner border and padding in Firefox. - */ - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; -} - -/** - * Restore the focus styles unset by the previous rule. - */ - -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; -} - -/** - * Correct the padding in Firefox. - */ - -fieldset { - padding: 0.35em 0.75em 0.625em; -} - -/** - * 1. Correct the text wrapping in Edge and IE. - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove the padding so developers are not caught out when they zero out - * `fieldset` elements in all browsers. - */ - -legend { - box-sizing: border-box; /* 1 */ - color: inherit; /* 2 */ - display: table; /* 1 */ - max-width: 100%; /* 1 */ - padding: 0; /* 3 */ - white-space: normal; /* 1 */ -} - -/** - * Add the correct vertical alignment in Chrome, Firefox, and Opera. - */ - -progress { - vertical-align: baseline; -} - -/** - * Remove the default vertical scrollbar in IE 10+. - */ - -textarea { - overflow: auto; -} - -/** - * 1. Add the correct box sizing in IE 10. - * 2. Remove the padding in IE 10. - */ - -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Correct the cursor style of increment and decrement buttons in Chrome. - */ - -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * 1. Correct the odd appearance in Chrome and Safari. - * 2. Correct the outline style in Safari. - */ - -[type="search"] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} - -/** - * Remove the inner padding in Chrome and Safari on macOS. - */ - -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * 1. Correct the inability to style clickable types in iOS and Safari. - * 2. Change font properties to `inherit` in Safari. - */ - -::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} - -/* Interactive - ========================================================================== */ - -/* - * Add the correct display in Edge, IE 10+, and Firefox. - */ - -details { - display: block; -} - -/* - * Add the correct display in all browsers. - */ - -summary { - display: list-item; -} - -/* Misc - ========================================================================== */ - -/** - * Add the correct display in IE 10+. - */ - -template { - display: none; -} - -/** - * Add the correct display in IE 10. - */ - -[hidden] { - display: none; -} diff --git a/css/style.css b/css/style.css deleted file mode 100644 index 801db80..0000000 --- a/css/style.css +++ /dev/null @@ -1,171 +0,0 @@ -body{ - font-family: 'SF Pro Display', sans-serif; -} -header{ - display: flex; - background-color: #2f2a2d; - justify-content: space-between; - color: #fafafa; - padding: 30px 80px; -} -button:focus{ - outline: none; -} -.logo{ - - text-transform: uppercase; - font-weight: bold; -} -.btn-cart{ - background-color: #fafafa; - padding: 10px 20px; - border: 1px solid transparent; - color: #2f2a2d; - border-radius: 5px; - transition: all ease-in-out .4s; - cursor: pointer; -} -.btn-cart:hover{ - background-color: transparent; - border-color: #fafafa; - color: #fafafa; -} -.btn-cart, .logo{ - align-self: center; -} -/*.products {*/ -/*display: flex;*/ -/*justify-content: space-between;*/ -/*flex-wrap: wrap;*/ -/*padding: 40px 80px;*/ -/*}*/ -.products{ - column-gap: 30px; - display: grid; - grid-template-columns: repeat(auto-fit, 200px); - grid-template-rows: 1fr; - padding: 40px 80px; - justify-content: space-between; -} -p { - margin: 0 0 5px 0; -} -.product-item{ - display: flex; - flex-direction: column; - width: 200px; - border-radius: 5px; - overflow: hidden; - margin: 20px 0; -} -img { - max-width: 100%; - height: auto -} -.desc { - border: 1px solid #c0c0c040; - padding: 15px -} -.cart{ - position: relative; -} -.cart-block{ - box-shadow: 0 0 5px rgba(0, 0, 0, 0.62); - border-radius: 5px; - box-sizing: border-box; - right: 0; - top: 130%; - position: absolute; - background-color: white; - padding: 20px; - color: black; - width: 300px; -} - -.invisible{ - display: none; -} -.cart-block:before{ - content: ''; - width: 0; - height: 0; - position: absolute; - top: -10px; - right: 35px; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-bottom: 10px solid white; -} - -.buy-btn, .del-btn{ - margin-top: 5px; - background-color: #2f2a2d; - padding: 5px 15px; - border: 1px solid transparent; - color: #fafafa; - border-radius: 5px; - transition: all ease-in-out .4s; - cursor: pointer; -} -.buy-btn:hover, .del-btn:hover{ - background-color: #fafafa; - color: #2f2a2d; - border: 1px solid #2f2a2d; -} -.cart-item { - display: flex; - justify-content: space-between; -} -.cart-item:not(:last-child){ - margin-bottom: 20px; -} -.product-bio{ - display: flex; -} -.cart-item img{ - align-self: flex-start; - margin-right: 15px; -} -.product-single-price{ - color: #474747; - font-size: 0.5em; -} -.product-price{ - margin-left: 30px; -} -.product-desc{ - max-width: 150px; -} -.product-quantity { - margin-top: 15px; - font-size: 0.75em; -} -.right-block{ - text-align: right; -} -.btn-search { - background-color: transparent; - border: none; - color: #fafafa; - font-size: 1.2em; - position: absolute; - bottom: 5px; - right: 0; -} -.search-form{ - position: relative; - margin-right: 50px; - display: inline-block; -} -.search-field:focus{ - outline: none; -} -.search-field { - box-sizing: border-box; - width: 200px; - color: #fafafa; - padding: 10px; - background-color: transparent; - border: none; - border-bottom: 2px solid #fafafa; -} diff --git a/index.html b/index.html deleted file mode 100644 index 6623e74..0000000 --- a/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - Интернет-магазин - - - - - -
- -
-
- - -
- - -
-
-
-
-
- - - - - \ No newline at end of file diff --git a/js/script.js b/js/script.js deleted file mode 100644 index 34762fe..0000000 --- a/js/script.js +++ /dev/null @@ -1,218 +0,0 @@ -const API = - "https://raw.githubusercontent.com/GeekBrainsTutorial/online-store-api/master/responses"; - -class List { - constructor(url, container, list = listContext) { - this.container = container; - this.list = list; - this.url = url; - this.goods = []; - this.allProducts = []; - this.filtered = []; - this._init(); - } - - getJson(url) { - return fetch(url ? url : `${API + this.url}`) - .then((result) => result.json()) - .catch((error) => { - console.log(error); - }); - } - - handleData(data) { - this.goods = [...data]; - this.render(); - } - - calcSum() { - return this.allProducts.reduce((accum, item) => (accum += item.price), 0); - } - render() { - const block = document.querySelector(this.container); - for (let product of this.goods) { - console.log(this.constructor.name); - const productObj = new this.list[this.constructor.name](product); - console.log(productObj); - this.allProducts.push(productObj); - block.insertAdjacentHTML("beforeend", productObj.render()); - } - } - - filter(value) { - const regexp = new RegExp(value, "i"); - this.filtered = this.allProducts.filter((product) => - regexp.test(product.product_name) - ); - this.allProducts.forEach((el) => { - const block = document.querySelector( - `.product-item[data-id="${el.id_product}"]` - ); - if (!this.filtered.includes(el)) { - block.classList.add("invisible"); - } else { - block.classList.remove("invisible"); - } - }); - } - _init() { - return false; - } -} - -class Item { - constructor(el, img = "https://placehold.it/200x150") { - this.product_name = el.product_name; - this.price = el.price; - this.id_product = el.id_product; - this.img = img; - } - render() { - return ``; - } -} - -class ProductsList extends List { - constructor(cart, container = ".products", url = "/catalogData.json") { - super(url, container); - this.cart = cart; - this.getJson().then((data) => this.handleData(data)); - } - - _init() { - document.querySelector(this.container).addEventListener("click", (e) => { - if (e.target.classList.contains("buy-btn")) { - this.cart.addProduct(e.target); - } - }); - document.querySelector(".search-form").addEventListener("submit", (e) => { - e.preventDefault(); - this.filter(document.querySelector(".search-field").value); - }); - } -} - -class ProductItem extends Item { - render() { - return `
- Some img -
-

${this.product_name}

-

${this.price} ₽

- -
-
`; - } -} - -class Cart extends List { - constructor(container = ".cart-block", url = "/getBasket.json") { - super(url, container); - this.getJson().then((data) => { - this.handleData(data.contents); - }); - } - - addProduct(element) { - this.getJson(`${API}/addToBasket.json`).then((data) => { - if (data.result === 1) { - let productId = +element.dataset["id"]; - let find = this.allProducts.find( - (product) => product.id_product === productId - ); - if (find) { - find.quantity++; - this._updateCart(find); - } else { - let product = { - id_product: productId, - price: +element.dataset["price"], - product_name: element.dataset["name"], - quantity: 1, - }; - - this.goods = [product]; - this.render(); - } - } else { - alert("Error"); - } - }); - } - - removeProduct(element) { - this.getJson(`${API}/deleteFromBasket.json`).then((data) => { - if (data.result === 1) { - let productId = +element.dataset["id"]; - let find = this.allProducts.find( - (product) => product.id_product === productId - ); - if (find.quantity > 1) { - find.quantity--; - this._updateCart(find); - } else { - this.allProducts.splice(this.allProducts.indexOf(find), 1); - document.querySelector(`.cart-item[data-id="${productId}"]`).remove(); - } - } else { - alert("Error"); - } - }); - } - - _updateCart(product) { - let block = document.querySelector( - `.cart-item[data-id="${product.id_product}"]` - ); - block.querySelector( - ".product-quantity" - ).textContent = `Количество: ${product.quantity}`; - block.querySelector(".product-price").textContent = `${product.quantity * product.price - } ₽`; - } - _init() { - document.querySelector(".btn-cart").addEventListener("click", () => { - document.querySelector(this.container).classList.toggle("invisible"); - }); - document.querySelector(this.container).addEventListener("click", (e) => { - if (e.target.classList.contains("del-btn")) { - this.removeProduct(e.target); - } - }); - } -} - -class CartItem extends Item { - constructor(el, img = "https://placehold.it/50x100") { - super(el, img); - this.quantity = el.quantity; - } - render() { - return `
-
- Some image -
-

${this.product_name}

-

Количество: ${this.quantity}

-

${this.price} за ед.

-
-
-
-

${this.quantity * this.price} ₽

- -
-
`; - } -} - -const listContext = { - ProductsList: ProductItem, - Cart: CartItem, -}; - -let cart = new Cart(); -let products = new ProductsList(cart); \ No newline at end of file diff --git a/regex_replace/replace.js b/regex_replace/replace.js deleted file mode 100644 index 1ef53f8..0000000 --- a/regex_replace/replace.js +++ /dev/null @@ -1,4 +0,0 @@ -let text = document.getElementById('text'); -document.getElementById('replace').addEventListener('click', ()=>{ - text.textContent = text.textContent.replace(/\B'|'\B/g, '"'); -}); \ No newline at end of file diff --git a/regex_replace/replace_quotes.html b/regex_replace/replace_quotes.html deleted file mode 100644 index 119da32..0000000 --- a/regex_replace/replace_quotes.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - Document - - - -

Lorem ipsum dolor sit amet consectetur adipisicing elit. Architecto 'possimus suscipit delectus illo' cupiditate. - Iste inventore at culpa nulla! Praesentium veritatis molestiae neque possimus modi iusto dolorum soluta - reprehenderit excepturi deserunt, blanditiis, quidem omnis. Ipsam eligendi, vitae expedita laborum, unde tenetur - sed ullam, dolore nihil illo blanditiis ad consectetur provident beatae eius quod deserunt. Id quae, mollitia - illo repellat deleniti officiis inventore numquam beatae ab 'debitis', recusandae, ut voluptas optio adipisci - accusantium. Ducimus, officiis provident, ratione saepe suscipit velit illo soluta aspernatur aliquam atque eos - nisi iure dolorum don't dignissimos in. Accusamus nulla, atque perferendis iusto nemo numquam doloremque - error molestiae voluptatem corporis sit quisquam minus neque recusandae aliquid harum. 'Facilis fugiat eaque - perferendis quam explicabo! Harum numquam porro placeat, explicabo perspiciatis similique doloribus', saepe - facere dignissimos quia odit architecto rem, isn't aut omnis optio earum perferendis cupiditate eaque dolore - nobis. Ab pariatur quod ut perspiciatis expedita quasi. Magnam repellendus sapiente fugit officiis? Odio, in - optio eaque ipsa alias magnam et repellat molestias aren't eum amet, tempora, voluptatem itaque? Architecto, - asperiores doloremque ad culpa nobis libero! 'Ducimus error asperiores sapiente nesciunt earum non cupiditate - eveniet impedit assumenda' ratione libero aut atque odit, eaque provident tempore inventore doloremque est quos - sint?

- - - - - \ No newline at end of file From 635deeb62078c1a56709de2d3c4b4a4a07513a74 Mon Sep 17 00:00:00 2001 From: Chuzhikov Danil Date: Mon, 29 Mar 2021 15:51:07 +0300 Subject: [PATCH 5/5] homework_7 --- .DS_Store | Bin 0 -> 6148 bytes package-lock.json | 374 +++++++++++++++++++++++++++++++++++++++ package.json | 16 ++ public/css/normalize.css | 349 ++++++++++++++++++++++++++++++++++++ public/css/style.css | 198 +++++++++++++++++++++ public/index.html | 31 ++++ public/js/CartComp.js | 85 +++++++++ public/js/ErrorComp.js | 25 +++ public/js/FilterComp.js | 15 ++ public/js/ProducComp.js | 49 +++++ public/js/main.js | 50 ++++++ server/cart.js | 22 +++ server/cartRouter.js | 28 +++ server/db/products.json | 22 +++ server/db/stats.json | 72 ++++++++ server/db/userCart.json | 30 ++++ server/handler.js | 30 ++++ server/logger.js | 24 +++ server/server.js | 24 +++ yarn.lock | 373 ++++++++++++++++++++++++++++++++++++++ 20 files changed, 1817 insertions(+) create mode 100644 .DS_Store create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/css/normalize.css create mode 100644 public/css/style.css create mode 100644 public/index.html create mode 100644 public/js/CartComp.js create mode 100644 public/js/ErrorComp.js create mode 100644 public/js/FilterComp.js create mode 100644 public/js/ProducComp.js create mode 100644 public/js/main.js create mode 100644 server/cart.js create mode 100644 server/cartRouter.js create mode 100644 server/db/products.json create mode 100644 server/db/stats.json create mode 100644 server/db/userCart.json create mode 100644 server/handler.js create mode 100644 server/logger.js create mode 100644 server/server.js create mode 100644 yarn.lock diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b4896def5d0cf15d68c13fa4c4f7044fa687db65 GIT binary patch literal 6148 zcmeHKL5c!F3`|xLVJ{x{*k9NmG~&KsKOpMf1Yt$bbMjsLw5>{lAfp#yFG~fI>Q1M6 zm^w@*X6DP&?%ix*W^*{vE(~MiIela=m2n^(cYN9R?zr7=4u}1y`hJ4knH|Zr^Ar60 zw<;?Iq<|EV0#ZN91@dmUc-milf5PskEi4Q7UkwWQBev=fm;P8xm~dT zf50Ei|F= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "proxy-addr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..8fd3d19 --- /dev/null +++ b/package.json @@ -0,0 +1,16 @@ +{ + "name": "project_express", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "express": "^4.17.1", + "moment": "^2.24.0" + } +} diff --git a/public/css/normalize.css b/public/css/normalize.css new file mode 100644 index 0000000..192eb9c --- /dev/null +++ b/public/css/normalize.css @@ -0,0 +1,349 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Render the `main` element consistently in IE. + */ + +main { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; +} diff --git a/public/css/style.css b/public/css/style.css new file mode 100644 index 0000000..008f02f --- /dev/null +++ b/public/css/style.css @@ -0,0 +1,198 @@ +body{ + font-family: 'SF Pro Display', sans-serif; +} +header{ + display: flex; + background-color: #2f2a2d; + justify-content: space-between; + color: #fafafa; + padding: 30px 80px; +} +button:focus{ + outline: none; +} +.logo{ + + text-transform: uppercase; + font-weight: bold; +} +.btn-cart{ + background-color: #fafafa; + padding: 10px 20px; + border: 1px solid transparent; + color: #2f2a2d; + border-radius: 5px; + transition: all ease-in-out .4s; + cursor: pointer; +} +.btn-cart:hover{ + background-color: transparent; + border-color: #fafafa; + color: #fafafa; +} +.btn-cart, .logo{ + align-self: center; +} +/*.products {*/ +/*display: flex;*/ +/*justify-content: space-between;*/ +/*flex-wrap: wrap;*/ +/*padding: 40px 80px;*/ +/*}*/ +.products{ + column-gap: 30px; + display: grid; + grid-template-columns: repeat(auto-fit, 200px); + grid-template-rows: 1fr; + padding: 40px 80px; + justify-content: space-between; +} +p { + margin: 0 0 5px 0; +} +.product-item{ + display: flex; + flex-direction: column; + width: 200px; + border-radius: 5px; + overflow: hidden; + margin: 20px 0; +} +img { + max-width: 100%; + height: auto +} +.desc { + border: 1px solid #c0c0c040; + padding: 15px +} +.cart{ + display: flex; + position: relative; +} +.cart-block{ + box-shadow: 0 0 5px rgba(0, 0, 0, 0.62); + border-radius: 5px; + box-sizing: border-box; + right: 0; + top: 130%; + position: absolute; + background-color: white; + padding: 20px; + color: black; + width: 300px; +} + +.invisible{ + display: none; +} +.cart-block:before{ + content: ''; + width: 0; + height: 0; + position: absolute; + top: -10px; + right: 35px; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-bottom: 10px solid white; +} + +.buy-btn, .del-btn{ + margin-top: 5px; + background-color: #2f2a2d; + padding: 5px 15px; + border: 1px solid transparent; + color: #fafafa; + border-radius: 5px; + transition: all ease-in-out .4s; + cursor: pointer; +} +.buy-btn:hover, .del-btn:hover{ + background-color: #fafafa; + color: #2f2a2d; + border: 1px solid #2f2a2d; +} +.cart-item { + display: flex; + justify-content: space-between; +} +.cart-item:not(:last-child){ + margin-bottom: 20px; +} +.product-bio{ + display: flex; +} +.cart-item img{ + align-self: flex-start; + margin-right: 15px; +} +.product-single-price{ + color: #474747; + font-size: 0.5em; +} +.product-price{ + margin-left: 30px; +} +.product-desc{ + max-width: 150px; +} +.product-quantity { + margin-top: 15px; + font-size: 0.75em; +} +.right-block{ + text-align: right; +} +.btn-search { + background-color: transparent; + border: none; + color: #fafafa; + font-size: 1.2em; + position: absolute; + bottom: 5px; + right: 0; +} +.search-form{ + position: relative; + margin-right: 50px; + display: inline-block; +} +.search-field:focus{ + outline: none; +} +.search-field { + box-sizing: border-box; + width: 200px; + color: #fafafa; + padding: 10px; + background-color: transparent; + border: none; + border-bottom: 2px solid #fafafa; +} +.error-msg { + padding: 30px 20px; + background-color: red; + color: white; + position: relative; +} +.error-block { + background-color: rgba(0,0,0, .5); + justify-content: center; + display: flex; + position: absolute; + top: 0; + width: 100%; + height: 100%; + align-items: center; +} +.close-btn { + font-size: 1.5em; + top: -40px; + position: absolute; + right: 0; + background: none; + border: none; + color: white; + font-weight: bold; +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..583bb8c --- /dev/null +++ b/public/index.html @@ -0,0 +1,31 @@ + + + + + Интернет-магазин + + + + +
+
+ +
+ + +
+
+
+ + +
+
+ + + + + + + + + diff --git a/public/js/CartComp.js b/public/js/CartComp.js new file mode 100644 index 0000000..3323a7c --- /dev/null +++ b/public/js/CartComp.js @@ -0,0 +1,85 @@ +Vue.component('cart', { + data(){ + return { + imgCart: 'https://placehold.it/50x100', + cartItems: [], + showCart: false, + } + }, + methods: { + addProduct(product){ + let find = this.cartItems.find(el => el.id_product === product.id_product); + if(find){ + this.$parent.putJson(`/api/cart/${find.id_product}`, {quantity: 1}); + find.quantity++; + } else { + let prod = Object.assign({quantity: 1}, product); + this.$parent.postJson('/api/cart', prod) + .then(data => { + if (data.result === 1) { + this.cartItems.push(prod); + } + }); + } + }, + remove(item) { + if (item.quantity > 1) { + this.$parent.putJson(`/api/cart/${item.id_product}`, {quantity: -1}) + .then(data => { + if (data.result === 1) { + item.quantity--; + } + }); + } else { + this.$parent.deleteJson(`/api/cart/${item.id_product}`) + .then(data => { + if (data.result === 1) { + this.cartItems.splice(this.cartItems.indexOf(item), 1); + } + }); + } + }, + }, + mounted(){ + this.$parent.getJson('/api/cart') + .then(data => { + for(let el of data.contents){ + this.cartItems.push(el); + } + }); + }, + template: ` +
+ +
+

Корзина пуста

+ + +
+
` +}); + +Vue.component('cart-item', { + props: ['cartItem', 'img'], + template: ` +
+
+ Some image +
+

{{cartItem.product_name}}

+

Количество: {{cartItem.quantity}}

+

{{cartItem.price}}₽ за единицу

+
+
+
+

{{cartItem.quantity*cartItem.price}}₽

+ +
+
+ ` +}); diff --git a/public/js/ErrorComp.js b/public/js/ErrorComp.js new file mode 100644 index 0000000..7fef048 --- /dev/null +++ b/public/js/ErrorComp.js @@ -0,0 +1,25 @@ +Vue.component('error', { + data(){ + return { + text: '' + } + }, + methods: { + setError(error){ + this.text = error + } + }, + computed: { + isVisible(){ + return this.text !== '' + } + }, + template: ` +
+

+ + {{ text }} +

+
+ ` +}); diff --git a/public/js/FilterComp.js b/public/js/FilterComp.js new file mode 100644 index 0000000..c9347ff --- /dev/null +++ b/public/js/FilterComp.js @@ -0,0 +1,15 @@ +Vue.component('filter-el', { + data(){ + return { + userSearch: '' + } + }, + template: ` +
+ + +
+ ` +}); diff --git a/public/js/ProducComp.js b/public/js/ProducComp.js new file mode 100644 index 0000000..79a4307 --- /dev/null +++ b/public/js/ProducComp.js @@ -0,0 +1,49 @@ +Vue.component('products', { + data(){ + return { + products: [], + filtered: [], + imgCatalog: 'https://placehold.it/200x150', + } + }, + methods: { + filter(userSearch){ + let regexp = new RegExp(userSearch, 'i'); + this.filtered = this.products.filter(el => regexp.test(el.product_name)); + } + }, + mounted(){ + this.$parent.getJson('/api/products') + .then(data => { + for(let el of data){ + this.products.push(el); + this.filtered.push(el); + } + }); + }, + template: ` +
+ +
+ ` +}); + +Vue.component('product', { + props: ['product', 'img'], + data() { + return { + cartAPI: this.$root.$refs.cart, + }; + }, + + template: ` +
+ Some img +
+

{{product.product_name}}

+

{{product.price}}₽

+ +
+
+ ` +}); diff --git a/public/js/main.js b/public/js/main.js new file mode 100644 index 0000000..c68a7b8 --- /dev/null +++ b/public/js/main.js @@ -0,0 +1,50 @@ +const API = 'https://raw.githubusercontent.com/GeekBrainsTutorial/online-store-api/master/responses'; + +const app = new Vue({ + el: '#app', + methods: { + getJson(url) { + return fetch(url) + .then(result => result.json()) + .catch(error => { + this.$refs.error.setError(error); + }) + }, + postJson(url, data) { + return fetch(url, { + method: 'POST', + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(data) + }).then(result => result.json()) + .catch(error => { + this.$refs.error.setError(error); + }); + }, + putJson(url, data) { + return fetch(url, { + method: 'PUT', + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(data) + }).then(result => result.json()) + .catch(error => { + this.$refs.error.setError(error); + }); + }, + deleteJson(url) { + return fetch(url, { + method: 'DELETE', + headers: { + "Content-Type": "application/json" + }, + }).then(result => result.json()) + .catch(error => { + this.$refs.error.setError(error); + }); + }, + }, +}); + diff --git a/server/cart.js b/server/cart.js new file mode 100644 index 0000000..ae41670 --- /dev/null +++ b/server/cart.js @@ -0,0 +1,22 @@ +const add = (cart, req) => { + cart.contents.push(req.body); + return { name: req.body.product_name, newCart: JSON.stringify(cart, null, 4) }; +}; + +const change = (cart, req) => { + const find = cart.contents.find(el => el.id_product === +req.params.id); + find.quantity += req.body.quantity; + return { name: find.product_name, newCart: JSON.stringify(cart, null, 4) }; +}; + +const remove = (cart, req) => { + const find = cart.contents.find(el => el.id_product === +req.params.id); + cart.contents.splice(cart.contents.indexOf(find), 1); + return { name: find.product_name, newCart: JSON.stringify(cart, null, 4) }; +}; + +module.exports = { + add, + change, + remove, +}; diff --git a/server/cartRouter.js b/server/cartRouter.js new file mode 100644 index 0000000..ed7e8d3 --- /dev/null +++ b/server/cartRouter.js @@ -0,0 +1,28 @@ +const express = require('express'); +const fs = require('fs'); +const handler = require('./handler'); +const router = express.Router(); + +router.get('/', (req, res) => { + fs.readFile('./server/db/userCart.json', 'utf-8', (err, data) => { + if (err) { + res.sendStatus(404, JSON.stringify({result: 0, text: err})); + } else { + res.send(data); + } + }); +}); + +router.post('/', (req, res) => { + handler(req, res, 'add', './server/db/userCart.json'); +}); + +router.put('/:id', (req, res) => { + handler(req, res, 'change', './server/db/userCart.json'); +}); + +router.delete('/:id', (req, res) => { + handler(req, res, 'remove', './server/db/userCart.json'); +}); + +module.exports = router; diff --git a/server/db/products.json b/server/db/products.json new file mode 100644 index 0000000..a65d344 --- /dev/null +++ b/server/db/products.json @@ -0,0 +1,22 @@ +[ + { + "id_product": 124, + "product_name": "Keyboard", + "price": 1600 + }, + { + "id_product": 457, + "product_name": "Gamepad", + "price": 3000 + }, + { + "id_product": 123, + "product_name": "Notebook", + "price": 45600 + }, + { + "id_product": 456, + "product_name": "Mouse", + "price": 1000 + } +] \ No newline at end of file diff --git a/server/db/stats.json b/server/db/stats.json new file mode 100644 index 0000000..5ea6018 --- /dev/null +++ b/server/db/stats.json @@ -0,0 +1,72 @@ +[ + { + "time": "29 Mar 2021, 3:27:47 pm", + "prod_name": "Keyboard", + "action": "remove" + }, + { + "time": "29 Mar 2021, 3:27:49 pm", + "prod_name": "Mouse", + "action": "add" + }, + { + "time": "29 Mar 2021, 3:27:51 pm", + "prod_name": "Notebook", + "action": "change" + }, + { + "time": "29 Mar 2021, 3:27:55 pm", + "prod_name": "Gamepad", + "action": "change" + }, + { + "time": "29 Mar 2021, 3:28:11 pm", + "prod_name": "Keyboard", + "action": "add" + }, + { + "time": "29 Mar 2021, 3:28:12 pm", + "prod_name": "Keyboard", + "action": "change" + }, + { + "time": "29 Mar 2021, 3:41:36 pm", + "prod_name": "Notebook", + "action": "change" + }, + { + "time": "29 Mar 2021, 3:41:37 pm", + "prod_name": "Mouse", + "action": "change" + }, + { + "time": "29 Mar 2021, 3:41:40 pm", + "prod_name": "Keyboard", + "action": "change" + }, + { + "time": "29 Mar 2021, 3:41:40 pm", + "prod_name": "Mouse", + "action": "change" + }, + { + "time": "29 Mar 2021, 3:41:41 pm", + "prod_name": "Mouse", + "action": "remove" + }, + { + "time": "29 Mar 2021, 3:41:42 pm", + "prod_name": "Gamepad", + "action": "change" + }, + { + "time": "29 Mar 2021, 3:41:43 pm", + "prod_name": "Notebook", + "action": "change" + }, + { + "time": "29 Mar 2021, 3:41:47 pm", + "prod_name": "Mouse", + "action": "add" + } +] \ No newline at end of file diff --git a/server/db/userCart.json b/server/db/userCart.json new file mode 100644 index 0000000..264e985 --- /dev/null +++ b/server/db/userCart.json @@ -0,0 +1,30 @@ +{ + "amount": 46600, + "countGoods": 2, + "contents": [ + { + "quantity": 5, + "id_product": 123, + "product_name": "Notebook", + "price": 45600 + }, + { + "quantity": 3, + "id_product": 457, + "product_name": "Gamepad", + "price": 3000 + }, + { + "quantity": 1, + "id_product": 124, + "product_name": "Keyboard", + "price": 1600 + }, + { + "quantity": 1, + "id_product": 456, + "product_name": "Mouse", + "price": 1000 + } + ] +} \ No newline at end of file diff --git a/server/handler.js b/server/handler.js new file mode 100644 index 0000000..e5e7d9c --- /dev/null +++ b/server/handler.js @@ -0,0 +1,30 @@ +const fs = require('fs'); +const cart = require('./cart'); +const logger = require('./logger'); + +const actions = { + add: cart.add, + change: cart.change, + remove: cart.remove, +}; + +const handler = (req, res, action, file) => { + fs.readFile(file, 'utf-8', (err, data) => { + if (err) { + res.sendStatus(404, JSON.stringify({result: 0, text: err})); + } else { + const { name, newCart } = actions[action](JSON.parse(data), req); + fs.writeFile(file, newCart, (err) => { + if (err) { + res.send('{"result": 0}'); + } else { + console.log(name); + logger(name, action); + res.send('{"result": 1}'); + } + }) + } + }); +}; + +module.exports = handler; diff --git a/server/logger.js b/server/logger.js new file mode 100644 index 0000000..64d539b --- /dev/null +++ b/server/logger.js @@ -0,0 +1,24 @@ +const moment = require('moment'); +const fs = require('fs'); + +const logger = (name, action) => { + fs.readFile('./server/db/stats.json', 'utf-8', (err, data) => { + if (err) { + console.log(err); + } else { + const stat = JSON.parse(data); + stat.push({ + time: moment().format('DD MMM YYYY, h:mm:ss a'), + prod_name: name, + action: action, + }); + fs.writeFile('./server/db/stats.json', JSON.stringify(stat, null, 4), (err) => { + if (err) { + console.log(err); + } + }); + } + }) +}; + +module.exports = logger; diff --git a/server/server.js b/server/server.js new file mode 100644 index 0000000..fd2fef4 --- /dev/null +++ b/server/server.js @@ -0,0 +1,24 @@ +const express = require('express'); +const fs = require('fs'); +const cartRouter = require('./cartRouter'); +const app = express(); + +app.use(express.json()); +app.use('/', express.static('./public')); +app.use('/api/cart', cartRouter); + +app.get('/api/products', (req, res) => { + fs.readFile('./server/db/products.json', 'utf-8', (err, data) => { + if (err) { + res.send(JSON.stringify({result: 0, text: err})); + } else { + res.send(data); + } + }); +}); + +const port = process.env.PORT || 8081; + +app.listen(port, () => { + console.log(`Server started at port ${port}`); +}); diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..0c45166 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,373 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +inherits@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ipaddr.js@1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" + integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +mime-db@1.43.0: + version "1.43.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" + integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== + +mime-types@~2.1.24: + version "2.1.26" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" + integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== + dependencies: + mime-db "1.43.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +moment@^2.24.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" + integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +proxy-addr@~2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" + integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.0" + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=