diff --git a/src/components/common/notification-modal/NotificationCard.tsx b/src/components/common/notification-modal/NotificationCard.tsx index 1b92f235..51a8cc90 100644 --- a/src/components/common/notification-modal/NotificationCard.tsx +++ b/src/components/common/notification-modal/NotificationCard.tsx @@ -1,16 +1,17 @@ -import { useNavigate } from 'react-router-dom'; -import { putAlerts } from '@/api/alertApi'; +import { Link } from 'react-router-dom'; import calculateTimeDifference from '@/utils/calculateTimeDifference'; import formatWorkTime from '@/utils/formatWorkTime'; interface NotificationCardProps { alertId: string; // 알림 id + shopId: string; // 가게 id noticeId: string; // 공고 id status: 'accepted' | 'rejected'; // 공고 지원 상태 restaurantName: string; // 음식점 이름 startsAt: string; // 공고 시작 시간 (ISO 8601 문자열) workhour: number; // 근무 시간 (시간 단위) createdAt: string; // 알림 생성 시간 (ISO 8601 문자열) + onMarkAsRead: (alertId: string) => void; } /* @@ -21,39 +22,27 @@ interface NotificationCardProps { export default function NotificationCard({ alertId, + shopId, noticeId, status, restaurantName, startsAt, workhour, createdAt, + onMarkAsRead, }: NotificationCardProps) { const formattedTime = formatWorkTime({ startsAt, workhour, }); - const navigate = useNavigate(); + const formattedCreatedAt = calculateTimeDifference(createdAt); const formattedStatus = status === 'accepted' ? '승인' : '거절'; const formattedStatusClass = status === 'accepted' ? 'text-blue-20' : 'text-red-20'; - const handleClick = () => { - const userId = localStorage.getItem('userId'); - - if (!userId) { - console.error('userId를 찾을 수 없습니다.'); - return; - } - try { - putAlerts(userId, alertId); // 알림 읽음 처리 - navigate(`/${noticeId}`); - } catch (error) { - console.error(error); - } - }; return ( -
+ onMarkAsRead(alertId)}>
{status === 'accepted' ? (
@@ -67,6 +56,6 @@ export default function NotificationCard({

{formattedCreatedAt}

-
+ ); } diff --git a/src/components/common/notification-modal/NotificationModal.tsx b/src/components/common/notification-modal/NotificationModal.tsx index 67e2e546..4633d344 100644 --- a/src/components/common/notification-modal/NotificationModal.tsx +++ b/src/components/common/notification-modal/NotificationModal.tsx @@ -4,8 +4,8 @@ import type { AlertListItem } from '@/api/alertApi'; interface NotificationModalProps { data?: AlertListItem[]; // 알림 데이터 배열 - count?: number; // 알림 개수 onClose: () => void; // x 버튼을 누를때 실행할 함수 + onMarkAsRead: (alertId: string) => void; } /* @@ -17,29 +17,32 @@ interface NotificationModalProps { export default function NotificationModal({ data = [], - count = 0, onClose, + onMarkAsRead, }: NotificationModalProps) { + const unreadData = data.filter((alertItem) => alertItem.item.read === false); return (
-

알림 {count}개

+

알림 {unreadData.length}개

- {data.length > 0 && - data.map((data) => ( + {unreadData.length > 0 && + unreadData.map((alertItem) => ( ))}
diff --git a/src/components/layout/Navbar.tsx b/src/components/layout/Navbar.tsx index 801b2d9d..106d1c43 100644 --- a/src/components/layout/Navbar.tsx +++ b/src/components/layout/Navbar.tsx @@ -8,11 +8,16 @@ import alarmActive from '@/assets/icons/alarm-active.svg'; import alarmInactive from '@/assets/icons/alarm-inactive.svg'; export default function Navbar() { - const { isLoggedIn, role, alarms, logout } = useContext(AuthContext); + const { isLoggedIn, role, alarms, logout, markAlertAsRead } = + useContext(AuthContext); const [isShowModal, setIsShowModal] = useState(false); const modalRef = useRef(null); const buttonRef = useRef(null); + const unreadAlarmCount = alarms.items.filter( + (alert) => !alert.item.read, + ).length; + // 바깥 클릭 시 모달 닫기 useEffect(() => { function handleClickOutside(event: MouseEvent): void { @@ -42,6 +47,11 @@ export default function Navbar() { return () => document.removeEventListener('keydown', handleKeyDown); }, []); + const handleNotificationClick = (alertId: string) => { + markAlertAsRead(alertId); // AuthContext의 함수를 호출해 알림을 읽음 처리 + setIsShowModal(false); // Navbar의 state를 변경해 모달을 닫음 + }; + return (
)} diff --git a/src/context/AuthContext.tsx b/src/context/AuthContext.tsx index f1599482..a0d46a6b 100644 --- a/src/context/AuthContext.tsx +++ b/src/context/AuthContext.tsx @@ -1,5 +1,5 @@ import { createContext, useState, useEffect, type ReactNode } from 'react'; -import { getAlerts, type AlertViewResponse } from '@/api/alertApi'; +import { getAlerts, putAlerts, type AlertViewResponse } from '@/api/alertApi'; type UserRole = 'employer' | 'employee' | null; interface AuthContextType { @@ -8,6 +8,7 @@ interface AuthContextType { alarms: AlertViewResponse; // 알림 정보 login: (token: string, role: UserRole, userId: string) => void; // 로그인 함수 logout: () => void; // 로그아웃 함수 + markAlertAsRead: (alertId: string) => void; } const defaultAuthContext: AuthContextType = { @@ -23,6 +24,7 @@ const defaultAuthContext: AuthContextType = { }, login: () => {}, logout: () => {}, + markAlertAsRead: () => {}, }; export const AuthContext = createContext(defaultAuthContext); @@ -35,12 +37,24 @@ export function AuthProvider({ children }: { children: ReactNode }) { ); useEffect(() => { - const token = localStorage.getItem('accessToken'); - const role = localStorage.getItem('userRole') as UserRole; - if (token && role) { - setIsLoggedIn(true); - setRole(role); - } + const fetchAuth = async () => { + const token = localStorage.getItem('accessToken'); + const userRole = localStorage.getItem('userRole') as UserRole; + const userId = localStorage.getItem('userId'); + + if (token && userRole && userId) { + setIsLoggedIn(true); + setRole(userRole); + try { + const alertRes = await getAlerts(userId); + setAlarms(alertRes); + } catch (error) { + console.error('앱 로딩 중 알림 가져오기 실패:', error); + } + } + }; + + fetchAuth(); }, []); const login = async (token: string, role: UserRole, userId: string) => { @@ -66,8 +80,29 @@ export function AuthProvider({ children }: { children: ReactNode }) { setAlarms(defaultAuthContext.alarms); }; + const markAlertAsRead = async (alertId: string) => { + const userId = localStorage.getItem('userId'); + if (!userId) { + console.error('읽음 처리 실패: userId를 찾을 수 없습니다.'); + return; + } + + setAlarms((prevAlarms) => ({ + ...prevAlarms, + items: prevAlarms.items.filter((alert) => alert.item.id !== alertId), + })); + + try { + await putAlerts(userId, alertId); + } catch (error) { + console.error('API - 알림 읽음 처리 실패:', error); + } + }; + return ( - + {children} );