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

[FE] 특정 테이블 셀에 마우스를 올리거나, 클릭하면 해당 셀을 선택한 약속 참여자들을 확인할 수 있는 툴팁 컴포넌트 구현 #156

Merged
merged 30 commits into from
Aug 8, 2024

Conversation

hwinkr
Copy link
Contributor

@hwinkr hwinkr commented Aug 4, 2024

관련 이슈

작업 내용

(우선 디버깅을 하느라, 예상보다 작업이 훨씬 많이 소요되어 PR 제출이 늦어진 점 죄송합니다...🥺
디버깅했던 컴포넌트들은 현재 버리기는 아까워 legacy 폴더에 있습니다!)

툴팁 컴포넌트 구현

재사용 가능한 툴팁 컴포넌트를 구현했습니다.

1) 사용법

export const Playground: Story = {
  args: {
    content: <div>안녕하세요 툴팁입니다</div>,
    children: <button>마우스를 올려보세요</button>,
    position: 'top',
  },
  render: (args) => {
    return (
      <Tooltip content={args.content} position={args.position}>
        {args.children}
      </Tooltip>
    );
  },
};
  • content : 툴팁을 사용해서 보여줄 컴포넌트
  • children : 툴팁 렌더링을 트리거하는 컴포넌트, 위 스토리북 예시에서는 버튼이 됩니다.
  • position : children을 기준으로 툴팁을 보여줄 위치, 동서남북 + 4가지 대각선 방향 총 8가지 방향이 있습니다.

2) 구현 과정

툴팁 구현할 때, 최대한 관심사를 분리하고자 했습니다.

  • 툴팁을 어느 방향에서 보여줄지를 결정하는 책임
  • 결정된 위치에 따라서 툴팁의 세부 위치를 결정하는 책임 (top, left)

따라서 <Tooltip /> 컴포넌트가 툴팁 렌더링을 트리거하는 컴포넌트를 children으로 가지고 있고, 해당 props의 위치에 따라서 content가 렌더링 될 위치를 결정하도록 했습니다.
position : absolute 속성을 사용했고 부모 요소(relative)기준으로 상대적인 위치를 구할지, React.createPortal을 사용하여 document.body 기준 절대적인 위치를 구할지 고민했었습니다. 현재는 부모 요소 기준 상대적인 위치를 구하는 것이 8가지 방향에 대해 공수가 너무 많이 드는 작업이라고 생각해 createPortal을 사용해서 절대적인 위치를 사용해서 구현했습니다. 평소에 상대, 절대 위치 중 어느 것을 선호하시는지 리뷰를 할 때 함께 달아주시면 감사하겠습니다!! :)

3) 2차원 테이블 셀 내부 툴팁의 위치

image 2차원 테이블 셀 내부에서 툴팁을 어느곳에 렌더링해야할 지 고민을 한 결과, 일단은 2차원 셀을 **최대한 벗어나지 않는 곳**으로 툴팁을 렌더링하고자 했고, 꼭짓점이나 양 끝의 경우 최대한 안쪽으로 툴팁이 렌더링될 수 있도록 했습니다.

특이 사항

Header 스타일 변경

현재 헤더 컴포넌트의 스타일이 고정되어 있지 않은데, sticky 속성을 사용하는 것으로 고정했습니다.

글로벌 레이아웃 스타일 변경

기존에는 height가 고정되어 있고, overflow-y 속성이 있었는데 툴팁이 렌더링 된 상태에서 스크롤을 하게 되면 툴팁의 위치는 고정되어 있고 툴팁 뒤 영역만 렌더링되는 문제가 있었습니다. 알고보니, 고정된 height와 관련된 문제였고 따라서 이 속성을 제거하게 되었습니다.

리뷰 요구사항 (선택)

툴팁 위치 결정 상대 vs 절대

부모 요소의 위치를 활용한 상대적인 위치를 사용하는 편인지, createPortal을 사용한 절대적인 위치를 사용하는 편인지 알려주세요 ㅎㅎ

아래는 이번 툴팁 기능을 구현하면서 두 방식을 비교한 내용입니다.


