Skip to content

Commit c75d0eb

Browse files
authored
Merge pull request #23 from codeit-6team/feat/notification-modal
✨ feat: 알림 모달창 구현
2 parents 72a6db7 + b150026 commit c75d0eb

File tree

12 files changed

+184
-0
lines changed

12 files changed

+184
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ node_modules
1111
dist
1212
dist-ssr
1313
*.local
14+
mocks
1415

1516
# Editor directories and files
1617
.vscode/*

package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"react": "^19.1.0",
1616
"react-dom": "^19.1.0",
1717
"react-router-dom": "^7.6.1",
18+
"tailwind-scrollbar-hide": "^4.0.0",
1819
"tailwindcss": "^4.1.8"
1920
},
2021
"devDependencies": {

src/assets/icons/.gitkeep

Whitespace-only changes.

src/assets/icons/ic_close.svg

Lines changed: 10 additions & 0 deletions
Loading

src/components/common/.gitkeep

Whitespace-only changes.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import calculateTimeDifference from '@/utils/calculateTimeDefference';
2+
import formatWorkTime from '@/utils/formatWorkTime';
3+
4+
interface NotificationCardProps {
5+
status: 'accepted' | 'rejected'; // 공고 지원 상태
6+
restaurantName: string; // 음식점 이름
7+
startsAt: string; // 공고 시작 시간 (ISO 8601 문자열)
8+
workHour: number; // 근무 시간 (시간 단위)
9+
createdAt: string; // 알림 생성 시간 (ISO 8601 문자열)
10+
}
11+
12+
/*
13+
* 사용자가 공고에 지원한 결과를 알리는 알림 카드 컴포넌트입니다.
14+
* 상태에 따라 '승인' 혹은 '거절'로 표시되며,
15+
* 가게 이름과 알바 시간, 생성 시간을 보여줍니다.
16+
*/
17+
18+
export default function NotificationCard({
19+
status,
20+
restaurantName,
21+
startsAt,
22+
workHour,
23+
createdAt,
24+
}: NotificationCardProps) {
25+
const formattedTime = formatWorkTime({
26+
startsAt,
27+
workHour,
28+
});
29+
const formattedCreatedAt = calculateTimeDifference(createdAt);
30+
const formattedStatus = status === 'accepted' ? '승인' : '거절';
31+
const formattedStatusClass =
32+
status === 'accepted' ? 'text-blue-20' : 'text-red-20';
33+
return (
34+
<div className="flex flex-col gap-4 md:w-328 py-16 px-12 bg-white border border-gray-20 rounded-5 ">
35+
{status === 'accepted' ? (
36+
<div className="w-5 h-5 rounded-full bg-blue-20"></div>
37+
) : (
38+
<div className="w-5 h-5 rounded-full bg-red-20"></div>
39+
)}
40+
<h2 className="text-body2/22 font-regular">
41+
{restaurantName} ({formattedTime}) 공고 지원이{' '}
42+
<span className={formattedStatusClass}>{formattedStatus}</span>
43+
되었어요.
44+
</h2>
45+
<p className="text-caption/16 text-gray-40">{formattedCreatedAt}</p>
46+
</div>
47+
);
48+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { useNavigate } from 'react-router-dom';
2+
import NotificationCard from './NotificationCard';
3+
import close from '@/assets/icons/ic_close.svg';
4+
5+
interface NotificationItem {
6+
createdAt: string; // 생성 일시 (ISO 8601 문자열)
7+
result: 'accepted' | 'rejected'; // 결과 상태
8+
read: boolean; // 읽음 여부
9+
shop: {
10+
item: {
11+
name: string; // 가게 이름
12+
};
13+
};
14+
notice: {
15+
item: {
16+
startsAt: string; // 근무 시작 시간 (ISO 8601 문자열)
17+
workhour: number; // 근무 시간 (시간 단위)
18+
};
19+
};
20+
}
21+
interface NotificationModalProps {
22+
data: NotificationItem[]; // 알림 데이터 배열
23+
count: number; // 알림 개수
24+
}
25+
26+
/*
27+
* 알림 모달 컴포넌트입니다.
28+
* 알림 데이터들을 카드로 표시하며, 스크롤 가능합니다.
29+
* PC/Tablet에서는 모달 형식으로, 바깥을 클릭하거나 esc를 통해 창을 닫을 수 있습니다.
30+
* 모바일에서는 닫기 버튼으로 창을 닫을 수 있습니다.
31+
*/
32+
33+
export default function NotificationModal({ data, count }: NotificationModalProps) {
34+
const navigate = useNavigate();
35+
return (
36+
<div className="flex flex-col px-20 py-40 bg-red-10 gap-16 h-screen md:py-24 md:border-4 md:border-gray-30 md:rounded-10 md:shadow-custom md:h-420 md:w-368">
37+
<div className="flex justify-between items-center">
38+
<h1 className="text-h3 font-bold">알림 {count}</h1>
39+
<button onClick={()=> navigate(-1)} className="md:hidden">
40+
<img src={close} alt="닫기" />
41+
</button>
42+
</div>
43+
<div className="flex flex-col gap-8 overflow-y-auto scrollbar-hide">
44+
{data.map((data, index) => (
45+
<NotificationCard
46+
key={index}
47+
status={data.result}
48+
restaurantName={data.shop.item.name}
49+
startsAt={data.notice.item.startsAt}
50+
workHour={data.notice.item.workhour}
51+
createdAt={data.createdAt}
52+
/>
53+
))}
54+
</div>
55+
</div>
56+
);
57+
}

src/index.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
@import 'tailwindcss';
2+
@import 'tailwind-scrollbar-hide/v4';
23

34
@font-face {
45
font-family: 'SpoqaHanSansNeo-Regular';
@@ -96,5 +97,6 @@
9697
--text-body1: 16px;
9798
--text-body2: 14px;
9899
--text-caption: 12px;
100+
--shadow-custom: 0px 2px 8px 0px rgba(120, 116, 134, 0.25);
99101
--spacing: 0.0625rem;
100102
}

src/utils/.gitkeep

Whitespace-only changes.

0 commit comments

Comments
 (0)