diff --git a/TinyBite/GoogleService-Info.plist b/TinyBite/GoogleService-Info.plist new file mode 100644 index 0000000..4e6a0f5 --- /dev/null +++ b/TinyBite/GoogleService-Info.plist @@ -0,0 +1,30 @@ + + + + + API_KEY + AIzaSyCYRetK8aTyzQ0B8FR8ewUvVu7F6gJHxVk + GCM_SENDER_ID + 748185101542 + PLIST_VERSION + 1 + BUNDLE_ID + com.tinybite2025.TinyBite + PROJECT_ID + tinybite-a7f3c + STORAGE_BUCKET + tinybite-a7f3c.firebasestorage.app + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:748185101542:ios:fa65ef6758ac9e8a28c727 + + \ No newline at end of file diff --git a/TinyBite/api/notificationApi.ts b/TinyBite/api/notificationApi.ts new file mode 100644 index 0000000..608d198 --- /dev/null +++ b/TinyBite/api/notificationApi.ts @@ -0,0 +1,21 @@ +import { privateAxios } from "@/api/axios"; +import { ENDPOINT } from "@/api/urls"; +/** + * FCM 토큰 등록 API + * @param token FCM 네이티브 푸시 토큰 + * @param userId 유저 ID + */ +export const registerFcmToken = async ( + token: string, + userId: number +): Promise => { + await privateAxios.post( + ENDPOINT.FCM.TOKEN, + { token }, + { + headers: { + "User-ID": userId.toString(), + }, + } + ); +}; diff --git a/TinyBite/api/urls.ts b/TinyBite/api/urls.ts index e1100ea..bc480b1 100644 --- a/TinyBite/api/urls.ts +++ b/TinyBite/api/urls.ts @@ -34,6 +34,7 @@ export const ENDPOINT = { }, USER: { ME: "/api/v1/user/me", + WITHDRAWAL_VALIDATE: "/api/v1/user/me/withdrawal/validate", NICKNAME_CHECK: "/api/v1/user/nickname/check", LOCATION: "/api/v1/user/me/location", ACTIVE_PARTIES: "/api/v1/user/parties/participating", @@ -49,4 +50,7 @@ export const ENDPOINT = { ONE_TO_ONE: "/api/v1/chatroom/one-to-one", GROUP: "/api/v1/chatroom/group", }, + FCM: { + TOKEN: "/api/v1/fcm/token", + }, }; diff --git a/TinyBite/api/userApi.ts b/TinyBite/api/userApi.ts index e2f2e75..da3766e 100644 --- a/TinyBite/api/userApi.ts +++ b/TinyBite/api/userApi.ts @@ -58,6 +58,15 @@ export const checkNickname = async (nickname: string): Promise => { }); }; +/** + * 탈퇴 가능 여부 확인 API + * @returns canWithdraw 값 (true: 탈퇴 가능, false: 탈퇴 불가능) + */ +export const validateWithdrawal = async (): Promise => { + const res = await privateAxios.get(ENDPOINT.USER.WITHDRAWAL_VALIDATE); + return res.data.data.canWithdraw; +}; + /** * 회원 탈퇴 API */ diff --git a/TinyBite/app.config.js b/TinyBite/app.config.js index 0ae0624..a82076e 100644 --- a/TinyBite/app.config.js +++ b/TinyBite/app.config.js @@ -13,6 +13,7 @@ module.exports = { ios: { supportsTablet: true, bundleIdentifier: "com.tinybite2025.TinyBite", + googleServicesFile: "./GoogleService-Info.plist", infoPlist: { ITSAppUsesNonExemptEncryption: false, }, @@ -26,6 +27,7 @@ module.exports = { edgeToEdgeEnabled: true, predictiveBackGestureEnabled: false, package: "com.tinybite2025.TinyBite", + googleServicesFile: "./google-services.json", splash: { backgroundColor: "#FE870F", image: "./assets/images/splash-icon.png", diff --git a/TinyBite/app/(mypage)/setting.tsx b/TinyBite/app/(mypage)/setting.tsx index 24a679b..c7915af 100644 --- a/TinyBite/app/(mypage)/setting.tsx +++ b/TinyBite/app/(mypage)/setting.tsx @@ -1,5 +1,5 @@ import { postLogout } from "@/api/authApi"; -import { deleteUserMe } from "@/api/userApi"; +import { deleteUserMe, validateWithdrawal } from "@/api/userApi"; import ConfirmModal from "@/components/ConfirmModal"; import { useAuthStore } from "@/stores/authStore"; import { colors } from "@/styles/colors"; @@ -91,7 +91,7 @@ export default function SettingScreen() { {/* Content */} - {/* 알림 설정 */} + {/* 알림 설정 router.push("../(mypage)/notification")} @@ -110,8 +110,8 @@ export default function SettingScreen() { style={styles.chevronIcon} /> - {/* 구분선 */} + */} {/* 내 동네 설정 */} {/* setShowWithdrawModal(true)} + onPress={async () => { + try { + const canWithdraw = await validateWithdrawal(); + if (canWithdraw) { + setShowWithdrawModal(true); + } else { + Toast.show({ + type: "basicToast", + props: { text: "진행 중인 파티가 있어 탈퇴할 수 없습니다." }, + position: "bottom", + bottomOffset: 98, + visibilityTime: 2000, + }); + } + } catch (error: any) { + const status = error?.response?.status; + if (status === 500) { + Toast.show({ + type: "basicToast", + props: { + text: "진행 중인 파티가 있어 탈퇴할 수 없습니다.", + }, + position: "bottom", + bottomOffset: 98, + visibilityTime: 2000, + }); + } else { + // 기타 서버 오류 + Toast.show({ + type: "basicToast", + props: { + text: "잠시 후 다시 시도해주세요.", + }, + position: "bottom", + bottomOffset: 98, + visibilityTime: 2000, + }); + } + } + }} > { if (user) { setUser(user); + // 푸시 알림 토큰 등록 + registerPushToken(user.userId); } }, [user, setUser]); diff --git a/TinyBite/app/(tabs)/index.tsx b/TinyBite/app/(tabs)/index.tsx index 7d72960..63be197 100644 --- a/TinyBite/app/(tabs)/index.tsx +++ b/TinyBite/app/(tabs)/index.tsx @@ -10,7 +10,6 @@ import { StyleSheet, View } from "react-native"; export default function HomeScreen() { const [isMenuOpen, setIsMenuOpen] = useState(false); - return ( diff --git a/TinyBite/app/_layout.tsx b/TinyBite/app/_layout.tsx index 432c2e5..1457b60 100644 --- a/TinyBite/app/_layout.tsx +++ b/TinyBite/app/_layout.tsx @@ -1,11 +1,23 @@ import { toastConfig } from "@/lib/toast/toastConfig"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import * as Notifications from "expo-notifications"; import { Stack } from "expo-router"; import { KeyboardProvider } from "react-native-keyboard-controller"; import Toast from "react-native-toast-message"; const queryClient = new QueryClient(); +// 알림 핸들러 설정 - 앱이 포그라운드에 있을 때 알림 표시 +Notifications.setNotificationHandler({ + handleNotification: async () => ({ + shouldShowAlert: true, + shouldPlaySound: true, + shouldSetBadge: true, + shouldShowBanner: true, + shouldShowList: true, + }), +}); + export default function RootLayout() { return ( diff --git a/TinyBite/google-services.json b/TinyBite/google-services.json new file mode 100644 index 0000000..766d2b0 --- /dev/null +++ b/TinyBite/google-services.json @@ -0,0 +1,29 @@ +{ + "project_info": { + "project_number": "748185101542", + "project_id": "tinybite-a7f3c", + "storage_bucket": "tinybite-a7f3c.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:748185101542:android:a3e225373c65b25f28c727", + "android_client_info": { + "package_name": "com.tinybite2025.TinyBite" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyBWuDAIiVfblq9U3kCChqeLfIWUkHe6ZnM" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/TinyBite/hooks/usePushNotification.ts b/TinyBite/hooks/usePushNotification.ts new file mode 100644 index 0000000..92e892d --- /dev/null +++ b/TinyBite/hooks/usePushNotification.ts @@ -0,0 +1,41 @@ +import { registerFcmToken } from "@/api/notificationApi"; +import * as Notifications from "expo-notifications"; + +/** + * FCM 푸시 토큰 등록 훅 + * @param userId 유저 ID + */ +export const registerPushToken = async (userId: number): Promise => { + try { + //개발 환경에서 테스트 할 때 주석 처리 + // 실제 기기에서만 작동 + //if (!Device.isDevice) { + // console.log("실제 기기에서만 작동합니다."); + // return; + //} + + // 1. 권한 확인 및 요청 + const { status: existingStatus } = + await Notifications.getPermissionsAsync(); + let finalStatus = existingStatus; + if (existingStatus !== "granted") { + const { status } = await Notifications.requestPermissionsAsync(); + finalStatus = status; + } + + if (finalStatus !== "granted") { + console.log("알림 권한 획득 실패"); + return; + } + + // 2. FCM 네이티브 토큰 가져오기 + const tokenData = await Notifications.getDevicePushTokenAsync(); + const fcmToken = tokenData.data; + + // 3. 서버 API 호출 + await registerFcmToken(fcmToken, userId); + console.log("FCM 토큰 등록 성공"); + } catch (error) { + console.error("토큰 등록 중 에러 발생:", error); + } +}; diff --git a/TinyBite/package-lock.json b/TinyBite/package-lock.json index 3bdb5be..ff4303f 100644 --- a/TinyBite/package-lock.json +++ b/TinyBite/package-lock.json @@ -22,6 +22,7 @@ "expo-constants": "~18.0.10", "expo-crypto": "~15.0.8", "expo-dev-client": "~6.0.20", + "expo-device": "~8.0.10", "expo-font": "~14.0.10", "expo-haptics": "~15.0.7", "expo-image": "~3.0.10", @@ -30,6 +31,7 @@ "expo-linear-gradient": "^15.0.8", "expo-linking": "~8.0.9", "expo-location": "~19.0.8", + "expo-notifications": "~0.32.16", "expo-router": "~6.0.15", "expo-secure-store": "~15.0.8", "expo-splash-screen": "~31.0.11", @@ -2318,6 +2320,12 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@ide/backoff": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ide/backoff/-/backoff-1.0.0.tgz", + "integrity": "sha512-F0YfUDjvT+Mtt/R4xdl2X0EYCHMMiJqNLdxHD++jDT5ydEFIyqbCHh51Qx2E211dgZprPKhV7sHmnXKpLuvc5g==", + "license": "MIT" + }, "node_modules/@isaacs/balanced-match": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", @@ -4319,6 +4327,19 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "license": "MIT" }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", @@ -4345,7 +4366,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, "license": "MIT", "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -4577,6 +4597,12 @@ "@babel/core": "^7.0.0" } }, + "node_modules/badgin": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/badgin/-/badgin-1.2.3.tgz", + "integrity": "sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw==", + "license": "MIT" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4778,7 +4804,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", @@ -4810,7 +4835,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -5321,7 +5345,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", @@ -5348,7 +5371,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.0.1", @@ -6212,6 +6234,15 @@ } } }, + "node_modules/expo-application": { + "version": "7.0.8", + "resolved": "https://registry.npmjs.org/expo-application/-/expo-application-7.0.8.tgz", + "integrity": "sha512-qFGyxk7VJbrNOQWBbE09XUuGuvkOgFS9QfToaK2FdagM2aQ+x3CvGV2DuVgl/l4ZxPgIf3b/MNh9xHpwSwn74Q==", + "license": "MIT", + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-asset": { "version": "12.0.12", "resolved": "https://registry.npmjs.org/expo-asset/-/expo-asset-12.0.12.tgz", @@ -6248,12 +6279,12 @@ } }, "node_modules/expo-constants": { - "version": "18.0.12", - "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.12.tgz", - "integrity": "sha512-WzcKYMVNRRu4NcSzfIVRD5aUQFnSpTZgXFrlWmm19xJoDa4S3/PQNi6PNTBRc49xz9h8FT7HMxRKaC8lr0gflA==", + "version": "18.0.13", + "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz", + "integrity": "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ==", "license": "MIT", "dependencies": { - "@expo/config": "~12.0.12", + "@expo/config": "~12.0.13", "@expo/env": "~2.0.8" }, "peerDependencies": { @@ -6346,6 +6377,44 @@ "expo": "*" } }, + "node_modules/expo-device": { + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/expo-device/-/expo-device-8.0.10.tgz", + "integrity": "sha512-jd5BxjaF7382JkDMaC+P04aXXknB2UhWaVx5WiQKA05ugm/8GH5uaz9P9ckWdMKZGQVVEOC8MHaUADoT26KmFA==", + "license": "MIT", + "dependencies": { + "ua-parser-js": "^0.7.33" + }, + "peerDependencies": { + "expo": "*" + } + }, + "node_modules/expo-device/node_modules/ua-parser-js": { + "version": "0.7.41", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.41.tgz", + "integrity": "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "bin": { + "ua-parser-js": "script/cli.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/expo-file-system": { "version": "19.0.21", "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-19.0.21.tgz", @@ -6521,6 +6590,26 @@ "react-native": "*" } }, + "node_modules/expo-notifications": { + "version": "0.32.16", + "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.32.16.tgz", + "integrity": "sha512-QQD/UA6v7LgvwIJ+tS7tSvqJZkdp0nCSj9MxsDk/jU1GttYdK49/5L2LvE/4U0H7sNBz1NZAyhDZozg8xgBLXw==", + "license": "MIT", + "dependencies": { + "@expo/image-utils": "^0.8.8", + "@ide/backoff": "^1.0.0", + "abort-controller": "^3.0.0", + "assert": "^2.0.0", + "badgin": "^1.1.5", + "expo-application": "~7.0.8", + "expo-constants": "~18.0.13" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, "node_modules/expo-router": { "version": "6.0.21", "resolved": "https://registry.npmjs.org/expo-router/-/expo-router-6.0.21.tgz", @@ -7272,7 +7361,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, "license": "MIT", "dependencies": { "is-callable": "^1.2.7" @@ -7382,7 +7470,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -7632,7 +7719,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" @@ -7934,6 +8020,22 @@ "loose-envify": "^1.0.0" } }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -8038,7 +8140,6 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -8151,7 +8252,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.4", @@ -8193,6 +8293,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-negative-zero": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", @@ -8236,7 +8352,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -8319,7 +8434,6 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, "license": "MIT", "dependencies": { "which-typed-array": "^1.1.16" @@ -9812,11 +9926,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -9826,7 +9955,6 @@ "version": "4.1.7", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", @@ -10300,7 +10428,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -11324,7 +11451,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dev": true, "license": "MIT", "dependencies": { "call-bound": "^1.0.2", @@ -11471,7 +11597,6 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", @@ -12751,6 +12876,19 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -13161,7 +13299,6 @@ "version": "1.1.19", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", - "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", diff --git a/TinyBite/package.json b/TinyBite/package.json index d52296a..d78cce9 100644 --- a/TinyBite/package.json +++ b/TinyBite/package.json @@ -25,6 +25,7 @@ "expo-constants": "~18.0.10", "expo-crypto": "~15.0.8", "expo-dev-client": "~6.0.20", + "expo-device": "~8.0.10", "expo-font": "~14.0.10", "expo-haptics": "~15.0.7", "expo-image": "~3.0.10", @@ -33,6 +34,7 @@ "expo-linear-gradient": "^15.0.8", "expo-linking": "~8.0.9", "expo-location": "~19.0.8", + "expo-notifications": "~0.32.16", "expo-router": "~6.0.15", "expo-secure-store": "~15.0.8", "expo-splash-screen": "~31.0.11",