Skip to content

[Refactor] Alert 서비스 추상화로 UI 피드백 로직 분리 #96

Description

@l2juhan

📋 개요

알림/모달 표시 로직을 추상화하여 테스트 용이성일관된 UX를 제공하는 Alert 서비스 추상화를 제안합니다.

🔍 현재 문제점

1. 구체적인 라이브러리에 직접 의존

// useEmployerRemittanceData.ts
import Swal from "sweetalert2";

const handleRemittance = useCallback(() => {
  Swal.fire({
    title: "알림",
    text: "송금 기능은 웹에서 제공하지 않습니다...",
    icon: "info",
    confirmButtonColor: "#769fcd",
  });
}, []);

2. 발생하는 문제들

  • 테스트 어려움: Swal 모킹이 필요하고 DOM 조작까지 테스트해야 함
  • 라이브러리 교체 어려움: SweetAlert2 → 다른 라이브러리 전환 시 모든 파일 수정 필요
  • 일관성 문제: Swal, toast, alert() 등이 혼재되면 UX 일관성 저하
  • 스타일 분산: 버튼 색상, 텍스트 등이 각 호출 위치에 분산

✅ 제안하는 해결책

Alert 서비스 인터페이스 정의

// src/services/alert.service.ts
export interface AlertService {
  info(message: string, title?: string): void;
  error(message: string, title?: string): void;
  success(message: string, title?: string): void;
  confirm(message: string, title?: string): Promise<boolean>;
}

SweetAlert2 구현체

// src/services/impl/swalAlert.service.ts
export class SwalAlertService implements AlertService {
  private readonly defaultOptions = {
    confirmButtonColor: "#769fcd",
  };

  info(message: string, title = "알림") {
    Swal.fire({ 
      title, 
      text: message, 
      icon: "info",
      ...this.defaultOptions 
    });
  }
  
  error(message: string, title = "오류") {
    Swal.fire({ 
      title, 
      text: message, 
      icon: "error",
      ...this.defaultOptions 
    });
  }
  
  async confirm(message: string, title = "확인"): Promise<boolean> {
    const result = await Swal.fire({
      title,
      text: message,
      icon: "question",
      showCancelButton: true,
      ...this.defaultOptions
    });
    return result.isConfirmed;
  }
}

Toast 구현체 (대안)

// src/services/impl/toastAlert.service.ts
export class ToastAlertService implements AlertService {
  info(message: string) { toast.info(message); }
  error(message: string) { toast.error(message); }
  success(message: string) { toast.success(message); }
  async confirm(message: string): Promise<boolean> {
    // toast는 confirm이 없으므로 window.confirm 사용
    return window.confirm(message);
  }
}

훅에서 의존성 주입

export function useEmployerRemittanceData(
  alertService: AlertService = defaultAlertService
) {
  const handleRemittance = () => {
    alertService.info("송금 기능은 웹에서 제공하지 않습니다.");
  };
}

테스트 시 Mock 서비스 주입

const mockAlertService: AlertService = {
  info: vi.fn(),
  error: vi.fn(),
  confirm: vi.fn().mockResolvedValue(true),
};
// Swal 모킹 불필요

📁 영향 받는 파일

  • src/hooks/employer/useEmployerRemittanceData.ts (Swal 사용)
  • src/hooks/worker/*.ts (Swal 사용 시)
  • 기타 Swal 직접 사용하는 컴포넌트들

🎯 기대 효과

현재 적용 후
Swal 모킹 필요 Mock 서비스로 간단한 테스트
라이브러리 변경 시 전체 수정 구현체만 교체
스타일 분산 한 곳에서 일관된 스타일 관리
Swal, toast 혼재 통일된 인터페이스 사용

🏷️ 참고

  • 코드 리뷰 보고서의 "낮은 우선순위" 항목으로 분류됨
  • Repository 패턴과 함께 도입하면 전체 아키텍처의 테스트 용이성이 크게 향상됨
  • 현재 프로젝트에서는 Swalreact-toastify가 혼용되고 있어 통합의 필요성 있음

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions