File

src/services/sunbird-splashscreen/splaschreen-deeplink-action-handler-delegate.ts

Index

Properties
Methods
Accessors

Constructor

constructor(contentService: ContentService, preferences: SharedPreferences, authService: AuthService, profileService: ProfileService, pageAssembleService: PageAssembleService, frameworkService: FrameworkService, frameworkUtilService: FrameworkUtilService, telemetryService: TelemetryService, storageService: StorageService, courseService: CourseService, telemetryGeneratorService: TelemetryGeneratorService, commonUtilService: CommonUtilService, appGlobalServices: AppGlobalService, events: Events, router: Router, appVersion: AppVersion, utilityService: UtilityService, loginNavigationHandlerService: LoginNavigationHandlerService, translateService: TranslateService, qrScannerResultHandler: QRScannerResultHandler, sbProgressLoader: SbProgressLoader, location: Location, navService: NavigationService, contentPlayerHandler: ContentPlayerHandler, formnFrameworkUtilService: FormAndFrameworkUtilService, updateProfileService: UpdateProfileService, platform: Platform)
Parameters :
Name Type Optional
contentService ContentService No
preferences SharedPreferences No
authService AuthService No
profileService ProfileService No
pageAssembleService PageAssembleService No
frameworkService FrameworkService No
frameworkUtilService FrameworkUtilService No
telemetryService TelemetryService No
storageService StorageService No
courseService CourseService No
telemetryGeneratorService TelemetryGeneratorService No
commonUtilService CommonUtilService No
appGlobalServices AppGlobalService No
events Events No
router Router No
appVersion AppVersion No
utilityService UtilityService No
loginNavigationHandlerService LoginNavigationHandlerService No
translateService TranslateService No
qrScannerResultHandler QRScannerResultHandler No
sbProgressLoader SbProgressLoader No
location Location No
navService NavigationService No
contentPlayerHandler ContentPlayerHandler No
formnFrameworkUtilService FormAndFrameworkUtilService No
updateProfileService UpdateProfileService No
platform Platform No

Methods

checkUtmContent
checkUtmContent(utmVal: string)
Parameters :
Name Type Optional
utmVal string No
Returns : void
Private closeProgressLoader
closeProgressLoader()
Returns : void
eventToSetDefaultOnboardingData
eventToSetDefaultOnboardingData()
Returns : void
Private generateProgressLoaderContext
generateProgressLoaderContext(url, identifier, dialCode)
Parameters :
Name Optional
url No
identifier No
dialCode No
Private generateUtmTelemetryEvent
generateUtmTelemetryEvent(identifier, dialCode, url)
Parameters :
Name Optional
identifier No
dialCode No
url No
Returns : {}
Async getChildContent
getChildContent(content, childContentId)
Parameters :
Name Optional
content No
childContentId No
Returns : unknown
Async getChildContents
getChildContents(identifier)
Parameters :
Name Optional
identifier No
Returns : unknown
Private getContentData
getContentData(contentId)
Parameters :
Name Optional
contentId No
Returns : Promise<Content | null>
Async getContentHeirarchy
getContentHeirarchy(identifier: string)
Parameters :
Name Type Optional
identifier string No
Returns : unknown
Private getCorrelationList
getCorrelationList(payloadUrl, corRelation?: Array)
Parameters :
Name Type Optional
payloadUrl No
corRelation Array<CorrelationData> Yes
Returns : Array<CorrelationData>
Private getCustomFilterValues
getCustomFilterValues(deeplinkParams, values, attribute)
Parameters :
Name Optional
deeplinkParams No
values No
attribute No
Returns : {}
Private getDefaultFilter
getDefaultFilter(deeplinkParams)
Parameters :
Name Optional
deeplinkParams No
Returns : any
Private getImportContentRequestBody
getImportContentRequestBody(identifiers: Array, isChild: boolean)
Parameters :
Name Type Optional
identifiers Array<string> No
isChild boolean No
Returns : Array<ContentImport>
Private getQueryParamValue
getQueryParamValue(payloadUrl: string, queryParam: string)
Parameters :
Name Type Optional
payloadUrl string No
queryParam string No
Returns : string
Private getRequest
getRequest(payloadUrl: string, matchedDeeplinkConfig, attributeList)
Parameters :
Name Type Optional
payloadUrl string No
matchedDeeplinkConfig No
attributeList No
Returns : { query?: string; filters?: {}; }
Private getRouterPath
getRouterPath(content)
Parameters :
Name Optional
content No
Returns : any
Private Async handleDeeplink
handleDeeplink(payloadUrl: string)
Parameters :
Name Type Optional
payloadUrl string No
Returns : any
Private Async handleNavigation
handleNavigation(payloadUrl, identifier, dialCode, matchedDeeplinkConfig, attributeList, urlMatchGroup)
Parameters :
Name Optional
payloadUrl No
identifier No
dialCode No
matchedDeeplinkConfig No
attributeList No
urlMatchGroup No
Returns : any
Private Async handleSearch
handleSearch(payload)
Parameters :
Name Optional
payload No
Returns : any
Async handleVendorAppAction
handleVendorAppAction(payload, banner?)
Parameters :
Name Optional
payload No
banner Yes
Returns : unknown
Private importContent
importContent(identifiers: Array, isChild: boolean)
Parameters :
Name Type Optional
identifiers Array<string> No
isChild boolean No
Returns : void
Private Async isAppCompatible
isAppCompatible(requiredVersionCode)
Parameters :
Name Optional
requiredVersionCode No
Returns : unknown
Private limitedSharingContentLinkClickedTelemery
limitedSharingContentLinkClickedTelemery()
Returns : void
Async navigateContent
navigateContent(identifier, isFromLink, content?: Content | null, payloadUrl?: string, route?: string, coreRelationList?: Array)
Parameters :
Name Type Optional Default value
identifier No
isFromLink No false
content Content | null Yes
payloadUrl string Yes
route string Yes
coreRelationList Array<CorrelationData> Yes
Returns : any
Private Async navigateQuizContent
navigateQuizContent(identifier, content, isFromLink, payloadUrl, corRelationList)
Parameters :
Name Optional
identifier No
content No
isFromLink No
payloadUrl No
corRelationList No
Returns : any
Async navigateToCollection
navigateToCollection(identifier, content: Content | null, payloadUrl: string, route?: string, isOnboardingSkipped, isFromChannelDeeplink, corRelationList?: Array)
Parameters :
Name Type Optional Default value
identifier No
content Content | null No
payloadUrl string No
route string Yes
isOnboardingSkipped No false
isFromChannelDeeplink No false
corRelationList Array<CorrelationData> Yes
Returns : any
Private Async navigateToDetailsPage
navigateToDetailsPage(payload)
Parameters :
Name Optional
payload No
Returns : any
onAction
onAction(payload: any, context?)
Parameters :
Name Type Optional
payload any No
context Yes
Returns : Observable<undefined>
Private Async setAppLanguage
setAppLanguage(langCode: string)
Parameters :
Name Type Optional
langCode string No
Returns : any
Private Async setOnboradingData
setOnboradingData(payloadUrl)
Parameters :
Name Optional
payloadUrl No
Returns : any
Private Async setProfileData
setProfileData(channelId: string, payloadUrl)
Parameters :
Name Type Optional
channelId string No
payloadUrl No
Returns : any
Private setTabsRoot
setTabsRoot()
Returns : void
Private Async setUserType
setUserType(userType)
Parameters :
Name Optional
userType No
Returns : any
Private Async updateProfile
updateProfile(payloadProfileAttribute)
Parameters :
Name Optional
payloadProfileAttribute No
Returns : any
Private Async upgradeAppPopover
upgradeAppPopover(requiredVersionCode)
Parameters :
Name Optional
requiredVersionCode No
Returns : any
Private validateDeeplinkPriority
validateDeeplinkPriority(matchedDeeplinkConfig, config)
Parameters :
Name Optional
matchedDeeplinkConfig No
config No
Returns : any

