File

src/app/my-groups/activity-details/activity-details.page.ts

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods

Constructor

constructor(groupService: GroupService, headerService: AppHeaderService, router: Router, filterPipe: FilterPipe, commonUtilService: CommonUtilService, telemetryGeneratorService: TelemetryGeneratorService, location: Location, platform: Platform, collectionService: CollectionService, appGlobalService: AppGlobalService, file: File, permissionService: AndroidPermissionsService, fileOpener: FileOpener, appVersion: AppVersion)
Parameters :
Name Type Optional
groupService GroupService No
headerService AppHeaderService No
router Router No
filterPipe FilterPipe No
commonUtilService CommonUtilService No
telemetryGeneratorService TelemetryGeneratorService No
location Location No
platform Platform No
collectionService CollectionService No
appGlobalService AppGlobalService No
file File No
permissionService AndroidPermissionsService No
fileOpener FileOpener No
appVersion AppVersion No

Methods

Async checkForPermissions
checkForPermissions()
Returns : Promise<boolean | undefined>
convertToCSV
convertToCSV(memberList)
Parameters :
Name Optional
memberList No
Returns : any
Async downloadCsv
downloadCsv()
Returns : any
getMemberName
getMemberName(member)
Parameters :
Name Optional
member No
Returns : any
getMemberProgress
getMemberProgress(member)
Parameters :
Name Optional
member No
Returns : string
Private getNestedCourses
getNestedCourses(courseData)
Parameters :
Name Optional
courseData No
Returns : void
handleBackButton
handleBackButton(isNavBack)
Parameters :
Name Optional
isNavBack No
Returns : void
handleDeviceBackButton
handleDeviceBackButton()
Returns : void
handleHeaderEvents
handleHeaderEvents($event)
Parameters :
Name Optional
$event No
Returns : void
Async ionViewWillEnter
ionViewWillEnter()
Returns : any
ionViewWillLeave
ionViewWillLeave()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
Async ngOnInit
ngOnInit()
Returns : any
onMemberSearch
onMemberSearch(query)
Parameters :
Name Optional
query No
Returns : void
openActivityToc
openActivityToc()
Returns : void
openCsv
openCsv(path)
Parameters :
Name Optional
path No
Returns : void
openDashboard
openDashboard()
Returns : void
Private Async showStoragePermissionPopover
showStoragePermissionPopover()
Returns : Promise<boolean | undefined>

Properties

activity
Type : any
activityDetail
Type : any
appName
Type : string
corRelationList
Type : Array<CorrelationData>
courseData
Type : Content
courseList
Type : []
Default value : []
filteredMemberList
Type : any
group
Type : Group
Public groupService
Type : GroupService
Decorators :
@Inject('GROUP_SERVICE')
headerObservable
Type : any
isActivityLoading
Default value : false
isGroupCreatorOrAdmin
Default value : false
isTrackable
Default value : false
loggedinUser
Type : GroupMember
memberList
Type : any
memberSearchQuery
Type : string
searchMember
Type : string
Default value : ''
selectedCourse
showCourseDropdownSection
Default value : false
unregisterBackButton
Type : Subscription
import {
  Component, OnInit, Inject, OnDestroy
} from '@angular/core';
import { Router } from '@angular/router';
import { Location } from '@angular/common';
import { FilterPipe } from '@app/pipes/filter/filter.pipe';
import {
  CommonUtilService, PageId, Environment, AppHeaderService,
  ImpressionType, TelemetryGeneratorService,
  CollectionService, AppGlobalService, InteractSubtype, InteractType, ID, AndroidPermissionsService
} from '@app/services';
import {
  GroupService, GroupMember, Content,
  Group, MimeType, CorrelationData, TrackingEnabled
} from '@project-sunbird/sunbird-sdk';
import {
  CsGroupActivityAggregationMetric
} from '@project-sunbird/client-services/services/group/activity';
import { Platform } from '@ionic/angular';
import { Subscription } from 'rxjs';
import { RouterLinks } from './../../app.constant';
import { CsContentType } from '@project-sunbird/client-services/services/content';
import { File } from '@ionic-native/file/ngx';
import { AndroidPermission, AndroidPermissionsStatus } from '@app/services/android-permissions/android-permission';
import { FileOpener } from '@ionic-native/file-opener/ngx';
import { AppVersion } from '@ionic-native/app-version/ngx';
@Component({
  selector: 'app-activity-details',
  templateUrl: './activity-details.page.html',
  styleUrls: ['./activity-details.page.scss'],
})
export class ActivityDetailsPage implements OnInit, OnDestroy {

