Skip to content

Conversation

@dasosann
Copy link
Contributor

@dasosann dasosann commented Jan 4, 2026

요약

기존에 Calander 쓰던 날짜피커 커스텀으로 직접 제작

구현 사항

  • 기존에 Calander 쓰던 날짜피커 커스텀으로 직접 제작
  • [ ]
  • [ ]
  • [ ]

📸 스크린샷

image

Need Review

  • ~ 부분 이렇게 구현했어요, 피드백 부탁해요!

Reference

📜 리뷰 규칙

Reviewer는 아래 P5 Rule을 참고하여 리뷰를 진행합니다.
P5 Rule을 통해 Reviewer는 Reviewee에게 리뷰의 의도를 보다 정확히 전달할 수 있습니다.

  • P1: 꼭 반영해주세요 (Comment)
  • P2: 적극적으로 고려해주세요 (Comment)
  • P3: 웬만하면 반영해 주세요 (Comment)
  • P4: 반영해도 좋고 넘어가도 좋습니다 (Approve)
  • P5: 그냥 사소한 의견입니다 (Approve)

@vercel
Copy link

vercel bot commented Jan 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
fe Ready Ready Preview, Comment Jan 10, 2026 2:47pm

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @dasosann, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 풀 리퀘스트는 기존에 사용하던 외부 라이브러리 기반의 날짜 피커를 제거하고, 사용자 경험을 개선하기 위해 직접 개발한 스크롤 가능한 날짜 피커로 교체하는 것을 목표로 합니다. 특히 모바일 환경에서의 날짜 선택 편의성을 높이기 위해 Popover 대신 Drawer를 활용하여 새로운 날짜 선택 인터페이스를 제공합니다. 또한, 일부 컴포넌트의 리팩토링과 확장성을 위한 개선도 포함되어 있습니다.

Highlights

  • 커스텀 스크롤 날짜 피커 구현: 기존 react-day-picker 기반의 날짜 피커를 제거하고, 연, 월, 일을 개별적으로 스크롤하여 선택할 수 있는 커스텀 날짜 피커 컴포넌트(ScrollableDatePicker)를 새로 추가했습니다.
  • 날짜 선택 UI 변경: DateXInput 컴포넌트에서 날짜 선택 시 Popover 대신 Drawer를 사용하여 모바일 환경에 더 적합한 UI/UX를 제공하도록 변경했습니다. 드로어 내에서 커스텀 날짜 피커를 사용합니다.
  • 컴포넌트 리팩토링: AlbumInfos 컴포넌트에서 forwardRef 사용 방식을 제거하고, ref를 직접 props로 전달받도록 리팩토링했습니다.
  • 버튼 컴포넌트 확장: LongButton 컴포넌트에 className prop을 추가하여 외부에서 스타일을 유연하게 적용할 수 있도록 개선했습니다.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

날짜 피커를 기존 react-day-picker 기반의 캘린더에서 커스텀 스크롤 피커로 교체하는 작업을 리뷰했습니다. 모바일 환경에 더 적합한 UI를 제공하려는 의도가 좋아 보입니다. 새로 추가된 ScrollableDatePicker 컴포넌트는 잘 구현되었지만, 몇 가지 잠재적인 버그와 개선점을 발견했습니다. 특히 AlbumInfos 컴포넌트의 ref 전달 방식 변경은 기존 기능을 손상시킬 수 있는 심각한 문제이므로 확인이 필요합니다. 자세한 내용은 각 파일에 대한 코멘트를 참고해주세요.

