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",