import { assertExists } from '@ulangi/assert' ; import { SQLiteDatabase , Transaction } from '@ulangi/sqlite-adapter' ; import { ActionType , createAction } from '@ulangi/ulangi-action' ; import { UploadLessonResultsRequest } from '@ulangi/ulangi-common/interfaces' ; import { UploadLessonResultsResponseResolver } from '@ulangi/ulangi-common/resolvers' ; import { DatabaseEvent , DatabaseEventBus , LessonResultModel , SessionModel , } from '@ulangi/ulangi-local-database' ; import axios , { AxiosResponse } from 'axios' ; import { EventChannel } from 'redux-saga' ; import { call , cancelled , fork , put , take } from 'redux-saga/effects' ; import { PromiseType } from 'utility-types' ; import { DatabaseEventChannel } from '../channels/DatabaseEventChannel' ; import { errorConverter } from '../converters/ErrorConverter' ; import { SagaEnv } from '../interfaces/SagaEnv' ; import { createRequest } from '../utils/createRequest' ; import { ProtectedSaga } from './ProtectedSaga' ; export class LessonResultSaga extends ProtectedSaga { private uploadLessonResultsResponseResolver = new UploadLessonResultsResponseResolver ( ) ; private userDb : SQLiteDatabase ; private sharedDb : SQLiteDatabase ; private sessionModel : SessionModel ; private lessonResultModel : LessonResultModel ; private databaseEventBus : DatabaseEventBus ; public constructor ( userDb , sharedDb , sessionModel , lessonResultModel , databaseEventBus ) { super ( ) ; this . userDb = userDb ; this . sharedDb = sharedDb ; this . sessionModel = sessionModel ; this . lessonResultModel = lessonResultModel ; this . databaseEventBus = databaseEventBus ; } public * run ( env ) { yield fork ( [ this , this . autoUploadLessonResults ] ) ; yield fork ( [ this , this . allowUploadLessonResults ] , env . API_URL ) ; } public * autoUploadLessonResults ( ) { let channel ! ; try { channel = new DatabaseEventChannel ( this . databaseEventBus ) . createChannel ( ) ; while ( true ) { const eventName = yield take ( channel ) ; if ( eventName === DatabaseEvent . LESSON_RESULT_INSERTED ) { yield put ( createAction ( ActionType . LESSON_RESULTS__UPLOAD , null ) ) ; } } } finally { if ( yield cancelled ( ) && typeof channel !== 'undefined' ) { channel . close ( ) ; console . log ( 'Local update event channel closed.' ) ; } } } private * allowUploadLessonResults ( apiUrl ) { while ( true ) { try { yield take ( ActionType . LESSON_RESULTS__UPLOAD ) ; const accessToken = yield call ( [ this . sessionModel , 'getAccessToken' ] , this . sharedDb ) ; let done = false ; while ( done === false ) { const lessonResults = yield call ( [ this . lessonResultModel , 'getLessonResults' ] , this . userDb , 30 , true ) ; if ( lessonResults . length > 0 ) { yield put ( createAction ( ActionType . LESSON_RESULTS__UPLOADING , { lessonResults , } ) ) ; const response = yield call ( [ axios , 'request' ] , createRequest < UploadLessonResultsRequest > ( 'post' , apiUrl , '/upload-lesson-results' , null , { lessonResults , } , { accessToken : assertExists ( accessToken ) } ) ) ; const { acknowledged , } = this . uploadLessonResultsResponseResolver . resolve ( response . data , true ) ; yield call ( [ this . userDb , 'transaction' ] , ( tx ) : void => { this . lessonResultModel . deleteLessonResults ( tx , acknowledged ) ; } ) ; } else { done = true ; } } yield put ( createAction ( ActionType . LESSON_RESULTS__UPLOAD_SUCCEEDED , null ) ) ; } catch ( error ) { yield put ( createAction ( ActionType . LESSON_RESULTS__UPLOAD_FAILED , { errorCode : errorConverter . getErrorCode ( error ) , error , } ) ) ; } } } }