File

src/services/local-course.service.ts

Index

Methods

Methods

onConsentPopoverDismiss
onConsentPopoverDismiss()
Returns : void
onConsentPopoverShow
onConsentPopoverShow()
Returns : void
import { Injectable, Inject, NgZone } from '@angular/core';
import {
  Batch, Course, CourseService, EnrollCourseRequest,
  InteractType, SharedPreferences,
  FetchEnrolledCourseRequest, TelemetryObject, HttpClientError,
  NetworkError, GetContentStateRequest, ContentStateResponse
} from 'sunbird-sdk';
import { Observable } from 'rxjs';
import { AppGlobalService } from './app-global-service.service';
import { TelemetryGeneratorService } from './telemetry-generator.service';
import { Environment, InteractSubtype, PageId } from './telemetry-constants';
import { Map } from '@app/app/telemetryutil';
import { CommonUtilService } from './common-util.service';
import { EnrollCourse } from './../app/enrolled-course-details-page/course.interface';
import { map, catchError } from 'rxjs/operators';
import { PreferenceKey, EventTopics, RouterLinks, AssessmentConstant } from '@app/app/app.constant';
import { Events } from '@app/util/events';
import { AppVersion } from '@ionic-native/app-version/ngx';
import { ContentUtil } from '@app/util/content-util';
import { DatePipe, Location } from '@angular/common';
import { Router } from '@angular/router';
import { SbProgressLoader } from '@app/services/sb-progress-loader.service';
import { UserConsent } from '@project-sunbird/client-services/models';
import { CategoryKeyTranslator } from '@app/pipes/category-key-translator/category-key-translator-pipe';
import { ConsentService } from './consent-service';
import { FormAndFrameworkUtilService } from './formandframeworkutil.service';
import { FormConstants } from '@app/app/form.constants';

export interface ConsentPopoverActionsDelegate {
  onConsentPopoverShow(): void;
  onConsentPopoverDismiss(): void;
}


@Injectable()
export class LocalCourseService {
  private userId: string;
  private isConsentPopupDisplayed: boolean;

  constructor(
    @Inject('COURSE_SERVICE') private courseService: CourseService,
    @Inject('SHARED_PREFERENCES') private preferences: SharedPreferences,
    private appGlobalService: AppGlobalService,
    private telemetryGeneratorService: TelemetryGeneratorService,
    private commonUtilService: CommonUtilService,
    private events: Events,
    private zone: NgZone,
    private appVersion: AppVersion,
    private router: Router,
    private location: Location,
    private sbProgressLoader: SbProgressLoader,
    private datePipe: DatePipe,
    private categoryKeyTranslator: CategoryKeyTranslator,
    private consentService: ConsentService,
    public formAndFrameworkUtilService: FormAndFrameworkUtilService
  ) {
  }

