Skip to content

fix: SP2 홈 화면 관련 바텀시트, 프로필 카드, 쿼리 등등 수정#420

Merged
bongtta merged 20 commits intodevelopfrom
fix/#419/fix-home
Apr 8, 2026
Merged

fix: SP2 홈 화면 관련 바텀시트, 프로필 카드, 쿼리 등등 수정#420
bongtta merged 20 commits intodevelopfrom
fix/#419/fix-home

Conversation

@bongtta
Copy link
Copy Markdown
Contributor

@bongtta bongtta commented Apr 8, 2026

#️⃣ Related Issue

Closes #419

☀️ New-insight

  • response.data를 일괄 반환하던 구조가 제거되어, 홈 화면과 관련된 query/mutation layer에서 엔드포인트별로 응답을 정규화하는 방식으로 수정했습니다.
  • query는 fallback 값을 반환해도 되지만, mutation은 fallback보다 throw로 흐름을 넘겨서 처리하는 방식으로 수정했습니다.

💎 PR Point

➊ 홈 경기 카드 및 매칭 카드 → 매칭 생성 CTA 흐름 연결

  • 홈 화면의 경기 일정 카드에서 메이트 만나기 버튼 클릭 시 바로 game 페이지로 이동하지 않고, 해당 경기의 매칭 리스트를 먼저 조회하도록 변경
  • 경기별 매칭 카드가 존재하지 않을 경우 MatchingCtaBottomSheet를 노출하고, 존재할 경우 game페이지로 이동하도록 분기
  • 이 과정에서 카드 내부에서 직접 navigate 하던 책임을 home 화면으로 끌어올려, 클릭-조건 판단-분기 흐름을 한 곳에서 제어하도록 정리

➋ CTA 바텀시트에서 바로 매칭 생성

  • CTA 바텀시트 이후 GameMatchBottomSheet로 한 번 더 이동하던 기존 흐름에서, 요구사항에 맞게 매칭 생성하기 버튼 클릭 시 바로 생성 mutation을 호출하도록 변경
  • 생성 성공 시 선택한 타입에 따라 성공 결과 페이지로 즉시 이동

➌ 결과 페이지 ui 수정

  • type=success일 때 single/group이 서로 다른 컴포넌트로 분기되던 흐름을 정리하고, 동일한 ui를 재사용하도록 구조 조정
  • 추후 필요없는 컴포넌트 정리 필요...

➍ query / mutation 응답 정규화

  • 매칭 관련 api들에 대해 공통적으로 응답 wrapper를 분기 처리
  • status/message/data 형태의 응답은 query/mutation 내부에서 data를 벗겨 반환하도록 수정
  • 엔드포인트 성격에 따라 핵심 데이터는 throw, 부가 데이터는 fallback으로 처리 기준 구분

++ 날짜 유지 로직은 우선 주석처리 해놓았고 나중에 수정할 예정입니다... (이거 때문에 자꾸 에러가 나서ㅜ.,ㅜ)

📸 Screenshot

스크린샷 2026-04-08 오후 5 12 10

Summary by CodeRabbit

  • 새로운 기능

    • 게임 선택 시 매칭 생성 플로우 추가(바텀시트 → 생성 → 결과 이동)
    • 홈페이지에 실시간 사용자 수 표시
  • 개선 사항

    • 게임 카드 클릭 동작을 외부 콜백으로 변경해 흐름 제어 유연화
    • 매칭 CTA 바텀시트 레이아웃 및 설명 노출 옵션 추가
    • 결과 화면의 개인/그룹 매칭 뷰를 통합
  • 문구/콘텐츠

    • 매칭 가이드 설명 문구 변경
    • 신규 안내 토스트 메시지 추가

@bongtta bongtta self-assigned this Apr 8, 2026
@bongtta bongtta requested a review from heesunee as a code owner April 8, 2026 08:12
@bongtta bongtta linked an issue Apr 8, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 8, 2026

Warning

Rate limit exceeded

@bongtta has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 15 minutes and 55 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 15 minutes and 55 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0d6ba1de-4149-4bcb-9318-84afea4f7d5f

📥 Commits

Reviewing files that changed from the base of the PR and between c21cdd5 and c1c321e.

