Skip to content

[🐛Fix] QA(8/29) 반영#202

Merged
dkslel1225 merged 7 commits into
devfrom
195-fix/reflect-feedback
Sep 3, 2025
Merged

[🐛Fix] QA(8/29) 반영#202
dkslel1225 merged 7 commits into
devfrom
195-fix/reflect-feedback

Conversation

@wnsdn00

@wnsdn00 wnsdn00 commented Sep 3, 2025

Copy link
Copy Markdown
Collaborator

✨ 요약

  • QA(8/29) 반영

📝 상세 내용

  • 헤더 이미지 클릭 시 검색 조건 초기화
  • 예약 현황(신청/완료한 건 승인/거절 탭) 나오지 않는 현상
  • (헤더 로그인/회원가입/서치 드롭다운) cursor-pointer 적용
  • 드롭다운 선택 시 닫히도록(체험 드롭다운, 서치 드롭다운)
  • 예약 승인,거절 후 my/reservation 페이지 관련 캐시 업데이트 (현재 새로고침 해야 업데이트O)
  • 다른 날짜를 선택하면, 모달에 이전날짜의 예약데이터가 남아 있는 순간이 있는데, selectedDate 변경 시 예약데이터 리셋
  • 여러 시간대의 예약 내역이 다 보이지 않음(시간 별 예약 내역이 보이도록 수정)
  • reserve-calendar/page내 useQuery사용하는 구조로 변경
  • searchStore 생성해서 전역 상태로 관리하도록 수정

✅ 체크리스트

  • 브랜치 네이밍 컨벤션을 준수했습니다
  • 커밋 컨벤션을 준수했습니다
  • 코드가 프로젝트의 스타일 가이드라인을 준수합니다

💡 추가 수정 사항

  • 날짜 빨간점 반응형 스타일 적용
  • 모바일일때 ‘예약현황’ sad laptop 이미지 가운데 정렬
  • 검색창, 예약현황-체험선택 등의 드롭다운 선택지 스타일(텍스트 사이즈 up, 구분선 추가, hover스타일 적용)
  • 모바일 일때 서치바 반응형 적용

Summary by CodeRabbit

  • New Features
    • 예약 캘린더가 최대 12개월 분량을 한 번에 불러오고, 가장 이른 예약일을 기준으로 캘린더 초기 월/연도를 설정합니다.
    • 날짜 선택 시 해당 날짜의 예약만 표시하며, 날짜별로 여러 스케줄을 선택해 상세 예약을 확인할 수 있습니다.
    • 활동 검색어·지역·카테고리 상태가 전역으로 공유되어 페이지 이동 시 유지됩니다.
    • 로고 클릭 시 검색 상태를 초기화한 뒤 활동 목록으로 이동합니다.
    • 드롭다운에서 옵션 선택 시 즉시 닫힙니다.
  • Style
    • 드롭다운 버튼과 옵션에 클릭 커서가 추가되었습니다.

@wnsdn00 wnsdn00 linked an issue Sep 3, 2025 that may be closed by this pull request
@coderabbitai

coderabbitai Bot commented Sep 3, 2025

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

Walkthrough

React Query 훅(useReservationsByActivity)으로 최대 12개월 예약을 집계하고, 날짜 클릭 시 해당 일자 예약에서 scheduleId 배열을 추출해 상태로 관리하도록 캘린더 데이터 흐름을 변경했으며, 검색 상태를 Zustand(store)로 통합하고 드롭다운에 close 콜백 패턴을 도입했습니다.

Changes

