Conversation
There was a problem hiding this comment.
Code Review
이번 PR은 하단 네비게이션 바의 스크롤 연동 처리, 경매 입찰 현황의 순위 탭 및 상세 내역 확장 기능, 그리고 월별 조회가 가능한 지갑 내역 화면 등 전반적인 UI/UX를 개선하고 관련 로직을 리팩토링했습니다. 리뷰어는 성능 최적화를 위해 buildBidRankings와 filteredLedgers 연산에 useMemo를 적용하고, 스크롤 이벤트 핸들러에 스로틀링을 도입할 것을 제안했습니다. 또한, 정렬 로직에서 불필요한 Date 객체 생성을 피하기 위해 localeCompare를 사용하는 등의 개선 사항이 지적되었습니다.
| ); | ||
| const { latestAuctionEvent } = useEventStream(); | ||
| const bids = bidHistory?.bids ?? []; | ||
| const bidRankings = buildBidRankings(bids); |
There was a problem hiding this comment.
buildBidRankings 함수는 그룹화 및 다중 정렬 로직을 포함하고 있어 계산 비용이 높습니다. 현재는 컴포넌트가 렌더링될 때마다 매번 호출되고 있는데, bids가 변경될 때만 계산되도록 useMemo를 사용하여 최적화가 필요합니다. (참고: React.useMemo를 사용하거나 useMemo를 임포트하여 적용해 주세요.)
| const bidRankings = buildBidRankings(bids); | |
| const bidRankings = React.useMemo(() => buildBidRankings(bids), [bids]); |
| const handleScroll = (event: Event) => { | ||
| const target = event.target as HTMLElement | Document | null; | ||
| const scrollElement = | ||
| target instanceof Document | ||
| ? target.scrollingElement | ||
| : target instanceof HTMLElement | ||
| ? target | ||
| : null; | ||
|
|
||
| if (!scrollElement) { | ||
| return; | ||
| } | ||
|
|
||
| const nextScrollTop = scrollElement.scrollTop; | ||
| const previousScrollTop = lastScrollTopRef.current; | ||
| const delta = nextScrollTop - previousScrollTop; | ||
|
|
||
| if (nextScrollTop <= 12 || delta < -8) { | ||
| setIsBottomNavVisible(true); | ||
| } else if (delta > 8) { | ||
| setIsBottomNavVisible(false); | ||
| } | ||
|
|
||
| lastScrollTopRef.current = Math.max(0, nextScrollTop); | ||
| }; |
| if (b.bidPrice !== a.bidPrice) { | ||
| return b.bidPrice - a.bidPrice; | ||
| } | ||
| return new Date(b.bidAt).getTime() - new Date(a.bidAt).getTime(); |
There was a problem hiding this comment.
| if (b.highestBid.bidPrice !== a.highestBid.bidPrice) { | ||
| return b.highestBid.bidPrice - a.highestBid.bidPrice; | ||
| } | ||
| return new Date(b.highestBid.bidAt).getTime() - new Date(a.highestBid.bidAt).getTime(); |
| const filteredLedgers = ledgers.filter((ledger) => | ||
| isSameMonth(ledger.createdAt, selectedMonth), | ||
| ); |
There was a problem hiding this comment.
Pull request overview
This PR makes several UI/UX fixes across the home, wallet, and auction flows. It restructures /home so the route renders the full MainLayout (fixing the missing bottom nav and theme/URL race), adds scroll-driven hide/show for the bottom navigation, redesigns the Dealit money history into a full‑screen view with a month picker bottom sheet, switches quick‑amount buttons to accumulate, adds a "전액 입력" shortcut for withdraw, renames TEMP_CHARGE to "딜릿머니 충전", and adds a "입찰 기록 / 입찰 순위" tabbed view to the bidding status screen with per‑bidder rankings and an expandable bid history. Auction/product detail pages are also wrapped in a relative full‑screen container, and the global app uses an isThemeModeReady gate to avoid clobbering stored theme on hydration.
Changes:
- Restructure
/homeroute to renderMainLayoutand defer theme‑mode reads until after mount (in App and HomePage). - Wallet panel redesign: full‑screen history with month picker sheet, accumulating quick amounts,
parseWalletDatehelper, "전액 입력" for withdraw. - Bidding status: add
BidStatusTabButton,buildBidRankings, expandable per‑bidder ranking list, and a sticky bottom action button.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/services/wallet/service.ts | Expose createdAt on view model, add pagination params, rename TEMP_CHARGE label, extract parseWalletDate. |
| src/components/wallet/DealitMoneyPanel.tsx | Full‑screen history modal, month picker sheet, accumulating quick amounts, withdraw "전액 입력" shortcut. |
| src/app/products/[productId]/page.tsx | Wrap detail screen in a relative h-screen container; type the toast state. |
| src/app/auctions/[auctionId]/page.tsx | Same relative wrapper; type the toast state. |
| src/app/auctions/[auctionId]/bidding-status/index.tsx | Add tabs (record vs ranking), per‑bidder ranking with expandable bids, sticky bottom button. |
| src/app/(main)/index.tsx | Add scroll‑direction driven hide/show for bottom nav. |
| src/app/(main)/home/page.tsx | Render MainLayout from the home route and wire all callbacks; defer theme read to effect. |
| src/app/page.tsx | Add isThemeModeReady gate, switch outer container to h-screen overflow-hidden, add a global toast layer. |
Comments suppressed due to low confidence (3)
src/components/wallet/DealitMoneyPanel.tsx:493
- When the user is at month=1 and taps the displayed "12월" (from
normalizeMonth(0)), or at month=12 and taps "1월" (fromnormalizeMonth(13)), onlymonthis updated andyearstays the same. The result is that the picker jumps to December/January of the same year instead of crossing the year boundary as visually implied. The wrap-around should also adjustdraftMonth.yearaccordingly (e.g., decrement when wrapping 0→12, increment when wrapping 13→1).
<MonthPickerColumn
values={[
normalizeMonth(draftMonth.month - 1),
draftMonth.month,
normalizeMonth(draftMonth.month + 1),
]}
selectedValue={draftMonth.month}
label={(value) => `${value}월`}
onSelect={(month) => setDraftMonth((prev) => ({ ...prev, month }))}
/>
src/components/wallet/DealitMoneyPanel.tsx:494
- The
MonthPickerColumnis rendered as a static list with three buttons (year-1/year/year+1, and month-1/month/month+1). The "selected" row in the middle still has anonClickthat callssetDraftMonthwith the same value, but the outer rows never advance the window beyond ±1 unless the user taps them one step at a time. There is also no way to pick a year more than one off, no scroll/swipe behavior, and tapping the wrapped month (e.g., 12 when current is 1) re-centers the column without moving the year. This is likely to confuse users who expect a wheel-picker-style interaction; consider clarifying the UX (either make it a true wheel picker, or render a longer fixed list / dropdown).
<div className="mt-8 grid grid-cols-2 items-center gap-4 px-8 text-center">
<MonthPickerColumn
values={[
draftMonth.year - 1,
draftMonth.year,
draftMonth.year + 1,
]}
selectedValue={draftMonth.year}
label={(value) => `${value}년`}
onSelect={(year) => setDraftMonth((prev) => ({ ...prev, year }))}
/>
<MonthPickerColumn
values={[
normalizeMonth(draftMonth.month - 1),
draftMonth.month,
normalizeMonth(draftMonth.month + 1),
]}
selectedValue={draftMonth.month}
label={(value) => `${value}월`}
onSelect={(month) => setDraftMonth((prev) => ({ ...prev, month }))}
/>
</div>
src/components/wallet/DealitMoneyPanel.tsx:499
h-13is not part of Tailwind's default spacing scale (the defaults areh-12,h-14, ...). Unless the project extends Tailwind's theme with a13step, this class will be silently dropped and the confirm button will fall back to its content height. Please verify Tailwind config or replace with a supported value (e.g.,h-12/h-14or an arbitrary value likeh-[52px]).
className="mt-10 h-13 w-full rounded-xl bg-[#F64257] text-base font-black text-white shadow-sm"
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <div className="absolute bottom-0 left-0 right-0 z-20 border-t border-gray-50 bg-white p-6"> | ||
| <button | ||
| onClick={onBack} | ||
| className="w-full h-14 bg-gray-900 text-white font-bold rounded-2xl hover:bg-black transition-colors" | ||
| className="w-full h-14 bg-gray-900 text-white font-bold rounded-2xl shadow-[0_8px_18px_rgba(15,23,42,0.18)] hover:bg-black transition-colors" | ||
| > |
| useEffect(() => { | ||
| if (!isThemeModeReady) { | ||
| return; | ||
| } | ||
|
|
||
| writeStoredThemeMode(themeMode); | ||
| }, [themeMode]); | ||
| }, [isThemeModeReady, themeMode]); |
| useEffect(() => { | ||
| setIsBottomNavVisible(true); | ||
| lastScrollTopRef.current = 0; | ||
|
|
||
| const handleScroll = (event: Event) => { | ||
| const target = event.target as HTMLElement | Document | null; | ||
| const scrollElement = | ||
| target instanceof Document | ||
| ? target.scrollingElement | ||
| : target instanceof HTMLElement | ||
| ? target | ||
| : null; | ||
|
|
||
| if (!scrollElement) { | ||
| return; | ||
| } | ||
|
|
||
| const nextScrollTop = scrollElement.scrollTop; | ||
| const previousScrollTop = lastScrollTopRef.current; | ||
| const delta = nextScrollTop - previousScrollTop; | ||
|
|
||
| if (nextScrollTop <= 12 || delta < -8) { | ||
| setIsBottomNavVisible(true); | ||
| } else if (delta > 8) { | ||
| setIsBottomNavVisible(false); | ||
| } | ||
|
|
||
| lastScrollTopRef.current = Math.max(0, nextScrollTop); | ||
| }; | ||
|
|
||
| window.addEventListener('scroll', handleScroll, true); | ||
| return () => window.removeEventListener('scroll', handleScroll, true); | ||
| }, [displayTab]); |
| onSalesManagementClick={() => router.push("/mypage/sales-management")} | ||
| onNotificationSettingsClick={() => router.push("/notifications/settings")} | ||
| onChatClick={(id) => router.push(`/chats/${id}`)} | ||
| onCategoryResetClick={() => router.push("/category-selection?mode=edit")} |
| {modal === "history" && ( | ||
| <WalletHistoryScreen | ||
| ledgers={ledgers} | ||
| isLoading={isHistoryLoading} | ||
| selectedMonth={historyMonth} | ||
| isMonthPickerOpen={isMonthPickerOpen} | ||
| onClose={closeModal} | ||
| onPreviousMonth={() => setHistoryMonth(shiftMonth(historyMonth, -1))} | ||
| onNextMonth={() => setHistoryMonth(shiftMonth(historyMonth, 1))} | ||
| onOpenMonthPicker={() => setIsMonthPickerOpen(true)} | ||
| onCloseMonthPicker={() => setIsMonthPickerOpen(false)} | ||
| onSelectMonth={(nextMonth) => { | ||
| setHistoryMonth(nextMonth); | ||
| setIsMonthPickerOpen(false); | ||
| }} | ||
| /> |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🚀 Summary
ui수정 및 경매 상세 탭 추가 했습니다.
✨ Description
/home진입 및 새로고침 시 url미스매치 문제와 하단 네비게이션 누락 문제가 발생하지 않도록 테마 초기화와 라우트 렌더링 구조를 수정했습니다.전액 입력버튼을 추가했습니다.TEMP_CHARGE표시를딜릿머니 충전으로 변경했습니다.입찰 기록/입찰 순위탭을 추가했습니다.확인버튼을 하단 고정 버튼으로 변경하고 버튼 자체에 그림자를 적용했습니다.🎲 Issue Number
close #97