createPortal을 사용하면, body 기준으로 렌더링 요소의 위치를 결정하기 때문에, 절대값 기준으로 위치를 설정하면 된다. 예를 들어, 툴팁을 렌더링 할 때 툴팁 트리거 컴포넌트의 오른쪽에 띄워야 한다면

right: css`
top: ${targetRect.top + targetRect.height / 2 + window.scrollY}px;
left: ${targetRect.right + window.scrollX}px;
transform: translate(0, -50%);
`,

이렇게 위치를 결정할 수 있을 것이다.

만약, createPortal을 사용하지 않는다면 부모 요소 기준으로 상대적인 위치를 결정해야 한다. 따라서,

right: css`
top: 50%;
left: 100%;
transform: translateY(-50%);
`,

이렇게 위치를 결정해야 한다.

만약, 부모 요소에 종속되지 않고 위치를 독립적으로 결정하고 싶다면 createPortal을 사용할 수 있을 것이다.

@hwinkr hwinkr added 🐈 프론트엔드 프론트엔드 관련 이슈에요 :) 🎨 디자인 디자인을 해요 :) 🧪 테스트 테스트를 해요 :) labels Aug 4, 2024
@hwinkr hwinkr added this to the 3차 데모데이 milestone Aug 4, 2024
@hwinkr hwinkr self-assigned this Aug 4, 2024
@hwinkr hwinkr changed the title Feat/130 tooltip [FE] 특정 테이블 셀에 마우스를 올리거나, 클릭하면 해당 셀을 선택한 약속 참여자들을 확인할 수 있는 툴팁 컴포넌트 구현 Aug 4, 2024
Copy link

github-actions bot commented Aug 4, 2024

Test Results

5 tests   5 ✅  3s ⏱️
1 suites  0 💤
1 files    0 ❌

Results for commit 4000146.

♻️ This comment has been updated with latest results.

Copy link
Contributor

@Largopie Largopie left a comment

Choose a reason for hiding this comment

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

안녕하세요 해리~! 구현하신 부분 너무 잘 봤습니다 :) 주말에 해주신 컨텍스트 공유도 너무 좋았어요! 덕분에 코드를 읽는데 더 수월했던 것 같습니다!

많은 고민하고 구현해주신게 느껴졌습니다 :)
현재 아까 오후에 공유한 css 위치 선정되는 부분에 대한 문제 함께 해결해주시면 감사드리겠습니다!

추가적으로 질문에 대한 답변입니다!

부모 요소의 위치를 활용한 상대적인 위치를 사용하는 편인지, createPortal을 사용한 절대적인 위치를 사용하는 편인지 알려주세요 ㅎㅎ

경우에 따라 많이 달라지는 내용이 될 것 같다는 생각이 먼저 들었어요!
현재 경우로 보았을 때, 저 같은 경우 툴팁은 어떻게 보면 table 기준에서만 작동이 이루어지는 컴포넌트이다보니 테이블 측에서 상대경로로 구현했을 것 같네요!

기능 구현하느라 너무 고생했습니다 :) 반영사항 반영 부탁드리며, 남은 데모데이도 화이팅~! 🐫

Comment on lines 35 to 39
useEffect(() => {
if (triggerRef.current) {
console.log(triggerRef.current.getBoundingClientRect());
}
}, [visible]);
Copy link
Contributor

Choose a reason for hiding this comment

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

[P2]

console.log()는 개발단에만 필요한 내용이라서 제외해도 좋을 것 같아요 :)

Copy link
Contributor

Choose a reason for hiding this comment

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

[COMMENT]
동의합니다~ 디버깅 목적으로 사용한 useEffect hook을 지워도 될 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

동의합니다..! 툴팁을 트리거하는 컴포넌트의 rect 정보를 얻은 후, 디버깅에 활용하기 위해서 useEffect 훅을 사용했던 것인데, 기능 구현이 완료되었으니 지우도록 하겠습니다~

Comment on lines 12 to 20
export const s_tooltipTitle = css`
font-size: 1.6rem;
font-weight: 500;
`;