Cohort / File(s) Summary
Reserve Calendar aggregation & per-day selection
src/app/my/reserve-calendar/page.tsx
React Query 기반 useReservationsByActivity(activityId, month) 추가(최대 12개월 월별 조회, allReservations·earliestDate 반환). 날짜 클릭 시 해당 일자 API로 조회해 unique scheduleId[] 저장. 기존 월별/일별 인라인 fetch 로직 제거 및 선택 scheduleId 타입을 배열로 변경.
Reservation content filtering
src/features/reservation-state/components/content-reservation.tsx
DisplayReservationdate: string 추가. 선택 날짜와 일치하는 예약만 필터링해 상태와 타임슬롯을 구성하도록 변경(날짜 기준 필터링 적용).
Activities search centralization
src/features/activities/components/search.tsx
키워드/지역/카테고리 로컬 상태 제거, useSearchStore로 이전. setKeyword prop 제거. 드롭다운 옵션 선택 시 store setter 호출 후 close() 호출하도록 변경. UI에 cursor-pointer 추가.
Dropdown sort close via render-prop
src/features/activities/components/all-activities.tsx
정렬 드롭다운을 render-prop(close) 패턴으로 전환; 옵션 선택 시 정렬 처리 후 close() 호출.
Search Zustand store (new)
src/features/activities/libs/stores/searchStore.ts
useSearchStore 추가: keyword/region/categorysetKeyword/setRegion/setCategory/reset 제공(초기값 빈 문자열).
Header search reset on logo
src/shared/components/header/header.tsx
로고 클릭 시 기본 네비게이션 방지 후 resetSearch() 호출하고 router.push('/activities')로 이동. hydration 가드 변경(비수화 시 placeholder div 렌더). 비로그인 버튼에 cursor-pointer 추가.

Sequence Diagram(s)

sequenceDiagram
  participant U as 사용자
  participant RC as ReserveCalendarPage
  participant Q as useReservationsByActivity (React Query)
  participant API as getReservationsByMonthApi
  participant CR as ContentReservation

  U->>RC: 액티비티 선택
  RC->>Q: selectedActivityId, month로 쿼리 시작
  loop 최대 12개월
    Q->>API: 월별 예약 조회
    API-->>Q: MonthReservations
  end
  Q-->>RC: { allReservations, earliestDate }
  RC->>RC: 캘린더 데이터 및 month/year 업데이트

  U->>RC: 특정 날짜 클릭
  RC->>API: 해당 날짜 예약 조회
  API-->>RC: 일자 예약 리스트
  RC->>RC: unique scheduleId[] 추출 및 저장
  RC->>CR: scheduleId[] 전달
Loading
sequenceDiagram
  participant U as 사용자
  participant S as Search 컴포넌트
  participant Z as useSearchStore (Zustand)
  participant H as Header

  U->>S: 키워드/지역/카테고리 입력
  S->>Z: setKeyword/setRegion/setCategory
  U->>S: 드롭다운 옵션 선택
  S->>S: 선택 후 close() 호출

  U->>H: 로고 클릭
  H->>Z: reset()
  H->>H: router.push('/activities')
Loading
sequenceDiagram
  participant U as 사용자
  participant A as AllActivities
  participant D as Dropdown (render-prop)

  U->>A: 정렬 드롭다운 열기
  A->>D: children(fn close)
  U->>D: 정렬 옵션 클릭
  D->>A: handleSortChange()
  D->>D: close()
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • [🐛Fix] 8/29 피드백 반영 #195 — 헤더의 검색 리셋, 드롭다운 자동 닫힘 패턴과 예약 캘린더/모달 데이터 일관성 문제를 다루는 점이 본 변경과 목적적으로 겹칩니다.

Possibly related PRs

Suggested reviewers

  • dkslel1225
  • Hyunbara

Poem

햇빛 따라 훅이 달력을 모으네,
날짜를 톡 누르면 일정들이 줄지어,
드롭다운은 살며시 닫히고, 로고는 검색을 비운다.
토끼는 깡총—예약도 깡총, 오늘만 반짝! 🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7f829dc and 3244ee5.

