Skip to content

Commit 19f743d

Browse files
committed
2 parents 742c97a + d727085 commit 19f743d

7 files changed

Lines changed: 132 additions & 53 deletions

File tree

โ€Žsrc/app/(public)/concerts/[id]/page.tsxโ€Ž

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,21 @@ export default async function Page({ params }: { params: Promise<{ id: string }>
7575
notFound();
7676
}
7777

78+
const now = new Date();
79+
80+
let isChatAvailable = false;
81+
82+
if (concertDetail.ticketTime) {
83+
// ticketTime์€ KST ๊ธฐ์ค€ ์‹œ๊ฐ„์œผ๋กœ ๋‚ด๋ ค์˜จ๋‹ค๊ณ  ๊ฐ€์ •
84+
const ticketTime = new Date(concertDetail.ticketTime);
85+
// ์ฑ„ํŒ…์€ ํ‹ฐ์ผ“ ์˜คํ”ˆ ์‹œ์  ๊ธฐ์ค€ ยฑ3์ผ ๋™์•ˆ๋งŒ ๊ฐ€๋Šฅ
86+
const THREE_DAYS = 3 * 24 * 60 * 60 * 1000;
87+
88+
isChatAvailable =
89+
now.getTime() >= ticketTime.getTime() - THREE_DAYS &&
90+
now.getTime() <= ticketTime.getTime() + THREE_DAYS;
91+
}
92+
7893
return (
7994
<>
8095
<BreadcrumbNavbar
@@ -85,10 +100,10 @@ export default async function Page({ params }: { params: Promise<{ id: string }>
85100
]}
86101
/>
87102
<Suspense fallback={<ConcertHeaderSkeleton />}>
88-
<ConcertHeader concertId={id} />
103+
<ConcertHeader concertId={id} isLoggedIn={isLoggedIn} isChatAvailable={isChatAvailable} />
89104
</Suspense>
90105
<Suspense fallback={<ConcertDetailSkeleton />}>
91-
<ConcertDetail concertId={id} isLoggedIn={isLoggedIn} />
106+
<ConcertDetail concertId={id} isLoggedIn={isLoggedIn} isChatAvailable={isChatAvailable} />
92107
</Suspense>
93108
{similarConcerts.length > 0 && (
94109
<Suspense fallback={<ConcertSimilarSkeleton />}>

โ€Žsrc/components/concert/detail/ConcertChatButton.tsxโ€Ž

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,28 @@ import { useRouter } from "next/navigation";
1818
import { MessageSquareIcon } from "lucide-react";
1919
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
2020

21-
export default function ConcertChatButton({ concertId }: { concertId?: string }) {
21+
export default function ConcertChatButton({
22+
concertId,
23+
isLoggedIn,
24+
isChatAvailable,
25+
}: {
26+
concertId?: string;
27+
isLoggedIn?: boolean;
28+
isChatAvailable?: boolean;
29+
}) {
2230
const router = useRouter();
2331
const [chatDialogOpen, setChatDialogOpen] = useState(false);
2432

25-
const handleOpenChatModal = () => {
33+
const handleClick = () => {
34+
if (!isLoggedIn) {
35+
toast.error("๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.");
36+
router.push("/sign-in");
37+
return;
38+
}
39+
if (!isChatAvailable) {
40+
toast.error("์ง€๊ธˆ์€ ์ฑ„ํŒ… ๊ฐ€๋Šฅ ๊ธฐ๊ฐ„์ด ์•„๋‹™๋‹ˆ๋‹ค.");
41+
return;
42+
}
2643
setChatDialogOpen(true);
2744
};
2845

@@ -53,7 +70,7 @@ export default function ConcertChatButton({ concertId }: { concertId?: string })
5370
variant="outline"
5471
size="icon"
5572
className="border-border hover:bg-border group"
56-
onClick={handleOpenChatModal}
73+
onClick={handleClick}
5774
>
5875
<MessageSquareIcon className="h-4 w-4" />
5976
</Button>
@@ -73,8 +90,6 @@ export default function ConcertChatButton({ concertId }: { concertId?: string })
7390
<AlertDialogTitle>์ฑ„ํŒ…์— ์ฐธ์—ฌํ•˜์‹œ๊ฒ ์–ด์š”?</AlertDialogTitle>
7491
</AlertDialogHeader>
7592
<AlertDialogDescription>
76-
์˜ˆ๋งค์ผ์ด ์ž„๋ฐ•ํ•œ ๊ณต์—ฐ์ด์—์š”.
77-
<br />
7893
์ฑ„ํŒ…์— ์ฐธ์—ฌํ•ด ์‹ค์‹œ๊ฐ„ ์„œ๋ฒ„ ์‹œ๊ฐ„๊ณผ ๋‹ค๋ฅธ ์ด์šฉ์ž๋“ค๊ณผ์˜ ์ด์•ผ๊ธฐ๋ฅผ ํ•จ๊ป˜ ๋‚˜๋ˆ ๋ณด์„ธ์š”.
7994
</AlertDialogDescription>
8095
<AlertDialogFooter>

โ€Žsrc/components/concert/detail/ConcertDetail.tsxโ€Ž

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ import MobileQuickActions from "./MobileQuickActions";
1414
export default async function ConcertDetail({
1515
concertId,
1616
isLoggedIn,
17+
isChatAvailable,
1718
}: {
1819
concertId: string;
1920
isLoggedIn: boolean;
21+
isChatAvailable: boolean;
2022
}) {
2123
const [concertDetail, concertVenue, concertTicketing, isAuthenticated] = await Promise.all([
2224
getConcertDetail({ concertId }),
@@ -37,7 +39,7 @@ export default async function ConcertDetail({
3739

3840
return (
3941
<section className="bg-bg-main lg:px-15 lg:py-10">
40-
<div className="mx-auto flex w-full max-w-400 flex-col gap-5 lg:flex-row lg:gap-8">
42+
<div className="mx-auto flex w-full max-w-400 flex-col gap-5 lg:flex-row xl:gap-8">
4143
<div className="flex-2 space-y-15 lg:space-y-20">
4244
<ConcertDetailInfo
4345
concertImageUrls={concertDetail?.concertImageUrls}
@@ -59,6 +61,8 @@ export default async function ConcertDetail({
5961
concertEndDate={concertDetail?.endDate}
6062
userData={userData}
6163
isLiked={isLikedConcert?.isLike}
64+
isLoggedIn={isLoggedIn}
65+
isChatAvailable={isChatAvailable}
6266
/>
6367
</div>
6468
</div>
@@ -73,6 +77,8 @@ export default async function ConcertDetail({
7377
concertEndDate={concertDetail?.endDate}
7478
userData={userData}
7579
isLiked={isLikedConcert?.isLike}
80+
isLoggedIn={isLoggedIn}
81+
isChatAvailable={isChatAvailable}
7682
/>
7783
</section>
7884
);

โ€Žsrc/components/concert/detail/ConcertHeader.tsxโ€Ž

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,15 @@ import { getAuthStatus, getMe } from "@/lib/api/auth/auth.server";
1919
import ConcertChatButton from "./ConcertChatButton";
2020
import { PLACEHOLDER_IMAGE } from "@/components/home/upcoming-slider/constants";
2121

22-
export default async function ConcertHeader({ concertId }: { concertId: string }) {
22+
export default async function ConcertHeader({
23+
concertId,
24+
isLoggedIn,
25+
isChatAvailable,
26+
}: {
27+
concertId: string;
28+
isLoggedIn: boolean;
29+
isChatAvailable: boolean;
30+
}) {
2331
const [concertDetail, concertTicketing, isAuthenticated] = await Promise.all([
2432
getConcertDetail({ concertId }),
2533
getTicketOfficesByConcertId({ concertId }),
@@ -41,11 +49,11 @@ export default async function ConcertHeader({ concertId }: { concertId: string }
4149
}
4250

4351
return (
44-
<section className="header bg-bg-sub pb-6 lg:px-15 lg:py-10">
52+
<section className="header bg-bg-sub lg:px-15 lg:py-10">
4553
{/* ๋ชจ๋ฐ”์ผ: flex-col (์„ธ๋กœ), md ์ด์ƒ: flex-row (๊ฐ€๋กœ) */}
46-
<div className="mx-auto flex w-full max-w-400 flex-col gap-5 lg:flex-row lg:items-start lg:gap-8">
54+
<div className="mx-auto flex w-full max-w-400 flex-col gap-5 lg:flex-row lg:items-start xl:gap-8">
4755
{/* ํฌ์Šคํ„ฐ ์˜์—ญ: ๋ชจ๋ฐ”์ผ w-full, md ์ด์ƒ w-2/5 */}
48-
<div className="border-border w-full flex-1 overflow-hidden lg:sticky lg:top-30 lg:rounded-2xl lg:border">
56+
<div className="border-border w-full flex-1 overflow-hidden lg:sticky lg:top-30 lg:rounded-2xl lg:border xl:w-2/5">
4957
<AspectRatio ratio={320 / 426.5}>
5058
<Image
5159
src={concertDetail.posterUrl ?? PLACEHOLDER_IMAGE}
@@ -59,7 +67,7 @@ export default async function ConcertHeader({ concertId }: { concertId: string }
5967
</div>
6068

6169
{/* ์ •๋ณด ์˜์—ญ */}
62-
<div className="bg-bg-main border-border sticky top-4 mx-5 flex flex-1 flex-col gap-4 rounded-2xl border p-5 lg:top-30 lg:mx-0 lg:gap-8 lg:p-10">
70+
<div className="bg-bg-main border-border sticky top-4 mx-5 flex flex-1 flex-col gap-4 rounded-2xl border p-5 lg:top-30 lg:mx-0 xl:gap-8 xl:p-10">
6371
<div className="title flex items-start justify-between gap-4">
6472
<div className="flex flex-col gap-3 md:gap-4">
6573
{concertDetail.concertArtists.length > 0 && (
@@ -74,19 +82,18 @@ export default async function ConcertHeader({ concertId }: { concertId: string }
7482
))}
7583
</div>
7684
)}
77-
<div className="flex flex-col gap-1">
78-
<h2 className="text-text-main text-2xl font-bold lg:text-4xl">
79-
{concertDetail.name}
80-
</h2>
81-
<p className="text-text-sub text-base md:text-lg lg:text-xl">
82-
{concertDetail.description}
83-
</p>
84-
</div>
85+
<h2 className="text-text-main text-2xl font-bold xl:text-4xl">
86+
{concertDetail.name}
87+
</h2>
8588
</div>
8689

8790
{/* ๋ฒ„ํŠผ ๊ทธ๋ฃน: ๋ชจ๋ฐ”์ผ์—์„œ๋Š” ์ƒ๋‹จ ์šฐ์ธก ํ˜น์€ ํ•˜๋‹จ ๋ฐฐ์น˜ ๋“ฑ ๊ณ ๋ ค ๊ฐ€๋Šฅ */}
8891
<div className="flex gap-2">
89-
<ConcertChatButton concertId={concertDetail.concertId} />
92+
<ConcertChatButton
93+
concertId={concertDetail.concertId}
94+
isLoggedIn={isLoggedIn}
95+
isChatAvailable={isChatAvailable}
96+
/>
9097
<ConcertLikeButton
9198
concertId={concertDetail.concertId}
9299
isAuthenticated={isAuthenticated}
@@ -96,7 +103,7 @@ export default async function ConcertHeader({ concertId }: { concertId: string }
96103
</div>
97104

98105
{/* ์ •๋ณด ๊ทธ๋ฆฌ๋“œ: ๋ชจ๋ฐ”์ผ 1์—ด, md ์ด์ƒ 2์—ด */}
99-
<div className="border-border grid grid-cols-1 gap-x-4 gap-y-4 border-y py-6 md:grid-cols-2 md:gap-y-6 md:py-8">
106+
<div className="border-border grid grid-cols-1 gap-x-4 gap-y-4 border-y py-6 xl:grid-cols-2 xl:gap-y-6 xl:py-8">
100107
<ConcertHeaderInfo
101108
type="date"
102109
label="๋‚ ์งœ ๋ฐ ์‹œ๊ฐ„"

โ€Žsrc/components/concert/detail/MobileQuickActions.tsxโ€Ž

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ interface MobileQuickActionsProps {
2222
concertEndDate?: string;
2323
userData: User | null;
2424
isLiked?: boolean;
25+
isLoggedIn: boolean;
26+
isChatAvailable: boolean;
2527
}
2628

2729
export default function MobileQuickActions({
@@ -31,6 +33,8 @@ export default function MobileQuickActions({
3133
concertEndDate,
3234
userData,
3335
isLiked,
36+
isLoggedIn,
37+
isChatAvailable,
3438
}: MobileQuickActionsProps) {
3539
const [open, setOpen] = useState(false);
3640

@@ -63,7 +67,7 @@ export default function MobileQuickActions({
6367
</SheetHeader>
6468
<div className="p-4 pt-15 pb-6">
6569
<SheetClose
66-
className="bg-bg-sub border-border absolute top-4 left-1/2 h-2 w-40 -translate-x-1/2 rounded-lg border"
70+
className="bg-muted absolute top-4 left-1/2 h-1.5 w-12 -translate-x-1/2 rounded-lg"
6771
aria-label="๋น ๋ฅธ ์‹คํ–‰์ฐฝ ๋‹ซ๊ธฐ"
6872
/>
6973
<QuickActionsSection
@@ -73,6 +77,8 @@ export default function MobileQuickActions({
7377
concertEndDate={concertEndDate}
7478
userData={userData}
7579
isLiked={isLiked}
80+
isLoggedIn={isLoggedIn}
81+
isChatAvailable={isChatAvailable}
7682
/>
7783
</div>
7884
</SheetContent>

โ€Žsrc/components/concert/detail/QuickActionsSection.tsxโ€Ž

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import { createNewPlan } from "@/lib/api/planner/planner.client";
4242
import { useRouter } from "next/navigation";
4343
import { User } from "@/types/user";
4444
import { postLikeConcert } from "@/lib/api/concerts/concerts.client";
45-
import { getConcertStartDate, isSameDay, dateToISOString } from "@/utils/helpers/handleDate";
45+
import { dateToISOString, getConcertStartDate, isSameDay } from "@/utils/helpers/handleDate";
4646
import { joinChatRoom } from "@/lib/api/chat/chat.client";
4747

4848
export default function QuickActionsSection({
@@ -52,13 +52,17 @@ export default function QuickActionsSection({
5252
concertEndDate,
5353
userData,
5454
isLiked,
55+
isLoggedIn,
56+
isChatAvailable,
5557
}: {
5658
concertId?: string;
5759
concertTicketingData?: TicketOffice[] | null;
5860
concertStartDate?: string;
5961
concertEndDate?: string;
6062
userData: User | null;
6163
isLiked?: boolean;
64+
isLoggedIn: boolean;
65+
isChatAvailable: boolean;
6266
}) {
6367
// ๋งํฌ ์ด๋™
6468
const router = useRouter();
@@ -105,6 +109,17 @@ export default function QuickActionsSection({
105109
setAlarmDialogOpen(true);
106110
};
107111
const handleOpenChatModal = () => {
112+
if (!isLoggedIn) {
113+
toast.error("๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.");
114+
router.push("/sign-in");
115+
return;
116+
}
117+
if (!isChatAvailable) {
118+
toast.error("์ง€๊ธˆ์€ ์ฑ„ํŒ… ๊ฐ€๋Šฅ ๊ธฐ๊ฐ„์ด ์•„๋‹™๋‹ˆ๋‹ค.");
119+
return;
120+
}
121+
setChatDialogOpen(true);
122+
108123
setChatDialogOpen(true);
109124
};
110125

@@ -440,8 +455,6 @@ export default function QuickActionsSection({
440455
<AlertDialogTitle>์ฑ„ํŒ…์— ์ฐธ์—ฌํ•˜์‹œ๊ฒ ์–ด์š”?</AlertDialogTitle>
441456
</AlertDialogHeader>
442457
<AlertDialogDescription>
443-
์˜ˆ๋งค์ผ์ด ์ž„๋ฐ•ํ•œ ๊ณต์—ฐ์ด์—์š”.
444-
<br />
445458
์ฑ„ํŒ…์— ์ฐธ์—ฌํ•ด ์‹ค์‹œ๊ฐ„ ์„œ๋ฒ„ ์‹œ๊ฐ„๊ณผ ๋‹ค๋ฅธ ์ด์šฉ์ž๋“ค๊ณผ์˜ ์ด์•ผ๊ธฐ๋ฅผ ํ•จ๊ป˜ ๋‚˜๋ˆ ๋ณด์„ธ์š”.
446459
</AlertDialogDescription>
447460
<AlertDialogFooter>

0 commit comments

Comments
ย (0)