File

src/app/modules/sourcing/components/mvc-library/mvc-library.component.ts

Metadata

selector app-mvc-library
styleUrls mvc-library.component.scss
templateUrl mvc-library.component.html

Constructor

constructor(programTelemetryService: ProgramTelemetryService, telemetryService: any, contentService: any, configService: any, actionService: any, sourcingService: SourcingService, programsService: any, toasterService: any, route: ActivatedRoute, router: Router, resourceService: any, userService: any, navigationHelperService: any)

Methods

prepareTelemetryEvents
prepareTelemetryEvents()
Returns: void
getPageId
getPageId()
Returns: void
initialize
initialize()
Returns: void
getCollectionHierarchy
getCollectionHierarchy(identifier: string)
Returns: void
getProgramDetails
getProgramDetails()
Returns: void
getUnitWithChildren
getUnitWithChildren(data: any, collectionId: any)
Returns: void
generateNodeMeta
generateNodeMeta(node: any)
Returns: void
prepareFilterData
prepareFilterData()
Returns: void
fetchContentFacets
fetchContentFacets()
Returns: void
fetchContentList
fetchContentList()
Returns: void
filterContentList
filterContentList(selectedContentId: any)
Returns: void
plusMinusGradeLevel
plusMinusGradeLevel(gradeLevel: any[])
Returns: void
openFilter
openFilter()
Returns: void
onContentChange
onContentChange(event: any)
Returns: void
onFilterChange
onFilterChange(event: any)
Returns: void
showResourceTemplate
showResourceTemplate(event: any)
Returns: void
Public logTelemetryImpressionEvent
logTelemetryImpressionEvent(visits: any)
Returns: void
getParentsHelper
getParentsHelper(tree: any, id: string, parents: any[])
Returns: void
generateParentLevel
generateParentLevel(tree: any, parents: any)
Returns: void
getNameAndConceptOfSelectedUnit
getNameAndConceptOfSelectedUnit(data: any[], id: string)
Returns: void
handleBack
handleBack()
Returns: void

Properties

Public activeFilterData
activeFilterData: any
Public childNodes
childNodes: any
Public collectionData
collectionData: any
Public collectionHierarchy
collectionHierarchy: any[]
Public collectionId
collectionId: string
Public collectionUnitId
collectionUnitId: string
configService
configService: any
Public contentList
contentList: any
Public filterData
filterData: any
Public isFilterOpen
isFilterOpen: Boolean
Default value: false
Private onComponentDestroy$
onComponentDestroy$: Subject<any>
Public programDetails
programDetails: any
Public programId
programId: string
programTelemetryService
programTelemetryService: ProgramTelemetryService
Public resourceReorderBreadcrumb
resourceReorderBreadcrumb: any
resourceService
resourceService: any
Public selectedContentDetails
selectedContentDetails: string
Public selectedContentId
selectedContentId: any
Public selectedUnitName
selectedUnitName: string
Public sessionContext
sessionContext: any
Public showAddedContent
showAddedContent: Boolean
Default value: true
Public showLargeModal
showLargeModal: Boolean
Default value: false
Public showLoader
showLoader: Boolean
Default value: false
Public showSelectResourceModal
showSelectResourceModal: Boolean
Default value: false
Public skeletonLoader
skeletonLoader: Boolean
Default value: false
Public telemetryImpression
telemetryImpression: any
Public telemetryPageId
telemetryPageId: string
Public uniqueId
uniqueId: string
import { Component, OnInit, AfterViewInit, OnDestroy } from '@angular/core';
import { ActivatedRoute, Router, ParamMap } from '@angular/router';
import * as _ from 'lodash-es';
import { v4 as UUID } from 'uuid';
import { catchError, map, finalize, tap } from 'rxjs/operators';
import { throwError, forkJoin, Subject} from 'rxjs';
import { TelemetryService, IImpressionEventInput} from '@sunbird/telemetry';
import { ContentService, ActionService, ProgramsService, UserService } from '@sunbird/core';
import { ConfigService, ToasterService, ResourceService, NavigationHelperService } from '@sunbird/shared';
import { ProgramTelemetryService } from '../../../program/services';
import { SourcingService } from '../../services';

@Component({
  selector: 'app-mvc-library',
  templateUrl: './mvc-library.component.html',
  styleUrls: ['./mvc-library.component.scss']
})
export class MvcLibraryComponent implements OnInit, AfterViewInit, OnDestroy {

