From 11b0e1d24d4a0c2e5ebfe239f97170f3b75a73eb Mon Sep 17 00:00:00 2001 From: Mishawaka Date: Tue, 28 Jan 2020 20:53:45 +0200 Subject: [PATCH 1/7] Added icons in sidebar --- src/App.js | 1 + src/assets/img/AtomSpace.svg | 42 +++ src/assets/img/logout.svg | 2 + src/assets/img/members.svg | 11 + src/assets/img/merch.svg | 6 + src/assets/img/news.svg | 2 + src/assets/img/orders.svg | 26 ++ src/assets/img/user.svg | 2 + src/assets/styles/Sidebar.scss | 39 ++- src/assets/styles/normalize/normalize.scss | 351 +++++++++++++++++++++ src/assets/styles/styles.scss | 2 +- src/components/Sidebar/Sidebar.jsx | 52 ++- 12 files changed, 515 insertions(+), 21 deletions(-) create mode 100644 src/assets/img/AtomSpace.svg create mode 100644 src/assets/img/logout.svg create mode 100644 src/assets/img/members.svg create mode 100644 src/assets/img/merch.svg create mode 100644 src/assets/img/news.svg create mode 100644 src/assets/img/orders.svg create mode 100644 src/assets/img/user.svg create mode 100644 src/assets/styles/normalize/normalize.scss diff --git a/src/App.js b/src/App.js index a1acb0b..402bbe3 100644 --- a/src/App.js +++ b/src/App.js @@ -9,6 +9,7 @@ import { import { LoginPage } from './routes/LoginPage/LoginPage'; import { MainPage } from './routes/Main/MainPage'; import './assets/styles/styles.scss'; +import './assets/styles/normalize/normalize.scss'; import { ProtectedRoute } from './routes/ProtectedRoute/ProtectedRoute'; function App() { diff --git a/src/assets/img/AtomSpace.svg b/src/assets/img/AtomSpace.svg new file mode 100644 index 0000000..149df51 --- /dev/null +++ b/src/assets/img/AtomSpace.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/logout.svg b/src/assets/img/logout.svg new file mode 100644 index 0000000..f54fb4c --- /dev/null +++ b/src/assets/img/logout.svg @@ -0,0 +1,2 @@ + + diff --git a/src/assets/img/members.svg b/src/assets/img/members.svg new file mode 100644 index 0000000..919bbfc --- /dev/null +++ b/src/assets/img/members.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/img/merch.svg b/src/assets/img/merch.svg new file mode 100644 index 0000000..c3ff85c --- /dev/null +++ b/src/assets/img/merch.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/img/news.svg b/src/assets/img/news.svg new file mode 100644 index 0000000..63aed7c --- /dev/null +++ b/src/assets/img/news.svg @@ -0,0 +1,2 @@ + + diff --git a/src/assets/img/orders.svg b/src/assets/img/orders.svg new file mode 100644 index 0000000..61815d8 --- /dev/null +++ b/src/assets/img/orders.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/img/user.svg b/src/assets/img/user.svg new file mode 100644 index 0000000..e1b1b9f --- /dev/null +++ b/src/assets/img/user.svg @@ -0,0 +1,2 @@ + + diff --git a/src/assets/styles/Sidebar.scss b/src/assets/styles/Sidebar.scss index 6409f8d..b4dedce 100644 --- a/src/assets/styles/Sidebar.scss +++ b/src/assets/styles/Sidebar.scss @@ -4,11 +4,42 @@ width: 20vw; height: 100vh; background-color: $sidebar-content; - .user{ - height: 10vh; - } - & > div{ + display: flex; + flex-direction: column; + justify-content: space-between; + & > div > div{ + transition: 0.3s; + &:hover{ + background-color: $grey; + } height: 7vh; color: white; + margin: 1em 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 1em; + & > .icon{ + width: 25%; + img { + width: 100%; + } + } + & > .icon:last-child{ + width: 100%; + } + & > p{ + font-size: 1.5em; + } + } + .user{ + height: 10vh; + border-bottom: 2px solid grey; + & > div{ + transition: none; + &:hover{ + background-color: $sidebar-content; + } + } } } \ No newline at end of file diff --git a/src/assets/styles/normalize/normalize.scss b/src/assets/styles/normalize/normalize.scss new file mode 100644 index 0000000..e1348b6 --- /dev/null +++ b/src/assets/styles/normalize/normalize.scss @@ -0,0 +1,351 @@ +/*! 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/src/assets/styles/styles.scss b/src/assets/styles/styles.scss index d85ac5d..846ee5e 100644 --- a/src/assets/styles/styles.scss +++ b/src/assets/styles/styles.scss @@ -5,7 +5,7 @@ body { background-image: url('../img/background-main.png'); background-attachment: fixed; - font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } .container{ diff --git a/src/components/Sidebar/Sidebar.jsx b/src/components/Sidebar/Sidebar.jsx index 7f7d6d0..2901a94 100644 --- a/src/components/Sidebar/Sidebar.jsx +++ b/src/components/Sidebar/Sidebar.jsx @@ -1,27 +1,47 @@ import React from 'react'; import '../../assets/styles/Sidebar.scss'; +import user from '../../assets/img/user.svg'; +import atomspace from '../../assets/img/AtomSpace.svg'; +import merch from '../../assets/img/merch.svg'; +import news from '../../assets/img/news.svg'; +import members from '../../assets/img/members.svg'; +import orders from '../../assets/img/orders.svg'; +import logout from '../../assets/img/logout.svg'; export const Sidebar = () => { return (
-
- User +
+
+
+

User

+
+
+
+

Merch

+
+
+
+

News

+
+
+
+

Members

+
+
+
+

Orders

+
-
- Merch -
-
- News -
-
- Members -
-
- Orders -
-
- Logout +
+
+
+

Logout

+
+
+
+
); From c021bf038dfe03652113bb224c85d8a0c81c2a11 Mon Sep 17 00:00:00 2001 From: Mishawaka Date: Fri, 31 Jan 2020 15:00:37 +0200 Subject: [PATCH 2/7] Finished working on sidebar, started making other pages --- src/App.js | 10 ++-- src/assets/styles/Sidebar.scss | 26 ++++++--- src/components/GridItem/GridItem.jsx | 31 +++++----- src/components/LoginForm/LoginForm.jsx | 5 +- src/components/Sidebar/Sidebar.jsx | 64 ++++++++++++--------- src/routes/Main/MainPage.js | 20 ++++--- src/routes/NewsPage/NewsPage.js | 11 ++++ src/routes/ProtectedRoute/ProtectedRoute.js | 8 +-- 8 files changed, 102 insertions(+), 73 deletions(-) create mode 100644 src/routes/NewsPage/NewsPage.js diff --git a/src/App.js b/src/App.js index 402bbe3..af0c68a 100644 --- a/src/App.js +++ b/src/App.js @@ -2,12 +2,12 @@ import React from 'react'; import { Switch, Route, - Redirect, BrowserRouter as Router, } from 'react-router-dom'; import { LoginPage } from './routes/LoginPage/LoginPage'; import { MainPage } from './routes/Main/MainPage'; +import { NewsPage } from './routes/NewsPage/NewsPage'; import './assets/styles/styles.scss'; import './assets/styles/normalize/normalize.scss'; import { ProtectedRoute } from './routes/ProtectedRoute/ProtectedRoute'; @@ -18,10 +18,10 @@ function App() { - - - - + + + + diff --git a/src/assets/styles/Sidebar.scss b/src/assets/styles/Sidebar.scss index b4dedce..6912835 100644 --- a/src/assets/styles/Sidebar.scss +++ b/src/assets/styles/Sidebar.scss @@ -7,11 +7,19 @@ display: flex; flex-direction: column; justify-content: space-between; - & > div > div{ + + a { + text-decoration: none; + } + + & > div > a > div, .logout, .user{ transition: 0.3s; &:hover{ background-color: $grey; } + & > .capitalize{ + text-transform: capitalize; + } height: 7vh; color: white; margin: 1em 0; @@ -20,26 +28,28 @@ justify-content: space-between; padding: 0 1em; & > .icon{ - width: 25%; + width: 20%; img { width: 100%; } } - & > .icon:last-child{ - width: 100%; - } & > p{ font-size: 1.5em; } } + + .atomspace > .icon{ + padding: 0 1em; + & > img{ + width: 100%; + } + } + .user{ height: 10vh; border-bottom: 2px solid grey; & > div{ transition: none; - &:hover{ - background-color: $sidebar-content; - } } } } \ No newline at end of file diff --git a/src/components/GridItem/GridItem.jsx b/src/components/GridItem/GridItem.jsx index d80c2cc..c64e0e6 100644 --- a/src/components/GridItem/GridItem.jsx +++ b/src/components/GridItem/GridItem.jsx @@ -1,21 +1,22 @@ import React from 'react'; import img from '../../assets/img/space.png'; -import edit from '../../assets/img/edit.svg'; -import remove from '../../assets/img/remove.svg'; -export const GridItem = () => ( -
-
-
-
-

Name: Some name

-

Price: 600

+export const GridItem = ({ merch }) => { + let { name, price } = merch; + return ( +
+
+
t-shirt
+
+

Name: {name}

+

Price: {price}

+
+
+
+
Edit
+
Delete
-
-
Edit
-
Delete
-
-
-); \ No newline at end of file + ); +} \ No newline at end of file diff --git a/src/components/LoginForm/LoginForm.jsx b/src/components/LoginForm/LoginForm.jsx index 674f6d0..d3847f2 100644 --- a/src/components/LoginForm/LoginForm.jsx +++ b/src/components/LoginForm/LoginForm.jsx @@ -1,5 +1,4 @@ import React, { useState } from "react"; -import { Redirect } from 'react-router-dom'; import history from '../../history'; export const LoginForm = () => { @@ -21,8 +20,8 @@ export const LoginForm = () => { .then(res => res.json()) .then(data => { localStorage.setItem('token', data.accessToken); - console.log(data); - history.push('/'); + history.push('/merch'); + window.location.reload(); }) .catch(err => console.error(err)); }; diff --git a/src/components/Sidebar/Sidebar.jsx b/src/components/Sidebar/Sidebar.jsx index 2901a94..5062fac 100644 --- a/src/components/Sidebar/Sidebar.jsx +++ b/src/components/Sidebar/Sidebar.jsx @@ -1,46 +1,54 @@ import React from 'react'; +import { Link } from 'react-router-dom'; import '../../assets/styles/Sidebar.scss'; -import user from '../../assets/img/user.svg'; import atomspace from '../../assets/img/AtomSpace.svg'; +import user from '../../assets/img/user.svg'; import merch from '../../assets/img/merch.svg'; import news from '../../assets/img/news.svg'; import members from '../../assets/img/members.svg'; import orders from '../../assets/img/orders.svg'; -import logout from '../../assets/img/logout.svg'; +import logoutImg from '../../assets/img/logout.svg'; export const Sidebar = () => { + + const pages = [ + { id: 1, name: 'user', photo: user }, + { id: 2, name: 'merch', photo: merch }, + { id: 3, name: 'news', photo: news }, + { id: 4, name: 'members', photo: members }, + { id: 5, name: 'orders', photo: orders } + ]; + return (
-
-
-

User

-
-
-
-

Merch

-
-
-
-

News

-
-
-
-

Members

-
-
-
-

Orders

-
+ {pages.map(({ id, name, photo }) => name === 'user' ? + ( +
+
{name}
+

{name}

+
+ ) + : + ( + +
+
{name}
+

{name}

+
+ + ))}
-
-
-
-

Logout

-
+
+ +
localStorage.removeItem('token')} className='logout'> +
logout
+

Logout

+
+
-
+
atomspace icon
diff --git a/src/routes/Main/MainPage.js b/src/routes/Main/MainPage.js index e745996..b525a6a 100644 --- a/src/routes/Main/MainPage.js +++ b/src/routes/Main/MainPage.js @@ -3,21 +3,25 @@ import { GridItem } from '../../components/GridItem/GridItem'; import { Sidebar } from '../../components/Sidebar/Sidebar'; import '../../assets/styles/MainPage.scss'; -import main from '../../assets/img/main.jpg'; export const MainPage = () => { - console.log('MainPage'); + const merches = [ + { id: 1, name: 'Shirt 1', price: 600 }, + { id: 2, name: 'Shirt 2', price: 200 }, + { id: 3, name: 'Shirt 3', price: 100 }, + { id: 4, name: 'Shirt 4', price: 700 }, + { id: 5, name: 'Shirt 5', price: 300 }, + { id: 6, name: 'Shirt 6', price: 400 } + ]; + return (
- - - - - - + {merches.map(merch => ( + + ))}
+++
diff --git a/src/routes/NewsPage/NewsPage.js b/src/routes/NewsPage/NewsPage.js new file mode 100644 index 0000000..c42c9d2 --- /dev/null +++ b/src/routes/NewsPage/NewsPage.js @@ -0,0 +1,11 @@ +import React from 'react'; +import { Sidebar } from '../../components/Sidebar/Sidebar'; + +export const NewsPage = () => { + return ( +
+ +

Hello World!

+
+ ); +} \ No newline at end of file diff --git a/src/routes/ProtectedRoute/ProtectedRoute.js b/src/routes/ProtectedRoute/ProtectedRoute.js index 08c0fe3..8eaae6c 100644 --- a/src/routes/ProtectedRoute/ProtectedRoute.js +++ b/src/routes/ProtectedRoute/ProtectedRoute.js @@ -1,15 +1,11 @@ import React from 'react'; -import history from '../../history'; -import { LoginPage } from '../LoginPage/LoginPage'; import { Route, Redirect } from 'react-router-dom'; export const ProtectedRoute = props => { let authed = !!localStorage.getItem('token'); - console.log('ProtectedRoute'); return ( { - console.log(!authed); return !authed ? ( { }} /> ) : ( - props.children - ); + props.children + ); }} /> ); From 188aa4330f28e40a0a82d38d9a3de7976dd8df7c Mon Sep 17 00:00:00 2001 From: Mishawaka Date: Sun, 9 Feb 2020 22:03:41 +0200 Subject: [PATCH 3/7] Added merch page, with all functions, except adding new merch --- package-lock.json | 136 +++++++++++++++++++++ package.json | 4 + src/App.js | 5 +- src/assets/img/close.svg | 6 + src/assets/img/plus.svg | 2 + src/assets/styles/Loader.scss | 15 +++ src/assets/styles/LoginForm.scss | 6 +- src/assets/styles/MainPage.scss | 25 +++- src/assets/styles/Modal.scss | 55 +++++++++ src/assets/styles/normalize/normalize.scss | 11 ++ src/components/GridItem/GridItem.jsx | 52 ++++++-- src/components/Loader/Loader.jsx | 20 +++ src/components/Modal/Modal.jsx | 54 ++++++++ src/contexts/MerchContext.js | 16 +++ src/routes/Main/MainPage.js | 48 +++++--- 15 files changed, 418 insertions(+), 37 deletions(-) create mode 100644 src/assets/img/close.svg create mode 100644 src/assets/img/plus.svg create mode 100644 src/assets/styles/Loader.scss create mode 100644 src/assets/styles/Modal.scss create mode 100644 src/components/Loader/Loader.jsx create mode 100644 src/components/Modal/Modal.jsx create mode 100644 src/contexts/MerchContext.js diff --git a/package-lock.json b/package-lock.json index 9888baf..f01d66b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1928,6 +1928,12 @@ "color-convert": "^1.9.0" } }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, "anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", @@ -3692,6 +3698,16 @@ "shallow-clone": "^0.1.2" } }, + "cls-bluebird": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", + "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", + "dev": true, + "requires": { + "is-bluebird": "^1.0.2", + "shimmer": "^1.1.0" + } + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -4702,6 +4718,12 @@ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" }, + "dottie": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", + "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==", + "dev": true + }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -5027,6 +5049,28 @@ } } }, + "eslint-config-airbnb": { + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-18.0.1.tgz", + "integrity": "sha512-hLb/ccvW4grVhvd6CT83bECacc+s4Z3/AEyWQdIT2KeTsG9dR7nx1gs7Iw4tDmGKozCNHFn4yZmRm3Tgy+XxyQ==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^14.0.0", + "object.assign": "^4.1.0", + "object.entries": "^1.1.0" + } + }, + "eslint-config-airbnb-base": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz", + "integrity": "sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA==", + "dev": true, + "requires": { + "confusing-browser-globals": "^1.0.7", + "object.assign": "^4.1.0", + "object.entries": "^1.1.0" + } + }, "eslint-config-react-app": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.1.0.tgz", @@ -6789,6 +6833,12 @@ "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -6896,6 +6946,12 @@ "binary-extensions": "^1.0.0" } }, + "is-bluebird": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", + "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=", + "dev": true + }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -9105,6 +9161,21 @@ } } }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "dev": true + }, + "moment-timezone": { + "version": "0.5.27", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.27.tgz", + "integrity": "sha512-EIKQs7h5sAsjhPCqN6ggx6cEbs94GK050254TIJySD1bzoM5JTYDwAU1IoVOeTOL6Gm27kYJ51/uuvq1kIlrbw==", + "dev": true, + "requires": { + "moment": ">= 2.9.0" + } + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -12028,6 +12099,15 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" }, + "retry-as-promised": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", + "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", + "dev": true, + "requires": { + "any-promise": "^1.3.0" + } + }, "rework": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz", @@ -12512,6 +12592,35 @@ } } }, + "sequelize": { + "version": "5.21.3", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.21.3.tgz", + "integrity": "sha512-ptdeAxwTY0zbj7AK8m+SH3z52uHVrt/qmOTSIGo/kyfnSp3h5HeKlywkJf5GEk09kuRrPHfWARVSXH1W3IGU7g==", + "dev": true, + "requires": { + "bluebird": "^3.5.0", + "cls-bluebird": "^2.1.0", + "debug": "^4.1.1", + "dottie": "^2.0.0", + "inflection": "1.12.0", + "lodash": "^4.17.15", + "moment": "^2.24.0", + "moment-timezone": "^0.5.21", + "retry-as-promised": "^3.2.0", + "semver": "^6.3.0", + "sequelize-pool": "^2.3.0", + "toposort-class": "^1.0.1", + "uuid": "^3.3.3", + "validator": "^10.11.0", + "wkx": "^0.4.8" + } + }, + "sequelize-pool": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-2.3.0.tgz", + "integrity": "sha512-Ibz08vnXvkZ8LJTiUOxRcj1Ckdn7qafNZ2t59jYHMX1VIebTAOYefWdRYFt6z6+hy52WGthAHAoLc9hvk3onqA==", + "dev": true + }, "serialize-javascript": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", @@ -12672,6 +12781,12 @@ "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", + "dev": true + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -13659,6 +13774,12 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=", + "dev": true + }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -14011,6 +14132,12 @@ "spdx-expression-parse": "^3.0.0" } }, + "validator": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==", + "dev": true + }, "value-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", @@ -14562,6 +14689,15 @@ } } }, + "wkx": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.8.tgz", + "integrity": "sha512-ikPXMM9IR/gy/LwiOSqWlSL3X/J5uk9EO2hHNRXS41eTLXaUFEVw9fn/593jW/tE5tedNg8YjT5HkCa4FqQZyQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/package.json b/package.json index 0dad5b7..ba7d6ea 100644 --- a/package.json +++ b/package.json @@ -144,5 +144,9 @@ "presets": [ "react-app" ] + }, + "devDependencies": { + "eslint-config-airbnb": "^18.0.1", + "sequelize": "^5.21.3" } } diff --git a/src/App.js b/src/App.js index af0c68a..ba11129 100644 --- a/src/App.js +++ b/src/App.js @@ -11,6 +11,7 @@ import { NewsPage } from './routes/NewsPage/NewsPage'; import './assets/styles/styles.scss'; import './assets/styles/normalize/normalize.scss'; import { ProtectedRoute } from './routes/ProtectedRoute/ProtectedRoute'; +import { MerchProvider } from './contexts/MerchContext'; function App() { return ( @@ -18,7 +19,9 @@ function App() { - + + + diff --git a/src/assets/img/close.svg b/src/assets/img/close.svg new file mode 100644 index 0000000..ca51122 --- /dev/null +++ b/src/assets/img/close.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/img/plus.svg b/src/assets/img/plus.svg new file mode 100644 index 0000000..e7ffc6d --- /dev/null +++ b/src/assets/img/plus.svg @@ -0,0 +1,2 @@ + + diff --git a/src/assets/styles/Loader.scss b/src/assets/styles/Loader.scss new file mode 100644 index 0000000..cfd417f --- /dev/null +++ b/src/assets/styles/Loader.scss @@ -0,0 +1,15 @@ +.loader{ + width: 100%; + height: 3em; + text-align: center; + display: inline-block; + vertical-align: top; +} + +svg { + width: 50px; + height: 50px; + & > rect, & > path{ + fill: #2d4bd0; + } +} \ No newline at end of file diff --git a/src/assets/styles/LoginForm.scss b/src/assets/styles/LoginForm.scss index 8a6455b..56ed5d9 100644 --- a/src/assets/styles/LoginForm.scss +++ b/src/assets/styles/LoginForm.scss @@ -12,7 +12,7 @@ .auth-form { display: flex; flex-direction: column; - width: 80%; + width: 60%; margin: 0 auto; } @@ -23,7 +23,7 @@ padding: 10px; } -input.submit-input { +.submit-input { margin: 3%; width: 100%; background-color: rgba(61, 62, 62, 0.8); @@ -42,7 +42,7 @@ input.submit-input { transition: all 1s ease; } -input.submit-input:hover { +.submit-input:hover { transition: all 1s ease; background-color: rgba(43, 44, 44, 0.8); } \ No newline at end of file diff --git a/src/assets/styles/MainPage.scss b/src/assets/styles/MainPage.scss index c9d2267..008c464 100644 --- a/src/assets/styles/MainPage.scss +++ b/src/assets/styles/MainPage.scss @@ -4,6 +4,29 @@ width: 100%; } +.add-item{ + width: 100%; + display: flex; + justify-content: center; + padding: 2em 0 1em 0; + .add-img{ + width: 2vw; + background-color: $grey; + border-radius: 100%; + padding: 10px; + transition: 1s; + display: flex; + align-items: center; + &:hover{ + background-color: gray; + } + } + img{ + width: 100%; + } +} + + .grid-items { display: grid; grid-template-columns: repeat(3, 1fr); @@ -17,7 +40,7 @@ background: $back-content; background-clip: content-box; padding: 1.5em 15%; - height: 40vh; + height: 43vh; text-align: center; color: white; display: grid; diff --git a/src/assets/styles/Modal.scss b/src/assets/styles/Modal.scss new file mode 100644 index 0000000..531cec3 --- /dev/null +++ b/src/assets/styles/Modal.scss @@ -0,0 +1,55 @@ +@import './variables.scss'; + +.modal-show{ + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + display: flex; + align-items: center; + justify-content: center; + background-color: $grey; + opacity: 0.8; + & > .form{ + width: 35%; + height: 40%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-evenly; + opacity: 1; + background-color: $back-content; + + & h2{ + color: white; + text-align: center; + } + } +} + +.close-item{ + position: fixed; + top: 0; + right: 0; + padding: 1em 1em 0 0; + display: flex; + justify-content: center; + .add-img{ + width: 2vw; + background-color: $grey; + border-radius: 100%; + padding: 10px; + transition: 1s; + &:hover{ + background-color: gray; + } + } + img{ + width: 100%; + } +} + +.modal-hide{ + display: none; +} \ No newline at end of file diff --git a/src/assets/styles/normalize/normalize.scss b/src/assets/styles/normalize/normalize.scss index e1348b6..1e17532 100644 --- a/src/assets/styles/normalize/normalize.scss +++ b/src/assets/styles/normalize/normalize.scss @@ -168,6 +168,17 @@ textarea { margin: 0; /* 2 */ } +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* Firefox */ +input[type=number] { + -moz-appearance:textfield; +} + /** * Show the overflow in IE. * 1. Show the overflow in Edge. diff --git a/src/components/GridItem/GridItem.jsx b/src/components/GridItem/GridItem.jsx index c64e0e6..2f5a85f 100644 --- a/src/components/GridItem/GridItem.jsx +++ b/src/components/GridItem/GridItem.jsx @@ -1,22 +1,48 @@ import React from 'react'; +import { Modal } from '../Modal/Modal'; import img from '../../assets/img/space.png'; +import { MerchContext } from '../../contexts/MerchContext'; -export const GridItem = ({ merch }) => { +export const GridItem = ({ merch, setModal }) => { let { name, price } = merch; + + const openModal = (setMerchToEdit) => { + setMerchToEdit(merch); + setModal(true); + } + + const deleteMerch = () => { + let conf = confirm('Are you sure'); + if (conf) { + fetch('http://localhost:8000/api/v1/delete-merch', { + method: 'DELETE', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(merch) + }) + .then(res => res.json()) + .catch(err => console.error(err)) + } + } + + return ( -
-
-
t-shirt
-
-

Name: {name}

-

Price: {price}

+ + {({ setMerchToEdit }) => ( +
+
+
t-shirt
+
+

{name}

+

{price} ₴

+
+
+
+
openModal(setMerchToEdit)}>Edit
+
Delete
+
-
-
-
Edit
-
Delete
-
-
+ )} + ); } \ No newline at end of file diff --git a/src/components/Loader/Loader.jsx b/src/components/Loader/Loader.jsx new file mode 100644 index 0000000..7f36c45 --- /dev/null +++ b/src/components/Loader/Loader.jsx @@ -0,0 +1,20 @@ +import React from 'react'; + +import '../../assets/styles/Loader.scss' + +export const Loader = ({ loading }) => ( +
+ + + + + +
+); \ No newline at end of file diff --git a/src/components/Modal/Modal.jsx b/src/components/Modal/Modal.jsx new file mode 100644 index 0000000..547ff4e --- /dev/null +++ b/src/components/Modal/Modal.jsx @@ -0,0 +1,54 @@ +import React, { useState, useContext } from 'react'; +import '../../assets/styles/Modal.scss'; +import { MerchContext } from '../../contexts/MerchContext'; +import { Loader } from '../Loader/Loader'; + +import closeImg from '../../assets/img/close.svg'; + +export const Modal = ({ edit, modal, setModal }) => { + let className = modal ? 'modal-show' : 'modal-hide'; + + const { merchToEdit, setMerchToEdit, loading, setLoading } = useContext(MerchContext); + const [message, setMessage] = useState(''); + + const editMerch = merch => { + setLoading(true); + fetch('http://localhost:8000/api/v1/edit-merch', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(merch) + }) + .then(res => res.json()) + .then(data => { + setLoading(false); + setMessage('Changed successfully!!!'); + setModal(false); + return setMessage(''); + }) + .catch(err => { + setLoading(false); + return setModal(false); + }); + return null; + } + + return ( +
+
setModal(false)} className='add-img'>Close
+
+
+

Edit merch info

+ setMerchToEdit({ ...merchToEdit, name: e.target.value })} + value={merchToEdit.name} placeholder='Merch Name' /> + setMerchToEdit({ ...merchToEdit, price: +e.target.value })} + value={merchToEdit.price} placeholder='Price' /> + + +

{message}

+
+
+
+ ); +} \ No newline at end of file diff --git a/src/contexts/MerchContext.js b/src/contexts/MerchContext.js new file mode 100644 index 0000000..122f79f --- /dev/null +++ b/src/contexts/MerchContext.js @@ -0,0 +1,16 @@ +import React, { createContext, useState, useReducer } from 'react'; + +export const MerchContext = createContext(); + +export const MerchProvider = ({ children }) => { + + let [loading, setLoading] = useState(false); + let [merches, setMerches] = useState([]); + let [merchToEdit, setMerchToEdit] = useState({}); + const addMerches = obj => setMerches(obj); + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/src/routes/Main/MainPage.js b/src/routes/Main/MainPage.js index b525a6a..b919648 100644 --- a/src/routes/Main/MainPage.js +++ b/src/routes/Main/MainPage.js @@ -1,30 +1,40 @@ -import React from 'react'; +import React, { useState, useEffect, useContext } from 'react'; import { GridItem } from '../../components/GridItem/GridItem'; import { Sidebar } from '../../components/Sidebar/Sidebar'; +import { Modal } from '../../components/Modal/Modal'; +import { MerchContext } from '../../contexts/MerchContext'; +import plusImg from '../../assets/img/plus.svg'; import '../../assets/styles/MainPage.scss'; export const MainPage = () => { - const merches = [ - { id: 1, name: 'Shirt 1', price: 600 }, - { id: 2, name: 'Shirt 2', price: 200 }, - { id: 3, name: 'Shirt 3', price: 100 }, - { id: 4, name: 'Shirt 4', price: 700 }, - { id: 5, name: 'Shirt 5', price: 300 }, - { id: 6, name: 'Shirt 6', price: 400 } - ]; + const [modal, setModal] = useState(false); + + const { addMerches } = useContext(MerchContext); + useEffect(() => { + fetch('http://localhost:8000/api/v1/get-all-merch') + .then(res => res.json()) + .then(data => addMerches(data)) + .catch(err => console.log(err)); + return undefined; + }); return ( -
- -
-
- {merches.map(merch => ( - - ))} -
+++
+ + {({ merches }) => ( +
+ +
+
Plus
+
+ {merches.map(merch => ( + + ))} +
+
+
-
-
+ )} + ); }; From adac08b0763f819e32b9a426cfcf1e3de866e6d5 Mon Sep 17 00:00:00 2001 From: Mishawaka Date: Mon, 10 Feb 2020 09:18:33 +0200 Subject: [PATCH 4/7] Fixed an infinite loop in useEffect hook --- src/routes/Main/MainPage.js | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/routes/Main/MainPage.js b/src/routes/Main/MainPage.js index b919648..6560a73 100644 --- a/src/routes/Main/MainPage.js +++ b/src/routes/Main/MainPage.js @@ -10,31 +10,27 @@ import '../../assets/styles/MainPage.scss'; export const MainPage = () => { const [modal, setModal] = useState(false); - const { addMerches } = useContext(MerchContext); + const { addMerches, merches, loading } = useContext(MerchContext); useEffect(() => { fetch('http://localhost:8000/api/v1/get-all-merch') .then(res => res.json()) .then(data => addMerches(data)) .catch(err => console.log(err)); return undefined; - }); + }, [loading]); return ( - - {({ merches }) => ( -
- -
-
Plus
-
- {merches.map(merch => ( - - ))} -
-
- +
+ +
+
Plus
+
+ {merches.map(merch => ( + + ))}
- )} - +
+ +
); }; From f07b62749ecfe71a7fd482e8e2a83312b263c110 Mon Sep 17 00:00:00 2001 From: Mishawaka Date: Sat, 15 Feb 2020 15:16:48 +0200 Subject: [PATCH 5/7] For Vova's check --- src/components/Modal/Modal.jsx | 75 ++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/src/components/Modal/Modal.jsx b/src/components/Modal/Modal.jsx index 547ff4e..52a7753 100644 --- a/src/components/Modal/Modal.jsx +++ b/src/components/Modal/Modal.jsx @@ -5,11 +5,12 @@ import { Loader } from '../Loader/Loader'; import closeImg from '../../assets/img/close.svg'; -export const Modal = ({ edit, modal, setModal }) => { +export const Modal = ({ modal, setModal, data }) => { let className = modal ? 'modal-show' : 'modal-hide'; - + let { type } = data; const { merchToEdit, setMerchToEdit, loading, setLoading } = useContext(MerchContext); - const [message, setMessage] = useState(''); + const [newMerch, setNewMerch] = useState({ name: '', price: '' }); + const [file, setFile] = useState(''); const editMerch = merch => { setLoading(true); @@ -21,9 +22,31 @@ export const Modal = ({ edit, modal, setModal }) => { .then(res => res.json()) .then(data => { setLoading(false); - setMessage('Changed successfully!!!'); - setModal(false); - return setMessage(''); + return setModal(false); + }) + .catch(err => { + setLoading(false); + return setModal(false); + }); + return null; + } + + const addNewMerch = merch => { + setLoading(true); + let form = new FormData(); + form.append('name', merch.name); + form.append('price', merch.price); + // form.append('photo', file); + console.log(file); + fetch('http://localhost:8000/api/v1/add-new-merch', { + method: 'POST', + // headers: { 'Content-Type': 'multipart/form-data' }, + body: form + }) + .then(res => res.json()) + .then(data => { + setLoading(false); + return setModal(false); }) .catch(err => { setLoading(false); @@ -36,18 +59,34 @@ export const Modal = ({ edit, modal, setModal }) => {
setModal(false)} className='add-img'>Close
-
-

Edit merch info

- setMerchToEdit({ ...merchToEdit, name: e.target.value })} - value={merchToEdit.name} placeholder='Merch Name' /> - setMerchToEdit({ ...merchToEdit, price: +e.target.value })} - value={merchToEdit.price} placeholder='Price' /> - - -

{message}

-
+ {type === 'add' ? ( +
+

Add new merch

+ setNewMerch({ ...newMerch, name: e.target.value })} + value={newMerch.name} placeholder='Merch Name' /> + setNewMerch({ ...newMerch, price: +e.target.value })} + value={newMerch.price} placeholder='Price' /> + setFile(e.target.files[0])} id='merch-img' /> + + +
+ ) + : + ( +
+

Edit merch info

+ setMerchToEdit({ ...merchToEdit, name: e.target.value })} + value={merchToEdit.name} placeholder='Merch Name' /> + setMerchToEdit({ ...merchToEdit, price: +e.target.value })} + value={merchToEdit.price} placeholder='Price' /> + + +
+ )}
); From 7a6a6147fe1ab7a9e9f64a7189fd11d591c44b97 Mon Sep 17 00:00:00 2001 From: Mishawaka Date: Sun, 16 Feb 2020 21:07:41 +0200 Subject: [PATCH 6/7] Working merch route --- src/App.js | 2 ++ src/assets/styles/MainPage.scss | 12 +++++--- src/components/GridItem/GridItem.jsx | 43 ++++++++++++---------------- src/components/Modal/Modal.jsx | 29 ++++++++++++------- src/routes/Main/MainPage.js | 32 +++++++++++++++++---- 5 files changed, 73 insertions(+), 45 deletions(-) diff --git a/src/App.js b/src/App.js index ba11129..21c2f5c 100644 --- a/src/App.js +++ b/src/App.js @@ -3,6 +3,7 @@ import { Switch, Route, BrowserRouter as Router, + Redirect, } from 'react-router-dom'; import { LoginPage } from './routes/LoginPage/LoginPage'; @@ -19,6 +20,7 @@ function App() { + diff --git a/src/assets/styles/MainPage.scss b/src/assets/styles/MainPage.scss index 008c464..01ee956 100644 --- a/src/assets/styles/MainPage.scss +++ b/src/assets/styles/MainPage.scss @@ -5,18 +5,22 @@ } .add-item{ - width: 100%; display: flex; justify-content: center; padding: 2em 0 1em 0; + position: absolute; + bottom: 0; + right: 0; + margin: 0 1em 1em 0; .add-img{ - width: 2vw; + width: 1.5vw; background-color: $grey; border-radius: 100%; padding: 10px; transition: 1s; display: flex; align-items: center; + justify-content: end; &:hover{ background-color: gray; } @@ -29,7 +33,7 @@ .grid-items { display: grid; - grid-template-columns: repeat(3, 1fr); + grid-template-columns: repeat(4, 1fr); @media only screen and (max-width: 1000px) { grid-template-columns: repeat(2, 1fr); } @@ -39,7 +43,7 @@ .grid-item{ background: $back-content; background-clip: content-box; - padding: 1.5em 15%; + padding: 1.5em 8%; height: 43vh; text-align: center; color: white; diff --git a/src/components/GridItem/GridItem.jsx b/src/components/GridItem/GridItem.jsx index 2f5a85f..2c18be5 100644 --- a/src/components/GridItem/GridItem.jsx +++ b/src/components/GridItem/GridItem.jsx @@ -1,48 +1,41 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { Modal } from '../Modal/Modal'; import img from '../../assets/img/space.png'; import { MerchContext } from '../../contexts/MerchContext'; -export const GridItem = ({ merch, setModal }) => { - let { name, price } = merch; - - const openModal = (setMerchToEdit) => { - setMerchToEdit(merch); - setModal(true); - } +export const GridItem = ({ merch, openModal }) => { + let { name, price, avatar_url } = merch; + let { setLoading } = useContext(MerchContext); const deleteMerch = () => { let conf = confirm('Are you sure'); if (conf) { + setLoading(true); fetch('http://localhost:8000/api/v1/delete-merch', { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(merch) }) .then(res => res.json()) + .then(data => setLoading(false)) .catch(err => console.error(err)) } } - return ( - - {({ setMerchToEdit }) => ( -
-
-
t-shirt
-
-

{name}

-

{price} ₴

-
-
-
-
openModal(setMerchToEdit)}>Edit
-
Delete
-
+
+
+
t-shirt
+
+

{name}

+

{price} ₴

- )} - +
+
+
openModal(e, merch)}>Edit
+
Delete
+
+
); } \ No newline at end of file diff --git a/src/components/Modal/Modal.jsx b/src/components/Modal/Modal.jsx index 52a7753..f72cc3c 100644 --- a/src/components/Modal/Modal.jsx +++ b/src/components/Modal/Modal.jsx @@ -31,27 +31,34 @@ export const Modal = ({ modal, setModal, data }) => { return null; } - const addNewMerch = merch => { - setLoading(true); + const addMerchPhoto = async photo => { let form = new FormData(); - form.append('name', merch.name); - form.append('price', merch.price); - // form.append('photo', file); - console.log(file); - fetch('http://localhost:8000/api/v1/add-new-merch', { + form.append('photo', photo); + await fetch('http://localhost:8000/api/v1/add-merch-photo', { method: 'POST', - // headers: { 'Content-Type': 'multipart/form-data' }, body: form + }) + .then(res => res.json()) + .catch(err => err.json()); + }; + + const addNewMerch = () => { + setLoading(true); + fetch('http://localhost:8000/api/v1/add-new-merch', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ ...newMerch, avatar_url: 'merch/' + file.name }) }) .then(res => res.json()) .then(data => { + addMerchPhoto(file); setLoading(false); return setModal(false); }) .catch(err => { setLoading(false); return setModal(false); - }); + }) return null; } @@ -68,8 +75,8 @@ export const Modal = ({ modal, setModal, data }) => { setNewMerch({ ...newMerch, price: +e.target.value })} value={newMerch.price} placeholder='Price' /> - setFile(e.target.files[0])} id='merch-img' /> - + setFile(e.target.files[0])} id='merch-img' /> +
) diff --git a/src/routes/Main/MainPage.js b/src/routes/Main/MainPage.js index 6560a73..fa1476d 100644 --- a/src/routes/Main/MainPage.js +++ b/src/routes/Main/MainPage.js @@ -8,9 +8,13 @@ import plusImg from '../../assets/img/plus.svg'; import '../../assets/styles/MainPage.scss'; export const MainPage = () => { - const [modal, setModal] = useState(false); + let [modal, setModal] = useState(false); + let { addMerches, merches, loading, setMerchToEdit } = useContext(MerchContext); + let [data, setData] = useState({ + modal, + setModal + }); - const { addMerches, merches, loading } = useContext(MerchContext); useEffect(() => { fetch('http://localhost:8000/api/v1/get-all-merch') .then(res => res.json()) @@ -19,18 +23,36 @@ export const MainPage = () => { return undefined; }, [loading]); + const openModal = (e, merch = null) => { + let { className } = e.target.parentElement; + if (className === 'add-img' || className === 'add-item') { + setData({ + ...data, + type: 'add' + }); + setModal(true); + } else { + setData({ + ...data, + type: 'edit', + }); + setMerchToEdit(merch); + setModal(true); + } + }; + return (
-
Plus
{merches.map(merch => ( - + ))}
+
openModal(e)}>Plus
- +
); }; From 0be64455133253ddf308cf4418098d185018cf25 Mon Sep 17 00:00:00 2001 From: Mishawaka Date: Wed, 1 Apr 2020 11:32:00 +0300 Subject: [PATCH 7/7] Added Merch and News pages --- src/App.js | 7 +- src/assets/styles/LoginForm.scss | 4 +- src/assets/styles/MainPage.scss | 2 +- src/assets/styles/Modal.scss | 7 +- src/assets/styles/styles.scss | 16 ++- src/components/GridItem/GridItem.jsx | 62 +++++++--- .../Modal.jsx => MerchModal/MerchModal.jsx} | 4 +- src/components/NewsModal/NewsModal.jsx | 109 ++++++++++++++++++ src/contexts/NewsContext.js | 43 +++++++ src/routes/Main/MainPage.js | 6 +- src/routes/NewsPage/NewsPage.js | 51 +++++++- 11 files changed, 280 insertions(+), 31 deletions(-) rename src/components/{Modal/Modal.jsx => MerchModal/MerchModal.jsx} (98%) create mode 100644 src/components/NewsModal/NewsModal.jsx create mode 100644 src/contexts/NewsContext.js diff --git a/src/App.js b/src/App.js index 21c2f5c..f18ec8d 100644 --- a/src/App.js +++ b/src/App.js @@ -13,6 +13,7 @@ import './assets/styles/styles.scss'; import './assets/styles/normalize/normalize.scss'; import { ProtectedRoute } from './routes/ProtectedRoute/ProtectedRoute'; import { MerchProvider } from './contexts/MerchContext'; +import { NewsProvider } from './contexts/NewsContext'; function App() { return ( @@ -20,11 +21,13 @@ function App() { - + - + + + diff --git a/src/assets/styles/LoginForm.scss b/src/assets/styles/LoginForm.scss index 56ed5d9..949b1b1 100644 --- a/src/assets/styles/LoginForm.scss +++ b/src/assets/styles/LoginForm.scss @@ -14,10 +14,12 @@ flex-direction: column; width: 60%; margin: 0 auto; + & > input, textarea{ + margin-top: 20px; + } } .login , .password { - margin-top: 20px; border: 0; border-radius: 7px; padding: 10px; diff --git a/src/assets/styles/MainPage.scss b/src/assets/styles/MainPage.scss index 01ee956..721bdb6 100644 --- a/src/assets/styles/MainPage.scss +++ b/src/assets/styles/MainPage.scss @@ -20,7 +20,7 @@ transition: 1s; display: flex; align-items: center; - justify-content: end; + justify-content: flex-end; &:hover{ background-color: gray; } diff --git a/src/assets/styles/Modal.scss b/src/assets/styles/Modal.scss index 531cec3..2201d87 100644 --- a/src/assets/styles/Modal.scss +++ b/src/assets/styles/Modal.scss @@ -10,7 +10,7 @@ align-items: center; justify-content: center; background-color: $grey; - opacity: 0.8; + opacity: 0.98; & > .form{ width: 35%; height: 40%; @@ -19,7 +19,10 @@ align-items: center; justify-content: space-evenly; opacity: 1; - background-color: $back-content; + + & textarea{ + width: 93%; + } & h2{ color: white; diff --git a/src/assets/styles/styles.scss b/src/assets/styles/styles.scss index 846ee5e..1daccde 100644 --- a/src/assets/styles/styles.scss +++ b/src/assets/styles/styles.scss @@ -11,4 +11,18 @@ body { .container{ display: flex; justify-content: space-between; -} \ No newline at end of file +} + +textarea{ + display: block; + box-sizing: padding-box; + overflow: hidden; + + padding: 10px; + width: 250px; + font-size: 14px; + margin: 50px auto; + border-radius: 6px; + box-shadow: 2px 2px 8px rgba(black, .3); + border: 0; + } \ No newline at end of file diff --git a/src/components/GridItem/GridItem.jsx b/src/components/GridItem/GridItem.jsx index 2c18be5..efeb3e9 100644 --- a/src/components/GridItem/GridItem.jsx +++ b/src/components/GridItem/GridItem.jsx @@ -1,21 +1,34 @@ import React, { useContext } from 'react'; -import { Modal } from '../Modal/Modal'; -import img from '../../assets/img/space.png'; import { MerchContext } from '../../contexts/MerchContext'; +import { NewsContext } from '../../contexts/NewsContext'; -export const GridItem = ({ merch, openModal }) => { - let { name, price, avatar_url } = merch; - let { setLoading } = useContext(MerchContext); +export const GridItem = ({ item, openModal }) => { + let fecthUrl = ''; + let header = '', description = '', news_picture_url = '', name = '', price = '', avatar_url = '', setLoading = ''; + let whichPage = Object.keys(item).includes('avatar_url'); + if (whichPage) { + name = item.name; + price = item.price; + avatar_url = item.avatar_url; + setLoading = useContext(MerchContext).setLoading; + fecthUrl = 'http://localhost:8000/api/v1/delete-merch'; + } else { + header = item.header; + description = item.content; + news_picture_url = item.news_picture_url; + setLoading = useContext(NewsContext).setLoading; + fecthUrl = 'http://localhost:8000/api/v1/delete-article'; + } const deleteMerch = () => { let conf = confirm('Are you sure'); if (conf) { setLoading(true); - fetch('http://localhost:8000/api/v1/delete-merch', { + fetch(fecthUrl, { method: 'DELETE', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(merch) + body: JSON.stringify(item) }) .then(res => res.json()) .then(data => setLoading(false)) @@ -26,16 +39,33 @@ export const GridItem = ({ merch, openModal }) => { return (
-
t-shirt
-
-

{name}

-

{price} ₴

+ { + whichPage ? + ( +
+
t-shirt
+
+

{name}

+

{price} ₴

+
+
+ ) + : + ( +
+
t-shirt
+
+

{header}

+

{description}

+
+
+ ) + } +
+
openModal(e, item)}>Edit
+
Delete
-
-
-
openModal(e, merch)}>Edit
-
Delete
-
+
); } \ No newline at end of file diff --git a/src/components/Modal/Modal.jsx b/src/components/MerchModal/MerchModal.jsx similarity index 98% rename from src/components/Modal/Modal.jsx rename to src/components/MerchModal/MerchModal.jsx index f72cc3c..f698efd 100644 --- a/src/components/Modal/Modal.jsx +++ b/src/components/MerchModal/MerchModal.jsx @@ -5,9 +5,9 @@ import { Loader } from '../Loader/Loader'; import closeImg from '../../assets/img/close.svg'; -export const Modal = ({ modal, setModal, data }) => { - let className = modal ? 'modal-show' : 'modal-hide'; +export const MerchModal = ({ data, modal, setModal }) => { let { type } = data; + let className = modal ? 'modal-show' : 'modal-hide'; const { merchToEdit, setMerchToEdit, loading, setLoading } = useContext(MerchContext); const [newMerch, setNewMerch] = useState({ name: '', price: '' }); const [file, setFile] = useState(''); diff --git a/src/components/NewsModal/NewsModal.jsx b/src/components/NewsModal/NewsModal.jsx new file mode 100644 index 0000000..fb4d7a1 --- /dev/null +++ b/src/components/NewsModal/NewsModal.jsx @@ -0,0 +1,109 @@ +import React, { useState, useContext } from 'react'; +import '../../assets/styles/Modal.scss'; +import { NewsContext } from '../../contexts/NewsContext'; +import { Loader } from '../Loader/Loader'; + +import closeImg from '../../assets/img/close.svg'; + +export const NewsModal = ({ modal, setModal, data }) => { + let className = modal ? 'modal-show' : 'modal-hide'; + let { type } = data; + const { articleToEdit, setArticleToEdit, loading, setLoading } = useContext(NewsContext); + const [newArticle, setNewArticle] = useState({ header: '', content: '' }); + const [file, setFile] = useState(''); + + const editArticle = article => { + setLoading(true); + fetch('http://localhost:8000/api/v1/edit-article', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(article) + }) + .then(res => res.json()) + .then(data => { + setLoading(false); + return setModal(false); + }) + .catch(err => { + setLoading(false); + return setModal(false); + }); + return null; + } + + const addArticlePhoto = async photo => { + let form = new FormData(); + form.append('photo', photo); + await fetch('http://localhost:8000/api/v1/add-news-photo', { + method: 'POST', + body: form + }) + .then(res => res.json()) + .catch(err => err.json()); + }; + + const addNewArticle = () => { + setLoading(true); + fetch('http://localhost:8000/api/v1/add-new-article', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ ...newArticle, news_picture_url: 'news/' + file.name }) + }) + .then(res => res.json()) + .then(data => { + addArticlePhoto(file); + setLoading(false); + return setModal(false); + }) + .catch(err => { + setLoading(false); + return setModal(false); + }) + return null; + } + + const autoExpand = e => { + e.target.style.height = 'auto'; + // for box-sizing other than "content-box" use: + // el.style.cssText = '-moz-box-sizing:content-box'; + e.target.style.height = e.target.scrollHeight + 'px'; + } + + return ( +
+
setModal(false)} className='add-img'>Close
+
+ {type === 'add' ? ( +
+

Add new article

+ setNewArticle({ ...newArticle, header: e.target.value })} + value={newArticle.header} placeholder='Article Name' /> + + setFile(e.target.files[0])} id='news-img' /> + + +
+ ) + : + ( +
+

Edit article info

+ setArticleToEdit({ ...articleToEdit, header: e.target.value })} + value={articleToEdit.header} placeholder='Article Name' /> + + + +
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/src/contexts/NewsContext.js b/src/contexts/NewsContext.js new file mode 100644 index 0000000..2037c1d --- /dev/null +++ b/src/contexts/NewsContext.js @@ -0,0 +1,43 @@ +import React, { createContext, useState } from 'react'; + +export const NewsContext = createContext(); + +export const NewsProvider = ({ children }) => { + const lorem = 'Lorem ipsum dolor sit amet'; + + const newsObj = [ + { + id: 1, + header: 'Header 1', + content: lorem, + news_picture_url: 'some_url' + }, + { + id: 2, + header: 'Header 2', + content: lorem, + news_picture_url: 'some_url' + }, + { + id: 3, + header: 'Header 3', + content: lorem, + news_picture_url: 'some_url' + }, + { + id: 4, + header: 'Header 4', + content: lorem, + news_picture_url: 'some_url' + }, + ]; + let [loading, setLoading] = useState(false); + let [news, setNews] = useState(newsObj); + let [articleToEdit, setArticleToEdit] = useState({}); + const addNews = obj => setNews(obj); + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/src/routes/Main/MainPage.js b/src/routes/Main/MainPage.js index fa1476d..e2ecf93 100644 --- a/src/routes/Main/MainPage.js +++ b/src/routes/Main/MainPage.js @@ -1,7 +1,7 @@ import React, { useState, useEffect, useContext } from 'react'; import { GridItem } from '../../components/GridItem/GridItem'; import { Sidebar } from '../../components/Sidebar/Sidebar'; -import { Modal } from '../../components/Modal/Modal'; +import { MerchModal } from '../../components/MerchModal/MerchModal'; import { MerchContext } from '../../contexts/MerchContext'; import plusImg from '../../assets/img/plus.svg'; @@ -47,12 +47,12 @@ export const MainPage = () => {
{merches.map(merch => ( - + ))}
openModal(e)}>Plus
- +
); }; diff --git a/src/routes/NewsPage/NewsPage.js b/src/routes/NewsPage/NewsPage.js index c42c9d2..cf82916 100644 --- a/src/routes/NewsPage/NewsPage.js +++ b/src/routes/NewsPage/NewsPage.js @@ -1,11 +1,56 @@ -import React from 'react'; +import React, { useContext, useState, useEffect } from 'react'; import { Sidebar } from '../../components/Sidebar/Sidebar'; +import { NewsContext } from '../../contexts/NewsContext'; +import { GridItem } from '../../components/GridItem/GridItem'; +import { NewsModal } from '../../components/NewsModal/NewsModal'; +import plusImg from '../../assets/img/plus.svg'; + export const NewsPage = () => { + const { news, addNews, loading, setArticleToEdit } = useContext(NewsContext); + const [modal, setModal] = useState(false); + const [data, setData] = useState({ + modal, setModal + }); + + useEffect(() => { + fetch('http://localhost:8000/api/v1/get-all-news') + .then(res => res.json()) + .then(data => addNews(data)) + .catch(err => console.log(err)); + return undefined; + }, [loading]); + + const openModal = (e, article = null) => { + let { className } = e.target.parentElement; + if (className === 'add-img' || className === 'add-item') { + setData({ + ...data, + type: 'add' + }); + setModal(true); + } else { + setData({ + ...data, + type: 'edit', + }); + setArticleToEdit(article); + setModal(true); + } + }; + return ( -
+
-

Hello World!

+
+
+ {news.map(article => ( + + ))} +
+
openModal(e)}>Plus
+
+
); } \ No newline at end of file