Created
January 19, 2023 14:59
-
-
Save bbsmithy/62140e84dad1eaa5db31e220d1f28b37 to your computer and use it in GitHub Desktop.
Redux middleware for adding notification reminders
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { PayloadAction } from "@reduxjs/toolkit"; | |
import * as Notifications from "expo-notifications"; | |
export type ReminderType = "daily" | "weekly" | "every_other_day"; | |
export type Reminder = { | |
type: ReminderType; | |
title: string; | |
subTitle: string; | |
optionKey: string; | |
trigger: { | |
hours: number; | |
minutes: number; | |
repeats?: boolean; | |
weekday?: number; | |
daysInterval?: number; | |
}, | |
// notification identifier | |
id?: string; | |
// used for launch functionality when opening notification | |
data?: any; | |
} | |
Notifications.setNotificationHandler({ | |
handleNotification: async () => ({ | |
shouldShowAlert: true, | |
shouldPlaySound: false, | |
shouldSetBadge: false, | |
}), | |
}); | |
export const DEFAULT_THOUGHT_EXCERCISE_REMINDER: Reminder = { | |
type: "every_other_day", | |
title: "Every Second Day Reminder", | |
subTitle: "This is a default reminder", | |
data: {}, | |
optionKey: "every_other_day_2", | |
trigger: { | |
daysInterval: 2, | |
hours: 11, | |
minutes: 13, | |
} | |
} | |
const schduleEveryOtherDayReminder = (reminder: Reminder) => { | |
// TODO: Calculate seconds from daysInterval | |
const secondsInDays = 86400; | |
// @ts-ignore | |
let seconds = secondsInDays * reminder.trigger.daysInterval; | |
// Get the diff in seconds between 24hr current time | |
// and the 24hr time of the reminder | |
const selectedHourMinuteInSeconds = (reminder.trigger.hours * 3600) + (reminder.trigger.minutes * 60); | |
const currentHourMinuteInSeconds = (new Date().getHours() * 3600) + (new Date().getMinutes() * 60); | |
const diff = selectedHourMinuteInSeconds - currentHourMinuteInSeconds; | |
seconds = seconds + diff; | |
return Notifications.scheduleNotificationAsync({ | |
content: { | |
title: reminder.title, | |
body: reminder.subTitle, | |
data: reminder.data, | |
}, | |
trigger: { | |
seconds, | |
repeats: true | |
}, | |
}); | |
} | |
const schduleWeeklyReminder = (reminder: Reminder) => { | |
return Notifications.scheduleNotificationAsync({ | |
content: { | |
title: reminder.title, | |
body: reminder.subTitle, | |
data: reminder.data, | |
}, | |
trigger: { | |
hour: reminder.trigger.hours, | |
minute: reminder.trigger.minutes, | |
weekday: reminder.trigger.weekday, | |
repeats: true | |
}, | |
}); | |
} | |
const schduleDailyReminder = (reminder: Reminder) => { | |
return Notifications.scheduleNotificationAsync({ | |
content: { | |
title: reminder.title, | |
body: reminder.subTitle, | |
data: reminder.data | |
}, | |
trigger: { | |
hour: reminder.trigger.hours, | |
minute: reminder.trigger.minutes, | |
repeats: true, | |
}, | |
}) | |
} | |
const cancelReminder = (identifier: string) => { | |
return Notifications.cancelScheduledNotificationAsync(identifier) | |
} | |
export const notifications = | |
(store: any) => (next: any) => async (action: PayloadAction<Reminder>) => { | |
try { | |
switch (action.type) { | |
case "Reminders/setThoughtExcerciseReminder": { | |
const previousReminderId = store.getState().Reminders.thought_excercise?.id; | |
if (previousReminderId) { | |
await cancelReminder(previousReminderId); | |
} | |
if (action.payload.type === "daily") { | |
const notificationId = await schduleDailyReminder(action.payload); | |
if (notificationId) { | |
action.payload.id = notificationId; | |
next(action) | |
break; | |
} else { | |
throw new Error("Notification ID is null") | |
} | |
} else { | |
const notificationId = await schduleEveryOtherDayReminder(action.payload); | |
if (notificationId) { | |
action.payload.id = notificationId; | |
next(action) | |
break; | |
} else { | |
throw new Error("Notification ID is null") | |
} | |
} | |
} | |
case "Reminders/setSessionRatingReportReminder": { | |
const previousReminderId = store.getState().Reminders.session_rating_report?.id; | |
if (previousReminderId) { | |
await cancelReminder(previousReminderId); | |
} | |
const notificationId = await schduleWeeklyReminder(action.payload); | |
if (notificationId) { | |
action.payload.id = notificationId; | |
next(action) | |
} else { | |
throw new Error("Notification ID is null") | |
} | |
break; | |
} | |
case "Reminders/setOverallProgressReportReminder": { | |
const previousReminderId = store.getState().Reminders.overall_progress_report?.id; | |
if (previousReminderId) { | |
await cancelReminder(previousReminderId); | |
} | |
const notificationId = await schduleWeeklyReminder(action.payload); | |
if (notificationId) { | |
action.payload.id = notificationId; | |
next(action) | |
} else { | |
throw new Error("Notification ID is null") | |
} | |
break; | |
} | |
case "Reminders/updateReminder": { | |
// Cancel old reminder using identifier | |
// Schedule new reminder | |
next(action) | |
break; | |
} | |
case "Reminders/resetReminders": { | |
try { | |
// Cancel reminder using identifier | |
const notifs = await Notifications.getAllScheduledNotificationsAsync(); | |
const cancelReqs = notifs.map((notif) => { | |
return cancelReminder(notif.identifier) | |
}) | |
await Promise.all(cancelReqs) | |
next(action) | |
break; | |
} catch (err) { | |
console.log("deleteReminder Error: ", err) | |
break; | |
} | |
} | |
default: { | |
next(action); | |
} | |
} | |
} catch (err) { | |
console.log(err) | |
alert(JSON.stringify(err)) | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment