Skip to content

[refactor/native/menu-#236] 메뉴 전체 리팩토링 및 알림 설정 권한 요청 변경#237

Open
b0nsu wants to merge 8 commits intodevelopfrom
refactor/native/menu-#236
Open

[refactor/native/menu-#236] 메뉴 전체 리팩토링 및 알림 설정 권한 요청 변경#237
b0nsu wants to merge 8 commits intodevelopfrom
refactor/native/menu-#236

Conversation

@b0nsu
Copy link
Collaborator

@b0nsu b0nsu commented Mar 5, 2026

✅ Key Changes

이번 PR에서 작업한 내용을 간략히 설명해주세요

case-1: 메뉴 화면 12개 파일 리팩토링
MyInfoScreen providerFormatter 추가
NotificationSettingsScreen 권한 처리 개선
case-2: 메뉴 컴포넌트 14개 파일 리팩토링

@vercel
Copy link

vercel bot commented Mar 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pointer-admin Ready Ready Preview, Comment Mar 10, 2026 2:02pm

Copy link
Collaborator Author

@b0nsu b0nsu left a comment

Choose a reason for hiding this comment

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

리뷰 남깁니다. 동작 회귀 가능성이 있는 지점 위주로 확인했습니다.

  1. [P1] OS 알림 권한이 꺼져 있을 때, 푸시 OFF도 막히는 문제
  • 파일: apps/native/src/features/student/menu/screens/NotificationSettingsScreen.tsx (handlePushEnabledChange)
  • 현재 로직은 !osPermissionGranted이면 newValue와 무관하게 무조건 Linking.openSettings()로 빠집니다.
  • 그래서 앱 토글이 ON 상태 + OS 권한 OFF 상태일 때, 사용자가 앱 내 푸시를 OFF 하려 해도 불가능합니다.
  • 제안: if (!osPermissionGranted && newValue) { openSettings }처럼 ON 시도일 때만 설정 화면 이동 처리
  1. [P1] OS 권한 허용 복귀 시 마케팅/서비스/QnA 토글을 강제로 모두 ON 처리
  • 파일: apps/native/src/features/student/menu/screens/NotificationSettingsScreen.tsx (syncPermission)
  • !wasGranted && granted 분기에서 4개 토글을 모두 true로 저장하고 서버에도 그대로 반영합니다.
  • 사용자가 기존에 마케팅 알림을 OFF 해둔 상태였다면 의도와 다르게 다시 ON 될 수 있습니다.
  • 제안: OS 권한 변화는 마스터 푸시만 동기화하고, 세부 수신 동의값(특히 마케팅)은 기존 사용자 설정을 보존
  1. [P2] 권한 동기화 실패 시 롤백 값이 잘못 복원되는 문제
  • 파일: apps/native/src/features/student/menu/screens/NotificationSettingsScreen.tsx (onError rollback)
  • 해당 분기는 조건상 항상 wasGranted === false 경로라 현재 구현대로면 롤백 시 4개 토글을 전부 false로 내립니다.
  • 즉 실패 전의 실제 사용자 설정으로 복원되지 않습니다.
  • 제안: optimistic 변경 직전 상태(snapshot)를 저장해 실패 시 그 값으로 복원
  1. [P2] 휴대폰 인증 타이머가 wall-clock 기반이 아니라 백그라운드 복귀 시 드리프트 발생
  • 파일: apps/native/src/features/student/menu/screens/info/edit/EditPhoneNumberScreen.tsx
  • 기존 endTime 기반 계산에서 단순 setInterval 감소로 변경되어, 앱 백그라운드 동안 경과 시간이 반영되지 않습니다.
  • 결과적으로 실제 만료보다 UI 잔여 시간이 더 길게 보이거나 재전송 가능 시점이 늦어질 수 있습니다.
  • 제안: expiresAt을 저장하고 remaining = max(0, floor((expiresAt - Date.now())/1000)) 방식으로 계산

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

학생 메뉴 영역(내 정보/설정/공지/약관/탈퇴 등) 화면 및 공용 컴포넌트를 전반적으로 리팩토링하고, 푸시 알림 권한/설정 동기화 로직을 개선하려는 PR입니다.

Changes:

  • 메뉴/내정보 관련 UI를 AnimatedPressable, contentContainerClassName 등으로 정리하고 일부 렌더링/메모이제이션을 개선
  • 내 정보 화면에서 연동 계정(provider) 표기 포맷터 추가
  • 알림 설정 화면에서 OS 권한 상태와 앱 내 토글 상태를 동기화하도록 로직 확장

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
apps/native/src/features/student/menu/screens/info/edit/EditSchoolScreen.tsx 학교 검색 드롭다운 UX 및 Pressable 교체/쿼리 enabled 처리
apps/native/src/features/student/menu/screens/info/edit/EditPhoneNumberScreen.tsx 휴대폰 인증 UI 레이아웃 개편 및 타이머/쿼리 invalidate 추가
apps/native/src/features/student/menu/screens/info/edit/EditNicknameScreen.tsx 객체 shorthand 정리
apps/native/src/features/student/menu/screens/info/MyInfoScreen.tsx provider 표시 포맷팅 추가 및 ScrollView 컨테이너 클래스 정리
apps/native/src/features/student/menu/screens/WithdrawalScreen.tsx 탈퇴 처리 async/await 정리 및 항목 Pressable 교체
apps/native/src/features/student/menu/screens/TermsScreen.tsx 약관 리스트 항목 Pressable 교체(현재 onPress 로직 비어있음)
apps/native/src/features/student/menu/screens/NotificationSettingsScreen.tsx OS 알림 권한 체크 + 토글 동기화/저장 로직 대폭 변경
apps/native/src/features/student/menu/screens/NoticeScreen.tsx readNotice 콜백화 및 FlatList 스타일 상수화
apps/native/src/features/student/menu/screens/MenuScreen.tsx ScrollView contentContainer 및 unreadCount 처리/콜백 전달 정리
apps/native/src/features/student/menu/screens/FeedbackScreen.tsx 피드백 제출 성공/실패 처리 및 pending 상태로 버튼 disable
apps/native/src/features/student/menu/components/UserProfileCard.tsx 학년 라벨 포맷을 gradeOptions 기반으로 통일하고 useMemo 적용
apps/native/src/features/student/menu/components/SettingsToggleItem.tsx Switch trackColor 상수화 및 조건 렌더링 단순화
apps/native/src/features/student/menu/components/ScreenLayout.tsx 뒤로가기 버튼 접근성 속성 추가
apps/native/src/features/student/menu/components/MobileProfileCard.tsx 학년 라벨 포맷을 gradeOptions 기반으로 통일하고 useMemo 적용
apps/native/src/features/student/menu/components/MenuListItem.tsx 접근성 라벨 추가 및 조건 렌더링 정리
apps/native/src/features/student/menu/components/InfoSection.tsx fields map key를 index → label로 변경
apps/native/src/features/student/menu/components/IconMenuItem.tsx 접근성 라벨 추가 및 불필요 prop 제거
apps/native/src/features/student/menu/components/EditScreenLayout.tsx ScrollView contentContainer 스타일을 className 기반으로 변경
Comments suppressed due to low confidence (1)

apps/native/src/features/student/menu/screens/info/edit/EditSchoolScreen.tsx:42

  • useGetSchool is disabled when debouncedQuery is empty, but React Query will keep the previous data value. This means clearing the input (e.g., via handleClear) can still show stale dropdown results from the last non-empty query. Consider explicitly clearing/hiding the dropdown when the query becomes empty (or keep the query enabled with an empty string so results reset).
  const debouncedQuery = useDebounce(query.trim(), 300);
  const { data, isLoading } = useGetSchool(
    { query: debouncedQuery },
    debouncedQuery.length > 0
  );

  const results = data?.data ?? [];
  const showDropdown = dropdownVisible && (results.length > 0 || isLoading);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 44 to +55
useEffect(() => {
if (!endTime) return;

const interval = setInterval(() => {
const remaining = Math.max(0, Math.floor((endTime - Date.now()) / 1000));
if (!isCodeSent || expiresAt === null) {
return;
}

const syncRemainingTime = () => {
const remaining = Math.max(0, Math.floor((expiresAt - Date.now()) / 1000));
setTimer(remaining);

if (remaining === 0) {
clearInterval(interval);
// 여기서 인증 만료 처리해도 됨
setExpiresAt(null);
}
}, 1000);
};
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

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

When the timer reaches 0 you only set expiresAt to null, but isCodeSent remains true, so the verification-code input stays visible even though the code is expired (and the CTA switches back to “인증번호 받기”). Consider also resetting isCodeSent/verificationCode/verifyFeedbackMessage on expiry, or condition the verification UI on expiresAt !== null.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This has already been addressed in 861ec8b.
On expiry, we now call resetVerificationSession() which clears isCodeSent, verificationCode, verifyFeedbackMessage, expiresAt, and
timer, so the verification UI no longer remains visible after expiration.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

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.

[refactor/native/menu] 전체 리팩토링 및 알림설정 권한 체크 변경

2 participants