Properties

Private _context
Type : any
Public authService
Type : AuthService
Decorators :
@Inject('AUTH_SERVICE')
Private childContent
Private currentAppVersionCode
Type : number
Private enableRootNavigation
Default value : false
Private isChildContentFound
Private isOnboardingCompleted
Default value : false
Private progressLoaderId
Type : string
Private savedPayloadUrl
Type : any
Public translateService
Type : TranslateService

Accessors

isDelegateReady
setisDelegateReady(val: boolean)
Parameters :
Name Type Optional
val boolean No
Returns : void
context
getcontext()
setcontext(context)
Parameters :
Name Optional
context No
Returns : void
import {
  ContentFilterConfig,
  PreferenceKey,
  ProfileConstants,
  appLanguages,
  ProgressPopupContext,
  IgnoreTelemetryPatters
} from '@app/app/app.constant';
import { Inject, Injectable } from '@angular/core';
import { Router, NavigationExtras } from '@angular/router';
import { Events } from '@app/util/events';
import { Observable, of } from 'rxjs';
import {
  PageAssembleService,
  FrameworkService,
  ContentService,
  SharedPreferences,
  HttpServerError,
  NetworkError,
  AuthService, ProfileType, Content,
  ProfileService, Channel,
  GetFrameworkCategoryTermsRequest,
  CachedItemRequestSourceFrom,
  FrameworkCategoryCode,
  FrameworkUtilService,
  Profile,
  FrameworkCategoryCodesGroup,
  ProfileSource,
  CorrelationData,
  TelemetryObject,
  TelemetryService,
  ContentDetailRequest,
  ChildContentRequest,
  ContentImportRequest,
  StorageService,
  ContentImport,
  Rollup,
  FetchEnrolledCourseRequest,
  CourseService
} from 'sunbird-sdk';
import { SplashscreenActionHandlerDelegate } from './splashscreen-action-handler-delegate';
import { MimeType, EventTopics, RouterLinks, LaunchType } from '../../app/app.constant';
import { AppGlobalService } from '../app-global-service.service';
import { TelemetryGeneratorService } from '@app/services/telemetry-generator.service';
import { CommonUtilService } from '@app/services/common-util.service';
import { PageId, InteractType, Environment, ID, CorReleationDataType } from '../telemetry-constants';
import { AppVersion } from '@ionic-native/app-version/ngx';
import { UtilityService } from '../utility-service';
import { TranslateService } from '@ngx-translate/core';
import { QRScannerResultHandler } from '../qrscanresulthandler.service';
import { ContentUtil } from '@app/util/content-util';
import * as qs from 'qs';
import { SbProgressLoader, Context as SbProgressLoaderContext } from '../sb-progress-loader.service';
import { Location } from '@angular/common';
import { NavigationService } from '../navigation-handler.service';
import { CsPrimaryCategory } from '@project-sunbird/client-services/services/content';
import { ContentInfo } from '../content/content-info';
import { ContentPlayerHandler } from '../content/player/content-player-handler';
import { FormAndFrameworkUtilService } from '../formandframeworkutil.service';
import { FormConstants } from '@app/app/form.constants';
import {UpdateProfileService} from '@app/services/update-profile-service';
import {LoginNavigationHandlerService} from '@app/services/login-navigation-handler.service';
import { Platform } from '@ionic/angular';

@Injectable()
export class SplaschreenDeeplinkActionHandlerDelegate implements SplashscreenActionHandlerDelegate {
  private savedPayloadUrl: any;

