Skip to content

Commit 46b0125

Browse files
authored
Merge pull request #123 from billilge/feat/#121-notice-pop-up
[Feat/#121] 공지사항 팝업 구현
2 parents eabcf7d + 19916e1 commit 46b0125

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

src/app/mobile/main/page.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { WelfareItemData, Item } from '@/types/welfareItemType';
1111
import IconSearch from 'public/assets/icons/icon-search.svg';
1212
import { useRouter } from 'next/navigation';
1313
import { requestNotificationPermission } from '@/utils/pushNotification';
14+
import PopUp from '@/components/mobile/PopUp';
1415

1516
export default function MobileMain() {
1617
const [isBottomSheetOpen, setIsBottomSheetOpen] = useState(false);
@@ -19,6 +20,7 @@ export default function MobileMain() {
1920
items: [],
2021
});
2122
const [searchQuery, setSearchQuery] = useState('');
23+
const [showPopUp, setShowPopUp] = useState<boolean>(false);
2224
const router = useRouter();
2325

2426
const fetchWelfareItems = async () => {
@@ -47,6 +49,11 @@ export default function MobileMain() {
4749
fetchWelfareItems();
4850

4951
requestNotificationPermission();
52+
53+
// "다시 보지 않기" 플래그가 없으면 팝업 표시
54+
if (!localStorage.getItem('popUpDismissed')) {
55+
setShowPopUp(true);
56+
}
5057
}, []);
5158

5259
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -103,6 +110,19 @@ export default function MobileMain() {
103110
</section>
104111
</div>
105112

113+
{showPopUp && (
114+
<PopUp
115+
title="🚨 변경사항 안내 🚨"
116+
content={`물품 대여 신청은 현재 시간으로부터
117+
5분 후에 가능합니다.\n(16시 55분부터는 즉시 신청이 가능합니다.)`}
118+
onClickCta={() => setShowPopUp(false)}
119+
onClickOther={() => {
120+
localStorage.setItem('popUpDismissed', 'true');
121+
setShowPopUp(false);
122+
}}
123+
/>
124+
)}
125+
106126
{/* Bottom Sheet */}
107127
<BottomSheet
108128
isOpen={isBottomSheetOpen}

src/components/mobile/BottomSheet/index.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,32 @@ export default function BottomSheet({
119119
0,
120120
);
121121

122+
// 점심 시간
123+
const lunchOpenTime = new Date(
124+
now.getFullYear(),
125+
now.getMonth(),
126+
now.getDate(),
127+
12,
128+
0,
129+
);
130+
const lunchCloseTime = new Date(
131+
now.getFullYear(),
132+
now.getMonth(),
133+
now.getDate(),
134+
12,
135+
59,
136+
);
137+
122138
// 운영시간: 10:00 ~ 17:00
123139
if (inputTime < openTime || inputTime > closeTime) {
124140
return '대여 가능한 시간은 10:00 ~ 17:00입니다.';
125141
}
126142

143+
// 점심시간: 12:00 ~ 12:59
144+
if (inputTime >= lunchOpenTime && inputTime < lunchCloseTime) {
145+
return '12:00 ~ 12:59은 점심시간입니다.';
146+
}
147+
127148
// 입력 시간이 현재 시간보다 이후인지 체크
128149
if (inputTime <= now) {
129150
return '대여는 현재 시간 이후로만 가능합니다.';
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { handleTouchStart, handleTouchEnd } from '@/utils/handleTouch';
2+
3+
interface PopUpProps {
4+
title: string; // PopUp창 제목
5+
content: string; // PopUp창 내용
6+
ctaButtonText?: string; // 오른쪽 버튼에 들어갈 문구
7+
otherButtonText?: string; // 왼쪽 버튼에 들어갈 문구
8+
onClickCta?: () => void; // 오른쪽 버튼을 눌렀을 때 실행될 함수
9+
onClickOther?: () => void; // 왼쪽 버튼을 눌렀을 때 실행될 함수
10+
}
11+
12+
export default function PopUp({
13+
title,
14+
content,
15+
ctaButtonText = '확인',
16+
otherButtonText = '다시 보지 않기',
17+
onClickCta,
18+
onClickOther,
19+
}: PopUpProps) {
20+
const defalutButtonClass =
21+
'text-body-1-normal_semi w-[108px] rounded-[10px] py-[9px] font-medium outline-none ';
22+
23+
return (
24+
<div className="fixed inset-0 z-20 flex items-center justify-center">
25+
{/* 반투명한 검정 배경 */}
26+
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
27+
<div
28+
className="absolute inset-0 bg-black bg-opacity-50"
29+
onClick={onClickCta} // 배경 클릭 시 닫히도록 설정
30+
/>
31+
32+
<div className="relative flex w-[275px] flex-col gap-2.5 rounded-[20px] bg-white-primary p-5">
33+
<div className="flex flex-col gap-2.5 py-5 text-center">
34+
{/* 제목 */}
35+
<div className="text-body-1-normal_semi font-semibold">{title}</div>
36+
{/* 문구 */}
37+
<div className="whitespace-pre-line text-caption-1_midi font-medium text-gray-primary">
38+
{content}
39+
</div>
40+
</div>
41+
42+
{/* 버튼 2개(서브 버튼 / 메인 버튼) */}
43+
<div className="flex justify-between gap-5">
44+
<button
45+
type="button"
46+
onClick={onClickOther}
47+
onTouchStart={handleTouchStart}
48+
onTouchEnd={handleTouchEnd}
49+
className={`${defalutButtonClass} bg-gray-tertiary text-gray-secondary transition-all`}
50+
>
51+
{otherButtonText}
52+
</button>
53+
<button
54+
type="button"
55+
onClick={onClickCta}
56+
onTouchStart={handleTouchStart}
57+
onTouchEnd={handleTouchEnd}
58+
className={` ${defalutButtonClass} bg-return-blue text-white-primary`}
59+
>
60+
{ctaButtonText}
61+
</button>
62+
</div>
63+
</div>
64+
</div>
65+
);
66+
}

0 commit comments

Comments
 (0)