diff --git a/app/(app)/notifications.js b/app/(app)/notifications.js
new file mode 100644
index 0000000..09a5702
--- /dev/null
+++ b/app/(app)/notifications.js
@@ -0,0 +1,5 @@
+import { Notifications } from "../../pages/Notifications";
+
+export default function Page() {
+ return ;
+}
diff --git a/components/Icons.tsx b/components/Icons.tsx
index c0cf94f..7cb0e6f 100644
--- a/components/Icons.tsx
+++ b/components/Icons.tsx
@@ -3,6 +3,7 @@ import {
ArchiveRestore,
ArrowDown,
ArrowLeftRight,
+ Bell,
Bitcoin,
BookUser,
Camera,
@@ -95,13 +96,13 @@ interopIcon(CircleCheck);
interopIcon(TriangleAlert);
interopIcon(LogOut);
interopIcon(ArchiveRestore);
+interopIcon(Bell);
export {
AlertCircle,
ArchiveRestore,
ArrowDown,
- ArrowLeftRight,
- Bitcoin,
+ ArrowLeftRight, Bell, Bitcoin,
BookUser,
Camera,
CameraOff,
@@ -136,5 +137,6 @@ export {
WalletIcon,
X,
XCircle,
- ZapIcon,
+ ZapIcon
};
+
diff --git a/package.json b/package.json
index 7e69fa6..0d79d45 100644
--- a/package.json
+++ b/package.json
@@ -41,10 +41,12 @@
"expo-camera": "~15.0.16",
"expo-clipboard": "~6.0.3",
"expo-constants": "~16.0.2",
+ "expo-device": "~6.0.2",
"expo-font": "~12.0.10",
"expo-linear-gradient": "~13.0.2",
"expo-linking": "~6.3.1",
"expo-local-authentication": "~14.0.1",
+ "expo-notifications": "~0.28.19",
"expo-router": "^3.5.23",
"expo-secure-store": "^13.0.2",
"expo-status-bar": "~1.12.1",
diff --git a/pages/Notifications.tsx b/pages/Notifications.tsx
new file mode 100644
index 0000000..33c60b6
--- /dev/null
+++ b/pages/Notifications.tsx
@@ -0,0 +1,135 @@
+import Constants from "expo-constants";
+import React, { useEffect, useRef, useState } from "react";
+import { View, Platform } from "react-native";
+import { Button } from "~/components/ui/button";
+import { Text } from "~/components/ui/text";
+import Screen from "~/components/Screen";
+
+import * as Device from "expo-device";
+import * as ExpoNotifications from "expo-notifications";
+
+ExpoNotifications.setNotificationHandler({
+ handleNotification: async () => ({
+ shouldShowAlert: true,
+ shouldPlaySound: false,
+ shouldSetBadge: false,
+ }),
+});
+
+async function sendPushNotification(expoPushToken: string) {
+ const message = {
+ to: expoPushToken,
+ sound: 'default',
+ title: 'Original Title',
+ body: 'And here is the body!',
+ data: { someData: 'goes here' },
+ };
+
+ await fetch('https://exp.host/--/api/v2/push/send', {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Accept-encoding': 'gzip, deflate',
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(message),
+ });
+}
+
+function handleRegistrationError(errorMessage: string) {
+ alert(errorMessage);
+ throw new Error(errorMessage);
+}
+
+async function registerForPushNotificationsAsync() {
+ if (Platform.OS === 'android') {
+ ExpoNotifications.setNotificationChannelAsync('default', {
+ name: 'default',
+ importance: ExpoNotifications.AndroidImportance.MAX,
+ vibrationPattern: [0, 250, 250, 250],
+ lightColor: '#FF231F7C',
+ });
+ }
+
+ if (Device.isDevice) {
+ const { status: existingStatus } = await ExpoNotifications.getPermissionsAsync();
+ let finalStatus = existingStatus;
+ if (existingStatus !== 'granted') {
+ const { status } = await ExpoNotifications.requestPermissionsAsync();
+ finalStatus = status;
+ }
+ if (finalStatus !== 'granted') {
+ handleRegistrationError('Permission not granted to get push token for push notification!');
+ return;
+ }
+ const projectId =
+ Constants?.expoConfig?.extra?.eas?.projectId ?? Constants?.easConfig?.projectId;
+ if (!projectId) {
+ handleRegistrationError('Project ID not found');
+ }
+ try {
+ const pushTokenString = (
+ await ExpoNotifications.getExpoPushTokenAsync({
+ projectId,
+ })
+ ).data;
+ console.log(pushTokenString);
+ return pushTokenString;
+ } catch (e: unknown) {
+ handleRegistrationError(`${e}`);
+ }
+ } else {
+ handleRegistrationError('Must use physical device for push notifications');
+ }
+}
+
+export function Notifications() {
+ const [expoPushToken, setExpoPushToken] = useState('');
+ const [notification, setNotification] = useState(
+ undefined
+ );
+ const notificationListener = useRef();
+ const responseListener = useRef();
+
+ useEffect(() => {
+ registerForPushNotificationsAsync()
+ .then(token => setExpoPushToken(token ?? ''))
+ .catch((error: any) => setExpoPushToken(`${error}`));
+
+ notificationListener.current = ExpoNotifications.addNotificationReceivedListener(notification => {
+ setNotification(notification);
+ });
+
+ responseListener.current = ExpoNotifications.addNotificationResponseReceivedListener(response => {
+ console.log(response);
+ });
+
+ return () => {
+ notificationListener.current &&
+ ExpoNotifications.removeNotificationSubscription(notificationListener.current);
+ responseListener.current &&
+ ExpoNotifications.removeNotificationSubscription(responseListener.current);
+ };
+ }, []);
+
+ return (
+
+
+ Your Expo push token: {expoPushToken}
+
+ Title: {notification && notification.request.content.title}
+ Body: {notification && notification.request.content.body}
+ Data: {notification && JSON.stringify(notification.request.content.data)}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/pages/settings/Settings.tsx b/pages/settings/Settings.tsx
index 151543e..33eaea6 100644
--- a/pages/settings/Settings.tsx
+++ b/pages/settings/Settings.tsx
@@ -1,6 +1,7 @@
import { Link, router } from "expo-router";
import { Alert, TouchableOpacity, View } from "react-native";
import {
+ Bell,
Bitcoin,
Egg,
Fingerprint,
@@ -104,7 +105,16 @@ export function Settings() {
}}
>
- Open Onboarding
+ Onboarding
+
+ {
+ router.push("/notifications");
+ }}
+ >
+
+ Notifications