Skip to content
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주차] Team CakeWay 김류원 & 지민재 미션 제출합니다. #5

Open
wants to merge 69 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
5dbeae1
Initialize Next.js project
mimizae Dec 27, 2024
e23636c
feat : 파트장, 데모데이 투표 및 투표결과 페이지 ui
ryu-won Dec 28, 2024
f65de22
feat : 돌아가기 기능구현
ryu-won Dec 28, 2024
1503805
feat : 투표결과 기능구현
ryu-won Dec 28, 2024
ff1c360
Feat: Login 페이지 1차 퍼블리싱
mimizae Dec 28, 2024
3a6aede
dev merger
mimizae Dec 28, 2024
033984b
Feat: 회원가입, 로그인, 헤더 퍼블리싱
mimizae Dec 28, 2024
03aa06a
Merge pull request #1 from cake-way/mimizae
mimizae Dec 28, 2024
d1c474c
Feat: 모든 페이지에 반응형 적용
mimizae Dec 29, 2024
f403f21
Merge pull request #2 from cake-way/mimizae
mimizae Dec 29, 2024
cf9b887
design : 반응형 수정
ryu-won Dec 30, 2024
b7710d0
feat : lib/api.tsx구현
ryu-won Dec 30, 2024
dfb431a
feat : api/route.tsx 코드 작성중
ryu-won Dec 30, 2024
4ecfc6a
feat :투표 기능
ryu-won Dec 30, 2024
1402429
유효성 검사를 함수화해서 lib 폴더로 이동, signup 페이지의 요소들을 컴포넌트화, api 요청 함수 생성
mimizae Dec 31, 2024
3a19928
Merge pull request #3 from cake-way/mimizae
mimizae Dec 31, 2024
b941675
Merge branch 'ryuwon'
ryu-won Dec 31, 2024
9e88cdb
feat : 머지 후 lib/api 투표관련 함수작성
ryu-won Dec 31, 2024
3228afe
fix : api 연결 오류 해결
ryu-won Dec 31, 2024
ce9cda2
Chore: 미디어 쿼리 수정
mimizae Jan 1, 2025
1821a21
Merge branch 'master' of https://github.com/cake-way/next-vote-20th i…
mimizae Jan 1, 2025
9c6b3a2
Feat: login, signup api 연동 1차
mimizae Jan 1, 2025
2ccb806
Fix: hydration mismatch 해결하기
mimizae Jan 2, 2025
94b1e9e
Fix: api 403 에러 해결 중...
mimizae Jan 2, 2025
54d2cce
Fix: login 403 에러 해결 중
mimizae Jan 2, 2025
110ded1
Feat: 로그인, 회원가입 api 연동
mimizae Jan 2, 2025
e157720
Merge pull request #4 from cake-way/mimizae
mimizae Jan 2, 2025
9f470b2
Fix: 로컬스토리지에 토큰 저장
mimizae Jan 2, 2025
a7d1e67
Fix: 로컬에 토큰 저장 안 되는 에러 해결
mimizae Jan 2, 2025
97b024a
Merge branch 'master' of https://github.com/cake-way/next-vote-20th i…
mimizae Jan 2, 2025
a2ea752
Merge pull request #5 from cake-way/mimizae
mimizae Jan 2, 2025
ef35e2f
Merge branch 'master' of https://github.com/cake-way/next-vote-20th i…
mimizae Jan 3, 2025
acf7a7d
Feat: 파비콘 설정, 로그인 시 아이디 및 비밀번호 입력 안 된 경우 처리
mimizae Jan 3, 2025
12603f3
feat : api/results/ api 연결중
ryu-won Jan 3, 2025
5f5a5c8
feat : 투표결과 조회, 로그인 전 투표, 조회 불가
ryu-won Jan 3, 2025
dd7d080
feat : 후보자 목록 api 연결
ryu-won Jan 4, 2025
56bd86b
feat: 후보자 조회api 연결
ryu-won Jan 4, 2025
fe4a1fb
Fix: 새로고침 시 로그인 상태 초기화 되는 버그 해결
mimizae Jan 4, 2025
259f4da
feat : 투표하기 api 연결
ryu-won Jan 4, 2025
e0eaa8c
fix : 득표수 증가 오류 수정중....
ryu-won Jan 4, 2025
a0413a8
design: 후보자 목록 패딩값 조절
ryu-won Jan 4, 2025
442c237
fix: FE파트장 투표 오류 수정
ryu-won Jan 4, 2025
0133854
fix : 백엔드 투표, 팀투표 오류 수정
ryu-won Jan 4, 2025
97792f0
Refact: 상태 통합 및 props 객체를 이용해 스프레드 연산자 사용하는 방식으로 리팩토링
mimizae Jan 4, 2025
e60cbfe
fix : team 투표 오류 수정
ryu-won Jan 4, 2025
e51c687
fix : 투표하기 삼항연산자 템플릿리터럴 삭제
ryu-won Jan 4, 2025
9f26c1b
fix: 빌드 오류 수정
ryu-won Jan 4, 2025
cdb6c24
fix : build 오류 수정
ryu-won Jan 4, 2025
4fa9c5d
Merge: master 병합 충돌 해결
mimizae Jan 4, 2025
30a2168
fix : 빌드오류 수정
ryu-won Jan 4, 2025
b0b5766
Merge: master와 머지
mimizae Jan 4, 2025
6f812f7
fix : 빌드오류 수정
ryu-won Jan 4, 2025
70bafbd
Feat: Loading 컴포넌트 구현
mimizae Jan 4, 2025
9fcf404
master와 merge
mimizae Jan 4, 2025
106487b
fix : 13버전 변경 및 빌드 오류 수정
ryu-won Jan 4, 2025
e17f3b1
Fix: next 버전 수정
mimizae Jan 4, 2025
6777770
Merge pull request #6 from cake-way/mimizae
mimizae Jan 4, 2025
e5076ba
Merge remote-tracking branch 'origin' into ryuwon
ryu-won Jan 4, 2025
585449e
merge
ryu-won Jan 4, 2025
f21b34a
Feat: 에러 핸들 유틸 함수 생성
mimizae Jan 4, 2025
e439715
mimizae
mimizae Jan 4, 2025
2a1e60a
feat : 투표 한번만 가능하게
ryu-won Jan 4, 2025
f43dba0
feat : 로그아웃시 메인으로 이동
ryu-won Jan 4, 2025
64ae00a
Merge branch 'master' of https://github.com/cake-way/next-vote-20th i…
mimizae Jan 4, 2025
dbd7641
Merge pull request #7 from cake-way/mimizae
mimizae Jan 4, 2025
f79020e
Chore: 로컬 스토리지 clear가 아닌 token만 remove
mimizae Jan 4, 2025
4bbe887
Merge pull request #8 from cake-way/mimizae
mimizae Jan 4, 2025
23e1967
feat : 로컬스토리지 로그인 정보 접근 오류 수정
ryu-won Jan 6, 2025
44df2e0
fix: 팝업오류 수정
ryu-won Jan 6, 2025
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
Prev Previous commit
Next Next commit
feat: 후보자 조회api 연결
ryu-won committed Jan 4, 2025
commit 56bd86b236b8e1a2ba5022cf88b07efd33161320
25 changes: 14 additions & 11 deletions src/app/api/auth/signup/route.ts
Original file line number Diff line number Diff line change
@@ -3,7 +3,6 @@ import { NextResponse } from "next/server";
const BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL;