function PickerColumn({ items, value, label, onChange }: PickerColumnProps) {
const containerRef = React.useRef<HTMLDivElement>(null);
const isScrollingRef = React.useRef(false);
const scrollTimeoutRef = React.useRef<NodeJS.Timeout | null>(null);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

scrollTimeoutRef의 타입을 NodeJS.Timeout | null로 지정하셨습니다. 이 컴포넌트는 'use client' 지시어가 있어 브라우저 환경에서 실행되므로, NodeJS.Timeout 타입이 항상 보장되지 않을 수 있습니다. 브라우저와 Node.js 환경 양쪽에서 호환성을 보장하기 위해 ReturnType<typeof setTimeout> | null 타입을 사용하는 것이 더 안전합니다.

Suggested change
const scrollTimeoutRef = React.useRef<NodeJS.Timeout | null>(null);
const scrollTimeoutRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);

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 44 to 62
// Debounce: wait for scroll to stop
scrollTimeoutRef.current = setTimeout(() => {
if (!containerRef.current) return;

const scrollTop = containerRef.current.scrollTop;
const index = Math.round(scrollTop / ITEM_HEIGHT);
const clampedIndex = Math.max(0, Math.min(index, items.length - 1));

// Snap to exact position
containerRef.current.scrollTop = clampedIndex * ITEM_HEIGHT;

const newValue = items[clampedIndex];
if (newValue !== undefined && newValue !== value) {
onChange(newValue);
}

isScrollingRef.current = false;
}, 100);
};
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

setTimeout 콜백 함수에서 value prop을 직접 사용하고 있습니다. setTimeout이 실행되기 전에 value prop이 변경될 경우, 콜백은 오래된(stale) value 값을 사용하여 비교하게 되어 의도치 않은 동작을 유발할 수 있습니다. 이 문제를 해결하기 위해 useRef를 사용하여 항상 최신 value 값을 참조하도록 하는 것이 좋습니다.

// PickerColumn 상단에 추가
const valueRef = React.useRef(value);
valueRef.current = value;

// setTimeout 콜백 내부 수정
scrollTimeoutRef.current = setTimeout(() => {
  // ...
  const newValue = items[clampedIndex];
  if (newValue !== undefined && newValue !== valueRef.current) {
    onChange(newValue);
  }
  // ...
}, 100);

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 +149 to +151
const getDaysInMonth = (year: number, month: number) => {
return new Date(year, month, 0).getDate();
};
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

getDaysInMonth 함수는 컴포넌트의 상태나 props에 의존하지 않는 순수 함수입니다. 컴포넌트 외부에 유틸리티 함수로 분리하면 재사용성을 높이고 ScrollableDatePicker 컴포넌트의 코드를 더 간결하게 만들 수 있습니다.

Comment on lines 214 to 229
{/* Top fade gradient */}
<div
className='pointer-events-none absolute inset-x-0 top-0 z-20 h-24'
style={{
background: 'linear-gradient(to bottom, white 0%, transparent 100%)',
}}
/>

{/* Bottom fade gradient */}
<div
className='pointer-events-none absolute inset-x-0 bottom-0 z-20 h-24'
style={{
background: 'linear-gradient(to top, white 0%, transparent 100%)',
}}
/>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

상단 및 하단 fade-out 효과에 white 색상이 하드코딩되어 있습니다. 다크 모드 등 다른 테마를 지원할 경우 UI가 어색해 보일 수 있습니다. 인라인 스타일 대신 Tailwind CSS의 그라데이션 유틸리티 클래스(bg-gradient-to-b from-white, bg-gradient-to-t from-white)를 사용하면 테마와 일관성을 유지하고 코드를 더 깔끔하게 만들 수 있습니다.

Suggested change
{/* Top fade gradient */}
<div
className='pointer-events-none absolute inset-x-0 top-0 z-20 h-24'
style={{
background: 'linear-gradient(to bottom, white 0%, transparent 100%)',
}}
/>
{/* Bottom fade gradient */}
<div
className='pointer-events-none absolute inset-x-0 bottom-0 z-20 h-24'
style={{
background: 'linear-gradient(to top, white 0%, transparent 100%)',
}}
/>
</div>
{/* Top fade gradient */}
<div
className='pointer-events-none absolute inset-x-0 top-0 z-20 h-24 bg-gradient-to-b from-white to-transparent'
/>
{/* Bottom fade gradient */}
<div
className='pointer-events-none absolute inset-x-0 bottom-0 z-20 h-24 bg-gradient-to-t from-white to-transparent'
/>

@dasosann dasosann merged commit 171ef34 into main Jan 12, 2026
4 checks passed
@dasosann dasosann deleted the refactor/tae branch January 12, 2026 11:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants