import { DOWNLOAD_STATUS , IApplication , modifyApplication , writeApplication , createReviewApplication } from '@client/applications' ; import { Action , IForm , IFormData } from '@client/forms' ; import { AppStore } from '@client/store' ; import { client } from '@client/utils/apolloClient' ; import * as Sentry from '@sentry/browser' ; import ApolloClient , { ApolloError } from 'apollo-client' ; import { getRegisterForm } from './forms/register/application-selectors' ; import { gqlToDraftTransformer } from './transformer' ; import { getQueryMapping } from './views/DataProvider/QueryProvider' ; import { RequestHandler } from 'mock-apollo-client' ; import { DocumentNode } from 'apollo-link' ; const INTERVAL_TIME = 5000 ; const MAX_RETRY_ATTEMPT = 3 ; const ALLOWED_STATUS_FOR_RETRY = [ DOWNLOAD_STATUS . READY_TO_DOWNLOAD . toString ( ) ] ; interface IActionList { [ key ] : string ; } const ACTION_LIST = { [ Action . LOAD_REVIEW_APPLICATION ] : Action . LOAD_REVIEW_APPLICATION , [ Action . LOAD_CERTIFICATE_APPLICATION ] : Action . LOAD_CERTIFICATE_APPLICATION } ; const REQUEST_IN_PROGRESS_STATUS = { [ Action . LOAD_REVIEW_APPLICATION ] : DOWNLOAD_STATUS . DOWNLOADING , [ Action . LOAD_CERTIFICATE_APPLICATION ] : DOWNLOAD_STATUS . DOWNLOADING } ; const SUCCESS_DOWNLOAD_STATUS = { [ Action . LOAD_REVIEW_APPLICATION ] : DOWNLOAD_STATUS . DOWNLOADED , [ Action . LOAD_CERTIFICATE_APPLICATION ] : DOWNLOAD_STATUS . DOWNLOADED } ; export class InboxController { private store : AppStore ; public client : ApolloClient < { } > & { setRequestHandler : ( query : DocumentNode , handler : RequestHandler ) => void ; } ; public syncRunning = false ; constructor ( store ) { this . store = store ; this . client = client ; } public start = ( ) => { setInterval ( ( ) => { this . sync ( ) ; } , INTERVAL_TIME ) ; } ; private getApplications = ( ) => this . store . getState ( ) . applicationsState . applications || [ ] ; private getDownloadableApplications = ( ) => { return this . getApplications ( ) . filter ( ( app ) => app . downloadStatus && ALLOWED_STATUS_FOR_RETRY . includes ( app . downloadStatus ) ) ; } ; public sync = async ( ) => { if ( this . syncRunning ) { return ; } this . syncRunning = true ; const applications = this . getDownloadableApplications ( ) ; for ( const application of applications ) { await this . queryData ( application ) ; } this . syncRunning = false ; } ; public queryData = async ( application ) => { if ( ! application ) { return ; } const applicationAction = ACTION_LIST [ application . action as string ] || null ; const forms = getRegisterForm ( this . store . getState ( ) ) ; const result = getQueryMapping ( application . event , applicationAction ) ; const { query , dataKey } = result || { query : null , dataKey : null } ; const requestInProgressStatus = REQUEST_IN_PROGRESS_STATUS [ application . action as string ] || DOWNLOAD_STATUS . DOWNLOADING ; application . downloadStatus = requestInProgressStatus ; this . store . dispatch ( modifyApplication ( application ) ) ; this . store . dispatch ( writeApplication ( application ) ) ; if ( query ) { try { const queryResult = await this . client . query ( { query , variables : { id : application . id } } ) ; this . onSuccess ( application , forms [ application . event ] , queryResult . data [ dataKey as string ] ) ; } catch ( exception ) { this . onError ( application , exception ) ; } } } ; private onSuccess = ( application , form , result ) => { const transData = gqlToDraftTransformer ( form , result ) ; const app = createReviewApplication ( application . id , transData , application . event ) ; app . downloadStatus = SUCCESS_DOWNLOAD_STATUS [ application . action as string ] || DOWNLOAD_STATUS . DOWNLOADED ; this . store . dispatch ( modifyApplication ( app ) ) ; this . store . dispatch ( writeApplication ( app ) ) ; } ; private onError = ( application , error ) => { application . downloadRetryAttempt = ( application . downloadRetryAttempt || 0 ) + 1 ; if ( application . downloadRetryAttempt < MAX_RETRY_ATTEMPT ) { application . downloadStatus = DOWNLOAD_STATUS . READY_TO_DOWNLOAD ; this . store . dispatch ( modifyApplication ( application ) ) ; this . store . dispatch ( writeApplication ( application ) ) ; return ; } let status ; if ( error . networkError ) { status = DOWNLOAD_STATUS . FAILED_NETWORK ; } else { status = DOWNLOAD_STATUS . FAILED ; Sentry . captureException ( error ) ; } application . downloadStatus = status ; this . store . dispatch ( modifyApplication ( application ) ) ; this . store . dispatch ( writeApplication ( application ) ) ; } ; }