  public telemetryImpression: IImpressionEventInput;
  public sessionContext: any;
  public selectedContentId : any;
  public showSelectResourceModal: Boolean = false;
  public isFilterOpen: Boolean = false;
  public showLargeModal : Boolean = false;
  public showLoader: Boolean = false;
  public skeletonLoader: Boolean = false;
  public selectedContentDetails: string;
  public contentList: any = [];
  public collectionId: string;
  public collectionUnitId: string;
  public selectedUnitName: string;
  public collectionData: any;
  public collectionHierarchy = [];
  public childNodes: any;
  public programId: string;
  public programDetails: any;
  public resourceReorderBreadcrumb: any = [];
  public filterData: any = {};
  public activeFilterData: any = {};
  public showAddedContent: Boolean = true;
  public uniqueId: string;
  public telemetryPageId: string;
  private onComponentDestroy$ = new Subject<any>();

  constructor(
    public programTelemetryService: ProgramTelemetryService, private telemetryService: TelemetryService,
    private contentService: ContentService, public configService: ConfigService, private actionService: ActionService,
    private sourcingService: SourcingService, private programsService: ProgramsService,
    private toasterService: ToasterService, private route: ActivatedRoute, private router: Router, public resourceService: ResourceService,
    private userService: UserService, private navigationHelperService: NavigationHelperService,
  ) { }

  ngOnInit() {
    this.uniqueId = UUID();
    this.route.paramMap.subscribe((params: ParamMap) => {
      this.collectionId = params.get('collectionId');
      this.collectionUnitId = params.get('collectionUnitId');
      this.programId = params.get('programId');
      this.showLoader = true;
      this.prepareTelemetryEvents();
      this.initialize();
    });
  }

  ngOnDestroy() {
    this.onComponentDestroy$.next();
    this.onComponentDestroy$.complete();
  }

  prepareTelemetryEvents() {
    this.sessionContext = {
      'collection': this.collectionId,
      'programId': this.programId,
      'collectionUnitId': this.collectionUnitId
    };
    this.sessionContext.telemetryPageId = this.getPageId();
     this.sessionContext.telemetryInteractCdata = [
      {id: this.userService.channel, type: 'sourcing_organization'},
      {id: this.programId, type: 'project'},
      {id: this.uniqueId, type: 'content-reuse'},
      {id: this.collectionId, type: 'linked_collection'}];
     // tslint:disable-next-line:max-line-length
     this.sessionContext.telemetryInteractPdata = this.programTelemetryService.getTelemetryInteractPdata(this.userService.appId, this.configService.appConfig.TELEMETRY.PID );
  }

  ngAfterViewInit() {
    const buildNumber = (<HTMLInputElement>document.getElementById('buildNumber'));
    const version = buildNumber && buildNumber.value ? buildNumber.value.slice(0, buildNumber.value.lastIndexOf('.')) : '1.0';
    // tslint:disable-next-line:max-line-length
    const telemetryCdata = [{ 'type': 'project', 'id': this.programId }, { 'type': 'content-reuse', 'id': this.uniqueId }];
    setTimeout(() => {
      this.telemetryImpression = {
        context: {
          env: this.route.snapshot.data.telemetry.env,
          cdata: this.sessionContext.telemetryInteractCdata || [],
          pdata: {
            id: this.userService.appId,
            ver: version,
            pid: `${this.configService.appConfig.TELEMETRY.PID}`
          }
        },
        edata: {
          type: _.get(this.route, 'snapshot.data.telemetry.type'),
          pageid: this.getPageId(),
          uri: this.userService.slug.length ? `/${this.userService.slug}${this.router.url}` : this.router.url,
          duration: this.navigationHelperService.getPageLoadTime(),
          visits: [],
        }
      };
    });
  }

  getPageId() {
    this.telemetryPageId = _.get(this.route, 'snapshot.data.telemetry.pageid');
    return this.telemetryPageId;
  }


  initialize() {
    forkJoin([this.getCollectionHierarchy(this.collectionId), this.getProgramDetails()]).subscribe(
      ([collection, programDetails]) => {
        this.collectionData = collection;
        this.childNodes = _.get(this.collectionData, 'childNodes');
        this.resourceReorderBreadcrumb.push(this.collectionData.name);
        this.collectionHierarchy = this.getUnitWithChildren(this.collectionData, this.collectionId);
        this.programDetails = _.get(programDetails, 'result');
        this.prepareFilterData();
        this.fetchContentFacets();
      }, (error) => {
        this.showLoader = false;
        const errorMes = typeof _.get(error, 'error.params.errmsg') === 'string' && _.get(error, 'error.params.errmsg');
        this.toasterService.error(errorMes || 'Fetching textbook details failed. Please try again...');
        this.handleBack();
      });
  }

