Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Design] 좌석표 구현 (좌석 선택 뷰) #59

Merged
merged 20 commits into from
Nov 25, 2024

Conversation

seueooo
Copy link
Collaborator

@seueooo seueooo commented Nov 25, 2024

🔥 Related Issues

💙 작업 내용

  • 좌석표 구현

✅ PR Point

좌석표 퍼블리싱 했습니다. 클릭시 변경되는 상태들은 이 pr 머지되면 새로 이슈 파서 생성하겠습니다! 일단은 가로 스크롤로 구현했고, 드래그와 미니맵 부분은 모든 기능이 제대로 완료되고 난 후에 진행하겠습니다!
그리고 정확히 피그마에 있는대로 간격을 설정했는데, 살짝 다르게 보여요..
좌석 시트 크기 더 키워서 피그마 비율을 임의로 맞추는게 더 나을지, 이대로 진행할지 의견 부탁드립니다!
아 그리고 커밋 기록 보면,, 제가 브랜치 파놓고 디벨롭에 머지된거 반영하려고 rebase를 하면서 진혁이 커밋이랑 합쳐졌습니다 참고하십쇼ㅜㅜ

😡 Trouble Shooting

1. SVG 컴포넌트에 텍스트 삽입하기

좌석시트 svg 위에 좌석 정보 텍스트를 보이도록 해야하는데, 좌석정보 리스트를 쭉 mapping하여 렌더링해야하는 부분이어서, svg 컴포넌트 파일에 props로 좌석정보 텍스트를 받게 하고, text 태그를 이용하여 글자를 컴포넌트 위에 그려지도록 했습니다. 또 text 태그의 x, y를 설정하여 글자의 위치를 지정해줄 수 있다는 사실을 알게 됐습니다.

interface SvgSeatsProps extends SVGProps<SVGSVGElement> {
  seat: string;
}

const SvgBtnSeatDefaultLarge = ({ seat, ...props }: SvgSeatsProps) => (
  <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 28 21" {...props}>
    <path fill="#1EAFFD" d="M0 8a8 8 0 0 1 8-8h12a8 8 0 0 1 8 8v10a3 3 0 0 1-3 3H0z" />
    <path fill="#fff" d="M9 3h10v1H9z" />
    <text x="50%" y="60%" dominantBaseline="middle" textAnchor="middle" fontSize="10" fill="#ffffff">
      {seat}
    </text>
  </svg>
);

2. 좌석표 나열하기

좌석표를 mockdata로 index 0부터 74까지 다음과 같이 임의로 생성해줬는데요,

export const SEAT_INFO: string[] = (() => {
  const rows = ['B', 'C', 'D', 'E', 'F', 'G'] as const;
  const seatsPerRow: Record<(typeof rows)[number], number> = {
    B: 11,
    C: 13,
    D: 13,
    E: 12,
    F: 13,
    G: 13,
  };

  const seatInfo: string[] = [];
  rows.forEach((row) => {
    for (let i = 1; i <= seatsPerRow[row]; i++) {
      seatInfo.push(`${row}${i}`);
    }
  });

  return seatInfo;
})();

저희 뷰에서는 알파벳 row마다 줄바꿈을 해야하고, i에 해당하는 숫자가 2와 11이면 오른쪽 마진을 줘야합니다.

<S.SeatTableBody>
          {SEAT_ROWS.map((row) => (
            <S.SeatRowWrapper key={row}>
              {SEAT_INFO.filter((seat) => seat.startsWith(row)).map((seat) => (
                <BtnSeatDefaultLarge
                  key={seat}
                  width={'2.8rem'}
                  seat={seat}
                  style={{
                    marginRight: [2, 11].includes(parseInt(seat.slice(1))) ? '2.8rem' : '0',
                    cursor: 'pointer',
                  }}
                />
              ))}
            </S.SeatRowWrapper>
          ))}
</S.SeatTableBody>

일단 다음과 같이 SEAT_ROWS에 해당하는 알파벳들을 따로 상수로 빼주고, row안에서 또 개별적인 좌석들을 mapping해서 알파벳마다 줄바꿈이 되도록 해줬습니다. 또 마진을 주는 부분은, 첫번째 문자를 제외하고 slice하여 좌석의 번호만 가져오게 한 후, 해당 숫자가 배열 2,11에 포함된다면 마진을 주도록 구현했습니다.

3. 좌석표 중앙 정렬과 스크롤 컨테이너가 충돌하는 이슈

초기 렌더링 될때, 좌석표의 정중앙이 화면에 보이도록 하고, 양쪽으로 스크롤을 이동할 수 있게끔 구현하려했습니다. 그러나 좌석표를 중앙정렬할 때 justify-content: center;를 이용하면 좌우 scroll을 적용시킬 때 중앙정렬과 스크롤 컨테이너가 충돌해서 왼쪽 좌석표가 짤리는 현상이 발생했습니다. 그래서 margin: 0 auto;로 중앙정렬을 시도하였으나 짤리는 현상을 해결하지 못했습니다.
결국 수평정렬 + 좌우 스크롤을 화면 짤림 없이 구현하는 것이 어려워, 일단 좌우 스크롤이 되도록 구현한 후에 초기 렌더링시 스크롤 위치를 중앙으로 해주는 것으로 구현했습니다. 더 나은 방법을 찾지 못했는데, 이 부분 리뷰 해주시면 감사하겠습니당

