Skip to content

일반 공지 get api 연결 및 모달 ui 생성#32

Merged
kimnamheeee merged 10 commits into
developfrom
feat/announcement
May 9, 2026
Merged

일반 공지 get api 연결 및 모달 ui 생성#32
kimnamheeee merged 10 commits into
developfrom
feat/announcement

Conversation

@kimnamheeee

@kimnamheeee kimnamheeee commented May 3, 2026

Copy link
Copy Markdown
Collaborator

작업 내용

인앱 공지 api 연결 및 모달 생성

홈 진입 시 일반 공지를 노출할 수 있도록 공지/약관 API 계층을 추가하고, 홈 화면에 공지 모달 렌더링 및 prefetch 로직을 붙였습니다.

1. 공지/약관 API 계층 추가

  • Announcement, Term entity를 추가했습니다.
  • GET /v1/announcements, GET /v1/terms를 호출하는 repository를 추가했습니다.
  • announcement/term usecase를 추가하고 serviceContextApp.tsx에 주입했습니다.
  • terms 조회는 기존 보호 API 패턴에 맞춰 토큰이 없으면 호출 전에 에러를 던지도록 구현했습니다.

2. 홈 공지 노출 로직 추가

  • 홈 전용 공지 query 설정을 src/features/home/utils/announcementQueries.ts로 분리했습니다.
  • useHomeAnnouncements 훅에서 다음 책임을 담당하도록 구성했습니다.
    • 공지 query 사용
    • 앱 세션 기준 최초 1회 노출 정책 적용
    • 모달 큐 구성 및 현재 공지 관리
    • 닫기/숨김 핸들러 제공
  • HomeScreen은 공지 오케스트레이션을 훅에 위임하고, 현재 공지가 있을 때만 AnnouncementModal을 렌더링하도록 정리했습니다.

3. 홈 공지 prefetch 적용

  • HomeTab 진입 시 prefetchQuery로 공지 데이터를 미리 캐시에 적재하도록 구성했습니다.
  • query key / queryFn / staleTime은 홈 전용 query options를 공유하도록 정리해 중복을 줄였습니다.

4. 공지 전용 모달 추가

  • 공지 전용 AnnouncementModal을 추가했습니다.
  • 공용 AlertModal을 확장하지 않고, 공지 요구사항에 맞는 별도 UI로 분리했습니다. (나중에 모달 종류가 많아지면 AlertModal을 composite pattern으로 리팩토링하는 것도 좋다고 생각합니다)
  • 모달 UI는 다음 요소를 포함합니다.
    • 상단 공지 배지
    • 우상단 닫기 버튼
    • 긴 본문을 위한 내부 스크롤 영역
    • 다시 보지 않기 체크박스
    • 중앙 정렬 CTA 버튼
  • 작은 화면에서도 모달이 잘리지 않도록 실제 높이는 min(500, 화면 높이 - safe area - 여백) 기준으로 계산합니다.
  • backdrop과 콘텐츠 영역을 분리해, 본문 스크롤과 배경 dismiss가 서로 간섭하지 않도록 구성했습니다.

5. 공용 컬러 상수 정리

  • AnnouncementModal의 일부 하드코딩 색상을 Colors 상수로 치환했습니다.
  • 이 과정에서 figma에는 정의되어 있지만 Colors에는 없던 POINTCOLOR_10을 추가해 공지 배지 배경에 사용했습니다.

Notes

  • 현재 다시 보지 않기는 서버 dismiss API 연동 전 단계입니다. 약관 렌더링 PR 이후, 약관 동의와 함께 api 연결할 예정해서 세 번째 PR로 올릴 예정입니다.
  • 약관 entity/repository/usecase는 이번 PR에 포함되지만, 홈 약관 렌더링 로직은 현재 포함하지 않았습니다. (일반 공지만 노출)

스크린샷 (선택)

Simulator Screenshot - iPhone 17 Pro - 2026-05-03 at 02 02 24

체크

  • 정상 동작 확인
  • UI 깨짐 없음
  • 콘솔 에러 없음

@kimnamheeee kimnamheeee marked this pull request as draft May 3, 2026 12:46
@kimnamheeee kimnamheeee marked this pull request as ready for review May 4, 2026 08:55
Comment thread src/tabs/HomeTab.tsx Outdated
const Stack = createNativeStackNavigator<StackParamList>()