📒 Files selected for processing (1)
  • src/shared/apis/user/user-queries.ts

Walkthrough

GameCard의 내부 라우팅을 제거하고 클릭을 상위로 위임하는 콜백 기반으로 재구성했습니다. 홈/게임 페이지에서 매칭 조회 후 MatchingCtaBottomSheet로 매칭 생성(Create Match) 흐름을 구현하고 API 엔드포인트 및 응답 처리 로직을 v3로 업데이트했습니다.

Changes

Cohort / File(s) Summary
Home UI & flow
src/pages/home/home.tsx, src/pages/home/components/game-list-section.tsx, src/pages/home/components/top-section.tsx
GameCard 클릭을 onGameClick 콜백으로 처리하도록 변경, selectedGame 상태/매칭 생성 흐름 추가, URL 날짜 동기화 제거, 사용자 수 조회 쿼리(USER_COUNT) 추가.
Game page & GameCard
src/pages/game/game.tsx, src/pages/game/components/game-card.tsx
GameCard에서 내부 네비게이션 제거 → onGameClick: (game) => void로 변경 및 matchCount? 필드 추가. 게임 페이지에 CREATE_MATCH 뮤테이션 및 MatchingCtaBottomSheet 연동, match detail prefetch 및 400/404 처리 도입.
Match API: queries & mutations
src/shared/apis/match/match-queries.ts, src/shared/apis/match/match-mutations.ts
API 응답이 ApiResponse<T> 유니온인 경우 해제/검증 로직 추가 및 기본값/404 처리 통일, CREATE_MATCH의 응답 검증 로직 보강.
User API & counts
src/shared/apis/user/user-queries.ts, src/shared/types/user-types.ts
USER_INFO/MATCH_CONDITION 응답 검증 패턴 추가 및 USER_COUNT 쿼리와 getUserCountResponse 타입 추가.
API endpoints, keys, types
src/shared/constants/api.ts, src/shared/constants/query-key.ts, src/shared/types/match-types.ts
POST_MATCH/GET_OPEN_CHAT_URL을 v3로 변경, USER_KEY.COUNT 추가, match 응답에 count/isGroup/leader 필드 추가.
BottomSheet & UI constants
src/shared/components/bottom-sheet/.../matching-cta-bottom-sheet.tsx, src/shared/components/bottom-sheet/bottom-sheet.tsx, src/pages/match/constants/matching.ts, src/pages/match/components/mate.tsx, src/pages/match/create/components/match-guide-section.tsx, src/shared/constants/header.ts
MatchingCtaBottomSheet에 showDescription? 추가 및 레이아웃 변경, 내부 콘텐츠 클릭으로 닫히지 않게 수정, 매칭 가이드 텍스트 상수 추가, Mate에 leader 전달, ROUTES.RESULT()NO_HEADER_PATHS에 추가.
Result page view
src/pages/result/result.tsx, src/pages/result/components/matching-created-view.tsx
그룹/단일 결과 뷰 통합 → MatchingCreatedView로 변경, mode에 따른 쿼리 분기 및 Card props/데이터 정규화 적용.
Other: constants/toasts
src/shared/constants/error-toast.ts
내가 만든 매칭 안내 토스트(MY_MATCH_TOAST_MESSAGE) 추가.

Sequence Diagram(s)

sequenceDiagram
    participant User as 사용자
    participant Home as 홈페이지
    participant GameList as GameListSection
    participant GameCard as GameCard
    participant API as Match API
    participant BottomSheet as MatchingCtaBottomSheet
    participant Result as 결과페이지

    User->>Home: 날짜 선택
    User->>GameList: 게임 카드 클릭
    GameList->>GameCard: onGameClick(game)
    GameCard->>Home: onGameClick 콜백 전달
    Home->>API: GAME_MATCH_LIST(game.id)
    API-->>Home: 매칭 목록 응답

    alt 매칭 없음
        Home->>BottomSheet: MatchingCtaBottomSheet 열기 (gameSchedule)
        User->>BottomSheet: 매칭 타입 선택 및 제출
        BottomSheet->>Home: onSubmit(type)
        Home->>API: CREATE_MATCH(matchType)
        API-->>Home: 생성된 매칭 ID
        Home->>Result: 결과 페이지로 네비게이션 (type=success&mode=...)
    else 매칭 존재
        Home->>Result: 기존 매칭으로 이동 (게임 상세)
    end

    Result-->>User: 생성/상세 결과 표시
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • heesunee
  • Dubabbi

"🐇 내가 클릭한 게임, 매칭으로 달려가요
콜백 하나로 흐름이 착착
API는 v3로 빛나고
바삭한 bottom-sheet가 열리면
결과까지 폴짝 도착해요 🎉"

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Pull request title accurately describes the main changes: home screen related bottom sheet, profile card, and query improvements.
Linked Issues check ✅ Passed Changes comprehensively address issue #419 objectives: home screen modifications including bottom sheet behavior, matching flow, query/mutation normalization, and navigation pattern restructuring.
Out of Scope Changes check ✅ Passed All changes directly support the home screen fixes: component API updates, query/mutation handlers, endpoint versions, types, and constants are all aligned with the stated objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/#419/fix-home

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 8, 2026

MATEBALL-STORYBOOK
⚾ Storybook 배포가 완료되었습니다!

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (4)
src/pages/match/components/mate.tsx (1)

61-62: 변수명에 값의 의미를 더 드러내 주세요.

leader만 보면 역할이나 객체처럼 읽히는데 실제 값은 닉네임 문자열입니다. leaderNickname처럼 풀어 두면 아래 MateHeader 전달부까지 맥락이 더 분명해지고, TODO도 훨씬 구체적으로 정리됩니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/match/components/mate.tsx` around lines 61 - 62, Rename the
ambiguous variable leader to leaderNickname (and update the TODO comment) so its
string nature is explicit; update every usage of leader across this component
(including the prop passed into MateHeader and any other places referencing
leader) to use leaderNickname, and ensure any TypeScript types or prop names
remain consistent or are updated if necessary to reflect the new name.
src/pages/match/create/components/match-guide-section.tsx (1)

2-4: 제목 상수명을 생성 상태에 맞춰 통일하세요.

현재 이 컴포넌트는 MATCHING_GUIDE_MESSAGE_TITLE(제목)과 MATCHING_GUIDE_CREATED_DESCRIPTION(설명)을 함께 사용하고 있습니다. 생성 완료 상태 전용 제목 상수(MATCHING_GUIDE_CREATED_TITLE)는 존재하지 않으며, 같은 패턴이 matching-created-view.tsx에도 반복되고 있습니다.

제목의 텍스트 내용("맞춤 매칭이 생성되었어요!")은 생성 상태에 맞지만, 상수 이름이 "MESSAGE"인 반면 설명은 "CREATED"로 네이밍 규칙이 일관되지 않습니다. 코드 가독성과 유지보수성을 위해:

  • MATCHING_GUIDE_MESSAGE_TITLEMATCHING_GUIDE_CREATED_TITLE로 이름 변경하거나
  • 설명(MATCHING_GUIDE_CREATED_DESCRIPTION)도 "MESSAGE" 패턴으로 통일하세요.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/match/create/components/match-guide-section.tsx` around lines 2 -
4, 현재 컴포넌트가 MATCHING_GUIDE_MESSAGE_TITLE(제목)과
MATCHING_GUIDE_CREATED_DESCRIPTION(설명)을 혼용해 네이밍이 일관되지 않습니다; 수정 방법은 하나를 선택해
적용하세요: (1) constants 파일에서 MATCHING_GUIDE_MESSAGE_TITLE을
MATCHING_GUIDE_CREATED_TITLE로 리네임하고 해당 상수를 이 파일의 import 및 모든 사용처(예:
matching-created-view.tsx)에서 교체하거나, (2) 반대로 MATCHING_GUIDE_CREATED_DESCRIPTION을
MATCHING_GUIDE_MESSAGE_DESCRIPTION으로 리네임해 제목 네이밍(MESSAGE 패턴)에 맞추고 모든 사용처를 함께
교체합니다; 또한 constants 모듈(export)과 모든 참조(import 식별자 MATCHING_GUIDE_MESSAGE_TITLE,
MATCHING_GUIDE_CREATED_DESCRIPTION)를 일관되게 업데이트하세요.
src/shared/apis/match/match-queries.ts (1)

