import md5 from 'crypto-js/md5' ; import { groupBy , isNull , isUndefined } from 'lodash' ; import { NotificationsPrefs , PathTips , UserNotification } from '../types' ; import { PKG_DETAIL_PATH } from './data' ; import hasToBeDisplayedNewNotification from './hasToBeDisplayedNewNotification' ; const DEFAULT_START_TIME = 3 * 1000 ; const DEFAULT_DISMISS_TIME = 20 * 1000 ; export interface UserNotificationsUpdatesHandler { updateUserNotificationsWrapper ( notification ) : void ; } const getNotifications = ( ) : UserNotification [ ] => { const list = require ( './notifications.json' ) . notifications ; return list . map ( ( notif ) => { const notification = { ... notif , id : md5 ( notif . body ) . toString ( ) , } ; return notification ; } ) ; } ; const getCurrentLocationPath = ( location ? ) : PathTips | undefined => { const currentLocation = location || window . location . pathname ; if ( currentLocation . startsWith ( '/control-panel' ) ) { return PathTips . ControlPanel ; } else if ( PKG_DETAIL_PATH . test ( currentLocation ) ) { return PathTips . Package ; } else { switch ( currentLocation ) { case '/' : return PathTips . Home ; case '/packages/search' : return PathTips . Search ; default : return ; } } } ; export class UserNotificationsDispatcher { private updatesHandler ? : UserNotificationsUpdatesHandler ; private activeNotification : UserNotification | null = null ; private startTimeout ? : NodeJS . Timeout ; private dismissTimeout ? : NodeJS . Timeout ; private settings : NotificationsPrefs | null = null ; private notifications : UserNotification [ ] = getNotifications ( ) ; private breakpoint : string | undefined ; private locationPathTip : PathTips | undefined ; public start ( prefs , breakpoint ? ) { this . settings = prefs ; this . breakpoint = breakpoint ; this . startTimeout = setTimeout ( ( ) => { this . get ( true ) ; this . startTimeout = undefined ; } , DEFAULT_START_TIME ) ; } public get ( dateLimit ) { if ( isUndefined ( this . breakpoint ) || ! [ 'xs' , 'sm' ] . includes ( this . breakpoint ) ) { this . dismissNotification ( ) ; const notif = this . getRandomNotification ( dateLimit ) ; if ( ! isNull ( notif ) ) { this . postNotification ( notif ) ; } } } public subscribe ( updatesHandler ) { this . updatesHandler = updatesHandler ; } public postNotification ( notification ) { this . activeNotification = notification ; if ( this . updatesHandler ) { this . updatesHandler . updateUserNotificationsWrapper ( this . activeNotification ) ; } if ( ! isNull ( notification ) ) { this . dismissTimeout = setTimeout ( ( ) => { this . dismissNotification ( ) ; } , DEFAULT_DISMISS_TIME ) ; } else { this . cleanTimeouts ( ) ; } } public dismissNotification ( currentLocation ? ) { if ( this . activeNotification ) { this . postNotification ( null ) ; } if ( currentLocation ) { this . updateCurrentLocation ( currentLocation ) ; } } private cleanTimeouts ( ) { if ( this . startTimeout ) { clearTimeout ( this . startTimeout ) ; } if ( this . dismissTimeout ) { clearTimeout ( this . dismissTimeout ) ; } } public close ( ) { this . cleanTimeouts ( ) ; } public updateSettings ( settings ) { this . settings = settings ; } private updateCurrentLocation ( location ) { const currentLocationPathTip = getCurrentLocationPath ( location ) ; if ( ! isNull ( this . settings ) && currentLocationPathTip !== this . locationPathTip ) { this . locationPathTip = currentLocationPathTip ; if ( isUndefined ( this . startTimeout ) && hasToBeDisplayedNewNotification ( true , this . settings . lastDisplayedTime ) ) { this . get ( true ) ; } } } private getRandomNotification ( dateLimit ) { if ( ! isNull ( this . settings ) ) { if ( this . settings . enabled && this . settings . displayed . length < this . notifications . length && hasToBeDisplayedNewNotification ( dateLimit , this . settings . lastDisplayedTime ) ) { let notDisplayedNotifications = groupBy ( this . notifications . filter ( ( notif ) => ! this . settings ! . displayed . includes ( notif . id ) ) , 'linkTip' ) ; const currentLocationTip = this . locationPathTip || getCurrentLocationPath ( ) ; const getCommonTip = ( ) : UserNotification | null => { return notDisplayedNotifications . hasOwnProperty ( 'undefined' ) && notDisplayedNotifications . undefined . length > 0 ? ( notDisplayedNotifications . undefined [ Math . floor ( Math . random ( ) * notDisplayedNotifications . undefined . length ) ] as UserNotification ) : null ; } ; if ( currentLocationTip ) { if ( notDisplayedNotifications . hasOwnProperty ( currentLocationTip ) && notDisplayedNotifications [ currentLocationTip ] . length > 0 ) { return notDisplayedNotifications [ currentLocationTip ] [ Math . floor ( Math . random ( ) * notDisplayedNotifications [ currentLocationTip ] . length ) ] as UserNotification ; } else { return getCommonTip ( ) ; } } else { return getCommonTip ( ) ; } } } return null ; } } const notificationsDispatcher = new UserNotificationsDispatcher ( ) ; export default notificationsDispatcher ;