11import { useRouter } from 'next/navigation' ;
22
33import { Icon } from '@/components/icon' ;
4+ import { Toast } from '@/components/ui' ;
5+ import { useToast } from '@/components/ui/toast/core' ;
46import { useUpdateNotificationRead } from '@/hooks/use-notification/use-notification-update-read' ;
57import { formatTimeAgo } from '@/lib/formatDateTime' ;
68import { cn } from '@/lib/utils' ;
@@ -13,17 +15,22 @@ interface Props {
1315export const NotificationCard = ( { item } : Props ) => {
1416 const router = useRouter ( ) ;
1517 const { mutateAsync } = useUpdateNotificationRead ( ) ;
18+ const { run } = useToast ( ) ;
1619
1720 const NotificationIcon = IconMap [ item . type ] ;
1821 const title = getTitle ( item ) ;
1922 const description = getDescription ( item ) ;
2023 const timeAgo = getTimeAgo ( item ) ;
24+ const redirectUrl = getRedirectUrl ( item ) ;
2125
2226 const handleNotificationClick = ( ) => {
2327 try {
2428 mutateAsync ( item . id ) ;
25-
26- router . push ( `${ item . redirectUrl } ` ) ;
29+ if ( redirectUrl ) {
30+ router . push ( redirectUrl ) ;
31+ } else {
32+ run ( < Toast > 이미 마감되었거나 삭제된 모임입니다.</ Toast > ) ;
33+ }
2734 } catch { }
2835 } ;
2936
@@ -50,45 +57,91 @@ export const NotificationCard = ({ item }: Props) => {
5057} ;
5158
5259const IconMap : Record < NotificationType , React . ReactNode > = {
53- FOLLOW : < Icon id = 'heart' className = 'text-mint-500 size-6' /> ,
54- GROUP_CREATE : < Icon id = 'map-pin-2' className = 'size-6 text-[#FFBA1A]' /> ,
55- GROUP_DELETE : < Icon id = 'x-2' className = 'size-6 text-gray-500' /> ,
56- GROUP_JOIN : < Icon id = 'symbol' className = 'text-mint-500 size-6' /> ,
57- EXIT : < Icon id = 'x-2' className = 'size-6 text-gray-500' /> ,
60+ follow : < Icon id = 'heart' className = 'text-mint-500 size-6' /> ,
61+ 'group-join' : < Icon id = 'symbol' className = 'text-mint-500 size-6' /> ,
62+ 'group-leave' : < Icon id = 'x-2' className = 'size-6 text-gray-500' /> ,
63+ 'group-create' : < Icon id = 'map-pin-2' className = 'size-6 text-[#FFBA1A]' /> ,
64+ 'group-delete' : < Icon id = 'x-2' className = 'size-6 text-gray-500' /> ,
65+ 'group-join-request' : < Icon id = 'send' className = 'text-mint-500 size-6' /> ,
66+ 'group-join-approved' : < Icon id = 'congratulate' className = 'size-6' /> ,
67+ 'group-join-rejected' : < Icon id = 'kick' className = 'size-6' /> ,
68+ 'group-join-kicked' : < Icon id = 'kick' className = 'size-6' /> ,
5869} ;
5970
6071const getTitle = ( data : NotificationItem ) => {
6172 switch ( data . type ) {
62- case 'FOLLOW ' :
73+ case 'follow ' :
6374 return `새 팔로워` ;
64- case 'GROUP_CREATE' :
65- return `모임 생성` ;
66- case 'GROUP_DELETE' :
67- return `모임 취소` ;
68- case 'GROUP_JOIN' :
75+ case 'group-join' :
6976 return `모임 현황` ;
70- case 'EXIT ' :
77+ case 'group-leave ' :
7178 return `모임 현황` ;
79+ case 'group-create' :
80+ return `모임 생성` ;
81+ case 'group-delete' :
82+ return `모임 취소` ;
83+ case 'group-join-request' :
84+ return `모임 참여 신청` ;
85+ case 'group-join-approved' :
86+ return `모임 신청 승인` ;
87+ case 'group-join-rejected' :
88+ return `모임 신청 거절` ;
89+ case 'group-join-kicked' :
90+ return `모임 강퇴` ;
7291 }
7392} ;
7493
7594const getDescription = ( data : NotificationItem ) => {
76- // switch (data.type) {
77- // case 'FOLLOW':
78- // return `${data.actorNickname} 님이 팔로우 했습니다.`;
79- // case 'GROUP_CREATE':
80- // return `${data.actorNickname} 님이 "${data.actorNickname}" 모임을 생성했습니다.`;
81- // case 'CANCLE':
82- // return `${data.actorNickname} 님이 "${data.actorNickname}" 모임을 취소했습니다.`;
83- // case 'ENTER':
84- // return `${data.actorNickname} 님이 "${data.actorNickname}" 모임에 참가했습니다.`;
85- // case 'EXIT':
86- // return `${data.actorNickname} 님이 "${data.actorNickname}" 모임을 떠났습니다.`;
87- // }
88- return data . message ;
95+ // user type 알림
96+ switch ( data . type ) {
97+ case 'follow' :
98+ return `${ data . user . nickname } 님이 팔로우했어요.` ;
99+ }
100+
101+ // group type 알림
102+ // 알림 필드 type 변경 전 데이터는 group 필드가 null로 조회되므로 fallback 처리
103+ if ( ! data . group ) return data . message ;
104+
105+ // group 필드가 null이 아닐 경우
106+ switch ( data . type ) {
107+ case 'group-join' :
108+ return `${ data . user . nickname } 님이 "${ data . group . title } " 모임에 참여했어요.` ;
109+ case 'group-leave' :
110+ return `${ data . user . nickname } 님이 "${ data . group . title } " 모임을 탈퇴했어요.` ;
111+ case 'group-create' :
112+ return `${ data . user . nickname } 님이 "${ data . group . title } " 모임을 생성했어요.` ;
113+ case 'group-delete' :
114+ return `${ data . user . nickname } 님이 "${ data . group . title } " 모임을 취소했어요.` ;
115+ case 'group-join-request' :
116+ return `${ data . user . nickname } 님이 "${ data . group . title } " 모임에 참여를 요청했어요.` ;
117+ case 'group-join-approved' :
118+ return `"${ data . group . title } " 모임 참여 신청이 승인됐어요.` ;
119+ case 'group-join-rejected' :
120+ return `"${ data . group . title } " 모임 참여 신청이 거절됐어요.` ;
121+ case 'group-join-kicked' :
122+ return `"${ data . group . title } " 모임에서 퇴장됐어요.` ;
123+ }
89124} ;
90125
91126const getTimeAgo = ( data : NotificationItem ) => {
92127 const { createdAt } = data ;
93128 return formatTimeAgo ( createdAt ) ;
94129} ;
130+
131+ const getRedirectUrl = ( data : NotificationItem ) => {
132+ // user type 알림
133+ switch ( data . type ) {
134+ case 'follow' :
135+ return `/profile/${ data . user . id } ` ;
136+ }
137+
138+ // 알림 필드 type 변경 전 데이터는 group 필드가 null로 조회되므로 fallback 처리
139+ if ( ! data . group ) return null ;
140+
141+ switch ( data . type ) {
142+ case 'group-join-request' :
143+ return `/pending/${ data . group . id } ` ;
144+ default :
145+ return `/group/${ data . group . id } ` ;
146+ }
147+ } ;
0 commit comments