Bladeren bron

HW js20-22

Ivar 2 jaren geleden
bovenliggende
commit
48d14aaa3d

+ 8 - 0
js/09_closures/tasks/index.js

@@ -51,6 +51,14 @@ function makeSaverWrapp() {
       let value4 = saver2()
       console.log(value3, value4) 
    }
+
+
+
+   let namePrompt = prompt.bind(window, 'Как тебя зовут?')
+   let nameSaver = makeSaver(namePrompt)
+   alert(`Привет! Prompt еще не было!`)
+   alert(`Привет ${nameSaver()}. Только что запустился prompt, первый и последний раз`)
+   alert(`Слушай, ${nameSaver()}, го пить пиво. Ведь prompt был только один раз`)
 }
 
 // finalCountdownWrapp()

+ 9 - 6
js/18_redux-thunk-3/index.js

@@ -183,7 +183,7 @@ const actionResolved = (name, payload) => ({type: 'PROMISE', status: 'RESOLVED',
 const actionRejected = (name, error) => ({type: 'PROMISE', status: 'REJECTED', name, error})
 
 
-const actionPromise = (name, promise) => 
+const actionPromise = (name, promise) => (
     async (dispatch) => {
         dispatch(actionPending(name))
         try { 
@@ -195,8 +195,9 @@ const actionPromise = (name, promise) =>
             dispatch(actionRejected(name, error))
         }
     }
+)
 
-const getGQL = url =>
+const getGQL = url => (
   async (query, variables={}) => {
       let obj = await fetch(url, {
         method: 'POST',
@@ -213,6 +214,7 @@ const getGQL = url =>
           return a.data[Object.keys(a.data)[0]]
       }      
   }
+)
 
   const backURL = 'http://shop-roles.asmer.fs.a-level.com.ua/'
   const gql = getGQL(backURL + 'graphql');
@@ -377,15 +379,15 @@ store.subscribe(() => {
             aside.innerHTML = ''
             const regBtn = document.createElement('a')
             regBtn.href = '#/register'
-            regBtn.classList = 'btn btn-primary'
+            regBtn.classList = 'btn btn-primary logBtn'
             regBtn.innerText = 'Register'
             const loginBtn = document.createElement('a')
             loginBtn.href = `#/login`
-            loginBtn.classList = 'btn btn-primary'
+            loginBtn.classList = 'btn btn-primary logBtn'
             loginBtn.innerText = 'Login'
-            const logoutBtn = document.createElement('button')
+            const logoutBtn = document.createElement('a')
             logoutBtn.innerText = 'Logout'
-            logoutBtn.classList = 'btn btn-primary'
+            logoutBtn.classList = 'btn btn-primary logBtn'
             aside.append(regBtn, loginBtn, logoutBtn)
 
 
@@ -395,6 +397,7 @@ store.subscribe(() => {
             }
             for (const {_id, name} of rootCats?.payload) {
                 const link = document.createElement('a')
+                link.classList = 'catBtn bg-light'
                 link.href = `#/category/${_id}`
                 link.innerText = name
                 aside.append(link)

+ 19 - 4
js/18_redux-thunk-3/style.css

@@ -1,26 +1,41 @@
 
-body {
-
+a.btn {
+   width: max-content;
 }
 
 img {
    max-width: 300px;
 }
 
+
 .wrapper {
    display: flex;
    flex-direction: column;
 }
 
+
 header {
    display: flex;
    justify-content: space-around;
 }
 
-#mainContainer {
-   display: flex;
+.catBtn {
+   width: 100%;
+   min-height: 40px;
+   margin: 5px;
+   text-decoration: none;
+   text-align: start;
+   padding: 5px;
 }
 
+.logBtn {
+   margin: 10px;
+}
+
+   #mainContainer {
+      display: flex;
+   }
+
    #aside {
       width: 30%;
    }

+ 101 - 51
js/20_canvas-2/index.js

@@ -11,17 +11,17 @@ let selection = []
 const tools = {
     graffity: {
         mousemove(e){ //e.buttons 0b00000x11 & 0b00000100 == x
-            (e.buttons & 1) && new Circle(e.clientX, e.clientY, +size.value, color.value)
+            (e.buttons & 1) && new Circle(e.layerX, e.layerY, +size.value, color.value)
         }
     },
     circle: {
         mousedown(e){
-            current = new Circle(e.clientX,e.clientY, 1, color.value)
+            current = new Circle(e.layerX,e.layerY, 1, color.value)
         },
         mousemove(e){
             if (!current) return;
 
-            current.radius = current.distanceTo(e.clientX, e.clientY)
+            current.radius = current.distanceTo(e.layerX, e.layerY)
             Drawable.drawAll()
         },
 
@@ -31,13 +31,13 @@ const tools = {
     },
     line: {
         mousedown(e){
-            current = new Line(e.clientX, e.clientY, 0, 0, color.value, +size.value)
+            current = new Line(e.layerX, e.layerY, 0, 0, color.value, +size.value)
         },
         mousemove(e){
             if (!current) return;
 
-            current.width = e.clientX - current.x
-            current.height = e.clientY - current.y
+            current.width = e.layerX - current.x
+            current.height = e.layerY - current.y
 
             Drawable.drawAll()
         },
@@ -48,13 +48,13 @@ const tools = {
     },
     rectangle: {
         mousedown(e){
-            current = new Rectangle(e.clientX, e.clientY, 0, 0, color.value)
+            current = new Rectangle(e.layerX, e.layerY, 0, 0, color.value)
         },
         mousemove(e){
             if (!current) return;
 
-            current.width = e.clientX - current.x
-            current.height = e.clientY - current.y
+            current.width = e.layerX - current.x
+            current.height = e.layerY - current.y
 
             Drawable.drawAll()
         },
@@ -65,13 +65,13 @@ const tools = {
     },
     ellipse: {
         mousedown(e){
-            current = new Ellipse(e.clientX, e.clientY, 0, 0, color.value)
+            current = new Ellipse(e.layerX, e.layerY, 0, 0, color.value)
         },
         mousemove(e){
             if (!current) return;
 
-            current.width = e.clientX - current.x
-            current.height = e.clientY - current.y
+            current.width = e.layerX - current.x
+            current.height = e.layerY - current.y
 
             Drawable.drawAll()
         },
@@ -83,7 +83,7 @@ const tools = {
     select: {
         click(e){
             console.log(e)
-            let found = Drawable.instances.filter(c => c.in && c.in(e.clientX, e.clientY))
+            let found = Drawable.instances.filter(c => c.in && c.in(e.layerX, e.layerY))
             if (found.length){
                 if (e.ctrlKey){
                     selection.push(found.pop())
@@ -208,14 +208,23 @@ class Line extends Drawable {
     }
     
 
-    draw(){
-        ctx.beginPath();
-        ctx.moveTo(this.x, this.y);
-        ctx.lineTo(this.x + this.width, this.y + this.height);
-        ctx.closePath();
-        ctx.strokeStyle = this.color;
+    draw(selected){
+        if (selected){
+            ctx.beginPath()
+            ctx.moveTo(this.x, this.y)
+            ctx.lineTo(this.x + this.width, this.y + this.height)
+            ctx.closePath()            
+            ctx.strokeStyle = '#000000'            
+            ctx.lineWidth   = this.lineWidth + 2
+            ctx.stroke()
+        }
+        ctx.beginPath()
+        ctx.moveTo(this.x, this.y)
+        ctx.lineTo(this.x + this.width, this.y + this.height)
+        ctx.closePath()
+        ctx.strokeStyle = this.color
         ctx.lineWidth   = this.lineWidth
-        ctx.stroke();
+        ctx.stroke()
     }
 
 
@@ -226,15 +235,16 @@ class Line extends Drawable {
         let lineTurnAngle = mouseAngle - lineAngle;
         let cursorWidth = distance(this.x,this.y,x,y);
 
-        let rotX = Math.cos(lineTurnAngle) * distance(x,y,this.x,this.y);
-        let rotY = Math.sin(lineTurnAngle) * distance(x,y,this.x,this.y);
+        let rotX = Math.cos(lineTurnAngle) * cursorWidth;
+        let rotY = Math.sin(lineTurnAngle) * cursorWidth;
         
         if (rotX > 0 && rotX < this.distanceTo(this.x + this.width, this.y + this.height) && (rotY > -this.lineWidth / 2)
         && (rotY < this.lineWidth / 2)) {
-            console.log(true)
-            return
+            // console.log('попал')
+            return true
         } else {
-            console.log(false)
+            // console.log('мимо')
+            return false
         }
     }
 }
@@ -242,6 +252,7 @@ class Line extends Drawable {
 
 
 class Rectangle extends Drawable {
+
     constructor(x,y, width, height, color){
         super()
         this.x      = x;
@@ -251,12 +262,12 @@ class Rectangle extends Drawable {
         this.color  = color;
 
         this.draw(); 
-    }    
+    }   
 
     // invertColor(hex){
     //     function padZero(str, len) {
     //         len = len || 2;
-    //         var zeros = new Array(len).join('0');
+    //         let zeros = new Array(len).join('0');
     //         return (zeros + str).slice(-len);
     //     }
     //     if (hex.indexOf('#') === 0) {
@@ -270,7 +281,7 @@ class Rectangle extends Drawable {
     //         throw new Error('Invalid HEX color.');
     //     }
     //     // invert color components
-    //     var r = (255 - parseInt(hex.slice(0, 2), 16)).toString(16),
+    //     let r = (255 - parseInt(hex.slice(0, 2), 16)).toString(16),
     //         g = (255 - parseInt(hex.slice(2, 4), 16)).toString(16),
     //         b = (255 - parseInt(hex.slice(4, 6), 16)).toString(16);
     //     // pad each with zeros and return
@@ -279,6 +290,7 @@ class Rectangle extends Drawable {
 
 
     draw(selected){
+
         ctx.beginPath();
         ctx.moveTo(this.x, this.y);
 
@@ -296,31 +308,59 @@ class Rectangle extends Drawable {
 
 
     in(x,y){
-        return this.x < x && this.x + this.width > x &&
-                this.y < y && this.y + this.height  > y  
+
+        if (this.width > 0 && this.height > 0) {
+            if (this.x < x && this.x + this.width > x &&
+                this.y < y && this.y + this.height > y) {
+                    // console.log('попал', x, y, this.x, this.y, this.width, this.height)
+                    return true
+            } else {
+                // console.log('мимо', x, y, this.x, this.y, this.width, this.height)
+                return false
+            }
+        } 
+
+        if (this.width < 0 && this.height < 0) {
+            if (this.x > x && this.x + this.width < x &&
+                this.y > y && this.y + this.height < y) {
+                    return true
+            } else {
+                return false
+            }
+        } 
+
+        if (this.width > 0 && this.height < 0) {
+            if (this.x < x && this.x + this.width > x &&
+                this.y > y && this.y + this.height < y) {
+                    return true
+            } else {
+                return false
+            }
+        } 
+
+        if (this.width < 0 && this.height > 0) {
+            if (this.x > x && this.x + this.width < x &&
+                this.y < y && this.y + this.height > y) {
+                    return true
+            } else {
+                return false
+            }
+        } 
+           
     }
 }
 
 
 
 class Ellipse extends Drawable {
-    constructor(x,y, width, height, color){
-        super()
-        this.x      = x;
-        this.y      = y;
-        this.width  = width;
-        this.height = height;
-        this.color  = color;
 
-        this.draw(); 
-    }
     #width = 0
     #height = 0
 
     set width(newWidth){
         if (newWidth < 0){
             this.#width = -newWidth
-            this.x     += newWidth
+            this.x     += newWidth/2
         }
         else 
             this.#width = newWidth
@@ -329,7 +369,7 @@ class Ellipse extends Drawable {
     set height(newHeight){
         if (newHeight < 0){
             this.#height = -newHeight
-            this.y      +=  newHeight
+            this.y      +=  newHeight/2
         }
         else 
             this.#height = newHeight
@@ -351,25 +391,35 @@ class Ellipse extends Drawable {
         return this.#height/2
     }
 
-    
+    constructor(x,y, width, height, color){
+        super()
+        this.x      = x;
+        this.y      = y;
+        this.width  = width;
+        this.height = height;
+        this.color  = color;
+
+        this.draw(); 
+    }    
     
 
     draw(selected){
         ctx.beginPath();
-        // console.log(this.ry)
-        ctx.moveTo(this.x, this.y);
-        ctx.fillStyle = this.color;
-        // ctx.ellipse(this.x + this.width/2, this.y + this.height/2, this.width/2, this.height/2, 0, 0, 2 * Math.PI);
         ctx.ellipse(this.x + this.rx, this.y + this.ry, this.rx, this.ry, 0, 0, 2 * Math.PI);
-        ctx.fill()
         ctx.closePath();
+        ctx.fillStyle = this.color;
+        if (selected){
+            ctx.lineWidth = 2
+            ctx.strokeStyle = '#000000'
+            ctx.stroke()
+        }
+        ctx.fill()
     }
 
 
-    // in(x,y){
-    //     return this.x < x && this.x + this.width > x &&
-    //             this.y < y && this.y + this.height  > y  
-    // }
+    in(x,y){
+        return (( (x - (this.x + this.rx))**2 / this.rx**2 ) + ( (y - (this.y + this.ry))**2 / this.ry**2 )) <= 1
+    }
 }
 
 

+ 58 - 0
js/22_react/shop/package-lock.json

@@ -14,6 +14,7 @@
         "react": "^17.0.2",
         "react-dom": "^17.0.2",
         "react-redux": "^7.2.6",
+        "react-router-dom": "^6.1.1",
         "react-scripts": "5.0.0",
         "redux": "^4.1.2",
         "redux-thunk": "^2.4.1",
@@ -7810,6 +7811,14 @@
         "he": "bin/he"
       }
     },
+    "node_modules/history": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/history/-/history-5.1.0.tgz",
+      "integrity": "sha512-zPuQgPacm2vH2xdORvGGz1wQMuHSIB56yNAy5FnLuwOwgSYyPKptJtcMm6Ev+hRGeS+GzhbmRacHzvlESbFwDg==",
+      "dependencies": {
+        "@babel/runtime": "^7.7.6"
+      }
+    },
     "node_modules/hoist-non-react-statics": {
       "version": "3.3.2",
       "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
@@ -13226,6 +13235,30 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/react-router": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.1.1.tgz",
+      "integrity": "sha512-55o96RiDZmC0uD17DPqVmzzfdNd2Dc+EjkYvMAmHl43du/GItaTdFr5WwjTryNWPXZ+OOVQxQhwAX25UwxpHtw==",
+      "dependencies": {
+        "history": "^5.1.0"
+      },
+      "peerDependencies": {
+        "react": ">=16.8"
+      }
+    },
+    "node_modules/react-router-dom": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.1.1.tgz",
+      "integrity": "sha512-O3UH89DI4o+swd2q6lF4dSmpuNCxwkUXcj0zAFcVc1H+YoPE6T7uwoFMX0ws1pUvCY8lYDucFpOqCCdal6VFzg==",
+      "dependencies": {
+        "history": "^5.1.0",
+        "react-router": "6.1.1"
+      },
+      "peerDependencies": {
+        "react": ">=16.8",
+        "react-dom": ">=16.8"
+      }
+    },
     "node_modules/react-scripts": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.0.tgz",
@@ -21738,6 +21771,14 @@
       "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
       "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
     },
+    "history": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/history/-/history-5.1.0.tgz",
+      "integrity": "sha512-zPuQgPacm2vH2xdORvGGz1wQMuHSIB56yNAy5FnLuwOwgSYyPKptJtcMm6Ev+hRGeS+GzhbmRacHzvlESbFwDg==",
+      "requires": {
+        "@babel/runtime": "^7.7.6"
+      }
+    },
     "hoist-non-react-statics": {
       "version": "3.3.2",
       "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
@@ -25521,6 +25562,23 @@
       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
       "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
     },
+    "react-router": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.1.1.tgz",
+      "integrity": "sha512-55o96RiDZmC0uD17DPqVmzzfdNd2Dc+EjkYvMAmHl43du/GItaTdFr5WwjTryNWPXZ+OOVQxQhwAX25UwxpHtw==",
+      "requires": {
+        "history": "^5.1.0"
+      }
+    },
+    "react-router-dom": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.1.1.tgz",
+      "integrity": "sha512-O3UH89DI4o+swd2q6lF4dSmpuNCxwkUXcj0zAFcVc1H+YoPE6T7uwoFMX0ws1pUvCY8lYDucFpOqCCdal6VFzg==",
+      "requires": {
+        "history": "^5.1.0",
+        "react-router": "6.1.1"
+      }
+    },
     "react-scripts": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.0.tgz",

+ 1 - 0
js/22_react/shop/package.json

@@ -9,6 +9,7 @@
     "react": "^17.0.2",
     "react-dom": "^17.0.2",
     "react-redux": "^7.2.6",
+    "react-router-dom": "^6.1.1",
     "react-scripts": "5.0.0",
     "redux": "^4.1.2",
     "redux-thunk": "^2.4.1",

+ 82 - 38
js/22_react/shop/src/App.js

@@ -2,7 +2,10 @@ import logoDefault from './logo.svg';
 import './App.scss';
 import {Provider, connect}   from 'react-redux';
 import {createStore, combineReducers, applyMiddleware} from 'redux';
-import thunk from 'redux-thunk'
+import thunk from 'redux-thunk';
+import { BrowserRouter as Router, Route, Routes, Link} from 'react-router-dom';
+
+
 
 function authReducer(state, { type, token }) {
   if (!state) {
@@ -54,25 +57,23 @@ function cartReducer(state = {}, { type, good = {}, count = 1 }) {
     const { _id } = good
     const types = {
         CART_ADD() {
-            count = +count
-            if (!count) return state
+            count = +count  
+            if (!count) {
+              return state
+            }            
             return {
                 ...state,
-                [_id]: {
-                    good,
-                    count: count + (state[_id]?.count || 0)
-                }
+                [_id]: {good, count: (count + (state[_id]?.count || 0)) < 0 ? 0 : count + (state[_id]?.count || 0)}
             }
         },
         CART_CHANGE() {
             count = +count
-            if (!count) return state
+            if (!count) {
+              return state
+            } 
             return {
                 ...state,
-                [_id]: {
-                    good,
-                    count: count
-                }
+                [_id]: {good, count: count < 0 ? 0 : count}
             }
         },
         CART_REMOVE() {
@@ -138,16 +139,18 @@ const actionRootCats = () => (
 
 
 const actionCatById = (_id) => (
-    actionPromise('catById', gql(`query catById($q: String){
-            CategoryFindOne(query: $q){
-                subCategories{name, _id}
-                _id name goods {
-                    _id name price images {
-                        url
-                    }
-                }
-            }
-        }`, { q: JSON.stringify([{ _id }]) }))
+  actionPromise('catById', gql(`query catById($q: String){
+      CategoryFindOne(query: $q){
+          _id name goods {
+              _id name price images {
+                  url
+              }
+          }
+          subCategories {
+              _id name 
+          }
+      }
+  }`, {q: JSON.stringify([{_id}])}))
 )
 
 const getGQL = url => (
@@ -196,7 +199,7 @@ const Koshik = ({cart}) => {
   let sum = Object.entries(cart).map(([, val]) => val.count)
   count = sum.reduce((a, b) => a + b, 0)
   return (
-      <div className='Koshik'>{count}</div>
+      <Link to='/cart' className='Koshik'>{count}</Link>
   )
 }
 
@@ -223,7 +226,8 @@ const defaultRootCats = [
 
 const RootCategory = ({cat:{_id, name}={}}) => (
   <li>
-    <a href={`#/category/${_id}`}>{name}</a>
+    <Link to='/category' >{name}</Link>
+    {/* <a href={`#/category/${_id}`}>{name}</a> */}
   </li>
 )
 
@@ -252,16 +256,18 @@ const SubCategories = ({cats}) => (
 <></>
 )
 
-const GoodCard = ({good:{_id, name, price, images}={}, onCartAdd}) =>
+const GoodCard = ({good:{_id, name, price, images}={}, onCartAdd}) => (
 <div className='GoodCard'>
     <h2>{name}</h2>
     {images && images[0] && images[0].url && <img src={backURL + '/' + images[0].url} />}
     <strong>{price}</strong>
     <button onClick={() => onCartAdd({_id, name, price, images})}>+</button>
 </div>
+)
 
 const CGoodCard = connect(null, {onCartAdd: actionCartAdd})(GoodCard)
 
+
 const Category = ({cat:{_id, name, goods, subCategories}}) => (
   <div className="Category">
     <h1>{name}</h1>
@@ -273,11 +279,47 @@ const Category = ({cat:{_id, name, goods, subCategories}}) => (
 const CCategory = connect(state => ({cat: state.promise.catById?.payload || []}))(Category)
 
 
+
+const GoodInCart = ({item: {count, good: {_id, name, price, images}}, onCartChange, onCartRemove, onCartAdd}) => (
+  <div className='GoodInCart'>
+      <h2>{name}</h2>
+      {images && images[0] && images[0].url && <img src={backURL + '/' + images[0].url} />}
+      <strong>{count}</strong>
+      <button onClick={() => onCartAdd({_id, name, price, images}, -1)}>-</button>
+      <input onInput={(e) => onCartChange({_id, name, price, images}, e.currentTarget.value)}  value={count} type="number"/>
+      <button onClick={() => onCartAdd({_id, name, price, images})}>+</button>
+      <button onClick={() => onCartRemove({_id, name, price, images})}>Удалить</button>
+  </div>
+)
+
+const CGoodInCart = connect(null, {onCartChange: actionCartChange, onCartRemove: actionCartRemove, onCartAdd: actionCartAdd})(GoodInCart)
+
+
+const Cart = ({cartQ, onCartClear}) => (  
+  <div className='Cart'>
+    {cartQ.length === 0 ? <></> : <button onClick={() => onCartClear()}>Очистить корзину</button>} 
+    {cartQ.map(item => <CGoodInCart item={item}/>)}
+    {cartQ.length === 0 ? <></> : <button>Оформить заказ</button>} 
+  </div>
+)
+
+const CCart = connect(state => ({cartQ: Object.values(state.cart) || []}), {onCartClear: actionCartClear})(Cart)
+
+
 const Main = ({}) => (
   <main>
       <Aside />
       <Content>
-        <CCategory/>
+
+
+      <Routes>
+
+        <Route path='/cart' element={<CCart />}/>
+        <Route path='/category' element={<CCategory/>}/>
+
+      </Routes>
+
+        
       </Content>
   </main>
 )
@@ -290,6 +332,8 @@ const Footer = ({logo=logoDefault}) => (
 
 
 
+
+
 const JSONTest = ({data}) => (
   <pre>
     {JSON.stringify(data, null, 4)}
@@ -297,15 +341,11 @@ const JSONTest = ({data}) => (
     {Math.random() > 0.5 && <h1>zzzz</h1>}
   </pre>
 )
-
 const ReduxJSON = connect(state => ({data: state}))(JSONTest)
 
-
 const ListItem = ({item}) => (
   <li>{item}</li>
 )
-
-
 const List = ({data=["пиво", "чипсы", "сиги",]}) => (
   <ul>
     {/* {[  <ListItem item={data[0]}/>,
@@ -322,14 +362,18 @@ const List = ({data=["пиво", "чипсы", "сиги",]}) => (
 function App() {
   return (
     <Provider store={store}> 
-      <div className="App">
-        <Header />
-        <Main />
-        {/* <List /> */}
-        {/* <JSONTest data={[1,2,{a:5}]} /> */}
-        {/* <ReduxJSON /> */}
-        <Footer />
-      </div>
+      <Router>
+        <div className="App">
+          <Header />       
+          <Main />
+          
+          {/* <List /> */}
+          {/* <JSONTest data={[1,2,{a:5}]} /> */}
+          {/* <ReduxJSON /> */}
+          <Footer />
+          
+        </div>
+      </Router>
     </Provider>
   );
 }

+ 1 - 1
js/22_react/shop/src/App.scss

@@ -8,7 +8,7 @@
 .GoodCard {
   border: 1px solid black;
   border-radius: 15px;
-  margin: 15px 0;
+  margin: 15px;
   img {
     max-width: 300px;
   }