Skip to content

Commit c07268d

Browse files
committed
알림 게시물 추적기능
1 parent aaeac65 commit c07268d

2 files changed

Lines changed: 162 additions & 25 deletions

File tree

src/components/header/Header.css

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,11 +311,13 @@
311311
.notification-item {
312312
padding: 10px 15px;
313313
border-bottom: 1px solid #eee;
314-
cursor: pointer;
315314
transition: background-color 0.2s;
316315
font-size: 14px;
317316
line-height: 1.4;
318317
color: #333;
318+
display: flex;
319+
align-items: center;
320+
gap: 10px;
319321
font-weight: bold;
320322
}
321323

@@ -340,6 +342,38 @@
340342
.notification-message {
341343
flex-grow: 1;
342344
margin-right: 10px;
345+
background: none;
346+
border: none;
347+
text-align: left;
348+
color: inherit;
349+
font: inherit;
350+
cursor: pointer;
351+
padding: 0;
352+
}
353+
354+
.notification-read-btn {
355+
background: none;
356+
border: 1px solid #ccc;
357+
border-radius: 4px;
358+
padding: 4px 8px;
359+
font-size: 12px;
360+
cursor: pointer;
361+
color: #555;
362+
transition: background-color 0.2s, color 0.2s, border-color 0.2s;
363+
}
364+
365+
.notification-read-btn:hover {
366+
background-color: #6a0dad;
367+
color: #fff;
368+
border-color: #6a0dad;
369+
}
370+
371+
.notification-read-btn:disabled,
372+
.notification-read-btn:disabled:hover {
373+
cursor: not-allowed;
374+
background-color: #f0f0f0;
375+
color: #aaa;
376+
border-color: #ddd;
343377
}
344378

345379
.no-notifications {
@@ -408,6 +442,29 @@
408442
background-color: #4d3319;
409443
}
410444

445+
.dark-mode .notification-message {
446+
color: inherit;
447+
}
448+
449+
.dark-mode .notification-read-btn {
450+
border-color: #666;
451+
color: #ddd;
452+
background-color: transparent;
453+
}
454+
455+
.dark-mode .notification-read-btn:hover {
456+
background-color: #b88eff;
457+
color: #1e1e1e;
458+
border-color: #b88eff;
459+
}
460+
461+
.dark-mode .notification-read-btn:disabled,
462+
.dark-mode .notification-read-btn:disabled:hover {
463+
background-color: #333;
464+
color: #777;
465+
border-color: #555;
466+
}
467+
411468
.dark-mode .notification-footer {
412469
border-color: #3a3a3a;
413470
}

src/components/header/Header.jsx

Lines changed: 104 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,79 @@ const Header = ({ isDark, setIsDark, isLoggedIn, nickname, onLoginModalOpen }) =
7373
}
7474
};
7575

76-
const handleNotificationRead = async (id) => {
77-
try {
78-
const token = localStorage.getItem('token');
79-
await fetch(`${config.API_BASE_URL}/api/notifications/${id}/read`, {
80-
method: 'PUT',
81-
headers: {
82-
'Authorization': `Bearer ${token}`
76+
const resolveNotificationId = useCallback((notification) => {
77+
if (!notification) return null;
78+
return (
79+
notification.id ??
80+
notification.notificationId ??
81+
notification.notificationNo ??
82+
notification.notificationSeq ??
83+
null
84+
);
85+
}, []);
86+
87+
const handleNotificationRead = useCallback(
88+
async (id) => {
89+
if (!id) return false;
90+
try {
91+
const token = localStorage.getItem('token');
92+
if (!token) {
93+
console.error("Error marking notification as read: missing auth token");
94+
return false;
8395
}
84-
});
85-
fetchNotifications();
86-
} catch (error) {
87-
console.error("Error marking notification as read:", error);
88-
}
89-
};
96+
const response = await fetch(`${config.API_BASE_URL}/api/notifications/${id}/read`, {
97+
method: 'PUT',
98+
headers: {
99+
'Authorization': `Bearer ${token}`
100+
}
101+
});
102+
103+
if (!response.ok) {
104+
throw new Error(`Failed to mark notification as read: ${response.status}`);
105+
}
106+
107+
let didMark = false;
108+
setNotifications((prev) =>
109+
prev.map((item) => {
110+
const itemId = resolveNotificationId(item);
111+
if (itemId && itemId === id && !item.read) {
112+
didMark = true;
113+
return { ...item, read: true };
114+
}
115+
return item;
116+
})
117+
);
118+
119+
if (didMark) {
120+
setUnreadCount((prev) => Math.max(prev - 1, 0));
121+
}
122+
123+
return true;
124+
} catch (error) {
125+
console.error("Error marking notification as read:", error);
126+
return false;
127+
}
128+
},
129+
[resolveNotificationId]
130+
);
131+
132+
const handleNotificationNavigate = useCallback(
133+
async (notification) => {
134+
if (!notification) return;
135+
136+
const notificationId = resolveNotificationId(notification);
137+
await handleNotificationRead(notificationId);
138+
139+
if (notification.postId) {
140+
navigate(`/community/post/${notification.postId}`);
141+
}
142+
143+
setIsNotificationMenuOpen(false);
144+
setIsViewAll(false);
145+
setCurrentPage(1);
146+
},
147+
[handleNotificationRead, navigate, resolveNotificationId]
148+
);
90149

91150
const handleViewAll = () => {
92151
setIsViewAll(true);
@@ -162,17 +221,38 @@ const Header = ({ isDark, setIsDark, isLoggedIn, nickname, onLoginModalOpen }) =
162221
</button>
163222
)}
164223
{displayNotifications.length > 0 ? (
165-
displayNotifications.map(notification => (
166-
<div
167-
key={notification.id}
168-
className={`notification-item ${!notification.read ? 'unread' : 'read'}`}
169-
onClick={() => handleNotificationRead(notification.id)}
170-
>
171-
<span className="notification-message">
172-
{notification.message}
173-
</span>
174-
</div>
175-
))
224+
displayNotifications.map((notification, index) => {
225+
const notificationId = resolveNotificationId(notification);
226+
const key = notificationId ?? `notification-${index}`;
227+
const isUnread = !notification.read;
228+
const disableRead = !notificationId || !isUnread;
229+
230+
return (
231+
<div
232+
key={key}
233+
className={`notification-item ${isUnread ? 'unread' : 'read'}`}
234+
>
235+
<button
236+
type="button"
237+
className="notification-message"
238+
onClick={() => handleNotificationNavigate(notification)}
239+
>
240+
{notification.message}
241+
</button>
242+
<button
243+
type="button"
244+
className="notification-read-btn"
245+
disabled={disableRead}
246+
onClick={async (e) => {
247+
e.stopPropagation();
248+
await handleNotificationRead(notificationId);
249+
}}
250+
>
251+
읽음
252+
</button>
253+
</div>
254+
);
255+
})
176256
) : (
177257
<div className="no-notifications">알림이 없습니다.</div>
178258
)}

0 commit comments

Comments
 (0)