  corRelationList: Array<CorrelationData>;
  isActivityLoading = false;
  loggedinUser: GroupMember;
  headerObservable: any;
  unregisterBackButton: Subscription;
  searchMember = '';
  memberList: any;
  activityDetail: any;
  filteredMemberList: any;
  memberSearchQuery: string;
  group: Group;
  activity: any;
  courseList = [];
  showCourseDropdownSection = false;
  selectedCourse;
  courseData: Content;
  isTrackable = false;
  isGroupCreatorOrAdmin = false;
  appName: string;

  constructor(
    @Inject('GROUP_SERVICE') public groupService: GroupService,
    private headerService: AppHeaderService,
    private router: Router,
    private filterPipe: FilterPipe,
    private commonUtilService: CommonUtilService,
    private telemetryGeneratorService: TelemetryGeneratorService,
    private location: Location,
    private platform: Platform,
    private collectionService: CollectionService,
    private appGlobalService: AppGlobalService,
    private file: File,
    private permissionService: AndroidPermissionsService,
    private fileOpener: FileOpener,
    private appVersion: AppVersion
  ) {
    const extras = this.router.getCurrentNavigation().extras.state;
    this.loggedinUser = extras.loggedinUser;
    this.group = extras.group;
    this.activity = extras.activity;
    this.corRelationList = extras.corRelation;
    this.isTrackable = this.activity.trackable && (this.activity.trackable.enabled === TrackingEnabled.YES) ;
    this.isGroupCreatorOrAdmin = extras.isGroupCreatorOrAdmin;
  }

  async ngOnInit() {
    this.telemetryGeneratorService.generateImpressionTelemetry(
      ImpressionType.VIEW, '', PageId.ACTIVITY_DETAIL, Environment.GROUP,
      undefined, undefined, undefined, undefined, this.corRelationList);
      this.appName = await this.appVersion.getAppName();
  }

  async ionViewWillEnter() {
    this.headerService.showHeaderWithBackButton();
    this.headerObservable = this.headerService.headerEventEmitted$.subscribe(eventName => {
      this.handleHeaderEvents(eventName);
    });
    this.handleDeviceBackButton();
    this.courseList = [];
    try {
      this.courseData = await this.collectionService.fetchCollectionData(this.activity.identifier, this.activity.objectType);
      console.log('this.courseData', this.courseData);
      this.getNestedCourses(this.courseData.children);
      if (this.courseList.length) {
        this.showCourseDropdownSection = true;
      }
      console.log('this.courselist', this.courseList)
    } catch (err) {
      console.log('fetchCollectionData err', err);
    }
    this.selectedCourse = this.courseList.find((s) => s.identifier === this.appGlobalService.selectedActivityCourseId) || '';
  }

  ionViewWillLeave() {
    this.headerObservable.unsubscribe();
    if (this.unregisterBackButton) {
      this.unregisterBackButton.unsubscribe();
    }
  }

  ngOnDestroy() {
    this.appGlobalService.selectedActivityCourseId = '';
  }


  onMemberSearch(query) {
    this.memberSearchQuery = query;
    this.filteredMemberList = [...this.filterPipe.transform(this.memberList, 'name', query)];
  }

  getMemberName(member) {
    let memberName = member.name;
    if (this.loggedinUser.userId === member.userId) {
      memberName = this.commonUtilService.translateMessage('LOGGED_IN_MEMBER', { member_name: member.name });
    }
    return memberName;
  }

  getMemberProgress(member) {
    let progress = 0;
    if (member.agg) {
      const progressMetric = member.agg.find((agg) => agg.metric === CsGroupActivityAggregationMetric.PROGRESS);
      progress = progressMetric ? progressMetric.value : 0;
    }
    return '' + progress;
  }

  private getNestedCourses(courseData) {
    courseData.forEach(c => {
      if ((c.mimeType === MimeType.COLLECTION) && (c.contentType.toLowerCase() === CsContentType.COURSE.toLowerCase())) {
        this.courseList.push(c);
      }
      if (c.children && c.children.length) {
        this.getNestedCourses(c.children);
      }
    });
  }

  openActivityToc() {
    this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
      InteractSubtype.SELECT_NESTED_ACTIVITY_CLICKED, Environment.GROUP, PageId.ACTIVITY_DETAIL,
      undefined, undefined, undefined, this.corRelationList);

    this.router.navigate([`/${RouterLinks.MY_GROUPS}/${RouterLinks.ACTIVITY_DETAILS}/${RouterLinks.ACTIVITY_TOC}`],
      {
        state: {
          courseList: this.courseList,
          mainCourseName: this.activity.name,
          corRelation: this.corRelationList
        }
      });
  }

  handleDeviceBackButton() {
    this.unregisterBackButton = this.platform.backButton.subscribeWithPriority(10, () => {
      this.handleBackButton(false);
    });
  }

  handleHeaderEvents($event) {
    if($event.name === 'back')
    {
      this.handleBackButton(true);
    }
  }

  handleBackButton(isNavBack) {
    this.telemetryGeneratorService.generateBackClickedTelemetry(PageId.ACTIVITY_DETAIL,
      Environment.GROUP, isNavBack, undefined, this.corRelationList);
    this.location.back();
  }

  convertToCSV(memberList) {
    let csv: any = '';
    let line: any = '';

    memberList.forEach(member => {
      let progress = 0;
      if (member.agg) {
        const progressMetric = member.agg.find((agg) => agg.metric === CsGroupActivityAggregationMetric.PROGRESS);
        progress = progressMetric ? progressMetric.value : 0;
      }
      member.progress = progress;
    });
    console.log('memberList progress', this.memberList)
    line += 'Course name' + ',';
    line += 'Member name' + ',';
    line += 'Progress' + '\n';
    line += '\n';
    for (let j = 0; j < memberList.length; j++) {
      line += '\"' + this.courseData.name.trim() + '\"' + ',';
      line += '\"' + memberList[j].name + '\"' + ',';
      line += '\"' + memberList[j].progress + '%\"' + '\n';
    }
    csv += line + '\n';
    return csv;

  }

  async downloadCsv() {
    await this.checkForPermissions().then(async (result) => {
      if (result) {
        this.telemetryGeneratorService.generateInteractTelemetry(
          InteractType.TOUCH,
          InteractSubtype.DOWNLOAD_CLICKED,
          Environment.USER,
          PageId.ACTIVITY_DETAIL
        );
        const expTime = new Date().getTime();
        const csvData: any = this.convertToCSV(this.memberList);
        const filename = this.courseData.name.trim() + '_' + expTime + '.csv';
        const folderPath = this.platform.is('ios') ? cordova.file.documentsDirectory : cordova.file.externalRootDirectory 
        const downloadDirectory = `${folderPath}Download/`;
        
        this.file.writeFile(downloadDirectory, filename, csvData, {replace: true})
        .then((res)=> {
          console.log('rs write file', res);
          this.openCsv(res.nativeURL)
          this.commonUtilService.showToast(this.commonUtilService.translateMessage('DOWNLOAD_COMPLETED', filename), false, 'custom-toast');
        })
        .catch((err) => {
          console.log('writeFile err', err)
        });
      } else{
        this.commonUtilService.showSettingsPageToast('FILE_MANAGER_PERMISSION_DESCRIPTION', this.appName, PageId.ACTIVITY_DETAIL, true);
      }
    });
    
  }

  async checkForPermissions(): Promise<boolean | undefined> {
    if(this.platform.is('ios')) {
      return new Promise<boolean | undefined>(async (resolve, reject) => {
        resolve(true);
      });
    }
    return new Promise<boolean | undefined>(async (resolve) => {
      const permissionStatus = await this.commonUtilService.getGivenPermissionStatus(AndroidPermission.WRITE_EXTERNAL_STORAGE);
      if (permissionStatus.hasPermission) {
        resolve(true);
      } else if (permissionStatus.isPermissionAlwaysDenied) {
        await this.commonUtilService.showSettingsPageToast('FILE_MANAGER_PERMISSION_DESCRIPTION', this.appName, PageId.PROFILE, true);
        resolve(false);
      } else {
        this.showStoragePermissionPopover().then((result) => {
          if (result) {
            resolve(true);
          } else {
            resolve(false);
          }
        });
      }
    });
  }

  private async showStoragePermissionPopover(): Promise<boolean | undefined> {
    return new Promise<boolean | undefined>(async (resolve) => {
      const confirm = await this.commonUtilService.buildPermissionPopover(
        async (selectedButton: string) => {
          if (selectedButton === this.commonUtilService.translateMessage('NOT_NOW')) {
            this.telemetryGeneratorService.generateInteractTelemetry( InteractType.TOUCH, InteractSubtype.NOT_NOW_CLICKED, Environment.SETTINGS, PageId.PERMISSION_POPUP);
            await this.commonUtilService.showSettingsPageToast('FILE_MANAGER_PERMISSION_DESCRIPTION', this.appName, PageId.PROFILE, true);
          } else if (selectedButton === this.commonUtilService.translateMessage('ALLOW')) {
            this.telemetryGeneratorService.generateInteractTelemetry(
              InteractType.TOUCH,
              InteractSubtype.ALLOW_CLICKED,
              Environment.SETTINGS,
              PageId.PERMISSION_POPUP);
            this.permissionService.requestPermission(AndroidPermission.WRITE_EXTERNAL_STORAGE).subscribe(async (status: AndroidPermissionsStatus) => {
                if (status.hasPermission) {
                  this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH, InteractSubtype.ALLOW_CLICKED, Environment.SETTINGS, PageId.APP_PERMISSION_POPUP);
                  resolve(true);
                } else if (status.isPermissionAlwaysDenied) {
                  await this.commonUtilService.showSettingsPageToast
                    ('FILE_MANAGER_PERMISSION_DESCRIPTION', this.appName, PageId.PROFILE, true);
                  resolve(false);
                } else {
                  this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH, InteractSubtype.DENY_CLICKED, Environment.SETTINGS, PageId.APP_PERMISSION_POPUP);
                  await this.commonUtilService.showSettingsPageToast('FILE_MANAGER_PERMISSION_DESCRIPTION', this.appName, PageId.PROFILE, true);
                }
                resolve(undefined);
              });
          }
        }, this.appName, this.commonUtilService.translateMessage('FILE_MANAGER'), 'FILE_MANAGER_PERMISSION_DESCRIPTION', PageId.PROFILE, true
      );
      await confirm.present();
    });
  }

  openCsv(path) {
    this.fileOpener.open(path, 'text/csv')
      .then(() => console.log('File is opened'))
      .catch((e) => {
        console.log('Error opening file', e);
        this.commonUtilService.showToast('CERTIFICATE_ALREADY_DOWNLOADED');
      });
  }
  
  openDashboard() {
    this.telemetryGeneratorService.generateInteractTelemetry(
      InteractType.SELECT_ACTIVITY_DASHBOARD,
      undefined,
      Environment.GROUP,
      PageId.ACTIVITY_DETAIL,
      undefined,
      undefined,
      undefined,
      this.corRelationList,
      ID.SELECT_ACTIVITY_DASHBOARD
    );
  }

}
<ion-content>
  <div class="ad-container" tabindex="0">
    <div class="ad-card-container">
      <ion-icon src="assets/imgs/dashboard-icon.svg" class="dashboard-icon" *ngIf="activityDetail && isTrackable" (click)="openDashboard()"></ion-icon>
      <sb-course-card *ngIf="isTrackable" [section]="null"
        [cardImg]="commonUtilService.getContentImg(activity)" [course]="activity">
      </sb-course-card>
      <sb-library-card *ngIf="!isTrackable" [content]="activity" [type]="'mobile_textbook'" (click)="onActivityCardClick($event, activity)"
        [cardImg]="commonUtilService.getContentImg(activity)" [isMenu]="false"
        (menuClick)="activityMenuClick($event, activity, i)">
      </sb-library-card>
    </div>
    <div class="ad-member-container" tabindex="0">
      <div class="ad-note" *ngIf="!isTrackable">
        <span>{{'NOTE' | translate}} :</span>
        {{'PROGRESS_CANNOT_BE_TRACKED' | translate: {'collectionType': activity.type } }}
      </div>
      <div class="font-14" *ngIf="showCourseDropdownSection" tabindex="0">
        <div class="activity-toc clearfix" (click)="openActivityToc()" tabindex="0">
          <span class="pull-left">{{selectedCourse?.name || activity?.name}}</span>
          <div class="activity-toc-change pull-right">{{'CHANGE' | translate}}</div>
        </div>
      </div>
      <div class="gd-member-search" tabindex="0">
        <ion-icon class="gd-member-search-icon" md="md-search"></ion-icon>
        <input type="text" [(ngModel)]="searchMember" (ngModelChange)="onMemberSearch(searchMember)"
          placeholder="{{'SEARCH_FOR_GROUP_MEMBER' | translate}}">
      </div>
      <div class="ad-timestamp-container" tabindex="0">
        <div *ngIf="isTrackable && isGroupCreatorOrAdmin && (!showCourseDropdownSection || (!selectedCourse || (selectedCourse?.name === activity?.name)))" (click)="downloadCsv()" tabindex="0">
          <span class="ad-dw-csv">{{'DOWNLOAD_CSV' | translate}}</span>
          <img src="assets/imgs/download-icon.svg" alt="download-scv">
        </div>
      </div>
     

      <div class="ad-mebers-container" tabindex="0">
        <div *ngIf="isActivityLoading">
          <div *ngFor="let item of [0,1,2,3,4,5,6,7,8,9]">
            <sb-member-card [isLoading]="true"
              [config]="{size:'medium', isBold:false, isSelectable:false, view:'horizontal'}"></sb-member-card>
          </div>
        </div>
        <div *ngIf="!isActivityLoading" tabindex="0">
          <div *ngFor="let member of filteredMemberList; let i = index" tabindex="0">
            <sb-member-card *ngIf="isTrackable" [config]="{size:'medium', isBold:false, isSelectable:false, view:'horizontal'}"
              [identifier]="member.userId" [indexOfMember]="i" [initial]="member.name | initial"
              [title]="getMemberName(member)" [progressDisplay]="getMemberProgress(member)">
            </sb-member-card>
            <sb-member-card *ngIf="!isTrackable" [config]="{size:'medium', isBold:false, isSelectable:false, view:'horizontal'}"
              [identifier]="member.userId" [indexOfMember]="i" [initial]="member.name | initial"
              [title]="getMemberName(member)">
            </sb-member-card>
          </div>
        </div>
        <div
          *ngIf="(!isActivityLoading && !filteredMemberList) || (!isActivityLoading && filteredMemberList?.length <= 1)"
          class="text-center">
          <div class="ad-empty-result" *ngIf="!memberSearchQuery">
            <img src="assets/imgs/no_member.svg" alt="no-member">
          </div>
          <div class="ad-empty-result" *ngIf="memberSearchQuery && !filteredMemberList?.length">
            <img src="assets/imgs/empty_search_result.svg" alt="no-result">
            <p>{{'EMPTY_SEARCH_RESULT_GROUPS' | translate}}</p>
          </div>
        </div>
      </div>
    </div>
  </div>