  private isOnboardingCompleted = false;
  private currentAppVersionCode: number;
  private progressLoaderId: string;
  private childContent;
  private isChildContentFound;
  private enableRootNavigation = false;
  private _context: any;

  // should delay the deeplinks until tabs is loaded- gets triggered from Resource components
  set isDelegateReady(val: boolean) {
    if (val && this.savedPayloadUrl) {
      this.handleDeeplink(this.savedPayloadUrl);
      this.savedPayloadUrl = null;
    }
  }

  constructor(
    @Inject('CONTENT_SERVICE') private contentService: ContentService,
    @Inject('SHARED_PREFERENCES') private preferences: SharedPreferences,
    @Inject('AUTH_SERVICE') public authService: AuthService,
    @Inject('PROFILE_SERVICE') private profileService: ProfileService,
    @Inject('PAGE_ASSEMBLE_SERVICE') private pageAssembleService: PageAssembleService,
    @Inject('FRAMEWORK_SERVICE') private frameworkService: FrameworkService,
    @Inject('FRAMEWORK_UTIL_SERVICE') private frameworkUtilService: FrameworkUtilService,
    @Inject('TELEMETRY_SERVICE') private telemetryService: TelemetryService,
    @Inject('STORAGE_SERVICE') private storageService: StorageService,
    @Inject('COURSE_SERVICE') private courseService: CourseService,
    private telemetryGeneratorService: TelemetryGeneratorService,
    private commonUtilService: CommonUtilService,
    private appGlobalServices: AppGlobalService,
    private events: Events,
    private router: Router,
    private appVersion: AppVersion,
    private utilityService: UtilityService,
    private loginNavigationHandlerService: LoginNavigationHandlerService,
    public translateService: TranslateService,
    private qrScannerResultHandler: QRScannerResultHandler,
    private sbProgressLoader: SbProgressLoader,
    private location: Location,
    private navService: NavigationService,
    private contentPlayerHandler: ContentPlayerHandler,
    private formnFrameworkUtilService: FormAndFrameworkUtilService,
    private updateProfileService: UpdateProfileService,
    private platform: Platform
  ) {
    this.eventToSetDefaultOnboardingData();
  }

  set context(context) {
    this._context = context;
  }

  get context() {
    return this._context;
  }

  onAction(payload: any, context?): Observable<undefined> {
    if (context) {
      this.context = context;
    }
    if (payload && payload.url) {
      this.handleDeeplink(payload.url);
    } else if (payload && payload.action) {
      this.handleVendorAppAction(payload);
    }
    return of(undefined);
  }

  // This method is called only when the user redirects directly from the Playstore
  checkUtmContent(utmVal: string): void {
    const utmRegex = new RegExp(String.raw`(?:utm_content=(?<utm_content>[^&]*))`);
    const res = utmRegex.exec(utmVal);
    if (res && res.groups && res.groups.utm_content && res.groups.utm_content.length) {
      const payload = { url: res.groups.utm_content };
      this.onAction(payload);
    }
  }

  private async handleDeeplink(payloadUrl: string) {
    const dialCode = await this.qrScannerResultHandler.parseDialCode(payloadUrl);


    // Assumptions priority cannot have value as 0 and two simiar urls should not have same priority level;

    const deepLinkUrlConfig: { name: string, code: string, pattern: string, route: string, priority?: number, params?: {} }[] =
        await this.formnFrameworkUtilService.getFormFields(FormConstants.DEEPLINK_CONFIG);
  
    let matchedDeeplinkConfig: { name: string, code: string, pattern: string, route: string, priority?: number } = null;
    let urlMatch;

    deepLinkUrlConfig.forEach(config => {
      const urlRegexMatch = payloadUrl.match(new RegExp(config.pattern));
      if (!!urlRegexMatch && (!matchedDeeplinkConfig || this.validateDeeplinkPriority(matchedDeeplinkConfig, config))) {
        if (config.code === 'profile' && !this.appGlobalServices.isUserLoggedIn()) {
          config.route = 'tabs/guest-profile';
        }
        matchedDeeplinkConfig = config;
        urlMatch = urlRegexMatch;
      }
    });

    if (!matchedDeeplinkConfig) {
      return;
    }

    let identifier;
    if (urlMatch && urlMatch.groups && Object.keys(urlMatch.groups).length) {
      identifier = urlMatch.groups.quizId || urlMatch.groups.content_id || urlMatch.groups.course_id;
    }

    await this.sbProgressLoader.show(this.generateProgressLoaderContext(payloadUrl, identifier, dialCode));

    this.generateUtmTelemetryEvent(identifier, dialCode, payloadUrl);

    // Read version code from deeplink.
    const requiredVersionCode = this.getQueryParamValue(payloadUrl, 'vCode');
    // Check if deelink is compatible with the current app.
    if (requiredVersionCode && !(await this.isAppCompatible(requiredVersionCode))) {
      this.closeProgressLoader();
      this.upgradeAppPopover(requiredVersionCode);
    } else {
      this.isOnboardingCompleted =
        (await this.preferences.getString(PreferenceKey.IS_ONBOARDING_COMPLETED).toPromise() === 'true') ? true : false;


      // If onboarding not completed
      if (!this.isOnboardingCompleted) {  // && !session
        // skip info popup
        this.appGlobalServices.skipCoachScreenForDeeplink = true;
        this.enableRootNavigation = true;

        // Set onboarding data if available in query params. e.g. channel, role, lang
        await this.setOnboradingData(payloadUrl);
      }
      const attributeConfig = deepLinkUrlConfig.find(config => config.code === 'attributes');
      this.handleNavigation(payloadUrl, identifier, dialCode, matchedDeeplinkConfig, attributeConfig.params['attributes'], urlMatch.groups);
    }
  }

