Skip to content

Dropdown

Jay edited this page May 10, 2025 · 4 revisions

Alert: 알림 목록을 드롭다운 형태로 보여주는 컴포넌트입니다.

AlertCard: 개별 알림 정보를 렌더링하는 카드 컴포넌트입니다.

FilterDropdownContent: 상세 조건(지역, 날짜, 시급)을 입력할 수 있는 드롭다운 콘텐츠입니다.

useAlarmStore: 알림 목록과 읽음 상태를 관리하는 전역 상태입니다.

useFilterStore: 상세 필터 조건을 관리하는 전역 상태입니다.


알림 드롭다운

구성 파일

  • Alert.tsx: 드롭다운 전체 레이아웃 및 동작
  • AlertCard.tsx: 개별 알림 렌더링

Alert 사용 방식 예시 코드

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() 호출 및 라우팅

AlertCard 사용 방식 예시 코드

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) 실행 + 해당 링크로 이동

알림 전역 상태 (useAlarmStore.ts)

Zustand로 구성된 알림 전역 상태는 다음을 포함합니다:

const useAlarmStore = create<AlarmState>()((set, get) => ({
  alerts: [],
  unreadCount: 0,
  fetchAlarms: async () => { ... },
  markAllAsRead: async () => { ... },
  markAsRead: async (id: string) => { ... },
}))

주요 메서드

  • fetchAlarms(): 알림 목록 호출
  • markAllAsRead(): 모든 알림 읽음 처리
  • markAsRead(id): 개별 알림 읽음 처리
  • alerts: 알림 리스트 상태
  • unreadCount: 안 읽은 알림 개수

알림 드롭다운 UI 예시

스크린샷 2025-05-10 22 46 36


상세 필터 드롭다운

구성 파일

  • 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() 호출

필터 전역 상태 (useFilterStore.ts)

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 함수: 외부에서 호출 가능


상세 필터 UI 예시

스크린샷 2025-05-10 22 47 16

📁 Components

Clone this wiki locally