본문 바로가기

2024-08-16 미인증 사용자에게는 블러 처리된 오버레이 모달 렌더링하기

codeConnection 2024. 8. 16.

스크린샷

 

구현의도

복잡할 것 없는 간단한 기능이지만, 프로젝트를 기획하면서 팀에 conditional route를 제안했었다.

 

제안했던 이유는 크게 아래와 같다.

 

1) 보다 안전한 사용을 위한 회원가입을 유도 -> 회원 정보를 입력하기 위해선 가입이 필요

2) 회원 정보를 입력한 사용자의 개인정보를 최소한으로 보호

 

우리 서비스는 마치 소개팅 앱처럼 사용자들이 입력한 정보를 토대로 안전한 매칭을 해주는 서비스이다.

이에 따라 사용자가 직접 사용자의 정보를 보고 판단할 수 있도록 여러가지 소셜 기능을 기획했다.

 

버디즈 지수는 사용자의 사이트 이용 정도를 알고리즘에 의해 평가한다.

사용자는 우리의 알고리즘을 신뢰할 수 있다고 판단하면 이 지수를 보고 자신과 매칭되는 사용자의 안전성을 평가할 수 있다.

 

팔로잉, 팔로워는 단순 재미요소를 넘어 이 사용자가 어떤 유형의 사용자들과 관계를 맺고 있는지 판단할 수 있다.

예를 들어 남성 사용자인데 팔로잉 목록에 온통 여성 뿐이라면 여성의 입장에서는 다소 경계할 수도 있을 것 같다.

또는 팔로워는 별로 없는데 팔로잉 사용자만 비대칭적으로 많다면 스팸 계정이거나 봇으로 의심해볼 수도 있다.

또는 팔로잉은 별로 없는데 팔로워가 비대칭적으로 많다면, 대게 인플루언서들이 이런 형태를 띄기도 하지만, 이 역시 정상적인 사용 패턴은 아님을 알 수 있다.

 

그리고 사용자가 직접 작성한 글과, 참여만 한 매칭이 어떤 것들이 있는지 서비스 이용 기록을 보면서도 판단할 수 있다.

 

추가적으로 더 안전한 사용을 위해 사용자 신고 기능과, 사용자 평가 후기 등을 사용자들이 직접 코멘트 형태로 달 수 있는 기능도 기획하였다.

 

그러나 어디까지나 사용자의 안전을 서비스가 100% 보장할 순 없다.

엄격하게 가입 절차부터 신원을 확인하는 결혼정보 서비스가 아니라 소셜 네트워크 서비스이고

따라서 '누구나' 이용 가능한 서비스이기 때문이다.

 

이러한 서비스에서 여러가지 안전 장치를 마련하는 것은 사용자로 하여금 안전하다는 인식을 갖게 할 수 있고,

사이트 이용률의 증가를 제고할 수 있다.

 

그래서, 우리 서비스는 사용자에게 많은 정보를 받는다.

실명인증 API 등을 사용할 수 없어 진위 여부를 모두 판단할 순 없지만, 실명, 생년월일, 취향 등의 관심사 정보들을 많이 받고 있다.

 

계정 비공개 기능을 만들면 노출시키지 않을 수도 있겠지만,

우리 서비스가 인스타그램과 같은 완전한 소셜 네트워크 서비스가 아니라, 소셜 네트워크의 성격을 띄는 것 뿐이므로

우리 서비스 규모에서 사용자의 데이터를 비공개 처리하는 기능은 후순위 개발 과제이다.

 

그렇다면 최대한 많은 회원들이 추가 정보를 기입하도록 유도하는 것이 중요한데,

사이트 가입 단계에서부터 이러한 정보를 많이 받으면 회원가입부터 질려 버려서 이탈할 확률이 높다고 판단하여

사이트 온보딩 튜토리얼 과정에서 추가 정보를 자연스럽게 입력할 수 있도록 플로우를 설계하였다.

 

즉 사용자가 추가정보를 입력하는 것은 어디까지나 사용자의 자유라는 것이다.

하지만 추가 정보를 기입한 사용자와 기입하지 않은 사용자의 서비스 이용 권한을 동일하게 가져간다면 누구도 정보를 입력하고 싶지 않아할 것이다.

 

따라서 생각해낸 것이 조건부 렌더링 기능이고, 추가 정보를 기입하지 않은 회원에게까지 블러 처리하는 것은 과한 정책이라고 판단하여

회원가입을 유도해서 자연스럽게 온보딩에 참여할 수 있도록 유도하고자 함이 conditional route를 기획한 목적이다.

 

