2022-12-06 08:53:09 +03:00
import { Row , Spin , Typography , Button } from 'antd' ;
2022-09-07 10:00:28 +03:00
import React , { FC , useState } from 'react' ;
2023-05-22 00:12:14 +03:00
import UploadOutlined from '@ant-design/icons/lib/icons/UploadOutlined' ;
import PlusSquareOutlined from '@ant-design/icons/lib/icons/PlusSquareOutlined' ;
2022-05-30 07:52:38 +03:00
import { useRecoilValue } from 'recoil' ;
2023-03-13 09:05:21 +03:00
import { ErrorBoundary } from 'react-error-boundary' ;
2022-05-30 07:52:38 +03:00
import { accessTokenAtom , clientConfigStateAtom } from '../../stores/ClientConfigStore' ;
import {
registerWebPushNotifications ,
saveNotificationRegistration ,
} from '../../../services/notifications-service' ;
2022-09-07 10:00:28 +03:00
import styles from './BrowserNotifyModal.module.scss' ;
2023-03-13 09:05:21 +03:00
import { ComponentError } from '../../ui/ComponentError/ComponentError' ;
2022-05-30 07:52:38 +03:00
2023-05-22 00:12:14 +03:00
import { isMobileSafariHomeScreenApp , isMobileSafariIos } from '../../../utils/helpers' ;
import { arePushNotificationSupported } from '../../../utils/browserPushNotifications' ;
2022-05-30 07:52:38 +03:00
const { Title } = Typography ;
2022-09-07 10:00:28 +03:00
const NotificationsNotSupported = ( ) = > (
< div > Browser notifications are not supported in your browser . < / div >
) ;
2022-05-30 07:52:38 +03:00
2023-04-16 06:10:34 +03:00
const NotificationsNotSupportedLocal = ( ) = > (
< div > Browser notifications are not supported for local servers . < / div >
) ;
2023-05-22 00:12:14 +03:00
const MobileSafariInstructions = ( ) = > (
< div >
< Title level = { 3 } > Get notified on iOS < / Title >
It takes a couple extra steps to make sure you get notified when your favorite streams go live .
< ol >
< li >
Tap the < strong > share < / strong > button < UploadOutlined / > in Safari .
< / li >
< li >
Scroll down and tap < strong > & ldquo ; Add to Home Screen & rdquo ; < / strong > < PlusSquareOutlined / >
.
< / li >
< li >
Tap < strong > & ldquo ; Add & rdquo ; < / strong > .
< / li >
< li > Give this link a name and tap the new icon on your home screen < / li >
< li > Come back to this screen and enable notifications . < / li >
< li >
Tap < strong > & ldquo ; Allow & rdquo ; < / strong > when prompted .
< / li >
< / ol >
< / div >
) ;
2022-09-07 10:00:28 +03:00
export type PermissionPopupPreviewProps = {
2022-05-30 07:52:38 +03:00
start : ( ) = > void ;
2022-09-07 10:00:28 +03:00
} ;
2022-05-30 07:52:38 +03:00
2022-09-07 10:00:28 +03:00
const PermissionPopupPreview : FC < PermissionPopupPreviewProps > = ( { start } ) = > (
< div id = "browser-push-preview-box" className = { styles . pushPreview } >
< div className = { styles . inner } >
< div className = { styles . title } > { window . location . toString ( ) } wants to < / div >
< div className = { styles . permissionLine } >
< svg
2022-12-06 08:53:09 +03:00
className = { styles . bell }
2022-09-07 10:00:28 +03:00
width = "16"
height = "16"
viewBox = "0 0 16 16"
fill = "none"
xmlns = "http://www.w3.org/2000/svg"
>
< path
d = "M14 12.3333V13H2V12.3333L3.33333 11V7C3.33333 4.93333 4.68667 3.11333 6.66667 2.52667C6.66667 2.46 6.66667 2.4 6.66667 2.33333C6.66667 1.97971 6.80714 1.64057 7.05719 1.39052C7.30724 1.14048 7.64638 1 8 1C8.35362 1 8.69276 1.14048 8.94281 1.39052C9.19286 1.64057 9.33333 1.97971 9.33333 2.33333C9.33333 2.4 9.33333 2.46 9.33333 2.52667C11.3133 3.11333 12.6667 4.93333 12.6667 7V11L14 12.3333ZM9.33333 13.6667C9.33333 14.0203 9.19286 14.3594 8.94281 14.6095C8.69276 14.8595 8.35362 15 8 15C7.64638 15 7.30724 14.8595 7.05719 14.6095C6.80714 14.3594 6.66667 14.0203 6.66667 13.6667"
fill = "#676670"
/ >
< / svg >
2022-12-06 08:53:09 +03:00
< span className = { styles . showNotificationsText } > Show notifications < / span >
2022-09-07 10:00:28 +03:00
< / div >
< div className = { styles . buttonRow } >
< Button
type = "primary"
onClick = { ( ) = > {
start ( ) ;
} }
>
Allow
< / Button >
< button type = "button" className = { styles . disabled } >
Block
< / button >
2022-05-30 07:52:38 +03:00
< / div >
< / div >
2022-09-07 10:00:28 +03:00
< / div >
) ;
2022-05-30 07:52:38 +03:00
2022-10-02 19:42:06 +03:00
const NotificationsEnabled = ( ) = > (
< div >
2023-04-16 05:58:52 +03:00
< Title level = { 2 } > Notifications are enabled < / Title >
2022-10-02 19:42:06 +03:00
To disable push notifications from { window . location . hostname . toString ( ) } access your browser
permissions for this site and turn off notifications .
< a href = "https://owncast.online/docs/notifications" > Learn more . < / a >
< / div >
) ;
2022-09-07 10:00:28 +03:00
export const BrowserNotifyModal = ( ) = > {
2022-05-30 07:52:38 +03:00
const [ error , setError ] = useState < string > ( null ) ;
const accessToken = useRecoilValue ( accessTokenAtom ) ;
const config = useRecoilValue ( clientConfigStateAtom ) ;
const [ browserPushPermissionsPending , setBrowserPushPermissionsPending ] =
useState < boolean > ( false ) ;
const notificationsPermitted =
2023-05-22 00:12:14 +03:00
arePushNotificationSupported ( ) && Notification . permission !== 'default' ;
2022-05-30 07:52:38 +03:00
const { notifications } = config ;
const { browser } = notifications ;
const { publicKey } = browser ;
2023-05-22 00:12:14 +03:00
const browserPushSupported =
browser . enabled && ( arePushNotificationSupported ( ) || isMobileSafariHomeScreenApp ( ) ) ;
2022-05-30 07:52:38 +03:00
2022-10-02 19:42:06 +03:00
// If notification permissions are granted, show user info how to disable them
2022-05-30 07:52:38 +03:00
if ( notificationsPermitted ) {
return < NotificationsEnabled / > ;
}
2023-05-22 00:12:14 +03:00
if ( isMobileSafariIos ( ) && ! isMobileSafariHomeScreenApp ( ) ) {
return < MobileSafariInstructions / > ;
}
2022-05-30 07:52:38 +03:00
const startBrowserPushRegistration = async ( ) = > {
2022-10-02 19:42:06 +03:00
// If notification permissions are already denied or granted, don't do anything.
2023-05-22 00:12:14 +03:00
if ( arePushNotificationSupported ( ) && Notification . permission !== 'default' ) {
2022-05-30 07:52:38 +03:00
return ;
}
setBrowserPushPermissionsPending ( true ) ;
try {
const subscription = await registerWebPushNotifications ( publicKey ) ;
saveNotificationRegistration ( 'BROWSER_PUSH_NOTIFICATION' , subscription , accessToken ) ;
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 ) ;
} ;
2023-04-16 06:10:34 +03:00
if ( window . location . hostname === 'localhost' ) {
return < NotificationsNotSupportedLocal / > ;
}
2022-05-30 07:52:38 +03:00
if ( ! browserPushSupported ) {
return < NotificationsNotSupported / > ;
}
return (
2023-03-13 09:05:21 +03:00
< ErrorBoundary
// eslint-disable-next-line react/no-unstable-nested-components
2023-03-13 09:12:39 +03:00
fallbackRender = { ( { error : e , resetErrorBoundary } ) = > (
2023-03-13 09:05:21 +03:00
< ComponentError
componentName = "BrowserNotifyModal"
2023-03-13 09:12:39 +03:00
message = { e . message }
2023-03-13 09:05:21 +03:00
retryFunction = { resetErrorBoundary }
/ >
) }
>
< Spin spinning = { browserPushPermissionsPending } >
< Row className = { styles . description } >
Get notified right in the browser each time this stream goes live .
< a href = "https://owncast.online/docs/notifications/#browser-notifications" > Learn more < / a >
& nbsp ; about Owncast browser notifications .
< / Row >
< Row > { error } < / Row >
< PermissionPopupPreview start = { ( ) = > startBrowserPushRegistration ( ) } / >
< / Spin >
< / ErrorBoundary >
2022-05-30 07:52:38 +03:00
) ;
2022-09-07 10:00:28 +03:00
} ;