export const s_attendeeText = css`
font-size: 1.2rem;
font-weight: 300;
`;
Copy link
Contributor

Choose a reason for hiding this comment

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

[P1]
우리가 토큰으로 만들어둔 typography를 사용해보는 것은 어떨까요?
만약 토큰이 없다면, 새로 만들어서 적용해봐도 좋을 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

툴팁 컴포넌트를 구현할 당시에는, 디자인 토큰 pr이 머지가 되지 않은 상태라 사용하지 못했었는데 활용해보도록 할게요~

Comment on lines 31 to 38
const params = useParams<{ uuid: string }>();
const uuid = params.uuid!;

const [selectedAttendee, setSelectedAttendee] = useState('');
const handleAttendeeChange = (attendee: string) => {
if (selectedAttendee === attendee) return;
setSelectedAttendee(attendee);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3]
굉장히 사소하지만 변수, 함수, return과 같은 부분에도 개행 규칙을 정해봐도 좋을 것 같아요 :)
저같은 경우에는 보통 변수는 변수끼리 선언하고 함수는 개행을 하는 편입니다!
그래야 개인적으로는 가독성이 조금 나아보이더라구요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

변수끼리는 개행을 하지 않고, 붙어서 선언을 하고 함수끼리는 개행을 하는 편이라는 말씀이신가요??? 좋네요!!

낙타의 의견에 더해 변수끼리도 관심사 분리를 해서, 관심사가 일치하는 변수끼리는 개행을 하지 않고 다른 변수들끼리는 개행을 해도 좋을 것 같아요!

});

return (
<>
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3]
저도 알아봐야 하는 사항이지만, 이 Fragment를 사용할 때만 import React from 'react'를 해야하는 부분이 조금 불편하게 느껴지더라구요..! 제가 나중에 해결방법을 찾아오겠습니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fragment를 사용할 때마다, 런타임 에러가 발생해서 너무 당황스럽더라구요...! 이번 데모데이 끝나면 함께 알아보시죠!

Comment on lines +28 to +36
if (rowIndex === 0 && columnIndex === 0) return 'bottomRight';
if (rowIndex === 0 && columnIndex === totalColumns - 1) return 'bottomLeft';
if (rowIndex === totalRows - 1 && columnIndex === 0) return 'topRight';
if (rowIndex === totalRows - 1 && columnIndex === totalColumns - 1) return 'topLeft';
if (rowIndex === 0) return 'bottom';
if (rowIndex === totalRows - 1) return 'top';
if (columnIndex === 0) return 'right';
if (columnIndex === totalColumns - 1) return 'left';
return 'top';
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3]
지금 현재 상태로 보면 가장 바깥 상태에 위치해있는 표에 대해서만 로직 처리가 되어있고 그 외 내부 컴포넌트는 모두 'top'속성을 갖는 것으로 이해했습니다. 그렇게 되면 rowIndex = 1을 갖는 로직도 'top'으로 처리가 되어 어느정도 넘는 부분이 생길 것 같아요!

현재로서 구현할 수 있는 최선으로 구현해주신 것으로 생각하는데, 추후에 이를 더 잘 이용할 수 있도록 함께 고민해봐야할 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

rowIndex === 1 조건을 만족하는 경우 bottom으로 처리할까도 생각을 했지만,,,우선은 top으로 뒀습니다! rowIndex를 기준으로 rowIndex / 2 보다 작으면(위에 있으면) bottom, 그렇지 않으면(아래에 있으면) top방향으로 툴팁이 그려지도록 해도 괜찮을 것 같네요! colIndex를 기준으로 right, left 방향을 결정할 때도 마찬가지일 것 같아요 :)

Copy link
Contributor

@Yoonkyoungme Yoonkyoungme left a comment

Choose a reason for hiding this comment

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

해리 툴팁 만드느라 정말 고생 많았습니다!!!!!!! 대단하네요👏👏👏👏
백로그에 작성해주신 부분도 잘 읽었습니다 :) 덕분에 코드 리뷰할 때 해리가 어떤 고민을 가지고 문제를 해결하였는지 알 수 있었어요
legacy 코드들 넘 아쉽네요ㅜㅡㅜ (깔끔해서 더 아쉬워요) 스프린트 끝나고 스크롤 문제 같이 해결해봐요