  // Lesser the value higher the priority
  private validateDeeplinkPriority(matchedDeeplinkConfig, config) {
    return (matchedDeeplinkConfig && !matchedDeeplinkConfig.priority && config.priority) ||
      (matchedDeeplinkConfig && matchedDeeplinkConfig.priority
        && config.priority && matchedDeeplinkConfig.priority > config.priority);
  }

  private generateProgressLoaderContext(url, identifier, dialCode): SbProgressLoaderContext {
    if (this.progressLoaderId) {
      this.closeProgressLoader();
    }
    this.progressLoaderId = dialCode || identifier || ProgressPopupContext.DEEPLINK;
    const deeplinkUrl: URL = new URL(url);
    const channelSlug = deeplinkUrl.searchParams.get('channel');
    if (channelSlug) {
      return {
        id: this.progressLoaderId,
        ignoreTelemetry: {
          when: {
            interact: IgnoreTelemetryPatters.IGNORE_DEEPLINK_PAGE_ID_EVENTS,
            impression: IgnoreTelemetryPatters.IGNORE_CHANNEL_IMPRESSION_EVENTS
          }
        }
      };
    } else if (dialCode) {
      return {
        id: this.progressLoaderId,
        ignoreTelemetry: {
          when: {
            interact: IgnoreTelemetryPatters.IGNORE_DIAL_CODE_PAGE_ID_EVENTS,
            impression: IgnoreTelemetryPatters.IGNORE_DEEPLINK_PAGE_ID_EVENTS
          }
        }
      };
    } else if (identifier) {
      return {
        id: this.progressLoaderId,
        ignoreTelemetry: {
          when: {
            interact: IgnoreTelemetryPatters.IGNORE_DEEPLINK_PAGE_ID_EVENTS,
            impression: IgnoreTelemetryPatters.IGNORE_DEEPLINK_PAGE_ID_EVENTS
          }
        }
      };
    }
    return {
      id: this.progressLoaderId
    };
  }

  private closeProgressLoader() {
    this.sbProgressLoader.hide({
      id: this.progressLoaderId
    });
    this.progressLoaderId = undefined;
  }

  private generateUtmTelemetryEvent(identifier, dialCode, url) {
    const telemetryObject = new TelemetryObject(identifier ? identifier : dialCode, identifier ? 'Content' : 'qr', undefined);
    const utmUrl = url.slice(url.indexOf('?') + 1);
    const params: { [param: string]: string } = qs.parse(utmUrl);
    const utmcData: CorrelationData[] = [];

    if (utmUrl !== url) {
      ContentUtil.genrateUTMCData(params).forEach((element) => {
        utmcData.push(element);
      });
    }

    const corRelationData: CorrelationData[] = [{
      id: CorReleationDataType.DEEPLINK,
      type: CorReleationDataType.ACCESS_TYPE
    }];
    if (utmcData && utmcData.length) {
      this.telemetryService.updateCampaignParameters(utmcData);
      this.telemetryGeneratorService.generateUtmInfoTelemetry(params, PageId.HOME, telemetryObject, corRelationData);
    }

    return utmcData;
  }

  private getQueryParamValue(payloadUrl: string, queryParam: string): string {
    const url = new URL(payloadUrl);
    return url.searchParams.get(queryParam);
  }

  private async isAppCompatible(requiredVersionCode) {
    this.currentAppVersionCode = await this.utilityService.getAppVersionCode();

    // If requiredVersionCode is available then should display upgrade popup is installed version is less than the expected appVesion.
    return (this.currentAppVersionCode
      && requiredVersionCode
      && this.currentAppVersionCode >= requiredVersionCode);
  }

  private getRequest(payloadUrl: string, matchedDeeplinkConfig, attributeList) {
    if (!matchedDeeplinkConfig.params || !Object.keys(matchedDeeplinkConfig.params).length) {
      return undefined;
    }

    const url = new URL(payloadUrl);
    const request: {
      query?: string;
      filters?: {};
    } = {};
    const filters = this.getDefaultFilter(matchedDeeplinkConfig.params);
    const queryParamFilters = {};
    const urlAttributeList = [];
    request.query = url.searchParams.get(matchedDeeplinkConfig.params.key) || '';
    if (url.searchParams.has('se_mediums')) {
      url.searchParams.set('medium', url.searchParams.get('se_mediums'));
    }
    if (url.searchParams.has('se_boards')) {
      url.searchParams.set('board', url.searchParams.get('se_boards'));
    }
    if (url.searchParams.has('se_gradeLevels')) {
      url.searchParams.set('gradeLevel', url.searchParams.get('se_gradeLevels'));
    }
    if (url.searchParams.has('se_subjects')) {
      url.searchParams.set('subject', url.searchParams.get('se_subjects'));
    }
    url.searchParams.forEach((value, key) => {
      urlAttributeList.push(key);
    });

    attributeList = attributeList.filter((attribute) =>  urlAttributeList.indexOf(attribute.code) >= 0
          || urlAttributeList.indexOf(attribute.proxyCode) >= 0);
    attributeList.forEach((attribute) => {
      let values ;
      if (attribute.type === 'Array') {
         values = url.searchParams.getAll(attribute.proxyCode ? attribute.proxyCode : attribute.code);
      } else if (attribute.type === 'String') {
         values = url.searchParams.get(attribute.proxyCode ? attribute.proxyCode : attribute.code);
      }

      if (values && values.length) {
        if (attribute.filter === 'custom') {
          queryParamFilters[attribute.code] =
                  this.getCustomFilterValues(matchedDeeplinkConfig.params, values, attribute);
        } else {
          queryParamFilters[attribute.code] = values;
        }
      }
    });
    request.filters = { ...filters, ...queryParamFilters };
    return request;
  }

