From 2572d0b90fccfe2079b0029fd85613bb9d9a1d42 Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Mon, 23 Sep 2024 22:39:01 +0900 Subject: [PATCH 01/13] =?UTF-8?q?[SKP-189]=20chore=20:=20=EC=B2=AB=20?= =?UTF-8?q?=EC=8B=A4=ED=96=89=20=EC=8B=9C=20No=20APNS=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/skeepcli/AppDelegate.mm | 3 ++- ios/skeepcli/Info.plist | 2 +- src/utils/pushUtils.ts | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ios/skeepcli/AppDelegate.mm b/ios/skeepcli/AppDelegate.mm index 6be0806..cab2184 100644 --- a/ios/skeepcli/AppDelegate.mm +++ b/ios/skeepcli/AppDelegate.mm @@ -15,7 +15,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( self.initialProps = @{}; [FIRApp configure]; - + [application registerForRemoteNotifications]; + bool didFinish = [super application:application didFinishLaunchingWithOptions:launchOptions]; [RNSplashScreen show]; diff --git a/ios/skeepcli/Info.plist b/ios/skeepcli/Info.plist index 060d81a..64db469 100644 --- a/ios/skeepcli/Info.plist +++ b/ios/skeepcli/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion $(CURRENT_PROJECT_VERSION) FirebaseAppDelegateProxyEnabled - + LSApplicationCategoryType KAKAO_APP_KEY diff --git a/src/utils/pushUtils.ts b/src/utils/pushUtils.ts index afb6ba5..7d91e97 100644 --- a/src/utils/pushUtils.ts +++ b/src/utils/pushUtils.ts @@ -40,6 +40,9 @@ async function requestUserPermission() { } async function getToken() { + const apnsToken = await messaging.getAPNSToken(); + console.log('Device APNS Token:', apnsToken); + const fcmToken = await messaging.getToken(); console.log('Device FCM Token:', fcmToken); From f32dd69840887686e00d23064787e0e53cfb497f Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Mon, 23 Sep 2024 22:39:17 +0900 Subject: [PATCH 02/13] =?UTF-8?q?[SKP-189]=20chore=20:=20husky=20=EA=B6=8C?= =?UTF-8?q?=ED=95=9C=20=EB=B6=80=EC=97=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .husky/prepare-commit-msg | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 .husky/prepare-commit-msg diff --git a/.husky/prepare-commit-msg b/.husky/prepare-commit-msg old mode 100755 new mode 100644 From 69f188c50506ef5dcbbb4a7baf7619c87a5af178 Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Mon, 23 Sep 2024 23:25:12 +0900 Subject: [PATCH 03/13] =?UTF-8?q?[SKP-189]=20feat=20:=20=ED=8F=AC=EA=B7=B8?= =?UTF-8?q?=EB=9D=BC=EC=9A=B4=EB=93=9C=20=ED=91=B8=EC=8B=9C=20=EB=94=A5?= =?UTF-8?q?=EB=A7=81=ED=81=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.tsx | 21 +++++++++++++++++++-- index.js | 13 +++++++++++++ src/navigators/Navigator.tsx | 9 ++++++++- src/utils/pushUtils.ts | 10 ++++------ 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/App.tsx b/App.tsx index 307ace1..b4b906e 100644 --- a/App.tsx +++ b/App.tsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, {useEffect} from 'react'; import {SafeAreaProvider} from 'react-native-safe-area-context'; -import Navigator from './src/navigators/Navigator'; +import Navigator, {DEEPLINK_PREFIX_URL} from './src/navigators/Navigator'; import {GestureHandlerRootView} from 'react-native-gesture-handler'; import {BottomSheetModalProvider} from '@gorhom/bottom-sheet'; import {RecoilRoot} from 'recoil'; @@ -8,10 +8,27 @@ import AppSetupWrapper from './src/container/AppSetupContainer'; import Snackbar from './src/components/common/Global/Snackbar/Snackbar'; import Toast from './src/components/common/Global/Toast/Toast'; import usePushNotification from './src/hooks/usePushNotification'; +import notifee, {EventType} from '@notifee/react-native'; +import {Linking} from 'react-native'; const App = () => { usePushNotification(); + useEffect(() => { + return notifee.onForegroundEvent(({type, detail}) => { + console.log('-->', type, detail); + switch (type) { + case EventType.PRESS: + console.log('User pressed notification', detail.notification); + const url = (detail.notification?.data as object).url; + const deepurl = `${DEEPLINK_PREFIX_URL[0]}detail/65` as string; + console.log(deepurl); + Linking.openURL(deepurl); + break; + } + }); + }); + return ( diff --git a/index.js b/index.js index a850d03..ab42843 100644 --- a/index.js +++ b/index.js @@ -5,5 +5,18 @@ import {AppRegistry} from 'react-native'; import App from './App'; import {name as appName} from './app.json'; +import notifee, {EventType} from '@notifee/react-native'; + +notifee.onBackgroundEvent(async ({type, detail}) => { + const {notification, pressAction} = detail; + + // Check if the user pressed the "Mark as read" action + if (type === EventType.ACTION_PRESS && pressAction.id === 'mark-as-read') { + console.log('notifee', type, detail); + + // Remove the notification + await notifee.cancelNotification(notification.id); + } +}); AppRegistry.registerComponent(appName, () => App); diff --git a/src/navigators/Navigator.tsx b/src/navigators/Navigator.tsx index b21d2b5..5bed5e4 100644 --- a/src/navigators/Navigator.tsx +++ b/src/navigators/Navigator.tsx @@ -14,10 +14,11 @@ import { import {StackParamList} from './types'; import {lightPalette} from '../styles'; +export const DEEPLINK_PREFIX_URL = ['kakao378c5d01c3e4b03529594678b0a76911://']; const Navigator = () => { const {authData, setAuthData} = useInitialData(); const linking: LinkingOptions = { - prefixes: ['kakao378c5d01c3e4b03529594678b0a76911://'], + prefixes: DEEPLINK_PREFIX_URL, config: { screens: { TabNavigator: { @@ -27,6 +28,12 @@ const Navigator = () => { }, }, }, + Detail: { + path: 'detail/:id', + parse: { + id: id => `${id}`, + }, + }, }, }, }; diff --git a/src/utils/pushUtils.ts b/src/utils/pushUtils.ts index 7d91e97..0f3b521 100644 --- a/src/utils/pushUtils.ts +++ b/src/utils/pushUtils.ts @@ -61,15 +61,13 @@ export async function displayNotification( name: 'SKEEP', }); - const {notification} = message; + const {notification, data} = message; await notifee.displayNotification({ title: notification?.title, body: notification?.body, - android: { - channelId, - pressAction: { - id: 'default', - }, + data: data, + ios: { + sound: 'default', }, }); } From 9e2c4f3f44eb21818d118d96eb4661ac78720319 Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Mon, 23 Sep 2024 23:47:54 +0900 Subject: [PATCH 04/13] =?UTF-8?q?[SKP-189]=20feat=20:=20=ED=8F=AC=EA=B7=B8?= =?UTF-8?q?=EB=9D=BC=EC=9A=B4=EB=93=9C=20=EB=9E=9C=EB=94=A9=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.tsx | 19 +++++++++---------- index.js | 6 +++--- src/utils/pushUtils.ts | 41 +++++++++++++++++++++++++++++++++-------- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/App.tsx b/App.tsx index b4b906e..2a73b0b 100644 --- a/App.tsx +++ b/App.tsx @@ -1,6 +1,6 @@ import React, {useEffect} from 'react'; import {SafeAreaProvider} from 'react-native-safe-area-context'; -import Navigator, {DEEPLINK_PREFIX_URL} from './src/navigators/Navigator'; +import Navigator from './src/navigators/Navigator'; import {GestureHandlerRootView} from 'react-native-gesture-handler'; import {BottomSheetModalProvider} from '@gorhom/bottom-sheet'; import {RecoilRoot} from 'recoil'; @@ -9,7 +9,7 @@ import Snackbar from './src/components/common/Global/Snackbar/Snackbar'; import Toast from './src/components/common/Global/Toast/Toast'; import usePushNotification from './src/hooks/usePushNotification'; import notifee, {EventType} from '@notifee/react-native'; -import {Linking} from 'react-native'; +import {linkUrl} from './src/utils/pushUtils'; const App = () => { usePushNotification(); @@ -17,14 +17,13 @@ const App = () => { useEffect(() => { return notifee.onForegroundEvent(({type, detail}) => { console.log('-->', type, detail); - switch (type) { - case EventType.PRESS: - console.log('User pressed notification', detail.notification); - const url = (detail.notification?.data as object).url; - const deepurl = `${DEEPLINK_PREFIX_URL[0]}detail/65` as string; - console.log(deepurl); - Linking.openURL(deepurl); - break; + + if (type === EventType.PRESS) { + const url = detail.notification?.data?.url as string; + if (url) { + console.log('url', url); + linkUrl(url); + } } }); }); diff --git a/index.js b/index.js index ab42843..9842464 100644 --- a/index.js +++ b/index.js @@ -10,11 +10,11 @@ import notifee, {EventType} from '@notifee/react-native'; notifee.onBackgroundEvent(async ({type, detail}) => { const {notification, pressAction} = detail; - // Check if the user pressed the "Mark as read" action - if (type === EventType.ACTION_PRESS && pressAction.id === 'mark-as-read') { + console.log('onBackgroundEvent', type, detail); + + if (type === EventType.ACTION_PRESS) { console.log('notifee', type, detail); - // Remove the notification await notifee.cancelNotification(notification.id); } }); diff --git a/src/utils/pushUtils.ts b/src/utils/pushUtils.ts index 0f3b521..74d4bb9 100644 --- a/src/utils/pushUtils.ts +++ b/src/utils/pushUtils.ts @@ -5,6 +5,8 @@ import { FirebaseMessagingTypes, } from '@react-native-firebase/messaging'; import notifee from '@notifee/react-native'; +import {DEEPLINK_PREFIX_URL} from '../navigators/Navigator'; +import {Linking} from 'react-native'; export const messaging = firebase.messaging(); @@ -62,12 +64,35 @@ export async function displayNotification( }); const {notification, data} = message; - await notifee.displayNotification({ - title: notification?.title, - body: notification?.body, - data: data, - ios: { - sound: 'default', - }, - }); + console.log('>>data', data?.data); + try { + const parsedData = JSON.parse(data?.data as string); + + await notifee.displayNotification({ + title: notification?.title, + body: notification?.body, + data: parsedData, + ios: { + sound: 'default', + }, + }); + } catch (error) { + console.error('Failed to parse notification data:', error); + } +} + +/** + * linkUrl + * 딥링크 랜딩 로직 수행 + */ +export async function linkUrl(url: string) { + const cleanUrl = url.startsWith('/') ? url.slice(1) : url; + const deepurl = `${DEEPLINK_PREFIX_URL[0]}${cleanUrl}`; + console.log('🚀 DEEPLINK - ', deepurl); + + try { + await Linking.openURL(deepurl); + } catch (error) { + console.error('Failed to open deep link:', error); + } } From 24f10fe039fe219644edfd06a64fbef6ec90ca9d Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Mon, 23 Sep 2024 23:52:15 +0900 Subject: [PATCH 05/13] =?UTF-8?q?[SKP-189]=20refac=20:=20linking=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/navigators/Linking.ts | 33 +++++++++++++++++++++++++++++++++ src/navigators/Navigator.tsx | 29 ++--------------------------- src/utils/pushUtils.ts | 2 +- 3 files changed, 36 insertions(+), 28 deletions(-) create mode 100644 src/navigators/Linking.ts diff --git a/src/navigators/Linking.ts b/src/navigators/Linking.ts new file mode 100644 index 0000000..1d98612 --- /dev/null +++ b/src/navigators/Linking.ts @@ -0,0 +1,33 @@ +import {LinkingOptions} from '@react-navigation/native'; +import {StackParamList} from './types'; + +export const DEEPLINK_PREFIX_URL = ['kakao378c5d01c3e4b03529594678b0a76911://']; + +const linking: LinkingOptions = { + prefixes: DEEPLINK_PREFIX_URL, + config: { + screens: { + TabNavigator: { + screens: { + SettingTab: { + path: 'kakaolink', + }, + }, + }, + Detail: { + path: 'detail/:id', + parse: { + id: id => `${id}`, + }, + }, + CategoryList: { + path: 'category/:id', + parse: { + id: id => `${id}`, + }, + }, + }, + }, +}; + +export default linking; diff --git a/src/navigators/Navigator.tsx b/src/navigators/Navigator.tsx index 5bed5e4..480b1ed 100644 --- a/src/navigators/Navigator.tsx +++ b/src/navigators/Navigator.tsx @@ -6,37 +6,12 @@ import {TokenKeys} from '../libs/async-storage/constants/keys'; import useInitialData from '../hooks/auth/useInitialData'; import SplashScreen from 'react-native-splash-screen'; import {Interceptor} from '../apis/client'; -import { - DefaultTheme, - LinkingOptions, - NavigationContainer, -} from '@react-navigation/native'; -import {StackParamList} from './types'; +import {DefaultTheme, NavigationContainer} from '@react-navigation/native'; import {lightPalette} from '../styles'; +import linking from './Linking'; -export const DEEPLINK_PREFIX_URL = ['kakao378c5d01c3e4b03529594678b0a76911://']; const Navigator = () => { const {authData, setAuthData} = useInitialData(); - const linking: LinkingOptions = { - prefixes: DEEPLINK_PREFIX_URL, - config: { - screens: { - TabNavigator: { - screens: { - SettingTab: { - path: 'kakaolink', - }, - }, - }, - Detail: { - path: 'detail/:id', - parse: { - id: id => `${id}`, - }, - }, - }, - }, - }; const theme = { ...DefaultTheme, diff --git a/src/utils/pushUtils.ts b/src/utils/pushUtils.ts index 74d4bb9..7ed7aa0 100644 --- a/src/utils/pushUtils.ts +++ b/src/utils/pushUtils.ts @@ -5,8 +5,8 @@ import { FirebaseMessagingTypes, } from '@react-native-firebase/messaging'; import notifee from '@notifee/react-native'; -import {DEEPLINK_PREFIX_URL} from '../navigators/Navigator'; import {Linking} from 'react-native'; +import {DEEPLINK_PREFIX_URL} from '../navigators/Linking'; export const messaging = firebase.messaging(); From d9d5f4b42e4bf168bec67512a2ea2fd3ddcad8a3 Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Tue, 24 Sep 2024 00:11:24 +0900 Subject: [PATCH 06/13] =?UTF-8?q?[SKP-189]=20refac=20:=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20API?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20=EB=B0=98=EC=98=81=20(name,=20desc=20?= =?UTF-8?q?=ED=8C=8C=EB=9E=8C=20=EC=A0=9C=EA=B1=B0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../queries/category/useGetCategoryDetail.ts | 3 +++ src/navigators/StackNavigator.tsx | 1 - src/navigators/types/index.ts | 2 +- src/screens/CategoryAdd/CategoryAdd.tsx | 2 -- src/screens/CategoryList/CategoryList.tsx | 20 ++++++++++++------- src/screens/DetailTour/DetailTour.tsx | 2 -- .../TabNavigator/CategoryTab/CategoryTab.tsx | 2 -- src/types/dtos/category.ts | 11 ++++------ 8 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/hooks/queries/category/useGetCategoryDetail.ts b/src/hooks/queries/category/useGetCategoryDetail.ts index 576c795..3f9664b 100644 --- a/src/hooks/queries/category/useGetCategoryDetail.ts +++ b/src/hooks/queries/category/useGetCategoryDetail.ts @@ -23,6 +23,7 @@ const getCategoryList = async ({ console.log(userCategoryId); return { items: result.userLocationList, + category: result.userCategory, nextPage: result.totalPage > page ? page + 1 : undefined, totalPage: result.totalPage, totalElement: result.totalElement, @@ -37,6 +38,7 @@ const useGetCategoryList = (requestParams: GetPostHistoryRequest) => { getNextPageParam: lastPage => lastPage.nextPage, select: data => ({ pages: data.pages.flatMap(page => page.items), + category: data.pages?.[0]?.category, totalElement: data.pages?.[0]?.totalElement ?? 0, }), initialPageParam: requestParams.page, @@ -54,6 +56,7 @@ const useGetCategoryList = (requestParams: GetPostHistoryRequest) => { isFetching, hasNextPage, totalElement: data?.totalElement, + category: data?.category, }; }; diff --git a/src/navigators/StackNavigator.tsx b/src/navigators/StackNavigator.tsx index ec3a773..fdf021e 100644 --- a/src/navigators/StackNavigator.tsx +++ b/src/navigators/StackNavigator.tsx @@ -13,7 +13,6 @@ import Withdraw from '../screens/Withdraw/Withdraw'; import CategoryList from '../screens/CategoryList/CategoryList'; import DetailTour from '../screens/DetailTour/DetailTour'; import CategoryAdd from '../screens/CategoryAdd/CategoryAdd'; -import {TouchableOpacity} from 'react-native'; import {IcLeft} from '../assets/icon'; import Icon from '../components/common/Icon/Icon'; import Notification from '../screens/Notification/Notification'; diff --git a/src/navigators/types/index.ts b/src/navigators/types/index.ts index dbbdb8c..0878e0c 100644 --- a/src/navigators/types/index.ts +++ b/src/navigators/types/index.ts @@ -28,7 +28,7 @@ export type StackParamList = { Detail: {id: number}; DetailTour: {location: TourLocationDTO}; - CategoryList: {title: string; description: string; id: number}; + CategoryList: {id: number}; CategoryAdd: undefined; Notification: undefined; diff --git a/src/screens/CategoryAdd/CategoryAdd.tsx b/src/screens/CategoryAdd/CategoryAdd.tsx index a68e41d..00a747f 100644 --- a/src/screens/CategoryAdd/CategoryAdd.tsx +++ b/src/screens/CategoryAdd/CategoryAdd.tsx @@ -95,8 +95,6 @@ export default function CategoryAdd({navigation}: CategoryAddProps) { if (userCategoryId) { navigation.replace('CategoryList', { - title: nameValue, - description: memoValue, id: userCategoryId, }); } else { diff --git a/src/screens/CategoryList/CategoryList.tsx b/src/screens/CategoryList/CategoryList.tsx index e093ed0..514842c 100644 --- a/src/screens/CategoryList/CategoryList.tsx +++ b/src/screens/CategoryList/CategoryList.tsx @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, {useMemo, useState} from 'react'; import { View, Text, @@ -29,19 +29,25 @@ import Icon from '../../components/common/Icon/Icon'; type CategoryListProps = StackScreenProps<'CategoryList'>; export default function CategoryList({navigation, route}: CategoryListProps) { - const {title, description, id} = route.params; + const {id} = route.params; const [modalVisible, setModalVisible] = useState(false); const queryClient = useQueryClient(); - const backgroundColor = COLOR_DETAIL_MAP[title] || theme.palette.gray1; - const IconComponent = ICON_DETAIL_MAPS[title] || IcRoundEtc; const {mutate: deleteCategory} = useDeleteCategory(); - const {data, loadMore, isFetching, hasNextPage, totalElement} = + const {data, loadMore, isFetching, hasNextPage, totalElement, category} = useGetCategoryList({ userCategoryId: id, page: 1, }); + const backgroundColor = useMemo(() => { + return COLOR_DETAIL_MAP[category?.name as string] || theme.palette.gray1; + }, [category]); + + const IconComponent = useMemo(() => { + return ICON_DETAIL_MAPS[category?.name as string] || IcRoundEtc; + }, [category]); + const renderItem = ({item}: {item: UserLocation}) => ( navigation.navigate('Detail', {id: item.id})}> @@ -94,8 +100,8 @@ export default function CategoryList({navigation, route}: CategoryListProps) { - {title} - {description} + {category?.name} + {category?.description} 총 {totalElement}개 diff --git a/src/screens/DetailTour/DetailTour.tsx b/src/screens/DetailTour/DetailTour.tsx index 0bc68c1..895a437 100644 --- a/src/screens/DetailTour/DetailTour.tsx +++ b/src/screens/DetailTour/DetailTour.tsx @@ -51,8 +51,6 @@ export default function DetailTour({navigation, route}: DetailTourProps) { }); navigation.replace('CategoryList', { - title: category.name, - description: category.description, id: category.id, }); }, diff --git a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx index 067ec17..55b3512 100644 --- a/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx +++ b/src/screens/TabNavigator/CategoryTab/CategoryTab.tsx @@ -60,8 +60,6 @@ export default function CategoryTab({navigation}: CategoryTabProps) { const handleCardPress = (item: CardData) => { navigation.navigate('CategoryList', { - title: item.title, - description: item.description, id: item.id, }); }; diff --git a/src/types/dtos/category.ts b/src/types/dtos/category.ts index 4c4ceab..8672e85 100644 --- a/src/types/dtos/category.ts +++ b/src/types/dtos/category.ts @@ -1,3 +1,5 @@ +import {ICategory} from './location'; + export type CardEntity = { id: number; name: string; @@ -15,23 +17,18 @@ export interface Location { y: string; } -export interface UserCategory { - id: number; - title: string; - description: string; -} - export interface UserLocation { id: number; photoUrl: string; location: Location; - userCategory: UserCategory; + userCategory: ICategory; } export interface IPage { totalElement: number; totalPage: number; userLocationList: any; + userCategory: ICategory; result: { userLocationList: T[]; }; From 76c5f27054a0179c7035aee4e21eacd60076bffd Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Tue, 24 Sep 2024 00:28:51 +0900 Subject: [PATCH 07/13] =?UTF-8?q?[SKP-189]=20test=20:=20background=20?= =?UTF-8?q?=ED=91=B8=EC=8B=9C=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.tsx | 2 +- index.js | 13 ------------- src/hooks/usePushNotification.tsx | 20 ++++++++++++++++---- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/App.tsx b/App.tsx index 2a73b0b..ef9cebb 100644 --- a/App.tsx +++ b/App.tsx @@ -16,7 +16,7 @@ const App = () => { useEffect(() => { return notifee.onForegroundEvent(({type, detail}) => { - console.log('-->', type, detail); + console.log('onForegroundEvent', type, detail); if (type === EventType.PRESS) { const url = detail.notification?.data?.url as string; diff --git a/index.js b/index.js index 9842464..a850d03 100644 --- a/index.js +++ b/index.js @@ -5,18 +5,5 @@ import {AppRegistry} from 'react-native'; import App from './App'; import {name as appName} from './app.json'; -import notifee, {EventType} from '@notifee/react-native'; - -notifee.onBackgroundEvent(async ({type, detail}) => { - const {notification, pressAction} = detail; - - console.log('onBackgroundEvent', type, detail); - - if (type === EventType.ACTION_PRESS) { - console.log('notifee', type, detail); - - await notifee.cancelNotification(notification.id); - } -}); AppRegistry.registerComponent(appName, () => App); diff --git a/src/hooks/usePushNotification.tsx b/src/hooks/usePushNotification.tsx index 2d635ed..9da03b2 100644 --- a/src/hooks/usePushNotification.tsx +++ b/src/hooks/usePushNotification.tsx @@ -8,10 +8,22 @@ export default function usePushNotification() { displayNotification(remoteMessage); }); + messaging.onNotificationOpenedApp(remoteMessage => { + console.log( + 'Notification caused app to open from background state:', + remoteMessage.notification, + ); + }); + + messaging.getInitialNotification().then(remoteMessage => { + if (remoteMessage) { + console.log( + 'Notification caused app to open from quit state:', + remoteMessage.notification, + ); + } + }); + return unsubscribe; }, []); - - messaging.setBackgroundMessageHandler(async remoteMessage => { - console.log('Message handled in the background!', remoteMessage); - }); } From 297f8ea3468b2b38e66f326571db8cb54e303b37 Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Tue, 24 Sep 2024 00:43:29 +0900 Subject: [PATCH 08/13] =?UTF-8?q?[SKP-189]=20feat=20:=20=EB=B0=B1=EA=B7=B8?= =?UTF-8?q?=EB=9D=BC=EC=9A=B4=EB=93=9C=20=ED=91=B8=EC=8B=9C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App.tsx | 10 +++--- src/hooks/usePushNotification.tsx | 33 ++++++++++++++----- src/utils/pushUtils.ts | 55 +++++++++++++++++++++++++++---- 3 files changed, 77 insertions(+), 21 deletions(-) diff --git a/App.tsx b/App.tsx index ef9cebb..ba9b041 100644 --- a/App.tsx +++ b/App.tsx @@ -9,7 +9,7 @@ import Snackbar from './src/components/common/Global/Snackbar/Snackbar'; import Toast from './src/components/common/Global/Toast/Toast'; import usePushNotification from './src/hooks/usePushNotification'; import notifee, {EventType} from '@notifee/react-native'; -import {linkUrl} from './src/utils/pushUtils'; +import {getDeepLinkUrl, linkToDeepLinkURL} from './src/utils/pushUtils'; const App = () => { usePushNotification(); @@ -19,10 +19,10 @@ const App = () => { console.log('onForegroundEvent', type, detail); if (type === EventType.PRESS) { - const url = detail.notification?.data?.url as string; - if (url) { - console.log('url', url); - linkUrl(url); + const deepLinkURL = getDeepLinkUrl(detail.notification); + if (deepLinkURL) { + console.log('url', deepLinkURL); + linkToDeepLinkURL(deepLinkURL); } } }); diff --git a/src/hooks/usePushNotification.tsx b/src/hooks/usePushNotification.tsx index 9da03b2..35366e8 100644 --- a/src/hooks/usePushNotification.tsx +++ b/src/hooks/usePushNotification.tsx @@ -1,5 +1,12 @@ import {useEffect} from 'react'; -import {displayNotification, messaging} from '../utils/pushUtils'; +import { + displayNotification, + getDeepLinkUrl, + getDeepLinkUrlFromUrl, + linkToDeepLinkURL, + messaging, + parseNotificationData, +} from '../utils/pushUtils'; export default function usePushNotification() { useEffect(() => { @@ -9,18 +16,26 @@ export default function usePushNotification() { }); messaging.onNotificationOpenedApp(remoteMessage => { - console.log( - 'Notification caused app to open from background state:', - remoteMessage.notification, - ); + console.log('background state:', remoteMessage); + + const parsedData = parseNotificationData(remoteMessage?.data?.data); + const deepLinkURL = getDeepLinkUrlFromUrl(parsedData.url); + if (deepLinkURL) { + console.log('url', deepLinkURL); + linkToDeepLinkURL(deepLinkURL); + } }); messaging.getInitialNotification().then(remoteMessage => { if (remoteMessage) { - console.log( - 'Notification caused app to open from quit state:', - remoteMessage.notification, - ); + console.log('quit state:', remoteMessage); + + const parsedData = parseNotificationData(remoteMessage?.data?.data); + const deepLinkURL = getDeepLinkUrlFromUrl(parsedData.url); + if (deepLinkURL) { + console.log('url', deepLinkURL); + linkToDeepLinkURL(deepLinkURL); + } } }); diff --git a/src/utils/pushUtils.ts b/src/utils/pushUtils.ts index 7ed7aa0..9d79bc5 100644 --- a/src/utils/pushUtils.ts +++ b/src/utils/pushUtils.ts @@ -4,7 +4,7 @@ import { firebase, FirebaseMessagingTypes, } from '@react-native-firebase/messaging'; -import notifee from '@notifee/react-native'; +import notifee, {Notification} from '@notifee/react-native'; import {Linking} from 'react-native'; import {DEEPLINK_PREFIX_URL} from '../navigators/Linking'; @@ -66,7 +66,7 @@ export async function displayNotification( const {notification, data} = message; console.log('>>data', data?.data); try { - const parsedData = JSON.parse(data?.data as string); + const parsedData = parseNotificationData(data?.data); await notifee.displayNotification({ title: notification?.title, @@ -85,14 +85,55 @@ export async function displayNotification( * linkUrl * 딥링크 랜딩 로직 수행 */ -export async function linkUrl(url: string) { - const cleanUrl = url.startsWith('/') ? url.slice(1) : url; - const deepurl = `${DEEPLINK_PREFIX_URL[0]}${cleanUrl}`; - console.log('🚀 DEEPLINK - ', deepurl); +export async function linkToDeepLinkURL(deepLinkURL: string) { + console.log('🚀 DEEPLINK - ', deepLinkURL); try { - await Linking.openURL(deepurl); + await Linking.openURL(deepLinkURL); } catch (error) { console.error('Failed to open deep link:', error); } } + +/** + * getDeepLinkUrl + * notification에서 deeplink url 추출 + */ +export function getDeepLinkUrl(notification?: Notification) { + try { + const url = notification?.data?.url as string; + if (!url) throw new Error('url이 존재하지 않습니다.'); + + return getDeepLinkUrlFromUrl(url); + } catch (e) { + console.error(e); + } +} + +/** + * getDeepLinkUrlFromUrl + * deeplinkurl 생성 + */ +export function getDeepLinkUrlFromUrl(url?: string) { + try { + if (!url) throw new Error('url이 존재하지 않습니다.'); + + const cleanUrl = url.startsWith('/') ? url.slice(1) : url; + const deepurl = `${DEEPLINK_PREFIX_URL[0]}${cleanUrl}`; + + return deepurl; + } catch (e) { + console.error(e); + } +} + +/** + * parseNotificationData + */ +export function parseNotificationData(data: string | object | undefined) { + try { + return JSON.parse(data as string); + } catch (e) { + console.error(e); + } +} From 1d837a7816fc134428a689446bbcfa7bbebbe99d Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Tue, 24 Sep 2024 00:51:36 +0900 Subject: [PATCH 09/13] =?UTF-8?q?[SKP-189]=20test=20:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=ED=91=B8=EC=8B=9C=20=EC=BD=94=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20(=ED=9B=84=20=EB=A1=A4=EB=B0=B1=20=ED=95=84?= =?UTF-8?q?=EC=9A=94)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Settings/Profile.tsx | 28 ++++++++----- .../mutations/test/useTestNotification.ts | 39 +++++++++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 src/hooks/mutations/test/useTestNotification.ts diff --git a/src/components/Settings/Profile.tsx b/src/components/Settings/Profile.tsx index aa35d8f..1e4ca42 100644 --- a/src/components/Settings/Profile.tsx +++ b/src/components/Settings/Profile.tsx @@ -2,6 +2,11 @@ import React from 'react'; import {View, Text} from 'react-native'; import {IcApple, IcProfile} from '../../assets/icon'; import styles from './Profile.style'; +import {TouchableOpacity} from 'react-native-gesture-handler'; +import { + sendCategoryPush, + sendDetailPush, +} from '../../hooks/mutations/test/useTestNotification'; type ProfileProps = { userInfo: { @@ -14,16 +19,21 @@ type ProfileProps = { export default function Profile({userInfo}: ProfileProps) { return ( - - - {userInfo.name} - - {userInfo.email} - {userInfo.provider === 'APPLE' && ( - - )} + sendCategoryPush()}> + + + + sendDetailPush()}> + + {userInfo.name} + + {userInfo.email} + {userInfo.provider === 'APPLE' && ( + + )} + - + ); } diff --git a/src/hooks/mutations/test/useTestNotification.ts b/src/hooks/mutations/test/useTestNotification.ts new file mode 100644 index 0000000..7f488c0 --- /dev/null +++ b/src/hooks/mutations/test/useTestNotification.ts @@ -0,0 +1,39 @@ +import {useMutation} from '@tanstack/react-query'; +import {BaseResponse, POST} from '../../../apis/client'; +import {checkPermission} from '../../../utils/pushUtils'; + +interface SendFCMPushRequest { + token: string; + isCategory: boolean; +} + +/** + * 테스트 푸시 전송용 + */ +export const sendFCMPush = async (req: SendFCMPushRequest) => { + const res = await POST(`/api/fcm/test`, req); + return res.data; +}; + +interface PatchFCMTokenProps { + onSuccess: (res: BaseResponse) => void; + onError: (e: Error) => void; +} + +export const usePatchFCMToken = ({onSuccess, onError}: PatchFCMTokenProps) => { + return useMutation({ + mutationFn: (req: SendFCMPushRequest) => sendFCMPush(req), + onSuccess: onSuccess, + onError: onError, + }); +}; + +export const sendCategoryPush = async () => { + const token = await checkPermission(); + await sendFCMPush({token: token, isCategory: true}); +}; + +export const sendDetailPush = async () => { + const token = await checkPermission(); + await sendFCMPush({token: token, isCategory: false}); +}; From 0927099adf7414adc6ff7673a7d119c973cef9a5 Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Tue, 24 Sep 2024 01:13:19 +0900 Subject: [PATCH 10/13] =?UTF-8?q?[SKP-189]=20feat=20:=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20API=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icon/ic_noti_empty.svg | 6 ++ src/assets/icon/index.ts | 1 + .../Notification/NotificationItem.tsx | 11 +--- .../notification/usePatchNotification.ts | 32 ++++++++++ src/hooks/queries/QueryKeys.ts | 18 +++++- .../notification/useGetNotification.ts | 59 +++++++++++++++++++ .../Notification/Notification.styles.ts | 9 +++ src/screens/Notification/Notification.tsx | 27 +++++++-- 8 files changed, 148 insertions(+), 15 deletions(-) create mode 100644 src/assets/icon/ic_noti_empty.svg create mode 100644 src/hooks/mutations/notification/usePatchNotification.ts create mode 100644 src/hooks/queries/notification/useGetNotification.ts diff --git a/src/assets/icon/ic_noti_empty.svg b/src/assets/icon/ic_noti_empty.svg new file mode 100644 index 0000000..5ec4220 --- /dev/null +++ b/src/assets/icon/ic_noti_empty.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/assets/icon/index.ts b/src/assets/icon/index.ts index 7ce8d59..a604d2f 100644 --- a/src/assets/icon/index.ts +++ b/src/assets/icon/index.ts @@ -69,3 +69,4 @@ export {default as IcRoundRest} from './ic_round_rest.svg'; export {default as IcRoundEtc} from './ic_round_etc.svg'; export {default as IcBell} from './ic_bell.svg'; +export {default as IcNotiEmpty} from './ic_noti_empty.svg'; diff --git a/src/components/Notification/NotificationItem.tsx b/src/components/Notification/NotificationItem.tsx index e44ee7e..db2fcfd 100644 --- a/src/components/Notification/NotificationItem.tsx +++ b/src/components/Notification/NotificationItem.tsx @@ -2,13 +2,8 @@ import React from 'react'; import {Pressable, StyleSheet, Text, View} from 'react-native'; import {theme} from '../../styles'; import {flexBox} from '../../styles/common'; +import {NotificationDTO} from '../../hooks/queries/notification/useGetNotification'; -export interface NotificationDTO { - title: string; - date: string; - type: string; - isRead: boolean; -} interface NotificationItemProps { item: NotificationDTO; } @@ -26,11 +21,11 @@ export default function NotificationItem({item}: NotificationItemProps) { onPress={handleOnPress}> {item.type} - {!item.isRead && } + {!item.isChecked && } {item.title} - {item.date} + {item.createdAt} ); } diff --git a/src/hooks/mutations/notification/usePatchNotification.ts b/src/hooks/mutations/notification/usePatchNotification.ts new file mode 100644 index 0000000..a9df3a7 --- /dev/null +++ b/src/hooks/mutations/notification/usePatchNotification.ts @@ -0,0 +1,32 @@ +import {useMutation} from '@tanstack/react-query'; +import {BaseResponse, POST} from '../../../apis/client'; +import {checkPermission} from '../../../utils/pushUtils'; + +interface CheckNotificationRequest { + id: number; + type: string; +} + +/** + * 푸시 확인 API + */ +export const checkNotification = async (req: CheckNotificationRequest) => { + const res = await POST(`/api/notification/check`, req); + return res.data; +}; + +interface PatchFCMTokenProps { + onSuccess: (res: BaseResponse) => void; + onError: (e: Error) => void; +} + +export const usePatchNotification = ({ + onSuccess, + onError, +}: PatchFCMTokenProps) => { + return useMutation({ + mutationFn: (req: CheckNotificationRequest) => checkNotification(req), + onSuccess: onSuccess, + onError: onError, + }); +}; diff --git a/src/hooks/queries/QueryKeys.ts b/src/hooks/queries/QueryKeys.ts index c891ffb..65f8123 100644 --- a/src/hooks/queries/QueryKeys.ts +++ b/src/hooks/queries/QueryKeys.ts @@ -33,4 +33,20 @@ const TOUR_KEYS = { [...TOUR_KEYS.details(), {x: location.x, y: location.y}] as const, // ["tours", "detail", {x: "x", y: "y"}] }; -export {LOCATION_KEYS, CATEGORY_KEYS, WEATHER_KEYS, TOUR_KEYS}; +const NOTIFICATION_KEYS = { + all: ['notifications'] as const, + + lists: () => [...NOTIFICATION_KEYS.all, 'list'] as const, // ["notifications", "list"] + list: (filters: object) => [...NOTIFICATION_KEYS.lists(), {filters}] as const, // ["notifications", "list", "..."] + + details: () => [...NOTIFICATION_KEYS.all, 'detail'] as const, // ["notifications", "detail"] + detail: (id: string) => [...NOTIFICATION_KEYS.details(), id] as const, // ["notifications", "detail", "id"] +}; + +export { + LOCATION_KEYS, + CATEGORY_KEYS, + WEATHER_KEYS, + TOUR_KEYS, + NOTIFICATION_KEYS, +}; diff --git a/src/hooks/queries/notification/useGetNotification.ts b/src/hooks/queries/notification/useGetNotification.ts new file mode 100644 index 0000000..6a14140 --- /dev/null +++ b/src/hooks/queries/notification/useGetNotification.ts @@ -0,0 +1,59 @@ +import {useInfiniteQuery} from '@tanstack/react-query'; +import {GET} from '../../../apis/client'; +import {useCallback} from 'react'; +import {CATEGORY_KEYS} from '../QueryKeys'; + +const getNotificationList = async (page: number) => { + const { + data: {result}, + } = await GET(`/api/notification?page=${page}`); + + console.log('>', result); + return { + notificationList: result.notificationList, + nextPage: result.totalPage > page ? page + 1 : undefined, + totalPage: result.totalPage, + }; +}; + +export interface NotificationDTO { + id: string; + title: string; + body: string; + type: string; + isChecked: boolean; + createdAt: string; +} + +interface GetNotificationResponse { + totalPage: number; + notificationList: NotificationDTO[]; +} + +const useGetNotification = (page: number) => { + const {data, hasNextPage, fetchNextPage, isFetching} = useInfiniteQuery({ + queryKey: CATEGORY_KEYS.list({page: page}), + queryFn: ({pageParam = 1}: {pageParam?: number}) => + getNotificationList(pageParam), + getNextPageParam: lastPage => lastPage.nextPage, + select: data => ({ + pages: data.pages.flatMap(page => page.notificationList), + }), + initialPageParam: page, + }); + + const loadMore = useCallback(() => { + if (hasNextPage) { + fetchNextPage(); + } + }, [hasNextPage, fetchNextPage]); + + return { + data: data?.pages, + loadMore, + isFetching, + hasNextPage, + }; +}; + +export default useGetNotification; diff --git a/src/screens/Notification/Notification.styles.ts b/src/screens/Notification/Notification.styles.ts index 81f2923..e7fef44 100644 --- a/src/screens/Notification/Notification.styles.ts +++ b/src/screens/Notification/Notification.styles.ts @@ -12,4 +12,13 @@ export const styles = StyleSheet.create({ ...theme.typography.title_sb_21, marginVertical: 25, }, + emptyContainer: { + flex: 1, + ...flexBox('column'), + gap: 20, + paddingBottom: '30%', + }, + emptyText: { + ...theme.typography.body_sb_17, + }, }); diff --git a/src/screens/Notification/Notification.tsx b/src/screens/Notification/Notification.tsx index 9c989fb..3a63c81 100644 --- a/src/screens/Notification/Notification.tsx +++ b/src/screens/Notification/Notification.tsx @@ -1,18 +1,20 @@ import React from 'react'; import {SafeAreaView} from 'react-native-safe-area-context'; -import {wrapper, wrapperFull} from '../../styles/common'; +import {wrapperFull} from '../../styles/common'; import {FlatList, Text, View} from 'react-native'; import {styles} from './Notification.styles'; import Icon from '../../components/common/Icon/Icon'; -import {IcLeft} from '../../assets/icon'; +import {IcLeft, IcNotiEmpty} from '../../assets/icon'; import {StackScreenProps} from '../../navigators/types'; -import dummies from './dummies.json'; -import NotificationItem, { +import NotificationItem from '../../components/Notification/NotificationItem'; +import useGetNotification, { NotificationDTO, -} from '../../components/Notification/NotificationItem'; +} from '../../hooks/queries/notification/useGetNotification'; type NotificationProps = StackScreenProps<'Notification'>; export default function Notification({navigation}: NotificationProps) { + const {data, loadMore, isFetching, hasNextPage} = useGetNotification(1); + return ( @@ -22,11 +24,24 @@ export default function Notification({navigation}: NotificationProps) { 알림 item.id.toString()} renderItem={({item}: {item: NotificationDTO}) => ( )} + onEndReached={hasNextPage ? loadMore : undefined} + onEndReachedThreshold={0.5} + ListEmptyComponent={EmptyNotificationList} /> ); } + +function EmptyNotificationList() { + return ( + + + 아직 알림이 없어요! + + ); +} From 6955e5962b4196366158c160fcb63f7b2f775859 Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Tue, 24 Sep 2024 01:19:39 +0900 Subject: [PATCH 11/13] =?UTF-8?q?[SKP-189]=20style=20:=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Notification/NotificationItem.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/Notification/NotificationItem.tsx b/src/components/Notification/NotificationItem.tsx index db2fcfd..2561006 100644 --- a/src/components/Notification/NotificationItem.tsx +++ b/src/components/Notification/NotificationItem.tsx @@ -15,8 +15,16 @@ export default function NotificationItem({item}: NotificationItemProps) { return ( [ - {backgroundColor: pressed ? '#43C7FF1A' : 'white'}, styles.container, + { + backgroundColor: pressed + ? !item.isChecked + ? '#43C7FF26' + : 'white' + : !item.isChecked + ? '#43C7FF1A' + : 'white', + }, ]} onPress={handleOnPress}> From 3ac9f49b00d4982aaee3d34042396d3c4e0845fc Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Tue, 24 Sep 2024 01:24:33 +0900 Subject: [PATCH 12/13] =?UTF-8?q?[SKP-189]=20feat=20:=20=ED=91=B8=EC=8B=9C?= =?UTF-8?q?=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20->=20=ED=91=B8=EC=8B=9C=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20API=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Notification/NotificationItem.tsx | 18 ++++++++++++++++++ .../notification/usePatchNotification.ts | 5 ++--- .../queries/notification/useGetNotification.ts | 6 +++--- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/components/Notification/NotificationItem.tsx b/src/components/Notification/NotificationItem.tsx index 2561006..e965ba1 100644 --- a/src/components/Notification/NotificationItem.tsx +++ b/src/components/Notification/NotificationItem.tsx @@ -3,13 +3,31 @@ import {Pressable, StyleSheet, Text, View} from 'react-native'; import {theme} from '../../styles'; import {flexBox} from '../../styles/common'; import {NotificationDTO} from '../../hooks/queries/notification/useGetNotification'; +import {usePatchNotification} from '../../hooks/mutations/notification/usePatchNotification'; +import {useQueryClient} from '@tanstack/react-query'; +import {NOTIFICATION_KEYS} from '../../hooks/queries/QueryKeys'; interface NotificationItemProps { item: NotificationDTO; } export default function NotificationItem({item}: NotificationItemProps) { + const queryClient = useQueryClient(); + + const {mutate: checkNotitifcation} = usePatchNotification({ + onSuccess(res) { + console.log(res); + queryClient.invalidateQueries({ + queryKey: NOTIFICATION_KEYS.all, + }); + }, + onError(e) { + console.error(e); + }, + }); function handleOnPress() { /* 알림 타입 별로 랜딩 로직 수행 */ + // 1. 푸시 확인 API + checkNotitifcation({id: item.id, type: item.type}); } return ( diff --git a/src/hooks/mutations/notification/usePatchNotification.ts b/src/hooks/mutations/notification/usePatchNotification.ts index a9df3a7..2dc4bc9 100644 --- a/src/hooks/mutations/notification/usePatchNotification.ts +++ b/src/hooks/mutations/notification/usePatchNotification.ts @@ -1,6 +1,5 @@ import {useMutation} from '@tanstack/react-query'; -import {BaseResponse, POST} from '../../../apis/client'; -import {checkPermission} from '../../../utils/pushUtils'; +import {BaseResponse, PATCH} from '../../../apis/client'; interface CheckNotificationRequest { id: number; @@ -11,7 +10,7 @@ interface CheckNotificationRequest { * 푸시 확인 API */ export const checkNotification = async (req: CheckNotificationRequest) => { - const res = await POST(`/api/notification/check`, req); + const res = await PATCH(`/api/notification/check`, req); return res.data; }; diff --git a/src/hooks/queries/notification/useGetNotification.ts b/src/hooks/queries/notification/useGetNotification.ts index 6a14140..e151d25 100644 --- a/src/hooks/queries/notification/useGetNotification.ts +++ b/src/hooks/queries/notification/useGetNotification.ts @@ -1,7 +1,7 @@ import {useInfiniteQuery} from '@tanstack/react-query'; import {GET} from '../../../apis/client'; import {useCallback} from 'react'; -import {CATEGORY_KEYS} from '../QueryKeys'; +import {NOTIFICATION_KEYS} from '../QueryKeys'; const getNotificationList = async (page: number) => { const { @@ -17,7 +17,7 @@ const getNotificationList = async (page: number) => { }; export interface NotificationDTO { - id: string; + id: number; title: string; body: string; type: string; @@ -32,7 +32,7 @@ interface GetNotificationResponse { const useGetNotification = (page: number) => { const {data, hasNextPage, fetchNextPage, isFetching} = useInfiniteQuery({ - queryKey: CATEGORY_KEYS.list({page: page}), + queryKey: NOTIFICATION_KEYS.list({page: page}), queryFn: ({pageParam = 1}: {pageParam?: number}) => getNotificationList(pageParam), getNextPageParam: lastPage => lastPage.nextPage, From 4541e5bae1657ae49f03c23efd44d829126fd406 Mon Sep 17 00:00:00 2001 From: Yooshin Kim Date: Wed, 25 Sep 2024 00:36:24 +0900 Subject: [PATCH 13/13] =?UTF-8?q?[SKP-189]=20fix=20:=20id=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=20=EC=98=A4=EB=A5=98=20=EB=A7=89=EA=B8=B0=20=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20=EC=A1=B0=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/screens/Notification/Notification.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/screens/Notification/Notification.tsx b/src/screens/Notification/Notification.tsx index 3a63c81..e3dbeaf 100644 --- a/src/screens/Notification/Notification.tsx +++ b/src/screens/Notification/Notification.tsx @@ -25,7 +25,7 @@ export default function Notification({navigation}: NotificationProps) { item.id.toString()} + keyExtractor={item => `${item.id}-${item.createdAt}`} renderItem={({item}: {item: NotificationDTO}) => ( )}