41-61: 응답 언래핑 분기는 공통 헬퍼로 모아두는 편이 안전합니다.

같은 status/message/data 체크가 이 파일 전체에 반복되고, 같은 패턴이 src/shared/apis/match/match-mutations.tssrc/shared/apis/user/user-queries.ts에도 복사돼 있습니다. 한 군데라도 fallback/throw 기준이 어긋나기 시작하면 endpoint별 동작이 쉽게 갈라져서, 지금 단계에서 공통 유틸로 묶어두는 편이 유지보수에 유리합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/shared/apis/match/match-queries.ts` around lines 41 - 61, Extract the
repeated "status/message/data" unwrap logic into a shared helper (e.g.,
unwrapApiResponse<T>(res: T | ApiResponse<T>)) and replace the inline branch
inside queryFn in match-queries.ts (the block that checks typeof res ===
'object' && 'status' in res && 'message' in res && 'data' in res and throws when
!res.data) with a call to that helper so it consistently returns the inner data
or throws; then reuse that same helper from other files that currently duplicate
the pattern (match-mutations.ts and user-queries.ts) to ensure uniform
fallback/throw behavior across all endpoints that call get<...>(...) and expect
getSingleMatchResultResponse or similar payloads.
src/pages/game/game.tsx (1)

58-85: 매칭 생성 분기 로직은 공용 helper로 묶는 편이 안전합니다.

matchType/queryType/gaMatchType 계산, gaEvent('match_create_click'), 성공 후 결과 페이지 라우팅이 src/pages/home/home.tsx의 동일 흐름과 사실상 복제돼 있습니다. 이 로직은 이벤트명이나 mode 쿼리가 조금만 어긋나도 화면별 동작이 갈라지기 쉬워서 지금 시점에 공용 helper/hook으로 정리해 두는 편이 유지보수에 유리합니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/game/game.tsx` around lines 58 - 85, The matching creation logic in
handleMatchingCtaSubmit (calculating matchType/queryType/gaMatchType, calling
gaEvent('match_create_click'), invoking createMatchMutation.mutate, closing
sheet and navigating to ROUTES.RESULT) is duplicated with
src/pages/home/home.tsx; extract it into a shared helper or hook (e.g.,
useCreateMatch or createMatchHelper) that accepts the TabType (or explicit
role/mode), parsedGameId and createMatchMutation instance, computes the three
type values (using TAB_TYPES), fires gaEvent, calls createMatchMutation.mutate
with the same onSuccess behavior (setIsMatchingCtaBottomSheetOpen false/close
callback should be injectable), and returns a single function to be invoked from
both pages to ensure consistent event name, query param `mode`, and routing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/pages/game/game.tsx`:
- Around line 35-56: The click handler opens the matching bottom sheet even when
gameMatchData is not yet loaded; update handleCreateMatchClick to first guard
that gameMatchData exists (or that data is loaded) before using hasCreatedMatch
— if gameMatchData is falsy, early-return or show a loading/error state instead
of calling setIsMatchingCtaBottomSheetOpen; keep the existing
duplicate-prevention logic using hasCreatedMatch and showErrorToast
(HAS_DONE_TOAST_MESSAGE) when data is present.

In `@src/pages/home/components/top-section.tsx`:
- Around line 5-10: Banner shows "명" alone when data is undefined; update the
TopSection JSX that calls useQuery(userQueries.USER_COUNT()) so the count span
renders a safe fallback or the entire sentence only when data.userCnt exists.
Specifically, in the component (top-section.tsx) replace the inline
{data?.userCnt} with a conditional render or placeholder (e.g., data?.userCnt ??
'...') or wrap the whole sentence in a check like data?.userCnt ? <p>현재
<span>{data.userCnt}명</span>이 메이트를 찾고 있어요!</p> : <p>현재 메이트를 찾는 중입니다...</p> so
the UI doesn't show "명" alone.

In `@src/pages/home/home.tsx`:
- Around line 108-121: handleGameClick is vulnerable to race conditions and
unhandled rejections because it immediately sets selectedGame and fires
queryClient.fetchQuery(matchQueries.GAME_MATCH_LIST(...)) without in-flight
protection; update it to track the latest click (e.g., a ref/nonce like
latestClickedGameId or an AbortController token) before calling fetchQuery,
cancel or ignore any earlier responses by comparing the token when the promise
resolves, and wrap the fetchQuery call in try/catch to swallow/log errors so
rejections don't escape the handler; only call setIsMatchingCtaBottomSheetOpen
or navigate when the response token matches the latestClickedGameId and the
component is still mounted.

In `@src/pages/result/components/matching-created-view.tsx`:
- Around line 25-26: The analytics payload currently hardcodes match_type:
'group' in the chat_enter_click event (and similarly at the block around lines
52-55); update the payload construction to branch on the existing
isGroupMatching variable (derived from mode) so match_type is 'group' when
isGroupMatching is true and '1to1' (or the correct 1:1 identifier used
elsewhere) when false; ensure both the chat_enter_click payload and the other
analytics calls referenced (the block around where isGroupMatching is used) use
this conditional so 1:1 results are recorded correctly.

In `@src/shared/apis/match/match-queries.ts`:
- Around line 228-231: MATCH_MEMBERS and MATCH_MEMBERS_DETAIL are using the same
React Query key (MATCH_KEY.MEMBERS(matchId)) causing cache collisions; create a
distinct key MATCH_KEY.MEMBERS_DETAIL(matchId) and update the query definition
for MATCH_MEMBERS_DETAIL to use that new key instead of
MATCH_KEY.MEMBERS(matchId) so the two queryFns (MATCH_MEMBERS returning {
leader, results } and MATCH_MEMBERS_DETAIL returning { results }) have separate
cache entries; ensure any places that invalidate or refetch members-detail use
the new MATCH_KEY.MEMBERS_DETAIL symbol.

In `@src/shared/constants/api.ts`:
- Line 21: The UI currently uses the GET_USER_COUNT endpoint (constant
GET_USER_COUNT) whose type in src/shared/types/user-types.ts documents it as
total users, but top-section.tsx displays it as "currently looking" (userCnt),
causing mismatch; either (A) change the top-section.tsx copy to reflect "전체 가입자
수" and keep using GET_USER_COUNT/userCnt as-is, or (B) add a new endpoint/metric
for real-time waiting users and wire that into top-section.tsx (create a new
constant, a matching type in src/shared/types/user-types.ts, and replace userCnt
with the new value); update variable names and UI copy to unambiguously match
the chosen metric (e.g., totalUsers vs currentWaitingUsers).

---

Nitpick comments:
In `@src/pages/game/game.tsx`:
- Around line 58-85: The matching creation logic in handleMatchingCtaSubmit
(calculating matchType/queryType/gaMatchType, calling
gaEvent('match_create_click'), invoking createMatchMutation.mutate, closing
sheet and navigating to ROUTES.RESULT) is duplicated with
src/pages/home/home.tsx; extract it into a shared helper or hook (e.g.,
useCreateMatch or createMatchHelper) that accepts the TabType (or explicit
role/mode), parsedGameId and createMatchMutation instance, computes the three
type values (using TAB_TYPES), fires gaEvent, calls createMatchMutation.mutate
with the same onSuccess behavior (setIsMatchingCtaBottomSheetOpen false/close
callback should be injectable), and returns a single function to be invoked from
both pages to ensure consistent event name, query param `mode`, and routing.

In `@src/pages/match/components/mate.tsx`:
- Around line 61-62: Rename the ambiguous variable leader to leaderNickname (and
update the TODO comment) so its string nature is explicit; update every usage of
leader across this component (including the prop passed into MateHeader and any
other places referencing leader) to use leaderNickname, and ensure any
TypeScript types or prop names remain consistent or are updated if necessary to
reflect the new name.

In `@src/pages/match/create/components/match-guide-section.tsx`:
- Around line 2-4: 현재 컴포넌트가 MATCHING_GUIDE_MESSAGE_TITLE(제목)과
MATCHING_GUIDE_CREATED_DESCRIPTION(설명)을 혼용해 네이밍이 일관되지 않습니다; 수정 방법은 하나를 선택해
적용하세요: (1) constants 파일에서 MATCHING_GUIDE_MESSAGE_TITLE을
MATCHING_GUIDE_CREATED_TITLE로 리네임하고 해당 상수를 이 파일의 import 및 모든 사용처(예:
matching-created-view.tsx)에서 교체하거나, (2) 반대로 MATCHING_GUIDE_CREATED_DESCRIPTION을
MATCHING_GUIDE_MESSAGE_DESCRIPTION으로 리네임해 제목 네이밍(MESSAGE 패턴)에 맞추고 모든 사용처를 함께
교체합니다; 또한 constants 모듈(export)과 모든 참조(import 식별자 MATCHING_GUIDE_MESSAGE_TITLE,
MATCHING_GUIDE_CREATED_DESCRIPTION)를 일관되게 업데이트하세요.

In `@src/shared/apis/match/match-queries.ts`:
- Around line 41-61: Extract the repeated "status/message/data" unwrap logic
into a shared helper (e.g., unwrapApiResponse<T>(res: T | ApiResponse<T>)) and
replace the inline branch inside queryFn in match-queries.ts (the block that
checks typeof res === 'object' && 'status' in res && 'message' in res && 'data'
in res and throws when !res.data) with a call to that helper so it consistently
returns the inner data or throws; then reuse that same helper from other files
that currently duplicate the pattern (match-mutations.ts and user-queries.ts) to
ensure uniform fallback/throw behavior across all endpoints that call
get<...>(...) and expect getSingleMatchResultResponse or similar payloads.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: baa82b6d-e6e9-4215-baac-3ebf63380e1a

📥 Commits

Reviewing files that changed from the base of the PR and between a72259e and d069c02.

📒 Files selected for processing (20)
  • src/pages/game/components/game-card.tsx
  • src/pages/game/game.tsx
  • src/pages/home/components/game-list-section.tsx
  • src/pages/home/components/top-section.tsx
  • src/pages/home/home.tsx
  • src/pages/match/components/mate.tsx
  • src/pages/match/constants/matching.ts
  • src/pages/match/create/components/match-guide-section.tsx
  • src/pages/result/components/matching-created-view.tsx
  • src/pages/result/result.tsx
  • src/shared/apis/match/match-mutations.ts
  • src/shared/apis/match/match-queries.ts
  • src/shared/apis/user/user-queries.ts
  • src/shared/components/bottom-sheet/bottom-sheet.tsx
  • src/shared/components/bottom-sheet/matching-cta/matching-cta-bottom-sheet.tsx
  • src/shared/constants/api.ts
  • src/shared/constants/header.ts
  • src/shared/constants/query-key.ts
  • src/shared/types/match-types.ts
  • src/shared/types/user-types.ts
💤 Files with no reviewable changes (1)
  • src/shared/components/bottom-sheet/bottom-sheet.tsx

Comment thread src/pages/game/game.tsx
Comment thread src/pages/home/home.tsx
Comment on lines +108 to +121
const handleGameClick = async (game: GameCardItem) => {
setSelectedGame(game);

const gameMatchData = await queryClient.fetchQuery(matchQueries.GAME_MATCH_LIST(game.id));

const hasMatchCard = (gameMatchData.result ?? []).length > 0;

if (!hasMatchCard) {
setIsMatchingCtaBottomSheetOpen(true);
return;
}

navigate(ROUTES.GAME(dateStr, String(game.id)));
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

게임 카드 클릭은 in-flight 보호가 필요합니다.

지금은 클릭할 때마다 fetchQuery를 병렬로 날리고 바로 selectedGame을 바꿉니다. 그래서 A 요청이 늦게 돌아오면 B를 선택한 상태에서도 A 결과로 바텀시트가 열릴 수 있고, 요청이 실패하면 fetchQuery(...) rejection도 이벤트 핸들러 밖으로 빠집니다. 클릭 중 상태를 두거나 요청 토큰을 비교해서 마지막 선택에만 후속 동작을 적용해 주세요.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/home/home.tsx` around lines 108 - 121, handleGameClick is
vulnerable to race conditions and unhandled rejections because it immediately
sets selectedGame and fires
queryClient.fetchQuery(matchQueries.GAME_MATCH_LIST(...)) without in-flight
protection; update it to track the latest click (e.g., a ref/nonce like
latestClickedGameId or an AbortController token) before calling fetchQuery,
cancel or ignore any earlier responses by comparing the token when the promise
resolves, and wrap the fetchQuery call in try/catch to swallow/log errors so
rejections don't escape the handler; only call setIsMatchingCtaBottomSheetOpen
or navigate when the response token matches the latestClickedGameId and the
component is still mounted.

Comment thread src/pages/result/components/matching-created-view.tsx
Comment thread src/shared/apis/match/match-queries.ts
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages bot commented Apr 8, 2026

Deploying mateball-client with  Cloudflare Pages  Cloudflare Pages

Latest commit: 1c2edd2
Status: ✅  Deploy successful!
Preview URL: https://e905a2c8.mateball-client.pages.dev
Branch Preview URL: https://fix--419-fix-home.mateball-client.pages.dev

View logs

@MATEBALL MATEBALL deleted a comment from coderabbitai bot Apr 8, 2026
@MATEBALL MATEBALL deleted a comment from coderabbitai bot Apr 8, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/pages/result/components/matching-created-view.tsx (1)

99-105: imgUrl 정규화 로직이 방어적으로 구현되어 있습니다.

getSingleMatchResultResponseimgUrlstring이고 getGroupMatchResultResponsestring[]이기 때문에 런타임 정규화가 필요합니다. 현재 구현은 동작하지만, 이 정규화를 쿼리/API 레이어에서 처리하면 컴포넌트가 더 깔끔해집니다.

♻️ 쿼리 레이어에서 정규화하는 방안

match-queries.tsSINGLE_MATCH_RESULT 셀렉터에서 imgUrl을 배열로 정규화하면, 컴포넌트에서는 항상 string[] 타입으로 일관되게 사용할 수 있습니다:

