[OMT] 빠른예매 페이지

2023.12.15(금)


이번에 예매 페이지를 개발하면서 빠른예매와 직접예매로 두 부분을 나눠보았다.

이렇게 두 부분으로 나눈 이유는 사실 기존에 우리가 예매하는 CGV,메가박스,롯데시네마에도 이렇게 빠른 예매라는 기능이 있지만 말만 빠른 예매지 유저가 직접적으로 예매하는 방식과 다르지 않았다.

그래서 선택지를 두 가지로 나누어보았다.

내가 원한 기능

빠른예매
  1. 영화선택 페이지 이후 + 인원 수 선택
  2. 위치 기반 서비스를 이용하여 현재 내 위치에서 가장 가까운 영화관 나열
  3. 현재 시각에서 가장 가까운 시간( 최소 1시간 이후 ) , 가장 뒤쪽 가장자리 좌석 탐색 [ 자동 ]
  4. 결제
직접예매
  1. 영화관 선택하기 [ CGV,메가박스,롯데시네마 ]
  2. 영화 선택하기
  3. 영화관 별 지역 선택하기
  4. 시간 , 인원수 선택하기
  5. 좌석 선택하기
  6. 결제

이렇게 두 가지로 비교해 보았을 때 빠른 예매에서 유저가 선택해야 하는 것은 영화와, 인원수, 그리고 현재 내 위치 근처의 영화관 이렇게 3개만 선택하면 된다.

영화 시간과 좌석을 직접 선택할 수 없다는 단점이 있는 것 아닐까 라는 생각을 했지만 말 그대로 빠른 예매에 집중했다. 유저가 직접 선택하는 요소는 줄이며 가장 빠른 시간을 탐색하고 보통의 영화인들이 좋아하는 뒤쪽 가장자리를 자동으로 탐색해서 지정해주는 방식이 시간적인 측면에서는 굉장히 이점이 많다고 생각했다. 이를 원치 않는 유저일 경우 직접예매를 통해 예매를 하면 되기 때문에 그에 대비한 선택지도 마련해놓았다고 생각해 이 방식을 고안해보았다.

현재 완료되어 배포된 화면

영화 선택 파트는 직접 예매 페이지와 동일하기 때문에 생략하고 UI적인 부분은 좀 더 세련되게 수정할 계획이다.

[ 영화 선택 페이지에서 예매하기 버튼을 눌렀을 때 ]

스크린샷 2024-01-01 22 48 15

[ 위치 기반 서비스를 이용한 영화관 선택하기 ]

스크린샷 2024-01-01 22 49 29

[ 현재 시각에서 가장 가까운 시간( 최소 1시간 이후 ) , 가장 뒤쪽 가장자리 좌석 탐색 [ 자동 ] ]

스크린샷 2024-01-01 22 50 11

이렇게 로딩이 완료되면 결제 페이지로 이동한다.

주요 내용

사실 위 내용에서 특별하게 사용된 코드는 없다. 지도 API를 사용한 내용은 별도로 포스팅 할 예정이기 때문에 어떤식으로 시간 선택과 가장자리 탐색을 진행했는지만 code를 남겨보려고 한다.

실제 상영되는 영화관의 시간, 좌석을 직접 알 수 있다면 정말 좋겠지만 내가 착안할 수 있던 방식은 크롤링이라는 방식이였고 이 방법이 올바른 루트로 사용 가능한 방법인지는 잘 몰라서 시도해보진 않았다.

그래서 현재 시각을 기준으로 한 랜덤한 시간을 배치했고 ( 최소 1시간 이상 30분 혹은 00분으로 마무리 되도록 ) 이전에 만들었던 좌석 배치도를 기준으로 가장자리를 우선으로 한 랜덤한 좌석을 ( 3명이라면 3자리를 붙여서 ) 배치했다.

Code

loding.tsx
// 랜덤한 좌석 배치
const generateConsecutiveSeats = (numberOfSeats: number) => {
    const seatCategories = ['E', 'F', 'G', 'H'];
    const seatNumbers = ['3', '4', '5', '6', '7', '8', '9', '10', '11'];
    const selectedSeats: string[] = [];

    for (let i = 0; i < numberOfSeats; i++) {
      const randomCategoryIndex = Math.floor(
        Math.random() * seatCategories.length
      );
      const randomCategory = seatCategories[randomCategoryIndex];

      const randomSeatNumberIndex = Math.floor(
        Math.random() * seatNumbers.length
      );
      const randomSeatNumber = seatNumbers[randomSeatNumberIndex];

      const seat = `${randomCategory}${randomSeatNumber}`;
      selectedSeats.push(seat);
    }

    return selectedSeats.join(',');
  };

랜덤한 좌석 배치는 위와 같이 진행했다.

아래 코드는 로딩 Txt와 로딩되는 시간 및 랜덤 시간 설정 방식이다.

  const timeoutId = setTimeout(() => {
      setLoadingText('후방 가장자리를 탐색중입니다.');

      // 오늘 날짜 yyyy-mm-dd 변환
      const currentDate = new Date();
      const formattedDate = `${currentDate.getFullYear()}-${(
        currentDate.getMonth() + 1
      )
        .toString()
        .padStart(2, '0')}-${currentDate
        .getDate()
        .toString()
        .padStart(2, '0')}`;
      localStorage.setItem('예매날짜', formattedDate);

      // 현재시각에서 1시간 + 하기 
      const closestTime = new Date(currentDate.getTime() + 60 * 60 * 1000);
      closestTime.setMinutes(30 * Math.ceil(closestTime.getMinutes() / 30)); // Round to the nearest 30 minutes

      // localSotrage에 예매정보 저장
      const formattedTime = `${closestTime
        .getHours()
        .toString()
        .padStart(2, '0')}:${closestTime
        .getMinutes()
        .toString()
        .padStart(2, '0')}`;
      localStorage.setItem('예매정보', JSON.stringify({ time: formattedTime }));

      // 인원 수에 따라 임의 좌석 선택 생성
      const numberOfAttendees = parseInt(
        localStorage.getItem('인원수') || '0',
        10
      );
      const selectedSeats = generateConsecutiveSeats(numberOfAttendees);
      localStorage.setItem('선택좌석', selectedSeats);

      // 5초 후에 티켓팅/결제 페이지로 리디렉션
      setTimeout(() => {
        router.push('/ticketing/pay');
      }, 5000);
    }, 5000);

    return () => {
      
      document.removeEventListener('mousedown', handler);
      document.body.style.overflow = 'unset'; // Do not scroll when creating a modal
      // document.removeEventListener('touchstart', handler); // Mobile response

      // 구성 요소가 마운트 해제되거나 효과가 다시 실행될 때의 시간 초과를 지우기
      clearTimeout(timeoutId);
    };
  }, [router]);