  private getDefaultFilter(deeplinkParams) {
    if (!deeplinkParams || !deeplinkParams.data ||  !deeplinkParams.data.length) {
      return {};
    }
    const defaultFilter = deeplinkParams.data.filter((param) => param.type === 'default');
    return defaultFilter.reduce((acc, item) => {
      acc[item.code] = item.values;
      return acc;
    }, {});
  }

  private getCustomFilterValues(deeplinkParams, values, attribute) {
    if (!deeplinkParams || !deeplinkParams.data || !deeplinkParams.data.length) {
      return [];
    }
    const customFilterData = deeplinkParams.data.find((param) => param.type === 'custom' && param.code === attribute.code);
    console.log('deeplinkParams', deeplinkParams);
    console.log('customFilterData', customFilterData);
    console.log('attribute', attribute);

    let customFilterOptions = [];
    if (customFilterData && customFilterData.values) {
      values.forEach((v) => {
          const customFilterValues = customFilterData.values.find(m => m.name === v);
          customFilterOptions = customFilterOptions.concat(customFilterValues ? customFilterValues.options : []);
      });
    }
    return customFilterOptions;
    }

private async upgradeAppPopover(requiredVersionCode) {
    const packageName = await this.appVersion.getPackageName();
    const playStoreLink = `https://play.google.com/store/apps/details?id=${packageName}`;
    const result: any = {
      type: 'optional',
      title: 'UPDATE_APP_SUPPORT_TITLE',
      isOnboardingCompleted: this.isOnboardingCompleted,
      requiredVersionCode,
      currentAppVersionCode: (this.currentAppVersionCode).toString(),
      isFromDeeplink: true,
      actionButtons: [
        {
          action: 'yes',
          label: 'UPDATE_APP_BTN_ACTION_YES',
          link: playStoreLink
        }
      ]
    };
    await this.appGlobalServices.openPopover(result);
  }

  private async setOnboradingData(payloadUrl) {
    const lang = this.getQueryParamValue(payloadUrl, 'lang');
    this.setAppLanguage(lang);

    const userType = this.getQueryParamValue(payloadUrl, 'role');
    this.setUserType(userType);

    const channelSlug = this.getQueryParamValue(payloadUrl, 'channel');
    if (channelSlug) {
      const orgSearchRequest = {
        filters: {
          slug: channelSlug,
          isRootOrg: true
        }
      };

      try {
        const result = await this.frameworkService.searchOrganization(orgSearchRequest).toPromise();
        const org: any = result.content && result.content[0];
        if (org) {
          const channelId = org.id;
          this.setProfileData(channelId, payloadUrl);

          // Set the channel for page assemble and load the channel specifc course page is available.
          this.pageAssembleService.setPageAssembleChannel({ channelId });

          setTimeout(() => {
            this.events.publish(EventTopics.COURSE_PAGE_ASSEMBLE_CHANNEL_CHANGE);
          }, 500);
        }
      } catch (e) {
        console.error(e);
      }
    }


  }

  private async setAppLanguage(langCode: string) {
    const selctedLangCode = await this.preferences.getString(PreferenceKey.SELECTED_LANGUAGE_CODE).toPromise();
    const selectedLangLabel = await this.preferences.getString(PreferenceKey.SELECTED_LANGUAGE).toPromise();
    if (!selctedLangCode && !selectedLangLabel) {
      let languageDetail;
      if (!langCode) {
        // Set the default to english if not available.
        langCode = 'en';
      }
      const LangList = appLanguages;
      languageDetail = LangList.find(i => i.code === langCode);

      await this.preferences.putString(PreferenceKey.SELECTED_LANGUAGE_CODE, languageDetail.code).toPromise();
      this.translateService.use(languageDetail.code);

      await this.preferences.putString(PreferenceKey.SELECTED_LANGUAGE, languageDetail.name).toPromise();
    }
  }

  private async setUserType(userType) {
    if (!(userType && Object.values(ProfileType).includes(userType))) {
      userType = ProfileType.TEACHER;
    }
    const selectedUserType = await this.preferences.getString(PreferenceKey.SELECTED_USER_TYPE).toPromise();
    if (!selectedUserType) {
      await this.preferences.putString(PreferenceKey.SELECTED_USER_TYPE, userType).toPromise();
    }
  }

  private async setProfileData(channelId: string, payloadUrl) {
    try {
      const channelDetails: Channel = await this.frameworkService.getChannelDetails({ channelId }).toPromise();
      const frameworkId = channelDetails.defaultFramework;

      const categories = [
        { code: FrameworkCategoryCode.BOARD, prevCode: null },
        { code: FrameworkCategoryCode.MEDIUM, prevCode: FrameworkCategoryCode.BOARD },
        { code: FrameworkCategoryCode.GRADE_LEVEL, prevCode: FrameworkCategoryCode.MEDIUM }
      ];
      const categoryData: any = {};
      for (const category of categories) {
        const boardCategoryTermsRequet: GetFrameworkCategoryTermsRequest = {
          from: category.code === FrameworkCategoryCode.BOARD ? CachedItemRequestSourceFrom.SERVER : null,
          frameworkId,
          requiredCategories: FrameworkCategoryCodesGroup.DEFAULT_FRAMEWORK_CATEGORIES,
          currentCategoryCode: category.code,
          language: this.translateService.currentLang,
          selectedTermsCodes: category.prevCode ? [category.prevCode] : null
        };
        const terms = await this.frameworkUtilService.getFrameworkCategoryTerms(boardCategoryTermsRequet).toPromise();
        categoryData[category.code] = terms[0].code;
      }

      // Get the active profile
      const activeSessionProfile = await this.profileService.getActiveSessionProfile({
        requiredFields: ProfileConstants.REQUIRED_FIELDS
      }).toPromise();

      const userType = await this.preferences.getString(PreferenceKey.SELECTED_USER_TYPE).toPromise();
      const updateProfileRequest: Profile = {
        ...activeSessionProfile,
        syllabus: [frameworkId],
        board: [categoryData[FrameworkCategoryCode.BOARD]],
        medium: [categoryData[FrameworkCategoryCode.MEDIUM]],
        grade: [categoryData[FrameworkCategoryCode.GRADE_LEVEL]],
        handle: 'Guest1',
        profileType: userType as any,
        source: ProfileSource.LOCAL
      };
      const profile: Profile = await this.profileService.updateProfile(updateProfileRequest).toPromise();


      this.appGlobalServices.guestUserProfile = profile;

      this.commonUtilService.handleToTopicBasedNotification();

      setTimeout(async () => {
        this.appGlobalServices.setOnBoardingCompleted();
        this.loginNavigationHandlerService.setDefaultProfileDetails();
      }, 1000);

      this.events.publish('onboarding-card:completed', { isOnBoardingCardCompleted: true });
      this.events.publish('refresh:profile');
      this.appGlobalServices.guestUserProfile = profile;
      this.telemetryGeneratorService.generateProfilePopulatedTelemetry(
        PageId.HOME, profile, 'auto', Environment.ONBOARDING, ContentUtil.extractBaseUrl(payloadUrl)
      );

      this.isOnboardingCompleted = true;
    } catch (e) {
      this.closeProgressLoader();
    }
  }

  private async handleNavigation(payloadUrl, identifier, dialCode, matchedDeeplinkConfig, attributeList, urlMatchGroup) {
    const route = matchedDeeplinkConfig.route;
    if (dialCode) {
      this.telemetryGeneratorService.generateAppLaunchTelemetry(LaunchType.DEEPLINK, payloadUrl);
      this.setTabsRoot();
      this.router.navigate([route],
        {
          state: {
            dialCode,
            source: PageId.HOME,
            corRelation: this.getCorrelationList(payloadUrl)
          }
        });
    } else if (identifier) {
      const content = await this.getContentData(identifier);
      if (!content) {
        if (urlMatchGroup.contentId) {
          this.navigateContent(urlMatchGroup.contentId, true, null, payloadUrl, null);
        }
        this.closeProgressLoader();
      } else {
        this.navigateContent(identifier, true, content, payloadUrl, route);
      }
    } else {
      let extras = {};
      const request = this.getRequest(payloadUrl, matchedDeeplinkConfig, attributeList);
      if (request && (request.query || request.filters && Object.keys(request.filters).length)) {
        extras = {
          state: {
            source: PageId.SPLASH_SCREEN,
            preAppliedFilter: {
              query: request.query || '',
              filters: {
                status: ['Live'],
                objectType: ['Content'],
                ...request.filters
              }
            }
          }
        };
      } else if (matchedDeeplinkConfig &&
        matchedDeeplinkConfig.pattern && matchedDeeplinkConfig.pattern.includes('manage-learn')) {
          extras = {
            state: {
              data: urlMatchGroup
            }
          };
      }
      this.setTabsRoot();
      this.router.navigate([route], extras);
      this.closeProgressLoader();
    }
  }

  /////////////////////////////////////////////////

  async navigateContent(
    identifier, isFromLink = false, content?: Content | null,
    payloadUrl?: string, route?: string, coreRelationList?: Array<CorrelationData>
  ) {
    try {
      this.appGlobalServices.resetSavedQuizContent();
      if (!content) {
        content = await this.getContentData(identifier);
      }

      if (isFromLink) {
        this.telemetryGeneratorService.generateAppLaunchTelemetry(LaunchType.DEEPLINK, payloadUrl);
      }

      if (content && content.contentData &&
        content.contentData.status === ContentFilterConfig.CONTENT_STATUS_UNLISTED) {
        this.navigateQuizContent(identifier, content, isFromLink, payloadUrl, coreRelationList);
      } else if (content) {
        if (!route) {
          route = this.getRouterPath(content);
        }
        if (content.mimeType === MimeType.COLLECTION) {
          this.navigateToCollection(identifier, content, payloadUrl, route, false, false, coreRelationList);
        } else {
          this.setTabsRoot();
          if (this.context && this.context.notificationPayload && this.context.notificationPayload.actionData.openPlayer) {
            const contentInfo: ContentInfo = {
              telemetryObject: undefined,
              rollUp: undefined,
              correlationList: coreRelationList,
              hierachyInfo: undefined,
              course: undefined
            };
            const navExtras = {
              state: {
                content,
              }
            };
            const telemetryObject = {
              corRelationList: []
            };
            this.contentPlayerHandler.playContent(content, navExtras, telemetryObject, false, false);
            this.closeProgressLoader();
          } else {
            await this.router.navigate([route],
              {
                state: {
                  content,
                  corRelation: this.getCorrelationList(payloadUrl, coreRelationList)
                }
              });
          }
        }
      } else {
        if (!this.commonUtilService.networkInfo.isNetworkAvailable) {
          this.commonUtilService.showToast('NEED_INTERNET_FOR_DEEPLINK_CONTENT');
          this.appGlobalServices.skipCoachScreenForDeeplink = false;
          this.closeProgressLoader();
          return;
        }
      }
    } catch (err) {
      this.closeProgressLoader();
      console.log(err);
    }
  }

  private getRouterPath(content) {
    let route;
    if (content.primaryCategory === CsPrimaryCategory.COURSE.toLowerCase()) {
      route = RouterLinks.ENROLLED_COURSE_DETAILS;
    } else if (content.mimeType === MimeType.COLLECTION) {
      route = RouterLinks.COLLECTION_DETAIL_ETB;
    } else {
      route = RouterLinks.CONTENT_DETAILS;
    }
    return route;
  }

