File

src/app/modules/search/components/home-search/home-search.component.ts

Implements

OnInit OnDestroy AfterViewInit

Metadata

Index

Properties
Methods

Constructor

constructor(searchService: SearchService, router: Router, activatedRoute: ActivatedRoute, paginationService: PaginationService, resourceService: ResourceService, toasterService: ToasterService, changeDetectorRef: ChangeDetectorRef, configService: ConfigService, utilService: UtilService, coursesService: CoursesService, playerService: PlayerService, userService: UserService, cacheService: CacheService, browserCacheTtlService: BrowserCacheTtlService, orgDetailsService: OrgDetailsService, navigationhelperService: NavigationHelperService, layoutService: LayoutService, schemaService: SchemaService, contentManagerService: ContentManagerService, telemetryService: TelemetryService, offlineCardService: OfflineCardService)
Parameters :
Name Type Optional
searchService SearchService No
router Router No
activatedRoute ActivatedRoute No
paginationService PaginationService No
resourceService ResourceService No
toasterService ToasterService No
changeDetectorRef ChangeDetectorRef No
configService ConfigService No
utilService UtilService No
coursesService CoursesService No
playerService PlayerService No
userService UserService No
cacheService CacheService No
browserCacheTtlService BrowserCacheTtlService No
orgDetailsService OrgDetailsService No
navigationhelperService NavigationHelperService No
layoutService LayoutService No
schemaService SchemaService No
contentManagerService ContentManagerService No
telemetryService TelemetryService No
offlineCardService OfflineCardService No

Methods

addHoverData
addHoverData()
Returns : void
callDownload
callDownload()
Returns : void
checkForBack
checkForBack()
Returns : void
downloadContent
downloadContent(contentId)
Parameters :
Name Optional
contentId No
Returns : void
Private fetchContentOnParamChange
fetchContentOnParamChange()
Returns : void
Private fetchContents
fetchContents()
Returns : void
Private fetchEnrolledCoursesSection
fetchEnrolledCoursesSection()
Returns : any
getInteractEdata
getInteractEdata(event)
Parameters :
Name Optional
event No
Returns : void
goback
goback()
Returns : void
Public handleFilterChange
handleFilterChange(filters)
  • Function to handle filters data
  • filters object propagating from app-global-search-filter
  • Set filters data to cache with key searchFiltersAll
  • TTL for searchFiltersAll is based on form configuration
  • Form configuration key metaData.cacheTimeout provides TTL for cache storage of filters
  • If form configuration is not set then by default 3600000 value is set as TTL
  • If filters object has se_boards key and cache has data
  • Incoming data is merged with existing data
  • Final filters are stored in cache
  • If cache does not have filters
  • then incoming filters are stored in cache
Parameters :
Name Optional Description
filters No
  • filters object
Returns : void
hoverActionClicked
hoverActionClicked(event)
Parameters :
Name Optional
event No
Returns : void
initLayout
initLayout()
Returns : void
Public inView
inView(event)
Parameters :
Name Optional
event No
Returns : void
Public isUserLoggedIn
isUserLoggedIn()
Returns : boolean
Private listenLanguageChange
listenLanguageChange()
Returns : void
logTelemetry
logTelemetry(content, actionId)
Parameters :
Name Optional
content No
actionId No
Returns : void
logViewAllTelemetry
logViewAllTelemetry(event)
Parameters :
Name Optional
event No
Returns : void
moveToTop
moveToTop()
Returns : void
Public navigateToPage
navigateToPage(page: number)
Parameters :
Name Type Optional
page number No
Returns : void
ngAfterViewInit
ngAfterViewInit()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
Public playContent
playContent(undefined)
Parameters :
Name Optional
No
Returns : any
redoLayout
redoLayout()
Returns : void
Private setNoResultMessage
setNoResultMessage()
Returns : void
Private setTelemetryData
setTelemetryData()
Returns : void
Public viewAll
viewAll(event)
Parameters :
Name Optional
event No
Returns : void

Properties