// match-queries.ts의 SINGLE_MATCH_RESULT select 옵션에서
select: (data) => ({
  ...data,
  imgUrl: Array.isArray(data.imgUrl) ? data.imgUrl : [data.imgUrl],
}),

이렇게 하면 Line 100을 단순히 imgUrl={createdData.imgUrl}로 변경할 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/pages/result/components/matching-created-view.tsx` around lines 99 - 105,
Normalize imgUrl in the query layer instead of the component: update the
SINGLE_MATCH_RESULT selector in match-queries.ts to map the response to always
return imgUrl as string[] (e.g., replace imgUrl with Array.isArray(data.imgUrl)
? data.imgUrl : [data.imgUrl] in the select result), then simplify
matching-created-view.tsx to pass imgUrl={createdData.imgUrl} (remove the
runtime Array.isArray normalization) so the component always receives string[].
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/pages/result/components/matching-created-view.tsx`:
- Around line 99-105: Normalize imgUrl in the query layer instead of the
component: update the SINGLE_MATCH_RESULT selector in match-queries.ts to map
the response to always return imgUrl as string[] (e.g., replace imgUrl with
Array.isArray(data.imgUrl) ? data.imgUrl : [data.imgUrl] in the select result),
then simplify matching-created-view.tsx to pass imgUrl={createdData.imgUrl}
(remove the runtime Array.isArray normalization) so the component always
receives string[].

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 04572484-aa69-4554-b6bd-5ff913dbba58

📥 Commits

Reviewing files that changed from the base of the PR and between 3453899 and c21cdd5.

📒 Files selected for processing (5)
  • src/pages/game/game.tsx
  • src/pages/result/components/matching-created-view.tsx
  • src/shared/apis/match/match-queries.ts
  • src/shared/apis/user/user-queries.ts
  • src/shared/constants/query-key.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/shared/constants/query-key.ts
  • src/shared/apis/match/match-queries.ts
  • src/shared/apis/user/user-queries.ts
  • src/pages/game/game.tsx

* style: fotter color 수정 (#421)

* style: bottom navigation color 수정 (#421)

* style: 마이페이지 text color 수정 (#421)

* fix: 마이페이지 헤더 수정 (#421)

* fix: user query 수정 (#421)
@bongtta bongtta merged commit d98795b into develop Apr 8, 2026
5 checks passed
@bongtta bongtta deleted the fix/#419/fix-home branch April 8, 2026 16:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: 홈 화면을 수정합니다.

1 participant