export async function POST(req: Request) {

try {
// 요청 데이터 확인
const body = await req.json();
@@ -16,28 +15,32 @@ export async function POST(req: Request) {
},
body: JSON.stringify(body),
});

if (!response.ok) {
const errorText = await response.text();
console.error("백엔드 오류 텍스트:", errorText);
return NextResponse.json({ success: false, error: errorText }, { status: response.status });
return NextResponse.json(
{ success: false, error: errorText },
{ status: response.status }
);
}
const contentType = response.headers.get('Content-Type');

const contentType = response.headers.get("Content-Type");
let responseBody;

if (contentType && contentType.includes('application/json')) {
if (contentType && contentType.includes("application/json")) {
responseBody = await response.json();
}
else {
} else {
responseBody = await response.text(); // JSON이 아닌 경우 처리
}

console.log("백엔드 응답:", responseBody);
return NextResponse.json({ success: true, data: responseBody });
}
catch (error) {
} catch (error) {
console.error("에러 발생:", error);
return NextResponse.json({ success: false, error: "서버 요청 실패" }, { status: 500 });
return NextResponse.json(
{ success: false, error: "서버 요청 실패" },
{ status: 500 }
);
}
}
39 changes: 39 additions & 0 deletions src/app/api/leader/[part]/route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { BACKEND_URL } from "@/app/constants/common";
import { NextResponse } from "next/server";

