Skip to content

Commit

Permalink
Merge pull request #212 from TripInfoWeb/dev_gathering
Browse files Browse the repository at this point in the history
Dev gathering
  • Loading branch information
ssssksss authored Aug 20, 2024
2 parents 545a8a5 + b98bda5 commit d394cbf
Show file tree
Hide file tree
Showing 27 changed files with 693 additions and 354 deletions.
1 change: 1 addition & 0 deletions src/app/api/gathering/category/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export async function GET(request: Request) {
headers: {
"Content-Type": "application/json",
},
cache: "no-cache"
}
);

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

export async function GET(request: NextRequest) {
const queryString = request.url.substring(request.url.indexOf("/api/gathering")+14);
const access_cookie = request.cookies.get("access_token");

try {
const response = await fetch(
`${process.env.BACKEND_URL}/api/gatherings`+queryString,
{
method: "GET",
headers: {
Cookie: `${access_cookie?.name}=${access_cookie?.value}`,
"Content-Type": "application/json",
},
cache: "no-cache"
},
);

if (response.status === 200) {
const data = await response.json();
return new NextResponse(JSON.stringify(data), {
status: 200,
});
}
} catch (error) {
console.error("서버에서 데이터 처리 중 오류 발생:", error);
return NextResponse.json({ error: "서버 오류" }, { status: 500 });
}
}
18 changes: 14 additions & 4 deletions src/app/api/gathering/write/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,25 @@ export async function POST(request: NextRequest) {
},
body: JSON.stringify(requestData),
});
// TODO : 에러처리 작업 필요함
// TODO : 에러처리 작업 필요함
if (!response.ok) {
const errorData = await response.json();
throw new Error(`Error: ${errorData.error || 'Unknown error occurred'}`);
}
const resultData = await response.json()
return NextResponse.json({ data: resultData, message: '데이터가 성공적으로 처리되었습니다.' }, { status: 200 });
} catch (error) {
console.error('요청 처리 중 오류 발생:', error);
return NextResponse.json({ error: '서버에서 오류가 발생했습니다.' }, { status: 500 });
} catch (error: unknown) {
if (error instanceof Error) {
console.log(error.message);
return NextResponse.json(
{ error: error.message },
{ status: 500 }
);
} else {
return NextResponse.json(
{ error: '알 수 없는 오류가 발생했습니다.' },
{ status: 500 }
);
}
}
}
12 changes: 8 additions & 4 deletions src/app/gathering/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ interface PageProps {

async function fetchGatheringData(id: number): Promise<GatheringDetailResponseDto> {
try {
const response = await fetch(`${process.env.BACKEND_URL}/api/gatherings/${id}`, {
headers: { 'Content-Type': 'application/json' },
credentials: "include"
});
const response = await fetch(
`${process.env.BACKEND_URL}/api/gatherings/${id}`,
{
headers: { "Content-Type": "application/json" },
credentials: "include",
cache: "no-cache",
},
);

if (!response.ok) {
throw new Error('네트워크 응답이 좋지 않습니다.');
Expand Down
17 changes: 11 additions & 6 deletions src/app/gathering/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,35 @@ export const metadata: Metadata = {

async function getData() {
const res = await fetch(`${process.env.BACKEND_URL}/api/categories/gathering`, {
next: { revalidate: 21600 }, // 6시간 = 21600초
cache: "no-cache"
});

if (!res.ok) {
throw new Error('Failed to fetch data');
}

return res.json();
return await res.json();
}


export default async function Page({ searchParams }: { searchParams: { [key: string]: string | undefined } }) {
const gatheringCategoryList = await getData();

return (
<div className="w-full flex min-h-[calc(100vh-25rem)] flex-col items-center">
<div className="min-h-[calc(100vh-25rem)] w-full">
<div className="flex flex-col items-center">
<Banner
content={[`<b>직접 내 모임</b>을`, "<b>만들어</b>보세요!"]}
buttonText="모임 등록하기"
category={"모임"}
/>
<div className="mt-[26.25rem] max-[744px]:mt-[31rem] " />
/>
</div>
<div className="mt-[26.25rem] max-[744px]:mt-[31rem]"> </div>
<TopList title="모임" />
<GatheringListContainer gatheringCategoryList={gatheringCategoryList} sortDefaultValue={searchParams.sort || ""} />
<GatheringListContainer
gatheringCategoryList={gatheringCategoryList}
sortDefaultValue={searchParams.sort || ""}
/>
</div>
);
}
124 changes: 86 additions & 38 deletions src/components/common/GatheringItem.tsx
Original file line number Diff line number Diff line change
@@ -1,99 +1,147 @@
import GatheringBookMarkContainer from "@/containers/gathering/GatheringBookmarkContainer";
import GatheringLikeContainer from "@/containers/gathering/GatheringLikeContainer";
import { GatheringRecommend } from "@/types/GatheringDto";
import { Gathering } from "@/types/GatheringDto";
import { convertNumberToShortForm } from "@/utils/convertNumberToShortForm";
import { format } from "date-fns";
import { ko } from "date-fns/locale";
import Image from "next/image";
import Link from "next/link";

const SEX: { [key: string]: string } = {
"ALL": "성별무관",
"MALE": "남성분만",
"FEMALE": "여성분만",
ALL: "성별무관",
MALE: "남성분만",
FEMALE: "여성분만",
};


// todo
const GatheringItem = (data: GatheringRecommend) => {

const GatheringItem = (data: Gathering) => {
return (
<Link href={`/gathering/${data.gatheringId}`} className={"border-0 flex max-[744px]:w-[312px] min-[745px]:w-full min-[745px]:min-w-[312px] flex-col gap-[1.25rem] rounded-2xl p-6 outline outline-offset-[-2px] outline-2 outline-gray3 hover:bg-[#F2FAF7] hover:outline-main dark:bg-slate-800 dark:outline-slate-400 dark:hover:bg-slate-600"}>
<Link
href={`/gathering/${data.gatheringId}`}
className={
"flex w-full flex-col gap-[1.25rem] rounded-2xl border-0 p-6 outline outline-2 outline-offset-[-2px] outline-gray3 hover:bg-[#F2FAF7] hover:outline-main max-[744px]:max-w-[27.5rem] min-[745px]:min-w-[312px] dark:bg-slate-800 dark:outline-slate-400 dark:hover:bg-slate-600"
}
>
<div className="flex flex-col">
<div className="flex flex-row items-center justify-between">
<p
className={`w-fit rounded-full border-[0.0625rem] px-4 py-[0.375rem] text-xs font-semibold shadow`}
>
{data.gatheringCategoryName}
</p>
<GatheringBookMarkContainer isBookMark={data.isBookMark} postId={data.gatheringId} />
<GatheringBookMarkContainer
isBookMark={data.isBookMark}
postId={data.gatheringId}
/>
</div>
<p
className="pb-1 pt-6 text-lg font-bold hover:text-main dark:text-slate-200"
>
<p className="overflow-hidden text-ellipsis whitespace-nowrap pb-1 pt-6 text-lg font-bold hover:text-main dark:text-slate-200">
{data.title}
</p>
<p className="text-sm font-medium text-gray1 dark:text-slate-400">
<p className="overflow-hidden text-ellipsis whitespace-nowrap text-sm font-medium text-gray1 dark:text-slate-400">
{data.userName}
</p>
</div>
<div className="flex flex-col gap-5">
<div className="flex flex-col text-sm font-semibold gap-[0.625rem] min-[1024px]:grid min-[1024px]:grid-cols-2">
<div className="flex flex-row items-center gap-2 ">
<div className="grid gap-[0.625rem] text-sm font-semibold max-[744px]:grid-cols-[auto_7rem] max-[432px]:grid-cols-1 min-[745px]:grid-cols-1 min-[1024px]:grid-cols-2">
<div className="flex flex-row items-center gap-2">
{/* 모임 기간 */}
<Image
src="/calendar-icon.svg"
alt="calendar-icon"
width={14}
height={14}
/>
{format(new Date(data.scheduleStartDate),"yyyy-MM-dd")} {data.scheduleEndDate && format(new Date(data.scheduleEndDate),"~ yyyy-MM-dd")}
/>
{format(new Date(data.scheduleStartDate), "yyyy-MM-dd")}
{data.scheduleEndDate &&
format(new Date(data.scheduleEndDate), "~ yyyy-MM-dd")}
</div>
<div className="flex flex-row items-center gap-2 text-black dark:text-slate-400">
{/* 모임 장소 */}
<div className={"h-4 w-[0.875rem]"}>
<Image src="/location-icon.svg" alt="location-icon" width={14} height={14} />
<div className="flex items-center gap-2 text-black dark:text-slate-400 ">
{/* 모임 장소 */}
<div className={"h-4 min-w-[0.875rem] flex items-center"}>
<Image
src="/location-icon.svg"
alt="location-icon"
width={14}
height={14}
/>
</div>
<p>{data.zoneCategoryParentName} {","} {data.zoneCategoryChildName}</p>
<p className="overflow-hidden truncate whitespace-nowrap">
{data.zoneCategoryParentName} {","} {data.zoneCategoryChildName}
</p>
</div>
<div className="flex flex-row items-center gap-2 text-black dark:text-slate-400 ">
<div className={"flex min-w-fit gap-2"}>
<div className={"relative h-5 w-[0.875rem] "}>
<Image src="/people-icon.svg" alt="people-icon" width={14} height={14} className="absolute top-[50%] translate-y-[-50%]" />
<div className="flex flex-row items-center gap-2 text-black dark:text-slate-400">
<div className={"flex min-w-fit gap-2"}>
<div className={"relative h-5 w-[0.875rem]"}>
{/* 모임 인원 */}
<Image
src="/people-icon.svg"
alt="people-icon"
width={14}
height={14}
className="absolute top-[50%] translate-y-[-50%]"
/>
</div>
<p
className={`${data.nowPersonCount == data.personCount && "text-[#ff0000]"}`}
>
<span
className={`text-main ${data.nowPersonCount / data.personCount > 0.5 && "text-[#FC9F3A]"} ${data.nowPersonCount == data.personCount && "text-[#ff0000]"}`}
>
{data.nowPersonCount}
</span>
{"/"}
{data.personCount}
</p>
</div>
<p className={`${(data.nowPersonCount + 1) == data.personCount && 'text-[#ff0000]'}`}>
<span className={`text-main ${(data.nowPersonCount + 1) / data.personCount > 0.5 && 'text-[#FC9F3A]'} ${(data.nowPersonCount + 1) == data.personCount && 'text-[#ff0000]'}`}> {data.nowPersonCount + 1} </span> / {data.personCount}
<p>
{"(" +
(new Date().getFullYear() - data.startAge) +
"세 ~ " +
(new Date().getFullYear() - data.endAge) +
"세 ," +
SEX[data.allowedSex] +
")"}
</p>
</div>
<p>{"(" + (new Date().getFullYear() - data.startAge) + "세 ~ " + (new Date().getFullYear() - data.endAge) + "세 ," + SEX[data.allowedSex] + ")"}</p>
</div>
<div className="flex flex-row items-center gap-2">
{/* 모임 인원 */}
<Image
{/* 모임 시간 */}
<Image
src="/clock-icon.svg"
alt="clock-icon"
width={14}
height={14}
className="ml-[.0625rem]"
/>
<span> {format(new Date(data.scheduleStartDate),"hh:mm")} </span>
</div>
/>
<span> {format(new Date(data.scheduleStartDate), "hh:mm")} </span>
</div>
</div>
<div className="flex flex-row items-center justify-between">
<div className="flex flex-row items-center gap-1">
<Image src="/pin-icon.png" alt="pin-icon" width={16} height={16} />
<p className="text-sm dark:text-slate-400">모집마감일: 06.07(금)</p>
<p className="text-sm dark:text-slate-400">
모집마감일:
{format(new Date(data.deadline), "yyyy-MM-dd(EE)", {
locale: ko,
})}
</p>
</div>
<div className="flex flex-row justify-between">
<div className="flex flex-row items-center gap-3">
<GatheringLikeContainer likes={data.likeCount} isLike={true} gatheringId={data.gatheringId} />
<GatheringLikeContainer
likes={data.likeCount}
isLike={data.isLike}
gatheringId={data.gatheringId}
/>
<div className="flex flex-row items-center gap-1 text-gray2 dark:text-slate-400">
<Image
src="/eyes-icon.svg"
alt="eyes-icon"
width={15}
height={15}
/>
<p className="text-sm">{convertNumberToShortForm(data.viewCount)}</p>
<p className="text-sm">
{convertNumberToShortForm(data.viewCount)}
</p>
</div>
</div>
</div>
Expand Down
13 changes: 2 additions & 11 deletions src/components/common/TopList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import LottieImage from "@/../public/lottie/solitour_gathering_animation.json";
import { TopGatheringResponseDto } from "@/types/GatheringDto";
import { TopInformationResponseDto } from "@/types/InformationDto";
import Image from "next/image";
import Link from "next/link";
Expand Down Expand Up @@ -26,9 +27,8 @@ async function getTopInformationList() {
}

async function getTopGatheringList() {
/*
const response = await fetch(
`${process.env.BACKEND_URL}/api/?????????????????????????`,
`${process.env.BACKEND_URL}/api/gatherings/ranks`,
{
method: "GET",
next: { revalidate: 3600, tags: ["getTopGatheringList"] },
Expand All @@ -41,15 +41,6 @@ async function getTopGatheringList() {
}

return response.json() as Promise<TopGatheringResponseDto[]>;
*/

return [
{ id: 1, title: "동해 서핑 투게더" },
{ id: 2, title: "강릉 빵지순례 같이 해요!" },
{ id: 3, title: "전시회 좋아하는 사람? 국립현대미술관 같이 가요" },
{ id: 4, title: "퇴근 후 운동할 사람? 인왕산 같이 올라가요!" },
{ id: 5, title: "떡볶이 맛잘알과 함께 전국 떡볶이 투어" },
];
}

const TopList = async ({ title }: Props) => {
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export default function Dropdown<T>({ options, dropdownHandler, defaultValue, va

{isOpen && (
<div
className="absolute w-full mt-2 rounded-md bg-white ring-2 ring-offset-2 ring-black ring-opacity-5 focus:outline-none transition ease-out duration-200"
className="absolute w-full z-40 mt-2 rounded-md bg-white ring-2 ring-offset-2 ring-black ring-opacity-5 focus:outline-none transition ease-out duration-200"
>
<div className={"py-1 min-w-max "} role="menu" aria-orientation="vertical" aria-labelledby="options-menu">
{options.map((i) => (
Expand Down
15 changes: 4 additions & 11 deletions src/components/gathering/GatheringCardList.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
import { GatheringRecommend } from "@/types/GatheringDto";
import { Gathering } from "@/types/GatheringDto";
import GatheringItem from "../common/GatheringItem";

interface IGatheringCardList {
data: GatheringRecommend[]
data: Gathering[]
}
const GatheringCardList = ({data}: IGatheringCardList) => {
return (
<div className="min-h-[20rem]">
<div className="my-6 grid min-[745px]:grid-cols-2 m-auto gap-x-3 gap-y-3">
{data?.map((i, index) => (
<GatheringItem
key={i.gatheringId}
{...i}
/>
))}
</div>
<div className="my-6 grid min-h-[20rem] w-full justify-items-center gap-x-3 gap-y-3 min-[745px]:grid-cols-2">
{data?.map((i, index) => <GatheringItem key={i.gatheringId} {...i} />)}
</div>
);
};
Expand Down
Loading

0 comments on commit d394cbf

Please sign in to comment.