export function HomeTab() {
const { announcementService } = useContext(serviceContext)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Screen이 아니라 tab에서 구현하신 이유가 있나요?

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.

뭔가 이 useContext + useEffect의 거취가 굉장히 애매해서 고민을 하다가 이렇게 된 것 같습니다... 근데 screen으로 가는 게 좋을 것 같군요

@kimnamheeee kimnamheeee May 7, 2026

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.

아 그리고 그것도 있었습니다
공지 모달이 홈에 첫 진입할 때 즉시 표시되게 하려면 홈 스택 진입 시점에 prefetch가 필요하다고 생각했고, 그래서 홈 화면 관련된 가장 바깥 레이어인 hometab에 넣었습니다 (홈화면 렌더 전에 데이터를 가져와서 보여줘야 늦지 않게 공지가 노출될 것 같았습니다)

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.

이걸 여기에 넣어서 뭔가 책임 분리가 안 된 것 같은 느낌이 있는데 어떻게 하면 좋을지 고민이 되는군요 🥲

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

현재 App.tsx에서

useEffect(() => {
    setIsNavigationReady(true)
    setTimeout(() => SplashScreen.hide(), 1000)
}, [])

로 1초 뒤에 SplashScreen을 숨기는데, 이 전에 HomeScreen의 렌더가 실행되므로 따로 prefetch 로직은 두지 않아도 될거 같습니다.
이에 따라 announcementQueries도 훅에 포함시켜도 될거 같습니다.

참고) claude와 함께한 공부

  1. useEffect는 자식 -> 부모 컴포넌트 순으로 실행(bubbling)되기에, 지금처럼 HomeTab -> HomeScreen으로 타고 가는 구조면 HomeScreen의 useEffect가 먼저 실행되어 HomeTab의 useEffect는 prefetch의 기능을 하지 못한다고 합니다.
  2. 의도하신대로 홈화면 렌더 전에 데이터를 가져오려면(SplashScreen이 없었다면) HomeTab에서 usePrefetchQuery를 사용했어야 합니다.

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.

아하 스플래시 스크린이 무조건 1초 표시되는 구조라서 홈이 보이기 전에 데이터를 받아두는 건 충분히 달성 가능하겠네요

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.

그리고 지금

  1. React가 HomeTab을 렌더링함 - Stack.Navigator, Stack.Screen, HomeScreen 같은 트리가 만들어짐
  2. 렌더가 다 끝난 뒤 commit 단계가 오고 그 다음에야 useEffect들이 실행됨. 그래서 지금 구조대로면 queryClient.prefetchQuery를 써도 소용이 없음

이라서 useEffect를 쓴 것도 판단미스였군요...

좋은 피드백 감사합니다 최고

@@ -0,0 +1,10 @@
import { AnnouncementService } from '@/usecases/announcement'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

hook에 포함 안하고 따로 util로 빼신 이유가 있나요?

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.

이 옵션이 현재 두 군데서 사용이 되고 있습니다

  • HomeTab에 구현되어 있는 훅
  • custom hook으로 구현되어 있는 useHomeAnnouncements

원래 이 둘을 하나의 훅으로 완전 통합하는 방향도 생각을 해 봤는데, 둘은 역할이 다르다고 생각해서 + HomeTab에 있는 로직은 커스텀 훅으로 빼면 진짜 단순 분리 이상의 의미를 가지지 못할 것 같아서 현재 상태가 되었습니다

Comment thread src/features/home/components/AnnouncementModal.tsx
Comment thread src/entities/term.ts
@kimnamheeee kimnamheeee self-assigned this May 8, 2026
@kimnamheeee kimnamheeee merged commit ef2936f into develop May 9, 2026
Daniel-Na118 pushed a commit that referenced this pull request May 26, 2026
* feat: add GET announcement, term functions

* feat: integrate announcement and term services into App component

* feat: add announcement and term services to ServiceContext

* feat: add announcement modal ui and actions

* fix: update missing colors

* style: update dim background blur

* refactor: apply typography class and scaling utils

* refactor: replace announcement query options with a custom hook and remove unused utility file
Daniel-Na118 added a commit that referenced this pull request May 26, 2026
* feat: add sharing component

* Fixed sharing link

* Android Intent Filter Changes

* Link Structure Change

* ios settings change

* ios universal links logic added

* chore: add associated domains

* fix: url duplicate