  getCollectionHierarchy(identifier: string) {

    const hierarchyUrl = `${this.configService.urlConFig.URLS.COLLECTION.HIERARCHY_GET_NEW}/${identifier}`;
    const req = {
      url: hierarchyUrl,
      param: { 'mode': 'edit' }
    };
    return this.actionService.get(req).pipe(map((data: any) => data.result.content));
  }

  getProgramDetails() {
    const req = {
      url: `program/v1/read/${this.programId}`
    };
    return this.programsService.get(req);
  }

  getUnitWithChildren(data, collectionId) {
    const self = this;
    const childData = data.children;
    if (_.isEmpty(childData)) { return []; }
    const tree = childData.map(child => {
      if (child.identifier === this.collectionUnitId) {
        this.selectedUnitName = child.name;
      }
      const treeItem = this.generateNodeMeta(child);
      const treeUnit = self.getUnitWithChildren(child, collectionId);
      const treeChildren = treeUnit && treeUnit.filter(item => item.contentType === 'TextBookUnit');
      treeItem['children'] = (treeChildren && treeChildren.length > 0) ? treeChildren : null;
      return treeItem;
    });
    return tree;
  }

  generateNodeMeta(node) {
    const nodeMeta = {
      identifier: node.identifier,
      name: node.name,
      contentType: node.contentType,
      topic: node.topic,
      status: node.status,
      creator: node.creator,
      createdBy: node.createdBy || null,
      parentId: node.parent || null,
      organisationId: _.has(node, 'organisationId') ? node.organisationId : null,
      prevStatus: node.prevStatus || null,
    };
    return nodeMeta;
  }

  prepareFilterData(): void {
    this.filterData['medium'] = this.collectionData.medium;
    this.filterData['subject'] = this.collectionData.subject;
    this.filterData['gradeLevel'] = this.plusMinusGradeLevel(this.collectionData.gradeLevel);
    this.filterData['contentType'] =  this.programDetails.targetprimarycategories ?
    _.map(this.programDetails.targetprimarycategories, 'name') : this.programDetails.content_types;
    if (_.isEmpty(this.activeFilterData)) { this.activeFilterData = _.cloneDeep(this.filterData); }
    const textbookLevel = this.getNameAndConceptOfSelectedUnit(this.collectionHierarchy, this.collectionUnitId);
    this.activeFilterData = _.assign(this.activeFilterData, ...textbookLevel);
  }

  fetchContentFacets() {
    const option = {
      url: this.configService.urlConFig.URLS.DOCKCONTENT_MVC.SEARCH,
      data: {
        request: {
          'filters': _.omit(this.activeFilterData, ['contentType']),
          'limit': 0,
          'facets': ['level1Name']
        }
      }
    };
    this.contentService.post(option).pipe(
      finalize(() => {
        this.showLoader = false;
      }),
      map((data: any) => data.result.facets))
      .subscribe((result: any) => {
        const level1Name = _.find(result, { name: 'level1Name' });
        this.filterData['chapter'] = _.map(level1Name['values'], 'name');
        // this.activeFilterData['chapter'] = _.cloneDeep(this.filterData['chapter']);
        this.fetchContentList();
      });
  }

  fetchContentList() {
    this.skeletonLoader = true;
    const option = {
      url: this.configService.urlConFig.URLS.DOCKCONTENT_MVC.SEARCH,
    data: {
      request: {
        'filters': {
          'textbook_name': this.collectionData.name,
          'status': [
            'live'
          ],
          ..._.pick(this.activeFilterData, ['medium', 'subject', 'gradeLevel', 'contentType']),
          'level1Name' : this.activeFilterData.chapter ? _.get(this.activeFilterData, 'chapter') : undefined
        }
      }
    }
    };
    this.contentService.post(option).pipe(catchError(err => {
      const errInfo = {
        errorMsg: 'Fetching content list failed',
        telemetryPageId: this.telemetryPageId, telemetryCdata : this.sessionContext.telemetryInteractCdata,
        env : this.route.snapshot.data.telemetry.env, request: option };
      return throwError(this.sourcingService.apiErrorHandling(err, errInfo));
    }),
      finalize(() => {
        this.skeletonLoader = false;
        if (_.isEmpty(this.contentList)) { this.openFilter(); }
      }),
      map((data: any) => data.result.content ? data.result.content : []))
      .subscribe((result: any) => {
        this.contentList = result;
        this.filterContentList();
      });
  }