const SeatTableBody = () => {
  const seatTableWrapperRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const wrapper = seatTableWrapperRef.current;
    if (wrapper) {
    // 스크롤을 화면 중앙으로 이동
      wrapper.scrollLeft = (wrapper.scrollWidth - wrapper.clientWidth) / 2;
    }
  }, []);

👀 스크린샷 / GIF / 링크

2024-11-25.7.48.58.mov

seueooo and others added 18 commits November 25, 2024 03:51
- Menu 클릭 시 선택한 탭 active 표시 (underline, color)
- Bar 이동 시 transition으로 부드럽게 이동하도록 설정
- 재사용성을 위한 children text 사용
- Pin UI 분기 없이 helperText만 추가 (이후 로직 브랜치에서 구현 예정)
- 상태 관리 로직 제외 UI 전체 구현
- IcCloseGray1414라는 tsx (svg) 이름으로 fill이 다르게 사용되고 있어서 충돌
- 다른 팀원 Icon을 일단 그대로 유지하고 내 아이콘을 fill을 다르게 넣은 temp 아이콘으로 교체
@seueooo seueooo added 🎨 Design UI 등 스타일링 코드 한서 labels Nov 25, 2024
@seueooo seueooo self-assigned this Nov 25, 2024
@seueooo seueooo linked an issue Nov 25, 2024 that may be closed by this pull request
1 task
@seueooo seueooo requested review from gonn-i, constantly-dev and look-back-luca and removed request for gonn-i November 25, 2024 11:10
Copy link
Collaborator

@look-back-luca look-back-luca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

너무 깔끔하게 잘 만들었어요

Copy link
Collaborator

@gonn-i gonn-i left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

딱히 코리 내용 없는거 같습니다! 굿굿

Comment on lines 18 to 19
<Button variant="default">결제</Button>
<Button variant="secondary">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5: 버튼 타입 넣어주시면 좋을 것 같아용!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 맞다!!!!!!!!!!!!!!! 바로 수정 완료

Comment on lines +33 to +43
{SEAT_INFO.filter((seat) => seat.startsWith(row)).map((seat) => (
<BtnSeatDefaultLarge
key={seat}
width={'2.8rem'}
seat={seat}
style={{
marginRight: [2, 11].includes(parseInt(seat.slice(1))) ? '2.8rem' : '0',
cursor: 'pointer',
}}
/>
))}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5: 오 좌석 이렇게 구현하셨군요 !!! 굿굿 너무 좋아요!!! 아주 깔꼼하네요

Copy link
Collaborator

@constantly-dev constantly-dev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다 :) pr에 올려주신 스크롤 중앙으로 초기화 되는 부분은 저도 더 고민해볼게요!!

Comment on lines +38 to +41
style={{
marginRight: [2, 11].includes(parseInt(seat.slice(1))) ? '2.8rem' : '0',
cursor: 'pointer',
}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5 : 이렇게 tsx로 변환한 svg에 props를 줄 수도 있군요! 이미지를 컴포넌트화 해서 사용할 때의 장점을 제대로 사용하신 것 같습니다 :)

Comment on lines +12 to +17
useEffect(() => {
const wrapper = seatTableWrapperRef.current;
if (wrapper) {
wrapper.scrollLeft = (wrapper.scrollWidth - wrapper.clientWidth) / 2;
}
}, []);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p5 : 저도 pr을 보고 생각을 해봤는데 이외 확실한 방법이 잘 생각나지는 않네요... 더 생각해보고 방법이 떠오르면 같이 얘기해보며 좋을 것 같아요...!

Comment on lines +3 to +21
const seatsPerRow: Record<(typeof rows)[number], number> = {
B: 11,
C: 13,
D: 13,
E: 12,
F: 13,
G: 13,
};

const seatInfo: string[] = [];
rows.forEach((row) => {
for (let i = 1; i <= seatsPerRow[row]; i++) {
seatInfo.push(`${row}${i}`);
}
});

return seatInfo;
})();

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

p4 : 지금도 좋지만 이 좌석을 생성하는 로직을 함수로 사용해도 좋을 것 같아요!
예를 들면

export const SEAT_ROWS = ['B', 'C', 'D', 'E', 'F', 'G'] as const;

export const generateSeatInfo = (row: string): string[] => {
  const seatsPerRow: Record<string, number> = {
    B: 11,
    C: 13,
    D: 13,
    E: 12,
    F: 13,
    G: 13,
  };

  return Array.from({ length: seatsPerRow[row] }, (_, i) => `${row}${i + 1}`);
};

대충 이른 느낌으로?! 그냥 참고정도로!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋은 디벨롭 방안 감사합니다 ㅎㅎ

@seueooo seueooo merged commit 01da310 into develop Nov 25, 2024
2 checks passed
@seueooo seueooo deleted the design/reserve-seat/#55 branch November 25, 2024 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
한서 🎨 Design UI 등 스타일링 코드
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Design] 좌석표 구현 (좌석 선택 뷰)
4 participants