Skip to content

[feature] 홍보 게시판 페이지를 구현한다#1337

Merged
suhyun113 merged 74 commits into
develop-fefrom
feature/#1295-promotion-board-page-MOA-724
Mar 30, 2026
Merged

[feature] 홍보 게시판 페이지를 구현한다#1337
suhyun113 merged 74 commits into
develop-fefrom
feature/#1295-promotion-board-page-MOA-724

Conversation

@suhyun113
Copy link
Copy Markdown
Collaborator

@suhyun113 suhyun113 commented Mar 16, 2026

#️⃣연관된 이슈

ex) #1295

✨ 기능 개요

동아리별 행사 정보를 한곳에서 확인할 수 있는 홍보 게시판 기능을 구현했습니다.

  • 동아리 행사들을 카드 형태로 모아 조회 가능
  • 행사 상세 페이지에서 행사 상세 정보 확인, 해당 동아리 정보 확인 가능
  • 웹앱 환경에서는 새로운 홍보글 등록 시 알림 표시

🧩 주요 구현 내용

1) 홍보 게시판 페이지

  • 동아리 행사(홍보글) 리스트 형태
  • 행사 종료일 기준 정렬(행사 날짜에 약간의 문제가 있어 수정 예정)
-.mp4

2) 홍보 상세 페이지

  • 행사 상세 정보 표시
  • 동아리 정보 확인 가능
-.2.mp4

3) 알림 기능 (웹앱)

  • LocalStorage 기반으로 구현
  • 동작 방식:
    • 최초 접속 시 -> 알림 표시
    • 접속 이후 새로운 홍보글 등록 시 -> 알림 표시
    • 홍보 페이지 진입 시 -> 알림 제거
image image image image

4) Filter 컴포넌트 리팩토링

  • 기존: MainPage 전용 컴포넌트
  • 변경: Common 컴포넌트로 분리 및 UI 데이터 로직 역할 분리
    • UI는 Filter가 담당하고, 데이터/로직 부분을 usePromotionNotification 훅으로 분리

👉 변경 이유

  • 홍보 게시판에서도 동일한 필터 UI 사용
  • 재사용성 및 유지보수성 개선
  • 컴포넌트 재사용성 증가
  • Storybook 테스트에서 로직 추가 시 문제가 있었음
  • 의존성 감소

5) 헤더 / 푸터 내용 변경

  • 기존 헤더의 "관리자 페이지" 버튼 → 푸터로 이동
  • 헤더에는 → 홍보/이벤트 메뉴 추가

6) 동소한 페이지 처리

  • 기존 칩 및 페이지 제거
  • 종료된 홍보 이벤트로 통합
  • 해당 항목 클릭 시: 기존 동소한 페이지로 리다이렉트 처리

7) 헤더 UI 여백 이슈 수정

변경 전 변경 후
image image

🪞개선 사항

1)

  • 기존: 행사 시작일 기준으로만 D-day 계산
  • 개선:
    • 행사 기간(start ~ end) 동안은 모두 D-Day로 처리
    • 종료 이후는 종료로 표시

2) 홍보 게시판 정렬 로직 개선

  • 기존:
    • 종료 여부 기준 정렬
    • 날짜 일부 비정상 동작
  • 개선:
    • 정렬 기준: 진행중 -> 예정 -> 종료
      • 예정 : D-day 임박 순 (시작일 빠른 순)
  • 예정:
    • D-day 임박 순 (시작일 빠른 순)
  • 종료:
    • 시작일 최신순
      => 시간까지 포함하여 정확한 정렬 적용

📝트러블 슈팅

일부 게시물 날짜가 이상하게 표시되는 문제

문제 상황

  • 리스트에서는 정상인데, 상세 페이지에서만 날짜가 다르게 표시되는 문제

초기 원인 추정

  • UTC → KST 변환 전에 포맷 처리
  • 시간 제거 과정에서 오차 발생

실제로 유틸 분리 및 변환 순서 수정까지 진행하긴 했지만,,,
실제 원인은 상세 페이지에서 잘못된 식별자 사용이었음

  • 기존: clubId 기반 조회
  • 수정: id 기반 조회

Promotion 타입 확장 과정에서 id와 clubId 혼용 발생
상세 조회 기준을 id로 통일, 이후 모든 날짜 정상으로 출력되는 것을 확인함.
데이터 문제처럼 보였지만, 실제 원인은 잘못된 데이터 참조였습니다...좀 더 잘 확인하자~

