Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions frontend/src/assets/images/icons/location_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface InteractiveMapViewProps {
clubLogo?: string;
active: boolean;
markerSize?: number;
bubbleText?: string;
bubbleFontSize?: number;
bubbleFontWeight?: number;
mapInstanceRef: RefObject<NaverMapInstance | null>;
Expand All @@ -22,6 +23,7 @@ const InteractiveMapView = ({
clubLogo,
active,
markerSize = 40,
bubbleText = '동아리방',
bubbleFontSize = 13,
bubbleFontWeight = 700,
mapInstanceRef,
Expand All @@ -32,7 +34,7 @@ const InteractiveMapView = ({
active,
interactive: true,
markerSize,
bubbleText: '동아리방',
bubbleText,
bubbleFontSize,
bubbleFontWeight,
mapInstanceRef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,18 @@ export const LocationRow = styled.div`
align-items: center;
gap: 4px;

img {
width: 11px;
height: 14px;
svg {
width: 22px;
height: 22px;
margin: 0px 2px 0px 0px;
flex-shrink: 0;
color: ${colors.gray[500]};

${media.tablet} {
width: 18px;
height: 18px;
margin: 1px 2px 1px 0px;
}
}
`;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import locationIcon from '@/assets/images/icons/location_icon.svg';
import LocationIcon from '@/assets/images/icons/location_icon.svg?react';
import DefaultLogo from '@/assets/images/logos/default_profile_image.svg';
import * as Styled from './MapClubInfoCard.styles';

Expand All @@ -21,7 +21,7 @@ const MapClubInfoCard = ({
<Styled.ClubInfo>
<Styled.ClubName>{name}</Styled.ClubName>
<Styled.LocationRow>
<img src={locationIcon} alt='위치 아이콘' />
<LocationIcon />
<Styled.LocationText>
{building} {detailLocation}
</Styled.LocationText>
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/components/map/MapModal/MapModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ interface MapModalProps {
clubName: string;
clubLogo?: string;
location: ClubLocation;
bubbleText?: string;
}

const MapModal = ({
Expand All @@ -23,6 +24,7 @@ const MapModal = ({
clubName,
clubLogo,
location,
bubbleText,
}: MapModalProps) => {
const { isMobile, isTablet } = useDevice();
const isMobileView = isMobile || isTablet;
Expand All @@ -38,6 +40,7 @@ const MapModal = ({
clubLogo={clubLogo}
active={isOpen}
markerSize={isMobileView ? 40 : 50}
bubbleText={bubbleText}
bubbleFontSize={isMobileView ? 14 : 16}
bubbleFontWeight={isMobileView ? 700 : 600}
mapInstanceRef={mapInstanceRef}
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/components/map/NaverMap/NaverMap.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { useRef } from 'react';
import { ClubLocation } from '@/constants/clubLocation';
import { useNaverMap } from '@/hooks/Map/useNaverMap';
import * as Styled from './NaverMap.styles';

interface NaverMapProps {
location: Pick<ClubLocation, 'lat' | 'lng'>;
location: { lat: number; lng: number };
}

const NaverMap = ({ location }: NaverMapProps) => {
Expand Down
10 changes: 7 additions & 3 deletions frontend/src/hooks/Queries/useClub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,16 @@ interface UseGetCardListProps {
division: string;
}

export const useGetClubDetail = (clubParam: string) => {
export const useGetClubDetail = (
clubParam: string,
options?: { enabled?: boolean; staleTime?: number; gcTime?: number },
) => {
return useQuery<ClubDetail>({
queryKey: queryKeys.club.detail(clubParam),
queryFn: () => getClubDetail(clubParam as string),
staleTime: 60 * 1000,
enabled: !!clubParam,
staleTime: options?.staleTime ?? 60 * 1000,
gcTime: options?.gcTime,
enabled: !!clubParam && (options?.enabled ?? true),
select: (data) =>
({
...data,
Expand Down
12 changes: 8 additions & 4 deletions frontend/src/pages/ClubDetailPage/ClubDetailPage.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export const MapInfo = styled.div`
}
`;

export const MapCard = styled.div`
export const MapCard = styled.button`
padding: 0;
font: inherit;
Comment on lines +59 to +61
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 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 || true

Repository: 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 || true

Repository: 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" || true

Repository: 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
done

Repository: Moadong/moadong

Length of output: 1820


MapCard에 키보드 포커스(:focus-visible) 스타일이 누락되었습니다.
frontend/src/pages/ClubDetailPage/ClubDetailPage.styles.tsMapCardstyled.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.

Suggested change
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.

width: 100%;
height: 189px;
Expand Down Expand Up @@ -84,9 +86,11 @@ export const MapDetailText = styled.div`
cursor: default;
user-select: none;
img {
width: 12px;
height: 15px;
svg {
width: 18px;
height: 18px;
margin: 1px 2px 1px 0px;
color: ${colors.gray[500]};
}
`;

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/pages/ClubDetailPage/ClubDetailPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useMemo, useRef, useState } from 'react';
import { useParams, useSearchParams } from 'react-router-dom';
import locationIcon from '@/assets/images/icons/location_icon.svg';
import LocationIcon from '@/assets/images/icons/location_icon.svg?react';
import Footer from '@/components/common/Footer/Footer';
import Header from '@/components/common/Header/Header';
import UnderlineTabs from '@/components/common/UnderlineTabs/UnderlineTabs';
Expand Down Expand Up @@ -172,7 +172,7 @@ const ClubDetailPage = () => {
</Styled.MapCard>

<Styled.MapDetailText>
<img src={locationIcon} alt='위치 아이콘' />
<LocationIcon />
동아리방 위치 {clubLocation.building}{' '}
{clubLocation.detailLocation}
</Styled.MapDetailText>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,10 +230,12 @@ export const LocationInfo = styled.div`
min-width: 0;
overflow: hidden;
img {
width: 12px;
height: 15px;
svg {
width: 18px;
height: 18px;
margin: 1px 2px 1px 0px;
flex-shrink: 0;
color: ${colors.gray[500]};
}
span {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import locationIcon from '@/assets/images/icons/location_icon.svg';
import LocationIcon from '@/assets/images/icons/location_icon.svg?react';
import InstagramIcon from '@/assets/images/icons/sns/instagram_icon.svg';
import YoutubeIcon from '@/assets/images/icons/sns/youtube_icon.svg';
import defaultCover from '@/assets/images/logos/default_cover_image.png';
Expand Down Expand Up @@ -128,7 +128,7 @@ const ClubProfileCard = ({
<Styled.LocationDivider />
<Styled.LocationRow>
<Styled.LocationInfo>
<img src={locationIcon} alt='위치 아이콘' />
<LocationIcon />
<span>
동아리방 위치 {location.building} {location.detailLocation}
</span>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/pages/PromotionPage/PromotionDetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import PromotionClubCTA from './components/detail/PromotionClubCTA/PromotionClub
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';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ 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.

Suggested change
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.

import PromotionTitleSection from './components/detail/PromotionTitleSection/PromotionTitleSection';
import RelatedPromotionSection from './components/detail/RelatedPromotionSection/RelatedPromotionSection';
import * as Styled from './PromotionDetailPage.styles';
Expand Down Expand Up @@ -53,6 +54,7 @@ const PromotionDetailPage = () => {
<Styled.ContentWrapper>
<Styled.LeftSection>
<PromotionInfoSection article={article} />
<PromotionMapSection article={article} />
<PromotionClubCTA
clubId={article.clubId}
clubName={article.clubName}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { colors } from '@/styles/theme/colors';

export const Container = styled.section`
padding: 0px 0px 0px 0px;
margin: 16px 0px;
margin: 20px 0px;
${media.tablet} {
padding: 0px 20px 24px 20px;
padding: 24px 20px 24px 20px;
margin: 0px 0px;
}
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const Image = styled.img`

export const Gradient = styled.div`
position: absolute;
bottom: 0;
bottom: -20px;
width: 100%;
height: 180px;
z-index: 1;
Expand Down Expand Up @@ -64,7 +64,7 @@ export const Gradient = styled.div`
export const ImageMoreButtonWrapper = styled.div`
padding: 0px 0px 32px;

${media.mobile} {
${media.tablet} {
padding: 0 20px;
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const Container = styled.section`
padding: 0px 0px;

${media.tablet} {
padding: 24px 20px;
padding: 24px 20px 0px 20px;
}
`;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import styled from 'styled-components';
import { media } from '@/styles/mediaQuery';
import { colors } from '@/styles/theme/colors';

export const Container = styled.section`
padding-top: 20px;

${media.tablet} {
padding: 16px 20px 0px 20px;
}
`;

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;

* {
cursor: pointer !important;
}
`;

export const LocationText = styled.div`
display: flex;
align-items: center;
gap: 2px;
padding: 8px 2px 0;
font-size: 14px;
color: ${colors.gray[700]};

svg {
width: 18px;
height: 18px;
margin: 1px 2px 1px 0px;
color: ${colors.gray[500]};
}

${media.tablet} {
padding: 6px 2px 0;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useState } from 'react';
import LocationIcon from '@/assets/images/icons/location_icon.svg?react';
import MapModal from '@/components/map/MapModal/MapModal';
import NaverMap from '@/components/map/NaverMap/NaverMap';
import { ClubLocation } from '@/constants/clubLocation';
import { useGetClubDetail } from '@/hooks/Queries/useClub';
import { PromotionArticle } from '@/types/promotion';
import * as Styled from './PromotionMapSection.styles';

interface Props {
article: PromotionArticle;
}

const PromotionMapSection = ({ article }: Props) => {
const [isMapModalOpen, setIsMapModalOpen] = useState(false);
const { data: clubDetail } = useGetClubDetail(`@${article.clubName}`, {
enabled: isMapModalOpen,
staleTime: 60 * 60 * 1000,
gcTime: 60 * 60 * 1000,
});

if (article.latitude == null || article.longitude == null) {
return null;
}

const location: ClubLocation = {
clubName: article.clubName,
lat: article.latitude,
lng: article.longitude,
building: article.location,
detailLocation: '',
};

return (
<>
<Styled.Container>
<Styled.MapCard onClick={() => setIsMapModalOpen(true)}>
<NaverMap location={location} />
</Styled.MapCard>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
<Styled.LocationText>
<LocationIcon />
{article.location}
</Styled.LocationText>
</Styled.Container>

<MapModal
isOpen={isMapModalOpen}
onClose={() => setIsMapModalOpen(false)}
clubName={article.clubName}
clubLogo={clubDetail?.logo}
location={location}
bubbleText='행사 위치'
/>
</>
);
};

export default PromotionMapSection;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export const Icon = styled.div`
svg {
width: 100%;
height: 100%;
color: ${colors.gray[700]};
}

${media.mobile} {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/types/promotion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export interface PromotionArticle {
clubId: string;
title: string;
location: string;
latitude?: number;
longitude?: number;
eventStartDate: string;
eventEndDate: string;
description: string;
Expand Down
Loading