import { h } from '/js/web_modules/preact.js'; import { useState, useEffect } from '/js/web_modules/preact/hooks.js'; import htm from '/js/web_modules/htm.js'; import { ExternalActionButton } from './external-action-modal.js'; import { registerWebPushNotifications, isPushNotificationSupported, } from '../notification/registerWeb.js'; import { URL_REGISTER_NOTIFICATION, URL_REGISTER_EMAIL_NOTIFICATION, HAS_DISPLAYED_NOTIFICATION_MODAL_KEY, USER_VISIT_COUNT_KEY, USER_DISMISSED_ANNOYING_NOTIFICATION_POPUP_KEY, } from '../utils/constants.js'; import { setLocalStorage, getLocalStorage } from '../utils/helpers.js'; const html = htm.bind(h); export function NotifyModal({ notifications, streamName, accessToken }) { const [error, setError] = useState(null); const [loaderStyle, setLoaderStyle] = useState('none'); const [emailNotificationsButtonEnabled, setEmailNotificationsButtonEnabled] = useState(false); const [emailAddress, setEmailAddress] = useState(null); const emailNotificationButtonState = emailNotificationsButtonEnabled ? '' : 'cursor-not-allowed opacity-50'; const [browserPushPermissionsPending, setBrowserPushPermissionsPending] = useState(false); const { browser } = notifications; const { publicKey } = browser; const browserPushEnabled = browser.enabled && isPushNotificationSupported(); let emailEnabled = false; // Store that the user has opened the notifications modal at least once // so we don't ever need to remind them to do it again. useEffect(() => { setLocalStorage(HAS_DISPLAYED_NOTIFICATION_MODAL_KEY, true); }, []); async function saveNotificationRegistration(channel, destination) { const options = { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ channel: channel, destination: destination }), }; try { await fetch( URL_REGISTER_NOTIFICATION + `?accessToken=${accessToken}`, options ); } catch (e) { console.error(e); } } async function startBrowserPushRegistration() { // If it's already denied or granted, don't do anything. if (Notification.permission !== 'default') { return; } setBrowserPushPermissionsPending(true); try { const subscription = await registerWebPushNotifications(publicKey); saveNotificationRegistration('BROWSER_PUSH_NOTIFICATION', subscription); setError(null); } catch (e) { setError( `Error registering for live notifications: ${e.message}. Make sure you're not inside a private browser environment or have previously disabled notifications for this stream.` ); } setBrowserPushPermissionsPending(false); } async function handlePushToggleChange() { // Nothing can be done if they already denied access. if (Notification.permission === 'denied') { return; } if (!pushEnabled) { startBrowserPushRegistration(); } } async function registerForEmailButtonPressed() { try { const options = { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ emailAddress: emailAddress }), }; try { await fetch( URL_REGISTER_EMAIL_NOTIFICATION + `?accessToken=${accessToken}`, options ); } catch (e) { console.error(e); } } catch (e) { setError(`Error registering for email notifications: ${e.message}.`); } } function onEmailInput(e) { const { value } = e.target; // TODO: Add validation for email const valid = true; setEmailAddress(value); setEmailNotificationsButtonEnabled(valid); } function getBrowserPushButtonText() { let pushNotificationButtonText = html` CLICK TO ENABLE`; if (browserPushPermissionsPending) { pushNotificationButtonText = '↑ ACCEPT THE BROWSER PERMISSIONS'; } else if (Notification.permission === 'granted') { pushNotificationButtonText = 'ENABLED'; } else if (Notification.permission === 'denied') { pushNotificationButtonText = 'DENIED. PLEASE FIX BROWSER PERMISSIONS.'; } return pushNotificationButtonText; } const pushEnabled = Notification.permission === 'granted'; return html`

Email Notifications

Get notified directly to your email when this stream goes live.

Enter your email address:
Stop receiving emails any time by clicking the unsubscribe link in the email. Learn more.

Browser notification permissions were denied. Please visit your browser settings to re-enable in order to get notifications.
${getBrowserPushButtonText()}

Browser Notifications

Get notified right in the browser each time this stream goes live.

To disable push notifications from ${window.location.hostname} ${' '} access your browser permissions for this site and turn off notifications.
Learn more.
${window.location.toString()} wants to
Show notifications

You'll need to allow your browser to receive notifications from ${' '} ${streamName}, first.

Contacting your server.

Please wait...

`; } export function NotifyButton({ serverName, onClick }) { const hasDisplayedNotificationModal = getLocalStorage( HAS_DISPLAYED_NOTIFICATION_MODAL_KEY ); const hasPreviouslyDismissedAnnoyingPopup = getLocalStorage( USER_DISMISSED_ANNOYING_NOTIFICATION_POPUP_KEY ); let visits = parseInt(getLocalStorage(USER_VISIT_COUNT_KEY)); if (isNaN(visits)) { visits = 0; } // Only show the annoying popup if the user has never opened the notification // modal previously _and_ they've visited more than 3 times. const [showPopup, setShowPopup] = useState( !hasPreviouslyDismissedAnnoyingPopup && !hasDisplayedNotificationModal && visits > 3 ); const notifyAction = { color: 'rgba(219, 223, 231, 1)', description: `Never miss a stream! Get notified when ${serverName} goes live.`, icon: '/img/notification-bell.svg', openExternally: false, }; const buttonClicked = (e) => { onClick(e); setShowPopup(false); }; const notifyPopupDismissedClicked = () => { setShowPopup(false); setLocalStorage(USER_DISMISSED_ANNOYING_NOTIFICATION_POPUP_KEY, true); }; return html`
Stay updated!
<${ExternalActionButton} onClick=${buttonClicked} action=${notifyAction} />
`; }