  private async navigateQuizContent(identifier, content, isFromLink, payloadUrl, corRelationList) {
    this.appGlobalServices.limitedShareQuizContent = identifier;
    if (isFromLink) {
      this.limitedSharingContentLinkClickedTelemery();
    }
    if (this.router.url && this.router.url.indexOf(RouterLinks.CONTENT_DETAILS) !== -1) {
      this.events.publish(EventTopics.DEEPLINK_CONTENT_PAGE_OPEN, { content, autoPlayQuizContent: true });
      this.closeProgressLoader();
      return;
    }
    this.setTabsRoot();
    await this.router.navigate([RouterLinks.CONTENT_DETAILS],
      {
        state: {
          content, autoPlayQuizContent: true,
          corRelation: this.getCorrelationList(payloadUrl, corRelationList)
        }
      });
  }

  private getContentData(contentId): Promise<Content | null> {
    return new Promise(async resolve => {
      const content = await this.contentService.getContentDetails({ contentId }).toPromise()
        .catch(e => {
          if (HttpServerError.isInstance(e)) {
            this.commonUtilService.showToast('ERROR_FETCHING_DATA');
          } else if (NetworkError.isInstance(e)) {
            this.commonUtilService.showToast('NEED_INTERNET_FOR_DEEPLINK_CONTENT');
          } else if (e.response && e.response.responseCode === 404) {
            return null;
          } else {
            this.commonUtilService.showToast('ERROR_CONTENT_NOT_AVAILABLE');
          }
          return null;
        });
      resolve(content);
    });
  }

  private limitedSharingContentLinkClickedTelemery(): void {
    const corRelationList = [];
    corRelationList.push({ id: ID.QUIZ, type: CorReleationDataType.DEEPLINK });
    this.telemetryGeneratorService.generateInteractTelemetry(
      InteractType.QUIZ_DEEPLINK,
      '',
      Environment.HOME,
      undefined,
      undefined,
      undefined,
      undefined,
      corRelationList,
      ID.DEEPLINK_CLICKED
    );
  }

  // This method is called only when a deeplink is clicked before Onboarding is not completed
  eventToSetDefaultOnboardingData(): void {
    this.events.subscribe(EventTopics.SIGN_IN_RELOAD, () => {
      if (!this.isOnboardingCompleted) {
        this.setAppLanguage(undefined);
        this.setUserType(undefined);
      }
    });
  }

  async navigateToCollection(
    identifier, content: Content | null, payloadUrl: string, route?: string,
    isOnboardingSkipped = false, isFromChannelDeeplink = false, corRelationList?: Array<CorrelationData>
  ) {
    let childContentId;
    if (payloadUrl) {
      childContentId = this.getQueryParamValue(payloadUrl, 'moduleId');
    }
    if (!childContentId && payloadUrl) {
      childContentId = this.getQueryParamValue(payloadUrl, 'contentId');
    }

    this.isChildContentFound = false;
    this.childContent = undefined;

    if (childContentId) {
      try {
        if (content && content.isAvailableLocally) {
          this.childContent = await this.getChildContents(childContentId);
        } else {
          this.importContent([identifier], false);
          content = await this.getContentHeirarchy(identifier);
          await this.getChildContent(content, childContentId);
        }
      } catch (e) {
        console.error(e);
      }
    }
    if (this.childContent) {
      switch (ContentUtil.isTrackable(this.childContent)) {
        case 0:
          switch (ContentUtil.isTrackable(content)) {
            case 1:
              const chapterParams: NavigationExtras = {
                state: {
                  courseContent: content,
                  chapterData: this.childContent,
                  isOnboardingSkipped,
                  isFromDeeplink: true
                }
              };
              this.closeProgressLoader();
              this.setTabsRoot();
              this.router.navigate([`/${RouterLinks.CURRICULUM_COURSES}/${RouterLinks.CHAPTER_DETAILS}`],
                chapterParams);
              break;
            case 0:
              this.navService.navigateToCollection({
                content,
                corRelation: this.getCorrelationList(payloadUrl, corRelationList)
              });
              this.closeProgressLoader();
              break;
          }
          break;
        case -1:
        case 1:
          switch (ContentUtil.isTrackable(content)) {
            case 1:
              if (this.appGlobalServices.isGuestUser) { // guest user
                this.setTabsRoot();
                this.navService.navigateToTrackableCollection({
                  content,
                  isFromChannelDeeplink,
                  corRelation: this.getCorrelationList(payloadUrl, corRelationList)
                });
                this.closeProgressLoader();
              } else {
                const fetchEnrolledCourseRequest: FetchEnrolledCourseRequest = {
                  userId: await this.appGlobalServices.getActiveProfileUid(),
                };
                const enrolledCourses = await this.courseService.getEnrolledCourses(fetchEnrolledCourseRequest).toPromise();
                let isCourseEnrolled;
                if (enrolledCourses && enrolledCourses.length > 0) {
                  isCourseEnrolled = enrolledCourses.find(course => {
                    return course.contentId === childContentId;
                  });
                }
                if (isCourseEnrolled) { // already enrolled
                  this.setTabsRoot();
                  this.navService.navigateToContent({
                    content: this.childContent,
                    depth: 1,
                    isChildContent: true,
                    isCourse: content.primaryCategory.toLowerCase() === CsPrimaryCategory.COURSE.toLowerCase(),
                    isOnboardingSkipped,
                    corRelation: this.getCorrelationList(payloadUrl, corRelationList)
                  });
                  this.closeProgressLoader();
                } else { // not enrolled in batch
                  this.setTabsRoot();
                  this.navService.navigateToTrackableCollection({
                    content,
                    isFromChannelDeeplink,
                    corRelation: this.getCorrelationList(payloadUrl, corRelationList)
                  });
                  this.closeProgressLoader();
                }
              }
              break;
            case -1:
            case 0:
              this.setTabsRoot();
              this.navService.navigateToContent({
                content: this.childContent,
                depth: 1,
                isChildContent: true,
                corRelation: this.getCorrelationList(payloadUrl, corRelationList),
                isCourse: (content.primaryCategory.toLowerCase() === CsPrimaryCategory.COURSE.toLowerCase()) ||
                    (content.primaryCategory.toLowerCase() === CsPrimaryCategory.COURSE_UNIT.toLowerCase()),
                isOnboardingSkipped
              });
              this.sbProgressLoader.hide({ id: content.identifier });
              break;
          }
          break;
      }
    } else {
      this.setTabsRoot();
      switch (ContentUtil.isTrackable(content)) {
        case 1:
          this.navService.navigateToTrackableCollection({
            content,
            isOnboardingSkipped,
            isFromChannelDeeplink,
            corRelation: this.getCorrelationList(payloadUrl, corRelationList)
          });
          this.closeProgressLoader();
          break;
        case 0:
          this.navService.navigateToCollection({
            content,
            corRelation: this.getCorrelationList(payloadUrl, corRelationList)
          });
          this.closeProgressLoader();
          break;
      }
    }
  }