구현 환경

  • Next.js (react)
  • Supabase
  • Tailwind CSS

 

의사코드

  • 회원이 로그인 상태인지 아닌지 식별한다.
    • supabase의 경우에는 getUser() 메서드 등으로 현재 로그인 한 회원의 세션을 가져올 수 있다.
    • 또는 getSession 등 여러가지 방법이 있을 수 있다.
  • 로그인했다면 정상적으로 보여주고,
  • 로그인 하지 않았다면 블러로 가릴 컴포넌트의 최상단 div에서 전체를 블러처리한다.
  • 그리고 레이어의 최상위로 경고 문구와 버튼을 렌더링 해서 회원가입을 유도한다.

구현 과정

유저의 로그인 상태를 불러와 상태에 담거나 변수에 저장하는 로직은 이미 구현되었다고 가정한다.

 

최상단 div에 조건부 블러 처리 하기

<div className="relative flex flex-col items-center justify-center p-4 mt-4 xl:mt-8">
  <div className={`flex items-center ${!currentBuddy && 'blur-sm'}`}>
  // ... 이하 생략

 

currentBuddy는 현재 사용자의 로그인 세션 정보를 담은 상태이다.

이 상태가 있으면 tailwindCSS에서 blur-sm을 추가하라는 의미이다.

 

블러 위에 렌더링 할 문구와 버튼 컴포넌트 모듈 만들기

'use client';

import { useRouter } from 'next/navigation';

function BlurredBuddyProfile() {
    const router = useRouter();
    const moveToLogin = () => {
        router.push('/login');
    };
    return (
        <div className="absolute inset-0 flex flex-col items-center justify-center">
            <p className="text-lg font-semibold text-white mb-4 bg-black bg-opacity-50 rounded-lg p-2">
                로그인을 해야 버디 정보를 볼 수 있습니다.
            </p>
            <button
                className="text-white bg-main-color px-4 py-2 rounded-full"
                onClick={moveToLogin}
            >
                로그인 하러 가기
            </button>
        </div>
    );
}

export default BlurredBuddyProfile;

 

해당 페이지 컴포넌트에서 바로 작성해도 되지만, 유지보수를 편하게 하기 위해 모듈로 분리하는 것을 선호한다.

별도의 컴포넌트 파일을 만들었다.

 

이 컴포넌트가 다른 컴포넌트와 병합되었을 때 최상단으로 위치할 수 있는 이유는

absolute와 inset-0 클래스를 조합해서 사용했기 때문이다.

absoulte라는 속성은 이 요소가 포함된 부모 요소를 기준으로 위치를 잡겠다는 의미이고,

inset-0은 상하좌우 모든 방향을 0으로 설정하여 부모 요소의 전체를 차지하겠다는 의미이다.

 

그냥 단순하게 z-index를 위로 띄워서 하면 되는 것 아닌가? 생각할 수 있지만

absolute inset-0을 설정하면 부모 요소의 크기를 기준으로 이 컴포넌트의 크기를 만들 수 있기 때문에

부모 요소를 완전히 덮는 오버레이 모달을 만들기에 적합한 패턴이다.

 

본인의 경우에는 사용자 프로필 컴포넌트가 여기서만 쓰이는 게 아니라 다른 곳에서도 재사용하고 있는 컴포넌트이기 때문에

부모 컴포넌트의 사이즈가 얼마가 될 지 알 수가 없다.

z-50 등의 tailwind 속성을 주어서 만들게 되면 이러한 use cases에 대응하기가 어렵다.

더불어 반응형도 마찬가지다.

사이트가 반응형으로 제작된 경우에도 부모 컴포넌트의 사이즈가 변화함에 따라 같이 변하기 때문에 매우 편리하다.

 

z-50만 단독 사용하는 것은 말 그대로 화면에서 붕- 띄우는 느낌인 것이고, 위 조합은 덮는 느낌인 것이다.

 

그러나 부모 컴포넌트에서 position 속성이 제대로 설정되지 않았으면

의도한 화면이 안 나올 수 있는데, 이럴 때는 부모 요소의 position 관련 속성을 점검해보거나,

z-index를 추가 부여 해서 수정해보아야 한다.

 

페이지 컴포넌트에 조건부 렌더링 구문 추가

// ... 생략

  </div>
  {!currentBuddy && <BlurredBuddyProfile />}
</div>

 

아주 쉽다.

JSX에서 && 논리 연산자는 if문과 같다.

currentBuddy, 즉 로그인 세션이 ! 없으면 조금 전에 만들었던 그 컴포넌트를 띄우라는 의미이다.

 

끝.

댓글