-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[7주차] 댄서포트(Dan-support) 미션 제출합니다. #5
base: master
Are you sure you want to change the base?
Changes from all commits
78290a7
1ee0155
654ce0a
8ddefa3
e50e979
e506fb4
08e95e6
11eae95
c06cc39
0f37172
e70555a
5360568
31c6479
33484f3
4e05d5b
60e1bc9
9092e5e
95694a7
396b36f
03f7998
2d8bf54
aab5273
2e70166
4a5a887
e3eefa0
75484dc
8e93d79
cdd5046
3336f4b
5070cba
f51e1ba
6e382b9
79d5aee
1082ef3
d9c50d1
195981b
2f0177e
ee7b5c8
ece0b1d
12c002b
8af5e29
3849b9c
ac80e66
bb34645
0e26c65
12d81a9
aa5cfe2
0fbe54f
923ccf2
600bb1b
8dec885
a798a22
d36a325
14f749e
90b6341
a5a4f55
cb0579e
44b78d9
5e7c8f1
d42aba8
bc33a33
e77a64f
4f9da3f
145c96a
c0ee4ea
fd6dcc5
ee3868e
52f92c2
f0b4242
c802036
24a6a57
e7e838d
7c81619
73c4d0f
5a59aea
65152e8
8285257
db9996f
a283877
a89af29
c51cbc6
9ebcf4b
1b2a7fa
884f5ee
24dcc92
f02b69c
a77b996
9764cbd
e888339
c437da0
deda3bc
78888e2
081b32b
1daca47
951f5f7
3be8cc0
a289f3d
6ebb2bd
e86d29a
aa457d4
0883292
46a900e
6713e17
497c186
2275acb
85b31de
0be3f74
9d40e0d
4f92497
e428429
7d3ac75
ddf2ab8
fcaeba6
e2f0196
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"extends": "next/core-web-vitals" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.js | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
.env | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
|
||
# local env files | ||
.env*.local | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"printWidth": 80, | ||
"semi": true, | ||
"singleQuote": true, | ||
"trailingComma": "all", | ||
"tabWidth": 2, | ||
"bracketSpacing": true, | ||
"endOfLine": "auto", | ||
"useTabs": false, | ||
"arrowParens": "avoid" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,45 +1,58 @@ | ||
# **마지막 미션: React-Vote! 🗳** | ||
|
||
## **서론** | ||
|
||
안녕하세요! 프론트 파트장 오지은입니다🙌 어느덧 마지막 스터디네요. 그동안 과제하시면서 힘들고 어려우셨겠지만, 성장했다는 보람이 더 컸으면하는 바람입니다. | ||
|
||
이번 스터디는 각 팀의 백엔드와 함께 진행하는 **합동 과제**입니다. 모던 웹에서 REST API가 주류로 떠오름에 따라 프론트엔드와 백엔드의 구분이 이전보다 명확해졌습니다. 주로 백엔드는 API 서버의 역할을, 프론트엔드는 이를 이용해 사용자에게 UI를 제공하는 역할로 웹이 분화되었습니다. 그 말은 곧, API 없이는 사용자에게 의미있는 서비스를 제공하기 힘들어진다는 것이겠죠. 여러분께서도 차후 팀 프로젝트를 진행하시면서 백엔드 개발자들과 API에 대해 소통할 일이 많아질 것입니다. | ||
|
||
따라서 이번 과제는 백엔드 개발자들이 전달해준 `API`를 사용해서 구현해보는 미션입니다. 투표 서비스를 개발해 보는 것인데요. 백엔드 개발자와 함께 클라이언트 사이드에서 API를 조금 더 효율적으로 사용할 수 있는 방법에 대해 고민해 보고, 논의해 보는 시간을 가져 보시기 바랍니다. | ||
|
||
이번 미션도 화이팅입니다🔥 | ||
|
||
## **미션** | ||
|
||
### **미션 목표** | ||
|
||
- REST API를 통한 서버와의 통신 방법을 이해합니다. | ||
- async/await, Promise등 JavaScript의 비동기 처리를 이해합니다. | ||
- API document를 통해 백엔드 개발자와 소통하는 방법을 익힙니다. | ||
- 팀 내의 프론트엔드 개발자와 적절한 역할 분담을 통해 개발 효율을 높이는 방법에 대해 고민합니다. | ||
|
||
|
||
### **기한** | ||
|
||
2023년 6월 28일 | ||
|
||
### **필수 요건** | ||
|
||
- UI/UX에 대한 감각을 최대한 발휘해 디자인을 적용해 봅니다. | ||
- `HTTPS`를 통해 서버와 통신합니다. | ||
- 외의 사항은 [가이드 문서](https://delirious-sociology-a85.notion.site/FE-BE-416499e4b09e4f44b64a3951b3817f94)를 참고하세요. | ||
|
||
### **선택 사항** | ||
|
||
- API Fetch는 어떤 방식을 사용하든 무방합니다 (axios, Fetch API) | ||
- `Promise.then()` 보단 `async/await`를 사용해 보세요. 더 최신 스펙이랍니다. | ||
|
||
## **링크 및 참고자료** | ||
|
||
- [리액트 API 연동의 기본](https://react.vlpt.us/integrate-api/01-basic.html) | ||
- [자바스크립트 - 동기(Synchronous)? 비동기(asynchronous)?](https://ljtaek2.tistory.com/142) | ||
- [async와 await, 비동기를 동기코드 처럼](https://kamang-it.tistory.com/entry/JavaScript11async%EC%99%80-await-%EB%B9%84%EB%8F%99%EA%B8%B0%EB%A5%BC-%EB%8F%99%EA%B8%B0%EC%BD%94%EB%93%9C-%EC%B2%98%EB%9F%BC) | ||
- [REST API 제대로 알고 사용하기](https://meetup.toast.com/posts/92) | ||
- [axios란? (feat. Fetch API)](https://velog.io/@shin6403/React-axios%EB%9E%80-feat.-Fetch-API) | ||
- [Postman, 어렵지 않게 사용하기](https://gngsn.tistory.com/26) | ||
## CEOS 파트장/데모데이 투표 서비스 🗳️ | ||
각 파트장 선정과 데모데이 우수팀 선정에 대한 투표 진행 서비스입니다. | ||
|
||
<a href="https://react-vote-17th-ashen.vercel.app" target="_blank">🌐 배포 사이트</a> | ||
|
||
<br /> | ||
|
||
### 🛠️ 기술 스택 | ||
<img src="https://img.shields.io/badge/TypeScript-3178C6?style=flat-square&logo=TypeScript&logoColor=white" align="center"/></a> <img src="https://img.shields.io/badge/Next.js-000000?style=flat-square&logo=Next.js&logoColor=white" align="center"/> <img src="https://img.shields.io/badge/Recoil-3578E5?style=flat-square&logo=recoil&logoColor=white" align="center"/> <img src="https://img.shields.io/badge/React Query-FF4154?style=flat-square&logo=reactquery&logoColor=white" align="center"> <img src="https://img.shields.io/badge/Axios-5A29E4?style=flat-square&logo=Axios&logoColor=white" align="center"> <img src="https://img.shields.io/badge/CSS Modules-000000?style=flat-square&logo=cssmodules&logoColor=white" align="center"> | ||
|
||
<br /> | ||
|
||
### 🚀 주요 기능 | ||
#### 1. 회원 가입 | ||
<img width="1110" alt="image" src="https://github.com/Dan-support-CEOS/react-vote-17th/assets/88028826/6108e057-c44d-4040-9e0a-5564d98ced8d"> <br> | ||
- 회원가입 과정에서 이름, 아이디, 비밀번호, 이메일에 대한 유효성 검사를 진행합니다. | ||
|
||
#### 2. 로그인 | ||
<img width="831" alt="image" src="https://github.com/Dan-support-CEOS/react-vote-17th/assets/88028826/d296f0fc-c7f5-4a5b-ae4d-02a0025beb7e"> <br> | ||
- 비밀번호가 잘못되었거나 존재하지 않는 사용자인 경우 에러 메세지를 보여줍니다. | ||
|
||
#### 3. 메인 페이지 | ||
<img width="887" alt="image" src="https://github.com/Dan-support-CEOS/react-vote-17th/assets/88028826/7af994a6-7e32-43b2-8ac7-13a2c250bbd5"> <br> | ||
- 투표에 참여하기 위해서는 회원가입 및 로그인이 필요합니다. 로그인하지 않은 사용자는 투표 페이지에 접근 불가능합니다. | ||
- 투표는 한번만 가능합니다. 재투표는 불가능합니다. | ||
|
||
#### 4. 파트장 투표 및 결과 페이지 | ||
<img width="721" alt="image" src="https://github.com/Dan-support-CEOS/react-vote-17th/assets/88028826/0469a360-e42a-4cd8-bb17-7a9d1728eb51"> <br> | ||
- 본인의 파트에 해당하는 파트장 투표만 참여 가능합니다. | ||
<img width="682" alt="image" src="https://github.com/Dan-support-CEOS/react-vote-17th/assets/88028826/7894d793-8843-4328-a9c9-d42d962de5cd"> | ||
<img width="860" alt="image" src="https://github.com/Dan-support-CEOS/react-vote-17th/assets/88028826/97c1db90-abfb-42df-8190-2cd99bdd74b0"> <br> | ||
- 득표 순으로 내림차순 정렬되어 보여집니다. | ||
|
||
#### 5. 데모데이 투표 및 결과 페이지 | ||
<img width="856" alt="image" src="https://github.com/Dan-support-CEOS/react-vote-17th/assets/88028826/83d97903-84f2-4b2d-8f0b-e3375650baed"> <br> | ||
- 본인이 속한 팀을 제외한 팀에 대한 투표만 가능합니다. | ||
<img width="914" alt="image" src="https://github.com/Dan-support-CEOS/react-vote-17th/assets/88028826/76cd5a28-a9f8-48e1-9608-135e28eb14ba"> <br> | ||
- 득표 순으로 내림차순 정렬되어 보여집니다. | ||
|
||
|
||
|
||
<br /> | ||
|
||
### 🧑💻 팀원 소개 | ||
<table> | ||
<tr> | ||
<td align="center"><img src="https://github.com/Dan-sup/Dansup-Frontend/assets/88028826/9c1f109c-4995-4c19-b184-de388718bd99" width="160"></td> | ||
<td align="center"><img src="https://github.com/Dan-sup/Dansup-Frontend/assets/88028826/f327b639-ca1a-45ee-8089-5f3e315d4e03" width="160"></td> | ||
</tr> | ||
<tr> | ||
<td align="center">신유진</td> | ||
<td align="center">노수진</td> | ||
</tr> | ||
<tr> | ||
<td align="center"><a href="https://github.com/paya17" target="_blank">paya17</a></td> | ||
<td align="center"><a href="https://github.com/sujinRo" target="_blank" width="160">sujinRo</a></td> | ||
</tr> | ||
</table> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
/** @type {import('next').NextConfig} */ | ||
const nextConfig = { | ||
reactStrictMode: true, | ||
webpack: config => { | ||
config.module.rules.push({ | ||
test: /\.svg$/i, | ||
issuer: /\.[jt]sx?$/, | ||
use: ['@svgr/webpack'], | ||
}); | ||
return config; | ||
}, | ||
}; | ||
module.exports = nextConfig; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"name": "react-vote-17th", | ||
"version": "0.1.0", | ||
"private": true, | ||
"proxy": "https://takgyun.shop", | ||
"scripts": { | ||
"dev": "next dev", | ||
"build": "next build", | ||
"start": "next start", | ||
"lint": "next lint" | ||
}, | ||
"dependencies": { | ||
"@svgr/webpack": "^8.0.1", | ||
"@tanstack/react-query": "^4.29.7", | ||
"@types/node": "20.2.5", | ||
"@types/react": "18.2.7", | ||
"@types/react-dom": "18.2.4", | ||
"axios": "^1.4.0", | ||
"eslint": "8.41.0", | ||
"eslint-config-next": "13.4.4", | ||
"http-proxy-middleware": "^2.0.6", | ||
"next": "13.4.4", | ||
"react": "18.2.0", | ||
"react-dom": "18.2.0", | ||
"recoil": "^0.7.7", | ||
"typescript": "5.0.4" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import client from './client'; | ||
|
||
export const register = async (input: any) => { | ||
const response = await client.post('/auth/signup/', { | ||
name: input.name, | ||
login_id: input.id, | ||
password: input.password, | ||
email: input.email, | ||
part: input.part, | ||
team: input.team, | ||
}); | ||
return response.data; | ||
}; | ||
|
||
export const login = async (input: any) => { | ||
const response = await client.post('/auth/signin/', { | ||
login_id: input.id, | ||
password: input.password, | ||
}); | ||
return response.data; | ||
}; | ||
|
||
//id,email 중복 확인 | ||
export const checkId = async (id: string) => { | ||
const response = await client.post('/auth/id/check/', { | ||
login_id: id, | ||
}); | ||
return response.data; | ||
}; | ||
|
||
export const checkEmail = async (email: string) => { | ||
const response = await client.post('/auth/email/check/', { | ||
email: email, | ||
}); | ||
return response.data; | ||
}; | ||
|
||
export const logout = async (accessToken: string) => { | ||
const response = await client.get('/auth/signout/', { | ||
headers: { | ||
Authorization: `Bearer ${accessToken}`, | ||
}, | ||
}); | ||
return response.data; | ||
}; | ||
|
||
export const tokenRefresh = async () => { | ||
const response = await client.get('/auth/token/refresh/'); | ||
return response.data; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import axios from 'axios'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 만들어주신 axios 모듈에 토큰을 싣는 코드를 작성해주시면,
|
||
|
||
const client = axios.create({ | ||
baseURL: 'https://takgyun.shop', | ||
withCredentials: true, | ||
}); | ||
|
||
export default client; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import client from './client'; | ||
|
||
//파트장 투표 | ||
export const votePartLeader = async (info: any) => { | ||
const response = await client.post( | ||
'/votes/candidates/', | ||
{ | ||
cname: info.name, | ||
part: info.part, | ||
}, | ||
{ | ||
headers: { | ||
Authorization: `Bearer ${info.accessToken}`, | ||
}, | ||
}, | ||
); | ||
return response.data; | ||
}; | ||
|
||
//파트장 투표 중복 제한(권한 확인) | ||
export const checkPartLeaderVoteAuthority = async (accessToken: string) => { | ||
const response = await client.get('/votes/candidates/authority/', { | ||
headers: { | ||
Authorization: `Bearer ${accessToken}`, | ||
}, | ||
}); | ||
return response.data; | ||
}; | ||
Comment on lines
+20
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 파트장 투표 중복을 제한하는 기능은 |
||
|
||
//데모데이 투표 | ||
export const demoDayVote = async (info: any) => { | ||
const response = await client.post( | ||
'/votes/teams/', | ||
{ | ||
tname: info.tname, | ||
}, | ||
{ | ||
headers: { | ||
Authorization: `Bearer ${info.accessToken}`, | ||
}, | ||
}, | ||
); | ||
return response.data; | ||
}; | ||
|
||
//데모데이 투표 중복 제한(권한 확인) | ||
export const demoDayAuthority = async (info: any) => { | ||
const response = await client.get('/votes/teams/authority/', { | ||
headers: { | ||
Authorization: `Bearer ${info.accessToken}`, | ||
}, | ||
}); | ||
return response.data; | ||
}; | ||
Comment on lines
+1
to
+54
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오옴.. 각 API 요청을 깔끔하게 잘 분리해서 서비스화해주신 것 같아요 👍 유저 정보를 본 파일에서 공통으로 불러온다면, 매번 번거롭게 매 api 요청마다 유저 정보를 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import client from './client'; | ||
|
||
//파트장 투표 결과 | ||
export const getPartLeaderResult = async (part: string) => { | ||
const response = await client.get(`/votes/candidates/${part}/`); | ||
return response.data; | ||
}; | ||
|
||
//데모데이 투표 결과 | ||
export const getDemoDayResult = async () => { | ||
const response = await client.get('/votes/teams/result/'); | ||
return response.data; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
api 주소는 배포시에는 가려주시는게 좋을 것 같아요~!