brackt/app/hooks/useDraftNotifications.ts
Claude c89c1fd973
Add browser push notifications toggle to draft page
Adds a Notifications toggle in the draft sidebar (below Autodraft)
that uses the Browser Notification API to alert users when a pick is
made or when it's their turn, while the tab is not focused.

- New useDraftNotifications hook for state, permission, and localStorage
- New NotificationSettings component with Switch toggle
- Fires "It's your turn to pick!" when the next pick is the user's
- Fires "{Team} picked {Player}" for all other picks
- Gracefully hides toggle when Notification API is unavailable

https://claude.ai/code/session_0149MvVUYDY6pFUAV1fL4K69
2026-02-20 17:05:40 +00:00

84 lines
2.1 KiB
TypeScript

import { useState, useEffect, useCallback } from "react";
function getStorageKey(seasonId: string) {
return `draftNotifications-${seasonId}`;
}
export function useDraftNotifications(seasonId: string) {
const [isSupported, setIsSupported] = useState(false);
const [permissionState, setPermissionState] = useState<
NotificationPermission | "unsupported"
>("unsupported");
const [enabled, setEnabledState] = useState(false);
// Check browser support and restore persisted preference
useEffect(() => {
if (typeof window === "undefined" || !("Notification" in window)) {
return;
}
setIsSupported(true);
setPermissionState(Notification.permission);
// Restore preference from localStorage only if permission is granted
if (Notification.permission === "granted") {
const stored = localStorage.getItem(getStorageKey(seasonId));
if (stored === "true") {
setEnabledState(true);
}
}
}, [seasonId]);
const setEnabled = useCallback(
async (value: boolean) => {
if (!isSupported) return;
if (value) {
// Request permission if not yet granted
if (Notification.permission === "default") {
const result = await Notification.requestPermission();
setPermissionState(result);
if (result !== "granted") {
return;
}
} else if (Notification.permission === "denied") {
return;
}
setEnabledState(true);
localStorage.setItem(getStorageKey(seasonId), "true");
} else {
setEnabledState(false);
localStorage.setItem(getStorageKey(seasonId), "false");
}
},
[isSupported, seasonId]
);
const sendNotification = useCallback(
(title: string, body: string) => {
if (
!enabled ||
!isSupported ||
Notification.permission !== "granted" ||
!document.hidden
) {
return;
}
new Notification(title, {
body,
tag: `draft-${seasonId}`,
});
},
[enabled, isSupported, seasonId]
);
return {
isSupported,
permissionState,
enabled,
setEnabled,
sendNotification,
};
}