Public activatedRoute
Type : ActivatedRoute
Public allMimeType
Public allTabData
Public browserCacheTtlService
Type : BrowserCacheTtlService
Public cacheService
Type : CacheService
Public cardIntractEdata
Type : IInteractEventEdata
Public changeDetectorRef
Type : ChangeDetectorRef
Public closeIntractEdata
Public configService
Type : ConfigService
contentData
contentDownloadStatus
Type : object
Default value : {}
Public contentList
Type : Array<any>
Default value : []
Public contentManagerService
Type : ContentManagerService
contentName
Type : string
Public coursesService
Type : CoursesService
Public dataDrivenFilterEvent
Default value : new EventEmitter()
Public dataDrivenFilters
Type : any
Default value : {}
downloadIdentifier
Type : string
Public enrolledSection
Public facets
Type : Array<string>
Public facetsList
Type : any
Public filterIntractEdata
Public filterType
Type : string
FIRST_PANEL_LAYOUT
Public frameWorkName
Type : string
Public globalSearchFacets
Type : Array<string>
Public initFilters
Default value : false
Public inViewLogs
Type : []
Default value : []
isDesktopApp
Default value : false
layoutConfiguration
Type : any
Public layoutService
Type : LayoutService
Public loaderMessage
Type : ILoaderMessage
Public navigationhelperService
Type : NavigationHelperService
Public noResultMessage
Type : INoResultMessage
Public orgDetailsService
Type : OrgDetailsService
Public paginationDetails
Type : IPagination
Public paginationService
Type : PaginationService
Public queryParams
Type : any
Public redirectUrl
Public resourceService
Type : ResourceService
Public router
Type : Router
Public searchService
Type : SearchService
SECOND_PANEL_LAYOUT
Public selectedCourseBatches
Type : any
Public selectedFilters
showBackButton
Default value : false
Public showBatchInfo
Default value : false
showDownloadLoader
Default value : false
Public showLoader
Default value : true
showModal
Default value : false
sortingOptions
Type : Array<ISort>
Public sortIntractEdata
Type : IInteractEventEdata
Public telemetryImpression
Type : IImpressionEventInput
Public telemetryService
Type : TelemetryService
Public toasterService
Type : ToasterService
Public unsubscribe$
Default value : new Subject<void>()
Public userService
Type : UserService
Public utilService
Type : UtilService
import {
  PaginationService, ResourceService, ConfigService, ToasterService, INoResultMessage, ILoaderMessage, UtilService, BrowserCacheTtlService, NavigationHelperService, IPagination,
  LayoutService, COLUMN_TYPE, OfflineCardService
} from '@sunbird/shared';
import { SearchService, PlayerService, CoursesService, UserService, ISort, OrgDetailsService, SchemaService } from '@sunbird/core';
import { combineLatest, Subject, of } from 'rxjs';
import { Component, OnInit, OnDestroy, EventEmitter, ChangeDetectorRef, AfterViewInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import * as _ from 'lodash-es';
import { IInteractEventEdata, IImpressionEventInput, TelemetryService } from '@sunbird/telemetry';
import { takeUntil, map, delay, debounceTime, tap, mergeMap } from 'rxjs/operators';
import { CacheService } from '../../../shared/services/cache-service/cache.service';
import { ContentManagerService } from '../../../public/module/offline/services/content-manager/content-manager.service';
import {omit, groupBy, get, uniqBy, toLower, find, map as _map, forEach, each} from 'lodash-es';


@Component({
  templateUrl: './home-search.component.html'
})
export class HomeSearchComponent implements OnInit, OnDestroy, AfterViewInit {

  public showLoader = true;
  public noResultMessage: INoResultMessage;
  public filterType: string;
  public queryParams: any;
  public unsubscribe$ = new Subject<void>();
  public telemetryImpression: IImpressionEventInput;
  public inViewLogs = [];
  public sortIntractEdata: IInteractEventEdata;
  public dataDrivenFilters: any = {};
  public dataDrivenFilterEvent = new EventEmitter();
  public initFilters = false;
  public facets: Array<string>;
  public facetsList: any;
  public paginationDetails: IPagination;
  public contentList: Array<any> = [];
  public cardIntractEdata: IInteractEventEdata;
  public loaderMessage: ILoaderMessage;
  public redirectUrl;
  public frameWorkName: string;
  public closeIntractEdata;
  public enrolledSection;
  public filterIntractEdata;
  public showBatchInfo = false;
  public selectedCourseBatches: any;
  public selectedFilters;
  sortingOptions: Array<ISort>;
  layoutConfiguration: any;
  FIRST_PANEL_LAYOUT;
  SECOND_PANEL_LAYOUT;
  public globalSearchFacets: Array<string>;
  public allTabData;
  public allMimeType;
  isDesktopApp = false;
  contentDownloadStatus = {};
  downloadIdentifier: string;
  showDownloadLoader = false;
  contentData;
  contentName: string;
  showModal = false;
  showBackButton = false;

  constructor(public searchService: SearchService, public router: Router,
    public activatedRoute: ActivatedRoute, public paginationService: PaginationService,
    public resourceService: ResourceService, public toasterService: ToasterService, public changeDetectorRef: ChangeDetectorRef,
    public configService: ConfigService, public utilService: UtilService, public coursesService: CoursesService,
    private playerService: PlayerService, public userService: UserService, public cacheService: CacheService,
    public browserCacheTtlService: BrowserCacheTtlService, public orgDetailsService: OrgDetailsService,
    public navigationhelperService: NavigationHelperService, public layoutService: LayoutService, private schemaService: SchemaService,
    public contentManagerService: ContentManagerService, public telemetryService: TelemetryService,
    private offlineCardService: OfflineCardService) {
    this.paginationDetails = this.paginationService.getPager(0, 1, this.configService.appConfig.SEARCH.PAGE_LIMIT);
    this.filterType = this.configService.appConfig.home.filterType;
    // this.redirectUrl = this.configService.appConfig.courses.searchPageredirectUrl;
    this.sortingOptions = this.configService.dropDownConfig.FILTER.RESOURCES.sortingOptions;
    this.setTelemetryData();
  }
  ngOnInit() {
    this.isDesktopApp = this.utilService.isDesktopApp;
    this.listenLanguageChange();
    this.contentManagerService.contentDownloadStatus$
    .pipe(takeUntil(this.unsubscribe$))
    .subscribe(contentDownloadStatus => {
      this.contentDownloadStatus = contentDownloadStatus;
      this.addHoverData();
    });
    this.searchService.getContentTypes().pipe(takeUntil(this.unsubscribe$)).subscribe(formData => {
      this.allTabData = _.find(formData, (o) => o.title === 'frmelmnts.tab.all');
      this.globalSearchFacets = _.get(this.allTabData, 'search.facets');
      this.setNoResultMessage();
      this.initFilters = true;
    }, error => {
      this.toasterService.error(this.resourceService.frmelmnts.lbl.fetchingContentFailed);
      this.navigationhelperService.goBack();
    });
    this.initFilters = true;
    this.initLayout();
    combineLatest(this.fetchEnrolledCoursesSection(), this.dataDrivenFilterEvent)
    .pipe(takeUntil(this.unsubscribe$))
      .subscribe((data: Array<any>) => {
        this.enrolledSection = data[0];
        this.dataDrivenFilters = data[1];
        this.fetchContentOnParamChange();
        this.setNoResultMessage();
      },
        error => {
          this.toasterService.error(this.resourceService.messages.fmsg.m0002);
        });
        this.checkForBack();
        this.moveToTop();
  }
  checkForBack() {
    if (_.get(this.activatedRoute, 'snapshot.queryParams["showClose"]') === 'true') {
      this.showBackButton = true;
    }
  }
  initLayout() {
    this.layoutConfiguration = this.layoutService.initlayoutConfig();
    this.redoLayout();
    this.layoutService.switchableLayout().
      pipe(takeUntil(this.unsubscribe$)).subscribe(layoutConfig => {
        if (layoutConfig != null) {
          this.layoutConfiguration = layoutConfig.layout;
        }
        this.redoLayout();
      });
  }
  redoLayout() {
    if (this.layoutConfiguration != null) {
      this.FIRST_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(0, this.layoutConfiguration, COLUMN_TYPE.threeToNine);
      this.SECOND_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(1, this.layoutConfiguration, COLUMN_TYPE.threeToNine);
    } else {
      this.FIRST_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(0, null, COLUMN_TYPE.fullLayout);
      this.SECOND_PANEL_LAYOUT = this.layoutService.redoLayoutCSS(1, null, COLUMN_TYPE.fullLayout);
    }
  }
  private fetchContentOnParamChange() {
    combineLatest(this.activatedRoute.params, this.activatedRoute.queryParams, this.schemaService.fetchSchemas())
      .pipe(debounceTime(5),
        tap(data => this.inView({ inview: [] })), // trigger pageexit if last filter resulted 0 contents
        delay(10), // to trigger pageexit telemetry event
        tap(data => {
          this.showLoader = true;
          this.setTelemetryData();
        }),
        map((result) => ({ params: { pageNumber: Number(result[0].pageNumber) }, queryParams: result[1] })),
        takeUntil(this.unsubscribe$))
      .subscribe(({ params, queryParams }) => {
        this.queryParams = { ...queryParams };
        this.globalSearchFacets = (this.queryParams && this.queryParams.searchFilters) ?
        JSON.parse(this.queryParams.searchFilters) : this.globalSearchFacets;
        this.paginationDetails.currentPage = params.pageNumber;
        this.contentList = [];
        this.fetchContents();
      });
  }
  private fetchContents() {
    /* istanbul ignore next */
    const selectedMediaType = _.isArray(_.get(this.queryParams, 'mediaType')) ? _.get(this.queryParams, 'mediaType')[0] :
      _.get(this.queryParams, 'mediaType');
    const mimeType = _.find(_.get(this.allTabData, 'search.filters.mimeType'), (o) => {
      return o.name === (selectedMediaType || 'all');
    });
    let filters = _.pickBy(this.queryParams, (value: Array<string> | string) => value && value.length);
    filters = this.schemaService.schemaValidator({
      inputObj: filters || {},
      properties: _.get(this.schemaService.getSchema('content'), 'properties') || {},
      omitKeys: ['key', 'sort_by', 'sortType', 'appliedFilters', 'selectedTab', 'mediaType', 'contentType', 'board', 'medium', 'gradeLevel', 'subject', 'description']
    });
    filters.primaryCategory = filters.primaryCategory || _.get(this.allTabData, 'search.filters.primaryCategory');
    filters.mimeType = filters.mimeType || _.get(mimeType, 'values');

    const _filters = _.get(this.allTabData, 'search.filters');
    _.forEach(_filters, (el, key) => {
      if (!['primaryCategory', 'mimeType'].includes(key) && !_.has(filters, key)) {
        filters[key] = el;
      }
    });
    
    const option = {
      filters: filters,
      fields: _.get(this.allTabData, 'search.fields'),
      limit: _.get(this.allTabData, 'search.limit') ?  _.get(this.allTabData, 'search.limit')
      : this.configService.appConfig.SEARCH.PAGE_LIMIT,
      offset: (this.paginationDetails.currentPage - 1) * (this.configService.appConfig.SEARCH.PAGE_LIMIT),
      query: this.queryParams.key,
      sort_by: { lastPublishedOn: 'desc' },
      facets: this.globalSearchFacets,
      params: this.configService.appConfig.Course.contentApiQueryParams,
      pageNumber: this.paginationDetails.currentPage
    };
    this.searchService.contentSearch(option)
      .pipe(
        mergeMap(data => {
        //   const { subject: selectedSubjects = [] } = (this.selectedFilters || {}) as { subject: [] };
        //   const filteredContents = omit(groupBy(get(data, 'result.content') || get(data, 'result.QuestionSet'), content => {
        //     return ((this.queryParams['primaryCategory'] && this.queryParams['primaryCategory'].length > 0) ? content['subject'] : content['primaryCategory']);
        // }), ['undefined']);
        // for (const [key, value] of Object.entries(filteredContents)) {
        //     const isMultipleSubjects = key && key.split(',').length > 1;
        //     if (isMultipleSubjects) {
        //         const subjects = key && key.split(',');
        //         subjects.forEach((subject) => {
        //             if (filteredContents[subject]) {
        //                 filteredContents[subject] = uniqBy(filteredContents[subject].concat(value), 'identifier');
        //             } else {
        //                 filteredContents[subject] = value;
        //             }
        //         });
        //         delete filteredContents[key];
        //     }
        // }
        // const sections = [];
        // for (const section in filteredContents) {
        //     if (section) {
        //         if (selectedSubjects.length && !(find(selectedSubjects, selectedSub => toLower(selectedSub) === toLower(section)))) {
        //             continue;
        //         }
        //         sections.push({
        //             name: section,
        //             contents: filteredContents[section]
        //         });
        //     }
        // }
        // _map(sections, (section) => {
        //     forEach(section.contents, contents => {
        //         contents.cardImg = contents.appIcon || 'assets/images/book.png';
        //     });
        //     return section;
        // });
        // this.contentList = sections;
        if(get(data, 'result.content') && get(data, 'result.QuestionSet')){
          this.contentList = _.concat(get(data, 'result.content'), get(data, 'result.QuestionSet'));
        } else if(get(data, 'result.content')){
          this.contentList = get(data, 'result.content');
        } else {
          this.contentList = get(data, 'result.QuestionSet');
        }
        this.addHoverData();
          const channelFacet = _.find(_.get(data, 'result.facets') || [], facet => _.get(facet, 'name') === 'channel');
          if (channelFacet) {
            const rootOrgIds = this.orgDetailsService.processOrgData(_.get(channelFacet, 'values'));
            return this.orgDetailsService.searchOrgDetails({
              filters: { isTenant: true, id: rootOrgIds },
              fields: ['slug', 'identifier', 'orgName']
            }).pipe(
              mergeMap(orgDetails => {
                channelFacet.values = _.get(orgDetails, 'content');
                return of(data);
              })
            );
          }
          return of(data);
        })
      )
      .subscribe(data => {
        this.showLoader = false;
        this.facets = this.searchService.updateFacetsData(_.get(data, 'result.facets'));
        this.facets.forEach((facet) => {
          facet['label'] = this.utilService.transposeTerms(facet['label'], facet['label'], this.resourceService.selectedLang);
        });
        this.facetsList = this.searchService.processFilterData(_.get(data, 'result.facets'));
        this.paginationDetails = this.paginationService.getPager(data.result.count, this.paginationDetails.currentPage,
          this.configService.appConfig.SEARCH.PAGE_LIMIT);
      }, err => {
        this.showLoader = false;
        this.contentList = [];
        this.facetsList = [];
        this.paginationDetails = this.paginationService.getPager(0, this.paginationDetails.currentPage,
          this.configService.appConfig.SEARCH.PAGE_LIMIT);
        this.toasterService.error(this.resourceService.messages.fmsg.m0051);
      });
  }
  private fetchEnrolledCoursesSection() {
    return this.coursesService.enrolledCourseData$.pipe(map(({ enrolledCourses, err }) => {
      const enrolledSection = {
        name: this.resourceService.frmelmnts.lbl.mytrainings,
        length: 0,
        contents: []
      };
      if (err) {
        // shows toaster message this.resourceService.messages.fmsg.m0001
        return enrolledSection;
      }
      const { constantData, metaData, dynamicFields, slickSize } = this.configService.appConfig.CoursePageSection.enrolledCourses;
      enrolledSection.contents = this.utilService.getDataForCard(enrolledCourses, constantData, dynamicFields, metaData);
      return enrolledSection;
    }));
  }
  moveToTop() {
    window.scroll({
      top: 0,
      left: 0,
      behavior: 'smooth'
    });
  }
  public navigateToPage(page: number): void {
    if (page < 1 || page > this.paginationDetails.totalPages) {
      return;
    }
    const url = this.router.url.split('?')[0].replace(/[^\/]+$/, page.toString());
    this.router.navigate([url], { queryParams: this.queryParams });
    this.moveToTop();
  }
  goback() {
    if (this.navigationhelperService['_history'].length > 1) {
      this.navigationhelperService.goBack();
    }
  }

  public playContent({ data }) {
    const metaData = data;
    this.changeDetectorRef.detectChanges();
    const { onGoingBatchCount, expiredBatchCount, openBatch, inviteOnlyBatch } =
    this.coursesService.findEnrolledCourses(metaData.identifier);
    if (!expiredBatchCount && !onGoingBatchCount) { // go to course preview page, if no enrolled batch present
      return this.playerService.playContent(data);
    }

    if (onGoingBatchCount === 1) { // play course if only one open batch is present
      metaData.batchId = openBatch.ongoing.length ? openBatch.ongoing[0].batchId : inviteOnlyBatch.ongoing[0].batchId;
      return this.playerService.playContent(data);
    }
    // else if (onGoingBatchCount === 0 && expiredBatchCount === 1){
    //   metaData.batchId = openBatch.expired.length ? openBatch.expired[0].batchId : inviteOnlyBatch.expired[0].batchId;
    //   return this.playerService.playContent(metaData);
    // }
    this.selectedCourseBatches = { onGoingBatchCount, expiredBatchCount, openBatch, inviteOnlyBatch, courseId: metaData.identifier };
    this.showBatchInfo = true;
  }
  public inView(event) {
    _.forEach(event.inview, (elem, key) => {
      const obj = _.find(this.inViewLogs, { objid: elem.data.metaData.identifier });
      if (!obj) {
        this.inViewLogs.push({
          objid: elem.data.metaData.identifier,
          objtype: elem.data.metaData.contentType || 'content',
          index: elem.id
        });
      }
    });
    if (this.telemetryImpression) {
      this.telemetryImpression.edata.visits = this.inViewLogs;
      this.telemetryImpression.edata.subtype = 'pageexit';
      this.telemetryImpression = Object.assign({}, this.telemetryImpression);
    }
  }
  private setTelemetryData() {
    this.inViewLogs = []; // set to empty every time filter or page changes
    this.closeIntractEdata = {
      id: 'search-close',
      type: 'click',
      pageid: 'home-search'
    };
    this.cardIntractEdata = {
      id: 'content-card',
      type: 'click',
      pageid: 'home-search'
    };
    this.filterIntractEdata = {
      id: 'filter',
      type: 'click',
      pageid: 'home-search'
    };
  }
  ngAfterViewInit() {
    setTimeout(() => {
      this.telemetryImpression = {
        context: {
          env: this.activatedRoute.snapshot.data.telemetry.env
        },
        edata: {
          type: this.activatedRoute.snapshot.data.telemetry.type,
          pageid: this.activatedRoute.snapshot.data.telemetry.pageid,
          uri: this.router.url,
          subtype: this.activatedRoute.snapshot.data.telemetry.subtype,
          duration: this.navigationhelperService.getPageLoadTime()
        }
      };
    });
  }
  ngOnDestroy() {
    this.unsubscribe$.next();
    this.unsubscribe$.complete();
  }
  private setNoResultMessage() {
    this.noResultMessage = {
      'message': 'messages.stmsg.m0007',
      'messageText': 'messages.stmsg.m0006'
    };
  }

  callDownload() {
    this.showDownloadLoader = true;
    this.downloadContent(this.downloadIdentifier);
  }

  addHoverData() {
    this.contentList = this.utilService.addHoverData(this.contentList, true);  
  }

  hoverActionClicked(event) {
    event['data'] = event.content;
    this.contentName = event.content.name;
    this.contentData = event.data;
    let telemetryButtonId: any;
    switch (event.hover.type.toUpperCase()) {
        case 'OPEN':
            this.playContent(event);
            this.logTelemetry(this.contentData, 'play-content');
            break;
        case 'DOWNLOAD':
            this.downloadIdentifier = _.get(event, 'content.identifier');
            this.showModal = this.offlineCardService.isYoutubeContent(this.contentData);
            if (!this.showModal) {
                this.showDownloadLoader = true;
                this.downloadContent(this.downloadIdentifier);
            }
            telemetryButtonId = this.contentData.mimeType ===
                'application/vnd.ekstep.content-collection' ? 'download-collection' : 'download-content';
            this.logTelemetry(this.contentData, telemetryButtonId);
            break;
    }
  }

  downloadContent(contentId) {
    this.contentManagerService.downloadContentId = contentId;
    this.contentManagerService.downloadContentData = this.contentData;
    this.contentManagerService.failedContentName = this.contentName;
    this.contentManagerService.startDownload({})
        .pipe(takeUntil(this.unsubscribe$))
        .subscribe(data => {
            this.downloadIdentifier = '';
            this.contentManagerService.downloadContentId = '';
            this.contentManagerService.downloadContentData = {};
            this.contentManagerService.failedContentName = '';
            this.showDownloadLoader = false;
        }, error => {
            this.downloadIdentifier = '';
            this.contentManagerService.downloadContentId = '';
            this.contentManagerService.downloadContentData = {};
            this.contentManagerService.failedContentName = '';
            this.showDownloadLoader = false;
            _.each(this.contentList, (content) => {
              content['downloadStatus'] = this.resourceService.messages.stmsg.m0138;
            });
            if (!(error.error.params.err === 'LOW_DISK_SPACE')) {
                this.toasterService.error(this.resourceService.messages.fmsg.m0090);
            }
        });
  }

  private listenLanguageChange() {
    this.resourceService.languageSelected$.pipe(takeUntil(this.unsubscribe$)).subscribe((languageData) => {
      this.setNoResultMessage();
      if (_.get(this.contentList, 'length') ) {
        if (this.isDesktopApp) {
          this.addHoverData();
        }
        this.facets = this.searchService.updateFacetsData(this.facets);
      }
    });
  }

  logTelemetry(content, actionId) {
    const telemetryInteractObject = {
        id: content.identifier,
        type: content.contentType,
        ver: content.pkgVersion ? content.pkgVersion.toString() : '1.0'
    };

    const appTelemetryInteractData: any = {
        context: {
            env: _.get(this.activatedRoute, 'snapshot.root.firstChild.data.telemetry.env') ||
            _.get(this.activatedRoute, 'snapshot.data.telemetry.env') ||
            _.get(this.activatedRoute.snapshot.firstChild, 'children[0].data.telemetry.env')
        },
        edata: {
            id: actionId,
            type: 'click',
            pageid: this.router.url.split('/')[1] || 'Search-page'
        }
    };

    if (telemetryInteractObject) {
        if (telemetryInteractObject.ver) {
            telemetryInteractObject.ver = _.isNumber(telemetryInteractObject.ver) ?
            _.toString(telemetryInteractObject.ver) : telemetryInteractObject.ver;
        }
        appTelemetryInteractData.object = telemetryInteractObject;
    }
    this.telemetryService.interact(appTelemetryInteractData);
  }

  /**
   * @param  { Object } filters - filters object
   * @description handleFilterChange
   * - Function to handle filters data
   * - `filters` object propagating from app-global-search-filter
   * - Set filters data to cache with key `searchFiltersAll`
   * - TTL for `searchFiltersAll` is based on form configuration
   * - Form configuration key `metaData.cacheTimeout` provides TTL for cache storage of filters
   * - If form configuration is not set then by default `3600000` value is set as TTL
   * - If `filters` object has se_boards key and cache has data
   * - Incoming data is merged with existing data
   * - Final filters are stored in cache
   * - If cache does not have filters
   * - then incoming filters are stored in cache
   */
  /* istanbul ignore next */
  public handleFilterChange(filters) {
    const filterData = filters && filters.filters || {};
    if (filterData.channel && this.facets) {
      const channelIds = [];
      const facetsData = _.find(this.facets, { 'name': 'channel' });
      _.forEach(filterData.channel, (value, index) => {
        const data = _.find(facetsData.values, { 'identifier': value });
        if (data) {
          channelIds.push(data.name);
        }
      });
      if (channelIds && Array.isArray(channelIds) && channelIds.length > 0) {
        filterData.channel = channelIds;
      }
    }
    this.selectedFilters = filterData;
    const _cacheTimeout = _.get(this.allTabData, 'metaData.cacheTimeout') || 3600000;
    /* istanbul ignore next */
    if (this.cacheService.exists('searchFiltersAll') && Object.keys(filterData).length > 0 && !_.get(filterData, 'key') 
    && _.get(this.activatedRoute, 'snapshot.queryParams.ignoreSavedFilter') !== 'true' ) {
      const _searchFilters = this.cacheService.get('searchFiltersAll');
      let _cacheFilters = {
        primaryCategory: [..._.intersection(filterData['primaryCategory'], _searchFilters['primaryCategory']), ..._.difference(filterData['primaryCategory'], _searchFilters['primaryCategory'])],
        se_boards: (_.get(filterData, 'se_boards') && filterData['se_boards'].length > 0) ? [_.union(_searchFilters['se_boards'], filterData['se_boards'])[0]] : [],
        se_mediums: [..._.intersection(filterData['se_mediums'], _searchFilters['se_mediums']), ..._.difference(filterData['se_mediums'], _searchFilters['se_mediums'])],
        se_gradeLevels: [..._.intersection(filterData['se_gradeLevels'], _searchFilters['se_gradeLevels']), ..._.difference(filterData['se_gradeLevels'], _searchFilters['se_gradeLevels'])],
        se_subjects: [..._.intersection(filterData['se_subjects'], _searchFilters['se_subjects']),
        ..._.difference(filterData['se_subjects'], _searchFilters['se_subjects'])].map((e) => { return _.startCase(e) }),
        selectedTab: _.get(this.activatedRoute, 'snapshot.queryParams.selectedTab') || 'all'
      };
      for (const key in _cacheFilters) {
        if (_cacheFilters[key] && _cacheFilters[key].length == 0) delete _cacheFilters[key];
      }
      this.cacheService.set('searchFiltersAll', this.selectedFilters, { expires: Date.now() + _cacheTimeout });
    } else if (!this.cacheService.exists('searchFiltersAll') && Object.keys(filterData).length > 0 && !_.get(filterData, 'key') 
    && _.get(this.activatedRoute, 'snapshot.queryParams.ignoreSavedFilter') !== 'true') {
      this.cacheService.set('searchFiltersAll', filterData, { expires: Date.now() + _cacheTimeout });
    } else {
      if(_.get(this.activatedRoute, 'snapshot.queryParams.ignoreSavedFilter') === 'true'){
      } else{
        this.cacheService.remove('searchFiltersAll');
      }
    }
    const defaultFilters = _.reduce(filters, (collector: any, element) => {
      if (element.code === 'board') {
        collector.board = _.get(_.orderBy(element.range, ['index'], ['asc']), '[0].name') || '';
      }
      return collector;
    }, {});
    this.dataDrivenFilterEvent.emit(defaultFilters);
  }

public viewAll(event) {
    this.moveToTop();
    this.logViewAllTelemetry(event);
     const searchQueryParams: any = {};
    searchQueryParams.defaultSortBy = JSON.stringify({ lastPublishedOn: 'desc' });
    searchQueryParams['exists'] = undefined;
    searchQueryParams['primaryCategory'] = (this.queryParams.primaryCategory && this.queryParams.primaryCategory.length)
     ? this.queryParams.primaryCategory : [event.name];
     (this.queryParams.primaryCategory && this.queryParams.primaryCategory.length) ? (searchQueryParams['subject'] = [event.name]) :
    (searchQueryParams['se_subjects'] = this.queryParams.se_subjects);
    searchQueryParams['selectedTab'] = 'all';
  if (this.queryParams.channel) {
    searchQueryParams['channel'] = this.queryParams.channel;
  }
    searchQueryParams['visibility'] = [];
    searchQueryParams['appliedFilters'] = true;
    const sectionUrl = '/resources' + '/view-all/' + event.name.replace(/\s/g, '-');
    this.router.navigate([sectionUrl, 1], { queryParams: searchQueryParams, state: {} });
 }

 public isUserLoggedIn(): boolean {
  return this.userService && (this.userService.loggedIn || false);
}

logViewAllTelemetry(event) {
  const telemetryData = {
      cdata: [{
          type: 'section',
          id: event.name
      }],
      edata: {
          id: 'view-all'
      }
  };
  this.getInteractEdata(telemetryData);
}

getInteractEdata(event) {
  const cardClickInteractData = {
      context: {
          cdata: event.cdata,
          env: this.isUserLoggedIn() ? 'library' : this.activatedRoute.snapshot.data.telemetry.env,
      },
      edata: {
          id: get(event, 'edata.id'),
          type: 'click',
          pageid: this.isUserLoggedIn() ? 'library' : this.activatedRoute.snapshot.data.telemetry.pageid
      },
      object: get(event, 'object')
  };
  this.telemetryService.interact(cardClickInteractData);
}

}

<app-landing-section *ngIf="allTabData" [textToDisplay]="resourceService?.frmelmnts?.tab?.all" [layoutConfiguration]="layoutConfiguration" [svgToDisplay]="allTabData?.theme?.imageName"></app-landing-section>
<div [ngClass]="layoutConfiguration ? 'sbt-fluid-content-bg sbt-home-search-component':''">
  <div class="sb-g" [ngClass]="layoutConfiguration ? 'sb-g sbt-container sbt-page-content' : 'sb-g'">
    <div [ngClass]="FIRST_PANEL_LAYOUT">
      <div *ngIf="layoutConfiguration">
        <ng-container *ngIf="isDesktopApp">
          <app-network-status></app-network-status>
          <app-load-offline-content></app-load-offline-content>
          <app-system-warning></app-system-warning>
        </ng-container>
      </div>
      <div [ngClass]="isDesktopApp ? 'sb-desktop-filter-section' : ''">
        <ng-container>
          <app-global-search-filter [layoutConfiguration]="layoutConfiguration" [facets]="facets" [isOpen]='true'
            *ngIf="initFilters && allTabData" (filterChange)="handleFilterChange($event)" [cachedFilters]="selectedFilters">
          </app-global-search-filter>
        </ng-container>
      </div>
    </div>
    <div [ngClass]="SECOND_PANEL_LAYOUT">
      <div [ngClass]="layoutConfiguration ? 'sbt-page-content-area' : 'ui container mt-16'">
  <div class="content-grid relative9" >
    <div class="sb-pageSection" *ngIf="!showLoader && contentList?.length && !showBackButton">
        <div  class="sb-pageSection-header mb-10">
                <h4 class="sb-pageSection-title mb-10 mr-5"> {{resourceService.frmelmnts?.lbl?.showingResults | translate}}
                    <span class="text-lowercase" *ngIf="this.queryParams.key" appHighlightText [config]="{'resourcePath': 'frmelmnts.lbl.forSearch', 'key': '{searchString}', 'value': queryParams?.key}"></span>
                      {{resourceService.frmelmnts?.lbl?.inAll | translate}}
                </h4>
            <button appTelemetryInteract [telemetryInteractEdata]="closeIntractEdata" *ngIf="showBackButton" class="sb-btn sb-btn-normal sb-btn-error ml-auto sb-cls-btn " type="button"  tabindex="0" (click)= "goback()">
              {{resourceService?.frmelmnts?.btn?.close | translate}} <i class="close icon"></i></button>
        </div>
    </div>
    <div class="twelve wide column">
      <app-global-search-selected-filter [facets]="facets" [selectedFilters]="selectedFilters"
              *ngIf="initFilters && facets && layoutConfiguration" (filterChange)="handleFilterChange($event)"></app-global-search-selected-filter>
      <div [appTelemetryImpression]="telemetryImpression"  *ngIf="!showLoader && contentList?.length"
        class="dynamic-section-card">
        <ng-container>
          <!-- <ng-container *ngFor="let data of contentList;let i = index;"> -->
            <div class="sb-grid mb-16">
              <div *ngFor="let content of contentList;let i = index;" [id]="i" [data]="content" class="sb-grid--item"
                [ngClass]="{'last mb-0':last}">
                <sb-library-card *ngIf="!isDesktopApp;else desktopCard" [indexToDisplay]="i"
                  [layoutConfig]="layoutConfiguration" appTelemetryInteract [telemetryInteractEdata]="cardIntractEdata"
                  [telemetryInteractObject]="{id:content.identifier,type:content.contentType || 'content',ver:content.pkgVersion ? content.pkgVersion.toString():'1.0'}"
                  (cardClick)="playContent($event)" (enterKey)="playContent($event)" [content]="content"
                  [cardImg]="content?.appIcon || 'assets/images/book.png'">
                </sb-library-card>
                <ng-template #desktopCard>
                  <div class="sb-desktop-library-card relative9">
                    <sb-library-card [indexToDisplay]="i" [layoutConfig]="layoutConfiguration" appTelemetryInteract
                      [telemetryInteractEdata]="cardIntractEdata"
                      [telemetryInteractObject]="{id:content.identifier,type:content.contentType || 'content',ver:content.pkgVersion ? content.pkgVersion.toString():'1.0'}"
                      [hover-template]="hoverTemplate" [content]="content"
                      [cardImg]="content?.appIcon || 'assets/images/book.png'">
                      <ng-template #hoverTemplate let-hoverData="hoverData" let-content="content">
                        <sb-card-hover class="card-hover" [content]="content" [hoverData]="hoverData"
                          (hoverActionClick)="hoverActionClicked($event)">
                        </sb-card-hover>
                      </ng-template>
                    </sb-library-card>
                  </div>
                </ng-template>
              </div>
            </div>
          <!-- </ng-container> -->
        </ng-container>
        <!-- <div *ngFor="let section of contentList; let last = last" [ngClass]="{'last mb-0':last}">
          <sb-library-cards-grid *ngIf="!isDesktopApp" [layoutConfig]="layoutConfiguration" [type]="'infinite_card_grid'"
            [title]="section.name" [contentList]="section.contents" [maxCardCount]="3" [viewMore]="true"
            (viewMoreClick)="viewAll(section)" (cardClick)="playContent($event, section.name)">
          </sb-library-cards-grid>
          <div class="sb-desktop-library-card relative9">
            <sb-library-cards-grid *ngIf="isDesktopApp" [layoutConfig]="layoutConfiguration" [type]="'infinite_card_grid_with_hover'" 
            [title]="section?.name" [contentList]="section.contents" [maxCardCount]="3" [viewMore]="true"
            (hoverActionClick)="hoverActionClicked($event)" (viewMoreClick)="viewAll(section)">
            </sb-library-cards-grid>
          </div>
        </div> -->
      </div>
    </div>
    <div class="twelve wide column" [appTelemetryImpression]="telemetryImpression" *ngIf="contentList?.length === 0 && !showLoader">
      <app-no-result [data]="noResultMessage"></app-no-result>
    </div>
    <div class="twelve wide column right aligned mt-16" *ngIf="paginationDetails.totalItems > configService.appConfig.SEARCH.PAGE_LIMIT && !showLoader">
      <div class="sb-pagination-container flex-jc-flex-end" *ngIf="paginationDetails.pages.length">
        <div class="sb-pagination my-0">
            <a role="button" title="{{resourceService?.frmelmnts?.lbl?.first}}" attr.aria-label="{{resourceService?.frmelmnts?.lbl?.first}}" [ngClass]="{disabled:paginationDetails.currentPage===1 }" class="sb-item " tabindex="0" (click)="navigateToPage(1) ">&laquo;</a>
            <a role="button" title="{{resourceService?.frmelmnts?.lbl?.previous}}" attr.aria-label="{{resourceService?.frmelmnts?.lbl?.previous}}" [ngClass]="{disabled:paginationDetails.currentPage===1 }" class="sb-item " tabindex="0" (click)="navigateToPage(paginationDetails.currentPage - 1)">&lt;</a>
            <a role=“button” aria-current=“page” title="{{page}}" attr.aria-label="{{page}}" *ngFor="let page of paginationDetails.pages" [ngClass]="{active:paginationDetails.currentPage===page}" tabindex="0" (click)="navigateToPage(page)" class="sb-item">{{page}}</a>
            <a role="button" title="{{resourceService?.frmelmnts?.lbl?.next}}" attr.aria-label="{{resourceService?.frmelmnts?.lbl?.next}}" [ngClass]="{disabled:paginationDetails.currentPage=== paginationDetails.totalPages}" tabindex="0" (click)="navigateToPage(paginationDetails.currentPage + 1)" class="sb-item">&gt;</a>
            <a role="button" title="{{resourceService?.frmelmnts?.lbl?.last}}" attr.aria-label="{{resourceService?.frmelmnts?.lbl?.last}}" [ngClass]="{disabled:paginationDetails.currentPage=== paginationDetails.totalPages}" tabindex="0" (click)="navigateToPage(paginationDetails.totalPages)" class="sb-item ">&raquo;</a>
        </div>
        
      </div>
    </div>
    <div class="twelve wide column" *ngIf="showLoader">
      <app-loader [data]='loaderMessage'></app-loader>
    </div>
  </div>
      </div>
    </div>
</div>
</div>
<app-batch-info *ngIf="showBatchInfo" [enrolledBatchInfo]="selectedCourseBatches" (modelClose)="showBatchInfo = false"></app-batch-info>

<app-modal-wrapper *ngIf="showModal" [config]="{disableClose: false}" (dismiss)="showModal = !showModal;">
  <ng-template sbModalContent>
    <div class="sb-modal">
      <div class="transition ui dimmer page modals active visible">
        <div class="ui modal transition active visible small">
          <button aria-label="close dialog" mat-dialog-close class="mat-close-btn">
            <span>&times;</span>
          </button>
          <div class="sb-modal-header">
            {{resourceService.frmelmnts?.btn?.download}}
          </div>
          <div class="sb-modal-content">
            <p>{{resourceService?.messages?.stmsg?.m0137 }}</p>
          </div>
          <div class="sb-modal-actions">
            <button class="sb-btn sb-btn-normal sb-btn-primary" tabindex="0"
              (click)="callDownload(); showModal = !showModal; logTelemetry(contentData, 'confirm-download-content');">
              {{resourceService.frmelmnts?.btn?.yes}}
            </button>
            <button class="sb-btn sb-btn-normal sb-btn-outline-primary" tabindex="0"
              (click)="showModal = !showModal; logTelemetry(contentData, 'cancel-download-content');">
              {{resourceService.frmelmnts?.btn?.cancel}}
            </button>
          </div>
        </div>
      </div>
    </div>
  </ng-template>
</app-modal-wrapper>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""