src/app/profile/profile.page.ts
OnInit
providers |
CertificateDownloadAsPdfService
|
selector | app-profile |
styleUrls | ./profile.page.scss |
templateUrl | ./profile.page.html |
constructor(profileService: ProfileService, authService: AuthService, contentService: ContentService, courseService: CourseService, formService: FormService, frameworkService: FrameworkService, certificateService: CertificateService, zone: NgZone, router: Router, popoverCtrl: PopoverController, events: Events, appGlobalService: AppGlobalService, telemetryGeneratorService: TelemetryGeneratorService, formAndFrameworkUtilService: FormAndFrameworkUtilService, commonUtilService: CommonUtilService, socialSharing: SocialSharing, headerService: AppHeaderService, permissionService: AndroidPermissionsService, appVersion: AppVersion, navService: NavigationService, sbProgressLoader: SbProgressLoader, fileOpener: FileOpener, toastController: ToastController, translate: TranslateService, certificateDownloadAsPdfService: CertificateDownloadAsPdfService, profileHandler: ProfileHandler, segmentationTagService: SegmentationTagService, platform: Platform, locationHandler: LocationHandler, unnatiDataService: UnnatiDataService)
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Defined in src/app/profile/profile.page.ts:163
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Parameters :
|
Private Async callOTPPopover | ||||||||||||||||
callOTPPopover(type: string, key?: any, updateContact: boolean)
|
||||||||||||||||
Defined in src/app/profile/profile.page.ts:874
|
||||||||||||||||
Parameters :
Returns :
unknown
|
Private Async checkForPermissions |
checkForPermissions()
|
Defined in src/app/profile/profile.page.ts:1063
|
Returns :
Promise<boolean | undefined>
|
Private dismissMessage |
dismissMessage()
|
Defined in src/app/profile/profile.page.ts:988
|
Returns :
void
|
Async doRefresh | ||||
doRefresh(refresher?)
|
||||
Defined in src/app/profile/profile.page.ts:256
|
||||
Parameters :
Returns :
unknown
|
downloadCertificate | ||||||
downloadCertificate(data, type?)
|
||||||
Defined in src/app/profile/profile.page.ts:590
|
||||||
Parameters :
Returns :
void
|
Private Async downloadLegacyCertificate | ||||||
downloadLegacyCertificate(course, toast)
|
||||||
Defined in src/app/profile/profile.page.ts:670
|
||||||
Parameters :
Returns :
any
|
Async downloadTrainingCertificate | ||||||
downloadTrainingCertificate(course: literal type)
|
||||||
Defined in src/app/profile/profile.page.ts:617
|
||||||
Parameters :
Returns :
any
|
Async editEmail |
editEmail()
|
Defined in src/app/profile/profile.page.ts:813
|
Returns :
any
|
Async editMobileNumber |
editMobileNumber()
|
Defined in src/app/profile/profile.page.ts:799
|
Returns :
any
|
Async editRecoveryId |
editRecoveryId()
|
Defined in src/app/profile/profile.page.ts:1015
|
Returns :
any
|
formatRoles |
formatRoles()
|
Defined in src/app/profile/profile.page.ts:384
|
Method to store all roles from different organizations into single array
Returns :
void
|
Private getCategories |
getCategories()
|
Defined in src/app/profile/profile.page.ts:1276
|
Returns :
void
|
Async getEnrolledCourses | ||||||
getEnrolledCourses(refresher?, refreshCourseList?)
|
||||||
Defined in src/app/profile/profile.page.ts:474
|
||||||
To get enrolled course(s) of logged-in user i.e, trainings in the UI. It internally calls course handler of genie sdk
Parameters :
Returns :
any
|
getFieldDisplayValues |
getFieldDisplayValues(field: Array
|
Defined in src/app/profile/profile.page.ts:1256
|
Returns :
any[]
|
Private Async getFrameworkDetails |
getFrameworkDetails()
|
Defined in src/app/profile/profile.page.ts:1221
|
Returns :
any
|
Async getLearnerPassbook |
getLearnerPassbook()
|
Defined in src/app/profile/profile.page.ts:542
|
Returns :
any
|
getOrgDetails |
getOrgDetails()
|
Defined in src/app/profile/profile.page.ts:996
|
Returns :
void
|
getProjectsCertificate |
getProjectsCertificate()
|
Defined in src/app/profile/profile.page.ts:1282
|
Returns :
void
|
Async getSelfDeclaredDetails |
getSelfDeclaredDetails()
|
Defined in src/app/profile/profile.page.ts:1165
|
Returns :
any
|
Private Async handleCertificateDownloadIssue |
handleCertificateDownloadIssue(toast: any, err: any)
|
Defined in src/app/profile/profile.page.ts:686
|
Returns :
any
|
handleHeaderEvents | ||||
handleHeaderEvents($event)
|
||||
Defined in src/app/profile/profile.page.ts:950
|
||||
Parameters :
Returns :
void
|
ionViewDidEnter |
ionViewDidEnter()
|
Defined in src/app/profile/profile.page.ts:252
|
Returns :
void
|
ionViewWillEnter |
ionViewWillEnter()
|
Defined in src/app/profile/profile.page.ts:235
|
Returns :
void
|
ionViewWillLeave |
ionViewWillLeave()
|
Defined in src/app/profile/profile.page.ts:246
|
Returns :
void
|
mapTrainingsToCertificates | ||||||
mapTrainingsToCertificates(trainings: Course[])
|
||||||
Defined in src/app/profile/profile.page.ts:505
|
||||||
Parameters :
Returns :
any
|
navigateToCategoriesEditPage |
navigateToCategoriesEditPage()
|
Defined in src/app/profile/profile.page.ts:755
|
Returns :
void
|
navigateToDetailPage |
navigateToDetailPage(content: any, layoutName: string, index: number)
|
Defined in src/app/profile/profile.page.ts:712
|
Navigate to the course/content details page
Returns :
void
|
Async ngOnInit |
ngOnInit()
|
Defined in src/app/profile/profile.page.ts:229
|
Returns :
any
|
onEditProfileClicked |
onEditProfileClicked()
|
Defined in src/app/profile/profile.page.ts:767
|
Returns :
void
|
Private Async openContactVerifyPopup | ||||||||
openContactVerifyPopup(component, componentProps, cssClass)
|
||||||||
Defined in src/app/profile/profile.page.ts:911
|
||||||||
Parameters :
Returns :
unknown
|
Async openEnrolledCourse | ||||
openEnrolledCourse(training)
|
||||
Defined in src/app/profile/profile.page.ts:1049
|
||||
Parameters :
Returns :
any
|
openpdf | ||||
openpdf(path)
|
||||
Defined in src/app/profile/profile.page.ts:699
|
||||
Parameters :
Returns :
void
|
openSelfDeclareTeacherForm | ||||
openSelfDeclareTeacherForm(type)
|
||||
Defined in src/app/profile/profile.page.ts:1141
|
||||
Parameters :
Returns :
void
|
Async projectCertificateDownload | ||||
projectCertificateDownload(project)
|
||||
Defined in src/app/profile/profile.page.ts:597
|
||||
Parameters :
Returns :
any
|
Private redirectToActiveDownloads |
redirectToActiveDownloads()
|
Defined in src/app/profile/profile.page.ts:956
|
Returns :
void
|
refreshProfileData | ||||
refreshProfileData(refresher?)
|
||||
Defined in src/app/profile/profile.page.ts:301
|
||||
To refresh Profile data on pull to refresh or on click on the profile
Parameters :
Returns :
any
|
resetProfile |
resetProfile()
|
Defined in src/app/profile/profile.page.ts:294
|
To reset Profile Before calling new fresh API for Profile
Returns :
void
|
Async searchContent |
searchContent()
|
Defined in src/app/profile/profile.page.ts:774
|
Searches contents created by the user
Returns :
any
|
shareUsername |
shareUsername()
|
Defined in src/app/profile/profile.page.ts:1208
|
Returns :
void
|
Private Async showEditContactPopup | ||||
showEditContactPopup(componentProps)
|
||||
Defined in src/app/profile/profile.page.ts:859
|
||||
Parameters :
Returns :
any
|
showLessBadges |
showLessBadges()
|
Defined in src/app/profile/profile.page.ts:432
|
Returns :
void
|
showLessItems |
showLessItems()
|
Defined in src/app/profile/profile.page.ts:419
|
To show Less items in skills list DEFAULT_PAGINATION_LIMIT = 10
Returns :
void
|
showLessTrainings | ||||
showLessTrainings(listName)
|
||||
Defined in src/app/profile/profile.page.ts:456
|
||||
Parameters :
Returns :
void
|
showMoreBadges |
showMoreBadges()
|
Defined in src/app/profile/profile.page.ts:423
|
Returns :
void
|
showMoreItems |
showMoreItems()
|
Defined in src/app/profile/profile.page.ts:406
|
To show more Items in skills list
Returns :
void
|
Async showMoreTrainings | ||||
showMoreTrainings(listName)
|
||||
Defined in src/app/profile/profile.page.ts:436
|
||||
Parameters :
Returns :
Promise<void>
|
Private Async showStoragePermissionPopup |
showStoragePermissionPopup()
|
Defined in src/app/profile/profile.page.ts:1088
|
Returns :
Promise<boolean | undefined>
|
toggleTooltips | ||||||
toggleTooltips(event, field)
|
||||||
Defined in src/app/profile/profile.page.ts:966
|
||||||
Parameters :
Returns :
void
|
Private Async updateEmailInfo | ||||
updateEmailInfo(email)
|
||||
Defined in src/app/profile/profile.page.ts:928
|
||||
Parameters :
Returns :
any
|
updateLocalProfile | ||||
updateLocalProfile(framework)
|
||||
Defined in src/app/profile/profile.page.ts:739
|
||||
Parameters :
Returns :
void
|
Private Async updatePhoneInfo | ||||
updatePhoneInfo(phone)
|
||||
Defined in src/app/profile/profile.page.ts:919
|
||||
Parameters :
Returns :
any
|
Private Async updateProfile | |||||||||
updateProfile(request: UpdateServerProfileInfoRequest, successMessage: string)
|
|||||||||
Defined in src/app/profile/profile.page.ts:937
|
|||||||||
Parameters :
Returns :
any
|
Private Async validateAndEditContact |
validateAndEditContact()
|
Defined in src/app/profile/profile.page.ts:834
|
Returns :
Promise<boolean>
|
appName |
Type : string
|
Default value : ''
|
Defined in src/app/profile/profile.page.ts:111
|
badgesLimit |
Type : number
|
Default value : 2
|
Defined in src/app/profile/profile.page.ts:123
|
boardList |
Type : []
|
Default value : []
|
Defined in src/app/profile/profile.page.ts:112
|
categories |
Type : any
|
Defined in src/app/profile/profile.page.ts:160
|
checked |
Default value : false
|
Defined in src/app/profile/profile.page.ts:104
|
contentCreatedByMe |
Type : any
|
Default value : []
|
Defined in src/app/profile/profile.page.ts:132
|
custodianOrgId |
Type : string
|
Defined in src/app/profile/profile.page.ts:128
|
Readonly DEFAULT_ENROLLED_COURSE_LIMIT |
Type : number
|
Default value : 3
|
Defined in src/app/profile/profile.page.ts:120
|
Readonly DEFAULT_PAGINATION_LIMIT |
Type : number
|
Default value : 3
|
Defined in src/app/profile/profile.page.ts:119
|
Readonly DEFAULT_PROJECTS_LIMIT |
Type : number
|
Default value : 1
|
Defined in src/app/profile/profile.page.ts:121
|
enrolledCourseList |
Type : []
|
Default value : []
|
Defined in src/app/profile/profile.page.ts:159
|
Private frameworkCategoriesMap |
Type : literal type
|
Default value : {}
|
Defined in src/app/profile/profile.page.ts:94
|
gradeLevelList |
Type : []
|
Default value : []
|
Defined in src/app/profile/profile.page.ts:114
|
headerObservable |
Type : any
|
Defined in src/app/profile/profile.page.ts:140
|
imageUri |
Type : string
|
Default value : 'assets/imgs/ic_profile_default.png'
|
Defined in src/app/profile/profile.page.ts:117
|
informationOrgName |
Default value : false
|
Defined in src/app/profile/profile.page.ts:103
|
informationProfileName |
Default value : false
|
Defined in src/app/profile/profile.page.ts:102
|
isCustodianOrgId |
Type : boolean
|
Defined in src/app/profile/profile.page.ts:129
|
isDefaultChannelProfile |
Type : boolean
|
Defined in src/app/profile/profile.page.ts:153
|
isLoggedInUser |
Default value : false
|
Defined in src/app/profile/profile.page.ts:100
|
isRefreshProfile |
Default value : false
|
Defined in src/app/profile/profile.page.ts:101
|
isStateValidated |
Type : boolean
|
Defined in src/app/profile/profile.page.ts:130
|
layoutPopular |
Default value : ContentCard.LAYOUT_POPULAR
|
Defined in src/app/profile/profile.page.ts:139
|
learnerPassbook |
Type : any[]
|
Default value : []
|
Defined in src/app/profile/profile.page.ts:157
|
learnerPassbookCount |
Type : any
|
Defined in src/app/profile/profile.page.ts:158
|
learnerPassbookLimit |
Default value : this.DEFAULT_ENROLLED_COURSE_LIMIT
|
Defined in src/app/profile/profile.page.ts:126
|
loggedInUserId |
Type : string
|
Default value : ''
|
Defined in src/app/profile/profile.page.ts:105
|
mappedTrainingCertificates |
Type : literal type[]
|
Default value : []
|
Defined in src/app/profile/profile.page.ts:142
|
mediumList |
Type : []
|
Default value : []
|
Defined in src/app/profile/profile.page.ts:113
|
myImprovementsLimit |
Default value : this.DEFAULT_PROJECTS_LIMIT
|
Defined in src/app/profile/profile.page.ts:125
|
myLearningLimit |
Default value : this.DEFAULT_ENROLLED_COURSE_LIMIT
|
Defined in src/app/profile/profile.page.ts:124
|
onProfile |
Default value : true
|
Defined in src/app/profile/profile.page.ts:108
|
organisationName |
Type : string
|
Defined in src/app/profile/profile.page.ts:131
|
orgDetails |
Type : literal type
|
Defined in src/app/profile/profile.page.ts:133
|
personaTenantDeclaration |
Type : string
|
Defined in src/app/profile/profile.page.ts:154
|
profile |
Type : any
|
Default value : {}
|
Defined in src/app/profile/profile.page.ts:98
|
profileName |
Type : string
|
Defined in src/app/profile/profile.page.ts:107
|
projects |
Type : []
|
Default value : []
|
Defined in src/app/profile/profile.page.ts:161
|
projectsCount |
Type : number
|
Default value : 0
|
Defined in src/app/profile/profile.page.ts:162
|
projectStatus |
Default value : statusType
|
Defined in src/app/profile/profile.page.ts:163
|
refresh |
Type : boolean
|
Defined in src/app/profile/profile.page.ts:106
|
refresher |
Type : IonRefresher
|
Decorators :
@ViewChild('refresher', {static: false})
|
Defined in src/app/profile/profile.page.ts:96
|
roles |
Type : []
|
Default value : []
|
Defined in src/app/profile/profile.page.ts:109
|
rolesLimit |
Type : number
|
Default value : 2
|
Defined in src/app/profile/profile.page.ts:122
|
selfDeclarationInfo |
Type : any
|
Defined in src/app/profile/profile.page.ts:156
|
selfDeclaredDetails |
Type : any[]
|
Default value : []
|
Defined in src/app/profile/profile.page.ts:155
|
startLimit |
Type : number
|
Default value : 0
|
Defined in src/app/profile/profile.page.ts:127
|
subjectList |
Type : []
|
Default value : []
|
Defined in src/app/profile/profile.page.ts:115
|
timer |
Type : any
|
Defined in src/app/profile/profile.page.ts:141
|
userId |
Type : string
|
Default value : ''
|
Defined in src/app/profile/profile.page.ts:99
|
userLocation |
Type : object
|
Default value : {}
|
Defined in src/app/profile/profile.page.ts:110
|
import { Component, NgZone, OnInit, Inject, ViewChild } from '@angular/core';
import {
PopoverController,
ToastController,
IonRefresher,
Platform,
} from '@ionic/angular';
import { Events } from '@app/util/events';
import {
ContentCard,
ProfileConstants,
RouterLinks,
ContentFilterConfig,
EventTopics,
OTPTemplates
} from '@app/app/app.constant';
import { FormAndFrameworkUtilService } from '@app/services/formandframeworkutil.service';
import { AppGlobalService } from '@app/services/app-global-service.service';
import { CommonUtilService } from '@app/services/common-util.service';
import { TelemetryGeneratorService } from '@app/services/telemetry-generator.service';
import { AppHeaderService } from '@app/services/app-header.service';
import {
AuthService,
ContentSearchCriteria,
ContentSearchResult,
ContentService,
ContentSortCriteria,
Course,
CourseService,
OAuthSession,
ProfileService,
SearchType,
ServerProfileDetailsRequest,
SortOrder,
TelemetryObject,
UpdateServerProfileInfoRequest,
CachedItemRequestSourceFrom,
CourseCertificate,
CertificateAlreadyDownloaded,
NetworkError,
FormService,
FrameworkService,
ProfileType,
Batch,
GetLearnerCerificateRequest,
GenerateOtpRequest,
CertificateService,
CSGetLearnerCerificateRequest,
CsLearnerCertificate,
Framework,
FrameworkCategoryCodesGroup,
FrameworkDetailsRequest
} from 'sunbird-sdk';
import { Environment, InteractSubtype, InteractType, PageId, ID } from '@app/services/telemetry-constants';
import { Router } from '@angular/router';
import { EditContactVerifyPopupComponent } from '@app/app/components/popups/edit-contact-verify-popup/edit-contact-verify-popup.component';
import {
EditContactDetailsPopupComponent
} from '@app/app/components/popups/edit-contact-details-popup/edit-contact-details-popup.component';
import {
AccountRecoveryInfoComponent
} from '../components/popups/account-recovery-id/account-recovery-id-popup.component';
import { SocialSharing } from '@ionic-native/social-sharing/ngx';
import { AndroidPermissionsService } from '@app/services';
import {
AndroidPermissionsStatus,
AndroidPermission
} from '@app/services/android-permissions/android-permission';
import { AppVersion } from '@ionic-native/app-version/ngx';
import { SbProgressLoader } from '@app/services/sb-progress-loader.service';
import { FileOpener } from '@ionic-native/file-opener/ngx';
import { TranslateService } from '@ngx-translate/core';
import { FieldConfig } from 'common-form-elements';
import { CertificateDownloadAsPdfService } from 'sb-svg2pdf';
import { NavigationService } from '@app/services/navigation-handler.service';
import { ContentUtil } from '@app/util/content-util';
import { CsPrimaryCategory } from '@project-sunbird/client-services/services/content';
import { FormConstants } from '../form.constants';
import { ProfileHandler } from '@app/services/profile-handler';
import { SegmentationTagService, TagPrefixConstants } from '@app/services/segmentation-tag/segmentation-tag.service';
import { OrganizationSearchCriteria } from '@project-sunbird/sunbird-sdk';
import { FrameworkCategory } from '@project-sunbird/client-services/models/channel';
import { LocationHandler } from '@app/services/location-handler';
import { urlConstants } from '../manage-learn/core/constants/urlConstants';
import { UnnatiDataService } from '../manage-learn/core/services/unnati-data.service';
import { statusType } from '../manage-learn/core';
@Component({
selector: 'app-profile',
templateUrl: './profile.page.html',
styleUrls: ['./profile.page.scss'],
providers: [CertificateDownloadAsPdfService]
})
export class ProfilePage implements OnInit {
private frameworkCategoriesMap: { [code: string]: FrameworkCategory | undefined } = {};
@ViewChild('refresher', { static: false }) refresher: IonRefresher;
profile: any = {};
userId = '';
isLoggedInUser = false;
isRefreshProfile = false;
informationProfileName = false;
informationOrgName = false;
checked = false;
loggedInUserId = '';
refresh: boolean;
profileName: string;
onProfile = true;
roles = [];
userLocation = {};
appName = '';
boardList = [];
mediumList = [];
gradeLevelList = [];
subjectList = [];
imageUri = 'assets/imgs/ic_profile_default.png';
readonly DEFAULT_PAGINATION_LIMIT = 3;
readonly DEFAULT_ENROLLED_COURSE_LIMIT = 3;
readonly DEFAULT_PROJECTS_LIMIT = 1;
rolesLimit = 2;
badgesLimit = 2;
myLearningLimit = this.DEFAULT_ENROLLED_COURSE_LIMIT;
myImprovementsLimit = this.DEFAULT_PROJECTS_LIMIT;
learnerPassbookLimit = this.DEFAULT_ENROLLED_COURSE_LIMIT;
startLimit = 0;
custodianOrgId: string;
isCustodianOrgId: boolean;
isStateValidated: boolean;
organisationName: string;
contentCreatedByMe: any = [];
orgDetails: {
'state': string,
'district': string,
'block': string
};
layoutPopular = ContentCard.LAYOUT_POPULAR;
headerObservable: any;
timer: any;
mappedTrainingCertificates: {
courseName: string,
batch: Batch,
dateTime: string,
courseId: string,
certificate?: string,
issuedCertificate?: string,
status: number,
style: string,
label: string
}[] = [];
isDefaultChannelProfile: boolean;
personaTenantDeclaration: string;
selfDeclaredDetails: any[] = [];
selfDeclarationInfo: any;
learnerPassbook: any[] = [];
learnerPassbookCount: any;
enrolledCourseList = [];
categories: any;
projects=[];
projectsCount =0;
projectStatus =statusType;
constructor(
@Inject('PROFILE_SERVICE') private profileService: ProfileService,
@Inject('AUTH_SERVICE') private authService: AuthService,
@Inject('CONTENT_SERVICE') private contentService: ContentService,
@Inject('COURSE_SERVICE') private courseService: CourseService,
@Inject('FORM_SERVICE') private formService: FormService,
@Inject('FRAMEWORK_SERVICE') private frameworkService: FrameworkService,
@Inject('CERTIFICATE_SERVICE') private certificateService: CertificateService,
private zone: NgZone,
private router: Router,
private popoverCtrl: PopoverController,
private events: Events,
private appGlobalService: AppGlobalService,
private telemetryGeneratorService: TelemetryGeneratorService,
private formAndFrameworkUtilService: FormAndFrameworkUtilService,
private commonUtilService: CommonUtilService,
private socialSharing: SocialSharing,
private headerService: AppHeaderService,
private permissionService: AndroidPermissionsService,
private appVersion: AppVersion,
private navService: NavigationService,
private sbProgressLoader: SbProgressLoader,
private fileOpener: FileOpener,
private toastController: ToastController,
private translate: TranslateService,
private certificateDownloadAsPdfService: CertificateDownloadAsPdfService,
private profileHandler: ProfileHandler,
private segmentationTagService: SegmentationTagService,
private platform: Platform,
private locationHandler: LocationHandler,
private unnatiDataService : UnnatiDataService
) {
const extrasState = this.router.getCurrentNavigation().extras.state;
if (extrasState) {
this.userId = extrasState.userId || '';
this.isRefreshProfile = extrasState.returnRefreshedUserProfileDetails;
}
this.isLoggedInUser = !this.userId;
// Event for optional and forceful upgrade
this.events.subscribe('force_optional_upgrade', async (upgrade) => {
if (upgrade) {
await this.appGlobalService.openPopover(upgrade);
}
});
this.events.subscribe('loggedInProfile:update', (framework) => {
if (framework) {
this.updateLocalProfile(framework);
this.refreshProfileData();
} else {
this.doRefresh();
}
});
this.events.subscribe(EventTopics.SIGN_IN_RELOAD, async (data) => {
this.doRefresh();
});
this.formAndFrameworkUtilService.getCustodianOrgId().then((orgId: string) => {
this.custodianOrgId = orgId;
});
}
async ngOnInit() {
this.getCategories();
this.doRefresh();
this.appName = await this.appVersion.getAppName();
}
ionViewWillEnter() {
this.getCategories();
this.events.subscribe('update_header', () => {
this.headerService.showHeaderWithHomeButton();
});
this.headerObservable = this.headerService.headerEventEmitted$.subscribe(eventName => {
this.handleHeaderEvents(eventName);
});
this.headerService.showHeaderWithHomeButton();
}
ionViewWillLeave(): void {
this.headerObservable.unsubscribe();
this.events.unsubscribe('update_header');
this.refresher.disabled = true;
}
ionViewDidEnter() {
this.refresher.disabled = false;
}
async doRefresh(refresher?) {
const loader = await this.commonUtilService.getLoader();
this.isRefreshProfile = true;
if (!refresher) {
await loader.present();
} else if (refresher.target) {
this.telemetryGeneratorService.generatePullToRefreshTelemetry(PageId.PROFILE, Environment.HOME);
refresher.target.complete();
this.refresh = true;
}
return this.refreshProfileData(refresher)
.then(() => {
return new Promise((resolve) => {
setTimeout(async () => {
this.events.publish('refresh:profile');
this.refresh = false;
await loader.dismiss();
await this.sbProgressLoader.hide({ id: 'login' });
resolve();
}, 500);
// This method is used to handle trainings completed by user
this.getLearnerPassbook();
this.getEnrolledCourses(refresher);
this.searchContent();
this.getSelfDeclaredDetails();
this.getProjectsCertificate();
});
})
.catch(async error => {
this.refresh = false;
await loader.dismiss();
});
}
/**
* To reset Profile Before calling new fresh API for Profile
*/
resetProfile() {
this.profile = {};
}
/**
* To refresh Profile data on pull to refresh or on click on the profile
*/
refreshProfileData(refresher?) {
const that = this;
return new Promise((resolve, reject) => {
that.authService.getSession().toPromise().then((session: OAuthSession) => {
if (session === null || session === undefined) {
reject('session is null');
} else {
that.loggedInUserId = session.userToken;
if (that.userId && session.userToken === that.userId) {
that.isLoggedInUser = true;
}
const serverProfileDetailsRequest: ServerProfileDetailsRequest = {
userId: that.userId && that.userId !== session.userToken ? that.userId : session.userToken,
requiredFields: ProfileConstants.REQUIRED_FIELDS,
from: CachedItemRequestSourceFrom.SERVER
};
if (that.isLoggedInUser) {
that.isRefreshProfile = !that.isRefreshProfile;
}
that.profileService.getServerProfilesDetails(serverProfileDetailsRequest).toPromise()
.then((profileData) => {
that.zone.run(async () => {
that.resetProfile();
that.profile = profileData;
// ******* Segmentation
let segmentDetails = JSON.parse(JSON.stringify(profileData.framework));
Object.keys(segmentDetails).forEach((key) => {
if (key !== 'id' && Array.isArray(segmentDetails[key])) {
segmentDetails[key] = segmentDetails[key].map( x => x.replace(/\s/g, '').toLowerCase());
}
});
window['segmentation'].SBTagService.pushTag(segmentDetails, TagPrefixConstants.USER_ATRIBUTE, true);
let userLocation = [];
(profileData['userLocations'] || []).forEach(element => {
userLocation.push({ name: element.name, code: element.code });
});
window['segmentation'].SBTagService.pushTag({ location: userLocation }, TagPrefixConstants.USER_LOCATION, true);
window['segmentation'].SBTagService.pushTag(profileData.profileUserType.type, TagPrefixConstants.USER_LOCATION, true);
this.segmentationTagService.evalCriteria();
// *******
that.frameworkService.setActiveChannelId(profileData.rootOrg.hashTagId).toPromise();
that.isDefaultChannelProfile = await that.profileService.isDefaultChannelProfile().toPromise();
const role: string = (!that.profile.profileUserType.type ||
(that.profile.profileUserType.type
&& that.profile.profileUserType.type === ProfileType.OTHER.toUpperCase())) ? '' : that.profile.profileUserType.type;
that.profile['persona'] = await that.profileHandler.getPersonaConfig(role.toLowerCase());
that.userLocation = that.commonUtilService.getUserLocation(that.profile);
that.profile['subPersona'] = await that.profileHandler.getSubPersona(this.profile,
role.toLowerCase(), this.userLocation);
that.profileService.getActiveSessionProfile({ requiredFields: ProfileConstants.REQUIRED_FIELDS }).toPromise()
.then((activeProfile) => {
that.formAndFrameworkUtilService.updateLoggedInUser(profileData, activeProfile)
.then((frameWorkData) => {
if (!frameWorkData['status']) {
}
});
that.formatRoles();
that.getOrgDetails();
that.isCustodianOrgId = (that.profile.rootOrg.rootOrgId === this.custodianOrgId);
that.isStateValidated = that.profile.stateValidated;
resolve();
});
if(profileData && profileData.framework && Object.keys(profileData.framework).length == 0) {
await this.getFrameworkDetails();
}
});
}).catch(err => {
if (refresher) {
refresher.target.complete();
}
reject();
});
}
});
});
}
/**
* Method to store all roles from different organizations into single array
*/
formatRoles() {
this.roles = [];
if (this.profile && this.profile.roleList) {
const roles = {};
this.profile.roleList.forEach((r) => {
roles[r.id] = r;
});
if (this.profile.roles && this.profile.roles.length) {
for (let i = 0, len = this.profile.roles.length; i < len; i++) {
const roleKey = this.profile.roles[i].role;
const val = roles[roleKey];
if (val && val.name.toLowerCase() !== 'public') {
this.roles.push(val.name);
}
}
}
}
}
/**
* To show more Items in skills list
*/
showMoreItems(): void {
this.rolesLimit = this.roles.length;
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.VIEW_MORE_CLICKED,
Environment.HOME,
PageId.PROFILE, null);
}
/**
* To show Less items in skills list
* DEFAULT_PAGINATION_LIMIT = 10
*/
showLessItems(): void {
this.rolesLimit = this.DEFAULT_PAGINATION_LIMIT;
}
showMoreBadges(): void {
this.badgesLimit = this.profile.badgeAssertions.length;
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.VIEW_MORE_CLICKED,
Environment.HOME,
PageId.PROFILE, null);
}
showLessBadges(): void {
this.badgesLimit = this.DEFAULT_PAGINATION_LIMIT;
}
async showMoreTrainings(listName): Promise<void> {
switch (listName) {
case 'myLearning':
this.myLearningLimit = this.mappedTrainingCertificates.length;
break;
case 'learnerPassbook':
await this.getLearnerPassbook();
this.learnerPassbookLimit = this.learnerPassbook.length;
break;
case 'myImprovements':
this.myImprovementsLimit = this.projects.length;
break;
}
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.VIEW_MORE_CLICKED,
Environment.HOME,
PageId.PROFILE, null);
}
showLessTrainings(listName): void {
switch (listName) {
case 'myLearning':
this.myLearningLimit = this.DEFAULT_ENROLLED_COURSE_LIMIT;
break;
case 'learnerPassbook':
this.learnerPassbookLimit = this.DEFAULT_ENROLLED_COURSE_LIMIT;
this.learnerPassbookCount = null;
this.getLearnerPassbook();
break;
}
}
/**
* To get enrolled course(s) of logged-in user i.e, trainings in the UI.
*
* It internally calls course handler of genie sdk
*/
async getEnrolledCourses(refresher?, refreshCourseList?) {
const loader = await this.commonUtilService.getLoader();
if (refreshCourseList) {
await loader.present();
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.REFRESH_CLICKED,
Environment.USER,
PageId.PROFILE
);
}
const option = {
userId: this.profile.userId || this.profile.id,
returnFreshCourses: !!refresher
};
this.mappedTrainingCertificates = [];
this.courseService.getEnrolledCourses(option).toPromise()
.then(async (res: Course[]) => {
if (res.length) {
this.enrolledCourseList = res.sort((a, b) => (a.enrolledDate > b.enrolledDate ? -1 : 1));
this.mappedTrainingCertificates = this.mapTrainingsToCertificates(res);
}
if (refreshCourseList) {
await loader.dismiss();
}
})
.catch((error: any) => {
console.error('error while loading enrolled courses', error);
});
}
mapTrainingsToCertificates(trainings: Course[]) {
/**
* If certificate is there loop through certificates and add certificates in accumulator
* with Course_Name and Date
* if not then add only Course_Name and Date and add in to the accumulator
*/
return trainings.reduce((accumulator, course) => {
const oneCert = {
courseName: course.courseName,
batch: course.batch,
dateTime: course.dateTime,
courseId: course.courseId,
certificate: undefined,
issuedCertificate: undefined,
status: course.status,
style: 'completed-status-text',
label: 'COMPLETED'
};
if(course.status === 0 || course.status === 1) {
oneCert.style = 'ongoing-status-text';
oneCert.label = 'ONGOING';
if(course.batch && course.batch.status === 2) {
oneCert.style = 'ongoing-status-text';
oneCert.label = 'BATCH_EXPIRED';
}
}
if (course.certificates && course.certificates.length) {
oneCert.certificate = course.certificates[0];
}
if (course.issuedCertificates && course.issuedCertificates.length) {
oneCert.issuedCertificate = course.issuedCertificates[0];
}
accumulator = accumulator.concat(oneCert);
return accumulator;
}, []);
}
async getLearnerPassbook() {
try {
const request: GetLearnerCerificateRequest = { userId: this.profile.userId || this.profile.id };
request.size = this.learnerPassbookCount ? this.learnerPassbookCount : null;
const getCertsReq: CSGetLearnerCerificateRequest = {
userId: this.profile.userId || this.profile.id,
schemaName: 'certificate',
size: this.learnerPassbookCount? this.learnerPassbookCount : null
};
await this.certificateService.getCertificates(getCertsReq).toPromise().then(response => {
this.learnerPassbookCount = response.certRegCount + response.rcCount || null;
this.learnerPassbook = response.certificates
.map((learnerCertificate: CsLearnerCertificate) => {
const oneCert: any = {
issuingAuthority: learnerCertificate.issuerName,
issuedOn: learnerCertificate.issuedOn,
courseName: learnerCertificate.trainingName,
courseId: learnerCertificate.courseId,
};
if (learnerCertificate.pdfUrl) {
oneCert.certificate = {
url: learnerCertificate.pdfUrl || undefined,
id: learnerCertificate.id || undefined,
identifier: learnerCertificate.id,
issuedOn: learnerCertificate.issuedOn,
name: learnerCertificate.issuerName,
type: learnerCertificate.type,
templateUrl: learnerCertificate.templateUrl
};
} else {
oneCert.issuedCertificate = {
identifier: learnerCertificate.id,
name: learnerCertificate.issuerName,
issuedOn: learnerCertificate.issuedOn,
type: learnerCertificate.type,
templateUrl: learnerCertificate.templateUrl
};
}
return oneCert;
});
});
} catch (error) {
console.log('Learner Passbook API Error', error);
}
}
downloadCertificate(data,type?){
if(type && type == 'project'){
this.projectCertificateDownload(data);
}else{
this.downloadTrainingCertificate(data)
}
}
async projectCertificateDownload(project){
if (!this.commonUtilService.networkInfo.isNetworkAvailable) {
this.commonUtilService.showToast('OFFLINE_CERTIFICATE_MESSAGE', false, '', 3000, 'top');
return;
}
await this.checkForPermissions().then(async (result) => {
if (result) {
const request = { type:'project',name:project.title, project: project._id, certificate: project.certificate, templateUrl : project.certificate.templateUrl };
if (this.platform.is('ios')) {
(window as any).cordova.InAppBrowser.open(request.certificate['templateUrl'], '_blank', "toolbarposition=top");
} else {
this.router.navigate([`/${RouterLinks.PROFILE}/${RouterLinks.CERTIFICATE_VIEW}`], {
state: { request }
});
}
} else {
this.commonUtilService.showSettingsPageToast('FILE_MANAGER_PERMISSION_DESCRIPTION', this.appName, PageId.PROFILE, true);
}
});
}
async downloadTrainingCertificate(course: {
courseName: string,
dateTime: string,
courseId: string,
certificate?: CourseCertificate,
issuedCertificate?: CourseCertificate,
status: number
}) {
const telemetryObject: TelemetryObject = new TelemetryObject(course.courseId, 'Certificate', undefined);
const values = new Map();
values['courseId'] = course.courseId;
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.DOWNLOAD_CERTIFICATE_CLICKED,
Environment.USER,
PageId.PROFILE,
telemetryObject,
values);
await this.checkForPermissions().then(async (result) => {
if (result) {
if (course.issuedCertificate) {
const request = { courseId: course.courseId, certificate: course.issuedCertificate };
if (!this.commonUtilService.networkInfo.isNetworkAvailable) {
if (!(await this.courseService.certificateManager.isCertificateCached(request).toPromise())) {
this.commonUtilService.showToast('OFFLINE_CERTIFICATE_MESSAGE', false, '', 3000, 'top');
return;
}
}
this.router.navigate([`/${RouterLinks.PROFILE}/${RouterLinks.CERTIFICATE_VIEW}`], {
state: { request }
});
} else {
if (!this.commonUtilService.networkInfo.isNetworkAvailable) {
this.commonUtilService.showToast('OFFLINE_CERTIFICATE_MESSAGE', false, '', 3000, 'top');
return;
}
const downloadMessage = await this.translate.get('CERTIFICATE_DOWNLOAD_INFO').toPromise();
const toastOptions = {
message: downloadMessage || 'Certificate getting downloaded'
};
const toast = await this.toastController.create(toastOptions);
await toast.present();
await this.downloadLegacyCertificate(course, toast);
}
} else {
this.commonUtilService.showSettingsPageToast('FILE_MANAGER_PERMISSION_DESCRIPTION', this.appName, PageId.PROFILE, true);
}
});
}
private async downloadLegacyCertificate(course, toast) {
const downloadRequest = {
courseId: course.courseId,
certificate: course.certificate
};
this.courseService.downloadCurrentProfileCourseCertificate(downloadRequest).toPromise()
.then(async (res) => {
if (toast) {
await toast.dismiss();
}
this.openpdf(res.path);
}).catch(async (err) => {
await this.handleCertificateDownloadIssue(toast, err);
});
}
private async handleCertificateDownloadIssue(toast: any, err: any) {
if (toast) {
await toast.dismiss();
}
if (err instanceof CertificateAlreadyDownloaded) {
this.openpdf(err.filePath);
} else if (NetworkError.isInstance(err)) {
this.commonUtilService.showToast('OFFLINE_CERTIFICATE_MESSAGE', false, '', 3000, 'top');
} else {
this.commonUtilService.showToast(this.commonUtilService.translateMessage('SOMETHING_WENT_WRONG'));
}
}
openpdf(path) {
this.fileOpener
.open(path, 'application/pdf')
.then(() => console.log('File is opened'))
.catch((e) => {
console.log('Error opening file', e);
this.commonUtilService.showToast('CERTIFICATE_ALREADY_DOWNLOADED');
});
}
/**
* Navigate to the course/content details page
*/
navigateToDetailPage(content: any, layoutName: string, index: number): void {
const identifier = content.contentId || content.identifier;
let telemetryObject: TelemetryObject;
if (layoutName === ContentCard.LAYOUT_INPROGRESS) {
telemetryObject = new TelemetryObject(identifier, CsPrimaryCategory.COURSE, undefined);
} else {
telemetryObject = ContentUtil.getTelemetryObject(content);
}
const values = new Map();
values['sectionName'] = 'Contributions';
values['positionClicked'] = index;
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.CONTENT_CLICKED,
Environment.USER,
PageId.PROFILE,
telemetryObject,
values);
this.navService.navigateToDetailPage(
content,
{
content
}
);
}
updateLocalProfile(framework) {
this.profile.framework = framework;
this.profileService.getActiveSessionProfile({ requiredFields: ProfileConstants.REQUIRED_FIELDS })
.toPromise()
.then((resp: any) => {
if (framework.userType) {
resp.profileType = framework.userType;
}
this.formAndFrameworkUtilService.updateLoggedInUser(this.profile, resp)
.then((success) => {
console.log('updateLocalProfile-- ', success);
});
});
}
navigateToCategoriesEditPage() {
if (this.commonUtilService.networkInfo.isNetworkAvailable) {
this.telemetryGeneratorService.generateInteractTelemetry(InteractType.TOUCH,
InteractSubtype.EDIT_CLICKED,
Environment.HOME,
PageId.PROFILE, null);
this.router.navigate([`/${RouterLinks.PROFILE}/${RouterLinks.CATEGORIES_EDIT}`]);
} else {
this.commonUtilService.showToast('NEED_INTERNET_TO_CHANGE');
}
}
onEditProfileClicked() {
this.navService.navigateToEditPersonalDetails(this.profile, PageId.PROFILE);
}
/**
* Searches contents created by the user
*/
async searchContent() {
const contentSortCriteria: ContentSortCriteria = {
sortAttribute: 'lastUpdatedOn',
sortOrder: SortOrder.DESC
};
const contentTypes = await this.formAndFrameworkUtilService.getSupportedContentFilterConfig(
ContentFilterConfig.NAME_DOWNLOADS);
const contentSearchCriteria: ContentSearchCriteria = {
createdBy: [this.userId || this.loggedInUserId],
limit: 100,
contentTypes,
sortCriteria: [contentSortCriteria],
searchType: SearchType.SEARCH
};
this.contentService.searchContent(contentSearchCriteria).toPromise()
.then((result: ContentSearchResult) => {
this.contentCreatedByMe = result.contentDataList || [];
})
.catch((error: any) => {
console.error('Error', error);
});
}
async editMobileNumber() {
const componentProps = {
phone: this.profile.phone,
title: this.commonUtilService.translateMessage('UPDATE_PHONE_POPUP_TITLE'),
description: this.commonUtilService.translateMessage('ERROR_RECOVERY_ID_PHONE_INVALID'),
type: ProfileConstants.CONTACT_TYPE_PHONE,
userId: this.profile.userId
};
this.validateAndEditContact()
.then((_) => this.showEditContactPopup(componentProps))
.catch(err => console.log(err) );
}
async editEmail() {
const componentProps = {
email: this.profile.email,
title: this.commonUtilService.translateMessage('UPDATE_EMAIL_POPUP_TITLE'),
description: this.commonUtilService.translateMessage('EMAIL_PLACEHOLDER'),
type: ProfileConstants.CONTACT_TYPE_EMAIL,
userId: this.profile.userId
};
this.validateAndEditContact()
.then((_) => this.showEditContactPopup(componentProps))
.catch(e => {
if (e && e.response && e.response.body && e.response.body.params && e.response.body.params.err &&
e.response.body.params.err === 'UOS_OTPCRT0059') {
this.commonUtilService.showToast('ERROR_OTP_LIMIT_EXCEEDED');
} else if (e.message !== 'CANCEL') {
this.commonUtilService.showToast('SOMETHING_WENT_WRONG');
}
});
}
private async validateAndEditContact(): Promise<boolean> {
const request: GenerateOtpRequest = {
key: this.profile.email || this.profile.phone || this.profile.recoveryEmail,
userId: this.profile.userId,
templateId: OTPTemplates.EDIT_CONTACT_OTP_TEMPLATE,
type: ''
};
if ((this.profile.email && !this.profile.phone) ||
(!this.profile.email && !this.profile.phone && this.profile.recoveryEmail)) {
request.type = ProfileConstants.CONTACT_TYPE_EMAIL;
} else if (this.profile.phone || this.profile.recoveryPhone) {
request.type = ProfileConstants.CONTACT_TYPE_PHONE;
}
const resp = await this.profileService.generateOTP(request).toPromise();
if (resp) {
const response = await this.callOTPPopover(request.type, request.key, false);
if (response && response.OTPSuccess) {
return Promise.resolve(true);
} else {
return Promise.reject(true);
}
}
}
private async showEditContactPopup(componentProps) {
const popover = await this.popoverCtrl.create({
component: EditContactDetailsPopupComponent,
componentProps,
cssClass: 'popover-alert input-focus',
translucent: true
});
await popover.present();
const { data } = await popover.onDidDismiss();
if (data && data.isEdited) {
await this.callOTPPopover(componentProps.type, data.value);
}
}
private async callOTPPopover(type: string, key?: any, updateContact: boolean = true) {
if (type === ProfileConstants.CONTACT_TYPE_PHONE) {
const componentProps = {
key,
phone: this.profile.phone,
title: !updateContact ? this.commonUtilService.translateMessage('AUTHRISE_USER_OTP_TITLE') :
this.commonUtilService.translateMessage('AUTHRISE_USER_OTP_DESCRIPTION'),
description: !updateContact ? this.commonUtilService.translateMessage('AUTHRISE_USER_OTP_DESCRIPTION') :
this.commonUtilService.translateMessage('VERIFY_PHONE_OTP_DESCRIPTION'),
type: ProfileConstants.CONTACT_TYPE_PHONE,
userId: this.profile.userId
};
const data = await this.openContactVerifyPopup(EditContactVerifyPopupComponent, componentProps, 'popover-alert input-focus');
if (updateContact && data && data.OTPSuccess) {
this.updatePhoneInfo(data.value);
}
} else {
const componentProps = {
key,
phone: this.profile.email,
title: !updateContact ? this.commonUtilService.translateMessage('AUTHRISE_USER_OTP_TITLE') :
this.commonUtilService.translateMessage('VERIFY_EMAIL_OTP_TITLE'),
description: !updateContact ? this.commonUtilService.translateMessage('AUTHRISE_USER_OTP_DESCRIPTION') :
this.commonUtilService.translateMessage('VERIFY_EMAIL_OTP_DESCRIPTION'),
type: ProfileConstants.CONTACT_TYPE_EMAIL,
userId: this.profile.userId
};
const data = await this.openContactVerifyPopup(EditContactVerifyPopupComponent, componentProps, 'popover-alert input-focus');
if (updateContact && data && data.OTPSuccess) {
this.updateEmailInfo(data.value);
}
return data;
}
}
private async openContactVerifyPopup(component, componentProps, cssClass) {
const popover = await this.popoverCtrl.create({ component, componentProps, cssClass });
await popover.present();
const { data } = await popover.onDidDismiss();
return data;
}
private async updatePhoneInfo(phone) {
const req: UpdateServerProfileInfoRequest = {
userId: this.profile.userId,
phone,
phoneVerified: true
};
await this.updateProfile(req, 'PHONE_UPDATE_SUCCESS');
}
private async updateEmailInfo(email) {
const req: UpdateServerProfileInfoRequest = {
userId: this.profile.userId,
email,
emailVerified: true
};
await this.updateProfile(req, 'EMAIL_UPDATE_SUCCESS');
}
private async updateProfile(request: UpdateServerProfileInfoRequest, successMessage: string) {
const loader = await this.commonUtilService.getLoader();
this.profileService.updateServerProfile(request).toPromise()
.then(async () => {
await loader.dismiss();
this.doRefresh();
this.commonUtilService.showToast(this.commonUtilService.translateMessage(successMessage));
}).catch(async () => {
await loader.dismiss();
this.commonUtilService.showToast(this.commonUtilService.translateMessage('SOMETHING_WENT_WRONG'));
});
}
handleHeaderEvents($event) {
if ($event.name === 'download') {
this.redirectToActiveDownloads();
}
}
private redirectToActiveDownloads() {
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.ACTIVE_DOWNLOADS_CLICKED,
Environment.HOME,
PageId.PROFILE);
this.router.navigate([RouterLinks.ACTIVE_DOWNLOADS]);
}
toggleTooltips(event, field) {
clearTimeout(this.timer);
if (field === 'name') {
this.informationProfileName = !Boolean(this.informationProfileName);
this.informationOrgName = false;
if (this.informationProfileName) {
this.dismissMessage();
}
} else if (field === 'org') {
this.informationOrgName = !Boolean(this.informationOrgName);
this.informationProfileName = false;
if (this.informationOrgName) {
this.dismissMessage();
}
} else {
this.informationProfileName = false;
this.informationOrgName = false;
}
event.stopPropagation();
}
private dismissMessage() {
this.timer = setTimeout(() => {
this.informationProfileName = false;
this.informationOrgName = false;
}, 3000);
}
getOrgDetails() {
const orgList = [];
let orgItemList;
orgItemList = this.profile.organisations;
if (orgItemList.length > 1) {
orgItemList.map((org) => {
if (this.profile.rootOrgId !== org.organisationId) {
orgList.push(org);
}
});
orgList.sort((orgDate1, orgdate2) => orgDate1.orgjoindate > orgdate2.organisation ? 1 : -1);
this.organisationName = orgList[0].orgName;
this.orgDetails = this.commonUtilService.getOrgLocation(orgList[0]);
} else if (orgItemList.length === 1) {
this.organisationName = orgItemList[0].orgName;
this.orgDetails = this.commonUtilService.getOrgLocation(orgItemList[0]);
}
}
async editRecoveryId() {
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
InteractSubtype.RECOVERY_ACCOUNT_ID_CLICKED,
Environment.USER,
PageId.PROFILE
);
const componentProps = {
recoveryEmail: this.profile.recoveryEmail ? this.profile.recoveryEmail : '',
recoveryPhone: this.profile.recoveryPhone ? this.profile.recoveryPhone : '',
};
this.validateAndEditContact()
.then(async (_) => {
const popover = await this.popoverCtrl.create({
component: AccountRecoveryInfoComponent,
componentProps,
cssClass: 'popover-alert input-focus'
});
await popover.present();
const { data } = await popover.onDidDismiss();
if (data && data.isEdited) {
const req: UpdateServerProfileInfoRequest = {
userId: this.profile.userId
};
await this.updateProfile(req, 'RECOVERY_ACCOUNT_UPDATE_SUCCESS');
}
})
.catch(err => console.log(err) );
}
async openEnrolledCourse(training) {
try {
const content = this.enrolledCourseList.find((course) => (course.courseId === training.courseId)
&& training.batch.batchId === course.batch.batchId);
this.navService.navigateToTrackableCollection(
{
content
}
);
} catch (err) {
console.error(err);
}
}
private 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.showStoragePermissionPopup().then((result) => {
if (result) {
resolve(true);
} else {
resolve(false);
}
});
}
});
}
private async showStoragePermissionPopup(): 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.appGlobalService.isNativePopupVisible = true;
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);
}
this.appGlobalService.setNativePopupVisible(false);
resolve(undefined);
});
}
}, this.appName, this.commonUtilService.translateMessage
('FILE_MANAGER'), 'FILE_MANAGER_PERMISSION_DESCRIPTION', PageId.PROFILE, true
);
await confirm.present();
});
}
openSelfDeclareTeacherForm(type) {
if (!this.commonUtilService.networkInfo.isNetworkAvailable) {
this.commonUtilService.showToast('NEED_INTERNET_TO_CHANGE');
}
const telemetryId = type === 'add' ? ID.BTN_I_AM_A_TEACHER : ID.BTN_UPDATE;
this.telemetryGeneratorService.generateInteractTelemetry(
InteractType.TOUCH,
'',
Environment.USER,
PageId.PROFILE,
undefined,
undefined,
undefined,
undefined,
telemetryId
);
this.router.navigate([`/${RouterLinks.PROFILE}/${RouterLinks.SELF_DECLARED_TEACHER_EDIT}/${type}`], {
state: {
profile: this.profile
}
});
}
async getSelfDeclaredDetails() {
if (this.isCustodianOrgId && this.profile && this.profile.declarations && this.profile.declarations.length) {
this.selfDeclarationInfo = this.profile.declarations[0];
const tenantPersonaList = await this.formAndFrameworkUtilService.getFormFields(
FormConstants.TENANT_PERSONAINFO, this.profile.rootOrg.rootOrgId);
const tenantConfig: any = tenantPersonaList.find(config => config.code === 'tenant');
const searchOrganizationReq: OrganizationSearchCriteria<{ orgName: string, rootOrgId: string}> = {
filters: {
isTenant: true
},
fields: ['orgName', 'rootOrgId']
};
const organisations = (await this.frameworkService.searchOrganization(searchOrganizationReq).toPromise()).content;
let index = 0;
const organisationList = organisations.map((org) => ({
value: org.rootOrgId,
label: org.orgName,
index: index++
}));
index = 0;
tenantConfig.templateOptions.options = organisationList;
const tenantDetails = tenantConfig.templateOptions && tenantConfig.templateOptions.options &&
tenantConfig.templateOptions.options.find(tenant => tenant.value === this.selfDeclarationInfo.orgId);
this.personaTenantDeclaration = this.commonUtilService.translateMessage('FRMELEMNTS_LBL_SHARE_DATA_WITH', {
'%tenant': (tenantDetails && tenantDetails.label) || ''
});
if (this.selfDeclarationInfo.orgId) {
const formConfig = await this.formAndFrameworkUtilService.getFormFields(
FormConstants.SELF_DECLARATION, this.selfDeclarationInfo.orgId);
const externalIdConfig = formConfig.find(config => config.code === 'externalIds');
this.selfDeclaredDetails = [];
(externalIdConfig.children as FieldConfig<any>[]).forEach(config => {
if (this.profile.declarations[0].info[config.code]) {
this.selfDeclaredDetails.push({ name: config.fieldName, value: this.profile.declarations[0].info[config.code] });
}
});
}
}
}
shareUsername() {
let fullName = this.profile.firstName;
if (this.profile.lastName) {
fullName = fullName + ' ' + this.profile.lastName;
}
const translatedMsg = this.commonUtilService.translateMessage('SHARE_USERNAME', {
app_name: this.appName,
user_name: fullName,
sunbird_id: this.profile.userName
});
this.socialSharing.share(translatedMsg);
}
private async getFrameworkDetails() {
const guestUser = await this.commonUtilService.getGuestUserConfig();
let id = "";
id = guestUser.syllabus[0];
const frameworkDetailsRequest: FrameworkDetailsRequest = {
frameworkId: id,
requiredCategories: FrameworkCategoryCodesGroup.DEFAULT_FRAMEWORK_CATEGORIES
};
await this.frameworkService.getFrameworkDetails(frameworkDetailsRequest).toPromise()
.then(async (framework: Framework) => {
this.frameworkCategoriesMap = framework.categories.reduce((acc, category) => {
acc[category.code] = category;
return acc;
}, {});
this.profile.framework.board = [];
this.profile.framework.medium = [];
this.profile.framework.grade = [];
this.profile.framework.subject = [];
setTimeout(() => {
this.boardList = this.getFieldDisplayValues(guestUser.board, 'board');
this.mediumList = this.getFieldDisplayValues(guestUser.medium, 'medium');
this.gradeLevelList = this.getFieldDisplayValues(guestUser.grade, 'gradeLevel');
this.subjectList = this.getFieldDisplayValues(guestUser.subject, 'subject');
this.profile.framework.board = this.boardList;
this.profile.framework.medium = this.mediumList;
this.profile.framework.gradeLevel = this.gradeLevelList;
this.profile.framework.grade = this.gradeLevelList;
this.profile.framework.subject = this.subjectList;
}, 0);
});
this.profile.userLocations = await this.locationHandler.getAvailableLocation(guestUser, true);
this.userLocation = this.commonUtilService.getUserLocation(this.profile);
this.profile['persona'] = await this.profileHandler.getPersonaConfig(guestUser.profileType.toLowerCase());
}
getFieldDisplayValues(field: Array<any>, categoryCode: string, lowerCase?: boolean): any[] {
const displayValues = [];
if (!this.frameworkCategoriesMap[categoryCode]) {
return displayValues;
}
this.frameworkCategoriesMap[categoryCode].terms.forEach(element => {
if (field.includes(element.code) || field.includes(element.name.replace(/[^a-zA-Z0-9]/g,'').toLowerCase())) {
if (lowerCase) {
displayValues.push(element.name.toLowerCase());
} else {
displayValues.push(element.name);
}
}
});
return displayValues;
}
private getCategories() {
this.formAndFrameworkUtilService.getFrameworkCategoryList().then((categories) => {
this.categories = categories.supportedFrameworkConfig;
});
}
getProjectsCertificate(){
const config ={
url : urlConstants.API_URLS.PROJECT_CERTIFICATES
}
this.unnatiDataService.get(config).subscribe(resp =>{
this.projects = resp.result.data;
})
}
}
<ion-content hide-header-footer overflow-scroll="true" (click)="toggleTooltips($event,'')"
class="main-container avoid-bottom-tabs-space" #contentView scrollEvents="true">
<!-- Pull to Refresh -->
<div class="spinner-div" *ngIf="refresh">
<ion-spinner icon="spiral" class="refreshspinner"></ion-spinner>
</div>
<ion-refresher #refresher slot="fixed" (ionRefresh)="doRefresh($event)">
<ion-refresher-content refreshingSpinner="circles"></ion-refresher-content>
</ion-refresher>
<div class="MT15 ion-text-center ion-padding-horizontal" *ngIf="profile?.firstName">
<app-profile-avatar [username]="profile?.firstName" *ngIf="!isStateValidated"></app-profile-avatar>
<img *ngIf="isStateValidated" src="./assets/imgs/avatar-tickmark.svg" alt="certified" class="avatar-tickmark">
<app-profile-avatar [username]="profile?.firstName" [isStateUser]="isStateValidated" class="profileAvatar"
*ngIf="isStateValidated"></app-profile-avatar>
</div>
<div style="margin-top: 16px" class="ion-text-center ion-padding-horizontal">
<p class="profile-head">
<span class="profile-name">{{ profile?.firstName | titlecase }}{{ profile?.lastName | titlecase }}</span>
</p>
<p class="MT0 MB15">
<span class="app-name"> {{appName}} </span>
<span class="txt-uppercase"> {{'ID' | translate }}: </span>
<span>{{profile?.userName}}</span>
<span role="button" aria-label="Share profile" class="profile-share-icon" (click)="shareUsername()" tabindex="0">
<ion-icon name="share-social" aria-hidden="true" class="share-icon"></ion-icon>
</span>
</p>
</div>
<div class="roles-container ion-text-center ion-padding-horizontal">
<div class="MB5 ion-text-center" *ngFor="let role of roles | slice : startLimit:rolesLimit;">
<div class="roles">
{{role}}
</div>
</div>
<div class="ion-text-center">
<ion-button fill="clear" *ngIf="rolesLimit < roles?.length" (click)="showMoreItems()"
class="txt-capitalize">
+ {{roles?.length - 2}} {{'MORE' | translate}}
<ion-icon role="button" class="ML10" name="arrow-down" aria-label="Show more items"></ion-icon>
</ion-button>
<ion-button fill="clear" *ngIf="rolesLimit > DEFAULT_PAGINATION_LIMIT" (click)="showLessItems()"
class="txt-capitalize">
{{'SHOW_LESS' | translate }}
<ion-icon class="ML10" name="arrow-up" aria-label="show less items"></ion-icon>
</ion-button>
</div>
</div>
<div *ngIf="profile" class="school-details text-center">
<div *ngIf="profile?.persona || profile?.framework" class="preference-info" role="heading" aria-level="2">{{ 'CONTENT_PREFERENCE' | translate }}</div>
<div class="location-mapping-block">
<div *ngIf="profile?.persona?.name" class="text-center">
<div>
<span class="bolder">{{'FRMELEMNTS_LBL_PERSONA' | translate}}: </span>
<span>{{profile?.persona?.name}}</span>
</div>
</div>
<div *ngIf="profile?.subPersona && profile?.subPersona.length" class="text-center">
<div>
<span class="bolder">{{'FRMELEMNTS_LBL_SUBPERSONA' | translate}}: </span>
<span>{{profile?.subPersona.join(', ')}}</span>
</div>
</div>
<div *ngIf="userLocation?.state && userLocation?.state?.name && userLocation?.state?.name?.length">
<span class="bolder">{{'STATE' | translate}}: </span>
<span>{{userLocation.state.name}}</span>
<span *ngIf="!(userLocation?.state && userLocation?.state?.name && userLocation?.state?.name?.length)"
class="lighter">{{'ADD_STATE' | translate}}</span>
</div>
<div *ngIf="userLocation?.district && userLocation?.district?.name && userLocation?.district?.name?.length">
<span class="bolder">{{'DISTRICT' | translate}}: </span>
<span>{{userLocation.district.name}}</span>
<span
*ngIf="!(userLocation?.district && userLocation?.district?.name && userLocation?.district?.name?.length)"
class="lighter">{{'ADD_DISTRICT' | translate}}</span>
</div>
<div *ngIf="userLocation?.block && userLocation?.block?.name && userLocation?.block?.name?.length">
<span class="bolder">{{'FRMELEMNTS_LBL_BLOCK' | translate}}: </span>
<span>{{userLocation.block.name}}</span>
<span *ngIf="!(userLocation?.block && userLocation?.block?.name && userLocation?.block?.name?.length)"
class="lighter">{{'FRMELEMNTS_LBL_ADD_BLOCK' | translate}}</span>
</div>
<div *ngIf="userLocation?.cluster && userLocation?.cluster?.name && userLocation?.cluster?.name?.length">
<span class="bolder">{{'FRMELEMNTS_LBL_CLUSTER' | translate}}: </span>
<span>{{userLocation.cluster.name}}</span>
<span *ngIf="!(userLocation?.cluster && userLocation?.cluster?.name && userLocation?.cluster?.name?.length)"
class="lighter">{{'FRMELEMNTS_LBL_ADD_CLUSTER' | translate}}</span>
</div>
<div *ngIf="userLocation" class="location text-center">
<div *ngIf="userLocation?.school && userLocation?.school?.name && userLocation?.school?.name?.length">
<span class="bolder">{{'FRMELEMNTS_LBL_SCHOOL' | translate}}: </span>
<span>{{userLocation.school.name}}</span>
<span *ngIf="!(userLocation?.school && userLocation?.school?.name && userLocation?.school?.name?.length)"
class="lighter">{{'FRMELEMNTS_LBL_ADD_SCHOOL' | translate}}</span>
</div>
<div class="container MT10 MB10 edit-options">
<ion-button shape="round" aria-label="Edit Role, Block, District, State" (click)="onEditProfileClicked()"
class="custom-round ion-text-capitalize">
{{'EDIT' | translate }}
</ion-button>
</div>
</div>
</div>
<div class="framework-block" *ngIf="profile?.framework && categories.length>0">
<div *ngFor="let category of categories">
<div class="container" *ngIf="profile?.framework[category.frameworkCode]">
<span>{{category.label | translateJson}}: </span>
<span class="bolder">{{profile?.framework[category.frameworkCode].join(', ') | aliased}} ‎</span>
</div>
</div>
<div class="container">
<ion-button shape="round" aria-label="Edit Board, Medium, Classes, subjects" (click)="navigateToCategoriesEditPage()" class="custom-round ion-text-capitalize">
{{'EDIT' | translate }}
</ion-button>
</div>
</div>
</div>
<div class="self-declare-btn text-center" *ngIf="!profile?.declarations?.length && !profile?.isMinor && isCustodianOrgId">
<ion-button shape="round" (click)="openSelfDeclareTeacherForm('add')">
{{'SUBMIT_MY_DETAILS' | translate}}
</ion-button>
</div>
<div class="contacts" *ngIf="!profile?.managedBy && (profile?.phone || profile?.email)">
<div *ngIf="profile?.phone">
<div class="phone" role="button" (click)="editMobileNumber();">
<span class="icon MR10 align-middle">
<ion-icon aria-hidden="true" name="call"></ion-icon>
</span>
<span class="value align-middle">+91 {{ profile?.phone }}</span>
</div>
</div>
<div *ngIf="!profile?.phone">
<div class="phone light" role="button" (click)="editMobileNumber();" tabindex="0">
<span class="icon MR10 align-middle">
<ion-icon aria-hidden="true" name="call"></ion-icon>
</span>
<span class="value align-middle">{{'ADD_PHONE' | translate}}</span>
</div>
</div>
<div *ngIf="profile?.email">
<div class="email " role="button" (click)="editEmail();" tabindex="0">
<span class="icon MR10 align-middle">
<ion-icon aria-hidden="true" name="mail"></ion-icon>
</span>
<span class="value align-middle">{{ profile?.email }}</span>
</div>
</div>
<div *ngIf="!profile?.email">
<div class="email light" role="button" (click)="editEmail();" tabindex="0">
<span class="icon MR10 align-middle">
<ion-icon aria-hidden="true" name="mail"></ion-icon>
</span>
<span class="value align-middle">{{'ADD_EMAIL' | translate}}</span>
</div>
</div>
<div class="MT10" *ngIf=" ( profile?.recoveryEmail?.length > 0 ) || ( profile?.recoveryPhone?.length > 0 )">
<div class="email" role="button" (click)="editRecoveryId();">
<span class="icon MR10 align-middle">
<ion-icon src="assets/imgs/recovery_icon.svg"></ion-icon>
</span>
<span class="value align-middle" *ngIf="profile?.recoveryEmail?.length > 0">{{ profile?.recoveryEmail
}}</span>
<span class="value align-middle" *ngIf="profile?.recoveryPhone?.length > 0">
+91 {{ profile?.recoveryPhone }}
</span>
</div>
</div>
<div class="MT10" *ngIf="(!profile?.recoveryEmail && !profile?.recoveryPhone) ||
((profile?.recoveryEmail?.length === 0) && (profile?.recoveryPhone?.length === 0))">
<div class="email light" role="button" (click)="editRecoveryId();" tabindex="0">
<span class="icon MR10 align-middle">
<ion-icon src="assets/imgs/recovery_icon.svg"></ion-icon>
</span>
<span class="value align-middle">{{'ADD_RECOVERY_ID' | translate}}</span>
</div>
</div>
</div>
<div class="self-declare-teacher-details" *ngIf="isCustodianOrgId && profile?.declarations?.length">
<p class="declare-info">{{'MY_DETAILS' | translate | titlecase }}</p>
<div class="container" *ngIf="personaTenantDeclaration">
<div>{{personaTenantDeclaration}}</div>
</div>
<div class="container" *ngFor="let details of selfDeclaredDetails">
<div>{{ details.name | translate }}:</div>
<div class="bolder">{{ details.value }}</div>
</div>
<ion-button shape="round" (click)="openSelfDeclareTeacherForm('edit')" class="custom-round">
{{'UPDATE' | translate }}
</ion-button>
</div>
<div class="badges ion-text-center ion-padding-horizontal" *ngIf="profile?.badgeAssertions?.length > 0">
<p class="bolder f16">{{'MY_BADGES' | translate }} ({{profile?.badgeAssertions?.length}})‎</p>
<ion-avatar item-center="" *ngFor="let batch of profile.badgeAssertions | slice : startLimit:badgesLimit;">
<img height="80px" width="auto" alt="badge" [src]="commonUtilService.convertFileSrc(batch.badgeClassImage)">
</ion-avatar>
<div class="ion-text-center">
<ion-button shape="round" *ngIf="badgesLimit < profile?.badgeAssertions?.length" (click)="showMoreBadges()"
class="txt-capitalize custom-round">
+ {{profile?.badgeAssertions?.length - 2}} {{'MORE' | translate}}
<ion-icon role="button" class="ML10" name="arrow-down" aria-label="Show more badges"></ion-icon>
</ion-button>
<ion-button shape="round" *ngIf="badgesLimit > DEFAULT_PAGINATION_LIMIT" (click)="showLessBadges()"
class="txt-capitalize custom-round">
{{'SHOW_LESS' | translate }}
<ion-icon class="ML10" role="button" name="arrow-up" aria-label="Show Less badges"></ion-icon>
</ion-button>
</div>
</div>
<div class="bottom-block" *ngIf="mappedTrainingCertificates?.length > 0 || projects?.length > 0 || learnerPassbook?.length > 0 || contentCreatedByMe.length > 0">
<div class="trainings" *ngIf="mappedTrainingCertificates?.length > 0">
<div class="bolder heading f16">
<span>{{'FRMELEMNTS_LBL_MY_LEARNINGS' | translate}} ({{mappedTrainingCertificates?.length}})‎</span>
<span role="button" aria-label="Refresh"><ion-icon role="button" aria-label="Refresh" name="refresh-circle" class="refresh-icon"
(click)="getEnrolledCourses(true, true)"></ion-icon></span>
</div>
<div class="content">
<div *ngFor="let training of (mappedTrainingCertificates | slice : startLimit:myLearningLimit) |sortBy: 'status' : 'asc'; let i = index;"
[ngClass]="{'flex-nowrap': i !== mappedTrainingCertificates.length-1, 'flex-nowrap-last': i == mappedTrainingCertificates.length-1}">
<div class="training-1">
<div class="fw sb__ellipsis sb__ellipsis--two" (click)="openEnrolledCourse(training)">
{{training.courseName}}
</div>
<div class="batch-detail">
{{training?.batch?.name}}
</div>
<div>
<span [ngClass]="[training.style]"> {{ training.label | translate }}</span>
<span class="lighter"> {{training.dateTime | date:'dd/MM/yyyy'}} </span>
</div>
</div>
<div class="training-2" *ngIf="training?.certificate || training?.issuedCertificate">
<button class="sb-btn-tile ion-activatable ripple-parent"
(click)="downloadTrainingCertificate(training)">
<ion-icon class="view-icon" name="eye"></ion-icon>
<span class="sb-btn-footer-text m-t-4">{{ 'CERTIFICATE' | translate }}</span>
<ion-ripple-effect type="unbounded"></ion-ripple-effect>
</button>
</div>
</div>
<div class="ion-text-center"
*ngIf="mapTrainingsToCertificates(mappedTrainingCertificates).length > myLearningLimit">
<ion-button shape="round" class="txt-capitalize custom-round"
*ngIf="myLearningLimit < mappedTrainingCertificates?.length"
(click)="showMoreTrainings('myLearning')">
+ {{mappedTrainingCertificates?.length - myLearningLimit}} {{'MORE' | translate}}
<ion-icon class="ML10" name="arrow-down" aria-label="show more trainings"></ion-icon>
</ion-button>
<ion-button shape="round" class="txt-capitalize custom-round"
*ngIf="myLearningLimit >= mappedTrainingCertificates?.length"
(click)="showLessTrainings('myLearning')">
{{'SHOW_LESS' | translate }}
<ion-icon role="button" class="ML10" name="arrow-up" aria-label="show less trainings"></ion-icon>
</ion-button>
</div>
</div>
</div>
<!-- Projects -->
<div class="trainings" *ngIf="projects?.length > 0">
<div class="bolder heading f16">
<span>{{'FRMELEMNTS_LBL_IMP_CERTIFICATE' | translate}} ({{projects?.length}})‎</span>
<span role="button" aria-label="Refresh"><ion-icon role="button" aria-label="Refresh" name="refresh-circle" class="refresh-icon"
(click)="getProjectsCertificate()"></ion-icon></span>
</div>
<div class="content">
<div *ngFor="let training of (projects | slice : startLimit:myImprovementsLimit) |sortBy: 'status' : 'asc'; let i = index;"
[ngClass]="{'flex-nowrap': i !== projects.length-1, 'flex-nowrap-last': i == projects.length-1}">
<div class="training-1">
<div class="fw sb__ellipsis sb__ellipsis--two">
{{training.title}}
</div>
<div class="batch-detail">
{{training.completedDate | date :'dd/MM/yyyy'}}
</div>
<div class="batch-detail" [ngClass]="{'project-submitted': training.status === projectStatus.submitted}">
{{training?.status | titlecase}}
</div>
<div>
<span [ngClass]="[training.style]"> {{ training.label | translate }}</span>
<span class="lighter"> {{training.dateTime | date:'dd/MM/yyyy'}} </span>
</div>
</div>
<div class="training-2" *ngIf="training?.certificate || training?.issuedCertificate">
<button class="sb-btn-tile ion-activatable ripple-parent"
(click)="downloadCertificate(training,'project')">
<ion-icon class="view-icon" name="eye"></ion-icon>
<span class="sb-btn-footer-text m-t-4">{{ 'CERTIFICATE' | translate }}</span>
<ion-ripple-effect type="unbounded"></ion-ripple-effect>
</button>
</div>
</div>
<div class="ion-text-center"
*ngIf="projects.length > myImprovementsLimit">
<ion-button shape="round" class="custom-btn-txt-transform-none custom-round"
*ngIf="myImprovementsLimit < projects?.length"
(click)="showMoreTrainings('myImprovements')">
{{'FRMELEMNTS_BTN_LOAD_MORE' | translate}}
<ion-icon class="ML10" name="arrow-down" aria-label="show more trainings"></ion-icon>
</ion-button>
<ion-button shape="round" class="custom-btn-txt-transform-none custom-round"
*ngIf="myImprovementsLimit >= projects?.length"
(click)="showLessTrainings('myImprovements')">
{{'SHOW_LESS' | translate }}
<ion-icon role="button" class="ML10" name="arrow-up" aria-label="show less trainings"></ion-icon>
</ion-button>
</div>
</div>
</div>
<div class="trainings" *ngIf="learnerPassbook?.length > 0">
<div class="bolder heading f16">
<span>{{'FRMELEMNTS_LBL_LEARNER_PASSBOOK' | translate}} ({{learnerPassbookCount}})‎</span>
</div>
<div class="content">
<div *ngFor="let certificate of (learnerPassbook | slice : startLimit:learnerPassbookLimit) |sortBy: 'status' : 'asc'; let i = index;"
[ngClass]="{'flex-nowrap': i !== learnerPassbook.length-1, 'flex-nowrap-last': i == learnerPassbook.length-1}">
<div class="training-1">
<div class="fw sb__ellipsis sb__ellipsis--two" (click)="openEnrolledCourse(certificate)">
{{certificate.courseName}}
</div>
<div>
<span class="lighter">{{certificate.issuedOn | date:'dd/MM/yyyy'}} </span>
</div>
</div>
<div class="training-2" *ngIf="certificate?.certificate || certificate?.issuedCertificate">
<button class="sb-btn-tile ion-activatable ripple-parent"
(click)="downloadTrainingCertificate(certificate)">
<ion-icon class="view-icon" name="eye"></ion-icon>
<span class="sb-btn-footer-text m-t-4">{{ 'CERTIFICATE' | translate }}</span>
<ion-ripple-effect type="unbounded"></ion-ripple-effect>
</button>
</div>
</div>
<div class="ion-text-center" *ngIf="learnerPassbook.length >= learnerPassbookLimit">
<ion-button shape="round" class="txt-capitalize custom-round"
*ngIf="learnerPassbookLimit < learnerPassbook?.length"
(click)="showMoreTrainings('learnerPassbook')">
+ {{learnerPassbookCount - learnerPassbookLimit}} {{'MORE' | translate}}
<ion-icon class="ML10" role="button" name="arrow-down" aria-label="more"></ion-icon>
</ion-button>
<ion-button shape="round" class="txt-capitalize custom-round"
*ngIf="learnerPassbookLimit >= learnerPassbook?.length"
(click)="showLessTrainings('learnerPassbook')">
{{'SHOW_LESS' | translate }}
<ion-icon class="ML10" role="button" name="arrow-up" aria-label="show less trainings"></ion-icon>
</ion-button>
</div>
</div>
</div>
<div class="contributions" *ngIf="contentCreatedByMe.length > 0">
<div class="bolder f16" style="padding: 15px; background-color: #fff; margin-bottom: 2px;">
{{'CONTRIBUTIONS' | translate}} ({{contentCreatedByMe.length}})‎
</div>
<div class="cards-container" style="padding:0 5px; background-color: #fff; overflow-x: scroll; ">
<div style="width: 100%" class="ion-no-padding">
<div class="flex-container" *ngIf="contentCreatedByMe && isLoggedInUser">
<ion-card *ngFor="let courseItem of contentCreatedByMe; let i=index"
(click)="navigateToDetailPage(courseItem, layoutPopular, i);"
style="min-width: 84%;height: 10.313rem;">
<ion-card-content>
<ion-row class="top">
<ion-col size="3" class="img-container">
<img class="app-icon" alt="app"
[src]="commonUtilService.convertFileSrc(courseItem?.appIcon)" />
</ion-col>
<ion-col size="9" style="margin-bottom: 5px; padding: 0 0 0 15px;">
<div style="margin-bottom: 5px;" *ngIf="courseItem.resourceType">
<ion-button fill="outline" class="badge">
{{courseItem?.resourceType}}
</ion-button>
</div>
<div class="f11 ellipsis info" *ngIf="courseItem.subject">
{{'SUBJECT'| translate}}: {{courseItem?.subject}}
</div>
<div class="f11 ellipsis info"
*ngIf="courseItem.gradeLevel && courseItem.gradeLevel.length">
{{'CLASS' | translate}}: {{courseItem?.gradeLevel}}
</div>
<div class="f11 ellipsis info" *ngIf="courseItem.medium">
{{'MEDIUM' | translate}}: {{courseItem?.medium}}
</div>
</ion-col>
</ion-row>
<ion-row>
<ion-col size="12" class="PTB0">
<h6 class="name second-line-ellipsis">{{courseItem?.name}}</h6>
</ion-col>
<ion-col size="12" class="PTB0">
<p class="author">{{courseItem?.creator}}</p>
</ion-col>
</ion-row>
</ion-card-content>
</ion-card>
</div>
</div>
</div>
</div>
</div>
</ion-content>
./profile.page.scss
@import "src/assets/styles/variables";
@import "src/assets/styles/base/_variables.scss";
@import "src/assets/styles/_custom-mixins";
@import "src/assets/styles/fonts";
@import "src/assets/styles/_variables.scss";
:host {
.refreshspinner {
stroke: $blue !important;
width: 1.875rem;
left: 0;
top: 0;
height: 2.5rem;
position: relative !important;
}
.spinner-div {
padding: 40px;
background-color: map-get($colors, light_gray);
text-align: center;
border: none !important;
}
.profile-last-login-text {
color: map-get($colors, light_gray_bd);
text-align: center;
@include margin(0);
font-size: 1.2rem;
@include padding(0, 5px, 8px, 5px);
}
.profile-name {
color: map-get($colors, dark);
text-align: center;
font-size: 2rem;
@extend .font-weight-bold;
@include margin(0);
@include padding(10px, 5px, 0, 5px);
}
.profile-head {
position: relative;
.profile-symbol {
position: absolute;
top: -0.375rem;
}
}
.profile-share-icon{
.share-icon{
color: $blue;
position: relative;
top: 0.375rem;
margin-left: 8px;
}
}
ion-row {
@include padding(0 !important);
}
ion-spinner {
position: absolute;
display: inline-block;
width: 1.25rem;
left: 47vw;
top: 10vh;
height: 1.25rem;
}
.badges {
ion-avatar img,
ion-thumbnail img {
display: block;
@include margin(30px auto);
}
}
ion-card {
border-radius: 4px;
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.16);
background-color: map-get($colors, white);
border: solid 0.5px map-get($colors, medium_gray);
width: 80vw;
display: inline-block;
.badge {
color: map-get($colors, primary);
font-size: 0.688rem;
height: 1.25rem;
box-shadow: none;
--border-width: 0.031rem;
@extend .font-weight-400;
text-transform: capitalize;
letter-spacing: normal;
}
.top {
min-height: 5.313rem;
.img-container {
border: 1px solid map-get($colors, pale_cyan);
@include padding(0 !important);
background: map-get($colors, white_e9);
min-height: 5.313rem;
max-height: 5.313rem;
border-radius: 4px;
img {
max-height: 5.313rem;
@include margin(0 auto);
width: auto;
transform: translateY(-56%);
position: relative;
top: 50%;
}
}
.info {
color: map-get($colors, dark_gray_61);
}
}
h6.name {
word-break: break-all;
white-space: normal;
min-height: 2rem;
font-size: 0.875rem !important;
color: map-get($colors, primary_black);
width: 100%;
}
h6.second-line-ellipsis {
-webkit-line-clamp: 2;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
height: 2rem;
}
.author {
font-size: 0.813rem;
font-weight: normal;
font-style: normal;
font-stretch: normal;
line-height: normal;
letter-spacing: normal;
color: map-get($colors, granite_gray);
min-height: 1.25rem;
}
}
.roles-container {
color: map-get($colors, primary_blue);
@include margin(5px, 0);
}
.roles {
border: 0.5px solid map-get($colors, primary_blue);
@include padding(4px, 15px);
border-radius: 4px;
display: inline-block;
}
.school-recent {
margin: 0 auto;
@include padding(8px, 16px, 8px, 16px);
text-align: center;
}
.sb-btn-footer-text {
color : $gray;
font-weight: 100;
font-size: ($font-size-base - 0.125);
text-align: center;
text-transform: initial;
}
.sb-btn-tile {
position: relative;
flex-direction: column;
background-color: $white;
width:4.5rem;
height:4.5rem;
display: flex;
align-items: center;
justify-content: center;
.view-icon{
color: $blue;
}
.sb-btn-footer-text {
font-weight: 400;
color: $blue;
}
}
button.sb-btn-tile:focus {
outline: none;
}
.sb-dt-card-blue-icon{
font-size : ($font-size-base * 2) + 0.125;
color: $primary-color;
@include margin(0, 0, ($base-block-space * .5), 0);
}
.contacts {
padding: 15px;
background-color: map-get($colors, bright_blue_19);
text-align: center;
.phone {
display: inline-block;
border-radius: 25px;
@include padding($base-block-space, $base-block-space * 2);
@include margin(null, null, 10px, null);
background-color: map-get($colors, white);
color: map-get($colors, primary_blue);
&.light {
color: $signup-btn-bg-not-active-color;
}
}
.email {
display: inline-block;
border-radius: 25px;
@include padding($base-block-space, $base-block-space * 2);
background-color: map-get($colors, white);
color: map-get($colors, primary_blue);
border-bottom: 0.3px solid map-get($colors, bright_blue_19);
border-top: 0.3px solid map-get($colors, bright_blue_19);
&.light {
color: map-get($colors, gray_9b);
}
}
}
.school-details {
padding: 15px;
background-color: map-get($colors, pale_blue_e0);
text-align: center;
border-bottom: 0.3px solid map-get($colors, bright_blue_19);
border-top: 0.3px solid map-get($colors, bright_blue_19);
.container {
text-align: center;
@include margin(null, null, 10px, null);
}
}
.trainings {
.heading {
@include padding(15px);
background-color: map-get($colors, white);
@include margin(null, null, 2px, null);
border-bottom: 0.5px solid map-get($colors, dark_gray);
}
.content {
@include margin(8px);
background-color: map-get($colors, white);
border: 0.5px solid map-get($colors, dark_gray);
border-radius: 4px;
}
}
.contributions {
min-height: 14.375rem;
@include margin(0, 0, 16px, 0);
background: map-get($colors, white);
}
.short-btn {
height: 1.625rem;
}
.custom-round {
border-radius: 64px !important;
--background: #024F9D !important;
}
.bottom-block {
background: map-get($colors, white_fa);
}
.align-middle {
vertical-align: middle;
display: inline-block;
}
.avatar-tickmark {
width: $base-block-space*4;
height: $base-block-space*4;
position: absolute;
left: 53%;
}
.training-1 {
width: 80%;
float: left;
padding-left: 2rem;
@include padding(16px, null, 8px, null);
}
.training-2 {
.sb-btn-tile {
margin: 0.5rem 0 !important;
}
}
.batch-detail {
color: var(--app-primary);
}
.flex-nowrap {
display: flex;
justify-content: space-between;
flex-wrap: nowrap;
border-bottom: 0.5px solid map-get($colors, dark_gray);
@include padding(null, 16px, null, 16px);
}
.flex-nowrap-last {
display: flex;
justify-content: space-between;
flex-wrap: nowrap;
@include padding(null, 16px, null, 16px);
}
.margin-pull-up {
margin-top: -18px;
}
.m-t-4 {
margin-top: 4px;
}
.cert-download {
width:2.188rem;
height:1.563rem;
margin-bottom: 4px;
}
.add-size{
font-size: 1.5rem;
padding-right: 8px;
}
.enrolled-status-text {
font-family: "Noto Sans", sans-serif;
font-size: 0.75rem;
font-weight: bold;
}
.ongoing-status-text{
@extend .enrolled-status-text;
color: $blue;
}
.completed-status-text{
@extend .enrolled-status-text;
color: $green;
}
.self-declare-btn{
margin: 8px 0 16px;
ion-button{
text-transform: none;
--background: #{map-get($colors, dark_green)};
--padding-start: 24px;
--padding-end: 24px;
}
}
.self-declare-teacher-details{
padding: 16px;
background-color: map-get($colors, bright_blue_19);
text-align: center;
color: map-get($colors, white);
font-size: $font-size-base;
.container{
@include margin(null, null, 8px, null);
}
ion-button{
text-transform: none;
--padding-start: 24px;
--padding-end: 24px;
}
.declare-info{
margin: 0;
font-size: $font-size-base;
font-weight: bold;
}
}
.app-name{
text-transform: lowercase;
display: inline-block;
}
.app-name::first-letter{
text-transform: capitalize
}
.refresh-icon {
color: map-get($colors, primary_blue);
float: right;
height: 2.5rem !important;
width: 2.5rem !important;
margin-top: -0.5rem;
}
ion-icon.refresh-icon.md.hydrated:active {
background: map-get($colors, white_e8);
border-radius: 18px;
}
.declared-error-container{
margin: auto;
@include margin(null, null, 8px, null);
width: 50%;
border: 1px solid map-get($colors, danger);
border-left: 5px solid map-get($colors, danger);
border-radius: 10px;
background: map-get($colors, white);
@include padding(8px, 0, 8px, 0);
.declared-status{
color: map-get($colors, danger);
}
.declared-message{
color: map-get($colors, black);
}
}
.preference-info {
font-size: 1.3rem;
font-weight: 600;
text-align: center;
}
.framework-block {
border-style: double;
margin-top: 8px;
border-radius: 1rem;
background-color: aliceblue;
border-color: aliceblue;
padding-top: 12px;
}
.location-mapping-block {
border-style: double;
border-radius: 1rem;
background-color: aliceblue;
border-color: aliceblue;
padding-top: 12px;
}
}
.project-submitted{
color : var(--app-green) !important;
}