[feature] 홍보 상세페이지에 행사 위치 지도를 추가한다#1621
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning
|
| Layer / File(s) | Summary |
|---|---|
지도 버블 텍스트 설정 가능화 frontend/src/components/map/InteractiveMapView/InteractiveMapView.tsx, frontend/src/components/map/MapModal/MapModal.tsx, frontend/src/components/map/NaverMap/NaverMap.tsx |
InteractiveMapViewProps와 MapModalProps에 bubbleText?: string을 추가하고 useNaverMap 호출 시 전달하도록 변경. NaverMap의 location 타입을 { lat: number; lng: number }로 단순화. |
위치 아이콘 SVG에서 React 컴포넌트로 마이그레이션 frontend/src/components/map/MapClubInfoCard/*, frontend/src/pages/ClubDetailPage/*, frontend/src/pages/ClubDetailPage/components/ClubProfileCard/* |
SVG를 ?react로 임포트해 <LocationIcon />로 렌더링하도록 변경하고, 관련 스타일에서 img 셀렉터를 svg로 전환해 크기/여백/색상을 조정. ClubDetailPage의 MapCard를 button으로 변경. |
PromotionMapSection 컴포넌트 및 타입 확장 frontend/src/types/promotion.ts, frontend/src/pages/PromotionPage/components/detail/PromotionMapSection/*, frontend/src/pages/PromotionPage/PromotionDetailPage.tsx |
PromotionArticle에 선택적 latitude/longitude 추가. PromotionMapSection을 구현해 좌표 존재 시 NaverMap을 렌더링하고 모달로 클럽 로고를 전달하며, 모달 열림 상태에 따라 useGetClubDetail를 조건 실행. |
프로모션 페이지 레이아웃 및 스타일 조정 frontend/src/pages/PromotionPage/components/detail/*, frontend/src/pages/PromotionPage/components/list/* |
CTA 패딩/마진, 이미지 갤러리 그라데이션 오프셋, 반응형 조건, 정보 섹션 패딩, CardMeta 아이콘 색상 등 스타일 값을 조정. |
useGetClubDetail 훅 시그니처 확장 frontend/src/hooks/Queries/useClub.ts |
useGetClubDetail(clubParam, options?) 시그니처로 확장하여 enabled, staleTime, gcTime을 외부에서 제어 가능하도록 변경. |
Sequence Diagram (PromotionMapSection 흐름):
sequenceDiagram
participant PromotionDetailPage
participant PromotionMapSection
participant NaverMap
participant useGetClubDetail
participant MapModal
PromotionDetailPage->>PromotionMapSection: article (latitude/longitude, location)
PromotionMapSection->>NaverMap: render({ lat, lng })
PromotionMapSection->>useGetClubDetail: fetch(clubId) [enabled when modal open]
useGetClubDetail-->>PromotionMapSection: clubDetail.logo
PromotionMapSection->>MapModal: openModal(clubLogo, location)
MapModal->>NaverMap: showInteractiveMap(bubbleText)
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related issues
- [feature] MOA-922 홍보 상세페이지에 행사 위치 지도를 추가한다 #1620: 프로모션 상세 페이지에 좌표 기반 지도 섹션 추가와 PromotionArticle 타입 확장 목표와 일치합니다.
Possibly related PRs
- Moadong/moadong#1260: useGetClubDetail 관련 시그니처·동작 변경과 연관됩니다.
- Moadong/moadong#1402: InteractiveMapView/MapModal의 bubbleText 전달 경로와 코드 레벨로 연관됩니다.
- Moadong/moadong#1483: PromotionArticle의 latitude/longitude 필드 추가 및 데이터 연계 관련 변경과 직접 연관됩니다.
Suggested reviewers
- oesnuj
- seongwon030
🚥 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 | PR 제목이 주요 변경 사항을 명확하게 설명하고 있습니다. 홍보 상세페이지에 행사 위치 지도 추가라는 핵심 기능 변경을 직관적으로 전달합니다. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing Touches
📝 Generate docstrings
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
- Create PR with unit tests
- Commit unit tests in branch
feature/#1620-promotion-detail-map-MOA-922
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.
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Code Review
This pull request introduces a map section (PromotionMapSection) to the promotion detail page to display event locations, makes the map bubble text customizable, and refactors the location icon into a React component across multiple files for better styling flexibility. Feedback on these changes suggests optimizing the useGetClubDetail query in the new map section by using the enabled option so that the API call is only triggered when the map modal is actually open, preventing unnecessary network requests.
| const [isMapModalOpen, setIsMapModalOpen] = useState(false); | ||
| const { data: clubDetail } = useGetClubDetail(`@${article.clubName}`); |
There was a problem hiding this comment.
PR 본문에서 언급해주신 것처럼, 동아리 로고 하나를 가져오기 위해 페이지가 로드될 때마다 항상 전체 동아리 상세 정보를 조회하는 것은 비효율적일 수 있습니다. 특히 위도/경도 정보가 없어 지도가 렌더링되지 않는 상황(return null)에서도 불필요하게 API 요청이 발생하게 됩니다.\n\n이를 개선하기 위해 useGetClubDetail 훅에 enabled 옵션을 추가(또는 이미 지원하는 경우 활용)하여, 모달이 실제로 열렸을 때만(isMapModalOpen) 데이터를 조회하도록 제한하는 것을 추천합니다. 이렇게 하면 불필요한 초기 API 호출을 방지하고 성능을 개선할 수 있습니다.
const [isMapModalOpen, setIsMapModalOpen] = useState(false);
const { data: clubDetail } = useGetClubDetail(`@${article.clubName}`, {
enabled: isMapModalOpen,
});
There was a problem hiding this comment.
백엔드에 필드를 늘리도록 요청하는것도 고민했는데, 좋은 것 같습니다! 수정했습니다. 0ea2663
✅ UI 변경사항 없음
전체 57개 스토리 · 22개 컴포넌트 |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
frontend/src/pages/PromotionPage/components/detail/PromotionClubCTA/PromotionClubCTA.styles.ts (1)
10-10: ⚡ Quick win패딩 단축 표기 사용을 권장합니다.
padding: 24px 20px 24px 20px는 상하 값이 동일하므로padding: 24px 20px로 단축할 수 있습니다.♻️ 제안하는 수정
- padding: 24px 20px 24px 20px; + padding: 24px 20px;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/pages/PromotionPage/components/detail/PromotionClubCTA/PromotionClubCTA.styles.ts` at line 10, The padding declaration in PromotionClubCTA.styles.ts uses a redundant four-value form; update the padding on the PromotionClubCTA style rule from "24px 20px 24px 20px" to the shortened equivalent "24px 20px" so top/bottom and left/right are preserved but the rule is simplified.frontend/src/pages/PromotionPage/components/detail/PromotionInfoSection/PromotionInfoSection.styles.ts (1)
9-9: ⚡ Quick win패딩 단축 표기 사용을 권장합니다.
padding: 24px 20px 0px 20px는 좌우 값이 동일하므로padding: 24px 20px 0px로 단축할 수 있습니다.♻️ 제안하는 수정
- padding: 24px 20px 0px 20px; + padding: 24px 20px 0px;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/pages/PromotionPage/components/detail/PromotionInfoSection/PromotionInfoSection.styles.ts` at line 9, In PromotionInfoSection.styles.ts update the padding declaration: replace the four-value form that repeats left/right with the three-value shorthand (top, horizontal, bottom) so the rule becomes equivalent but more concise; locate the padding line inside the PromotionInfoSection styles and apply the shorthand.frontend/src/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection.tsx (1)
16-16: ⚡ Quick win모달 오픈 시점에 맞춰 클럽 상세 조회를 지연해 주세요.
현재 Line 16에서 상세 조회가 항상 실행되어, 모달을 열지 않아도 로고 조회 비용이 발생합니다.
isMapModalOpen(또는 좌표 존재 + 오픈 상태) 기준으로 쿼리를 조건부 실행하는 쪽이 더 안전합니다.제안 diff
- const { data: clubDetail } = useGetClubDetail(`@${article.clubName}`); + const { data: clubDetail } = useGetClubDetail(`@${article.clubName}`, { + enabled: isMapModalOpen, + });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection.tsx` at line 16, The club detail query is always fired because useGetClubDetail is called unconditionally; update the call to only run when the map modal is open (or when coordinates exist + modal open). Modify the useGetClubDetail invocation (the call that currently uses `@${article.clubName}` and returns `clubDetail`) to be conditional—either pass a null/empty key when `isMapModalOpen` (and optionally `article.lat`/`article.lng`) is false, or use the hook's options (e.g., an enabled flag) so the query only executes when `isMapModalOpen` is true and the article.clubName is present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@frontend/src/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection.tsx`:
- Around line 1-54: Prettier reported formatting mismatches in
PromotionMapSection.tsx; run Prettier --write on this file (or your project) and
reformat the code around the PromotionMapSection component (including imports,
the location object, JSX return block, and MapModal props) so it matches the
repo's Prettier settings, then stage and commit the formatted file; ensure no
semantic changes to functions/components (PromotionMapSection, NaverMap,
MapModal) while applying only whitespace/format fixes.
- Around line 33-35: The clickable map wrapper Styled.MapCard currently opens
the modal via onClick only, blocking keyboard users; update the component so it
is keyboard-accessible by either replacing Styled.MapCard with a semantic
<button> or adding accessibility attributes and handlers: give Styled.MapCard
role="button", tabIndex={0}, aria-haspopup="dialog" (or aria-label if needed),
and implement an onKeyDown handler that listens for Enter and Space and calls
setIsMapModalOpen(true) (same action as the onClick that opens NaverMap modal);
ensure focus styles remain visible and that NaverMap remains a child of the
interactive element.
In `@frontend/src/pages/PromotionPage/PromotionDetailPage.tsx`:
- Line 12: Change the relative import for PromotionMapSection to use the project
path alias: replace the current
"./components/detail/PromotionMapSection/PromotionMapSection" import in
PromotionDetailPage.tsx with the alias-based path starting with "`@/`": import
PromotionMapSection from
'`@/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection`';
ensure you update only the import statement referencing the PromotionMapSection
symbol so it resolves via the configured src/* alias.
---
Nitpick comments:
In
`@frontend/src/pages/PromotionPage/components/detail/PromotionClubCTA/PromotionClubCTA.styles.ts`:
- Line 10: The padding declaration in PromotionClubCTA.styles.ts uses a
redundant four-value form; update the padding on the PromotionClubCTA style rule
from "24px 20px 24px 20px" to the shortened equivalent "24px 20px" so top/bottom
and left/right are preserved but the rule is simplified.
In
`@frontend/src/pages/PromotionPage/components/detail/PromotionInfoSection/PromotionInfoSection.styles.ts`:
- Line 9: In PromotionInfoSection.styles.ts update the padding declaration:
replace the four-value form that repeats left/right with the three-value
shorthand (top, horizontal, bottom) so the rule becomes equivalent but more
concise; locate the padding line inside the PromotionInfoSection styles and
apply the shorthand.
In
`@frontend/src/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection.tsx`:
- Line 16: The club detail query is always fired because useGetClubDetail is
called unconditionally; update the call to only run when the map modal is open
(or when coordinates exist + modal open). Modify the useGetClubDetail invocation
(the call that currently uses `@${article.clubName}` and returns `clubDetail`)
to be conditional—either pass a null/empty key when `isMapModalOpen` (and
optionally `article.lat`/`article.lng`) is false, or use the hook's options
(e.g., an enabled flag) so the query only executes when `isMapModalOpen` is true
and the article.clubName is present.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ba51bbbe-26c9-4904-8780-e79cd7f833a8
⛔ Files ignored due to path filters (1)
frontend/src/assets/images/icons/location_icon.svgis excluded by!**/*.svg
📒 Files selected for processing (17)
frontend/src/components/map/InteractiveMapView/InteractiveMapView.tsxfrontend/src/components/map/MapClubInfoCard/MapClubInfoCard.styles.tsfrontend/src/components/map/MapClubInfoCard/MapClubInfoCard.tsxfrontend/src/components/map/MapModal/MapModal.tsxfrontend/src/components/map/NaverMap/NaverMap.tsxfrontend/src/pages/ClubDetailPage/ClubDetailPage.styles.tsfrontend/src/pages/ClubDetailPage/ClubDetailPage.tsxfrontend/src/pages/ClubDetailPage/components/ClubProfileCard/ClubProfileCard.styles.tsfrontend/src/pages/ClubDetailPage/components/ClubProfileCard/ClubProfileCard.tsxfrontend/src/pages/PromotionPage/PromotionDetailPage.tsxfrontend/src/pages/PromotionPage/components/detail/PromotionClubCTA/PromotionClubCTA.styles.tsfrontend/src/pages/PromotionPage/components/detail/PromotionImageGallery/PromotionImageGallery.styles.tsfrontend/src/pages/PromotionPage/components/detail/PromotionInfoSection/PromotionInfoSection.styles.tsfrontend/src/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection.styles.tsfrontend/src/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection.tsxfrontend/src/pages/PromotionPage/components/list/PromotionCard/CardMeta/CardMeta.styles.tsfrontend/src/types/promotion.ts
| import PromotionDetailTopBar from './components/detail/PromotionDetailTopBar/PromotionDetailTopBar'; | ||
| import PromotionImageGallery from './components/detail/PromotionImageGallery/PromotionImageGallery'; | ||
| import PromotionInfoSection from './components/detail/PromotionInfoSection/PromotionInfoSection'; | ||
| import PromotionMapSection from './components/detail/PromotionMapSection/PromotionMapSection'; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
새로 추가한 import는 @/* 경로 별칭으로 통일해 주세요.
상대 경로 대신 별칭을 쓰면 리팩터링/이동 시 안정성이 좋아집니다.
제안 diff
-import PromotionMapSection from './components/detail/PromotionMapSection/PromotionMapSection';
+import PromotionMapSection from '`@/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection`';As per coding guidelines, Use path alias @/* mapped to src/* for imports.
📝 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.
| import PromotionMapSection from './components/detail/PromotionMapSection/PromotionMapSection'; | |
| import PromotionMapSection from '`@/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection`'; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/pages/PromotionPage/PromotionDetailPage.tsx` at line 12, Change
the relative import for PromotionMapSection to use the project path alias:
replace the current
"./components/detail/PromotionMapSection/PromotionMapSection" import in
PromotionDetailPage.tsx with the alias-based path starting with "`@/`": import
PromotionMapSection from
'`@/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection`';
ensure you update only the import statement referencing the PromotionMapSection
symbol so it resolves via the configured src/* alias.
답변 감사합니다 api에 있는 모든 필드를 사용하지 않아도 되는건 알고있었지만, 하나의 필드 사용을 위해 api를 호출하는건 비효율적인가라는 고민이 있었습니다. 필드를 하나만 쓰더라도 api 호출 자체가 한 번이면 비효율은 아니라는거군요. 이해했습니다! API 호출 횟수가 중요한 이유는 역시 서버 입장에서 요청마다 비용이 발생하기 때문이 아닐까요. 동시 사용자가 많아지면 그 비용이 배로 늘어나기 때문이라고 생각합니다. 모달을 열지 않았을때 API를 호출하는 것을 방지하는 것으로 이 문제를 조금 완화할 수 있다고 생각했는데, API 호출 횟수를 고려했을때 모달을 다시 열 때 또 API를 호출하는 것을 방지하는 것이 효과적이겠네요 |
로고만 사용하므로 긴 staleTime 적용, 기존 호출부는 1분 유지
|
React Query의 기본 gcTime이 있어서 모달을 닫았다 5분 안에 열면 캐시된 데이터를 쓰네요. 로고는 거의 안 바뀌니까 말해주신 것처럼 staleTime을 길게 잡으면 될 것 같습니다. api 문서 참고하여 거의 변하지 않는 정적 데이터이니 1시간으로 수정했습니다. 6a4df3d |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
frontend/src/hooks/Queries/useClub.ts (1)
37-38: ⚡ Quick winenabled 조건 순서를 같은 파일의 다른 훅과 일관되게 맞추는 것을 고려하세요.
Line 58의
useGetClubCalendarEvents는(options?.enabled ?? true) && !!clubParam순서를 사용하지만, 여기서는!!clubParam && (options?.enabled ?? true)순서를 사용합니다. 논리적으로는 동일하지만 같은 파일 내에서 패턴을 일관되게 유지하면 가독성이 향상됩니다.참고:
!!clubParam을 먼저 체크하는 현재 방식이 미세하게 더 효율적이므로, 오히려 Line 58을 이 패턴으로 통일하는 것도 방법입니다.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/hooks/Queries/useClub.ts` around lines 37 - 38, The enabled condition ordering is inconsistent across hooks in this file: change the enabled expression in useClub (currently "!!clubParam && (options?.enabled ?? true)") to match the other hook pattern "(options?.enabled ?? true) && !!clubParam" (or vice versa—pick the pattern you want to standardize on), so update the enabled boolean in useClub.ts (the query options where staleTime and enabled are set) to use the same operand order as useGetClubCalendarEvents to keep the file consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/src/pages/ClubDetailPage/ClubDetailPage.styles.ts`:
- Around line 59-61: MapCard (the styled.button defined in
ClubDetailPage.styles.ts) lacks a visible keyboard focus state; add a
:focus-visible (and :focus fallback) rule to the MapCard styled component to
provide a clear visual indicator (e.g., outline or box-shadow with accessible
contrast) when focused via keyboard, ensuring you do not alter existing
padding/font and that the focus style is applied consistently for keyboard
navigation.
---
Nitpick comments:
In `@frontend/src/hooks/Queries/useClub.ts`:
- Around line 37-38: The enabled condition ordering is inconsistent across hooks
in this file: change the enabled expression in useClub (currently "!!clubParam
&& (options?.enabled ?? true)") to match the other hook pattern
"(options?.enabled ?? true) && !!clubParam" (or vice versa—pick the pattern you
want to standardize on), so update the enabled boolean in useClub.ts (the query
options where staleTime and enabled are set) to use the same operand order as
useGetClubCalendarEvents to keep the file consistent.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ee8bbf84-1663-4ea8-81f3-8d9b8f31d378
📒 Files selected for processing (4)
frontend/src/hooks/Queries/useClub.tsfrontend/src/pages/ClubDetailPage/ClubDetailPage.styles.tsfrontend/src/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection.styles.tsfrontend/src/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
- frontend/src/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection.styles.ts
- frontend/src/pages/PromotionPage/components/detail/PromotionMapSection/PromotionMapSection.tsx
| export const MapCard = styled.button` | ||
| padding: 0; | ||
| font: inherit; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check if global focus styles exist
# Search for global focus styles in theme or global styles
rg -n --type ts --type tsx -C 2 'focus-visible|:focus(?!-)' -g 'frontend/src/styles/**/*' -g 'frontend/src/**/global*'Repository: Moadong/moadong
Length of output: 308
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Inspect MapCard styles around the reported lines
FILE="frontend/src/pages/ClubDetailPage/ClubDetailPage.styles.ts"
if [ -f "$FILE" ]; then
echo "== $FILE (lines 40-120) =="
nl -ba "$FILE" | sed -n '40,120p'
else
echo "File not found: $FILE" >&2
fi
# 2) Search for global focus styles (use --pcre2 to support look-arounds)
echo
echo "== Search: global focus indicators =="
rg -n --pcre2 \
'(:focus-visible\b|:focus(-visible)?\b)' \
-S -g 'frontend/src/styles/**/*' -g 'frontend/src/**/global*' -g 'frontend/src/**/*.{css,scss,ts,tsx}' \
frontend/src >/tmp/focus_hits.txt || true
head -n 200 /tmp/focus_hits.txt || true
echo
echo "== Search: focus-ring utilities / outline in styles =="
rg -n \
'(focus-ring|ring-|outline:|box-shadow:.*(focus|ring))' \
-S -g 'frontend/src/styles/**/*' -g 'frontend/src/**/*.{css,scss,ts,tsx}' \
frontend/src >/tmp/outline_hits.txt || true
head -n 200 /tmp/outline_hits.txt || trueRepository: Moadong/moadong
Length of output: 200
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="frontend/src/pages/ClubDetailPage/ClubDetailPage.styles.ts"
if [ -f "$FILE" ]; then
echo "== $FILE (around MapCard) =="
# show around lines 50-110 even if line counts differ slightly
cat -n "$FILE" | sed -n '45,110p'
else
echo "File not found: $FILE" >&2
fi
echo
echo "== Search: :focus-visible / :focus in global styles =="
# Search common focus selectors in styles & global-like files
rg -n -S \
'(:focus-visible\b|:focus\b)' \
-g 'frontend/src/styles/**/*' \
-g 'frontend/src/**/global*' \
-g 'frontend/src/**/*.{css,scss,ts,tsx}' \
frontend/src >/tmp/focus_selector_hits.txt || true
head -n 200 /tmp/focus_selector_hits.txt || true
echo
echo "== Search: focus-ring / outline / box-shadow in global-ish styles =="
rg -n -S \
'(focus-ring|ring-|outline:|outline-offset|box-shadow:.*(focus|ring))' \
-g 'frontend/src/styles/**/*' \
-g 'frontend/src/**/*.{css,scss}' \
-g 'frontend/src/**/global*' \
frontend/src >/tmp/outline_hits.txt || true
head -n 200 /tmp/outline_hits.txt || trueRepository: Moadong/moadong
Length of output: 3230
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="frontend/src/pages/ClubDetailPage/ClubDetailPage.styles.ts"
echo "== $FILE (head/imports) =="
# show first 120 lines (should be safe)
cat -n "$FILE" | sed -n '1,120p'
echo
echo "== Search within file for colors.primary usage =="
rg -n 'colors\.primary' "$FILE" || true
echo
echo "== Search within file for focus styles =="
rg -n 'focus-visible|&:\s*focus\b|:focus\b' "$FILE" || trueRepository: Moadong/moadong
Length of output: 3080
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Locate the colors theme file referenced in MapCard styles
ls -la frontend/src/styles/theme/colors.* 2>/dev/null || true
# Search for primary token usage/definition
rg -n 'primary' frontend/src/styles/theme/colors* frontend/src/styles/theme -S || true
# Print the colors export file header/body near where primary is defined (if found)
for f in $(fd -e ts -e tsx -a "colors" frontend/src/styles/theme 2>/dev/null || true); do
echo "== $f (top 200 lines) =="
head -n 200 "$f"
echo
doneRepository: Moadong/moadong
Length of output: 1820
MapCard에 키보드 포커스(:focus-visible) 스타일이 누락되었습니다.
frontend/src/pages/ClubDetailPage/ClubDetailPage.styles.ts의 MapCard는 styled.button으로 바뀌었지만 :focus-visible(또는 :focus)이 없어 키보드 네비게이션 시 포커스가 시각적으로 확인되지 않습니다.
♿ 포커스 상태 추가 제안
export const MapCard = styled.button`
padding: 0;
font: inherit;
width: 100%;
height: 189px;
border-radius: 20px;
border: 1px solid ${colors.gray[400]};
overflow: hidden;
cursor: pointer;
background-color: `#f2f2f2`;
+
+ &:focus-visible {
+ outline: 2px solid ${colors.primary[500]};
+ outline-offset: 2px;
+ }
* {
cursor: pointer !important;
}
`;📝 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.
| export const MapCard = styled.button` | |
| padding: 0; | |
| font: inherit; | |
| export const MapCard = styled.button` | |
| padding: 0; | |
| font: inherit; | |
| width: 100%; | |
| height: 189px; | |
| border-radius: 20px; | |
| border: 1px solid ${colors.gray[400]}; | |
| overflow: hidden; | |
| cursor: pointer; | |
| background-color: `#f2f2f2`; | |
| &:focus-visible { | |
| outline: 2px solid ${colors.primary[500]}; | |
| outline-offset: 2px; | |
| } | |
| * { | |
| cursor: pointer !important; | |
| } | |
| `; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/src/pages/ClubDetailPage/ClubDetailPage.styles.ts` around lines 59 -
61, MapCard (the styled.button defined in ClubDetailPage.styles.ts) lacks a
visible keyboard focus state; add a :focus-visible (and :focus fallback) rule to
the MapCard styled component to provide a clear visual indicator (e.g., outline
or box-shadow with accessible contrast) when focused via keyboard, ensuring you
do not alter existing padding/font and that the focus style is applied
consistently for keyboard navigation.
모달을 닫았다 5분 안에 열면 캐시된 데이터를 쓰는 것은 staleTime으로 인한 것 아닌가요? gcTime은 해당 쿼리를 구독 중인 옵저버가 없어진 순간부터 타이머가 돈다고 하네요! 그렇다면 gcTime 도 1시간정도로 설정하면 어떨까요? |
모달 닫힘 시 옵저버가 사라져 gcTime 타이머가 시작되므로, 기본 gcTime(5분)이 staleTime(1시간)보다 먼저 만료되어 캐시가 삭제되는 문제 방지
staleTime을 1시간으로 늘려도 모달을 닫으면 옵저버가 사라져 gcTime이 시작되는데 여전히 5분이기 때문에 캐시가 삭제되어 의미가 없겠네요. gcTime도 1시간으로 늘리겠습니다! 6f2c925 |
#️⃣연관된 이슈
📝작업 내용
주요 변경사항
PromotionArticle타입에latitude?,longitude?필드추가
NaverMapprops를ClubLocation의존성에서 범용 좌표인터페이스(
{ lat: number; lng: number })로 변경PromotionMapSection컴포넌트 생성 (데스크탑/모바일 공통)InteractiveMapView,MapModal에bubbleTextprops 추가(동아리방 → 행사 위치)
location_icon.svg를currentColor방식으로 전환하여 색상재사용 가능하게 변경
스크린샷
데스크탑
모바일
지도 모달
중점적으로 리뷰받고 싶은 부분(선택)
useGetClubDetail로 가져오고있는데, 로고 하나를 위해 전체 클럽 상세를 조회하는게 괜찮을까요
🫡 참고사항
location_icon.svg를currentColor로 변경하면서 동아리상세페이지의 위치 아이콘도
img→ SVG 컴포넌트로전환되었습니다
overflow: hidden컨테이너내에서
bottom: 0이 보이는 영역 하단과 안 맞는 이슈가 있어bottom: -20px로 보정했습니다Summary by CodeRabbit
New Features
Improvements
Chores