Comment on lines 1 to 11
export type TooltipPosition =
| 'top'
| 'left'
| 'right'
| 'bottom'
| 'topLeft'
| 'topRight'
| 'bottomLeft'
| 'bottomRight'
| 'leftTop'
| 'leftBottom'
| 'rightTop'
| 'rightBottom';
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3]
BasicPositionCombinedPosition이라는 두 개의 서브타입을 정의한 다음, 이들을 결합하여 TooltipPosition을 정의해보는건 어떨까요?

export type BasicPosition =
  | 'top'
  | 'left'
  | 'right'
  | 'bottom';

export type CombinedPosition =
  | 'topLeft'
  | 'topRight'
  | 'bottomLeft'
  | 'bottomRight'
  | 'leftTop'
  | 'leftBottom'
  | 'rightTop'
  | 'rightBottom';

export type TooltipPosition = BasicPosition | CombinedPosition;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

BasePosition, CombinedPosotion를 구분하는 것을 통해 타입에서도 관심사를 분리하면 좋겠다는 의견이신가요?? top left right bottom은 다른 타입들과도 엮어서 확장성 장점을 챙길 수 있을 것 같아서 좋네요! 타입 분리 해보겠씁니다 ㅎㅎ

Comment on lines 35 to 39
useEffect(() => {
if (triggerRef.current) {
console.log(triggerRef.current.getBoundingClientRect());
}
}, [visible]);
Copy link
Contributor

Choose a reason for hiding this comment

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

[COMMENT]
동의합니다~ 디버깅 목적으로 사용한 useEffect hook을 지워도 될 것 같아요!

Comment on lines 12 to 13
s.date === availableDates[columnIndex] &&
s.time === `${rowIndex + parseInt(firstTime.slice(0, 2))}:00`,
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3]
해당 코드를 더 읽기 쉽고 유지 보수가 용이하도록 개선해보는건 어떨까요?

const date = availableDates[columnIndex];
const time = `${rowIndex +parseInt(firstTime.slice(0, 2))}:00`;

const schedule = allSchedules.schedules.find(
  (s) => s.date === date && s.time === time
);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

헉 지금 코드는 find메서드로 반복문을 돌 때마다 계속해서 동일한 값을 담는 변수를 계속해서 선언하고 있네요, 가독성도 좋지 않고 메모라 효율 관점에서도 좋지 못한 코드를 작성한 것 같습니다~ 좋은 피드백 고마워유

Copy link
Contributor

@Yoonkyoungme Yoonkyoungme Aug 6, 2024

Choose a reason for hiding this comment

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

[P3]

낙타의 토글 컴포넌트 PR에 달아둔 코멘트와 비슷한 느낌인 것 같네요. #158 (comment)

공통 컴포넌트에서 파생된 컴포넌트들을 어느 디렉터리에 위치시켜야할지에 대해 프론트엔드 다같이 컨벤션을 정하면 좋겠네요!!

@hwinkr @Largopie


const [selectedAttendee, setSelectedAttendee] = useState('');
const handleAttendeeChange = (attendee: string) => {
if (selectedAttendee === attendee) return;
Copy link
Contributor

Choose a reason for hiding this comment

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

[P2]
handleAttendeeChange 함수에서
if (selectedAttendee === attendee) return;조건문이 꼭 필요할까요?
state가 변하지 않았을 때 setState를 호출하면 어떤 일이 일어날까요?

handleAttendeeChange 함수로 감싸지 않고, setSelectedAttendee 사용해도 될 것 같아요 :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

해당 조건문이 필요하다고 생각했던 이유는, 사용자가 현재 보고 있는 사용자와 클릭한 사용자가 같은 경우 setState 호출로 인한 리렌더링이 필요하지 않다고 생각했기 때문입니다! 그래서 현재 selectedAttendee 상태와 클릭한 attendee의 값이 같으면 early return 하도록 했어요!

Copy link
Contributor

Choose a reason for hiding this comment

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

react의 상태 업데이트는 상태 값이 변경되었을 때만 컴포넌트를 리렌더링하기 때문에 조건문이 따로 필요없다고 생각했어요 :)

