import { Injectable, OnDestroy } from '@angular/core'; import { Dispatch } from '@ngxs-labs/dispatch-decorator'; import { merge, Observable, Subject, timer, interval } from 'rxjs'; import { Select } from '@ngxs/store'; import { first, switchMap, takeUntil, takeWhile } from 'rxjs/operators'; import { Effect } from 'ngxs-effects'; import { DevicePosControllerService } from '@app/api/services/device-pos-controller.service'; import { CheckIsReadyRequested, IsReadyCheckedSuccessfully } from '../device-qr-code.actions'; import { DeviceEnrolmentState } from '@app/device-enrolment/store/device-enrolment/device-enrolment.state'; import { Imei, PreCheckStatus } from '@app/device-enrolment/types'; import { REQUEST_POLLING_INTERVAL, REQUEST_POLLING_TIMEOUT, REQUEST_POLLING_TIMELIMIT } from './constants'; import { DevicePOSCreatedErrorOccurred } from '@app/device-enrolment/store/device-enrolment/device-enrolment.actions'; import { ProvisioningType, PreCheckDeviceStatus } from '@app/device-enrolment/constants'; import { PreCheckStatusRequested } from '../../index'; @Injectable() export class IsReadyEffectsService implements OnDestroy { @Select(DeviceEnrolmentState.imei) imei$!: Observable; @Select(DeviceEnrolmentState.preCheckStatus) preCheckStatus$!: Observable; private provisioningType: ProvisioningType; private isPOSerror$: Subject = new Subject(); private isTimedOut: boolean = false; constructor(private devicePOSControllerService: DevicePosControllerService) {} ngOnDestroy() { this.isPOSerror$.complete(); } @Dispatch() isReadyCheckedSuccessfully(isReady: boolean): IsReadyCheckedSuccessfully { return new IsReadyCheckedSuccessfully(isReady); } @Dispatch() preCheckStatusRequested(imei: Imei) { return new PreCheckStatusRequested(imei); } @Effect(DevicePOSCreatedErrorOccurred) setPosErrorEffect(): void { this.isPOSerror$.next(true); } @Effect(CheckIsReadyRequested) checkIsReadyRequestedEffect(): void { const stopPollingTimeLimit$ = timer(REQUEST_POLLING_TIMEOUT); const requestResult$ = new Subject(); const stopStream$ = merge( this.isPOSerror$, stopPollingTimeLimit$, requestResult$.pipe(first(isReady => isReady === true)) ); let isReadyCheckedSuccessfully = false; this.preCheckStatus$.subscribe(preCheckStatus => { this.provisioningType = preCheckStatus?.tac?.provisioningType as ProvisioningType; }); setTimeout(() => this.isTimedOut = true, REQUEST_POLLING_TIMELIMIT); this.imei$ .pipe(takeUntil(stopStream$)) .pipe( switchMap((imei: string) => timer(0, REQUEST_POLLING_INTERVAL) .pipe(takeUntil(stopStream$)) .pipe(switchMap(_ => this.devicePOSControllerService.isReady$Response({ imei }))) ) ) .subscribe( isReady => { const isReadyResult = Boolean(isReady.body?.ready) || this.provisioningType === ProvisioningType.PAY_TRIGGER || this.isTimedOut; // PAYTRIGGER device is considered registered even if "ready" is false if (isReadyResult) { isReadyCheckedSuccessfully = true; this.isReadyCheckedSuccessfully(true); } requestResult$.next(isReadyResult); }, () => {}, () => { this.isPOSerror$.next(false); if (!isReadyCheckedSuccessfully) { this.isReadyCheckedSuccessfully(false); } } ); } }