  enrollIntoBatch(enrollCourse: EnrollCourse, consentPopoverActionsDelegate?: ConsentPopoverActionsDelegate, course?): Observable<any> {
    const enrollCourseRequest: EnrollCourseRequest = this.prepareEnrollCourseRequest(
      enrollCourse.userId, enrollCourse.batch, enrollCourse.courseId);
    return this.courseService.enrollCourse(enrollCourseRequest).pipe(
      map(async (data: boolean) => {
        if (data) {
          this.telemetryGeneratorService.generateInteractTelemetry(
            InteractType.OTHER,
            InteractSubtype.ENROLL_SUCCESS,
            Environment.HOME,
            enrollCourse.pageId, enrollCourse.telemetryObject,
            this.prepareRequestValue(enrollCourseRequest),
            enrollCourse.objRollup,
            enrollCourse.corRelationList
          );
          if (enrollCourse.userConsent === UserConsent.YES) {
            if (consentPopoverActionsDelegate) {
              consentPopoverActionsDelegate.onConsentPopoverShow();
            }
            await this.sbProgressLoader.hide({ id: 'login' });
            this.isConsentPopupDisplayed = true;
            if (!this.isMinor()) {
              await this.consentService.showConsentPopup(enrollCourse, undefined, course);
            }

            if (consentPopoverActionsDelegate) {
              consentPopoverActionsDelegate.onConsentPopoverDismiss();
              this.isConsentPopupDisplayed = false;
            }
          }
        } else {
          this.telemetryGeneratorService.generateInteractTelemetry(
            InteractType.OTHER,
            InteractSubtype.ENROLL_FAILED,
            Environment.HOME,
            enrollCourse.pageId, enrollCourse.telemetryObject,
            this.prepareRequestValue(enrollCourseRequest),
            enrollCourse.objRollup,
            enrollCourse.corRelationList
          );
        }
        return data;
      }),
      catchError(async (err) => {
        const requestValue = this.prepareRequestValue(enrollCourseRequest);
        if (NetworkError.isInstance(err)) {
          requestValue.error = err.code;
          this.commonUtilService.showToast(this.commonUtilService.translateMessage('ERROR_NO_INTERNET_MESSAGE'));
        } else if (HttpClientError.isInstance(err)) {
          if (err.response.body && err.response.body.params && err.response.body.params.status === 'USER_ALREADY_ENROLLED_COURSE') {
            requestValue.error = err.response.body.params.status;
            this.commonUtilService.showToast(this.commonUtilService.translateMessage('ALREADY_ENROLLED_COURSE'));
            if (enrollCourse.userConsent === UserConsent.YES) {
              await this.sbProgressLoader.hide({ id: 'login' });
              if (!this.isMinor()) {
                await this.consentService.getConsent(enrollCourse, undefined, course);
              }
            }
          } else {
            this.commonUtilService.showToast('ERROR_WHILE_ENROLLING_COURSE');
          }
        }
        this.telemetryGeneratorService.generateInteractTelemetry(
          InteractType.OTHER,
          InteractSubtype.ENROLL_FAILED,
          Environment.HOME,
          enrollCourse.pageId, enrollCourse.telemetryObject,
          requestValue,
          enrollCourse.objRollup,
          enrollCourse.corRelationList
        );
        throw err;
      })
    );
  }

  prepareEnrollCourseRequest(userId: string, batch: Batch | any, courseId?: string): EnrollCourseRequest {
    const enrollCourseRequest: EnrollCourseRequest = {
      batchId: batch.id,
      courseId: batch.courseId || courseId,
      userId,
      batchStatus: batch.status
    };
    return enrollCourseRequest;
  }

  prepareRequestValue(enrollCourseRequest): Map {
    const reqvalues = new Map();
    reqvalues['enrollReq'] = enrollCourseRequest;
    return reqvalues;
  }

  // This method is called when the user login immediately after pressing JOIN TRAINING from app-components
  // And after filling signinOnboarding completely from externalId service.
  async checkCourseRedirect() {
    const isLoggedInUser = this.appGlobalService.isUserLoggedIn();
    if (!this.appGlobalService.isSignInOnboardingCompleted && isLoggedInUser) {
      this.appGlobalService.isJoinTraningOnboardingFlow = true;
      return;
    }

    const batchDetails = await this.preferences.getString(PreferenceKey.BATCH_DETAIL_KEY).toPromise();
    const courseDetail = await this.preferences.getString(PreferenceKey.COURSE_DATA_KEY).toPromise();
    if (batchDetails && courseDetail) {
      this.userId = await this.appGlobalService.getActiveProfileUid();

      const batch = JSON.parse(batchDetails);
      const course = JSON.parse(courseDetail);
      if (course.createdBy !== this.userId && isLoggedInUser) {
        this.enrollBatchAfterlogin(batch, course);
      } else {
        this.events.publish(EventTopics.ENROL_COURSE_SUCCESS, {
          batchId: batch.id,
          courseId: batch.courseId
        });
        this.commonUtilService.showToast('FRMELEMNTS_MSG_ENROLLMENT_ERROR');
      }
      this.preferences.putString(PreferenceKey.BATCH_DETAIL_KEY, '').toPromise();
    }
  }

  private async enrollBatchAfterlogin(batch: Batch, course: any) {
    const enrollCourseRequest = this.prepareEnrollCourseRequest(this.userId, batch);
    const telemetryObject: TelemetryObject = ContentUtil.getTelemetryObject(course);
    const corRelationList = await this.preferences.getString(PreferenceKey.CDATA_KEY).toPromise();
    this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
      InteractSubtype.ENROLL_CLICKED,
      Environment.HOME,
      PageId.COURSE_BATCHES, telemetryObject,
      this.prepareRequestValue(enrollCourseRequest),
      ContentUtil.generateRollUp(undefined, telemetryObject.id),
      corRelationList ? JSON.parse(corRelationList) : []);

