Showing
22 changed files
with
322 additions
and
242 deletions
... | @@ -2312,6 +2312,11 @@ | ... | @@ -2312,6 +2312,11 @@ |
2312 | "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", | 2312 | "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", |
2313 | "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" | 2313 | "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" |
2314 | }, | 2314 | }, |
2315 | + "attr-accept": { | ||
2316 | + "version": "2.2.2", | ||
2317 | + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", | ||
2318 | + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==" | ||
2319 | + }, | ||
2315 | "autoprefixer": { | 2320 | "autoprefixer": { |
2316 | "version": "9.7.5", | 2321 | "version": "9.7.5", |
2317 | "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.5.tgz", | 2322 | "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.5.tgz", |
... | @@ -5530,6 +5535,21 @@ | ... | @@ -5530,6 +5535,21 @@ |
5530 | "schema-utils": "^2.5.0" | 5535 | "schema-utils": "^2.5.0" |
5531 | } | 5536 | } |
5532 | }, | 5537 | }, |
5538 | + "file-selector": { | ||
5539 | + "version": "0.2.4", | ||
5540 | + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.2.4.tgz", | ||
5541 | + "integrity": "sha512-ZDsQNbrv6qRi1YTDOEWzf5J2KjZ9KMI1Q2SGeTkCJmNNW25Jg4TW4UMcmoqcg4WrAyKRcpBXdbWRxkfrOzVRbA==", | ||
5542 | + "requires": { | ||
5543 | + "tslib": "^2.0.3" | ||
5544 | + }, | ||
5545 | + "dependencies": { | ||
5546 | + "tslib": { | ||
5547 | + "version": "2.2.0", | ||
5548 | + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", | ||
5549 | + "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==" | ||
5550 | + } | ||
5551 | + } | ||
5552 | + }, | ||
5533 | "file-uri-to-path": { | 5553 | "file-uri-to-path": { |
5534 | "version": "1.0.0", | 5554 | "version": "1.0.0", |
5535 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", | 5555 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", |
... | @@ -11692,6 +11712,16 @@ | ... | @@ -11692,6 +11712,16 @@ |
11692 | "scheduler": "^0.19.1" | 11712 | "scheduler": "^0.19.1" |
11693 | } | 11713 | } |
11694 | }, | 11714 | }, |
11715 | + "react-dropzone": { | ||
11716 | + "version": "11.3.2", | ||
11717 | + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-11.3.2.tgz", | ||
11718 | + "integrity": "sha512-Z0l/YHcrNK1r85o6RT77Z5XgTARmlZZGfEKBl3tqTXL9fZNQDuIdRx/J0QjvR60X+yYu26dnHeaG2pWU+1HHvw==", | ||
11719 | + "requires": { | ||
11720 | + "attr-accept": "^2.2.1", | ||
11721 | + "file-selector": "^0.2.2", | ||
11722 | + "prop-types": "^15.7.2" | ||
11723 | + } | ||
11724 | + }, | ||
11695 | "react-error-overlay": { | 11725 | "react-error-overlay": { |
11696 | "version": "6.0.7", | 11726 | "version": "6.0.7", |
11697 | "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz", | 11727 | "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz", | ... | ... |
... | @@ -5,10 +5,13 @@ | ... | @@ -5,10 +5,13 @@ |
5 | "dependencies": { | 5 | "dependencies": { |
6 | "antd": "^3.24.1", | 6 | "antd": "^3.24.1", |
7 | "axios": "^0.19.2", | 7 | "axios": "^0.19.2", |
8 | + "core-js": "^3.6.4", | ||
8 | "formik": "^1.5.8", | 9 | "formik": "^1.5.8", |
9 | "moment": "^2.24.0", | 10 | "moment": "^2.24.0", |
10 | "react": "^16.8.6", | 11 | "react": "^16.8.6", |
12 | + "react-app-polyfill": "^1.0.6", | ||
11 | "react-dom": "^16.8.6", | 13 | "react-dom": "^16.8.6", |
14 | + "react-dropzone": "^11.3.2", | ||
12 | "react-icons": "^3.7.0", | 15 | "react-icons": "^3.7.0", |
13 | "react-redux": "^7.1.0-rc.1", | 16 | "react-redux": "^7.1.0-rc.1", |
14 | "react-router-dom": "^5.0.1", | 17 | "react-router-dom": "^5.0.1", |
... | @@ -16,9 +19,7 @@ | ... | @@ -16,9 +19,7 @@ |
16 | "redux": "^4.0.0", | 19 | "redux": "^4.0.0", |
17 | "redux-promise": "^0.6.0", | 20 | "redux-promise": "^0.6.0", |
18 | "redux-thunk": "^2.3.0", | 21 | "redux-thunk": "^2.3.0", |
19 | - "yup": "^0.27.0", | 22 | + "yup": "^0.27.0" |
20 | - "core-js": "^3.6.4", | ||
21 | - "react-app-polyfill": "^1.0.6" | ||
22 | }, | 23 | }, |
23 | "scripts": { | 24 | "scripts": { |
24 | "start": "react-scripts start", | 25 | "start": "react-scripts start", | ... | ... |
We-Shop/client/public/logo192.png
deleted
100644 → 0
5.22 KB
We-Shop/client/public/logo512.png
deleted
100644 → 0
9.44 KB
We-Shop/client/public/robots.txt
deleted
100644 → 0
We-Shop/client/src/App.css
deleted
100644 → 0
1 | -.App { | ||
2 | - text-align: center; | ||
3 | -} | ||
4 | - | ||
5 | -.App-logo { | ||
6 | - height: 40vmin; | ||
7 | - pointer-events: none; | ||
8 | -} | ||
9 | - | ||
10 | -@media (prefers-reduced-motion: no-preference) { | ||
11 | - .App-logo { | ||
12 | - animation: App-logo-spin infinite 20s linear; | ||
13 | - } | ||
14 | -} | ||
15 | - | ||
16 | -.App-header { | ||
17 | - background-color: #282c34; | ||
18 | - min-height: 100vh; | ||
19 | - display: flex; | ||
20 | - flex-direction: column; | ||
21 | - align-items: center; | ||
22 | - justify-content: center; | ||
23 | - font-size: calc(10px + 2vmin); | ||
24 | - color: white; | ||
25 | -} | ||
26 | - | ||
27 | -.App-link { | ||
28 | - color: #61dafb; | ||
29 | -} | ||
30 | - | ||
31 | -@keyframes App-logo-spin { | ||
32 | - from { | ||
33 | - transform: rotate(0deg); | ||
34 | - } | ||
35 | - to { | ||
36 | - transform: rotate(360deg); | ||
37 | - } | ||
38 | -} |
1 | -import axios from 'axios'; | ||
2 | -import { | ||
3 | - LOGIN_USER, | ||
4 | - REGISTER_USER, | ||
5 | - AUTH_USER | ||
6 | -} from './types'; | ||
7 | -export function loginUser(logInfo) { | ||
8 | - const request = axios.post('/api/users/login', logInfo) // logInfo를 post로 전달 | ||
9 | - .then(response => response.data); // 서버에서 받은 데이터를 request에 저장 | ||
10 | - | ||
11 | - return { // return을 통해 Reducer로 보냄 | ||
12 | - // Reducer에서 previousState, action을 이용해 nextState로 만들기 때문 :: (previousState, action) => nextState | ||
13 | - // request를 reducer로 보내는 작업 | ||
14 | - | ||
15 | - // action은 type과 response을 넣어줘야 함 | ||
16 | - type: "LOGIN_USER", | ||
17 | - payload: request // payroad == response | ||
18 | - } | ||
19 | -} | ||
20 | - | ||
21 | -export function RegisterUser(regInfo) { | ||
22 | - const request = axios.post('/api/users/register', regInfo) // logInfo를 post로 전달 | ||
23 | - .then(response => response.data); // 서버에서 받은 데이터를 request에 저장 | ||
24 | - | ||
25 | - return { // return을 통해 Reducer로 보냄. | ||
26 | - // Reducer에서 previousState, action을 이용해 nextState로 만들기 때문 :: (previousState, action) => nextState | ||
27 | - // request를 reducer로 보내는 작업 | ||
28 | - | ||
29 | - // action은 type과 response을 넣어줘야 함 | ||
30 | - type: "REGISTER_USER", | ||
31 | - payload: request // payroad == response | ||
32 | - } | ||
33 | -} | ||
34 | - | ||
35 | -export function auth() { | ||
36 | - const request = axios.get('/api/users/auth') // logInfo를 post로 전달 | ||
37 | - .then(response => response.data); // 서버에서 받은 데이터를 request에 저장 | ||
38 | - | ||
39 | - return { | ||
40 | - | ||
41 | - type: "AUTH_USER", | ||
42 | - payload: request // payroad == response | ||
43 | - } | ||
44 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -5,6 +5,7 @@ import Auth from "../hoc/auth"; | ... | @@ -5,6 +5,7 @@ import Auth from "../hoc/auth"; |
5 | import LandingPage from "./views/LandingPage/LandingPage.js"; | 5 | import LandingPage from "./views/LandingPage/LandingPage.js"; |
6 | import LoginPage from "./views/LoginPage/LoginPage.js"; | 6 | import LoginPage from "./views/LoginPage/LoginPage.js"; |
7 | import RegisterPage from "./views/RegisterPage/RegisterPage.js"; | 7 | import RegisterPage from "./views/RegisterPage/RegisterPage.js"; |
8 | +import UploadPage from './views/UploadPage/UploadPage'; | ||
8 | import NavBar from "./views/NavBar/NavBar"; | 9 | import NavBar from "./views/NavBar/NavBar"; |
9 | import Footer from "./views/Footer/Footer" | 10 | import Footer from "./views/Footer/Footer" |
10 | 11 | ||
... | @@ -21,6 +22,7 @@ function App() { | ... | @@ -21,6 +22,7 @@ function App() { |
21 | <Route exact path="/" component={Auth(LandingPage, null)} /> | 22 | <Route exact path="/" component={Auth(LandingPage, null)} /> |
22 | <Route exact path="/login" component={Auth(LoginPage, false)} /> | 23 | <Route exact path="/login" component={Auth(LoginPage, false)} /> |
23 | <Route exact path="/register" component={Auth(RegisterPage, false)} /> | 24 | <Route exact path="/register" component={Auth(RegisterPage, false)} /> |
25 | + <Route exact path="/upload" component={Auth(UploadPage, true)} /> | ||
24 | </Switch> | 26 | </Switch> |
25 | </div> | 27 | </div> |
26 | <Footer /> | 28 | <Footer /> | ... | ... |
1 | +import React from 'react' | ||
2 | +import Dropzone from 'react-dropzone' | ||
3 | +import axios from 'axios'; | ||
4 | + | ||
5 | +function ImageUpload() { | ||
6 | + | ||
7 | + const imageDropEvent = (files) => { | ||
8 | + let imageData = new FormData(); | ||
9 | + | ||
10 | + const config = { | ||
11 | + header: {'content-type': 'multipart/image-data'} | ||
12 | + } | ||
13 | + imageData.append("file", files[0]) | ||
14 | + | ||
15 | + // 이미지 전달 | ||
16 | + axios.post('/api/product/image', imageData, config) | ||
17 | + .then(response => { | ||
18 | + if (response.data.success) { | ||
19 | + console.log(response.data) | ||
20 | + } | ||
21 | + else { | ||
22 | + alert('파일 저장을 실패했습니다.') | ||
23 | + } | ||
24 | + }) | ||
25 | + | ||
26 | + } | ||
27 | + return ( | ||
28 | + <div style={ {display:'flex', justifyContent:'space-between'}}> | ||
29 | + <Dropzone onDrop={imageDropEvent}> | ||
30 | + {({getRootProps, getInputProps}) => ( | ||
31 | + <section> | ||
32 | + <div style={{ | ||
33 | + width: 300, height: 200, border: '1px solid lightgray', borderRadius: '1em', display: 'flex', | ||
34 | + alignItems: 'center', textAlign: 'center', justifyContent: 'center' | ||
35 | + }} | ||
36 | + {...getRootProps()}> | ||
37 | + <input {...getInputProps()} /> | ||
38 | + <p>이곳을 클릭하여 <br/> 상품 사진을 업로드 해주세요.</p> | ||
39 | + </div> | ||
40 | + </section> | ||
41 | + )} | ||
42 | +</Dropzone> | ||
43 | + </div> | ||
44 | + ) | ||
45 | +} | ||
46 | + | ||
47 | +export default ImageUpload |
... | @@ -36,6 +36,9 @@ function RightMenu(props) { | ... | @@ -36,6 +36,9 @@ function RightMenu(props) { |
36 | } else { | 36 | } else { |
37 | return ( | 37 | return ( |
38 | <Menu mode={props.mode}> | 38 | <Menu mode={props.mode}> |
39 | + <Menu.Item key="upload"> | ||
40 | + <a href="/upload">업로드</a> | ||
41 | + </Menu.Item> | ||
39 | <Menu.Item key="logout"> | 42 | <Menu.Item key="logout"> |
40 | <a onClick={logoutHandler}>로그아웃</a> | 43 | <a onClick={logoutHandler}>로그아웃</a> |
41 | </Menu.Item> | 44 | </Menu.Item> | ... | ... |
1 | -import React from 'react'; | ||
2 | -import { Menu } from 'antd'; | ||
3 | -const SubMenu = Menu.SubMenu; | ||
4 | -const MenuItemGroup = Menu.ItemGroup; | ||
5 | - | ||
6 | -function LeftMenu(props) { | ||
7 | - return ( | ||
8 | - <Menu mode={props.mode}> | ||
9 | - <Menu.Item key="mail"> | ||
10 | - <a href="/">Home</a> | ||
11 | - </Menu.Item> | ||
12 | - <SubMenu title={<span>Blogs</span>}> | ||
13 | - <MenuItemGroup title="Item 1"> | ||
14 | - <Menu.Item key="setting:1">Option 1</Menu.Item> | ||
15 | - <Menu.Item key="setting:2">Option 2</Menu.Item> | ||
16 | - </MenuItemGroup> | ||
17 | - <MenuItemGroup title="Item 2"> | ||
18 | - <Menu.Item key="setting:3">Option 3</Menu.Item> | ||
19 | - <Menu.Item key="setting:4">Option 4</Menu.Item> | ||
20 | - </MenuItemGroup> | ||
21 | - </SubMenu> | ||
22 | - </Menu> | ||
23 | - ) | ||
24 | -} | ||
25 | - | ||
26 | -export default LeftMenu | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
File mode changed
1 | -/* eslint-disable jsx-a11y/anchor-is-valid */ | ||
2 | -import React from 'react'; | ||
3 | -import { Menu } from 'antd'; | ||
4 | -import axios from 'axios'; | ||
5 | -//import { USER_SERVER } from '../../../Config'; | ||
6 | -import { withRouter } from 'react-router-dom'; | ||
7 | -import { useSelector } from "react-redux"; | ||
8 | - | ||
9 | -function RightMenu(props) { | ||
10 | - const user = useSelector(state => state.user) | ||
11 | - | ||
12 | - const logoutHandler = () => { | ||
13 | - axios.get('/api/users/logout').then(response => { | ||
14 | - if (response.status === 200) { | ||
15 | - props.history.push("/login"); | ||
16 | - } else { | ||
17 | - alert('Log Out Failed') | ||
18 | - } | ||
19 | - }); | ||
20 | - }; | ||
21 | - | ||
22 | - //console.log(user.userData) | ||
23 | - //console.log(!user.userData.isAuth) | ||
24 | - if (user.userData && !user.userData.isAuth) { | ||
25 | - return ( | ||
26 | - <Menu mode={props.mode}> | ||
27 | - <Menu.Item key="mail"> | ||
28 | - <a href="/login">Signin</a> | ||
29 | - </Menu.Item> | ||
30 | - <Menu.Item key="app"> | ||
31 | - <a href="/register">Signup</a> | ||
32 | - </Menu.Item> | ||
33 | - </Menu> | ||
34 | - ) | ||
35 | - } else { | ||
36 | - return ( | ||
37 | - <Menu mode={props.mode}> | ||
38 | - <Menu.Item key="logout"> | ||
39 | - <a onClick={logoutHandler}>Logout</a> | ||
40 | - </Menu.Item> | ||
41 | - </Menu> | ||
42 | - ) | ||
43 | - } | ||
44 | -} | ||
45 | - | ||
46 | -export default withRouter(RightMenu); | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | -import React from 'react' | 1 | +import React from 'react'; |
2 | +import { useState } from 'react'; | ||
3 | +import { Typography, Button, Form, Input } from 'antd'; // css | ||
4 | +import ImageUpload from '../../utils/ImageUpload' | ||
5 | + | ||
6 | +const { TextArea } = Input; // 박스크기 조절을 사용자가 임의로 가능하게 함. | ||
7 | + | ||
8 | +// Select Options | ||
9 | +const options = [{ key: 1, value: "a" }, | ||
10 | + { key: 2, value: "b" }, | ||
11 | + {key: 3, value : "c"} | ||
12 | +] | ||
2 | 13 | ||
3 | function UploadPage() { | 14 | function UploadPage() { |
15 | + | ||
16 | + // OnChange Function | ||
17 | + | ||
18 | + const [Image, setImage] = useState("") | ||
19 | + const [Title, setTitle] = useState(""); | ||
20 | + const [Info, setInfo] = useState(""); | ||
21 | + const [Cost, setCost] = useState(""); | ||
22 | + const [Option, setOption] = useState(1); | ||
23 | + | ||
24 | + const titleEvent = (event) => { | ||
25 | + setTitle(event.currentTarget.value); | ||
26 | + } | ||
27 | + | ||
28 | + const infoEvent = (event) => { | ||
29 | + setInfo(event.currentTarget.value); | ||
30 | + } | ||
31 | + | ||
32 | + const costEvent = (event) => { | ||
33 | + setCost(event.currentTarget.value); | ||
34 | + } | ||
35 | + | ||
36 | + | ||
37 | + const optionEvent = (event) => { | ||
38 | + setOption(event.currentTarget.value); | ||
39 | + } | ||
40 | + | ||
41 | + | ||
42 | + const imageEvent = (event) => { | ||
43 | + setImage(event.currentTarget.value); | ||
44 | + } | ||
45 | + | ||
46 | + | ||
4 | return ( | 47 | return ( |
5 | - <div> | 48 | + <div style={{ maxWidth: '700px', margin: '2rem auto' }}> |
6 | - uploadpage | 49 | + |
50 | + <div style={{ textAlign: 'center', marginBottom:'2rem'}}> | ||
51 | + <h2> 업로드 </h2> | ||
52 | + | ||
53 | + </div> | ||
54 | + | ||
55 | + <Form> | ||
56 | + {/* 파일업로드 부분은 코드가 길어서 따로 컴포넌트로 만들었습니다. */} | ||
57 | + <ImageUpload /> | ||
58 | + <br /> | ||
59 | + <br /> | ||
60 | + <label>이름</label> | ||
61 | + <Input onChange={ titleEvent} value={Title} /> | ||
62 | + {/* ㄴ ant design에서 가져온 Input */} | ||
63 | + <br /> | ||
64 | + <br /> | ||
65 | + <label>설명</label> | ||
66 | + <TextArea onChange={ infoEvent} value={Info} /> | ||
67 | + <br /> | ||
68 | + <br /> | ||
69 | + <label>가격</label> | ||
70 | + <Input onChange={ costEvent} value={Cost} type="number"/> | ||
71 | + <br /> | ||
72 | + <br /> | ||
73 | + <select onChange={optionEvent} value={ Option}> | ||
74 | + {options.map(item => ( | ||
75 | + <option key={item.key} value={item.key}>{ item.value}</option> | ||
76 | + ))} | ||
77 | + <option></option> | ||
78 | + </select> | ||
79 | + <br /> | ||
80 | + <br /> | ||
81 | + <Button>확인</Button> | ||
82 | + | ||
83 | + </Form> | ||
84 | + | ||
7 | </div> | 85 | </div> |
8 | ) | 86 | ) |
9 | -} | 87 | +} |
10 | 88 | ||
11 | export default UploadPage | 89 | export default UploadPage | ... | ... |
1 | -// 사용자의 상태를 보고 | ||
2 | -// 해당 페이지에 들어갈 수 있게 할지 안할지 결정해 줌. hoc 이용. | ||
3 | -import axios from 'axios'; | ||
4 | -import React, {useEffect} from 'react'; | ||
5 | -//import {useEffect} from 'react'; | ||
6 | -import {useDispatch} from 'react-redux'; | ||
7 | -import {auth} from '../_actions/user_action' | ||
8 | - | ||
9 | - | ||
10 | -export default function (SpecificComponent, option, adminRoute = null){ | ||
11 | - // ㄴ option 종류 | ||
12 | - // - null 아무나 출입 가능한 페이지 | ||
13 | - // - true 로그인한 유저만 출입 가능 | ||
14 | - // - false 로그인한 유저 출입 불가능 | ||
15 | - | ||
16 | - function AuthenticationCheck(props) { | ||
17 | - //1. backend에 request를 날려서 사용자의 상태를 확인 | ||
18 | - const dispatch = useDispatch(); // 1-1. dispatch 사용 | ||
19 | - useEffect(() => { | ||
20 | - dispatch(auth()) // 페이지가 이동할 때마다 dispatch가 작동해서 backend에 request를 줌 | ||
21 | - .then(response => { // 받은 response | ||
22 | - console.log(response); | ||
23 | - | ||
24 | - | ||
25 | - // 로그인 안했다면 | ||
26 | - if(!response.payload.isAuth) { | ||
27 | - if(option) { // 만약 위 option이 true이면 (로그인한 유저만 출입 가능한 페이지로 가게 하려면) | ||
28 | - props.history.push('/login'); // 로그인 하게 함 | ||
29 | - } | ||
30 | - } | ||
31 | - | ||
32 | - // 로그인 했다면 | ||
33 | - else { | ||
34 | - if(adminRoute && !response.payload.isAdmin) { // admin만 갈 수 있는 페이지를 admin이 false 사람이 들어가려 한다면 | ||
35 | - props.history.push('/'); // 홈페이지로 돌아가게 함 | ||
36 | - } | ||
37 | - else { | ||
38 | - if(option===false) {// 로그인한 유저가 출입 불가능한 곳을 가려고 한다면 | ||
39 | - props.history.push('/'); // 홈페이지로 돌아가게 함 | ||
40 | - | ||
41 | - } | ||
42 | - } | ||
43 | - } | ||
44 | - }) | ||
45 | - },[]) | ||
46 | - | ||
47 | - return ( | ||
48 | - <SpecificComponent /> | ||
49 | - ) | ||
50 | - | ||
51 | - } | ||
52 | - | ||
53 | - return AuthenticationCheck | ||
54 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | body { | 1 | body { |
2 | margin: 0; | 2 | margin: 0; |
3 | - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", | 3 | + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", |
4 | - "Droid Sans", "Helvetica Neue", sans-serif; | 4 | + "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", |
5 | + sans-serif; | ||
5 | -webkit-font-smoothing: antialiased; | 6 | -webkit-font-smoothing: antialiased; |
6 | -moz-osx-font-smoothing: grayscale; | 7 | -moz-osx-font-smoothing: grayscale; |
7 | } | 8 | } |
8 | 9 | ||
9 | code { | 10 | code { |
10 | - font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; | 11 | + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", |
12 | + monospace; | ||
11 | } | 13 | } |
12 | 14 | ||
13 | body { | 15 | body { |
14 | - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", | 16 | + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, |
15 | - "Segoe UI Emoji", "Segoe UI Symbol"; | 17 | + sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; |
16 | font-size: 14px; | 18 | font-size: 14px; |
17 | line-height: 1.5; | 19 | line-height: 1.5; |
18 | color: #24292e; | 20 | color: #24292e; |
... | @@ -31,7 +33,6 @@ input.error { | ... | @@ -31,7 +33,6 @@ input.error { |
31 | border-color: red; | 33 | border-color: red; |
32 | } | 34 | } |
33 | 35 | ||
34 | - | ||
35 | .input-feedback { | 36 | .input-feedback { |
36 | color: red; | 37 | color: red; |
37 | height: 5px; | 38 | height: 5px; | ... | ... |
1 | -const reportWebVitals = onPerfEntry => { | ||
2 | - if (onPerfEntry && onPerfEntry instanceof Function) { | ||
3 | - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { | ||
4 | - getCLS(onPerfEntry); | ||
5 | - getFID(onPerfEntry); | ||
6 | - getFCP(onPerfEntry); | ||
7 | - getLCP(onPerfEntry); | ||
8 | - getTTFB(onPerfEntry); | ||
9 | - }); | ||
10 | - } | ||
11 | -}; | ||
12 | - | ||
13 | -export default reportWebVitals; |
We-Shop/client/src/setupTests.js
deleted
100644 → 0
... | @@ -103,6 +103,11 @@ | ... | @@ -103,6 +103,11 @@ |
103 | } | 103 | } |
104 | } | 104 | } |
105 | }, | 105 | }, |
106 | + "append-field": { | ||
107 | + "version": "1.0.0", | ||
108 | + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", | ||
109 | + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" | ||
110 | + }, | ||
106 | "aproba": { | 111 | "aproba": { |
107 | "version": "1.2.0", | 112 | "version": "1.2.0", |
108 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", | 113 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", |
... | @@ -397,6 +402,43 @@ | ... | @@ -397,6 +402,43 @@ |
397 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", | 402 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", |
398 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" | 403 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" |
399 | }, | 404 | }, |
405 | + "buffer-from": { | ||
406 | + "version": "1.1.1", | ||
407 | + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", | ||
408 | + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" | ||
409 | + }, | ||
410 | + "busboy": { | ||
411 | + "version": "0.2.14", | ||
412 | + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", | ||
413 | + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", | ||
414 | + "requires": { | ||
415 | + "dicer": "0.2.5", | ||
416 | + "readable-stream": "1.1.x" | ||
417 | + }, | ||
418 | + "dependencies": { | ||
419 | + "isarray": { | ||
420 | + "version": "0.0.1", | ||
421 | + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", | ||
422 | + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" | ||
423 | + }, | ||
424 | + "readable-stream": { | ||
425 | + "version": "1.1.14", | ||
426 | + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", | ||
427 | + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", | ||
428 | + "requires": { | ||
429 | + "core-util-is": "~1.0.0", | ||
430 | + "inherits": "~2.0.1", | ||
431 | + "isarray": "0.0.1", | ||
432 | + "string_decoder": "~0.10.x" | ||
433 | + } | ||
434 | + }, | ||
435 | + "string_decoder": { | ||
436 | + "version": "0.10.31", | ||
437 | + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", | ||
438 | + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" | ||
439 | + } | ||
440 | + } | ||
441 | + }, | ||
400 | "bytes": { | 442 | "bytes": { |
401 | "version": "3.1.0", | 443 | "version": "3.1.0", |
402 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", | 444 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", |
... | @@ -604,6 +646,17 @@ | ... | @@ -604,6 +646,17 @@ |
604 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", | 646 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", |
605 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" | 647 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" |
606 | }, | 648 | }, |
649 | + "concat-stream": { | ||
650 | + "version": "1.6.2", | ||
651 | + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", | ||
652 | + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", | ||
653 | + "requires": { | ||
654 | + "buffer-from": "^1.0.0", | ||
655 | + "inherits": "^2.0.3", | ||
656 | + "readable-stream": "^2.2.2", | ||
657 | + "typedarray": "^0.0.6" | ||
658 | + } | ||
659 | + }, | ||
607 | "concurrently": { | 660 | "concurrently": { |
608 | "version": "4.1.2", | 661 | "version": "4.1.2", |
609 | "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.2.tgz", | 662 | "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.2.tgz", |
... | @@ -834,6 +887,38 @@ | ... | @@ -834,6 +887,38 @@ |
834 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", | 887 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", |
835 | "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" | 888 | "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" |
836 | }, | 889 | }, |
890 | + "dicer": { | ||
891 | + "version": "0.2.5", | ||
892 | + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", | ||
893 | + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", | ||
894 | + "requires": { | ||
895 | + "readable-stream": "1.1.x", | ||
896 | + "streamsearch": "0.1.2" | ||
897 | + }, | ||
898 | + "dependencies": { | ||
899 | + "isarray": { | ||
900 | + "version": "0.0.1", | ||
901 | + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", | ||
902 | + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" | ||
903 | + }, | ||
904 | + "readable-stream": { | ||
905 | + "version": "1.1.14", | ||
906 | + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", | ||
907 | + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", | ||
908 | + "requires": { | ||
909 | + "core-util-is": "~1.0.0", | ||
910 | + "inherits": "~2.0.1", | ||
911 | + "isarray": "0.0.1", | ||
912 | + "string_decoder": "~0.10.x" | ||
913 | + } | ||
914 | + }, | ||
915 | + "string_decoder": { | ||
916 | + "version": "0.10.31", | ||
917 | + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", | ||
918 | + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" | ||
919 | + } | ||
920 | + } | ||
921 | + }, | ||
837 | "dot-prop": { | 922 | "dot-prop": { |
838 | "version": "4.2.0", | 923 | "version": "4.2.0", |
839 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", | 924 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", |
... | @@ -2644,6 +2729,21 @@ | ... | @@ -2644,6 +2729,21 @@ |
2644 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | 2729 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", |
2645 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" | 2730 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" |
2646 | }, | 2731 | }, |
2732 | + "multer": { | ||
2733 | + "version": "1.4.2", | ||
2734 | + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz", | ||
2735 | + "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==", | ||
2736 | + "requires": { | ||
2737 | + "append-field": "^1.0.0", | ||
2738 | + "busboy": "^0.2.11", | ||
2739 | + "concat-stream": "^1.5.2", | ||
2740 | + "mkdirp": "^0.5.1", | ||
2741 | + "object-assign": "^4.1.1", | ||
2742 | + "on-finished": "^2.3.0", | ||
2743 | + "type-is": "^1.6.4", | ||
2744 | + "xtend": "^4.0.0" | ||
2745 | + } | ||
2746 | + }, | ||
2647 | "nan": { | 2747 | "nan": { |
2648 | "version": "2.14.0", | 2748 | "version": "2.14.0", |
2649 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", | 2749 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", |
... | @@ -3717,6 +3817,11 @@ | ... | @@ -3717,6 +3817,11 @@ |
3717 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", | 3817 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", |
3718 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" | 3818 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" |
3719 | }, | 3819 | }, |
3820 | + "streamsearch": { | ||
3821 | + "version": "0.1.2", | ||
3822 | + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", | ||
3823 | + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" | ||
3824 | + }, | ||
3720 | "string-width": { | 3825 | "string-width": { |
3721 | "version": "1.0.2", | 3826 | "version": "1.0.2", |
3722 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", | 3827 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", |
... | @@ -3913,6 +4018,11 @@ | ... | @@ -3913,6 +4018,11 @@ |
3913 | "mime-types": "~2.1.24" | 4018 | "mime-types": "~2.1.24" |
3914 | } | 4019 | } |
3915 | }, | 4020 | }, |
4021 | + "typedarray": { | ||
4022 | + "version": "0.0.6", | ||
4023 | + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", | ||
4024 | + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" | ||
4025 | + }, | ||
3916 | "undefsafe": { | 4026 | "undefsafe": { |
3917 | "version": "2.0.3", | 4027 | "version": "2.0.3", |
3918 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", | 4028 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", |
... | @@ -4178,6 +4288,11 @@ | ... | @@ -4178,6 +4288,11 @@ |
4178 | "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", | 4288 | "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", |
4179 | "dev": true | 4289 | "dev": true |
4180 | }, | 4290 | }, |
4291 | + "xtend": { | ||
4292 | + "version": "4.0.2", | ||
4293 | + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", | ||
4294 | + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" | ||
4295 | + }, | ||
4181 | "y18n": { | 4296 | "y18n": { |
4182 | "version": "4.0.0", | 4297 | "version": "4.0.0", |
4183 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", | 4298 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", | ... | ... |
... | @@ -25,6 +25,7 @@ | ... | @@ -25,6 +25,7 @@ |
25 | "jsonwebtoken": "^8.5.1", | 25 | "jsonwebtoken": "^8.5.1", |
26 | "moment": "^2.24.0", | 26 | "moment": "^2.24.0", |
27 | "mongoose": "^5.4.20", | 27 | "mongoose": "^5.4.20", |
28 | + "multer": "^1.4.2", | ||
28 | "react-redux": "^5.0.7", | 29 | "react-redux": "^5.0.7", |
29 | "saslprep": "^1.0.3", | 30 | "saslprep": "^1.0.3", |
30 | "supports-color": "^7.1.0" | 31 | "supports-color": "^7.1.0" | ... | ... |
... | @@ -30,6 +30,7 @@ app.use(cors()) | ... | @@ -30,6 +30,7 @@ app.use(cors()) |
30 | 30 | ||
31 | 31 | ||
32 | app.use('/api/users', require('./routes/users')); | 32 | app.use('/api/users', require('./routes/users')); |
33 | +app.use('/api/product', require('./routes/product')); | ||
33 | 34 | ||
34 | 35 | ||
35 | // 이미지 가져오려고 | 36 | // 이미지 가져오려고 | ... | ... |
We-Shop/server/routes/product.js
0 → 100644
1 | +const express = require('express'); | ||
2 | +const { User } = require("../models/User"); | ||
3 | +const { auth } = require("../middleware/auth"); | ||
4 | +const router = express.Router(); | ||
5 | +const multer = require('multer'); | ||
6 | + | ||
7 | + | ||
8 | +var storage = multer.diskStorage({ | ||
9 | + destination: function (req, file, cb) { | ||
10 | + cb(null, 'uploads/') // 어느 폴더에 저장할건지 | ||
11 | + }, | ||
12 | + filename: function (req, file, cb) { | ||
13 | + cb(null, Date.now() + '_' + file.originalname) // 이미지 이름 | ||
14 | + } | ||
15 | + }) | ||
16 | + | ||
17 | +var upload = multer({ storage: storage }).single("file"); | ||
18 | + | ||
19 | +router.post('/image', (req, res) => { | ||
20 | + | ||
21 | + // 클라이언트로부터 받은 이미지 저장 | ||
22 | + upload(req, res, (err) => { | ||
23 | + if (err) return req.json({ success: false, err }) | ||
24 | + return res.json({success: true, filePath: res.req.file.path, fileName: res.req.file.filename}) | ||
25 | + } | ||
26 | + ) | ||
27 | + | ||
28 | +}) | ||
29 | + | ||
30 | +module.exports = router; |
-
Please register or login to post a comment