-
Notifications
You must be signed in to change notification settings - Fork 4
Dropdown
Jay edited this page May 10, 2025
·
4 revisions
-
Alert.tsx: 드롭다운 전체 레이아웃 및 동작 -
AlertCard.tsx: 개별 알림 렌더링
const wrapperRef = useRef(null);
useOutsideClick(wrapperRef, () => {
setIsAlertOpen(false);
});
useEffect(() => {
if (isAlertOpen) {
markAllAsRead(); // 전체 알림 읽음 처리
}
}, [isAlertOpen]);
{isAlertOpen && (
<div ref={wrapperRef} className="absolute top-[3.6rem] right-0 z-[9999]">
<Alert onClose={() => setIsAlertOpen(false)} />
</div>
)}-
useOutsideClick: 드롭다운 외부 클릭 시setIsAlertOpen(false)호출 -
useEffect: 드롭다운이 열릴 때markAllAsRead()실행하여 전체 알림 읽음 처리 -
Alert내부에서alerts순회하여AlertCard목록 렌더링 - 알림 없을 경우 안내 메시지 출력
- 개별 알림 클릭 시
onClose()호출 및 라우팅
const AlertCard = ({ alarm, onClose }: { alarm: Alarm; onClose: () => void }) => {
const navigate = useNavigate();
const { markAsRead } = useAlarmStore();
const handleClick = () => {
if (!alarm.read) {
markAsRead(alarm.id); // 읽음 처리
}
if (alarm.link) {
navigate(alarm.link); // 링크 이동
}
onClose(); // 드롭다운 닫기
};
const isInfo = alarm.status === "@";
const isWarning = alarm.status === "!";
return (
<li
onClick={handleClick}
className={`flex items-center px-4 py-2 rounded-md cursor-pointer
${alarm.read ? "bg-white" : "bg-gray-100"}
hover:bg-gray-200`}
>
<div
className={`w-2 h-2 rounded-full mr-2
${isInfo ? "bg-blue-400" : ""}
${isWarning ? "bg-red-400" : ""}`}
/>
<span className={`text-sm ${isInfo ? "text-blue-400" : ""} ${isWarning ? "text-red-400" : ""}`}>
{alarm.message}
</span>
</li>
);
};-
alarm.read상태에 따라 배경 색상 분기 -
alarm.status에 따라 스타일 (@→ 파랑,!→ 빨강 등) - 클릭 시
markAsRead(alarm.id)실행 + 해당 링크로 이동
Zustand로 구성된 알림 전역 상태는 다음을 포함합니다:
const useAlarmStore = create<AlarmState>()((set, get) => ({
alerts: [],
unreadCount: 0,
fetchAlarms: async () => { ... },
markAllAsRead: async () => { ... },
markAsRead: async (id: string) => { ... },
}))-
fetchAlarms(): 알림 목록 호출 -
markAllAsRead(): 모든 알림 읽음 처리 -
markAsRead(id): 개별 알림 읽음 처리 -
alerts: 알림 리스트 상태 -
unreadCount: 안 읽은 알림 개수

-
FilterDropdownContent.tsx: 상세 필터 UI 렌더링
{isFilterOpen && (
<div className="absolute right-0 top-[3.6rem] z-[9999]">
<FilterDropdownContent
refetch={refetch}
onClose={() => setIsFilterOpen(false)}
onClickApplyButton={handleApply}
/>
</div>
)}- 버튼 클릭 시 열림
- 지역, 시작일, 시급 입력 기능 포함
- "초기화" 버튼: 상태 초기화 후 refetch 미수행
- "적용하기" 버튼: 상태 저장 +
refetch()호출
Zustand로 구성된 필터 전역 상태는 다음을 포함합니다:
const useFilterStore = create<FilterState>()((set) => ({
selectedAreas: [],
startDate: null,
minPay: '',
setSelectedAreas: (areas) => set({ selectedAreas: areas }),
setStartDate: (date) => set({ startDate: date }),
setMinPay: (pay) => set({ minPay: pay }),
resetFilters: () => set({ selectedAreas: [], startDate: null, minPay: '' }),
}))-
selectedAreas: 선택된 지역 배열 -
startDate: 필터 시작일 (Date | null) -
minPay: 최소 시급 (문자열) -
resetFilters(): 필터 초기화 - 각 setter 함수: 외부에서 호출 가능