    const enrollCourse: EnrollCourse = {
      userId: this.userId,
      batch,
      pageId: PageId.COURSE_BATCHES,
      telemetryObject,
      objRollup: ContentUtil.generateRollUp(undefined, telemetryObject.id),
      corRelationList: corRelationList ? JSON.parse(corRelationList) : [],
      channel: course.channel,
      userConsent: course.userConsent
    };
    this.enrollIntoBatch(enrollCourse, undefined, course).toPromise()
      .then(() => {
        this.zone.run(async () => {
          this.commonUtilService.showToast(this.categoryKeyTranslator.transform('FRMELEMNTS_MSG_COURSE_ENROLLED', course));
          this.events.publish(EventTopics.ENROL_COURSE_SUCCESS, {
            batchId: batch.id,
            courseId: batch.courseId
          });
          const appLabel = await this.appVersion.getAppName();
          this.events.publish(EventTopics.COACH_MARK_SEEN, { showWalkthroughBackDrop: false, appName: appLabel });
          await this.preferences.putString(PreferenceKey.CDATA_KEY, '').toPromise();
          this.getEnrolledCourses();
          this.navigateTocourseDetails();
          await this.sbProgressLoader.hide({ id: 'login' });
        });
      }, (err) => {
        this.zone.run(async () => {
          await this.preferences.putString(PreferenceKey.CDATA_KEY, '').toPromise();
          if (NetworkError.isInstance(err)) {
            this.commonUtilService.showToast(this.commonUtilService.translateMessage('ERROR_NO_INTERNET_MESSAGE'));
            this.getEnrolledCourses();
          } else if (HttpClientError.isInstance(err)) {
            if (err.response.body && err.response.body.params && err.response.body.params.status === 'USER_ALREADY_ENROLLED_COURSE') {
              this.events.publish(EventTopics.ENROL_COURSE_SUCCESS, {
                batchId: batch.id,
                courseId: batch.courseId
              });
            } else {
              this.commonUtilService.showToast('ERROR_WHILE_ENROLLING_COURSE');
            }
          }
          this.navigateTocourseDetails();
          await this.sbProgressLoader.hide({ id: 'login' });
        });
      });
  }

  navigateTocourseDetails() {
    const routeUrl = this.router.url;
    if ((routeUrl.indexOf(RouterLinks.ENROLLED_COURSE_DETAILS) === -1) && (routeUrl.indexOf(RouterLinks.COURSE_BATCHES) !== -1)) {
      this.location.back();
    }
  }

  private async getEnrolledCourses(returnRefreshedCourses: boolean = false) {
    const option: FetchEnrolledCourseRequest = {
      userId: this.userId,
      returnFreshCourses: returnRefreshedCourses
    };
    this.courseService.getEnrolledCourses(option).toPromise()
      .then(async (enrolledCourses) => {
        if (enrolledCourses) {
          this.zone.run(() => {
            if (enrolledCourses.length > 0) {
              const courseList: Array<Course> = [];
              for (const course of enrolledCourses) {
                courseList.push(course);
              }
              this.appGlobalService.setEnrolledCourseList(courseList);
              this.preferences.putString(PreferenceKey.COURSE_DATA_KEY, '').toPromise();
            }
          });
        }
      }, async (err) => {
      });
  }

  async getCourseProgress(courseContext) {
    return new Promise(async (resolve, reject) => {
      const request: GetContentStateRequest = {
        userId: this.appGlobalService.getUserId(),
        courseId: courseContext.courseId,
        contentIds: courseContext.leafNodeIds,
        returnRefreshedContentStates: false,
        batchId: courseContext.batchId,
        fields: ['progress', 'score']
      };
      let progress = 0;
      try {
        const contentStatusData: ContentStateResponse = await this.courseService.getContentState(request).toPromise();
        if (contentStatusData && contentStatusData.contentList) {
          const viewedContents = [];
          for (const contentId of courseContext.leafNodeIds) {
            if (contentStatusData.contentList.find((c) => c.contentId === contentId && c.status === 2)) {
              viewedContents.push(contentId);
            }
          }
          progress = Math.round((viewedContents.length / courseContext.leafNodeIds.length) * 100);

        }
        resolve({ progress, contentStatusData });
      } catch (err) {
        resolve({ progress });
      }
    });
  }

  isEnrollable(batches, course) {
    if (!batches || !batches.length) {
      this.commonUtilService.showToast('NO_BATCHES_AVAILABLE');
      return false;
    }

    let latestBatch = batches[0];
    const showEnrollmentEndedMessage = () => {
      this.commonUtilService.showToast(
        'ENROLLMENT_ENDED_ON',
        null, null, null, null,
        this.datePipe.transform(latestBatch.enrollmentEndDate)
      );
    };
    const showFutureBatchMessage = () => {
      this.commonUtilService.showToast(
        this.categoryKeyTranslator.transform('FRMELEMNTS_MSG_BATCH_AVAILABILITY_DATE', course,
          { 'batch_start_date': this.datePipe.transform(latestBatch.startDate) }
        )
      );
    };
    for (let i = 0; i < batches.length; i++) {
      if (batches.length > 1 && !batches[i].enrollmentEndDate &&
        batches[i].startDate && (new Date(batches[i].startDate).setHours(0, 0, 0, 0) <= new Date().setHours(0, 0, 0, 0))) {
        return true;
      }
      if (batches[i].startDate &&
        (new Date(batches[i].startDate) > new Date(latestBatch.startDate))) {
        latestBatch = batches[i];
      }
    }
    // start date is not passed, then check show message
    // start date is passed, then check for enrollmentenddate
    // enrollmentenddate is passed then show message

    if (latestBatch.startDate && (new Date(latestBatch.startDate).setHours(0, 0, 0, 0) > new Date().setHours(0, 0, 0, 0))) {
      showFutureBatchMessage();
      return false;
    } else if (latestBatch.enrollmentEndDate &&
      (new Date(latestBatch.enrollmentEndDate).setHours(0, 0, 0, 0) < new Date().setHours(0, 0, 0, 0))) {
      showEnrollmentEndedMessage();
      return false;
    }
    return true;
  }

  fetchAssessmentStatus(contentStatusData, content) {
    let maxAttempts = (content?.contentData) ? content.contentData.maxAttempts : content.maxAttempts;
    if (!maxAttempts && content.mimeType !== 'application/vnd.sunbird.questionset') {
      maxAttempts = AssessmentConstant.MAX_ATTEMPTS;
    }
    const assesmentsStatus: { isLastAttempt: boolean, isContentDisabled: boolean, currentAttempt: number, maxAttempts: number } = {
      isLastAttempt: false,
      isContentDisabled: false,
      currentAttempt: 0,
      maxAttempts
    };
    if (contentStatusData && contentStatusData.contentList) {
      contentStatusData.contentList.forEach((item) => {
        if (item.contentId === content.identifier && item.score) {
          assesmentsStatus.currentAttempt = item.score.length;
          if (maxAttempts - item.score.length === 1) {
            assesmentsStatus.isLastAttempt = true;
          }
          if (maxAttempts <= item.score.length) {
            assesmentsStatus.isContentDisabled = true;
          }
        }
      });
    }
    return assesmentsStatus;
  }

  async getTimeRemaining(endDate) {
    const utilityConfigFields = await this.formAndFrameworkUtilService.getFormFields(FormConstants.UTILITY_CONFIG);
    const batchEnrollmentEndDateDisplayThreshold: number = Number(utilityConfigFields
        .find((config) => config.code === 'batchEndTimerConfig')['config']['batchEndDateTimer']);
    const today = window.dayjs();
    const enrollmentEndDate = (window.dayjs(endDate)).add(1, 'days');
    if (enrollmentEndDate.diff(today, 'day') > batchEnrollmentEndDateDisplayThreshold) {
      return undefined;
    }
    const countTimeOfEOD = new Date(endDate);
    countTimeOfEOD.setDate(countTimeOfEOD.getDate() + 1);
    if (today.diff(countTimeOfEOD) > 0) {
      return undefined;
    }
    const duration = window.dayjs.duration(enrollmentEndDate.diff(today));
    return duration.format('D [day(s)] H [h] m [m]');
  }

  isConsentPopupVisible(): boolean {
    return this.isConsentPopupDisplayed;
  }

  setConsentPopupVisibility(status: boolean) {
    this.isConsentPopupDisplayed = status;
  }

  private isMinor(): boolean {
    return this.appGlobalService.getCurrentUser().serverProfile.isMinor;
  }

}

results matching ""

    No results matching ""