📒 Files selected for processing (1)
  • src/shared/components/header/header.tsx (5 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 195-fix/reflect-feedback

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@wnsdn00 wnsdn00 self-assigned this Sep 3, 2025
@wnsdn00 wnsdn00 requested review from 0Hyunn and dkslel1225 September 3, 2025 08:01
@wnsdn00 wnsdn00 added 🐛 bug 에러 해결 ♻️ refactor 코드 리팩토링 labels Sep 3, 2025
@dkslel1225 dkslel1225 merged commit ae9b994 into dev Sep 3, 2025

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (4)
src/features/activities/libs/stores/searchStore.ts (1)

13-21: 입력 정규화(트림)로 상태 일관성 확보

검색값 앞뒤 공백으로 인한 불필요한 파라미터 변형을 막기 위해 setter에서 trim을 적용하는 것을 권장합니다.

-  setKeyword: (value) => set({ keyword: value }),
-  setRegion: (value) => set({ region: value }),
-  setCategory: (value) => set({ category: value }),
+  setKeyword: (value) => set({ keyword: value.trim() }),
+  setRegion: (value) => set({ region: value.trim() }),
+  setCategory: (value) => set({ category: value.trim() }),

선택 사항: 초기 상태를 상수로 분리해 reset 재사용성을 높일 수 있습니다.

const initialState = { keyword: '', region: '', category: '' } as const;
// ...
reset: () => set(initialState),
src/features/activities/components/search.tsx (3)

23-25: Zustand 사용 패턴 개선 및 URL→스토어 동기화 제안

  • 전체 스토어 구독 대신 셀렉터를 사용하면 불필요한 리렌더를 줄일 수 있습니다.
  • /activities?keyword=... 등으로 진입 시 검색창에 현재 쿼리가 비어 보이는 불일치를 방지하려면 초기 마운트에서 URL 파라미터를 스토어로 동기화하세요.

셀렉터 사용 예:

const keyword = useSearchStore((s) => s.keyword);
const setKeyword = useSearchStore((s) => s.setKeyword);
const region = useSearchStore((s) => s.region);
const setRegion = useSearchStore((s) => s.setRegion);
const category = useSearchStore((s) => s.category);
const setCategory = useSearchStore((s) => s.setCategory);

URL→스토어 1회 동기화 예:

useEffect(() => {
  const k = searchParams.get('keyword') ?? '';
  const r = searchParams.get('region') ?? '';
  const c = searchParams.get('category') ?? '';
  // 이미 값이 있는 경우는 덮어쓰지 않도록 가드
  if (!keyword && (k || r || c)) {
    setKeyword(k);
    setRegion(r);
    setCategory(c);
  }
  // eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // 최초 진입시에만

원하시면 제가 반영 PR 패치를 작성해 드리겠습니다.


110-124: 옵션 선택 시 닫힘 처리: 좋습니다. 접근성 힌트 추가 제안

현재 동작은 적절합니다. 선택 상태 노출을 위해 aria-pressed를 추가하면 보조기기 호환성이 좋아집니다.

-                <button
+                <button
                   key={option}
                   type="button"
                   className={optionBtnClass}
+                  aria-pressed={region === option}
                   onClick={() => {
                     setRegion(option);
                     close();
                   }}
                 >

149-163: 카테고리 옵션도 동일하게 접근성 속성 적용 권장

region과 동일하게 aria-pressed를 추가하면 좋습니다.

-                <button
+                <button
                   key={option}
                   type="button"
                   className={optionBtnClass}
+                  aria-pressed={category === option}
                   onClick={() => {
                     setCategory(option);
                     close();
                   }}
                 >
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 9b8b1d4 and 7f829dc.

📒 Files selected for processing (6)
  • src/app/my/reserve-calendar/page.tsx (6 hunks)
  • src/features/activities/components/all-activities.tsx (1 hunks)
  • src/features/activities/components/search.tsx (4 hunks)
  • src/features/activities/libs/stores/searchStore.ts (1 hunks)
  • src/features/reservation-state/components/content-reservation.tsx (3 hunks)
  • src/shared/components/header/header.tsx (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (6)
src/features/reservation-state/components/content-reservation.tsx (2)
src/features/booking-detail/components/booking-card.tsx (1)
  • BookingCardProps (42-133)
src/shared/components/calendar/components/calendar-with-reservations.tsx (1)
  • reservationArray (38-195)
src/features/activities/components/all-activities.tsx (2)
src/features/activities/libs/constants/activitiesConstants.ts (1)
  • SORT_OPTIONS (19-23)
src/features/activityId/components/owner-drop-down.tsx (3)
  • close (46-68)
  • router (49-52)
  • ownerId (11-90)
src/features/activities/components/search.tsx (3)
src/features/activities/libs/stores/searchStore.ts (1)
  • useSearchStore (13-21)
src/features/activities/components/search-result.tsx (1)
  • searchParams (10-89)
src/app/activities/page-content.tsx (1)
  • searchParams (25-62)
src/shared/components/header/header.tsx (1)
src/features/activities/libs/stores/searchStore.ts (1)
  • useSearchStore (13-21)
src/features/activities/libs/stores/searchStore.ts (3)
src/features/my/my-activities/lib/stores/useActivityIdStore.ts (2)
  • ActivityIdState (2-5)
  • set (8-11)
src/features/activityId/libs/stores/useScheduleIdStore.ts (1)
  • set (10-13)
src/shared/components/calendar/libs/stores/useCalendarStore.ts (1)
  • set (20-37)
src/app/my/reserve-calendar/page.tsx (6)
src/shared/types/reservation.ts (1)
  • Reservation (12-27)
src/shared/components/calendar/libs/types/data.ts (1)
  • MonthReservations (1-15)
src/features/activities/libs/api/getReserveMonthApi.ts (1)
  • getReservationsByMonthApi (17-46)
src/features/auth/stores/useAuthStore.ts (1)
  • useAuthStore (26-66)
src/features/activities/libs/api/getReserveDayApi.ts (1)
  • getReservations (1-23)
src/shared/components/calendar/components/calendar-with-reservations.tsx (1)
  • reservationArray (38-195)
🔇 Additional comments (14)
src/features/activities/components/all-activities.tsx (1)

87-108: 드롭다운 render-prop 전환으로 선택 즉시 닫힘 UX 정착: 좋습니다.

close 콜백을 통해 정렬 옵션 선택 후 드롭다운을 닫는 흐름이 일관되고 명확합니다.

src/shared/components/header/header.tsx (4)

10-10: 검색 스토어 연동: 적절합니다.

헤더에서 전역 검색 상태를 리셋하는 의도가 명확합니다.


31-31: reset 셀렉터 사용: 적절합니다.

필요한 액션만 셀렉트하여 불필요한 리렌더를 줄입니다.


132-132: 로그인 버튼 커서 포인터 적용: OK

클릭 가능성 시각화가 개선되었습니다.


143-143: 회원가입 버튼 커서 포인터 적용: OK

일관된 인터랙션 피드백입니다.

src/features/activities/components/search.tsx (2)

75-75: 드롭다운 트리거에 cursor-pointer 추가: OK

클릭 가능성 피드백이 개선되었습니다.


81-81: 옵션 버튼에 cursor-pointer 추가: OK

일관된 호버/포인터 경험입니다.

src/features/reservation-state/components/content-reservation.tsx (3)

74-78: 날짜 필터링 로직이 정확합니다

선택한 날짜와 일치하는 예약만 필터링하여 onlySelectedDate에 저장하고 이를 상태로 설정하는 로직이 올바르게 구현되었습니다.


80-86: 시간 슬롯 생성 로직 개선됨

날짜별로 필터링된 예약 데이터(onlySelectedDate)를 기반으로 시간 슬롯을 생성하도록 변경되어, 선택한 날짜의 시간대만 정확하게 표시됩니다.


211-215: 드롭다운 옵션 렌더링 일관성 개선

timeSlot 변수명을 slot으로 변경하여 코드의 일관성이 향상되었습니다.

src/app/my/reserve-calendar/page.tsx (4)

37-72: React Query 훅 구현이 효율적입니다

useReservationsByActivity 훅이 최대 12개월간의 예약 데이터를 집계하여 반환하는 로직이 잘 구현되었습니다. 가장 빠른 날짜를 찾으면 즉시 중단하는 최적화도 적용되어 있습니다.


130-155: 날짜 클릭 핸들러의 스케줄 ID 처리 개선

선택한 날짜의 예약을 조회하여 고유한 스케줄 ID들을 추출하는 로직이 올바르게 구현되었습니다. 에러 처리와 빈 배열 초기화도 적절합니다.


269-269: scheduleId prop 타입 변경 확인됨

ContentReservation 컴포넌트에 전달되는 scheduleId가 배열로 변경되어 여러 시간대의 예약을 올바르게 처리할 수 있게 되었습니다.


158-172: 무한 루프 발생하지 않음 확인됨
setYearsetMonth는 Zustand store에서 생성된 안정적 레퍼런스를 가지므로, 의존성 배열에 포함되어도 effect는 data 변경 시에만 실행됩니다.

Comment on lines +90 to +97
<button
key={value}
onClick={() => {
handleSortChange(
value as 'latest' | 'price_asc' | 'price_desc',
);
close();
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

button 기본 type 지정 및 불필요한 타입 단언 제거 제안

  • form 문맥에서의 암묵적 submit 방지를 위해 type="button"을 명시해 주세요.
  • value as 'latest' | 'price_asc' | 'price_desc' 캐스트는 상수 타입을 제대로 선언하면 불필요합니다.

[issetential_refactor_typo]

다음 diff로 버튼 type을 추가하세요:

-                <button
+                <button type="button"
                   key={value}
                   onClick={() => {
-                    handleSortChange(
-                      value as 'latest' | 'price_asc' | 'price_desc',
-                    );
+                    handleSortChange(value);
                     close();
                   }}

추가로, 캐스트 제거를 위해 상수에 literal 타입을 부여하세요(다른 파일 수정):

activitiesConstants.ts

export const SORT_OPTIONS = [
  { label: '최신순', value: 'latest' },
  { label: '낮은 가격순', value: 'price_asc' },
  { label: '높은 가격순', value: 'price_desc' },
] as const;

export type SortValue = typeof SORT_OPTIONS[number]['value'];

그리고 본 컴포넌트에서 상태와 핸들러의 타입을 정교화하면 캐스트가 사라집니다:

const [selectedSort, setSelectedSort] = useState<SortValue>('latest');
const handleSortChange = (value: SortValue) => { ... };

Comment on lines +47 to +55
<Link
href="/activities"
className="flex items-center gap-3"
onClick={(e) => {
e.preventDefault();
resetSearch();
router.push('/activities');
}}
>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

로고 클릭 시 기본 동작 방지로 새 탭 열기 불가(UX 회귀) — 수정 권장

e.preventDefault() + router.push()로 인해 Cmd/Ctrl+Click, 마우스 중클릭 등 새 탭 열기가 막힙니다. Link 고유 내비게이션은 유지하고, 보조키/중클릭 시에는 리셋을 수행하지 않도록 가드하세요.

-          <Link
+          <Link
             href="/activities"
             className="flex items-center gap-3"
-            onClick={(e) => {
-              e.preventDefault();
-              resetSearch();
-              router.push('/activities');
-            }}
+            onClick={(e) => {
+              // 보조키/중클릭은 현재 탭 상태를 건드리지 않음
+              if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;
+              resetSearch();
+              // Link가 라우팅을 처리하므로 preventDefault/router.push 불필요
+            }}
           >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Link
href="/activities"
className="flex items-center gap-3"
onClick={(e) => {
e.preventDefault();
resetSearch();
router.push('/activities');
}}
>
<Link
href="/activities"
className="flex items-center gap-3"
onClick={(e) => {
// 보조키/중클릭은 현재 탭 상태를 건드리지 않음
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;
resetSearch();
// Link가 라우팅을 처리하므로 preventDefault/router.push 불필요
}}
>
🤖 Prompt for AI Agents
In src/shared/components/header/header.tsx around lines 47 to 55, the current
onClick handler calls e.preventDefault() and router.push(), which blocks
Cmd/Ctrl+Click and middle‑click new tab behavior; change the handler to allow
default Link behavior and only call resetSearch() for a plain left click (guard
with e.button === 0 and !e.metaKey && !e.ctrlKey && !e.shiftKey && !e.altKey),
and remove the preventDefault() and router.push() calls so that modifier/new‑tab
navigation works while still resetting search on a normal click.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 bug 에러 해결 ♻️ refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[🐛Fix] 8/29 피드백 반영

2 participants