패스트캠퍼스 데브캠프

파이널 프로젝트 - 회원가입(2) 약관 모달 구현

vitamin3000 2025. 4. 3. 22:13

이번 포스트에서는 저번 포스트에 이어서 회원가입 약관 컴포넌트에 관련된 내용이다.

 

약관 동의 모달 컴포넌트

아래와 같이, 각 항목마다 관련 내용을 출력하는 모달을 구현하였다.

 

 

우선 전체 동의에 대한 코드이다.

 

type에 대한 선언은 리터럴 타입으로 정의해 미리 정의된 값만을 사용하도록 하였다.

 

type ModalType = 'privacy' | 'terms' | 'marketing' | 'youtube';

 

우리는 각 항목별에 대한 boolean값을 아래와 같이 정의했었다.

  const [agreements, setAgreements] = useState(
    savedAgreements || {
      privacy: false,
      terms: false,
      marketing: false,
      youtube: false,
    }
  );

 

Javascript에서는 Object 관련 함수를 제공하는데,

  function isAllChecked() {
    return Object.values(agreements).every((value) => value === true);
  }

every를 사용하여 모든 값을 true로 설정하여 한번에 모든 항목이 체크되도록 하였다.

 

각 항목별 클릭시

각 항목 별로 클릭시 false이면 true로, true면 false로 설정해야한다.

function handleAgreementItemClick(type: ModalType) {
  if (type === null) return;
  
  if (agreements[type]) {
    const newAgreements = {
      ...agreements,
      [type]: !agreements[type],
    };
    setAgreements(newAgreements);
    onAgreementsChange(newAgreements);
    setIsChecked(false);
  } else {
    openModal(type);
  }
}

 

!연산자를 사용하여 이를 구현하였다.

 

약관 모달 세부 내용 출력

각 항목별로 title, mesage, type을 나누어 관련 정보를 출력하도록 하였다.

  const getModalContent = (type: ModalType) => {
    switch (type) {
      case 'privacy':
        return {
          title: '[필수] 개인정보처리방침',
          message: '개인정보처리방침에 관한 내용입니다. 동의하시겠습니까?',
          type: 'normal',
        };
      case 'terms':
        return {
          title: '[필수] 이용약관',
          message: '이용약관에 관한 내용입니다. 동의하시겠습니까?',
          type: 'normal',
        };
      case 'marketing':
        return {
          title: '[선택] 마케팅 이용 동의',
          message:
            '마케팅 이용에 동의하시면 다양한 이벤트 정보를 받아보실 수 있습니다. 동의하시겠습니까?',
          type: 'normal',
        };
      case 'youtube':
        return {
          title: '[선택] 유튜브 계정 연동',
          message:
            '유튜브 계정 연동에 동의하시면 서비스를 더 풍부하게 이용하실 수 있습니다.',
          type: 'youtube',
        };

 

 

유튜브 약관동의 모달

 

다른 약관 동의 항목과 달리, 유튜브 약관 동의 모달은 내용이 많고, api 호출 관련 내용까지 있어서 다른 컴포넌트로 구분하였다.

 

checkbox로 된 점을 제외하면 위의 코드와 같이 객체로 각 항목에 대한 boolean값을 설정하여 저장했다.

따라서 작성한 코드를 다시 작성하지는 않겠다.

 

UX 개선

출력된 모달을 닫으려면 X 아이콘을 누를 때도 있지만, esc를 눌러 종료하는 경우가 대부분일 것이다.

이 내용을 구현해보자

 

모달이 출력되어 있을 때 Esc를 의미하는 Escape가 눌리면, Modal을 null로 설정하여 닫히도록 하였다.

showModal을 의존성 배열로 추가하여 변화되는 값을 리액트가 추적하도록 하였다.

  useEffect(() => {
    const handleEscKey = (event: KeyboardEvent) => {
      if (event.key === 'Escape' && showModal) {
        setModalQueue([]);
        setShowModal(null);
      }
    };
    window.addEventListener('keydown', handleEscKey);

    return () => {
      window.removeEventListener('keydown', handleEscKey);
    };
  }, [showModal]);