Skip to content

Commit

Permalink
Merge pull request #248 from TripInfoWeb/dev_support
Browse files Browse the repository at this point in the history
Dev support
  • Loading branch information
ssssksss authored Sep 2, 2024
2 parents 02750e8 + a39c1f8 commit 5925c1c
Show file tree
Hide file tree
Showing 21 changed files with 933 additions and 589 deletions.
26 changes: 26 additions & 0 deletions src/app/api/support/notice/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { NextRequest } from "next/server";

/**
* 공지사항 목록 조회
*/
export async function GET(request: NextRequest) {
const url = new URL(request.url);
const page = url.searchParams.get("page") || "1";

// 페이지 번호를 0 기반으로 조정합니다.
const zeroBasedPage = Number(page) - 1;

const apiUrl = `${process.env.BACKEND_URL}/api/notice${zeroBasedPage > 0 ? `?page=${zeroBasedPage}` : ""}`;

// 백엔드 API 호출
const response = await fetch(apiUrl, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
cache: "no-cache",
});

return response;
}

102 changes: 102 additions & 0 deletions src/app/api/support/qna/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { NextRequest, NextResponse } from "next/server";

/**
* qna 등록
*/
export async function POST(request: NextRequest) {
const access_cookie = request.cookies.get("access_token");
if (!access_cookie) {
const refresh_cookie = request.cookies.get("refresh_token");
if (!refresh_cookie) {
// 리프레시 토큰이 없으므로 요청 중단
return new NextResponse("Refresh token not found", { status: 403 });
}
// 리프레시 토큰으로 재발급 받아 재요청 보내기 위한 응답
return new NextResponse("Refresh token not found", { status: 401 });
}
const bodyData = await request.json();

const response = await fetch(`${process.env.BACKEND_URL}/api/qna`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Cookie: `${access_cookie?.name}=${access_cookie?.value}`,
},
body: JSON.stringify(bodyData),
cache: "no-store",
});

return response;
}

/**
* qna 리스트 페이지네이션
*/
export async function GET(request: NextRequest) {
// 요청에서 access_token을 가져옵니다.
const access_cookie = request.cookies.get("access_token");

if (!access_cookie) {
// access_token이 없으면 refresh_token이 있는지 확인합니다.
const refresh_cookie = request.cookies.get("refresh_token");
if (!refresh_cookie) {
// refresh_token이 없는 경우 요청을 중단하고 403 응답을 보냅니다.
return new NextResponse("Refresh token not found", { status: 403 });
}
// refresh_token만으로는 유효하지 않으므로 401 응답을 보냅니다.
return new NextResponse("Access token not found", { status: 401 });
}

// 요청 URL에서 쿼리 파라미터를 가져옵니다.
const url = new URL(request.url);
const page = url.searchParams.get("page") || "1"; // 페이지가 없으면 기본값으로 1을 사용합니다.

// 페이지 번호를 0 기반으로 조정합니다.
const zeroBasedPage = Number(page) - 1;

// URL을 페이지 번호에 맞게 수정합니다. 페이지 번호가 0보다 큰 경우에만 쿼리 파라미터를 추가합니다.
const apiUrl = `${process.env.BACKEND_URL}/api/qna${zeroBasedPage > 0 ? `?page=${zeroBasedPage}` : ""}`;

// 백엔드 API 호출
const response = await fetch(apiUrl, {
method: "GET",
headers: {
"Content-Type": "application/json",
Cookie: `${access_cookie?.name}=${access_cookie?.value}`,
},
cache: "no-store",
});

return response;
}

/**
* qna 삭제
*/
export async function DELETE(request: NextRequest) {
const access_cookie = request.cookies.get("access_token");
if (!access_cookie) {
const refresh_cookie = request.cookies.get("refresh_token");
if (!refresh_cookie) {
// 리프레시 토큰이 없으므로 요청 중단
return new NextResponse("Refresh token not found", { status: 403 });
}
// 리프레시 토큰으로 재발급 받아 재요청 보내기 위한 응답
return new NextResponse("Refresh token not found", { status: 401 });
}
const url = new URL(request.url);

const response = await fetch(
`${process.env.BACKEND_URL}/api/qna/${url.searchParams.get("id")}`,
{
method: "DELETE",
headers: {
"Content-Type": "application/json",
Cookie: `${access_cookie?.name}=${access_cookie?.value}`,
},
cache: "no-store",
},
);

return response;
}
31 changes: 31 additions & 0 deletions src/app/api/support/question/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { NextRequest, NextResponse } from "next/server";

/**
* qna 질문 등록
*/
export async function POST(request: NextRequest) {
const access_cookie = request.cookies.get("access_token");
if (!access_cookie) {
const refresh_cookie = request.cookies.get("refresh_token");
if (!refresh_cookie) {
// 리프레시 토큰이 없으므로 요청 중단
return new NextResponse("Refresh token not found", { status: 403 });
}
// 리프레시 토큰으로 재발급 받아 재요청 보내기 위한 응답
return new NextResponse("Refresh token not found", { status: 401 });
}

const bodyData = await request.json();

const response = await fetch(`${process.env.BACKEND_URL}/api/qna/question`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Cookie: `${access_cookie?.name}=${access_cookie?.value}`,
},
body: JSON.stringify(bodyData),
cache: "no-store",
});

return response;
}
49 changes: 49 additions & 0 deletions src/app/support/notice/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// app/page.tsx
import SupportNoticeDetail from "@/components/support/SupportNoticeDetail";
import { Metadata } from "next";
import { cookies } from "next/headers";

export const metadata: Metadata = {
title: "공지사항 상세조회",
description: "공지사항 상세조회",
};

interface PageProps {
params: { id: string };
}

async function fetchData(id: number) {
const cookie = cookies().get("access_token");

try {
const res = await fetch(
`${process.env.BACKEND_URL}/api/notice/${id}`,
{
headers: {
"Content-Type": "application/json",
Cookie: `${cookie?.name}=${cookie?.value}`,
},
next: { revalidate: 3600 },
},
);
if (!res.ok) {
throw new Error(`Failed to fetch data: ${res.statusText}`);
}
return res.json();
} catch (error) {
return { error: "Failed to fetch data" };
}
}

export default async function Page({ params: { id } }: PageProps) {
const noticeId = Number(id);
if (noticeId <= 0 || !Number.isSafeInteger(noticeId)) {
throw Error("Not Found");
}

const data = await fetchData(noticeId);

return (
<SupportNoticeDetail data={data} />
);
}
62 changes: 49 additions & 13 deletions src/app/support/qna/detail/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,55 @@
import SupportQnADetailEditContainer from "@/containers/support/qna/SupportQnADetailEditContainer";
import { Metadata } from "next";
import { QnADetailType } from "@/types/QnADto";
import { fetchWithAuth } from "@/utils/fetchWithAuth";
import { cookies } from "next/headers";

export const metadata: Metadata = {
title: "마이페이지",
description: "Solitour 사용자 마이페이지",
};
interface Props {
params: { id: string };
}

export async function generateMetadata({ params: { id } }: Props) {
const qnaId = Number(id);
if (qnaId <= 0 || !Number.isSafeInteger(qnaId)) {
throw Error("Not Found");
}

return {
title: `공지사항 조회`,
description: "공지사항 상세조회",
};
}

async function fetchData(id: number) {
const cookie = cookies().get("access_token");

const res = await fetchWithAuth(`${process.env.BACKEND_URL}/api/qna/${id}`, {
headers: {
"Content-Type": "application/json",
Cookie: `${cookie?.name}=${cookie?.value}`,
},
});

console.log("page.tsx 파일 : ",res.status);
console.log("page.tsx 파일 : ",cookie);

if (!res.ok) {
throw new Error(`Failed to fetch data: ${res.statusText}`);
}

return res.json();
}

export default async function Page({ params: { id } }: Props) {
const qnaId = Number(id);
if (qnaId <= 0 || !Number.isSafeInteger(qnaId)) {
throw Error("Not Found");
}

const data: QnADetailType = await fetchData(qnaId);

export default async function page() {
return (
<main
className={
"w-full mt-4 mb-8"
}
>
<SupportQnADetailEditContainer />
<main className="mb-8 w-full">
<SupportQnADetailEditContainer data={data} />
</main>
);
}
}
2 changes: 1 addition & 1 deletion src/components/common/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ const Header = ({
href="/support?menu=about"
prefetch={userId > 0}
>
지원&안내
고객지원
</Link>
</li>
</ul>
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/HeaderSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ const HeaderSidebar = ({
height={22}
/>
)}
<p>지원&안내</p>
<p>고객지원</p>
</Link>
{signedIn ? (
<div className="flex flex-col gap-7">
Expand Down
32 changes: 0 additions & 32 deletions src/components/support/SupportNotice.tsx

This file was deleted.

51 changes: 51 additions & 0 deletions src/components/support/SupportNoticeDetail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
"use client";

import { NoticeType } from "@/types/NoticeDto";
import { NOTICE_DETAIL_BREADCRUMB_PATH } from "@/utils/constant/BreadCrumbDirectory";
import { format } from "date-fns";
import Breadcrumbs from "../common/Breadcrumb";

interface ISupportNoticeDetail {
data: NoticeType;
}

const SupportNoticeDetail = ({ data }: ISupportNoticeDetail) => {
const categoryStyles: { [key: string]: string } = {
이벤트: "bg-green-100 text-green-800",
공지: "bg-blue-100 text-blue-800",
점검: "bg-yellow-100 text-yellow-800",
기타: "bg-gray-100 text-gray-800",
};

return (
<div className={"flex w-full flex-col"}>
<Breadcrumbs categories={NOTICE_DETAIL_BREADCRUMB_PATH(data.id)} />
<div className="mb-8 flex min-h-[calc(100vh-160px)] w-full flex-col rounded-lg border border-gray-300 bg-white p-6 shadow-lg">
{/* 카테고리 및 날짜 */}
<div className="mb-6 flex items-center justify-between">
<div
className={`inline-block rounded-full px-4 py-2 text-sm font-semibold ${categoryStyles[data.categoryName]}`}
>
{data.categoryName}
</div>

<div className="text-sm text-gray-600">
{format(new Date(data.createdAt), "yyyy-MM-dd")}
</div>
</div>

{/* 제목 */}
<div className="mb-4 text-3xl font-extrabold text-gray-900">
{data.title}
</div>

<hr className="my-4 border-t-2 border-gray-300" />

{/* 본문 내용 */}
<div className="text-lg text-gray-800">{data.content}</div>
</div>
</div>
);
};

export default SupportNoticeDetail;
Loading

0 comments on commit 5925c1c

Please sign in to comment.