2026-02-20 17:05:40 +00:00
|
|
|
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);
|
|
|
|
|
|
2026-02-20 21:45:35 +00:00
|
|
|
// Check browser support, restore persisted preference, and watch for permission changes
|
2026-02-20 17:05:40 +00:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-02-20 21:45:35 +00:00
|
|
|
|
|
|
|
|
// Watch for the user revoking/granting permission in browser settings
|
|
|
|
|
let permissionStatus: PermissionStatus | null = null;
|
|
|
|
|
navigator.permissions
|
|
|
|
|
.query({ name: "notifications" })
|
|
|
|
|
.then((status) => {
|
|
|
|
|
permissionStatus = status;
|
|
|
|
|
status.onchange = () => {
|
|
|
|
|
setPermissionState(status.state as NotificationPermission);
|
|
|
|
|
// If permission was revoked, disable notifications
|
|
|
|
|
if (status.state !== "granted") {
|
|
|
|
|
setEnabledState(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
})
|
|
|
|
|
.catch(() => {
|
|
|
|
|
// Permissions API not available in all environments; silently ignore
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
if (permissionStatus) {
|
|
|
|
|
permissionStatus.onchange = null;
|
|
|
|
|
}
|
|
|
|
|
};
|
2026-02-20 17:05:40 +00:00
|
|
|
}, [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" ||
|
2026-02-20 21:45:35 +00:00
|
|
|
typeof document === "undefined" ||
|
2026-02-20 17:05:40 +00:00
|
|
|
!document.hidden
|
|
|
|
|
) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new Notification(title, {
|
|
|
|
|
body,
|
|
|
|
|
tag: `draft-${seasonId}`,
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
[enabled, isSupported, seasonId]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
isSupported,
|
|
|
|
|
permissionState,
|
|
|
|
|
enabled,
|
|
|
|
|
setEnabled,
|
|
|
|
|
sendNotification,
|
|
|
|
|
};
|
|
|
|
|
}
|