import { Notification, NotificationStatus, getNotificationHtmlUrl, isNotificationBuiltFromTask } from "../notification"; import { Action, ActionPanel, Icon, getPreferenceValues, showToast, Toast } from "@raycast/api"; import { CreateTaskFromNotification } from "./CreateTaskFromNotification"; import { LinkNotificationToTask } from "./LinkNotificationToTask"; import { Page, UniversalInboxPreferences } from "../types"; import { MutatePromise } from "@raycast/utils"; import { useMemo, ReactElement } from "react"; import { handleErrors } from "../api"; import { TaskStatus } from "../task"; import utc from "dayjs/plugin/utc"; import fetch from "node-fetch"; import dayjs from "dayjs"; dayjs.extend(utc); interface NotificationActionsProps { notification: Notification; detailsTarget: ReactElement; mutate: MutatePromise | undefined>; } export function NotificationActions({ notification, detailsTarget, mutate }: NotificationActionsProps) { const notification_html_url = useMemo(() => { return getNotificationHtmlUrl(notification); }, [notification]); return ( deleteNotification(notification, mutate)} /> unsubscribeFromNotification(notification, mutate)} /> snoozeNotification(notification, mutate)} /> } /> } /> ); } async function deleteNotification(notification: Notification, mutate: MutatePromise | undefined>) { const preferences = getPreferenceValues(); const toast = await showToast({ style: Toast.Style.Animated, title: "Deleting notification" }); try { if (isNotificationBuiltFromTask(notification) && notification.task) { await mutate( fetch(`${preferences.universalInboxBaseUrl}/api/tasks/${notification.task.id}`, { method: "PATCH", body: JSON.stringify({ status: TaskStatus.Deleted }), headers: { "Content-Type": "application/json", Authorization: `Bearer ${preferences.apiKey}`, }, }), { optimisticUpdate(page) { if (page) { page.content = page.content.filter((n) => n.id !== notification.id); } return page; }, }, ); } else { await mutate( handleErrors( fetch(`${preferences.universalInboxBaseUrl}/api/notifications/${notification.id}`, { method: "PATCH", body: JSON.stringify({ status: NotificationStatus.Deleted }), headers: { "Content-Type": "application/json", Authorization: `Bearer ${preferences.apiKey}`, }, }), ), { optimisticUpdate(page) { if (page) { page.content = page.content.filter((n) => n.id !== notification.id); } return page; }, }, ); } toast.style = Toast.Style.Success; toast.title = "Notification successfully deleted"; } catch (error) { toast.style = Toast.Style.Failure; toast.title = "Failed to delete notification"; toast.message = (error as Error).message; throw error; } } async function unsubscribeFromNotification( notification: Notification, mutate: MutatePromise | undefined>, ) { const preferences = getPreferenceValues(); const toast = await showToast({ style: Toast.Style.Animated, title: "Unsubscribing from notification" }); try { await mutate( handleErrors( fetch(`${preferences.universalInboxBaseUrl}/api/notifications/${notification.id}`, { method: "PATCH", body: JSON.stringify({ status: NotificationStatus.Unsubscribed }), headers: { "Content-Type": "application/json", Authorization: `Bearer ${preferences.apiKey}`, }, }), ), { optimisticUpdate(page) { if (page) { page.content = page.content.filter((n) => n.id !== notification.id); } return page; }, }, ); toast.style = Toast.Style.Success; toast.title = "Notification successfully unsubscribed"; } catch (error) { toast.style = Toast.Style.Failure; toast.title = "Failed to unsubscribe from notification"; toast.message = (error as Error).message; throw error; } } async function snoozeNotification(notification: Notification, mutate: MutatePromise | undefined>) { const preferences = getPreferenceValues(); const toast = await showToast({ style: Toast.Style.Animated, title: "Snoozing notification" }); try { const snoozeTime = computeSnoozedUntil(new Date(), 1, 6); await mutate( handleErrors( fetch(`${preferences.universalInboxBaseUrl}/api/notifications/${notification.id}`, { method: "PATCH", body: JSON.stringify({ snoozed_until: snoozeTime }), headers: { "Content-Type": "application/json", Authorization: `Bearer ${preferences.apiKey}`, }, }), ), { optimisticUpdate(page) { if (page) { page.content = page.content.filter((n) => n.id !== notification.id); } return page; }, }, ); toast.style = Toast.Style.Success; toast.title = "Notification successfully snoozed"; } catch (error) { toast.style = Toast.Style.Failure; toast.title = "Failed to snooze notification"; toast.message = (error as Error).message; throw error; } } function computeSnoozedUntil(fromDate: Date, daysOffset: number, resetHour: number): Date { const result = dayjs(fromDate) .utc() .add(fromDate.getHours() < resetHour ? daysOffset - 1 : daysOffset, "day"); return result.hour(resetHour).minute(0).second(0).millisecond(0).toDate(); }