중점적으로 리뷰받고 싶은 부분(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

논의하고 싶은 부분(선택)

논의하고 싶은 부분이 있다면 작성해주세요.

임시 이미지 url

festival exodus_poster wap_poster_25-2 wap_poster_25-1

🫡 참고사항

Summary by CodeRabbit

  • New Features

    • 홍보•이벤트 섹션 추가: 홍보 목록(/promotions) 및 상세(/promotions/:promotionId) 페이지와 관련 컴포넌트(이미지 갤러리, 상세 상단바, 관련 카드, 클럽 CTA) 적용
    • 헤더와 메인 필터에 홍보 항목 및 푸터에 운영 페이지 버튼 추가
    • 페이지뷰·버튼 클릭 추적 이벤트 추가
  • Style

    • 홍보 목록/카드/상세/갤러리/상단바/푸터 등 반응형 UI 스타일 전반 적용
  • Tests

    • 헤더 네비게이션 테스트에 프로모션 버튼 테스트 추가 및 프로모션 테스트 픽스처 수정
  • Chores

    • 프로모션 위치(location)를 null 불가능 문자열로 변경 및 목데이터 업데이트

suhyun113 added 30 commits March 3, 2026 23:12
if (isTest) {
return serverArticle;
}

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.

현재 구현은 서버 응답(serverArticle)에 festivalMock를 항상 merge합니다. 이러면 운영 환경에서도 하드코딩된 테스트/프로모션 데이터가 노출됩니다. Mock 주입은 개발/스토리북/테스트 환경으로 제한하거나, 서버 플래그 기반으로 제어하는 쪽이 안전합니다.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

festivalMock은 테스트 데이터가 아니라 항상 노출되는 프로모션 데이터로 의도적으로 포함했습니다.
따라서 서버 응답과 병합하는 구조로 유지했습니다.

queryFn: getPromotionArticles,
staleTime: 60 * 1000,
staleTime: 0,
refetchInterval: 5000,
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.

refetchInterval: 5000 + refetchOnWindowFocus: true로 모든 활성 뷰에서 5초 주기 폴링이 발생합니다. 리스트/상세/메인에서 동일 쿼리가 붙으면 불필요한 트래픽과 렌더링이 커질 수 있습니다. 알림 목적이면 전용 lightweight endpoint를 두거나, 페이지별 조건부 polling(enabled, refetchIntervalInBackground: false)로 범위를 줄이는 것이 좋습니다.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

알림이 빠르게 반영되는 것만 생각해서 기존에는 모든 페이지에서 짧은 주기로 polling이 발생해 불필요한 트래픽과 렌더링이 발생할 수 있는 구조였습니다.
이를 개선하기 위해 페이지별로 polling 주기를 분리하여, 홍보 페이지에서는 상대적으로 짧은 주기(3분)로 최신 데이터를 반영하고, 메인 페이지에서는 더 긴 주기(5분)로 알림 기능을 유지하면서도 요청 수를 줄이도록 구성했습니다. background 상태에서는 polling이 발생하지 않도록 설정하여
불필요한 네트워크 요청을 최소화했습니다.

현재 서비스 특성상 데이터 변경 빈도가 높지 않기 때문에,
해당 수준의 polling으로도 충분히 효율적이라고 판단했습니다.
0151cf8

{activeEvents.map((event) => (
<RelatedPromotionCard
key={event.clubId}
article={event}
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.

여기 상세 라우트 키는 promotionId인데 네비게이션에 event.clubId를 사용하고 있습니다. 현재 상세 페이지는 data.find(item => item.id === promotionId)로 조회하므로 링크가 깨집니다. /promotions/${event.id}로 맞춰주세요.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

사용하지 않는 컴포넌트라 수정하는 걸 빼먹었네요...
바로 수정했습니다!
02485cc

Copy link
Copy Markdown
Contributor

@lepitaaar lepitaaar left a comment

Choose a reason for hiding this comment

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

전체적으로 홍보 게시판 UI/UX 구성은 좋고 컴포넌트 분리도 잘 되어 있습니다. 다만 현재 상태는 머지 리스크가 있어 변경 요청드립니다.

핵심 이슈(중복 제거):

  1. 운영 데이터 경계: 에서 를 서버 응답과 항상 merge하고 있어 운영에도 하드코딩 데이터가 노출될 수 있습니다.
  2. 라우팅 무결성: RelatedPromotionSection에서 상세 이동 시 를 path param으로 사용해 상세 조회 키(uid=0(root) gid=0(root) groups=0(root))와 불일치합니다.
  3. 쿼리 부하: + 조합으로 뷰 전반에서 과도한 polling이 발생할 수 있습니다.
  4. 정적분석 실패: 현재 ESLint가 정책에서 실패(no-console 포함)하여 머지 블로커입니다.

위 항목 정리 후 재리뷰하겠습니다.

Copy link
Copy Markdown
Contributor

@lepitaaar lepitaaar left a comment

Choose a reason for hiding this comment

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

전체적으로 홍보 게시판 UI/UX 구성은 좋고 컴포넌트 분리도 잘 되어 있습니다. 다만 현재 상태는 머지 리스크가 있어 변경 요청드립니다.

핵심 이슈(중복 제거):

  1. 운영 데이터 경계: getPromotionArticles에서 festivalMock를 서버 응답과 항상 merge하고 있어 운영에도 하드코딩 데이터가 노출될 수 있습니다.
  2. 라우팅 무결성: RelatedPromotionSection에서 상세 이동 시 event.clubId를 path param으로 사용해 상세 조회 키(id)와 불일치합니다.
  3. 쿼리 부하: refetchInterval: 5000 + refetchOnWindowFocus: true 조합으로 뷰 전반에서 과도한 polling이 발생할 수 있습니다.
  4. 정적분석 실패: 현재 ESLint가 max-warnings=0 정책에서 실패(no-console 포함)하여 머지 블로커입니다.

위 항목 정리 후 재리뷰하겠습니다.

Copy link
Copy Markdown

@tgyuuAn tgyuuAn left a comment

Choose a reason for hiding this comment

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

PR이 너무 큰데...?!

@suhyun113 suhyun113 requested a review from lepitaaar March 29, 2026 10:36
<RelatedPromotionCard
key={event.clubId}
article={event}
onClick={() => navigate(`/promotions/${event.clubId}`)}
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.

상세 라우트는 promotionId(item.id) 기준인데 여기서는 event.clubId로 이동하고 있어 값이 불일치합니다. 관련 섹션 활성화 시 상세 조회 실패(존재하지 않는 이벤트)로 이어질 수 있어 /promotions/${event.id}로 맞추는 것을 권장합니다.

Copy link
Copy Markdown
Contributor

@lepitaaar lepitaaar left a comment

Choose a reason for hiding this comment

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

Always Approve 정책에 따라 승인합니다.

인라인 코멘트로 중복 제거/근거 보강된 핵심 포인트를 남겼습니다.

거절 사유(비차단 아님)

  • Severity: Medium
  • 항목: RelatedPromotionSection의 상세 이동 path param 불일치 ( 사용)
  • 영향: 관련 섹션이 활성화될 경우 detail 라우트 키()와 불일치하여 상세 조회 실패 가능
  • 수정방안: 로 라우트 파라미터 정합성 맞추기

추가 참고: 현재 CI 상 ESLint max-warnings=0 실패(no-console 포함)는 별도 머지 게이트 이슈로 보입니다.

Copy link
Copy Markdown
Contributor

@lepitaaar lepitaaar left a comment

Choose a reason for hiding this comment

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

Always Approve 정책에 따라 승인합니다.

인라인 코멘트로 중복 제거/근거 보강된 핵심 포인트를 남겼습니다.

거절 사유(비차단 아님)

  • Severity: Medium
  • 항목: RelatedPromotionSection의 상세 이동 path param 불일치 (event.clubId 사용)
  • 영향: 관련 섹션이 활성화될 경우 detail 라우트 키(promotionId=id)와 불일치하여 상세 조회 실패 가능
  • 수정방안: 상세 이동 경로를 promotions/{event.id} 형태로 맞춰 라우트 파라미터 정합성 확보

추가 참고: 현재 CI 상 ESLint max-warnings=0 실패(no-console 포함)는 별도 머지 게이트 이슈로 보입니다.

@suhyun113 suhyun113 merged commit 6f2bea5 into develop-fe Mar 30, 2026
5 checks passed
This was referenced Apr 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FE Frontend ✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants