import { SQLiteDatabase } from '@ulangi/sqlite-adapter' ; import { Action , ActionType , createAction } from '@ulangi/ulangi-action' ; import { VocabularyStatus } from '@ulangi/ulangi-common/enums' ; import { CategorySuggestion } from '@ulangi/ulangi-common/interfaces' ; import { CategoryModel } from '@ulangi/ulangi-local-database' ; import { Task } from 'redux-saga' ; import { call , cancel , fork , put , take } from 'redux-saga/effects' ; import { PromiseType } from 'utility-types' ; import { errorConverter } from '../converters/ErrorConverter' ; import { SagaConfig } from '../interfaces/SagaConfig' ; import { SagaEnv } from '../interfaces/SagaEnv' ; import { ProtectedSaga } from './ProtectedSaga' ; export class CategorySaga extends ProtectedSaga { private fetchSuggestionsTask ? : Task ; private userDb : SQLiteDatabase ; private categoryModel : CategoryModel ; public constructor ( userDb , categoryModel ) { super ( ) ; this . userDb = userDb ; this . categoryModel = categoryModel ; } public * run ( _ , config ) { yield fork ( [ this , this . allowPrepareAndClearFetchSuggestions ] , config . category . fetchSuggestionsLimit ) ; } public * allowPrepareAndClearFetchSuggestions ( limit ) { this . fetchSuggestionsTask = yield fork ( [ this , this . allowPrepareFetchSuggestions ] , limit ) ; yield fork ( [ this , this . allowClearFetchSuggestions ] , limit ) ; } private * allowClearFetchSuggestions ( limit ) { while ( true ) { yield take ( ActionType . CATEGORY__CLEAR_FETCH_SUGGESTIONS ) ; if ( typeof this . fetchSuggestionsTask !== 'undefined' ) { yield cancel ( this . fetchSuggestionsTask ) ; } this . fetchSuggestionsTask = yield fork ( [ this , this . allowPrepareFetchSuggestions ] , limit ) ; } } private * allowPrepareFetchSuggestions ( limit ) { try { const action = yield take ( ActionType . CATEGORY__PREPARE_FETCH_SUGGESTIONS ) ; const { setId , term } = action . payload ; yield put ( createAction ( ActionType . CATEGORY__PREPARING_FETCH_SUGGESTIONS , null ) ) ; yield fork ( [ this , this . allowFetchSuggestions ] , setId , term , limit ) ; yield put ( createAction ( ActionType . CATEGORY__PREPARE_FETCH_SUGGESTIONS_SUCCEEDED , null ) ) ; } catch ( error ) { yield put ( createAction ( ActionType . CATEGORY__PREPARE_FETCH_SUGGESTIONS_FAILED , { errorCode : errorConverter . getErrorCode ( error ) , error , } ) ) ; } } private * allowFetchSuggestions ( setId , term , limit ) { let offset = 0 ; while ( true ) { yield take ( ActionType . CATEGORY__FETCH_SUGGESTIONS ) ; try { yield put ( createAction ( ActionType . CATEGORY__FETCHING_SUGGESTIONS , null ) ) ; const suggestions = [ ] ; if ( offset === 0 && term !== '' ) { const hasCategory = yield call ( [ this . categoryModel , 'hasCategory' ] , this . userDb , setId , VocabularyStatus . ACTIVE , term ) ; if ( hasCategory === false ) { suggestions . push ( { kind : 'new' , categoryName : term , } ) ; } } const result = yield call ( [ this . categoryModel , 'getCategoryNameSuggestions' ] , this . userDb , setId , term , limit , offset ) ; const { categoryNames } = result ; offset += limit ; const noMore = categoryNames . length === 0 ? true : false ; suggestions . push ( ... categoryNames . map ( ( categoryName ) : CategorySuggestion => { return { kind : 'existing' , categoryName , } ; } ) ) ; yield put ( createAction ( ActionType . CATEGORY__FETCH_SUGGESTIONS_SUCCEEDED , { suggestions , noMore , } ) ) ; } catch ( error ) { yield put ( createAction ( ActionType . CATEGORY__FETCH_SUGGESTIONS_FAILED , { errorCode : errorConverter . getErrorCode ( error ) , error , } ) ) ; } } } }