Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

actual Notifications #57

Merged
merged 2 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion client/app.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"expo": {
"name": "client",
"slug": "client",
"slug": "care-wallet-generate",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
Expand All @@ -23,6 +23,12 @@
},
"web": {
"favicon": "./assets/favicon.png"
},
"extra": {
"eas": {
"projectId": "c66c08fd-ea3e-4a67-84da-77ef27bb3c23"
}
}
// "owner": "andrew10"
}
}
2 changes: 2 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@
"date-fns": "^3.3.1",
"expo": "50.0.6",
"expo": "^50.0.11",
"expo-device": "~5.4.0",
"expo-document-picker": "~11.10.1",
"expo-file-system": "~16.0.6",
"expo-notifications": "~0.20.1",
"expo-status-bar": "~1.11.1",
"firebase": "^10.7.2",
"lodash": "^4.17.21",
Expand Down
16 changes: 15 additions & 1 deletion client/screens/LoginPage.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { Alert, Pressable, Text, TextInput, View } from 'react-native';

import { onAuthStateChanged } from '@firebase/auth';
import { useNavigation } from '@react-navigation/native';
import Constants from 'expo-constants';

Check warning on line 6 in client/screens/LoginPage.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

Using exported name 'Constants' as identifier for default export

import { auth } from '../firebase.config';
import { AppStackNavigation } from '../navigation/types';
import { useAuth } from '../services/auth';
import { registerForPushNotificationsAsync } from '../services/notifications';

export default function LoginPage() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const { logInMutation, signUpMutation } = useAuth();
const [expoPushToken, setExpoPushToken] = useState('');

const navigation = useNavigation<AppStackNavigation>();

useEffect(() => {
console.log(Constants.easConfig?.projectId); // --> undefined
console.log(Constants.expoConfig?.extra?.eas.projectId); // --> my project id

registerForPushNotificationsAsync().then((token) =>
setExpoPushToken(token!)
);

console.log(expoPushToken); // this is here until we send to backend
}, []);

onAuthStateChanged(auth, (user) => {
if (user) {
navigation.navigate('Main');
Expand Down
167 changes: 167 additions & 0 deletions client/services/notifications.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import { Platform } from 'react-native';

import Constants from 'expo-constants';

Check warning on line 3 in client/services/notifications.tsx

View workflow job for this annotation

GitHub Actions / Lint (20.x, 1.21.x)

Using exported name 'Constants' as identifier for default export
import { isDevice } from 'expo-device';
import {
AndroidImportance,
cancelScheduledNotificationAsync,
getExpoPushTokenAsync,
requestPermissionsAsync,
scheduleNotificationAsync,
setNotificationChannelAsync
} from 'expo-notifications';

export async function registerForPushNotificationsAsync() {
// checks that this is a physical device
if (!isDevice) {
alert(
'Must use physical device for Push Notifications. Must be ios or android.'
);
return null;
}

// ask user for notification permissions
const { status } = await requestPermissionsAsync();
if (status !== 'granted') {
alert('Permission to receive push notifications was denied');
return null;
}

// android needs notification channel with highest importance so notificaiton goes through always
if (Platform.OS === 'android') {
setNotificationChannelAsync('default', {
name: 'default',
importance: AndroidImportance.MAX
});
}

const carewalletProjectId = Constants.easConfig?.projectId;

// gets push notification token
const token = (
await getExpoPushTokenAsync({
projectId: carewalletProjectId
})
).data;
console.log('ExpoPushToken: ', token);

return token;
}

export async function scheduleCalendarPushNotification(
title: string,
body: string,
repeat: boolean,
date: Date,
typeOfTrigger?: string
// OPTIONS for typeOfTrigger:
// NOTE: IN UTC TIME (Must convert time zone you are in to UTC)
// 1. Yearly: { repeats: true, month: [0-11], day: [1-31], hour: [0-23], minute: [0-59] }
// - Repeats annually on the specified month, day, hour, and minute.
// 2. Weekly: { weekday: [1-7], hour: [0-23], minute: [0-59] }
// - Repeats weekly on the specified weekday, hour, and minute. (1 for Sunday, 2 for Monday, ..., 7 for Saturday)
// 3. Daily: { repeats: true, hour: [0-23], minute: [0-59] }
// - Repeats daily at the specified hour and minute.
) {
try {
const triggerDate = new Date(date);

let Trigger;

if (repeat) {
if (typeOfTrigger === 'yearly') {
Trigger = {
repeats: true,
month: triggerDate.getUTCMonth(),
day: triggerDate.getUTCDate(),
hour: triggerDate.getUTCHours(),
minute: triggerDate.getUTCMinutes()
};
} else if (typeOfTrigger === 'weekly') {
Trigger = {
weekday: triggerDate.getUTCDay() === 0 ? 7 : triggerDate.getUTCDay(),
hour: triggerDate.getUTCHours(),
minute: triggerDate.getUTCMinutes()
};
} else if (typeOfTrigger === 'daily') {
Trigger = {
repeats: true,
hour: triggerDate.getUTCHours(),
minute: triggerDate.getUTCMinutes()
};
} else {
// will default to daily
Trigger = {
repeats: true,
hour: triggerDate.getUTCHours(),
minute: triggerDate.getUTCMinutes()
};
}
} else {
// One-time notification trigger
Trigger = new Date(triggerDate);
}

const notificationID = await scheduleNotificationAsync({
content: {
title: title,
body: body
},
trigger: Trigger
});

// notification ID is returned, so you can use it to cancel the notification
console.log('Notification scheduled successfully, %s', notificationID);
} catch (error) {
console.error('Error scheduling notification:', error);
alert('Failed to schedule notification. Please try again later.');
}
}

// INSTANT push notification - when this function is called with intended title and body,
// a notification will be sent to the user right away (in 1 second)
export async function scheduleInstantPushNotification(
title: string,
body: string
) {
scheduleNotificationAsync({
content: {
title: title,
body: body,
data: {}
},
trigger: {
seconds: 1
}
});
}

export async function cancelScheduleNotificationID(id: string) {
cancelScheduledNotificationAsync(id);
}

// this function can be used schedule a daily notification
// takes in title, body, the hour and minute to be repeated at, and date to begin repeating
export async function scheduleDailyNotification(
title: string,
body: string,
hour: number,
minutes: number,
dateToStart: Date
) {
// Get the current date
const currentDate = dateToStart;

// Set the time
currentDate.setHours(hour);
currentDate.setMinutes(minutes);

// Schedule the daily notification
await scheduleCalendarPushNotification(
title,
body,
true, // repeat daily
currentDate,
'daily' // specify the type of trigger as 'daily'
);
}
Loading