From 0bc3e51ac820fa52d7b23cfab1c83f74afd04b68 Mon Sep 17 00:00:00 2001 From: EunKo Date: Fri, 17 Apr 2020 17:10:58 +0900 Subject: [PATCH 1/8] index.js --- pages/index.js | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/pages/index.js b/pages/index.js index 6474ebb..e21d766 100644 --- a/pages/index.js +++ b/pages/index.js @@ -1,19 +1,21 @@ -import React from "react"; -import styled from "styled-components"; +import React from 'react'; +import styled from 'styled-components'; -import LoginForm from "../src/components/login-form"; +import LoginForm from '../src/components/login-form'; export default function Home() { - return ( - - 리액트 투-표 - - - ); + return ( + + 리액트 투-표 + + + ); } - +const Title = styled.h1` + font-size: 40px; +`; const Wrapper = styled.div` - min-height: 100vh; - padding: 10rem 40rem; - background-color: Azure; + min-height: 100vh; + padding: 10rem 40rem; + background-color: Azure; `; From 086863f140ad5462364a0c9b1790b95278607943 Mon Sep 17 00:00:00 2001 From: EunKo Date: Fri, 17 Apr 2020 17:53:34 +0900 Subject: [PATCH 2/8] login-form --- src/components/login-form.js | 120 ++++++++++++++++++++++++++++++++--- 1 file changed, 112 insertions(+), 8 deletions(-) diff --git a/src/components/login-form.js b/src/components/login-form.js index 418d945..9126a40 100644 --- a/src/components/login-form.js +++ b/src/components/login-form.js @@ -1,14 +1,118 @@ -import React from "react"; -import styled from "styled-components"; +import React, { useState } from 'react'; +import styled from 'styled-components'; +import axios from 'axios'; + +import VoteForm from './vote-form'; export default function LoginForm() { - return 안녕 나는 로그인 폼!; + const [logForm, setLogForm] = useState({ email: '', password: '' }); + const [isloged, setloged] = useState(false); + + const erasePW = () => { + document.getElementById('password').value = ''; + }; + + const eraseEmail = () => { + document.getElementById('email').value = ''; + }; + + const handleFormChange = (e) => { + setLogForm({ ...logForm, [e.target.id]: e.target.value }); + }; + + const handleSubmit = (logForm) => { + const { email, password } = logForm; + if (email === '' || password === '') { + alert('모든 항목을 입력해주세요!'); + return false; + } else { + axios + .post(process.env.API_HOST + '/auth/signin/', logForm) + .then(function (response) { + console.log(response); + setloged(true); + alert('로그인 성공!'); + }) + .catch(function (error) { + if (error.response.status === 404) { + console.log('unauthorized, logging out ...'); + alert('이메일이 존재하지 않습니다.'); + eraseEmail(); + erasePW(); + } else if (error.response.status === 422) { + alert('비밀번호가 일치하지 않습니다!'); + erasePW(); + } + return Promise.reject(error.response); + }); + } + }; + + return ( +
+ {!isloged && ( + + 로그인 + + + + + + + + + + + )} + + {isloged && } +
+ ); } +const Title = styled.h1` + font-size: 3rem; + margin-bottom: 4rem; + margin-top: 25px; +`; +const Row = styled.div` + display: flex; + flex-direction: row; + //justify-content: space-between; + margin-bottom: 2rem; +`; +const Button = styled.button` + display: block; + margin-left: auto; + font-size: 1.8rem; + padding: 0.5rem 1rem; + border-style: none; + border-radius: 1rem; +`; +const Label = styled.label` + font-size: 20px; + margin-right: auto; + //margin- auto는 display가 block일때만 사용가능 +`; +const Input = styled.input` + width: 75%; + padding: 0.5rem 1rem; + border: 1px solid grey; +`; const Wrapper = styled.div` - width: 100%; - min-height: 30rem; - background-color: white; - font-size: 18px; - padding: 3rem 4rem; + width: 100%; + min-height: 30rem; + background-color: white; + font-size: 18px; + padding: 3rem 4rem; `; From 66f470ab579c71784a02ab75c4544bd4b4f820fe Mon Sep 17 00:00:00 2001 From: EunKo Date: Fri, 17 Apr 2020 17:53:57 +0900 Subject: [PATCH 3/8] vote-form --- src/components/vote-form.js | 125 +++++++++++++++++++++++++++++++++--- 1 file changed, 116 insertions(+), 9 deletions(-) diff --git a/src/components/vote-form.js b/src/components/vote-form.js index 65bc549..ca6bf33 100644 --- a/src/components/vote-form.js +++ b/src/components/vote-form.js @@ -1,14 +1,121 @@ -import React from "react"; -import styled from "styled-components"; +import React, { useState, useEffect } from 'react'; +import axios from 'axios'; -export default function VoteForm() { - return 안녕 나는 투표 폼!; +import styled from 'styled-components'; + +function VoteForm() { + const [candi, setCandi] = useState([]); + const [voteCount, setVoteCount] = useState(); + + useEffect(() => { + getCandidates(); + }, []); + + const getCandidates = async () => { + await axios + .get(process.env.API_HOST + '/candidates/', candi) + .then(({ data }) => { + setCandi(data); + }) + .catch(function (error) { + console.log(error); + }); + }; + + const voteCandidates = async (person) => { + const newUrl = + process.env.API_HOST + '/candidates/' + person._id + '/vote/'; + await axios + .put(newUrl, voteCount) + .then(({ data }) => { + setVoteCount(data); + alert(person.name + '님에게 투표 완료!'); + getCandidates(); + }) + .catch(function (error) { + console.log(error); + alert('투표 실패!'); + }); + }; + let i = 1; + return ( + + + <RedTitle>프론트엔드 인기쟁이</RedTitle>는 누구? + + CEOS 프론트엔드 개발자 인기 순위 및 투표 창입니다. + + {candi + .sort((person1, person2) => { + return person2.voteCount - person1.voteCount; + }) + .map((person) => ( + + {i++}위: + + {person.name} +
[{person.voteCount}표] +
+ +
+ ))} +
+
+ ); } +export default React.memo( + VoteForm, + (prev, next) => prev.voteCount === next.voteCount +); +const Row = styled.div` + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; +`; +const Button = styled.button` + background-color: navy; + color: white; + font-size: 2rem; + padding: 0.5rem 1rem; + border-style: none; + border-radius: 1rem; +`; +const Rank = styled.strong` + font-size: 2.5rem; + margin: 0rem 4rem 1rem 0rem; +`; +const CandiName = styled.p` + font-size: 2.5rem; + display: block; + margin: 0rem auto 1rem 0rem; +`; +const VoteWrap = styled.div` + width: 100%; + padding: 5rem 10rem; + border: 1px solid black; + display: flex; + flex-direction: column; +`; +const Title = styled.span` + font-size: 3rem; + color: black; + display: inline-block; + font-weight: bold; +`; +const RedTitle = styled.span` + font-size: 3rem; + color: crimson; +`; +const SubTitle = styled.h1` + font-size: 2.5rem; + color: grey; +`; const Wrapper = styled.div` - width: 100%; - min-height: 30rem; - background-color: white; - font-size: 18px; - padding: 3rem 4rem; + width: 100%; + min-height: 30rem; + background-color: white; + font-size: 18px; + padding: 3rem 4rem 10rem; `; From 7ed4324e72669233e9558f0e1ed4b4c811ad46c3 Mon Sep 17 00:00:00 2001 From: EunKo Date: Fri, 17 Apr 2020 18:32:42 +0900 Subject: [PATCH 4/8] commit all --- now.json | 12 ++++++++++++ package-lock.json | 31 +++++++++++++++++++++++++++++++ package.json | 1 + src/components/vote-form.js | 6 +++--- 4 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 now.json diff --git a/now.json b/now.json new file mode 100644 index 0000000..c6266b5 --- /dev/null +++ b/now.json @@ -0,0 +1,12 @@ +{ + "version": 2, + "public": false, + "builds": [{ "src": "next.config.js", "use": "@now/next" }], + "build": { + "env": { + "NODE_ENV": "@react-vote-11th-node-env", + "PORT": "@react-vote-11th-port", + "API_HOST": "@react-vote-11th-api-host" + } + } +} diff --git a/package-lock.json b/package-lock.json index a439258..136f0db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1920,6 +1920,37 @@ } } }, + "axios": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz", + "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==", + "requires": { + "follow-redirects": "1.5.10" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", diff --git a/package.json b/package.json index 0e22c09..817c4b9 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "start": "node server" }, "dependencies": { + "axios": "^0.19.2", "compression": "^1.7.4", "dotenv": "^8.2.0", "express": "^4.17.1", diff --git a/src/components/vote-form.js b/src/components/vote-form.js index ca6bf33..5a4b3dd 100644 --- a/src/components/vote-form.js +++ b/src/components/vote-form.js @@ -44,7 +44,7 @@ function VoteForm() { 프론트엔드 인기쟁이는 누구? CEOS 프론트엔드 개발자 인기 순위 및 투표 창입니다. - + {candi .sort((person1, person2) => { return person2.voteCount - person1.voteCount; @@ -59,7 +59,7 @@ function VoteForm() { ))} - + ); } @@ -90,7 +90,7 @@ const CandiName = styled.p` display: block; margin: 0rem auto 1rem 0rem; `; -const VoteWrap = styled.div` +const VoteArea = styled.div` width: 100%; padding: 5rem 10rem; border: 1px solid black; From ae509f683df76cb21c25395e843406f5207a1281 Mon Sep 17 00:00:00 2001 From: EunKo Date: Fri, 17 Apr 2020 18:36:34 +0900 Subject: [PATCH 5/8] removed annotation --- src/components/login-form.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/components/login-form.js b/src/components/login-form.js index 9126a40..592a681 100644 --- a/src/components/login-form.js +++ b/src/components/login-form.js @@ -55,18 +55,12 @@ export default function LoginForm() { 로그인 - + @@ -87,7 +81,6 @@ const Title = styled.h1` const Row = styled.div` display: flex; flex-direction: row; - //justify-content: space-between; margin-bottom: 2rem; `; const Button = styled.button` @@ -102,7 +95,6 @@ const Button = styled.button` const Label = styled.label` font-size: 20px; margin-right: auto; - //margin- auto는 display가 block일때만 사용가능 `; const Input = styled.input` width: 75%; From 17258a20911a11ea0976c1991065937128b827c9 Mon Sep 17 00:00:00 2001 From: EunKo Date: Fri, 17 Apr 2020 20:20:33 +0900 Subject: [PATCH 6/8] modified form style --- .gitignore | 3 ++- src/components/vote-form.js | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index a5ac825..f014060 100644 --- a/.gitignore +++ b/.gitignore @@ -28,4 +28,5 @@ yarn-error.log* .env.development.local .env.test.local .env.production.local -.env* \ No newline at end of file +.env* +.now \ No newline at end of file diff --git a/src/components/vote-form.js b/src/components/vote-form.js index 5a4b3dd..150bd1a 100644 --- a/src/components/vote-form.js +++ b/src/components/vote-form.js @@ -71,22 +71,21 @@ const Row = styled.div` display: flex; flex-direction: row; align-items: center; - justify-content: space-between; `; const Button = styled.button` background-color: navy; color: white; - font-size: 2rem; + font-size: 1.5rem; padding: 0.5rem 1rem; border-style: none; border-radius: 1rem; `; const Rank = styled.strong` - font-size: 2.5rem; + font-size: 1.5rem; margin: 0rem 4rem 1rem 0rem; `; const CandiName = styled.p` - font-size: 2.5rem; + font-size: 1.5rem; display: block; margin: 0rem auto 1rem 0rem; `; @@ -96,6 +95,7 @@ const VoteArea = styled.div` border: 1px solid black; display: flex; flex-direction: column; + justify-content: space-between; `; const Title = styled.span` font-size: 3rem; From 6b8ec7d9ae46a2e1b513b4271f8a5985fe69e049 Mon Sep 17 00:00:00 2001 From: EunKo <58415191+eun-ko@users.noreply.github.com> Date: Fri, 17 Apr 2020 20:41:25 +0900 Subject: [PATCH 7/8] Update README.md --- README.md | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 461c3ec..f9a8573 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,4 @@ # react-vote-11th - -## 실행 방법 - -``` -npm install -npm run dev -``` - -- npm install : 필요한 모든 패키지를 설치합니다. 처음 1번만 실행하면 됩니다. -- npm run dev : react(next) 웹서버를 localhost:3000에서 실행합니다. +vote-form을 구현하는데 시간을 많이 썼던것같습니다 +axios.put에서 url로 각 후보별 id에 해당하는 인자를 어떻게 넘겨줄지가 어려웠고, 투표 버튼을 클릭해서 투표 완료시 화면에 업데이트 하는점도 어려웠습니다 로그인 오류시 폼 초기화하는걸 getElementById로 하느라 input에 props 전달할때 name으로 안하고 id로 해서 [e.target.id]: e.target.value로 했는데 맞는지 모르겠어요.. +useEffect에 대한 이해도 아직 부족하고 axios사용도 많이 미숙한것같습니다ㅠㅠ! From 3b08979fd385d1a34fb9a6b6bf4aae7c3a3abd75 Mon Sep 17 00:00:00 2001 From: EunKo Date: Sat, 18 Apr 2020 17:17:58 +0900 Subject: [PATCH 8/8] =?UTF-8?q?=EB=A6=AC=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/login-form.js | 71 ++++++++++++++++++------------------ src/components/vote-form.js | 34 +++++++---------- 2 files changed, 49 insertions(+), 56 deletions(-) diff --git a/src/components/login-form.js b/src/components/login-form.js index 592a681..f03defb 100644 --- a/src/components/login-form.js +++ b/src/components/login-form.js @@ -5,71 +5,70 @@ import axios from 'axios'; import VoteForm from './vote-form'; export default function LoginForm() { - const [logForm, setLogForm] = useState({ email: '', password: '' }); - const [isloged, setloged] = useState(false); + const [LoginForm, setLoginForm] = useState({ email: '', password: '' }); + const [isloggedIn, setloggedIn] = useState(false); - const erasePW = () => { - document.getElementById('password').value = ''; - }; - - const eraseEmail = () => { - document.getElementById('email').value = ''; + const erase = (name) => () => { + setLoginForm({ + ...loginForm, + [name]: '', + }); }; const handleFormChange = (e) => { - setLogForm({ ...logForm, [e.target.id]: e.target.value }); + setLoginForm({ ...LoginForm, [e.target.name]: e.target.value }); }; - const handleSubmit = (logForm) => { - const { email, password } = logForm; + const handleSubmit = () => { + const { email, password } = LoginForm; if (email === '' || password === '') { alert('모든 항목을 입력해주세요!'); return false; - } else { - axios - .post(process.env.API_HOST + '/auth/signin/', logForm) - .then(function (response) { - console.log(response); - setloged(true); - alert('로그인 성공!'); - }) - .catch(function (error) { - if (error.response.status === 404) { - console.log('unauthorized, logging out ...'); - alert('이메일이 존재하지 않습니다.'); - eraseEmail(); - erasePW(); - } else if (error.response.status === 422) { - alert('비밀번호가 일치하지 않습니다!'); - erasePW(); - } - return Promise.reject(error.response); - }); } + + axios + .post(process.env.API_HOST + '/auth/signin/', LoginForm) + .then((response) => { + console.log(response); + setloggedIn(true); + alert('로그인 성공!'); + }) + .catch((error) => { + if (error.response.status === 404) { + alert('이메일이 존재하지 않습니다.'); + erase('email')(); + erase('password')(); + } + if (error.response.status === 422) { + alert('비밀번호가 일치하지 않습니다!'); + erase('email')(); + } + return Promise.reject(error.response); + }); }; return (
- {!isloged && ( + {!isloggedIn && ( 로그인 - + - + )} - {isloged && } + {isloggedIn && }
); } diff --git a/src/components/vote-form.js b/src/components/vote-form.js index 150bd1a..12824f0 100644 --- a/src/components/vote-form.js +++ b/src/components/vote-form.js @@ -4,7 +4,7 @@ import axios from 'axios'; import styled from 'styled-components'; function VoteForm() { - const [candi, setCandi] = useState([]); + const [candidates, setCandidates] = useState([]); const [voteCount, setVoteCount] = useState(); useEffect(() => { @@ -13,23 +13,22 @@ function VoteForm() { const getCandidates = async () => { await axios - .get(process.env.API_HOST + '/candidates/', candi) + .get(process.env.API_HOST + '/candidates/', candidates) .then(({ data }) => { - setCandi(data); + setCandidates(data); }) - .catch(function (error) { + .catch((error) => { console.log(error); }); }; - const voteCandidates = async (person) => { - const newUrl = - process.env.API_HOST + '/candidates/' + person._id + '/vote/'; + const voteCandidates = async (candidate) => { + const newUrl = `${process.env.API_HOST}/candidates/${candidate._id}/vote/`; await axios .put(newUrl, voteCount) .then(({ data }) => { setVoteCount(data); - alert(person.name + '님에게 투표 완료!'); + alert(candidate.name + '님에게 투표 완료!'); getCandidates(); }) .catch(function (error) { @@ -37,7 +36,7 @@ function VoteForm() { alert('투표 실패!'); }); }; - let i = 1; + return ( @@ -45,13 +44,11 @@ function VoteForm() { CEOS 프론트엔드 개발자 인기 순위 및 투표 창입니다. - {candi - .sort((person1, person2) => { - return person2.voteCount - person1.voteCount; - }) - .map((person) => ( - - {i++}위: + {candidates + .sort((person1, person2) => person2.voteCount - person1.voteCount) + .map((person, index) => ( + + {index + 1}위: {person.name}
[{person.voteCount}표] @@ -63,10 +60,7 @@ function VoteForm() {
); } -export default React.memo( - VoteForm, - (prev, next) => prev.voteCount === next.voteCount -); +export default React.memo(VoteForm); const Row = styled.div` display: flex; flex-direction: row;