export async function GET(
req: Request,
{ params }: { params: { part: string } }
) {
const { part } = await params;

const { headers } = req;
const token = headers.get("Authorization");

try {
if (!token) {
console.error("Authorization header is missing");
return NextResponse.json(
{ error: "Unauthorized: No token provided" },
{ status: 401 }
);
}
const url = `${BACKEND_URL}/${part === "team" ? "" : "leader/"}${part}`;

Choose a reason for hiding this comment

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

이렇게 동적라우트쓰니까 간편한것같아요~

console.log(url);
const response = await fetch(url, {
headers: { Authorization: token },
});
// 백엔드 응답을 JSON으로 파싱!
const data = await response.json();

console.log(response);
return NextResponse.json({ success: true, data: data });
} catch (error) {
console.log(error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}
//try catch문으로 변경
1 change: 1 addition & 0 deletions src/app/api/results/[part]/route.tsx
Copy link

Choose a reason for hiding this comment

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

이 부분 파일들만 route.tsx로 해주신 이유가 있는지 궁금합니다!

Original file line number Diff line number Diff line change
@@ -48,6 +48,7 @@ export async function GET(
const data = await results.json();
return NextResponse.json({ success: true, data: data });
} catch (error) {
console.log(error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
21 changes: 17 additions & 4 deletions src/app/lib/api.ts
Original file line number Diff line number Diff line change
@@ -66,6 +66,7 @@ export const apiRequest = async (
break;
case "leader":
baseUrl = "/api/leader";
break;
default:
throw new Error("Unknown domain");
}
@@ -89,9 +90,9 @@ export const fetchVoteResults = async (endpoint: string) => {
const results = await apiRequest("results", "GET", null, endpoint);
console.log("투표 결과", results);

if (!results.ok) {
throw new Error(`${results.errorCode} 결과 조회 중 오류가 발생했습니다`);
}
// if (!results.ok) {
// throw new Error(`${results.errorCode} 결과 조회 중 오류가 발생했습니다`);
// }이거 왜안돼?
return results;
} catch (error) {
console.error("투표 결과 가져오기 실패", error);
@@ -118,5 +119,17 @@ export const fetchPostVote = async ({

//후보자 조회
export const fetchGetLeader = async (endpoint: string) => {
const response = await apiRequest("");
try {
const response = await apiRequest("leader", "GET", null, endpoint);

// if (!response.ok) {
// throw new Error(
// `${response.errorCode} 후보자 조회 중 오류가 발생했습니다`
// );
// }
console.log("후보자조회 결과", response);
return response;
} catch (error) {
console.error("후보자조회실패", error);
}
};
106 changes: 62 additions & 44 deletions src/app/vote/[votepart]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,40 @@
"use client";
import { useParams, useRouter } from "next/navigation";
import { styled } from "styled-components";
import { VOTE_CONTENT } from "@/app/constants/common";
import { useStore } from "@/stores/useVote";
import { useState } from "react";
import { fetchPostVote } from "@/app/lib/api";
import { gettoken } from "@/utils/utils";
import Modal from "@/components/Modal";
import { fetchGetLeader, fetchPostVote } from "@/app/lib/api";
import { getPartUrlName } from "@/utils/utils";
import { useQuery } from "@tanstack/react-query";

interface ILeader {
id: number;
name: string;
}

type VoteQueryKey = ["leader", string];

export default function Page() {
const params = useParams<{ votepart: "FE" | "BE" | "TEAM" }>();
const router = useRouter();
const [clicked, setClicked] = useState("");
const [isModalOpen, setIsModalOpen] = useState(false);
const [modalMessage, setModalMessage] = useState("");
const { setUserId, setVoteId, setLeaderId, user_id, leader_id } = useStore();

const token = gettoken();
const { setUserId, setVoteId, setLeaderId, user_id, leader_id } = useStore();
const { data, isLoading } = useQuery<
ILeader[],
Error,
ILeader[],
VoteQueryKey
>({
queryKey: ["leader", params.votepart],
queryFn: async () => {
const response = await fetchGetLeader(getPartUrlName(params.votepart));
return response.data;
},
});
console.log(data);

const onResultClick = (a: string) => {
if (!token) {
setIsModalOpen(true);
setModalMessage("로그인 후 결과조회가 가능해요!");
return;
}
router.push(`result/${a}`);
};
const backClicked = () => {
@@ -36,12 +47,6 @@ export default function Page() {
const onVoteCliced = async () => {
console.log("user_id:" + user_id, "leader_id:" + leader_id);
try {
if (!token) {
console.log(!token);
setIsModalOpen(true);
setModalMessage("로그인 후 투표가 가능해요!");
return;
}
setUserId("지민재"); // 현재 유저로 바꾸기
setLeaderId(clicked);
const newVoteId = new Date().toLocaleDateString();
@@ -61,12 +66,10 @@ export default function Page() {
}
};

const handleCloseModal = () => {
setIsModalOpen(false);
router.push("/login");
};
//결과화면이랑 중복되는건 컴포넌트로 만들기

if (isLoading) {
return;
}
return (
<>
<Container>
@@ -77,27 +80,29 @@ export default function Page() {
{params.votepart === "TEAM" ? "" : "파트장"} 투표
</span>
</Header>
<TextContainer $votepart={params.votepart}>
{VOTE_CONTENT[params.votepart].map((prop) => (
<Text
onClick={() => onLeaderClicked(prop.name)}
key={prop.name}
$isActive={clicked === prop.name} //$를 사용해야 p dom요소에 전달이 안됨
>
{prop.name}
</Text>
))}
<Result onClick={onVoteCliced}>투표하기</Result>
<Result onClick={() => onResultClick(params.votepart)}>
결과보기
</Result>
</TextContainer>
{isLoading ? (
<LoadingContainer>
<LoadingText>로딩중...</LoadingText>
</LoadingContainer>
) : (
<TextContainer $votepart={params.votepart}>
{/* {VOTE_CONTENT[params.votepart] */}
{data?.map((prop: { id: number; name: string }) => (
<Text
onClick={() => onLeaderClicked(prop.name)}
key={prop.id}
$isActive={clicked === prop.name} //$를 사용해야 p dom요소에 전달이 안됨
>
{prop.name}
</Text>
))}
<Result onClick={onVoteCliced}>투표하기</Result>
<Result onClick={() => onResultClick(params.votepart)}>
결과보기
</Result>
</TextContainer>
)}
</Container>
<Modal
isOpen={isModalOpen}
message={modalMessage}
onClose={handleCloseModal}
/>
</>
);
}
@@ -178,3 +183,16 @@ const Result = styled.button`
font-size: 0.8rem;
}
`;

//로딩
const LoadingContainer = styled.div`
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
`;

const LoadingText = styled.h1`
color: #ff6c81;
font-size: 2rem;
`;
2 changes: 2 additions & 0 deletions src/utils/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";

export const getPartUrlName = (part: string) => {
switch (part) {
case "FE":