-
Notifications
You must be signed in to change notification settings - Fork 0
[FIX] 9월 3주차 2차 QA 사항 - 희용 #260
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e77e359
d0f427a
c9828fe
03dcdba
0cc35c7
3c3367c
5c90a7a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import { apiClient } from '../index'; | ||
|
|
||
| export interface PostNotificationsCheckRequest { | ||
| notificationId: number; | ||
| } | ||
|
|
||
| export interface PostNotificationsCheckResponse<Params = Record<string, unknown>> { | ||
| isSuccess: boolean; | ||
| code: number; | ||
| message: string; | ||
| data: { | ||
| route: string; // e.g., 'POST_DETAIL' | ||
| params?: Params; // e.g., { postId: 123 } | ||
| }; | ||
| } | ||
|
|
||
| // 알림 확인(체크) 및 이동 정보 반환 API | ||
| export const postNotificationsCheck = async (notificationId: number) => { | ||
| const body: PostNotificationsCheckRequest = { notificationId }; | ||
| const response = await apiClient.post<PostNotificationsCheckResponse>( | ||
| '/notifications/check', | ||
| body, | ||
| ); | ||
| return response.data; | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,8 @@ | ||
| import { createRoot } from 'react-dom/client'; | ||
| import './main.css'; | ||
| import App from './App.tsx'; | ||
| import { initGA, sendPageView } from './lib/ga.ts'; | ||
| import { initGA } from './lib/ga.ts'; | ||
|
|
||
| initGA(); | ||
| sendPageView(window.location.pathname); | ||
|
|
||
| createRoot(document.getElementById('root')!).render(<App />); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ import TitleHeader from '@/components/common/TitleHeader'; | |||||||||||||||||||||||||||||||||||||||||||
| import leftArrow from '../../assets/common/leftArrow.svg'; | ||||||||||||||||||||||||||||||||||||||||||||
| import { colors, typography } from '@/styles/global/global'; | ||||||||||||||||||||||||||||||||||||||||||||
| import { getNotifications, type NotificationItem } from '@/api/notifications/getNotifications'; | ||||||||||||||||||||||||||||||||||||||||||||
| import { postNotificationsCheck } from '@/api/notifications/postNotificationsCheck'; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const Notice = () => { | ||||||||||||||||||||||||||||||||||||||||||||
| const [selected, setSelected] = useState<string>(''); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -78,16 +79,91 @@ const Notice = () => { | |||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||
| }, [isLoading, isLast, nextCursor, loadNotifications]); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // const handleReadNotification = (index: number) => { | ||||||||||||||||||||||||||||||||||||||||||||
| // setNotifications(prev => | ||||||||||||||||||||||||||||||||||||||||||||
| // prev.map((item, idx) => (idx === index ? { ...item, isChecked: true } : item)), | ||||||||||||||||||||||||||||||||||||||||||||
| // ); | ||||||||||||||||||||||||||||||||||||||||||||
| // }; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const filteredNotifications = notifications; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const tabs = ['피드', '모임']; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const handleNotificationClick = async (notif: NotificationItem) => { | ||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||
| const res = await postNotificationsCheck(notif.notificationId); | ||||||||||||||||||||||||||||||||||||||||||||
| if (!res.isSuccess) return; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // UI 즉시 반영: 읽음 처리 | ||||||||||||||||||||||||||||||||||||||||||||
| // setNotifications(prev => | ||||||||||||||||||||||||||||||||||||||||||||
| // prev.map(item => | ||||||||||||||||||||||||||||||||||||||||||||
| // item.notificationId === notif.notificationId ? { ...item, isChecked: true } : item, | ||||||||||||||||||||||||||||||||||||||||||||
| // ), | ||||||||||||||||||||||||||||||||||||||||||||
| // ); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const { route, params } = res.data as { route: string; params?: Record<string, unknown> }; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // 서버 라우팅 키 → 실제 앱 경로 매핑 | ||||||||||||||||||||||||||||||||||||||||||||
| switch (route) { | ||||||||||||||||||||||||||||||||||||||||||||
| // 이동 없음 | ||||||||||||||||||||||||||||||||||||||||||||
| case 'NONE': | ||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // 피드 1번 (해당유저 피드로 이동) | ||||||||||||||||||||||||||||||||||||||||||||
| case 'FEED_USER': { | ||||||||||||||||||||||||||||||||||||||||||||
| const userId = (params?.userId as number) ?? undefined; | ||||||||||||||||||||||||||||||||||||||||||||
| if (userId !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||
| navigate(`/otherfeed/${userId}`); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // 피드 2~6번 (피드상세페이지로 이동) | ||||||||||||||||||||||||||||||||||||||||||||
| case 'FEED_DETAIL': { | ||||||||||||||||||||||||||||||||||||||||||||
| const feedId = (params?.feedId as number) ?? undefined; | ||||||||||||||||||||||||||||||||||||||||||||
| if (feedId !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||
| navigate(`/feed/${feedId}`); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // 모임 (모집조기마감 or 모임시작) | ||||||||||||||||||||||||||||||||||||||||||||
| case 'ROOM_MAIN': { | ||||||||||||||||||||||||||||||||||||||||||||
| const roomId = (params?.roomId as number) ?? undefined; | ||||||||||||||||||||||||||||||||||||||||||||
| if (roomId !== undefined) navigate(`/group/detail/joined/${roomId}`); | ||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // host일때, 누군가 모임 참여를 눌렀을 때 | ||||||||||||||||||||||||||||||||||||||||||||
| case 'ROOM_DETAIL': { | ||||||||||||||||||||||||||||||||||||||||||||
| const roomId = (params?.roomId as number) ?? undefined; | ||||||||||||||||||||||||||||||||||||||||||||
| if (roomId !== undefined) navigate(`/group/detail/${roomId}`); | ||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| // 모임방 -> 기록장 -> 해당 기록 필터링 화면으로 이동 | ||||||||||||||||||||||||||||||||||||||||||||
| case 'ROOM_POST_DETAIL': { | ||||||||||||||||||||||||||||||||||||||||||||
| const roomId = (params?.roomId as number) ?? undefined; | ||||||||||||||||||||||||||||||||||||||||||||
| const postId = (params?.postId as number) ?? undefined; | ||||||||||||||||||||||||||||||||||||||||||||
| const page = (params?.page as number) ?? undefined; | ||||||||||||||||||||||||||||||||||||||||||||
| const postType = params?.postType as 'RECORD' | 'VOTE'; | ||||||||||||||||||||||||||||||||||||||||||||
| const shouldOpenComments = (params as { openComments?: boolean })?.openComments === true; | ||||||||||||||||||||||||||||||||||||||||||||
| if (roomId !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||
| navigate(`/rooms/${roomId}/memory`, { | ||||||||||||||||||||||||||||||||||||||||||||
| state: { | ||||||||||||||||||||||||||||||||||||||||||||
| focusPostId: postId, | ||||||||||||||||||||||||||||||||||||||||||||
| postType, | ||||||||||||||||||||||||||||||||||||||||||||
| page, | ||||||||||||||||||||||||||||||||||||||||||||
| ...(shouldOpenComments ? { openComments: true } : {}), | ||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||
| // noop: 실패 시 네비게이션 없이 무시 | ||||||||||||||||||||||||||||||||||||||||||||
| console.error('알림 확인 처리 실패:', e); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||
| <Wrapper> | ||||||||||||||||||||||||||||||||||||||||||||
| <TitleHeader | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -112,7 +188,7 @@ const Notice = () => { | |||||||||||||||||||||||||||||||||||||||||||
| <NotificationCard | ||||||||||||||||||||||||||||||||||||||||||||
| key={notif.notificationId ?? idx} | ||||||||||||||||||||||||||||||||||||||||||||
| read={notif.isChecked} | ||||||||||||||||||||||||||||||||||||||||||||
| // onClick={() => handleReadNotification(idx)} | ||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => handleNotificationClick(notif)} | ||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||
| {!notif.isChecked && <UnreadDot />} | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
188
to
193
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 클릭 가능한 div의 키보드 접근성 부족 — role/tabIndex/onKeyDown 추가 필요 현재 마우스 클릭만 가능하고 키보드로는 활성화할 수 없습니다. 최소한 role/button 시맨틱과 Enter/Space 처리 추가가 필요합니다. - <NotificationCard
+ <NotificationCard
key={notif.notificationId ?? idx}
read={notif.isChecked}
- onClick={() => handleNotificationClick(notif)}
+ onClick={() => handleNotificationClick(notif)}
+ role="button"
+ tabIndex={0}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ handleNotificationClick(notif);
+ }
+ }}
>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
| <TitleRow> | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -171,6 +247,12 @@ const NotificationList = styled.div` | |||||||||||||||||||||||||||||||||||||||||||
| padding: 0 20px 20px 20px; | ||||||||||||||||||||||||||||||||||||||||||||
| width: 100%; | ||||||||||||||||||||||||||||||||||||||||||||
| overflow-y: auto; | ||||||||||||||||||||||||||||||||||||||||||||
| /* Hide scrollbar but keep scroll */ | ||||||||||||||||||||||||||||||||||||||||||||
| -ms-overflow-style: none; /* IE and Edge */ | ||||||||||||||||||||||||||||||||||||||||||||
| scrollbar-width: none; /* Firefox */ | ||||||||||||||||||||||||||||||||||||||||||||
| &::-webkit-scrollbar { | ||||||||||||||||||||||||||||||||||||||||||||
| display: none; /* Chrome, Safari, Opera */ | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
| `; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const NotificationCard = styled.div<{ read: boolean }>` | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
오호 이렇게 navigate 하는 군요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
예 맞습니다 별거없습니다 ㅋㅋ