Skip to content

[시설물 정보] 백엔드 API 응답값 추가에 따른 코드 변경#1240

Merged
ff1451 merged 2 commits intodevelopfrom
feat/#1239/coopshop-api
Apr 29, 2026
Merged

[시설물 정보] 백엔드 API 응답값 추가에 따른 코드 변경#1240
ff1451 merged 2 commits intodevelopfrom
feat/#1239/coopshop-api

Conversation

@ff1451
Copy link
Copy Markdown
Contributor

@ff1451 ff1451 commented Apr 28, 2026

What is this PR? 🔍

Changes 📝

  • svg url 링크를 활용하여 렌더링하도록 수정

✔️ Please check if the PR fulfills these requirements

  • It's submitted to the correct branch, not the develop branch unconditionally?
  • If on a hotfix branch, ensure it targets main?
  • There are no warning message when you run yarn lint

Summary by CodeRabbit

  • New Features

    • 상점 데이터에 선택적 아이콘 URL(icon_url)이 추가되어 앱에서 서버 제공 이미지를 표시합니다.
    • 아이콘이 없을 경우 상점 이름의 첫 글자를 자동 폴백으로 표시합니다.
  • Style

    • 아이콘 표시를 위한 레이아웃과 폴백 텍스트 스타일이 개선되어 일관된 정렬과 크기 조정이 적용됩니다.

@ff1451 ff1451 self-assigned this Apr 28, 2026
@ff1451 ff1451 added 🔨 Refactor 코드 리팩토링 🎓 Campus 학교식단, 버스, 커뮤니티 도메인 labels Apr 28, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Walkthrough

백엔드에서 추가된 icon_url을 사용하도록 시설물 아이콘 렌더링을 변경합니다. 정적 SVG 매핑을 제거하고, icon_url로 이미지를 표시하되 URL이 없으면 상점 이름의 첫 글자로 폴백합니다. 페이지 파일은 컴포넌트 재내보내기로 단순화되었습니다.

Changes

Cohort / File(s) Summary
API 엔티티
src/api/coopshop/entity.ts
CoopShopDetailResponse에 선택적 `icon_url: string
스타일시트
src/components/CampusInfo/CampusInfo.module.scss
.icon-wrapper에 플렉스 정렬 추가, .icon-image(이미지 컨테인) 및 .icon-fallback(텍스트 폴백) 클래스 추가
CampusInfo 컴포넌트
src/components/CampusInfo/index.tsx
정적 SVG 매핑( SHOP_ICON ) 제거, ShopIcon 도입으로 icon_url 기반 <img> 렌더링 및 이름 첫글자 폴백 적용, 상점 목록 렌더링 업데이트
캠퍼스 정보 페이지
src/pages/campusinfo/index.tsx
UI 구성 및 헬퍼 제거 후 컴포넌트 재내보내기(export { default } from 'components/CampusInfo';)로 변경

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • ParkSungju01
  • kongwoojin
  • hyejun0228
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목이 주요 변경사항을 명확히 설명하고 있으며, 백엔드 API 응답값 추가에 따른 코드 변경이라는 핵심 내용을 잘 반영하고 있습니다.
Linked Issues check ✅ Passed PR의 모든 변경사항이 #1239의 요구사항을 충족합니다. 백엔드 SVG URL 응답에 따라 API 엔티티에 icon_url 필드를 추가하고, 컴포넌트에서 하드코딩된 SVG 매칭 대신 동적 URL을 렌더링하도록 수정했습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 #1239의 목표인 백엔드 SVG URL 기반 아이콘 렌더링으로의 마이그레이션과 직접적으로 관련되어 있으며 범위를 벗어나는 변경은 없습니다.

✏️ 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 feat/#1239/coopshop-api

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.

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: 1

🤖 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/components/CampusInfo/index.tsx`:
- Around line 44-51: The component currently renders the <img> whenever iconUrl
is truthy so a broken URL shows a broken image; update the CampusInfo component
to track image load state (e.g., a local state like hasImageError or
imageLoaded) and render the fallback when the image fails to load: keep the
existing <img className={styles['icon-image']} src={iconUrl} ... /> but add an
onError handler that sets hasImageError true (and optionally onLoad to mark
success), and change the conditional to show the <span
className={styles['icon-fallback']}>{name.slice(0,1)}</span> when !iconUrl ||
hasImageError so the fallback appears on broken URLs. Ensure aria-hidden/alt
handling remains 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bf2dc2f8-136e-4380-947c-4247eca98cec

📥 Commits

Reviewing files that changed from the base of the PR and between 702c988 and 512deb3.

📒 Files selected for processing (4)
  • src/api/coopshop/entity.ts
  • src/components/CampusInfo/CampusInfo.module.scss
  • src/components/CampusInfo/index.tsx
  • src/pages/campusinfo/index.tsx

Comment on lines +44 to +51
{iconUrl ? (
// NOTE: 백엔드가 내려주는 소형 반복 아이콘은 호스트가 고정되지 않을 수 있어 <img>를 유지합니다.
// eslint-disable-next-line @next/next/no-img-element
<img className={styles['icon-image']} src={iconUrl} alt="" aria-hidden="true" decoding="async" />
) : (
<span className={styles['icon-fallback']} aria-hidden="true">
{name.slice(0, 1)}
</span>
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 | 🟡 Minor

이미지 로드 실패 시 폴백이 동작하지 않습니다.

Line 44-48은 iconUrl 존재 여부만 확인해서 렌더링하기 때문에, URL이 깨졌을 때 icon-fallback으로 전환되지 않고 깨진 이미지가 노출됩니다.

수정 예시
+import { useState } from 'react';
 import { cn } from '@bcsdlab/utils';
 import { useSuspenseQuery } from '@tanstack/react-query';
 import { coopshopQueries } from 'api/coopshop/queries';
 import styles from './CampusInfo.module.scss';

 function ShopIcon({ iconUrl, name }: ShopIconProps) {
+  const [isImageError, setIsImageError] = useState(false);
+  const shouldRenderImage = Boolean(iconUrl) && !isImageError;
+
   return (
     <div className={styles['icon-wrapper']}>
-      {iconUrl ? (
+      {shouldRenderImage ? (
         // NOTE: 백엔드가 내려주는 소형 반복 아이콘은 호스트가 고정되지 않을 수 있어 <img>를 유지합니다.
         // eslint-disable-next-line `@next/next/no-img-element`
-        <img className={styles['icon-image']} src={iconUrl} alt="" aria-hidden="true" decoding="async" />
+        <img
+          className={styles['icon-image']}
+          src={iconUrl!}
+          alt=""
+          aria-hidden="true"
+          decoding="async"
+          onError={() => setIsImageError(true)}
+        />
       ) : (
         <span className={styles['icon-fallback']} aria-hidden="true">
           {name.slice(0, 1)}
         </span>
       )}
     </div>
   );
 }
📝 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
{iconUrl ? (
// NOTE: 백엔드가 내려주는 소형 반복 아이콘은 호스트가 고정되지 않을 수 있어 <img>를 유지합니다.
// eslint-disable-next-line @next/next/no-img-element
<img className={styles['icon-image']} src={iconUrl} alt="" aria-hidden="true" decoding="async" />
) : (
<span className={styles['icon-fallback']} aria-hidden="true">
{name.slice(0, 1)}
</span>
import { useState } from 'react';
import { cn } from '@bcsdlab/utils';
import { useSuspenseQuery } from '@tanstack/react-query';
import { coopshopQueries } from 'api/coopshop/queries';
import styles from './CampusInfo.module.scss';
function ShopIcon({ iconUrl, name }: ShopIconProps) {
const [isImageError, setIsImageError] = useState(false);
const shouldRenderImage = Boolean(iconUrl) && !isImageError;
return (
<div className={styles['icon-wrapper']}>
{shouldRenderImage ? (
// NOTE: 백엔드가 내려주는 소형 반복 아이콘은 호스트가 고정되지 않을 수 있어 <img>를 유지합니다.
// eslint-disable-next-line `@next/next/no-img-element`
<img
className={styles['icon-image']}
src={iconUrl!}
alt=""
aria-hidden="true"
decoding="async"
onError={() => setIsImageError(true)}
/>
) : (
<span className={styles['icon-fallback']} aria-hidden="true">
{name.slice(0, 1)}
</span>
)}
</div>
);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/CampusInfo/index.tsx` around lines 44 - 51, The component
currently renders the <img> whenever iconUrl is truthy so a broken URL shows a
broken image; update the CampusInfo component to track image load state (e.g., a
local state like hasImageError or imageLoaded) and render the fallback when the
image fails to load: keep the existing <img className={styles['icon-image']}
src={iconUrl} ... /> but add an onError handler that sets hasImageError true
(and optionally onLoad to mark success), and change the conditional to show the
<span className={styles['icon-fallback']}>{name.slice(0,1)}</span> when !iconUrl
|| hasImageError so the fallback appears on broken URLs. Ensure aria-hidden/alt
handling remains consistent.

Copy link
Copy Markdown
Contributor

@dooohun dooohun left a comment

Choose a reason for hiding this comment

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

수고하셨습니다. 리뷰 작성한 것만 수정하면 될 거 같습니다.

Comment thread src/components/CampusInfo/index.tsx Outdated
Comment on lines +47 to +48
<img className={styles['icon-image']} src={iconUrl} alt="" aria-hidden="true" decoding="async" />
) : (
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.

name이 있으니까 alt에 넣으면 좋을 거 같아요.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

추가했습니다! e8b323c

Co-authored-by: Copilot <copilot@github.com>
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.

♻️ Duplicate comments (1)
src/components/CampusInfo/index.tsx (1)

44-51: ⚠️ Potential issue | 🟡 Minor

이미지 로드 실패 시 폴백이 동작하지 않습니다.

Line 44-48은 iconUrl 존재만 검사하므로, URL이 깨진 경우에도 <img>가 유지되어 fallback이 보이지 않습니다. onError 상태를 추가해 !iconUrl || hasImageError일 때 fallback을 렌더링해주세요.

수정 예시
+import { useState } from 'react';
 import { cn } from '@bcsdlab/utils';
 import { useSuspenseQuery } from '@tanstack/react-query';
 import { coopshopQueries } from 'api/coopshop/queries';
 import styles from './CampusInfo.module.scss';

 function ShopIcon({ iconUrl, name }: ShopIconProps) {
+  const [hasImageError, setHasImageError] = useState(false);
+  const shouldRenderImage = Boolean(iconUrl) && !hasImageError;
+
   return (
     <div className={styles['icon-wrapper']}>
-      {iconUrl ? (
+      {shouldRenderImage ? (
         // NOTE: 백엔드가 내려주는 소형 반복 아이콘은 호스트가 고정되지 않을 수 있어 <img>를 유지합니다.
         // eslint-disable-next-line `@next/next/no-img-element`
-        <img className={styles['icon-image']} src={iconUrl} alt={name} decoding="async" />
+        <img
+          className={styles['icon-image']}
+          src={iconUrl!}
+          alt={name}
+          decoding="async"
+          onError={() => setHasImageError(true)}
+        />
       ) : (
         <span className={styles['icon-fallback']} aria-hidden="true">
           {name.slice(0, 1)}
         </span>
       )}
     </div>
   );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/CampusInfo/index.tsx` around lines 44 - 51, The CampusInfo
component currently only checks iconUrl so broken image URLs still render the
<img> and hide the fallback; introduce a local state (e.g., hasImageError via
useState) in the CampusInfo component and add an onError handler on the <img>
that sets hasImageError to true, then change the render condition to show the
fallback when (!iconUrl || hasImageError). Ensure the handler and state are
named clearly (e.g., hasImageError, setHasImageError, handleImageError) and that
the fallback span (styles['icon-fallback']) is rendered with name.slice(0,1)
when the image is absent/errored.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/components/CampusInfo/index.tsx`:
- Around line 44-51: The CampusInfo component currently only checks iconUrl so
broken image URLs still render the <img> and hide the fallback; introduce a
local state (e.g., hasImageError via useState) in the CampusInfo component and
add an onError handler on the <img> that sets hasImageError to true, then change
the render condition to show the fallback when (!iconUrl || hasImageError).
Ensure the handler and state are named clearly (e.g., hasImageError,
setHasImageError, handleImageError) and that the fallback span
(styles['icon-fallback']) is rendered with name.slice(0,1) when the image is
absent/errored.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d508a8ca-b93d-4193-b8aa-1f1f5b9dfc66

📥 Commits

Reviewing files that changed from the base of the PR and between 512deb3 and e8b323c.

📒 Files selected for processing (1)
  • src/components/CampusInfo/index.tsx

@ff1451 ff1451 requested a review from dooohun April 28, 2026 16:18
Copy link
Copy Markdown
Contributor

@ParkSungju01 ParkSungju01 left a comment

Choose a reason for hiding this comment

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

수고하셨습니다!

@ff1451 ff1451 merged commit feda477 into develop Apr 29, 2026
4 checks passed
@github-actions github-actions Bot deleted the feat/#1239/coopshop-api branch April 29, 2026 10:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🎓 Campus 학교식단, 버스, 커뮤니티 도메인 🔨 Refactor 코드 리팩토링

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[시설물 정보] 백엔드 API 응답값 추가에 따른 코드 변경

3 participants