import { As, Modal, ModalContent, ModalContentProps, ModalOverlay, ModalProps, useDisclosure } from '@chakra-ui/react' import {PageProps} from 'gatsby' import * as React from 'react' import {IJaenConnection, RequireAtLeastOne} from '../../../../types' import {useAppDispatch} from '../../redux' import {internalActions} from '../../redux/slices' import {INotification} from '../../types' export type NotificationOptions = { displayName: string description: string modalProps?: Omit modalContentProps?: ModalContentProps conditions: RequireAtLeastOne<{ entireSite: boolean templates: string[] urlPatterns: string[] }> triggers: RequireAtLeastOne<{ onPageLoad: number onPageScroll: { percentage: number direction: 'up' | 'down' } }> advanced?: Partial<{ showAfterXPageViews: number showUntilXPageViews: number }> logo?: As customCondition?: (props: PageProps) => boolean customTrigger?: () => Promise } export const NotificationContext = React.createContext< {id: string; notification?: INotification} | undefined >(undefined) export const useNotificationContext = () => { const context = React.useContext(NotificationContext) if (context === undefined) { throw new Error( `useNotificationContext must be used within a NotificationProvider` ) } return context } export interface NotificationProviderProps extends NotificationOptions { id: string notification?: INotification forceOpen?: boolean onClose?: () => void } export const NotificationProvider: React.FC< React.PropsWithChildren< NotificationProviderProps & { editable?: boolean } > > = ({ id, notification, children, modalProps, modalContentProps, triggers, customTrigger, advanced, forceOpen, onClose: onCloseProp, editable = false }) => { const dispatch = useAppDispatch() const {isOpen, onClose, onOpen} = useDisclosure({ defaultIsOpen: false, isOpen: forceOpen }) React.useEffect(() => { if (editable) { dispatch(internalActions.setEditing(true)) return () => { dispatch(internalActions.setEditing(false)) } } }, [dispatch, editable]) const handleClose = React.useCallback(() => { onCloseProp?.() onClose() }, [onCloseProp, onClose]) React.useEffect(() => { customTrigger && customTrigger().then(shouldOpen => { if (shouldOpen) { onOpen() } }) }, [isOpen]) React.useEffect(() => { if (triggers) { if (triggers.onPageLoad) { // wait onPageLoad seconds before opening setTimeout(() => { onOpen() }, triggers.onPageLoad * 1000) } if (triggers.onPageScroll) { const {percentage, direction} = triggers.onPageScroll const handleScroll = () => { const scrollPercentage = window.pageYOffset / (document.body.offsetHeight - window.innerHeight) if ( (direction === 'up' && scrollPercentage < percentage) || (direction === 'down' && scrollPercentage > percentage) ) { onOpen() window.removeEventListener('scroll', handleScroll) } } window.addEventListener('scroll', handleScroll) return () => window.removeEventListener('scroll', handleScroll) } } }, []) React.useEffect(() => { if (advanced) { if (advanced.showAfterXPageViews || advanced.showUntilXPageViews) { const {showAfterXPageViews, showUntilXPageViews} = advanced if (showAfterXPageViews || showUntilXPageViews) { dispatch(internalActions.increaseAdvancedPageViews(id)) } } } }, [advanced]) return ( {children} ) } export const connectNotification = < P extends { id: string notification?: INotification forceOpen?: boolean onClose?: () => void } >( Component: React.ComponentType

, options: NotificationOptions ) => { const MyComp: IJaenConnection = props => { return ( ) } MyComp.options = options return MyComp } export type INotificationConnection = ReturnType // is notification a banner or a modal? // enable duration => set duration in interface // default enabled / disabled // extended usage => get access to the page props