Skip to content

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

@l2juhan

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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions