import * as React from 'react' ; import { Logger } from 'polar-shared/src/logger/Logger' ; import { PersistenceLayerManager } from '../../../../web/js/datastore/PersistenceLayerManager' ; import { DefaultSplashEngine , SplashEngine , UserFacts } from './SplashEngine' ; import { Version } from 'polar-shared/src/util/Version' ; import { TimeDurations } from 'polar-shared/src/util/TimeDurations' ; import { NPSModal } from './nps/NPSModal' ; import { WhatsNewDialog } from './whats_new/WhatsNewDialog' ; import { SuggestionsModal } from './suggestions/SuggestionsModal' ; const log = Logger . create ( ) ; /**
 * This is a basic algorithm for displaying splashes which is designed to be
 * easy to manage / debug until we bring on something more sophisticated.
 *
 * This algorithm is generally very simple.
 *
 * - check if we have to display 'what's new' by seeing if the version number
 *   has incremented.
 *
 *    - if it has, display the what's new and have a timeout before we display
 *      the next message.
 *
 * - determine which additional splash to display:
 *
 *    - net-promoter-score must come first and we should only display it once
 *      per week
 *
 *    - Then, 24 hours later, should come a text prompt asking for the users
 *      feedback to improve polar.  Ask these separately spaced apart so we
 *      don't get latency.
 *
 *    - I think this should eventually be implemented via a more complex rules
 *      engine but these systems are complicated and might take 2-4 days to find
 *      one and implement that we actually like.
 *
 */ export class Splashes extends React . Component < IProps , IState > { constructor ( props , context ) { super ( props , context ) ; this . onWhatsNew = this . onWhatsNew . bind ( this ) ; this . onNetPromoter = this . onNetPromoter . bind ( this ) ; this . state = { splash : 'none' } ; this . init ( ) . catch ( err => log . error ( "Unable to init: " , err ) ) ; } public render ( ) { switch ( this . state . splash ) { case 'none' : return < div />; case 'net-promoter' : return < NPSModal />; case 'suggestions' : return < SuggestionsModal />; case 'whats-new' : return < WhatsNewDialog />; } } private onWhatsNew ( ) { this . setState ( { ... this . state , splash : 'whats-new' } ) ; } private onNetPromoter ( ) { this . setState ( { ... this . state , splash : 'net-promoter' } ) ; } private onSuggestions ( ) { this . setState ( { ... this . state , splash : 'suggestions' } ) ; } private async init ( ) { const userFacts = await this . computeUserFacts ( ) ; if ( userFacts ) { const splashEngine = new DefaultSplashEngine ( userFacts , { onWhatsNew : ( ) => this . onWhatsNew ( ) , onNetPromoter : ( ) => this . onNetPromoter ( ) , onSuggestions : ( ) => this . onSuggestions ( ) } ) ; this . doUpdate ( splashEngine ) ; } else { log . warn ( "Unable to run splash engine due to no user facts" ) ; } } private doUpdate ( splashEngine ) { try { splashEngine . run ( ) ; } finally { this . scheduleNextUpdate ( splashEngine ) ; } } private async computeUserFacts ( ) { const persistenceLayer = await this . props . persistenceLayerManager . getAsync ( ) ; const datastore = persistenceLayer . datastore ; const datastoreOverview = await datastore . overview ( ) ; if ( datastoreOverview ) { const userFacts = { datastoreCreated : datastoreOverview . created ! , version : Version . get ( ) } ; return userFacts ; } return undefined ; } private scheduleNextUpdate ( splashEngine ) { const delay = TimeDurations . toMillis ( '5m' ) ; setTimeout ( ( ) => { this . doUpdate ( splashEngine ) ; } , delay ) ; } } interface IProps { readonly persistenceLayerManager : PersistenceLayerManager ; } interface IState { readonly splash : SplashID ; } type SplashID = 'none' | 'net-promoter' | 'whats-new' | 'suggestions' ;