</ion-content>

./activity-details.page.scss

@import "src/assets/styles/_variables.scss";
.ad-container{
    padding: 16px;
}
.ad-card-container{
    padding-bottom: 16px;
}
.ad-member-container{
    box-shadow: 0 2px 7px 0 rgba(0,0,0,0.25);
}
.gd-member-search {
    position: relative;
    margin: 0 0 8px 0;
    padding: 0 8px;
    padding-top: 16px;
    .gd-member-search-icon {
        position: absolute;
        font-size: 1.25rem;
        color: $gray-400;
        top: 1.5rem;
        left: 1rem;
    }
    input {
        width: 100%;
        height: 2.188rem;
        padding: 0 8px 0 30px;
        border: 1px solid $blue;
        border-radius: 4px;
    }
}
.ad-courses-container {
    margin-top: 8px;
    padding: 8px;
    .ad-courses{
        color: $blue;
        .ad-course-text{
            font-weight: bold;
        }
    }
    .ad-course-name{
        padding: 0 4px;
    }
}
.ad-timestamp-container{
    padding: 8px;
    display: flex;
    justify-content: space-between;
    .ad-dw-csv{
        color: $blue;
        font-weight: bold;
    }
    .ad-timestamp{
        color: $gray-300;
    }
}
.ad-mebers-container{
    min-height: calc(100vh - 215px);
}
.ad-empty-result{
    img{
        max-width: 65%;
        margin-top: 20%;
        margin-bottom: 16px;
        font-size: 1rem;
    }
}
.activity-toc {
    background-color: $blue;
    color: map-get($colors, white);
    padding: 8px;
    border-top-right-radius: 4px;
    border-top-left-radius: 4px;

    .pull-left {
        position: relative;
        top: 0.375rem;
    }
    .activity-toc-change{
        color: $blue;
        border-radius: 15px;
        padding: 8px 16px;
        font-size: $font-size-base;
        background-color: map-get($colors, white);
        line-height: 0.938rem;
    }
}
.ad-note{
    padding: 8px 8px 0 8px;
    span{
        color: map-get($colors, vivid_red);
    }
}
.dashboard-icon{
    position: absolute;
    top: 3.125rem;
    right: 1.875rem;
    z-index: 9;
    font-size: 1.5rem;
}
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""