  private getCorrelationList(payloadUrl, corRelation?: Array<CorrelationData>) {
    if (!corRelation) {
      corRelation = [];
    }
    if (payloadUrl) {
      corRelation.push({
        id: ContentUtil.extractBaseUrl(payloadUrl),
        type: CorReleationDataType.SOURCE
      });
    }
    return corRelation;
  }

  async getChildContents(identifier) {
    const childContentRequest: ChildContentRequest = {
      contentId: identifier,
      hierarchyInfo: null
    };
    return this.contentService.getChildContents(childContentRequest).toPromise();
  }

  async getContentHeirarchy(identifier: string) {
    const request: ContentDetailRequest = {
      contentId: identifier
    };

    return this.contentService.getContentHeirarchy(request).toPromise();
  }

  async getChildContent(content, childContentId) {
    if (content.identifier === childContentId) {
      this.childContent = content;
      this.isChildContentFound = true;
    } else if (!this.isChildContentFound && content && content.children) {
      content.children.forEach((ele) => {
        if (!this.isChildContentFound) {
          this.getChildContent(ele, childContentId);
        }
      });
    }
    return (this.childContent);
  }

  private importContent(identifiers: Array<string>, isChild: boolean) {
    const contentImportRequest: ContentImportRequest = {
      contentImportArray: this.getImportContentRequestBody(identifiers, isChild),
      contentStatusArray: ['Live'],
      fields: ['appIcon', 'name', 'subject', 'size', 'gradeLevel'],
    };
    // // Call content service
    this.contentService.importContent(contentImportRequest).toPromise();
  }

  private getImportContentRequestBody(identifiers: Array<string>, isChild: boolean): Array<ContentImport> {
    const rollUpMap: { [key: string]: Rollup } = {};
    const requestParams: ContentImport[] = [];
    const folderPath = this.platform.is('ios') ? cordova.file.documentsDirectory : cordova.file.externalDataDirectory;
       
    identifiers.forEach((value) => {
      requestParams.push({
        isChildContent: isChild,
        destinationFolder: folderPath,
        contentId: value,
        correlationData: [],
        rollUp: rollUpMap[value]
      });
    });

    return requestParams;
  }

  // this only sets the Root for the Tabs.
  private setTabsRoot() {
    if (this.enableRootNavigation) {
      try {
        this.location.replaceState(this.router.serializeUrl(this.router.createUrlTree([RouterLinks.TABS])));
      } catch (e) {
        console.log(e);
      }
      this.enableRootNavigation = false;
    }
  }

  private async updateProfile(payloadProfileAttribute) {
    const currentProfile = this.appGlobalServices.getCurrentUser();
    this.updateProfileService.checkProfileData(payloadProfileAttribute.request, currentProfile);
  }

  private async handleSearch(payload) {
    this.closeProgressLoader();
    const extras: NavigationExtras = {
      state: {
        preAppliedFilter: payload.request
      }
    };
    this.router.navigate([RouterLinks.SEARCH], extras);
  }

  private async navigateToDetailsPage(payload) {
    if (payload.request.objectId || payload.request.collection) {
      const content = await this.getContentData(payload.request.objectId || payload.request.collection);
      await this.navigateContent(payload.objectId, false, content, null, null, null);
    }
  }

   async handleVendorAppAction(payload, banner?) {
    this.progressLoaderId = 'DEFAULT';
    if (banner) {
      await this.sbProgressLoader.show();
    }
    switch (payload.action) {
      case 'ACTION_SEARCH':
        await this.handleSearch(payload.data);
        break;
      case 'ACTION_GOTO':
        this.closeProgressLoader();
        if (payload.data && payload.data.request.params) {
          const navigationExtras: NavigationExtras = {
            state: {
              params: payload.data.request.params
            }
          };
          await this.router.navigate([payload.data.request.route], navigationExtras);
        } else {
          await this.router.navigate([payload.data.request.route]);
        }
        break;
      case 'ACTION_SETPROFILE':
        await this.updateProfile(payload.data);
        break;
      case 'ACTION_PLAY':
        await this.navigateToDetailsPage(payload.data);
        break;
      case 'ACTION_DEEPLINK':
        await this.handleDeeplink(payload.data.request.url);
        break;
      default:
        return of (undefined);
    }
  }
}

results matching ""

    No results matching ""