  filterContentList(selectedContentId?) {
    if (_.isEmpty(this.contentList)) { return; }
    _.forEach(this.contentList, (value, key) => {
      value.isAdded = _.includes(this.childNodes, value.identifier);
    });
    if (selectedContentId) {
      this.selectedContentDetails = _.pick(
        _.find(this.contentList, { 'identifier': selectedContentId }), ['name', 'identifier', 'isAdded']
      );
    } else {
      const selectedContentIndex = this.showAddedContent ? 0 : _.findIndex(this.contentList, { 'isAdded': false });
      this.selectedContentDetails = _.pick(this.contentList[selectedContentIndex], ['name', 'identifier', 'isAdded']);
    }
  }

  plusMinusGradeLevel(gradeLevel: Array<any>) {
    if (_.isEmpty(gradeLevel)) { return []; }
    const gradeLevelTemp: any = [...gradeLevel];
    _.forEach(gradeLevel, (value, key) => {
      value = _.head(_.map(value.match(/\d+/g), _.parseInt));  // Extract a number from a string
      if (value === 1) {
        gradeLevelTemp.push(`Class ${value + 1}`);
      } else if (value === 12) {
        gradeLevelTemp.push(`Class ${value - 1}`);
      } else if (value > 1 && value < 12) {
        gradeLevelTemp.push(`Class ${value + 1}`);
        gradeLevelTemp.push(`Class ${value - 1}`);
      }
    });
    return _.uniq(gradeLevelTemp);
  }

  openFilter(): void {
    window.scrollTo({
      top: 0,
      left: 0,
      behavior: 'smooth'
    });
    this.isFilterOpen = true;
  }

  onContentChange(event: any) {
    this.selectedContentDetails = _.pick(event.content, ['name', 'identifier', 'isAdded']);
  }

  onFilterChange(event: any) {
    if (event.action === 'filterDataChange') {
      this.activeFilterData = _.omitBy(_.assign(this.activeFilterData, event.filters), v => _.isEmpty(v));
      this.uniqueId = UUID();
      this.prepareTelemetryEvents();
      this.fetchContentList();
    } else if (event.action === 'filterStatusChange') {
      this.isFilterOpen = event.filterStatus;
    }
  }

  showResourceTemplate(event) {
    switch (event.action) {
      case 'beforeMove':
        this.sessionContext['selectedMvcContentDetails'] = this.selectedContentDetails;
        this.sessionContext['resourceReorderBreadcrumb'] = this.resourceReorderBreadcrumb;
        this.showSelectResourceModal = true;
        break;
      case 'afterMove':
        this.showSelectResourceModal = false;
        this.childNodes.push(event.contentId);
        this.filterContentList(this.showAddedContent ? event.contentId : undefined);
        break;
      case 'cancelMove':
        this.showSelectResourceModal = false;
        break;
      case 'showFilter':
        this.openFilter();
        break;
      case 'showAddedContent':
        this.showAddedContent = event.status;
        this.filterContentList();
        break;
      case 'contentVisits':
        this.logTelemetryImpressionEvent(event.visits);
        break;
      default:
        break;
    }
  }

  public logTelemetryImpressionEvent(visits) {
    const telemetryImpression = _.cloneDeep(this.telemetryImpression);
    telemetryImpression.edata.visits = visits;
    this.telemetryService.impression(telemetryImpression);
  }

  getParentsHelper(tree: any, id: string, parents: Array<any>) {
    const self = this;
    if (tree.identifier === id) {
      return {
        found: true,
        parents: [...parents, this.generateParentLevel(tree, parents)]
      };
    }
    let result = {
      found: false,
    };
    if (tree.children) {
      _.forEach(tree.children, (subtree, key) => {
        const maybeParents = _.concat([], parents);
        if (tree.identifier !== undefined) {
          maybeParents.push(this.generateParentLevel(tree, maybeParents));
        }
        const maybeResult: any = self.getParentsHelper(subtree, id, maybeParents);
        if (maybeResult.found) {
          result = maybeResult;
          return false;
        }
      });
    }
    return result;
  }

  generateParentLevel(tree, parents) {
    const obj = {};
    const index = parents.length + 1;
    obj[`level${index}Name`] = {
      value: tree.name
    };
    if (!_.isEmpty(tree.topic)) {
      obj[`level${index}Concept`] = {
        value: tree.topic
      };
    }
    return obj;
  }

  getNameAndConceptOfSelectedUnit(data: Array<any>, id: string) {
    const tree = {
      children: data
    };
    const result: any = this.getParentsHelper(tree, id, []);
    if (result.found) {
      return result.parents;
    } else {
      return [];
    }
  }

  handleBack() {
    this.programsService.setMvcStageData({
      collection: this.collectionData,
      lastOpenedUnitId: this.collectionUnitId
    });
    this.router.navigateByUrl(`/contribute/program/${this.programId}`);
  }

}

results matching ""

    No results matching ""