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/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사용도 많이 미숙한것같습니다ㅠㅠ!
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/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;
`;
diff --git a/src/components/login-form.js b/src/components/login-form.js
index 418d945..f03defb 100644
--- a/src/components/login-form.js
+++ b/src/components/login-form.js
@@ -1,14 +1,109 @@
-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 [LoginForm, setLoginForm] = useState({ email: '', password: '' });
+ const [isloggedIn, setloggedIn] = useState(false);
+
+ const erase = (name) => () => {
+ setLoginForm({
+ ...loginForm,
+ [name]: '',
+ });
+ };
+
+ const handleFormChange = (e) => {
+ setLoginForm({ ...LoginForm, [e.target.name]: e.target.value });
+ };
+
+ const handleSubmit = () => {
+ const { email, password } = LoginForm;
+ if (email === '' || password === '') {
+ alert('모든 항목을 입력해주세요!');
+ return false;
+ }
+
+ 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 (
+
+ {!isloggedIn && (
+
+ 로그인
+
+
+
+
+
+
+
+
+
+
+ )}
+
+ {isloggedIn && }
+
+ );
}
+const Title = styled.h1`
+ font-size: 3rem;
+ margin-bottom: 4rem;
+ margin-top: 25px;
+`;
+const Row = styled.div`
+ display: flex;
+ flex-direction: row;
+ 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;
+`;
+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;
`;
diff --git a/src/components/vote-form.js b/src/components/vote-form.js
index 65bc549..12824f0 100644
--- a/src/components/vote-form.js
+++ b/src/components/vote-form.js
@@ -1,14 +1,115 @@
-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 [candidates, setCandidates] = useState([]);
+ const [voteCount, setVoteCount] = useState();
+
+ useEffect(() => {
+ getCandidates();
+ }, []);
+
+ const getCandidates = async () => {
+ await axios
+ .get(process.env.API_HOST + '/candidates/', candidates)
+ .then(({ data }) => {
+ setCandidates(data);
+ })
+ .catch((error) => {
+ console.log(error);
+ });
+ };
+
+ const voteCandidates = async (candidate) => {
+ const newUrl = `${process.env.API_HOST}/candidates/${candidate._id}/vote/`;
+ await axios
+ .put(newUrl, voteCount)
+ .then(({ data }) => {
+ setVoteCount(data);
+ alert(candidate.name + '님에게 투표 완료!');
+ getCandidates();
+ })
+ .catch(function (error) {
+ console.log(error);
+ alert('투표 실패!');
+ });
+ };
+
+ return (
+
+
+ 프론트엔드 인기쟁이는 누구?
+
+ CEOS 프론트엔드 개발자 인기 순위 및 투표 창입니다.
+
+ {candidates
+ .sort((person1, person2) => person2.voteCount - person1.voteCount)
+ .map((person, index) => (
+
+ {index + 1}위:
+
+ {person.name}
+
[{person.voteCount}표]
+
+
+
+ ))}
+
+
+ );
}
+export default React.memo(VoteForm);
+const Row = styled.div`
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+`;
+const Button = styled.button`
+ background-color: navy;
+ color: white;
+ font-size: 1.5rem;
+ padding: 0.5rem 1rem;
+ border-style: none;
+ border-radius: 1rem;
+`;
+const Rank = styled.strong`
+ font-size: 1.5rem;
+ margin: 0rem 4rem 1rem 0rem;
+`;
+const CandiName = styled.p`
+ font-size: 1.5rem;
+ display: block;
+ margin: 0rem auto 1rem 0rem;
+`;
+const VoteArea = styled.div`
+ width: 100%;
+ padding: 5rem 10rem;
+ border: 1px solid black;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+`;
+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;
`;