Skip to content
This repository has been archived by the owner on Sep 19, 2021. It is now read-only.

[3주차] 고은 미션 제출합니다. #4

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ yarn-error.log*
.env.development.local
.env.test.local
.env.production.local
.env*
.env*
.now
13 changes: 3 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -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사용도 많이 미숙한것같습니다ㅠㅠ!
12 changes: 12 additions & 0 deletions now.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
Comment on lines +1 to +12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿입니다 👍

31 changes: 31 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"start": "node server"
},
"dependencies": {
"axios": "^0.19.2",
"compression": "^1.7.4",
"dotenv": "^8.2.0",
"express": "^4.17.1",
Expand Down
28 changes: 15 additions & 13 deletions pages/index.js
Original file line number Diff line number Diff line change
@@ -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 (
<Wrapper>
리액트 투-표
<LoginForm />
</Wrapper>
);
return (
<Wrapper>
<Title>리액트 투-표</Title>
<LoginForm />
</Wrapper>
);
}

const Title = styled.h1`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

semantic tag 좋습니다 ㅎㅎ

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;
`;
111 changes: 103 additions & 8 deletions src/components/login-form.js
Original file line number Diff line number Diff line change
@@ -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 <Wrapper>안녕 나는 로그인 폼!</Wrapper>;
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 (
<div>
{!isloggedIn && (
<Wrapper>
<Title>로그인</Title>
<Row>
<Label>EMAIL</Label>
<Input type="text" name="email" onChange={handleFormChange}></Input>
</Row>
<Row>
<Label>PASSWORD</Label>
<Input
type="password"
onChange={handleFormChange}
name="password"
></Input>
</Row>
<Button onClick={() => handleSubmit()}>로그인</Button>
</Wrapper>
)}

{isloggedIn && <VoteForm />}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VoteForm이 LoginForm 내부에 있네요 😅
분리해주세요!

</div>
);
}
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;
`;
119 changes: 110 additions & 9 deletions src/components/vote-form.js
Original file line number Diff line number Diff line change
@@ -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 <Wrapper>안녕 나는 투표 폼!</Wrapper>;
import styled from 'styled-components';

function VoteForm() {
const [candidates, setCandidates] = useState([]);
const [voteCount, setVoteCount] = useState();
Copy link
Member

@greatSumini greatSumini Apr 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 state가 사용되지 않고 있어요!, vote시 paramter로 넘겨줄 필요가 없기 때문에 지워주시면 될 것 같아요!

Suggested change
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.put(newUrl, voteCount)
.put(newUrl)

request body schema가 명시되지 않은 경우, 안 넘겨주셔도 됩니다!

.then(({ data }) => {
setVoteCount(data);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
setVoteCount(data);

삭제해주시면 됩니다 ㅎㅎ

alert(candidate.name + '님에게 투표 완료!');
getCandidates();
})
.catch(function (error) {
console.log(error);
alert('투표 실패!');
});
};

return (
<Wrapper>
<Title>
<RedTitle>프론트엔드 인기쟁이</RedTitle>는 누구?
</Title>
<SubTitle>CEOS 프론트엔드 개발자 인기 순위 및 투표 창입니다.</SubTitle>
<VoteArea>
{candidates
.sort((person1, person2) => person2.voteCount - person1.voteCount)
.map((person, index) => (
<Row key={person._id}>
<Rank>{index + 1}위:</Rank>
<CandiName>
{person.name}
<br />[{person.voteCount}표]
</CandiName>
<Button onClick={() => voteCandidates(person)}>투표</Button>
</Row>
))}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

candidate 한명 한명에 대한 component를 따로 분리해서 map 해보는건 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

엇 이게 map안에서 적용되고 있는거 아닌가요..??

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 넵 다른 파일로 분리해보시면 어떨까해서 드린 말씀이었어요!
CandidateCard
같은 이름으로요 😄

</VoteArea>
</Wrapper>
);
}
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`
Comment on lines +64 to +100
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

용도 별로 다른 태그 사용하신거 너무 잘하셨어요~~ 💯

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;
`;