Skip to content

Feat/#51 frontend UI batch#56

Open
johe00123 wants to merge 3 commits into
mainfrom
feat/#51-frontend-ui-batch
Open

Feat/#51 frontend UI batch#56
johe00123 wants to merge 3 commits into
mainfrom
feat/#51-frontend-ui-batch

Conversation

@johe00123

Copy link
Copy Markdown
Contributor

📢 기능 설명

필요시 실행결과 스크린샷 첨부

연결된 issue

연결된 issue를 자동을 닫기 위해 아래 {이슈넘버}를 입력해주세요.

close #{이슈넘버}

✅ 체크리스트

  • PR 제목 규칙 잘 지켰는가?
  • 추가/수정사항을 설명하였는가?
  • 이슈넘버를 적었는가?

johe00123 added 2 commits May 17, 2026 23:32
백엔드는 지원하지만 프론트에서 노출되지 않던 기능들을 추가하고,
가로 스크롤 UX 개선을 위한 드래그 스크롤을 도입.

- 빈자리 알림 시간대 선택 UI 추가 (#51)
  매장 상세에서 시간 슬롯 상태에 따라 진입 버튼/모달 헤더를 3-way로
  분기, 만석 슬롯에 점선 테두리 + 종 아이콘 적용

- 카테고리 페이지 지역 필터 드롭다운 추가 (#52)
  25개 서울 자치구 드롭다운 추가, 카테고리와 독립 동작, URL 파라미터
  동기화

- 가로 드래그 스크롤 기능 추가 (#53)
  useDragScroll 커스텀 훅으로 마우스 클릭+드래그 스크롤 지원,
  카테고리 탭과 14일 날짜 스트립에 적용
- 진입 버튼 라벨 조건 단순화 (분기 4개 → 3개)
- useDragScroll의 offsetLeft 계산 제거 (delta 산출에 불필요)
@vercel

vercel Bot commented May 18, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
catcheat Ready Ready Preview, Comment May 18, 2026 5:42am

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a district-based filtering system on the category page and a new useDragScroll hook to enable mouse-drag horizontal scrolling for UI components. The store detail page has been updated with logic to handle various reservation states, including "vacancy notifications" for fully booked time slots. Review feedback focuses on optimizing performance via useCallback, improving the robustness of query parameter parsing for empty strings, addressing a potential UX dead-end in the reservation flow, and refactoring complex conditional styling for better maintainability.

Comment thread src/app/category/page.tsx Outdated
'use client';

import { Suspense, useEffect, useRef } from 'react';
import { Suspense, useEffect, useRef, useState } from 'react';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Add useCallback to the React imports to support memoizing the click handlers in the component.

Suggested change
import { Suspense, useEffect, useRef, useState } from 'react';
import { Suspense, useEffect, useRef, useState, useCallback } from 'react';

Comment thread src/app/category/page.tsx Outdated
Comment on lines +27 to +28
category: selectedCategory ?? undefined,
district: selectedDistrict ?? undefined,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using ?? undefined only handles null values. If the query parameter is present but empty (e.g., ?selected=&district=), searchParams.get returns an empty string, which might be sent to the API. Using || undefined ensures that empty strings are also treated as undefined, preventing unnecessary empty filter values from being sent to the backend.

Suggested change
category: selectedCategory ?? undefined,
district: selectedDistrict ?? undefined,
category: selectedCategory || undefined,
district: selectedDistrict || undefined,

Comment thread src/app/category/page.tsx Outdated
Comment on lines +59 to +66
const handleCategoryClick = (categoryEnum: string | null) => {
if (categoryEnum) {
router.push(`/category?selected=${categoryEnum}`);
} else {
router.push('/category');
}
router.push(buildHref(categoryEnum, selectedDistrict));
};

const handleDistrictClick = (districtEnum: string | null) => {
router.push(buildHref(selectedCategory, districtEnum));
setIsDistrictOpen(false);
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

These handlers should be wrapped in useCallback to maintain stable references. This is a best practice in React to prevent unnecessary re-renders of child components (like the buttons in the map loops) and to keep the dependency graph clean.

Suggested change
const handleCategoryClick = (categoryEnum: string | null) => {
if (categoryEnum) {
router.push(`/category?selected=${categoryEnum}`);
} else {
router.push('/category');
}
router.push(buildHref(categoryEnum, selectedDistrict));
};
const handleDistrictClick = (districtEnum: string | null) => {
router.push(buildHref(selectedCategory, districtEnum));
setIsDistrictOpen(false);
};
const handleCategoryClick = useCallback((categoryEnum: string | null) => {
router.push(buildHref(categoryEnum, selectedDistrict));
}, [router, selectedDistrict]);
const handleDistrictClick = useCallback((districtEnum: string | null) => {
router.push(buildHref(selectedCategory, districtEnum));
setIsDistrictOpen(false);
}, [router, selectedCategory]);

Comment on lines +412 to +416
{slotState === 'mixed'
? '예약 또는 빈자리 알림'
: (slotState === 'vacancy' || (slotState === 'unknown' && isSelectedFullyBooked))
? '시간대 선택하고 빈자리 알림 받기'
: '예약하기'}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

There is a potential UX issue when slotState is unknown but isSelectedFullyBooked is true. The button text suggests the user can 'Select a time and get a vacancy notification', but if times is empty (which causes the unknown state), the BottomSheet will show 'No available times' and the user won't be able to select anything. Consider handling the case where no time slots are available at all for a fully booked day to avoid leading the user into a dead end.

Comment thread src/app/stores/[id]/page.tsx Outdated
Comment on lines 486 to 492
className={`flex items-center justify-center gap-1 rounded-lg border py-2 text-sm font-medium ${
selectedTime === displayTime
? selectedTimeIsFull ? 'border-blue-500 bg-blue-50 text-blue-500' : 'border-orange-500 bg-orange-50 text-orange-500'
: isFull
? 'border-gray-100 bg-gray-50 text-gray-400'
? 'border-dashed border-gray-300 text-gray-600 hover:border-blue-500 hover:text-blue-500'
: 'border-gray-200 text-gray-700 hover:border-orange-500 hover:text-orange-500'
}`}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The nested ternary for the button's className is quite complex and hard to read. Consider refactoring this into a helper function or a set of variables to improve maintainability and clarity. For example, you could define a getButtonStyles function that returns the appropriate Tailwind classes based on selectedTime, displayTime, and isFull.

- 카테고리 페이지: 빈 문자열 쿼리 파라미터 처리를 위해 ?? → || 변경
- 카테고리 페이지: handleCategoryClick, handleDistrictClick을 useCallback으로 래핑
- 매장 상세 페이지: slotState가 unknown일 때 버튼 비활성화 처리
- 매장 상세 페이지: 시간 슬롯 버튼 스타일 분기를 getTimeButtonStyles 헬퍼 함수로 추출
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.

1 participant