이거에 대해서는 왜 생각대로 동작하지 않는지 같이 딥다이브 해보죠🍡

Copy link
Contributor

@Largopie Largopie left a comment

Choose a reason for hiding this comment

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

해리 복잡한 기능 구현하느라 고생했습니다 :)
시간 관계상 더 깊게 모든 코드를 파악하기는 어려웠지만, 여러 주석 덕분에 이해하는데 많은 도움이 되었어요!

리뷰 남긴 부분 확인 부탁드립니다!

css={css`
position: relative;
`}
Copy link
Contributor

Choose a reason for hiding this comment

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

[Q]

이 부분만 css를 별도로 선언 없이 사용하신 것 같은데, 특별히 이유가 있을까요?
이 부분만 별도로 있으니 조금 어색하게 느껴져서 리뷰 남겨요!! 🙌

Copy link
Contributor Author

Choose a reason for hiding this comment

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

급하게 구현하느라 디테일적인 부분을 놓친 것 같아요! 빠르게 수정하겠습니다 ㅎㅎ

<div css={s_buttonContainer}>
<Button text="수정하기" onClick={handleToggleIsTimePickerUpdate} />
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

[P2]
해당 Button 컴포넌트는 현재 수정사항이 생겨서 필수적인 변경사항으로 예상됩니다!

git pull --rebase origin develop 명령어를 사용해서 변경 사항을 미리 적용하거나, 기본 button으로 수정하는 것은 어떨까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

git pull --rebase origin develop을 하면 충돌을 위한 공수가 너무 많이 들 것 같아 일단 기본 버튼으로 수정해 둘게요 :)

Comment on lines +55 to +59
const isMultiPage = totalPages > 1;
const isFirstPage = currentDatePage === 0;
const isLastPage = currentDatePage === totalPages - 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

👍👍👍

@@ -0,0 +1,71 @@
import { useState } from 'react';

interface UserDatePageReturn {
Copy link
Contributor

Choose a reason for hiding this comment

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

[P1]
오타 발견이요! 아래를 기대하고 작성하신 것으로 예상됩니다!

Suggested change
interface UserDatePageReturn {
interface UseDatePageReturn {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

사실 이 오타는 제가 여러분들이 코드 리뷰를 꼼꼼하게 하는지 확인하기 위한 이스터에그였습니다. 하하... 장난이고 예리하네요 낙타. 역시...사막에서 살아남으려면 강해져야하나 봐요

if (selectedAttendee === attendee) return;

setSelectedAttendee(attendee);
resetDatePage(); // 참여자를 변경할 때마다 페이지를 다시 0으로 초기화해 줍니다.(@해리)
Copy link
Contributor

Choose a reason for hiding this comment

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

주석 굿💯

Comment on lines +106 to +109
:disabled {
cursor: not-allowed;
opacity: 0.4;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

disabled 속성 사용 굿!👍

Comment on lines 129 to 131
css={css`
${s_td(currentValue[rowIndex][columnIndex])}
`}
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3]

이 부분도 요렇게 바꿀 수 있겠네요!

Suggested change
css={css`
${s_td(currentValue[rowIndex][columnIndex])}
`}
css={s_td(currentValue[rowIndex][columnIndex])}

"attendeeNames": ["마크", "배키", "다온"]
"attendeeNames": ["해리", "낙타", "빙봉"]
Copy link
Contributor

Choose a reason for hiding this comment

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

아싸 내이름 들어갔다 🐫🎶

Copy link
Contributor

Choose a reason for hiding this comment

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

아싸 내 이름도 있다 🔮🔮🚀🤸‍♀️😆

Copy link
Contributor

Choose a reason for hiding this comment

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

꿀팁 알아갑니다 🐫👍

Comment on lines 35 to 38
firstTime={meetingFrame?.firstTime}
lastTime={meetingFrame?.lastTime}
availableDates={meetingFrame?.availableDates}
meetingAttendees={meetingFrame?.attendeeNames}
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3]
이미 meetingFrame이 있다는 전제의 컴포넌트이기 때문에 옵셔널 체이닝 연산자는 제외해도 될 것 같아요!

Suggested change
firstTime={meetingFrame?.firstTime}
lastTime={meetingFrame?.lastTime}
availableDates={meetingFrame?.availableDates}
meetingAttendees={meetingFrame?.attendeeNames}
firstTime={meetingFrame.firstTime}
lastTime={meetingFrame.lastTime}
availableDates={meetingFrame.availableDates}
meetingAttendees={meetingFrame.attendeeNames}

@Largopie Largopie self-requested a review August 8, 2024 06:14
Copy link
Contributor

@Largopie Largopie left a comment

Choose a reason for hiding this comment

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

실수로 어프루브를 눌러서 다시 RC 요청합니다 😭

Copy link
Contributor

@Yoonkyoungme Yoonkyoungme 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 19 to 40
/**
* usePagedTimePick 훅은 시간 선택 테이블의 상태와 날짜 인덱스를 관리합니다.
* 약속 날짜가 4일 이상인 경우, 수정할 때 다음 날짜 페이지로 이동할 수 있게 하기 위해서 useDatePage 커스텀 훅과 조합하는 방향으로 구현했습니다.(@해리)
*
* @param {string[]} availableDates - 사용할 수 있는 날짜들의 배열
* @param {number[][]} initialSchedules - 초기 시간표 데이터
* @returns {UseTimePickReturn & Omit<ReturnType<typeof useDatePage>, 'resetDatePage'>}
* 시간 선택 테이블과 날짜 페이지네이션을 관리하는 상태와 함수들을 반환합니다.
* 시간을 선택할 때는, 날짜 페이지를 0으로 초기화할 필요가 없다고 판단해서 Omit을 활용해 반환 타입에서 제거했어요.
*
* * 아래는 usePagedTimePick 훅 반환 타입에 대한 간단한 설명입니다. :)
* @property {React.MutableRefObject<HTMLTableElement | null>} tableRef - 테이블 요소의 참조 객체
* @property {number[][]} tableValue - 전체 테이블 값
* @property {number[][]} currentValue - 현재 페이지에 해당하는 테이블 값
* @property {number} currentDatePage - 현재 날짜 페이지 인덱스
* @property {string[]} currentDates - 현재 페이지에 해당하는 날짜 배열
* @property {() => void} increaseDatePage - 날짜 페이지를 증가시키는 함수
* @property {() => void} decreaseDatePage - 날짜 페이지를 감소시키는 함수
* @property {boolean} isMultiPage - 페이지가 여러 개인지 여부
* @property {boolean} isFirstPage - 현재 페이지가 첫 페이지인지 여부
* @property {boolean} isLastPage - 현재 페이지가 마지막 페이지인지 여부
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

JSDoc 사용 좋네요👍🏻👍🏻 리뷰하기 편하네요 :)

return {
tableRef,
tableValue,
currentValue,
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3]
currentValue라고 하면 어떤 값인지 헷갈릴 수도 있을 것 같아요. 네이밍이 조금 길어지지만, currentTableValue로 변경해 보는 거 어떨까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

의미있는 변수명을 잘 사용해보도록 하겠습니다! ㅎㅎ

Comment on lines +40 to +43
const currentDates = availableDates.slice(
currentDatePage * DATES_PER_PAGE,
(currentDatePage + 1) * DATES_PER_PAGE,
);
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3]
slice(currentDatePage * DATES_PER_PAGE, (currentDatePage + 1) * DATES_PER_PAGE)
usePagedTimePick hook에서도 사용되네요. 이 부분을 함수로 빼서 재사용 하는건 어떤가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TODO 리뷰 반영하기

Copy link
Contributor

Choose a reason for hiding this comment

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

이번 스프린트 끝나고 꼭 반영해주세요 ^^

Comment on lines 45 to 55
const increaseDatePage = () => {
setCurrentDatePage((prev) => prev + 1);
};
const decreaseDatePage = () => {
setCurrentDatePage((prev) => prev - 1);
};
const resetDatePage = () => {
setCurrentDatePage(0);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3]
함수 선언 사이에 개행해주실 수 있나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

낙타, 빙봉 모두 함수 선언 사이에는 개행을 원하는 것 같군요~ 저는 관심사가 비슷한 즉, 위 코드 예시처럼 페이지 관리를 한다는 비슷한 역할을 하는 함수 사이에는 개행을 하지 않았는데 저는 이 부분이 취향 차이라고 생각해서 개행을 추가해 보도록 하겠습니다!

"attendeeNames": ["마크", "배키", "다온"]
"attendeeNames": ["해리", "낙타", "빙봉"]
Copy link
Contributor

Choose a reason for hiding this comment

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

아싸 내 이름도 있다 🔮🔮🚀🤸‍♀️😆

Copy link
Contributor

@Largopie Largopie left a comment

Choose a reason for hiding this comment

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

반영하느라 수고하셨습니다 :) 사소한 리뷰사항 몇 가지 남겨드렸으니 확인 부탁드려요~! 🐫

(s) =>
s.date === availableDates[columnIndex] &&
s.time === `${rowIndex + parseInt(firstTime.slice(0, 2))}:00`,
(s) => s.date === targetDate && s.time === targetTime,
Copy link
Contributor

Choose a reason for hiding this comment

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

[P3]

의미있는 변수명으로 바꾸는 김에 find 함수의 인자로 들어가는 s도 의미있는 변수명으로 바꿔주면 좋을 것 같아요! 🐫

@@ -118,7 +116,7 @@ export default function SchedulesViewer({
)}
</section>
<div css={s_buttonContainer}>
<Button text="수정하기" onClick={handleToggleIsTimePickerUpdate} />
<button onClick={handleToggleIsTimePickerUpdate}>수정하기</button>
Copy link
Contributor

Choose a reason for hiding this comment

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

rebase 요구할려고 했는데 봐 드리겠습니다 ^&^🐫🎶룰루랄라

Copy link
Contributor

@Yoonkyoungme Yoonkyoungme left a comment

Choose a reason for hiding this comment

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

고생하셨습니다 해리🍀

- useDatePage 커스텀 훅을 조합한 useSelectSchedule 커스텀 훅의 기능을 활용
- 각 테이블 셀의 width가 고정된 크기를 가지도록 수정
- 날짜가 2일 이하인 경우 왼쪽으로 붙어서 그려지도록 수정
- Time -> Schedule 도메인 용어 변경 사항 반영
- useDatePage 커스텀 훅을 조합한 usePagedTimePick 커스텀 훅 구현
- 날짜를 페이지네이션하면서 약속 참여 가능 시간을 수정할 수 있도록 구현
-
- meetingBase에서는 낙타, 해리, 빙봉이 약속 참여자였음.
- 하지만 약속 조회 데이터에서는 마크, 배키, 다온이 사용되어 싱크를 맞추기 위해서 닉네임 수정
- ${BASE_URL}/550e8400/attendees/me/schedules 경로로 요청해도 ${BASE_URL}/550e8400 경로로 요청 되는 문제를 해결하기 위한 수정
- 길이 상관없이 매칭이 되는 문자열이라고 판단되면, 해당 json 데이터를 반환해버리기 때문에 내 스케쥴을 조회하는 api의 우선순위를 높이기 위해서 배열 순서를 수정
- 변경된 공통 버튼 컴포넌트와 충돌을 피하기 위함
@hwinkr hwinkr merged commit 8bd5e2e into develop Aug 8, 2024
5 checks passed
@hwinkr hwinkr deleted the feat/130-tooltip branch August 13, 2024 16:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🎨 디자인 디자인을 해요 :) 🐈 프론트엔드 프론트엔드 관련 이슈에요 :) 🧪 테스트 테스트를 해요 :)
Projects
Status: Done
3 participants