* Refactor/home screen (#23)

* refactor: simplify tab navigator icon and screen options setup

* fix: correct spelling of RecommendClubCard component

* refactor: remove unnecessary 'display: flex' styles from HomeScreen components

* refactor: replace inline styles with StyleSheet.create in HomeScreen

* feat: prevent whitespace-only query and improve keyboard handling

* refactor: replace React import with specific hooks in home components

* refactor: migrate useQuery calls and rename function

* Refactor/overall structure (#24)

* refactor: move common modules to shared

* refactor: remove unused constants.ts

* refactor: move ENV.ts to config

* refactor: move localStorage.ts to constants

* refactor: flatten shared component modules

* refactor: flatten tab modules

* refactor: rearrange screens to each feature

* refactor: replace import path with @/ alias and cleanup relative paths

* fix: remove unnecessary whiteSpace style

* docs: update README.md and remove unused markdown file

* fix: iOS 인증 재구성

* fix: apple login error in simulators

* ios xcode settings change

* app.tsx hometab change

* Typography, layout scaling util 구현 (#34)

* feat: add scale utility for responsive sizing

* feat: add typography constants

* feat: apply typography and layout scaling for club components

* feat: add font files and add font weight mapping

* 홈 화면 리뉴얼 (#35)

* refactor: rename RecommendedClubCard to ClubPreviewCard and move to shared directory

* refactor: rename and change directory of home screen components

* feat: add new category icons and update Category type structure

* feat: implement CategoryCard and CategorySection component

* feat: refactor home screen layout and implement LatestClubsSection component

* fix: reset scroll when leave home screen

* TabBar 및 저장한 동아리 탭 디자인 반영 (#37)

* feat: add new tab icons and remove outdated image assets

* feat: remove type assertion of router params and adjust navigation prop type

* feat: add SavedTab component and apply new tab bar design

* feat: apply new design to SavedClubListScreen and move to feature directory

* feat: update background color to BACKGROUND_MAIN in Header and ClubListScreen

* fix: change snu icon directory

* 짜잘한 디자인 수정 및 리팩토링 (#38)

* design: remove white background and refactor ClubList header component

* design: replace tab bar icon to png

* design: remove LinearGradient from ClubListScreen

* design: update ClubCard styles and add new typography constant

* design: add empty placeholder text to ClubList component and change image

* chore: remove unused image assets

* refactor: separate category types to constants/ and update colors

* refactor: move screen.ts to constants/

* design: update ClubPreviewCard styles and add variant

* design: add border radius to ClubCard image

* design: adjust shadow of CategorySection styles

* design:  update HomeScreen header logo and adjust margin

* style: remove variant and add box shadow to club preview card (#39)

* 일반 공지 get api 연결 및 모달 ui 생성 (#32)

* feat: add GET announcement, term functions

* feat: integrate announcement and term services into App component

* feat: add announcement and term services to ServiceContext

* feat: add announcement modal ui and actions

* fix: update missing colors

* style: update dim background blur

* refactor: apply typography class and scaling utils

* refactor: replace announcement query options with a custom hook and remove unused utility file

* 일반 공지 dismiss api 연결 (#43)

* design: add background color for shadow of ClubPreviewCard on Android (#44)

* fix: add tabbar inset (#46)

* iOS 빌드 시 env 파일 생성되는 오류 수정 (#47)

* chore: remove blurhash library from iOS setup

* fix: remove auto-generated .env and fix Local scheme quote bug

* husky와 lint-staged를 이용한 pre-commit, pre-push 훅 추가 (#48)

* chore: add husky pre-commit and pre-push hooks with lint-staged and TypeScript checks

* style: apply prettier formatting across the codebase

* 검색페이지 생성(하단탭, 검색결과페이지 연결), 검색바 컴포넌트 구현 (#45)

* 검색페이지 생성 - 탭2 에서 진입, 검색바 컴포넌트 구현, 검색결과페이지 연결

* add max_length indicator

* fix max_length

* fix searchBar

* min duration toggle 컴포넌트 구현 (#40)

* AI agent를 위한 md 파일 생성 (#49)

* docs: add AGENTS.md for project commands and structure

* docs: update AGENTS.md with editing guidelines for before and after changes

* ClubList에 동아리 목록 로딩 시 보여주는 Skeleton screen 구현 및 캐싱 수정 (#50)

* docs: add AGENTS.md for project commands and structure

* feat: add skeleton screen to ClubList

* refactor: update cache settings for queryClient and remove staleTime from useCategoryClubs

* fix: use isLoading instead of inFetching and set staleTime to infinity

* Login Bottom Sheet 개선 및 Toast 스타일 수정 (#54)

* style: refactor toast component styling and visibility time

* feat: add login bottom sheet trigger on Saved tab press for unauthenticated users

* feat: apply height scaling and handle context error to loginBottomSheetContext

* feat: apply scaling and add error handling to LoginView

* feat: add tab navigation after login

* feat: add loading state and indicator after login

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: match params

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>

* Auth token caching 및 axios interceptor 도입 (#55)

* style: refactor toast component styling and visibility time

* feat: add login bottom sheet trigger on Saved tab press for unauthenticated users

* feat: apply height scaling and handle context error to loginBottomSheetContext

* feat: apply scaling and add error handling to LoginView

* feat: add tab navigation after login

* feat: add loading state and disable buttons during login process

* refactor: remove unused styles from MyPageScreen

* refactor: cache auth token in memory to avoid repeated AsyncStorage I/O

* refactor: remove unnecessary URLSearchParams from club.ts

* fix: match params

* 검색페이지 - 결과페이지 통합, 최근검색어 구현(API 미연결) (#53)

* 임시 커밋

* 검색 결과 페이지를 검색 페이지로 통합

- SearchResultClubListScreen 제거, SearchScreen 한 화면에서 검색바 고정 + 결과 영역 토글
- 탭/헤더 클릭 시 navigation.reset + 검색 상태 초기화 (animation: 'none')
- SearchInput unified (SearchResultClubList variant 제거), autoCapitalize/autoCorrect off
- SearchResultClubList 하위 컴포넌트(ClubListItem, SearchFilterBar, SearchResultList, TypoCorrectionNotice)를 features/search/components로 이동
- SCREEN_TYPE.SEARCH_RESULT_CLUB_LIST 및 search_result_screen 애널리틱스 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* 최근 검색어 섹션 구현 (UI only)

- RecentSearches 컴포넌트 추가: 헤더("최근 검색어") + "검색내역 지우기" 버튼 + chip wrap / 빈 상태 메시지("최근 검색한 내역이 없어요. 새로운 동아리를 탐색해보세요!")
- SearchScreen의 미제출 상태 placeholder에 통합, recentSearches state 및 select/clear 핸들러 연결

TODO: 현재는 mock data로 채워둔 상태. 백엔드 검색 관련 PR 머지된 후 API 응답으로 교체 필요. 이 PR(검색 페이지)이 dev에 머지되기 전에 반드시 수정되어야 함.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* delete mock data

* recent-searches:  fontLineHeight and padding setting

* delete mock data

* refactor: features/search를 features/club 하위로 통합

검색 화면이 동아리 도메인에 속하고 SearchBar·SearchFilterBar가
카테고리 화면에서도 재사용될 예정이라 features/club 하위로 이동.

- SearchInput을 SearchBar로 리네임
- ClubListItem/SearchResultList 제거, ClubList/ClubCard로 일원화
- ClubCard '리뷰 없어요' 분기는 기존 리뷰 뱃지를 재사용
- ClubList에 pageSize prop 추가 (백엔드 페이지네이션 도입 전 임시방편)
- 검색 결과 카드 리뷰 뱃지 폴백 색을 보라 톤(BUTTON_SELECTED/POINTCOLOR_10)으로 변경
- SearchScreen에 스켈레톤(isFetching) 적용, 미사용 ♥ 토글 로직 제거

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* style: 검색 페이지 헤더 패딩 조정

헤더 컨테이너 paddingTop(vs(32)) 제거, 헤더 텍스트 paddingVertical(vs(10)) 설정으로 여백 일원화.

* refactor: ClubList 클라이언트 페이지네이션 로직 제거

---------

Co-authored-by: dennis0405 <dennis0405@snu.ac.kr>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* 검색 상세 필터 오버레이 생성 (#52)

* style: remove unused style

* style: apply color, typography constats

* feat: add SearchFilterBar component

* fix: apply newline

* feat: add search filter overlay

* feat: add filtering logic to search api

* feat: match updated query schema

* feat: match updated query schema

* refactor: centralize filter states

* style: add box-shadow

* fix: enable multiple selection for searchfilterbar

* feat: only reset filters on overlay

* feat: update searchfilterbar component and add searchfilteroverlay

* fix: update api schema

* fix: update search filter overlay label

* feat: enhance SearchScreen with focus effect to manage filter overlay visibility

* style: simplify room and fee options in SearchFilterOverlay component

* fix: hide filter overlay when submitting search query in SearchScreen

* chore: remove unused screen

* fix: merge conflicts and removed unneeded code

---------

Co-authored-by: Jaewoong Choi <jwchoi.tech@gmail.com>
Co-authored-by: Jeongyeon Lee <jylee05@snu.ac.kr>
Co-authored-by: cirtuare <cirtuare@gmail.com>
Co-authored-by: Nam Hee Kim <103100783+kimnamheeee@users.noreply.github.com>
Co-authored-by: SeungYeon Kwag <95578121+cloNoey@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: dennis0405 <dennis0405@snu.ac.kr>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants