Skip to content

Refactor(ads): 저장한 공지 이미지 없을 때 기본 이미지 처리#280

Open
jin-evergreen wants to merge 3 commits intodevelopfrom
refactor/empty-notice-image/#279
Open

Refactor(ads): 저장한 공지 이미지 없을 때 기본 이미지 처리#280
jin-evergreen wants to merge 3 commits intodevelopfrom
refactor/empty-notice-image/#279

Conversation

@jin-evergreen
Copy link
Member

📌 Summary

저장한 공지 확인 시 공지 이미지가 없을 때 기본 이미지 처리 로직을 추가합니다.

📚 Tasks

  • 기본 이미지 파일(webp) 추가
  • 기본 이미지 조건부 렌더링

🔍 Describe

공지 이미지 없을 때 이미지 깨짐 해결

공연 공지는 이미지가 필수 입력 값이 아니므로, 이미지가 없는 경우도 존재해요. 기존에는 저장한 공지 확인 시 공지사항 데이터 중 이미지 URL이 비어있거나, 이미지를 불러오지 못할 경우 엑스박스가 노출되며 이미지가 깨지는 현상이 발생했어요.

이를 해결하기 위해 렌더링 시점에 imageUrl이 존재하지 않으면 기본 이미지를 렌더링하도록 했어요. 추가로, imageUrl 값은 존재하지만 이미지 로드 실패, 파일 손상, 브라우저 미지원 형식 등으로 이미지를 불러올 수 없는 경우에도 img 태그의 onError를 활용하여 기본 이미지가 렌더링 될 수 있도록 했어요.

👀 To Reviewer

  • 추가 개선 사항은 없는지 확인 부탁드립니다!

📸 Screenshot

image

@jin-evergreen jin-evergreen self-assigned this Mar 1, 2026
@jin-evergreen jin-evergreen requested a review from a team as a code owner March 1, 2026 13:21
@coderabbitai
Copy link

coderabbitai bot commented Mar 1, 2026

📝 Walkthrough

Summary by CodeRabbit

릴리스 노트

  • 버그 수정

    • 카드 공지사항에서 이미지 로드 실패 시 기본 플레이스홀더 이미지가 자동으로 표시되도록 개선했습니다.
    • 기본 플레이스홀더 자산이 추가되어 모든 공지에 일관된 대체 이미지가 제공됩니다.
  • 새 기능 / 접근성 개선

    • 카드 공지사항을 키보드(Enter/Space)로 활성화할 수 있도록 포커스 및 ARIA 지원을 추가했습니다.
  • 스타일

    • 공지 컨테이너가 가로 전체 폭을 사용하고 텍스트 정렬을 왼쪽으로 맞추도록 시각적 조정이 이루어졌습니다.

Walkthrough

빈 상태 이미지 자산을 추가하고, 카드 공지 컴포넌트의 이미지 소스와 에러 핸들링을 변경했으며, 공지 컨테이너 스타일에 너비와 정렬 속성을 추가했습니다. 버튼으로의 역할 변경과 접근성 속성도 포함됩니다.

Changes

Cohort / File(s) Summary
자산 인덱스
packages/ads-ui/src/assets/index.ts
empty-notice-image.webp를 import하고 IMAGES 맵에 EMPTY_NOTICE_IMAGE 항목을 추가했습니다.
카드 공지 컴포넌트
packages/ads-ui/src/components/card/card-notice/card-notice.tsx
IMAGES를 import, `displayImage = imageUrl
스타일 변경
packages/ads-ui/src/components/card/card-notice/card-notice.css.ts
공지 컨테이너 스타일에 width: '100%'textAlign: 'left' 속성을 추가했습니다.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • Sohyunnnn
  • jisooooooooooo
  • eunkr82
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed 제목은 [type] 형식을 따르고 있으며 40자로 50자 이내 요구사항을 충족하고 있어요. 저장한 공지의 기본 이미지 처리라는 PR의 핵심 변경사항을 명확히 반영하고 있습니다.
Description check ✅ Passed PR 설명은 변경사항과 완전히 일치하고 있어요. 기본 이미지 파일 추가, 조건부 렌더링, onError 핸들러 구현 등 코드 변경과 정확히 대응되며 충분한 맥락을 제공하고 있습니다.
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.


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.

@jin-evergreen jin-evergreen linked an issue Mar 1, 2026 that may be closed by this pull request
Copy link

@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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/ads-ui/src/components/card/card-notice/card-notice.tsx`:
- Line 1: The import in card-notice.tsx uses a relative path import of IMAGES
from '../../../assets' which violates the repo convention; change it to the
project's absolute alias import (e.g., replace the relative import with the
appropriate alias import that exposes IMAGES such as `@shared/assets` or `@assets`
depending on your alias map) so the IMAGES symbol is imported via the project's
configured path alias used across {apps,packages}/**/src/**.
- Line 26: The clickable article element in the CardNotice component lacks
keyboard accessibility; update the <article> (the element rendered in
card-notice.tsx) to be focusable and keyboard-activatable by adding
role="button", tabIndex={0}, and an onKeyDown handler that calls the existing
onClick when Enter (key === "Enter") or Space (key === " " or key ===
"Spacebar") is pressed; ensure the onKeyDown handler prevents default for Space
to avoid page scroll and preserves the existing onClick behavior so both mouse
and keyboard activate the same action.
- Around line 31-34: Replace the inline anonymous onError handler in
CardNotice's JSX with a named event handler (e.g., handleImageError) to follow
the 'handle*' convention; implement a function (handleImageError) in the
component that accepts the event (React.SyntheticEvent<HTMLImageElement, Event>
or appropriate type), sets e.currentTarget.onerror = null and
e.currentTarget.src = IMAGES.EMPTY_NOTICE_IMAGE, and then reference this handler
in the JSX as onError={handleImageError}; ensure the handler is declared in the
same component scope so it can access IMAGES and any props/state.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67ed865 and b5b9f70.

⛔ Files ignored due to path filters (1)
  • packages/ads-ui/src/assets/empty-notice-image.webp is excluded by !**/*.webp and included by packages/**/src/**
📒 Files selected for processing (2)
  • packages/ads-ui/src/assets/index.ts
  • packages/ads-ui/src/components/card/card-notice/card-notice.tsx

@@ -1,3 +1,4 @@
import { IMAGES } from '../../../assets';
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Suggest: Line 1 상대 경로 import를 절대 경로 alias로 통일해 주세요.

새로 추가된 import가 상대 경로(../../../assets)라서 레포 컨벤션과 어긋납니다. 프로젝트에서 사용하는 alias(@pages, @shared 등) 기준으로 바꿔주시면 유지보수성이 좋아집니다.
As per coding guidelines {apps,packages}/**/src/**: 절대 경로 임포트 사용 (@pages, @shared 등).

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

In `@packages/ads-ui/src/components/card/card-notice/card-notice.tsx` at line 1,
The import in card-notice.tsx uses a relative path import of IMAGES from
'../../../assets' which violates the repo convention; change it to the project's
absolute alias import (e.g., replace the relative import with the appropriate
alias import that exposes IMAGES such as `@shared/assets` or `@assets` depending on
your alias map) so the IMAGES symbol is imported via the project's configured
path alias used across {apps,packages}/**/src/**.

Copy link

@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

♻️ Duplicate comments (1)
packages/ads-ui/src/components/card/card-notice/card-notice.tsx (1)

3-3: ⚠️ Potential issue | 🟠 Major

Must: Line 3 import를 절대 경로 alias로 통일해 주세요.

현재 ../../../assets 상대 경로 import는 공용 코드 컨벤션과 맞지 않습니다. 프로젝트 alias 기준의 절대 경로 import로 변경 부탁드립니다.

As per coding guidelines {apps,packages}/**/src/**: 절대 경로 임포트 사용 (@pages, @shared 등).

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

In `@packages/ads-ui/src/components/card/card-notice/card-notice.tsx` at line 3,
Replace the relative import for IMAGES (currently importing from
'../../../assets') with the project's absolute alias import per repo conventions
(e.g., use the configured alias such as `@assets`, `@shared/assets`, or `@shared`) so
the line becomes an absolute-path import; update the import that references
IMAGES to use the correct project alias and ensure any export names remain
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/ads-ui/src/components/card/card-notice/card-notice.tsx`:
- Around line 40-47: The article currently assigns interactive/a11y attributes
unconditionally (onClick, onKeyDown, role='button', tabIndex={0}) which makes
non-clickable items focusable and announce as buttons; change the component to
apply these attributes only when clickable (e.g., when the onClick prop exists
or an explicit isClickable prop is true): attach onClick and onKeyDown
(handleKeyDown) conditionally, set role='button' and tabIndex=0 only for
clickable instances and omit or set tabIndex={-1} otherwise, while keeping
non-interactive markup for the rest (title/aria-label can remain); update
references in card-notice (props handling and JSX where onClick, handleKeyDown,
role, and tabIndex are set) to implement this conditional logic.

---

Duplicate comments:
In `@packages/ads-ui/src/components/card/card-notice/card-notice.tsx`:
- Line 3: Replace the relative import for IMAGES (currently importing from
'../../../assets') with the project's absolute alias import per repo conventions
(e.g., use the configured alias such as `@assets`, `@shared/assets`, or `@shared`) so
the line becomes an absolute-path import; update the import that references
IMAGES to use the correct project alias and ensure any export names remain
unchanged.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b5b9f70 and c1497f3.

⛔ Files ignored due to path filters (2)
  • packages/ads-ui/src/assets/.png is excluded by !**/*.png, !**/*.png and included by packages/**/src/**
  • packages/ads-ui/src/assets/img_empty_alert.png is excluded by !**/*.png, !**/*.png and included by packages/**/src/**
📒 Files selected for processing (1)
  • packages/ads-ui/src/components/card/card-notice/card-notice.tsx

Copy link
Contributor

@Sohyunnnn Sohyunnnn left a comment

Choose a reason for hiding this comment

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

수고하셨습니다 👍
이미지 로드 실패 케이스까지 onError로 방어해주신 점 좋았습니다!!

Copy link
Contributor

@jisooooooooooo jisooooooooooo left a comment

Choose a reason for hiding this comment

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

확인했습니당 !!
토끼 리뷰랑 소현님 리뷰만 고려해 보면 좋을 것 같네용ㅎㅎ😙

Copy link

@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 (2)
packages/ads-ui/src/components/card/card-notice/card-notice.tsx (2)

3-3: ⚠️ Potential issue | 🟠 Major

Must: 상대 경로 import를 절대 경로 alias로 통일해 주세요.

Line 3의 상대 경로 import는 현재 레포 컨벤션과 맞지 않습니다. 패키지 내 표준 alias 경로로 변경 부탁드립니다.

As per coding guidelines {apps,packages}/**/src/**: 절대 경로 임포트 사용 (@pages, @shared 등).

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

In `@packages/ads-ui/src/components/card/card-notice/card-notice.tsx` at line 3,
The import in card-notice.tsx uses a relative path (import { IMAGES } from
'../../../assets';) which violates the repo convention; update it to the
package's absolute alias import (e.g., import { IMAGES } from '@assets' or the
project's defined alias for assets) so it follows the {apps,packages}/**/src/**
absolute import rule (use the same alias pattern used elsewhere like `@pages` or
`@shared`).

33-38: ⚠️ Potential issue | 🟠 Major

Must: onClick이 없을 때는 비인터랙티브 상태를 명확히 처리해 주세요.

Line 33-38에서 onClick이 없는 경우에도 버튼과 aria-label이 유지되어 사용자에게 “클릭 가능”으로 전달됩니다. onClick을 필수로 만들거나, 없을 때 disabled/라벨 조건부 처리를 권장드립니다.

제안 diff
 const CardNotice = ({
   imageUrl,
   title,
   content,
   isPinned,
   createdAt,
   onClick,
 }: CardNoticeProps) => {
+  const isClickable = Boolean(onClick);
   const displayImage = imageUrl || IMAGES.EMPTY_NOTICE_IMAGE;

   const handleImageError = (event: SyntheticEvent<HTMLImageElement>) => {
     event.currentTarget.onerror = null;
     event.currentTarget.src = IMAGES.EMPTY_NOTICE_IMAGE;
   };

   return (
     <button
       className={styles.notice}
-      onClick={onClick}
-      aria-label={`${title} 상세 보기`}
+      onClick={isClickable ? onClick : undefined}
+      disabled={!isClickable}
+      aria-label={isClickable ? `${title} 상세 보기` : undefined}
       type='button'
     >

As per coding guidelines packages/ads-ui/src/**: 접근성(a11y)과 토큰 일관성 우선 검토.

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

In `@packages/ads-ui/src/components/card/card-notice/card-notice.tsx` around lines
33 - 38, The CardNotice button currently presents as interactive even when
onClick is not provided; update the CardNotice rendering logic (the element
using className={styles.notice}, props onClick and title) so that when onClick
is undefined it is rendered as non-interactive: either render a non-interactive
element (e.g., a <div> or <span>) or render the <button> with disabled and
aria-disabled="true" and remove/adjust the interactive aria-label; ensure the
accessible label reflects the non-interactive state and that styles.notice still
applies, or alternatively make onClick a required prop on the CardNotice
component to guarantee interactivity consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/ads-ui/src/components/card/card-notice/card-notice.tsx`:
- Line 3: The import in card-notice.tsx uses a relative path (import { IMAGES }
from '../../../assets';) which violates the repo convention; update it to the
package's absolute alias import (e.g., import { IMAGES } from '@assets' or the
project's defined alias for assets) so it follows the {apps,packages}/**/src/**
absolute import rule (use the same alias pattern used elsewhere like `@pages` or
`@shared`).
- Around line 33-38: The CardNotice button currently presents as interactive
even when onClick is not provided; update the CardNotice rendering logic (the
element using className={styles.notice}, props onClick and title) so that when
onClick is undefined it is rendered as non-interactive: either render a
non-interactive element (e.g., a <div> or <span>) or render the <button> with
disabled and aria-disabled="true" and remove/adjust the interactive aria-label;
ensure the accessible label reflects the non-interactive state and that
styles.notice still applies, or alternatively make onClick a required prop on
the CardNotice component to guarantee interactivity consistently.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c1497f3 and fb587fb.

📒 Files selected for processing (2)
  • packages/ads-ui/src/components/card/card-notice/card-notice.css.ts
  • packages/ads-ui/src/components/card/card-notice/card-notice.tsx

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactor] 저장한 공지 기본 이미지 처리

3 participants