src/app/plugins/profile/components/profile-page/profile-page.component.ts
OnInit
OnDestroy
AfterViewInit
providers |
CertificateDownloadAsPdfService
|
styleUrls | ./profile-page.component.scss |
templateUrl | ./profile-page.component.html |
constructor(courseCService: CsCourseService, cacheService: CacheService, resourceService: ResourceService, coursesService: CoursesService, toasterService: ToasterService, profileService: ProfileService, userService: UserService, configService: ConfigService, router: Router, utilService: UtilService, searchService: SearchService, playerService: PlayerService, activatedRoute: ActivatedRoute, orgDetailsService: OrgDetailsService, navigationhelperService: NavigationHelperService, certRegService: CertRegService, telemetryService: TelemetryService, layoutService: LayoutService, formService: FormService, certDownloadAsPdf: CertificateDownloadAsPdfService, connectionService: ConnectionService, CsCertificateService: CsCertificateService)
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Parameters :
|
convertToString | ||||
convertToString(value)
|
||||
Parameters :
Returns :
any
|
copyToClipboard | ||||
copyToClipboard(userName)
|
||||
Parameters :
Returns :
void
|
downloadCert | ||||
downloadCert(course)
|
||||
Parameters :
Returns :
void
|
downloadOldAndRCCert | ||||
downloadOldAndRCCert(courseObj)
|
||||
Parameters :
Returns :
void
|
downloadPdfCertificate | ||||
downloadPdfCertificate(value)
|
||||
Parameters :
Returns :
void
|
getContribution |
getContribution()
|
Returns :
void
|
Private getCustodianOrgUser |
getCustodianOrgUser()
|
Returns :
void
|
getLocationDetails | ||||||
getLocationDetails(locations, type)
|
||||||
Parameters :
Returns :
any
|
getNavParams |
getNavParams()
|
Returns :
void
|
getOrgDetails |
getOrgDetails()
|
Returns :
void
|
getOtherCertificates | |||||||||
getOtherCertificates(userId, certType)
|
|||||||||
It will fetch certificates of user, other than courses
Parameters :
Returns :
void
|
Private Async getPersonaConfig | ||||||
getPersonaConfig(persona: string)
|
||||||
Parameters :
Returns :
unknown
|
getSelfDeclaredDetails |
getSelfDeclaredDetails()
|
Returns :
void
|
Private Async getSubPersonaConfig |
getSubPersonaConfig(persona: string, userLocation: any)
|
Returns :
Promise<string[]>
|
getTrainingAttended |
getTrainingAttended()
|
Returns :
void
|
Private getUserLocation | ||||||
getUserLocation(profile: any)
|
||||||
Parameters :
Returns :
{}
|
goBack |
goBack()
|
Returns :
void
|
initLayout |
initLayout()
|
Returns :
void
|
navigate | ||||||
navigate(url, formAction)
|
||||||
Parameters :
Returns :
void
|
navigateToCourse | ||||||
navigateToCourse(coursedata)
|
||||||
Parameters :
Returns :
void
|
ngAfterViewInit |
ngAfterViewInit()
|
Returns :
void
|
ngOnDestroy |
ngOnDestroy()
|
Returns :
void
|
ngOnInit |
ngOnInit()
|
Returns :
void
|
Public onLocationModalClose | ||||
onLocationModalClose(event)
|
||||
Parameters :
Returns :
void
|
openContent | ||||
openContent(content)
|
||||
Parameters :
Returns :
void
|
Public prepareVisits | ||||
prepareVisits(event)
|
||||
Parameters :
Returns :
void
|
setInteractEventData |
setInteractEventData()
|
Returns :
void
|
setNonCustodianUserLocation |
setNonCustodianUserLocation()
|
Returns :
void
|
toggle | ||||
toggle(showMore)
|
||||
Parameters :
Returns :
void
|
toggleCourse | ||||||
toggleCourse(showMoreCourse, courseLimit)
|
||||||
Parameters :
Returns :
void
|
toggleOtherCertific | ||||
toggleOtherCertific(showMore)
|
||||
Parameters :
Returns :
void
|
triggerAutoScroll |
triggerAutoScroll()
|
Returns :
void
|
updateProfile | ||||
updateProfile(data)
|
||||
Parameters :
Returns :
void
|
addRecoveryIdInteractEdata |
Type : IInteractEventEdata
|
attendedTraining |
Type : Array<object>
|
avatarConfig |
Type : object
|
Default value : {
size: this.configService.constants.SIZE.LARGE,
view: this.configService.constants.VIEW.VERTICAL,
isTitle:false
}
|
Public certRegService |
Type : CertRegService
|
Public configService |
Type : ConfigService
|
contributions |
Type : []
|
Default value : []
|
courseLimit |
Default value : this.configService.appConfig.PROFILE.defaultViewMoreLimit
|
Public coursesService |
Type : CoursesService
|
declarationDetails |
Private Static Readonly DEFAULT_PERSONA_LOCATION_CONFIG_FORM_REQUEST |
Type : object
|
Default value : { formType: 'profileConfig_v2', contentType: 'default', formAction: 'get' }
|
districtObj |
downloadCertificateEData |
Type : IInteractEventEdata
|
downloadOthersCertificateEData |
Type : IInteractEventEdata
|
editEmailInteractEdata |
Type : IInteractEventEdata
|
editMobileInteractEdata |
Type : IInteractEventEdata
|
editProfileInteractEdata |
Type : IInteractEventEdata
|
editRecoveryIdInteractEdata |
Type : IInteractEventEdata
|
emailObj |
Type : literal type
|
externalIds |
Type : literal type
|
instance |
Type : string
|
isConnected |
Default value : true
|
isCustodianOrgUser |
Default value : true
|
isDesktopApp |
layoutConfiguration |
Type : any
|
Public layoutService |
Type : LayoutService
|
myFrameworkEditEdata |
Type : IInteractEventEdata
|
Public navigationhelperService |
Type : NavigationHelperService
|
nonCustodianUserLocation |
Type : object
|
Default value : {}
|
orgDetails |
Type : any
|
Default value : []
|
Public orgDetailsService |
Type : OrgDetailsService
|
otherCertificateLimit |
Default value : this.configService.appConfig.PROFILE.defaultViewMoreLimit
|
otherCertificates |
Type : Array<object>
|
otherCertificatesCounts |
Type : number
|
persona |
Type : literal type
|
phoneObj |
Type : literal type
|
profileModal |
Decorators :
@ViewChild('profileModal')
|
Public profileService |
Type : ProfileService
|
Public resourceService |
Type : ResourceService
|
roles |
Type : Array<string>
|
Public router |
Type : Router
|
schoolObj |
Type : literal type
|
scrollToId |
Public searchService |
Type : SearchService
|
selfDeclaredErrorTypes |
Type : []
|
Default value : []
|
selfDeclaredInfo |
Type : []
|
Default value : []
|
showContactPopup |
Default value : false
|
showEdit |
Default value : false
|
showEditUserDetailsPopup |
Default value : false
|
showFullScreenLoader |
Default value : false
|
showMoreCertificates |
Default value : true
|
showMoreRoles |
Default value : true
|
showMoreRolesLimit |
Default value : this.configService.appConfig.PROFILE.defaultShowMoreLimit
|
showMoreTrainings |
Default value : true
|
showRecoveryId |
Default value : false
|
slickModal |
Decorators :
@ViewChild('slickModal')
|
stateObj |
submitTeacherDetailsInteractEdata |
Type : IInteractEventEdata
|
subPersona |
Type : string[]
|
Private Static Readonly SUPPORTED_PERSONA_LIST_FORM_REQUEST |
Type : object
|
Default value : { formType: 'config', formAction: 'get', contentType: 'userType', component: 'portal' }
|
teacherObj |
Type : literal type
|
telemetryImpression |
Type : IImpressionEventInput
|
tenantInfo |
Public toasterService |
Type : ToasterService
|
totalContributions |
Type : Number
|
udiseObj |
Type : literal type
|
Public unsubscribe$ |
Default value : new Subject<void>()
|
updateTeacherDetailsInteractEdata |
Type : IInteractEventEdata
|
userFrameWork |
Type : any
|
userLocation |
Type : literal type
|
userProfile |
Type : any
|
Public userService |
Type : UserService
|
userSubscription |
Type : Subscription
|
Public utilService |
Type : UtilService
|
import {ProfileService} from '../../services';
import { AfterViewInit, Component, OnDestroy, OnInit, ViewChild, Inject } from '@angular/core';
import {
CertRegService,
CoursesService,
OrgDetailsService,
PlayerService,
SearchService,
UserService,
FormService
} from '@sunbird/core';
import {
ConfigService,
IUserData, LayoutService,
NavigationHelperService,
ResourceService,
ServerResponse,
ToasterService,
UtilService,
ConnectionService
} from '@sunbird/shared';
import * as _ from 'lodash-es';
import {Subject, Subscription} from 'rxjs';
import {IImpressionEventInput, IInteractEventEdata, TelemetryService} from '@sunbird/telemetry';
import {ActivatedRoute, Router} from '@angular/router';
import { CacheService } from '../../../../modules/shared/services/cache-service/cache.service';
import {takeUntil} from 'rxjs/operators';
import { CertificateDownloadAsPdfService } from 'sb-svg2pdf-v13';
import { CsCourseService } from '@project-sunbird/client-services/services/course/interface';
import { FieldConfig, FieldConfigOption } from '@project-sunbird/common-form-elements-full';
import { CsCertificateService } from '@project-sunbird/client-services/services/certificate/interface';
@Component({
templateUrl: './profile-page.component.html',
styleUrls: ['./profile-page.component.scss'],
providers: [CertificateDownloadAsPdfService]
})
export class ProfilePageComponent implements OnInit, OnDestroy, AfterViewInit {
private static readonly SUPPORTED_PERSONA_LIST_FORM_REQUEST =
{ formType: 'config', formAction: 'get', contentType: 'userType', component: 'portal' };
private static readonly DEFAULT_PERSONA_LOCATION_CONFIG_FORM_REQUEST =
{ formType: 'profileConfig_v2', contentType: 'default', formAction: 'get' };
@ViewChild('profileModal') profileModal;
@ViewChild('slickModal') slickModal;
userProfile: any;
contributions = [];
totalContributions: Number;
attendedTraining: Array<object>;
roles: Array<string>;
showMoreRoles = true;
showMoreTrainings = true;
showMoreCertificates = true;
isCustodianOrgUser = true; // set to true to avoid showing icon before api return value
showMoreRolesLimit = this.configService.appConfig.PROFILE.defaultShowMoreLimit;
courseLimit = this.configService.appConfig.PROFILE.defaultViewMoreLimit;
otherCertificateLimit = this.configService.appConfig.PROFILE.defaultViewMoreLimit;
showEdit = false;
userSubscription: Subscription;
orgDetails: any = [];
showContactPopup = false;
showEditUserDetailsPopup = false;
userFrameWork: any;
telemetryImpression: IImpressionEventInput;
myFrameworkEditEdata: IInteractEventEdata;
editProfileInteractEdata: IInteractEventEdata;
editMobileInteractEdata: IInteractEventEdata;
editEmailInteractEdata: IInteractEventEdata;
downloadCertificateEData: IInteractEventEdata;
editRecoveryIdInteractEdata: IInteractEventEdata;
addRecoveryIdInteractEdata: IInteractEventEdata;
submitTeacherDetailsInteractEdata: IInteractEventEdata;
updateTeacherDetailsInteractEdata: IInteractEventEdata;
showRecoveryId = false;
otherCertificates: Array<object>;
otherCertificatesCounts: number;
downloadOthersCertificateEData: IInteractEventEdata;
udiseObj: { idType: string, provider: string, id: string };
phoneObj: { idType: string, provider: string, id: string };
emailObj: { idType: string, provider: string, id: string };
teacherObj: { idType: string, provider: string, id: string };
stateObj;
districtObj;
externalIds: {};
schoolObj: { idType: string, provider: string, id: string };
instance: string;
layoutConfiguration: any;
public unsubscribe$ = new Subject<void>();
nonCustodianUserLocation: object = {};
declarationDetails;
tenantInfo;
selfDeclaredInfo = [];
selfDeclaredErrorTypes = [];
scrollToId;
isDesktopApp;
userLocation: {};
persona: {};
subPersona: string[];
isConnected = true;
showFullScreenLoader = false;
avatarConfig = {
size: this.configService.constants.SIZE.LARGE,
view: this.configService.constants.VIEW.VERTICAL,
isTitle:false
};
constructor(@Inject('CS_COURSE_SERVICE') private courseCService: CsCourseService, private cacheService: CacheService,
public resourceService: ResourceService, public coursesService: CoursesService,
public toasterService: ToasterService, public profileService: ProfileService, public userService: UserService,
public configService: ConfigService, public router: Router, public utilService: UtilService, public searchService: SearchService,
private playerService: PlayerService, private activatedRoute: ActivatedRoute, public orgDetailsService: OrgDetailsService,
public navigationhelperService: NavigationHelperService, public certRegService: CertRegService,
private telemetryService: TelemetryService, public layoutService: LayoutService, private formService: FormService,
private certDownloadAsPdf: CertificateDownloadAsPdfService, private connectionService: ConnectionService,
@Inject('CS_CERTIFICATE_SERVICE') private CsCertificateService: CsCertificateService) {
this.getNavParams();
}
getNavParams() {
this.scrollToId = _.get(this.router.getCurrentNavigation(), 'extras.state.scrollToId');
}
ngOnInit() {
this.isDesktopApp = this.utilService.isDesktopApp;
this.activatedRoute.queryParams.subscribe((params) => {
if (params['showEditUserDetailsPopup']) {
this.showEditUserDetailsPopup = true;
}
});
if (this.isDesktopApp) {
this.connectionService.monitor()
.pipe(takeUntil(this.unsubscribe$)).subscribe(isConnected => {
this.isConnected = isConnected;
});
}
this.initLayout();
this.instance = _.upperFirst(_.toLower(this.resourceService.instance || 'SUNBIRD'));
this.getCustodianOrgUser();
this.userSubscription = this.userService.userData$.subscribe((user: IUserData) => {
/* istanbul ignore else */
this.showFullScreenLoader = false;
if (user.userProfile) {
this.userProfile = user.userProfile;
const role: string = (!this.userProfile.profileUserType.type ||
(this.userProfile.profileUserType.type && this.userProfile.profileUserType.type === 'OTHER')) ? '' : this.userProfile.profileUserType.type;
this.userLocation = this.getUserLocation(this.userProfile);
this.getPersonaConfig(role).then((val) => {
this.persona = val;
});
this.getSubPersonaConfig(role.toLowerCase(), this.userLocation).then((val) => {
this.subPersona = val;
});
this.userFrameWork = this.userProfile.framework ? _.cloneDeep(this.userProfile.framework) : {};
this.getOrgDetails();
this.getContribution();
this.getOtherCertificates(_.get(this.userProfile, 'userId'), 'all');
this.getTrainingAttended();
this.setNonCustodianUserLocation();
/* istanbul ignore else */
if (_.get(this.userProfile, 'declarations') && this.userProfile.declarations.length > 0) {
this.declarationDetails = _.get(this.userProfile, 'declarations')[0];
if (this.declarationDetails.errorType) {
this.selfDeclaredErrorTypes = this.declarationDetails.errorType.split(',');
}
this.getSelfDeclaredDetails();
}
}
});
this.setInteractEventData();
}
initLayout() {
this.layoutConfiguration = this.layoutService.initlayoutConfig();
this.layoutService.switchableLayout().pipe(takeUntil(this.unsubscribe$)).subscribe(layoutConfig => {
/* istanbul ignore else */
if (layoutConfig != null) {
this.layoutConfiguration = layoutConfig.layout;
}
});
}
setNonCustodianUserLocation() {
const subOrgs = _.filter(this.userProfile.organisations, (org) => {
/*istanbul ignore else */
if (this.userProfile.rootOrgId !== org.organisationId) {
return org;
}
});
/*istanbul ignore else */
if (!_.isEmpty(subOrgs)) {
const sortedSubOrgs = _.reverse(_.sortBy(subOrgs, 'orgjoindate'));
/*istanbul ignore else */
if (!_.isEmpty(sortedSubOrgs[0]) && !_.isEmpty(sortedSubOrgs[0].locations)) {
_.forEach(sortedSubOrgs[0].locations, (location) => {
this.nonCustodianUserLocation[location.type] = location.name;
});
}
}
}
getOrgDetails() {
let orgList = [];
this.roles = [];
_.forEach(this.userProfile.organisations, (org, index) => {
if (this.userProfile.rootOrgId !== org.organisationId) {
if (org.locations && org.locations.length === 0) {
if (this.userProfile.organisations[0].locationIds && this.userProfile.organisations[0].locations) {
org.locationIds = this.userProfile.organisations[0].locationIds;
org.locations = this.userProfile.organisations[0].locations;
}
}
if (org.orgjoindate) {
org.modifiedJoinDate = new Date(org.orgjoindate).getTime();
}
orgList.push(org);
} else {
if (org.locations && org.locations.length !== 0) {
if (org.orgjoindate) {
org.modifiedJoinDate = new Date(org.orgjoindate).getTime();
}
orgList.push(org);
}
}
});
let userRoles;
if (_.get(this.userProfile, 'roles') && !_.isEmpty(this.userProfile.roles)) {
userRoles = _.map(this.userProfile.roles, 'role');
}
_.forEach(userRoles, (value, key) => {
if (value !== 'PUBLIC') {
const roleName = _.find(this.userProfile.roleList, { id: value });
if (roleName) {
this.roles.push(roleName['name']);
}
}
});
this.roles = _.uniq(this.roles).sort();
orgList = _.sortBy(orgList, ['modifiedJoinDate']);
this.orgDetails = _.last(orgList);
}
convertToString(value) {
return _.isArray(value) ? _.join(value, ', ') : undefined;
}
getLocationDetails(locations, type) {
const location: any = _.find(locations, { type: type });
return location ? location.name : false;
}
getContribution(): void {
const { constantData, metaData, dynamicFields } = this.configService.appConfig.Course.otherCourse;
const searchParams = {
status: ['Live'],
contentType: this.configService.appConfig.WORKSPACE.contentType,
params: { lastUpdatedOn: 'desc' }
};
const inputParams = { params: this.configService.appConfig.PROFILE.contentApiQueryParams };
this.searchService.searchContentByUserId(searchParams, inputParams).subscribe((data: ServerResponse) => {
this.contributions = this.utilService.getDataForCard(data.result.content, constantData, dynamicFields, metaData);
this.totalContributions = _.get(data, 'result.count') || 0;
});
}
getTrainingAttended() {
this.coursesService.enrolledCourseData$.pipe().subscribe(data => {
this.attendedTraining = _.reverse(_.sortBy(data.enrolledCourses, val => {
return _.isNumber(_.get(val, 'completedOn')) ? _.get(val, 'completedOn') : Date.parse(val.completedOn);
})) || [];
});
}
/**
* @param userId
*It will fetch certificates of user, other than courses
*/
getOtherCertificates(userId, certType) {
this.otherCertificates = [];
let requestBody = { userId: userId, schemaName: 'certificate' };
if (this.otherCertificatesCounts) {
requestBody['size'] = this.otherCertificatesCounts;
}
this.CsCertificateService.fetchCertificates(requestBody, {
apiPath: '/learner/certreg/v2',
apiPathLegacy: '/certreg/v1',
rcApiPath: '/learner/rc/${schemaName}/v1',
}).subscribe((_res) => {
if (_res && _res?.certificates?.length > 0) {
this.otherCertificates = _.get(_res, 'certificates');
this.otherCertificatesCounts = (_.get(_res, 'certRegCount') ? _.get(_res, 'certRegCount') : 0) + (_.get(_res, 'rcCount') ? _.get(_res, 'rcCount') : 0);
}
}, (error) => {
this.toasterService.error(this.resourceService.messages.emsg.m0005);
console.log('Portal :: CSL : Fetch certificate CSL API failed ', error);
});
}
downloadCert(course) {
if (this.isDesktopApp && !this.isConnected) {
this.toasterService.error(this.resourceService.messages.desktop.emsg.cannotAccessCertificate);
return;
}
// Check for V2
if (_.get(course, 'issuedCertificates.length')) {
this.toasterService.success(_.get(this.resourceService, 'messages.smsg.certificateGettingDownloaded'));
const certificateInfo = course.issuedCertificates[0];
const courseName = course.courseName || _.get(course, 'issuedCertificates[0].name') || 'certificate';
if (_.get(certificateInfo, 'type') === 'TrainingCertificate') {
const courseObj = {
id: certificateInfo.identifier,
type: 'rc_certificate_registry',
templateUrl: _.get(certificateInfo, 'templateUrl'),
trainingName: courseName
}
this.downloadOldAndRCCert(courseObj);
} else if (_.get(certificateInfo, 'identifier')) {
this.courseCService.getSignedCourseCertificate(_.get(certificateInfo, 'identifier'))
.pipe(takeUntil(this.unsubscribe$))
.subscribe((resp) => {
if (_.get(resp, 'printUri')) {
this.certDownloadAsPdf.download(resp.printUri, null, courseName);
} else if (_.get(course, 'certificates.length')) {
this.downloadPdfCertificate(course.certificates[0]);
} else {
this.toasterService.error(this.resourceService.messages.emsg.m0076);
}
}, error => {
this.downloadPdfCertificate(certificateInfo);
});
} else {
this.downloadPdfCertificate(certificateInfo);
}
} else if (_.get(course, 'certificates.length')) { // For V1 - backward compatibility
this.toasterService.success(_.get(this.resourceService, 'messages.smsg.certificateGettingDownloaded'));
this.downloadPdfCertificate(course.certificates[0]);
} else {
this.toasterService.error(this.resourceService.messages.emsg.m0076);
}
}
downloadOldAndRCCert(courseObj) {
let requestBody = {
certificateId: courseObj.id,
schemaName: 'certificate',
type: courseObj.type,
templateUrl: courseObj.templateUrl
};
this.CsCertificateService.getCerificateDownloadURI(requestBody, {
apiPath: '/learner/certreg/v2',
apiPathLegacy: '/certreg/v1',
rcApiPath: '/learner/rc/${schemaName}/v1',
})
.pipe(takeUntil(this.unsubscribe$))
.subscribe((resp) => {
if (_.get(resp, 'printUri')) {
this.certDownloadAsPdf.download(resp.printUri, null, courseObj.trainingName);
} else {
this.toasterService.error(this.resourceService.messages.emsg.m0076);
}
}, error => {
console.log('Portal :: CSL : Download certificate CSL API failed ', error);
});
}
downloadPdfCertificate(value) {
if (_.get(value, 'url')) {
const request = {
request: {
pdfUrl: _.get(value, 'url')
}
};
this.profileService.downloadCertificates(request).subscribe((apiResponse) => {
const signedPdfUrl = _.get(apiResponse, 'result.signedUrl');
if (signedPdfUrl) {
window.open(signedPdfUrl, '_blank');
} else {
this.toasterService.error(this.resourceService.messages.emsg.m0076);
}
}, (err) => {
this.toasterService.error(this.resourceService.messages.emsg.m0076);
});
} else {
this.toasterService.error(this.resourceService.messages.emsg.m0076);
}
}
toggle(showMore) {
if (showMore === true) {
this.showMoreRolesLimit = this.roles.length;
this.showMoreRoles = false;
} else {
this.showMoreRoles = true;
this.showMoreRolesLimit = this.configService.appConfig.PROFILE.defaultShowMoreLimit;
}
}
toggleCourse(showMoreCourse, courseLimit) {
if (showMoreCourse === true) {
this.courseLimit = courseLimit;
this.showMoreTrainings = false;
} else {
this.showMoreTrainings = true;
this.courseLimit = 3;
}
}
updateProfile(data) {
this.profileService.updateProfile({ framework: data }).subscribe(res => {
this.userProfile.framework = data;
this.toasterService.success(this.resourceService.messages.smsg.m0046);
this.profileModal && this.profileModal.deny();
// this.showEdit = false;
}, err => {
// this.showEdit = false;
this.toasterService.warning(this.resourceService.messages.emsg.m0012);
this.profileModal && this.profileModal.deny();
this.cacheService.set('showFrameWorkPopUp', 'installApp');
});
}
openContent(content) {
this.playerService.playContent(content.data.metaData);
}
public prepareVisits(event) {
const inViewLogs = _.map(event, (content, index) => ({
objid: content.metaData.courseId ? content.metaData.courseId : content.metaData.identifier,
objtype: 'course', index: index,
section: content.section,
}));
if (this.telemetryImpression) {
this.telemetryImpression.edata.visits = inViewLogs;
this.telemetryImpression.edata.subtype = 'pageexit';
this.telemetryImpression = Object.assign({}, this.telemetryImpression);
}
}
private getCustodianOrgUser() {
this.orgDetailsService.getCustodianOrgDetails().subscribe(custodianOrg => {
if (_.get(this.userService, 'userProfile.rootOrg.rootOrgId') === _.get(custodianOrg, 'result.response.value')) {
this.isCustodianOrgUser = true;
} else {
this.isCustodianOrgUser = false;
}
});
}
goBack() {
this.navigationhelperService.goBack();
}
setInteractEventData() {
this.myFrameworkEditEdata = {
id: 'profile-edit-framework',
type: 'click',
pageid: 'profile-read'
};
this.editProfileInteractEdata = {
id: 'profile-edit',
type: 'click',
pageid: 'profile-read'
};
this.editMobileInteractEdata = {
id: 'profile-edit-mobile',
type: 'click',
pageid: 'profile-read'
};
this.editEmailInteractEdata = {
id: 'profile-edit-emailId',
type: 'click',
pageid: 'profile-read'
};
this.downloadCertificateEData = {
id: 'profile-download-certificate',
type: 'click',
pageid: 'profile-read'
};
this.editRecoveryIdInteractEdata = {
id: 'profile-edit-recoveryId',
type: 'click',
pageid: 'profile-read'
};
this.addRecoveryIdInteractEdata = {
id: 'profile-add-recoveryId',
type: 'click',
pageid: 'profile-read'
};
this.downloadOthersCertificateEData = {
id: 'profile-download-others-certificate',
type: 'click',
pageid: 'profile-read'
};
this.submitTeacherDetailsInteractEdata = {
id: 'add-teacher-details',
type: 'click',
pageid: 'profile-read'
};
this.updateTeacherDetailsInteractEdata = {
id: 'edit-teacher-details',
type: 'click',
pageid: 'profile-read'
};
}
navigate(url, formAction) {
this.router.navigate([url], {queryParams: {formaction: formAction}});
}
ngAfterViewInit() {
setTimeout(() => {
this.telemetryImpression = {
context: {
env: this.activatedRoute.snapshot.data.telemetry.env
},
object: {
id: this.userService.userid,
type: 'User',
ver: '1.0'
},
edata: {
type: this.activatedRoute.snapshot.data.telemetry.type,
pageid: 'profile-read',
subtype: this.activatedRoute.snapshot.data.telemetry.subtype,
uri: this.router.url,
duration: this.navigationhelperService.getPageLoadTime()
}
};
});
}
ngOnDestroy() {
if (this.userSubscription) {
this.userSubscription.unsubscribe();
}
this.unsubscribe$.next();
this.unsubscribe$.complete();
}
/**
* @since - #SH-19
* @param {object} coursedata - data of the course which user will click from the courses section
* @description - This method will redirect to the courses page which enrolled by the user
*/
navigateToCourse(coursedata) {
const courseId = _.get(coursedata, 'courseId');
const batchId = _.get(coursedata, 'batchId');
const interactData = {
context: {
env: _.get(this.activatedRoute.snapshot.data.telemetry, 'env'),
cdata: [{
type: 'batch',
id: _.get(coursedata, 'batchId')
}]
},
edata: {
id: 'course-play',
type: 'click',
pageid: 'profile-read',
},
object: {
id: courseId,
type: _.get(coursedata, 'content.contentType'),
ver: '1.0',
rollup: {},
}
};
this.telemetryService.interact(interactData);
this.router.navigate([`learn/course/${courseId}/batch/${batchId}`]);
}
toggleOtherCertific(showMore) {
if (showMore) {
if (this.otherCertificates.length !== this.otherCertificatesCounts) {
this.getOtherCertificates(_.get(this.userProfile, 'userId'), 'all');
}
this.otherCertificateLimit = this.otherCertificatesCounts;
this.showMoreCertificates = false;
} else {
this.otherCertificateLimit = this.configService.appConfig.PROFILE.defaultViewMoreLimit;
this.showMoreCertificates = true;
}
}
/**
* @since - #SH-920
* @description - This method will map self declared values with teacher details dynamic fields to display on profile page
*/
getSelfDeclaredDetails() {
this.selfDeclaredInfo = [];
this.profileService.getPersonaTenantForm().pipe(takeUntil(this.unsubscribe$)).subscribe(res => {
const tenantConfig: any = res.find(config => config.code === 'tenant');
this.tenantInfo = _.get(tenantConfig, 'templateOptions.options').find(tenant => tenant.value === this.declarationDetails.orgId);
this.profileService.getSelfDeclarationForm(this.declarationDetails.orgId).pipe(takeUntil(this.unsubscribe$)).subscribe(formConfig => {
const externalIdConfig = formConfig.find(config => config.code === 'externalIds');
(externalIdConfig.children as FieldConfig<any>[]).forEach(config => {
if (this.declarationDetails.info[config.code]) {
this.selfDeclaredInfo.push({ label: config.fieldName, value: this.declarationDetails.info[config.code], code: config.code });
}
});
});
});
}
copyToClipboard(userName) {
const textElement = document.createElement('textarea');
textElement.style.position = 'fixed';
textElement.value = userName;
document.body.appendChild(textElement);
textElement.select();
document.execCommand('copy');
document.body.removeChild(textElement);
this.toasterService.success((this.resourceService.messages.profile.smsg.m0041).replace('{instance}', this.instance));
}
triggerAutoScroll() {
setTimeout(() => {
const element = document.getElementById(this.scrollToId);
if (!element) { return; }
const elementPosition = element.getBoundingClientRect().top;
const offsetPosition = elementPosition - 144;
window.scrollTo({
top: offsetPosition,
behavior: 'smooth'
});
});
}
private getUserLocation(profile: any) {
const userLocation = {};
if (profile && profile.userLocations && profile.userLocations.length) {
profile.userLocations.forEach((d) => {
userLocation[d.type] = d;
});
}
return userLocation;
}
private async getPersonaConfig(persona: string) {
const formFields = await this.formService.getFormConfig(ProfilePageComponent.SUPPORTED_PERSONA_LIST_FORM_REQUEST).toPromise();
return formFields.find(config => config.code === persona);
}
private async getSubPersonaConfig(persona: string, userLocation: any): Promise<string[]> {
if ((!this.userProfile.profileUserTypes || !this.userProfile.profileUserTypes.length) &&
(!this.userProfile.profileUserType || !this.userProfile.profileUserType.subType)) {
return undefined;
}
let formFields;
try {
const state = userLocation.state;
formFields = await this.formService.getFormConfig({
...ProfilePageComponent.DEFAULT_PERSONA_LOCATION_CONFIG_FORM_REQUEST,
...(state ? {contentType: state.code} : {})
}).toPromise();
} catch (e) {
formFields = await this.formService.getFormConfig(ProfilePageComponent.DEFAULT_PERSONA_LOCATION_CONFIG_FORM_REQUEST).toPromise();
}
const personaConfig = formFields.find(formField => formField.code === 'persona');
const personaChildrenConfig: FieldConfig<any>[] = personaConfig['children'][persona];
const subPersonaConfig = personaChildrenConfig.find(formField => formField.code === 'subPersona');
if (!subPersonaConfig) {
return undefined;
}
const subPersonaList = [];
if (_.get(subPersonaConfig, 'templateOptions.multiple')) {
if (this.userProfile.profileUserTypes && this.userProfile.profileUserTypes.length) {
this.userProfile.profileUserTypes.forEach(ele => {
if (_.get(ele, 'subType')) {
subPersonaList.push(ele.subType);
}
});
} else {
subPersonaList.push(this.userProfile.profileUserType.subType);
}
} else {
subPersonaList.push(this.userProfile.profileUserType.subType);
}
const subPersonaFieldConfigOption = [];
subPersonaList.forEach((ele) => {
subPersonaFieldConfigOption.push((subPersonaConfig.templateOptions.options as FieldConfigOption<any>[]).
find(option => option.value === ele).label);
});
return subPersonaFieldConfigOption;
}
public onLocationModalClose(event) {
this.showEditUserDetailsPopup = !this.showEditUserDetailsPopup;
this.showFullScreenLoader = !event?.isSubmitted ? false : true;
setTimeout(() => {
if (this.showFullScreenLoader) {
this.showFullScreenLoader = false;
this.toasterService.error(this.resourceService.messages.emsg.m0005);
}
}, 5000);
}
}
<app-landing-section [textToDisplay]=""
[layoutConfiguration]="{}" [noTitle]="true"></app-landing-section>
<!--profile Content Header -->
<div [ngClass]="layoutConfiguration ? 'sb-back-actionbar' : 'sb-bg-white cc-player__btn-back'" class="relative position mt-0">
<div class="ui container py-0 px-0 d-flex flex-ai-center">
<button type="button" (click)="goBack()" [ngClass]="layoutConfiguration ? 'sb-btn-primary sb-btn-round' : 'sb-btn-link sb-btn-link-primary sb-left-icon-btn px-0'" class="sb-btn sb-btn-normal" tabindex="0" attr.aria-label="{{resourceService?.frmelmnts?.btn?.back}}">
<i class="icon-svg icon-svg--xxs icon-back mr-4"><svg class="icon icon-svg--primary">
<use xlink:href="assets/images/sprite.svg#arrow-long-left"></use>
</svg></i>
<span>{{resourceService?.frmelmnts?.btn?.back}}</span>
</button>
<div class="content-header__content w-100 ml-16">
<div class="d-flex flex-dc flex-basis-1 mr-32 min-w-0 content-header__content__title">
<div class="content-header__title font-weight-bold ellipsis text-left" tabindex="0" role="heading" aria-level="2">{{resourceService.frmelmnts?.lnk?.profile}}</div>
</div>
</div>
</div>
</div>
<div [ngClass]="layoutConfiguration ? 'sbt-inside-page-container' : ''">
<div [ngClass]="layoutConfiguration ? 'relative9' : ''">
<div [appTelemetryImpression]="telemetryImpression" *ngIf="userProfile">
<section class="py-24 d-flex flex-ai-center flex-dc">
<div class="ui container">
<div class="mb-15 d-flex flex-jc-center relative avatar-container" aria-label="Profile">
<img *ngIf="userProfile.stateValidated || !isCustodianOrgUser" role="img" src="assets/images/avatar-tickmark.svg" alt="certified" class="avatar-tickmark"
matTooltip="{{resourceService.frmelmnts.lbl.stateVerified}}" [matTooltipPosition]="'right'">
<sb-avatar [ngClass]="{verified: userProfile.stateValidated}" class="my-avatar" [style]="avtarDesktopStyle"
[config]=avatarConfig initialsSize="1" [initial]="userProfile?.firstName[0]"
[title]="userProfile?.firstName">
</sb-avatar>
</div>
</div>
<div class="profile-user-label font-w-bold d-flex text-center relative position">{{userProfile.firstName | titlecase}} {{userProfile.lastName |
titlecase}}
</div>
<div class="mt-8 mb-16 d-flex flex-jc-center">
<div class="fnormal">{{resourceService?.frmelmnts?.lbl?.instacnceId | interpolate:'{instance}': instance}} :</div>
<div class="fnormal ml-5" id="copyUser">{{userProfile.userName}}</div>
<div role="button" class="ml-8 cursor-pointer" tabindex="0" (click)="copyToClipboard(userProfile.userName)" matTooltip="{{resourceService.frmelmnts?.lbl?.copyid | interpolate:'{instance}': instance}}" [matTooltipPosition]="'left'">
<i class="icon-svg icon-svg--xs icon-edit">
<svg class="icon icon-svg--primary">
<use xlink:href="assets/images/sprite.svg#copy-alternate"></use>
</svg>
</i>
<span class="sb-color-primary" role="link" tabindex="0" attr.aria-label=“{{resourceService?.frmelmnts?.lbl?.copy}}”>{{resourceService?.frmelmnts?.lbl?.copy}}</span>
</div>
</div>
<div class="mb-15 text-center profile-label-container" *ngIf="roles && roles.length > 0">
<span class="ui dodger-blue basic label mr-15 mt-5"
*ngFor="let role of roles | slice:0:showMoreRolesLimit">{{role}}</span>
</div>
<div *ngIf="roles.length > configService.appConfig.PROFILE.defaultShowMoreLimit"
class="fs-1 color-2 mb-8 font-w-bold cursor-pointer">
<span tabindex="0" *ngIf="showMoreRoles" (click)="toggle(true)">+ {{roles.length -
configService.appConfig.PROFILE.defaultShowMoreLimit}} {{resourceService.frmelmnts.lbl.more}}
<i class="chevron down icon"></i>
</span>
<span (click)="toggle(false)" *ngIf="!showMoreRoles">
{{resourceService.frmelmnts.lbl.showLess}}
<i class="chevron up icon"></i>
</span>
</div>
<div class="ui container">
</div>
<div class="fs-1-5 font-w-bold d-flex mb-8 text-center org-info" *ngIf=" orgDetails && orgDetails.orgName">{{orgDetails.orgName}}
</div>
<!-- <div class="ui container" *ngIf="!isCustodianOrgUser">
<div class="d-flex flex-dc flex-jcc-center flex-ai-center">
<button appTelemetryInteract
[telemetryInteractEdata]="editProfileInteractEdata"
class="sb-btn sb-btn-primary sb-btn-normal sb-btn-border my-16 computer only"
(click)="showEditUserDetailsPopup=true">{{resourceService.frmelmnts.lbl.edit}}</button>
</div>
</div> -->
<!-- <div class="m-0 pl-0 computer only" *ngIf="nonCustodianUserLocation && !isCustodianOrgUser">
<div class="mb-0 d-flex mb-5 flex-jc-center" *ngIf="nonCustodianUserLocation.block">
<div class="fmedium">{{resourceService.frmelmnts.lbl.block}} :</div>
<div class="fmedium font-w-bold ml-5">{{nonCustodianUserLocation.block}}</div>
</div>
<div class="mb-0 d-flex mb-5 flex-jc-center" *ngIf="nonCustodianUserLocation.district">
<div class="fmedium">{{resourceService.frmelmnts.lbl.district}} :</div>
<div class="fmedium font-w-bold ml-5">{{nonCustodianUserLocation.district}}</div>
</div>
<div class="mb-0 d-flex mb-5 flex-jc-center" *ngIf="nonCustodianUserLocation.state">
<div class="fmedium">{{resourceService.frmelmnts.lbl.state}} :</div>
<div class="fmedium font-w-bold ml-5">{{nonCustodianUserLocation.state}}</div>
</div>
</div> -->
<!-- <div class="m-0 pl-0 mobile only" *ngIf="orgDetails && orgDetails.locations && !isCustodianOrgUser">
<div class="mb-0 d-flex m-responsive-flex-dc mt-15" *ngIf="getLocationDetails(orgDetails.locations, 'block')">
<span class="fmedium text-center">{{resourceService.frmelmnts.lbl.block}} :</span>
<span class="fmedium font-w-bold text-center">{{getLocationDetails(orgDetails.locations, 'block')}}</span>
</div>
<div class="mb-0 d-flex m-responsive-flex-dc mt-15" *ngIf="getLocationDetails(orgDetails.locations, 'district')">
<span class="fmedium text-center">{{resourceService.frmelmnts.lbl.district}} :</span>
<span class="fmedium font-w-bold text-center">{{getLocationDetails(orgDetails.locations, 'district')}}</span>
</div>
<div class="mb-0 d-flex m-responsive-flex-dc mt-15" *ngIf="getLocationDetails(orgDetails.locations, 'state')">
<span class="fmedium text-center text-center">{{resourceService.frmelmnts.lbl.state}} :</span>
<span class="fmedium font-w-bold text-center">{{getLocationDetails(orgDetails.locations, 'state')}}</span>
</div>
</div> -->
</section>
<section class="d-flex flex-ai-center flex-dc pb-24 content-preference">
<h3 class="content-header-info font-weight-bold mb-16">{{resourceService.frmelmnts.lbl.profiledetails}}</h3>
<!-- add state and district -->
<div class="ui container content-preference__info pt-16">
<div *ngIf="persona?.name" class="mb-0 d-flex flex-jc-center m-responsive-flex-dc m-responsive-mt-15">
<div class="fmedium text-center">{{resourceService.frmelmnts.lbl.role}} :</div>
<div class="fmedium ml-5 font-w-bold text-center">{{persona.name}}</div>
</div>
<div *ngIf="subPersona" class="mb-0 d-flex flex-jc-center m-responsive-flex-dc m-responsive-mt-15">
<div class="fmedium text-center white-space-nowrap">{{resourceService.frmelmnts.lbl.subRole}} :</div>
<div class="fmedium ml-5 font-w-bold text-center">{{subPersona.join(', ')}}</div>
</div>
<div *ngIf="userLocation?.district && userLocation?.district?.name" class="mb-0 d-flex flex-jc-center m-responsive-flex-dc m-responsive-mt-15">
<div class="fmedium text-center">{{resourceService.frmelmnts.lbl.district}} :</div>
<div class="fmedium ml-5 font-w-bold text-center">
{{userLocation.district.name}} </div>
</div>
<div *ngIf="userLocation?.state && userLocation?.state?.name" class="d-flex mb-5 flex-jc-center m-responsive-flex-dc m-responsive-mt-15">
<div class="fmedium text-center">{{resourceService.frmelmnts.lbl.state}} :</div>
<div class="fmedium ml-5 font-w-bold text-center">
{{userLocation.state.name}}</div>
</div>
<div *ngIf="userLocation?.block && userLocation?.block?.name" class="mb-0 d-flex flex-jc-center m-responsive-flex-dc m-responsive-mt-15">
<div class="fmedium text-center">{{resourceService.frmelmnts.lbl.block}} :</div>
<div class="fmedium ml-5 font-w-bold text-center">
{{userLocation.block.name}} </div>
</div>
<div *ngIf="userLocation?.cluster && userLocation?.cluster?.name" class="mb-0 d-flex flex-jc-center m-responsive-flex-dc m-responsive-mt-15">
<div class="fmedium text-center">{{resourceService.frmelmnts.lbl.cluster}} :</div>
<div class="fmedium ml-5 font-w-bold text-center">
{{userLocation.cluster.name}} </div>
</div>
<div *ngIf="userLocation?.school && userLocation?.school?.name" class="mb-0 d-flex flex-jc-center m-responsive-flex-dc m-responsive-mt-15">
<div class="fmedium text-center">{{resourceService.frmelmnts.lbl.school}} :</div>
<div class="fmedium ml-5 font-w-bold text-center">
{{userLocation.school.name}} </div>
</div>
<div class="d-flex flex-dc flex-jcc-center flex-ai-center">
<button appTelemetryInteract appOnlineOnly
[telemetryInteractEdata]="editProfileInteractEdata"
class="sb-btn sb-btn-primary sb-btn-normal sb-btn-border my-16" attr.aria-label="{{resourceService?.frmelmnts?.lbl?.editPersonalDetails}}" tabindex="0"
(click)="showEditUserDetailsPopup=true" tabindex="0">{{resourceService.frmelmnts.lbl.edit}}</button>
<button appTelemetryInteract appOnlineOnly tabindex="0"
[telemetryInteractEdata]="submitTeacherDetailsInteractEdata"
*ngIf="!declarationDetails && isCustodianOrgUser && !userProfile.isMinor"
(click)="navigate('/profile/submit-declaration','submit')" tabindex="0"
class="no-text-transform sb-btn sb-btn-normal sb-btn-secondary sb-right-icon-btn mx-8 mb-8 px-24" type="submit">
{{resourceService?.frmelmnts?.lbl?.iAmStateTeacher}} </button>
</div>
</div>
</section>
<section class="d-flex flex-ai-center flex-dc pt-30 pb-30 profile-bg-c-4 content-preference">
<!-- User info computer view starts-->
<div class="ui container">
<div class="d-flex flex-jc-center flex-ai-center flex-dc" *ngIf="userProfile && userProfile.framework ">
<div class="max-w-400 computer only">
<div class="mb-15 d-flex flex-jc-center" *ngIf="convertToString(userProfile.framework.board)">
<span class="fmedium white-space-nowrap">{{resourceService.frmelmnts.lbl.boards | transposeTerms: 'frmelmnts.lbl.boards' : resourceService?.selectedLang}} :</span>
<span class="fmedium font-w-bold pl-4"
*ngIf="userProfile.framework">{{convertToString(userProfile.framework.board)}}</span>
</div>
<div class="mb-15 d-flex flex-jc-center" *ngIf="convertToString(userProfile.framework.medium)">
<span class="fmedium white-space-nowrap">{{resourceService.frmelmnts.lbl.medium | transposeTerms: 'frmelmnts.lbl.medium' : resourceService?.selectedLang}} :</span>
<span class="fmedium font-w-bold pl-4"
*ngIf="userProfile.framework">{{convertToString(userProfile.framework.medium)}}</span>
</div>
<div class="mb-15 d-flex flex-jc-center" *ngIf="convertToString(userProfile.framework.gradeLevel)">
<span class="fmedium white-space-nowrap">{{resourceService.frmelmnts.lbl.classes | transposeTerms: 'frmelmnts.lbl.classes' : resourceService?.selectedLang}} :</span>
<span class="fmedium font-w-bold pl-4"
*ngIf="userProfile.framework">{{convertToString(userProfile.framework.gradeLevel)}}</span>
</div>
<div class="d-flex flex-jc-center" *ngIf="convertToString(userProfile.framework.subject)">
<span class="fmedium white-space-nowrap">{{resourceService.frmelmnts.lbl.subjects | transposeTerms: 'frmelmnts.lbl.subjects' : resourceService?.selectedLang}} :</span>
<span class="fmedium font-w-bold pl-4"
*ngIf="userProfile.framework">{{convertToString(userProfile.framework.subject)}}</span>
</div>
</div>
<button class="sb-btn sb-btn-primary sb-btn-normal my-16 sb-btn-border computer only"
appTelemetryInteract appOnlineOnly
[telemetryInteractEdata]="myFrameworkEditEdata" attr.aria-label="{{resourceService.frmelmnts.lbl.edit}} {{resourceService.frmelmnts.lbl.boards}},{{resourceService.frmelmnts.lbl.medium}},{{resourceService.frmelmnts.lbl.classes}},{{convertToString(userProfile.framework.gradeLevel)}},{{resourceService.frmelmnts.lbl.subjects}}"
(click)="showEdit = !showEdit" tabindex="0">{{resourceService.frmelmnts.lbl.edit}}</button>
</div>
</div>
<!-- User info computer view ends-->
<!-- User info mobile view starts-->
<div class="max-w-300 mobile only">
<div class="mb-15 d-flex flex-ai-center flex-dc">
<span class="fmedium white-space-nowrap">{{resourceService.frmelmnts.lbl.boards | transposeTerms: 'frmelmnts.lbl.boards' : resourceService?.selectedLang}}:</span>
<span class="fmedium font-w-bold text-center"
*ngIf="userProfile.framework">{{convertToString(userProfile.framework.board)}}</span>
</div>
<div class="mb-15 d-flex flex-ai-center flex-dc">
<span class="fmedium white-space-nowrap">{{resourceService.frmelmnts.lbl.medium | transposeTerms: 'frmelmnts.lbl.medium' : resourceService?.selectedLang}} :</span>
<span class="fmedium font-w-bold text-center"
*ngIf="userProfile.framework">{{convertToString(userProfile.framework.medium)}}</span>
</div>
<div class="mb-15 d-flex flex-ai-center flex-dc">
<span class="fmedium white-space-nowrap">{{resourceService.frmelmnts.lbl.classes | transposeTerms: 'frmelmnts.lbl.classes' : resourceService?.selectedLang}} :</span>
<span class="fmedium font-w-bold text-center"
*ngIf="userProfile.framework">{{convertToString(userProfile.framework.gradeLevel)}}</span>
</div>
<div class="mb-15 d-flex flex-ai-center flex-dc">
<span class="fmedium white-space-nowrap">{{resourceService.frmelmnts.lbl.subjects | transposeTerms: 'frmelmnts.lbl.subjects' : resourceService?.selectedLang}} :</span>
<span class="fmedium font-w-bold text-center"
*ngIf="userProfile.framework">{{convertToString(userProfile.framework.subject)}}</span>
</div>
<div class="d-flex flex-ai-center flex-jc-center" appTelemetryInteract
[telemetryInteractEdata]="myFrameworkEditEdata" tabindex="0"
(click)="showEdit = !showEdit" attr.aria-label="{{resourceService?.frmelmnts?.lbl?.editPersonalDetails}}">
<button appOnlineOnly class="sb-btn sb-btn-primary sb-btn-xs mt-30">{{resourceService.frmelmnts.lbl.edit}}</button>
</div>
</div>
<!-- User info mobile view ends-->
</section>
<section class="pt-30 pb-30 d-flex flex-jc-center profile-bg-c-3" *ngIf="userProfile.email || userProfile.phone">
<div class="d-flex flex-dc">
<div class="d-flex flex-jc-center">
<div role="button" appOnlineOnly (click)="showContactPopup=true;contactType='phone'" tabindex="0"
class="ui semi-circular dodger-blue basic label mb-15 cursor-pointer" *ngIf="userProfile.phone"
appTelemetryInteract
[telemetryInteractEdata]="editMobileInteractEdata">
<i class="phone blue icon mr-5"></i> ‎+91 {{userProfile.phone}}
</div>
<div appOnlineOnly (click)="showContactPopup=true;contactType='phone'" attr.aria-label=“{{resourceService?.frmelmnts?.lbl?.addPhoneNo}}” tabindex="0"
class="ui semi-circular update basic label mb-15 cursor-pointer font-weight-normal" *ngIf="!userProfile.phone"
appTelemetryInteract
[telemetryInteractEdata]="editMobileInteractEdata">
<i class="phone icon mr-5"></i> {{resourceService?.frmelmnts?.lbl?.addPhoneNo}}
</div>
</div>
<div class="d-flex flex-jc-center">
<div appOnlineOnly (click)="showContactPopup=true;contactType='email'" tabindex="0"
class="ui semi-circular dodger-blue basic label cursor-pointer mb-15" attr.aria-label=“{{userProfile.email}}” *ngIf="userProfile.email" appTelemetryInteract
[telemetryInteractEdata]="editEmailInteractEdata">
<i class="mail blue icon mr-5"></i> {{userProfile.email}}
</div>
<div appOnlineOnly (click)="showContactPopup=true;contactType='email'" tabindex="0" attr.aria-label=“{{resourceService?.frmelmnts?.lbl?.addEmailID}}”
class="ui semi-circular update basic label mb-15 cursor-pointer font-weight-normal" *ngIf="!userProfile.email"
appTelemetryInteract
[telemetryInteractEdata]="editEmailInteractEdata">
<i class="mail icon mr-5"></i> {{resourceService?.frmelmnts?.lbl?.addEmailID}}
</div>
</div>
<!-- Add/edit recovery email/phone-->
<div class="d-flex flex-jc-center">
<div appOnlineOnly *ngIf="userProfile.recoveryEmail || userProfile.recoveryPhone" tabindex="0" (click)="showRecoveryId=true; mode='edit'" attr.aria-label=“{{userProfile.recoveryEmail}}” class="ui semi-circular dodger-blue basic label cursor-pointer mb-15 d-flex"
appTelemetryInteract
[telemetryInteractEdata]="editRecoveryIdInteractEdata">
<div class="recovery-img mr-5"></div>
<span *ngIf="userProfile.recoveryEmail">{{userProfile.recoveryEmail}}</span>
<span *ngIf="userProfile.recoveryPhone">{{userProfile.recoveryPhone}}</span>
</div>
<div appOnlineOnly *ngIf="!(userProfile.recoveryEmail || userProfile.recoveryPhone)" attr.aria-label=“{{resourceService?.frmelmnts?.lbl?.addRecoveryAccount}}” tabindex="0" (click)="showRecoveryId=true; mode='add'" class="ui semi-circular update basic label mb-15 cursor-pointer font-weight-normal d-flex"
appTelemetryInteract
[telemetryInteractEdata]="addRecoveryIdInteractEdata">
<div class="recovery-img mr-5"></div>
<span>{{resourceService?.frmelmnts?.lbl?.addRecoveryAccount}}</span>
</div>
</div>
</div>
</section>
<!-- 4 section start teacher profile-->
<section class="pt-30 pb-30 d-flex flex-jc-center profile-bg-c-3" *ngIf="declarationDetails && !userProfile.stateValidated">
<div class="flex-ai-jc-center flex-dc text-center school-id-section">
<div class="self-declared-title">{{resourceService.frmelmnts?.lbl?.selfDeclaredInfo}}</div>
<div>
{{resourceService?.frmelmnts?.lbl?.wishToShareDataWith}} : <span>{{ tenantInfo?.label }}</span>
</div>
<div *ngFor="let item of selfDeclaredInfo">
<div class="fnormal white-space-nowrap">{{ item.label }}:</div>
<div class="fnormal font-w-bold mt-4 mb-8">{{ item.code === 'declared-phone' ? '+91' : '' }} {{ item.value }}</div>
</div>
<div class="my-8">
<button appTelemetryInteract appOnlineOnly
[telemetryInteractEdata]="updateTeacherDetailsInteractEdata" tabindex="0" type="button" class="sb-btn sb-btn-normal sb-btn-outline-primary sb-btn-border"
(click)="navigate('/profile/submit-declaration','update')">{{resourceService.frmelmnts?.btn?.update}}</button>
</div>
</div>
</section>
<!-- 4 section end -->
<!-- my badges section starts -->
<!-- <extension-point *ngIf="userProfile.badgeAssertions && userProfile.badgeAssertions.length > 0"
[name]="'profile-widget'"></extension-point> -->
<app-profile-badge *ngIf="userProfile.badgeAssertions && userProfile.badgeAssertions.length > 0"></app-profile-badge>
<!-- my badges section ends -->
<div class="pt-30">
<div class="sb-profile-page-container" [ngClass]="layoutConfiguration ? 'sbt-center-container' : 'ui container'">
<!--contributions view starts-->
<div class="fs-1-7 font-w-bold pl-20 mobile only" *ngIf="contributions && contributions.length > 0">
{{resourceService.frmelmnts.scttl.contributions}}
({{totalContributions}})‎</div>
<div class="ui divider my-5 mobile only"></div>
<!--contributions computer view starts-->
<div class="ui segments" *ngIf="contributions && contributions.length > 0">
<div class="ui segment computer only">
<div class="fs-1-7 pl-10 font-w-bold">{{resourceService.frmelmnts.scttl.contributions}}
({{totalContributions}})‎</div>
</div>
<div class="ui segment">
<div class="regular slider pt-10">
<app-page-section [section]="{ contents: contributions}" (visits)="prepareVisits($event)"
(playEvent)="openContent($event)" [layoutConfiguration]="layoutConfiguration"></app-page-section>
</div>
</div>
</div>
<!--contributions computer view ends-->
<!--contributions view ends-->
<!-- tarainings attended computer view strats-->
<div class="container my-16 sb-certificate-trained" *ngIf="attendedTraining && attendedTraining.length">
<div class="list-heading">
<label class="mb-0">{{resourceService?.frmelmnts?.lbl?.myLearning}}({{attendedTraining.length}})‎</label>
<span class="fsmall mt-4 font-weight-bold"> ({{resourceService?.frmelmnts?.lbl?.refreshedDaily}})</span>
</div>
<div class="list-item-parent">
<div class="list-items sb-course-progress-status-label">
<div class="list-items__item"><span class="sb__ellipsis mr-auto mb-0 text-left">{{resourceService?.frmelmnts?.lbl?.course}}</span></div>
<div class="list-items__item"><span class="sb__ellipsis mr-auto mb-0 text-left">{{resourceService?.frmelmnts?.lbl?.batch}}</span></div>
<div class="list-items__item"><span class="sb__ellipsis mr-auto mb-0 text-left">{{resourceService?.frmelmnts?.lbl?.coursecompletiondate}}</span></div>
<div class="list-items__item"><span class="sb__ellipsis mr-auto mb-0 text-left">{{resourceService?.frmelmnts?.lbl?.status}}</span></div>
<div class="list-items__item"><span class="sb__ellipsis mr-auto mb-0 text-left"></span></div>
</div>
</div>
<div class="list-item-parent" *ngFor="let data of attendedTraining | slice:0:courseLimit">
<div class="list-items" *ngIf="data.courseName">
<div class="list-items__item"><a tabindex="0" (click)="navigateToCourse(data)" class="sb__ellipsis mr-auto mb-0 text-left">{{data.courseName}}</a></div>
<div class="list-items__item"><span class="sb__ellipsis mr-auto mb-0 text-left">{{data.batch.name}}</span></div>
<div class="list-items__item list-date" *ngIf="data.completedOn">{{data.completedOn | date :'MMMM yyy' }}</div>
<div class="list-items__item list-items__bar computer only" *ngIf="!data.completedOn">
<span class="bar mr-4"></span>
<span class="bar"></span>
</div>
<div class="list-items__item status-progress fsmall font-weight-bold text-left" *ngIf="(data.status === 0 || data.status === 1) && (data.batch.status !== 2)" >{{resourceService?.frmelmnts?.lbl?.ongoing}}</div>
<div class="list-items__item status-progress fsmall font-weight-bold text-left" *ngIf="(data.status === 0 || data.status === 1) && (data.batch.status === 2)" >{{resourceService?.frmelmnts?.lbl?.expiredbatch}}</div>
<div class="list-items__item status-completed fsmall font-weight-bold text-left" *ngIf="data.status === 2 " >{{resourceService?.frmelmnts?.lbl?.completed}}</div>
<div class="list-items__item" *ngIf="data?.certificates?.length || data?.issuedCertificates?.length">
<button appTelemetryInteract
[telemetryInteractEdata]="downloadCertificateEData"
[telemetryInteractCdata]="[{id: 'course:download:cert', type: 'Feature'},{id: 'SB-14120', type: 'Task'}]"
class="sb-btn sb-btn-normal sb-btn-link sb-btn-link-primary sb-left-icon-btn fnormal" (click)="downloadCert(data)" tabindex="0">
<i class="download icon"></i>{{resourceService?.frmelmnts?.btn?.downloadCertificate}}</button>
</div>
<div class="list-items__item list-items__bar computer only" *ngIf="!data?.certificates?.length && !data?.issuedCertificates?.length">
<span class="bar mr-4"></span>
<span class="bar"></span>
</div>
</div>
</div>
<div class="flex-ai-jc-center sb-ct-list" *ngIf="attendedTraining.length > 3">
<button class="sb-btn sb-btn-normal sb-btn-primary sb-right-icon-btn" appTelemetryInteract
[telemetryInteractEdata]="{id:'view-more' , type:'click' , pageid:'profile-read'}" *ngIf="showMoreTrainings"
(click)="toggleCourse(true, attendedTraining.length)" tabindex="0"> +{{attendedTraining.length - 3}} {{resourceService.frmelmnts.lbl.viewmore}}<i
class="chevron down icon"></i></button>
<button class="sb-btn sb-btn-normal sb-btn-primary sb-right-icon-btn" appTelemetryInteract
[telemetryInteractEdata]="{id:'view-less' , type:'click' , pageid:'profile-read'}"
(click)="toggleCourse(false, attendedTraining.length)" tabindex="0" *ngIf="!showMoreTrainings">{{resourceService.frmelmnts.lbl.viewless}}<i
class="chevron up icon"></i></button>
</div>
</div>
<!-- trainings attended computer view ends-->
<!-- certificates - old layout-->
<!-- <div class="container my-16 sb-certificate-trained" id="learner-passbook" *ngIf="otherCertificates && otherCertificates.length">
<div class="list-heading">
<label class="mb-0">{{resourceService.frmelmnts?.lbl?.learnerPassbook }}‎</label>
</div>
<div class="list-item-parent">
<div class="list-items sb-course-progress-status-label">
<label class="list-items__item mr-auto mb-0 text-left">{{resourceService?.frmelmnts?.lbl?.course}}</label>
<label class="list-items__item mr-auto mb-0 text-left">{{resourceService?.frmelmnts?.lbl?.certgivenby}}</label>
<label class="list-items__item mr-auto mb-0 last-date">{{resourceService?.frmelmnts?.lbl?.certissuedon}}</label>
<label class="list-items__item mr-auto mb-0 text-left"></label>
</div>
</div>
<div class="list-item-parent" *ngFor="let data of otherCertificates | slice:0:otherCertificateLimit">
<div class="list-items" *ngIf="data.issuingAuthority">
<label class="list-items__item mr-auto mb-0 text-left">{{data.courseName}}</label>
<label class="list-items__item mr-auto mb-0 text-left">{{data.issuingAuthority}}</label>
<label class="list-items__item list-date" *ngIf="data.issuedOn">{{data.issuedOn | date :'dd MMMM yyy' }}</label>
<div class="list-items__item" *ngIf="data?.certificates?.length">
<button appTelemetryInteract [telemetryInteractEdata]="downloadOthersCertificateEData"
class="sb-btn sb-btn-normal sb-btn-link sb-btn-link-primary sb-left-icon-btn fnormal" (click)="downloadCert(data)" tabindex="0">
<i class="download icon" ></i>{{resourceService?.frmelmnts?.btn?.downloadCertificate}}</button>
</div>
<div class="list-items__item list-items__bar computer only" *ngIf="!data?.certificates?.length">
<span class="bar"></span>
<span class="bar"></span>
</div>
</div>
</div>
<div class="flex-ai-jc-center sb-ct-list" *ngIf="otherCertificates.length > 3 ">
<button class="sb-btn sb-btn-normal sb-btn-primary sb-right-icon-btn" appTelemetryInteract
[telemetryInteractEdata]="{id:'view-more' , type:'click' , pageid:'profile-read'}" *ngIf="showMoreCertificates"
(click)="toggleOtherCertific(true)" tabindex="0">{{resourceService.frmelmnts.lbl.viewmore}}<i
class="chevron down icon"></i></button>
<button class="sb-btn sb-btn-normal sb-btn-primary sb-right-icon-btn" appTelemetryInteract
[telemetryInteractEdata]="{id:'view-less' , type:'click' , pageid:'profile-read'}"
(click)="toggleOtherCertific(false)" tabindex="0" *ngIf="!showMoreCertificates">{{resourceService.frmelmnts.lbl.viewless}}<i
class="chevron up icon"></i></button>
</div>
</div> -->
<!-- certificates - old layout-->
<!-- RC Certificates -->
<div class="container my-16 sb-certificate-trained" id="learner-passbook" *ngIf="otherCertificates && otherCertificates.length">
<div class="list-heading">
<label class="mb-0">{{resourceService.frmelmnts?.lbl?.learnerPassbook }}‎</label>
</div>
<div class="list-item-parent">
<div class="list-items sb-course-progress-status-label">
<label class="list-items__item mb-0 text-left">{{resourceService?.frmelmnts?.lbl?.course}}</label>
<label class="list-items__item mb-0 text-left">{{resourceService?.frmelmnts?.lbl?.certgivenby}}</label>
<label class="list-items__item mb-0 last-date">{{resourceService?.frmelmnts?.lbl?.certissuedon}}</label>
<label class="list-items__item mb-0 text-left"></label>
<label class="list-items__item mb-0 text-left"></label>
</div>
</div>
<div class="list-item-parent" *ngFor="let data of otherCertificates | slice:0:otherCertificateLimit">
<div class="list-items" *ngIf="data?.issuerName">
<label class="list-items__item mb-0 text-left">{{data.trainingName}}</label>
<label class="list-items__item mb-0 text-left">{{data?.issuerName}}</label>
<label class="list-items__item list-date" *ngIf="data.issuedOn">{{data.issuedOn | date :'dd MMMM yyy' }}</label>
<div class="list-items__item" *ngIf="data?.id">
<button appOnlineOnly appTelemetryInteract [telemetryInteractEdata]="downloadOthersCertificateEData"
class="sb-btn sb-btn-normal sb-btn-link sb-btn-link-primary sb-left-icon-btn"
(click)="downloadOldAndRCCert(data)" tabindex="0" >
<i class="download icon"></i>{{resourceService?.frmelmnts?.btn?.downloadCertificate}}</button>
</div>
<div class="list-items__item list-items__bar computer only" *ngIf="!data?.length">
<span class="bar"></span>
<span class="bar"></span>
</div>
</div>
</div>
<div class="flex-ai-jc-center sb-ct-list" *ngIf="otherCertificates.length > 3 ">
<button class="sb-btn sb-btn-normal sb-btn-primary sb-right-icon-btn" appTelemetryInteract
[telemetryInteractEdata]="{id:'view-more' , type:'click' , pageid:'profile-read'}" *ngIf="showMoreCertificates"
(click)="toggleOtherCertific(true)" tabindex="0">{{resourceService.frmelmnts.lbl.viewmore}}<i
class="chevron down icon"></i></button>
<button class="sb-btn sb-btn-normal sb-btn-primary sb-right-icon-btn" appTelemetryInteract
[telemetryInteractEdata]="{id:'view-less' , type:'click' , pageid:'profile-read'}"
(click)="toggleOtherCertific(false)" tabindex="0"
*ngIf="!showMoreCertificates">{{resourceService.frmelmnts.lbl.viewless}}<i class="chevron up icon"></i></button>
</div>
</div>
<!-- RC Certificates -->
</div>
</div>
</div>
</div>
</div>
<app-modal-wrapper #profileModal *ngIf="showEdit" [config]="{disableClose: false, panelClass: ['overflow-visible', 'material-modal']}" (dismiss)="showEdit = !showEdit">
<ng-template sbModalContent let-data>
<app-popup [dialogProps]="data" [formInput]="userFrameWork" [showCloseIcon]="true"
[buttonLabel]="resourceService?.frmelmnts?.btn?.submit" (submit)="updateProfile($event)">
</app-popup>
</ng-template>
</app-modal-wrapper>
<app-modal-wrapper *ngIf="showContactPopup" [config]="{disableClose: false, panelClass: ['overflow-visible', 'material-modal']}" (dismiss)="showContactPopup = !showContactPopup">
<ng-template sbModalContent let-data>
<app-update-contact-details [dialogProps]="data" (close)="showContactPopup = !showContactPopup" [contactType]="contactType" [userProfile]="userProfile">
</app-update-contact-details>
</ng-template>
</app-modal-wrapper>
<app-location-selection
(close)="onLocationModalClose($event)"
*ngIf="showEditUserDetailsPopup">
<div slot="popup-sub-header">
<p class="subtitle">{{resourceService?.frmelmnts?.lbl?.editPersonalDetails}}‎</p>
</div>
</app-location-selection>
<app-full-page-loader *ngIf="showFullScreenLoader"></app-full-page-loader>
<app-modal-wrapper *ngIf="showRecoveryId" [config]="{disableClose: false, panelClass: 'material-modal'}" (dismiss)="showRecoveryId = !showRecoveryId">
<ng-template sbModalContent let-data>
<app-account-recovery-info [dialogProps]="data" [mode]="mode" (close)="showRecoveryId = !showRecoveryId"
[userProfile]="userProfile"></app-account-recovery-info>
</ng-template>
</app-modal-wrapper>
<router-outlet></router-outlet>
./profile-page.component.scss
@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
@use 'pages/content-header' as *;
/* fonts */
.font-w-bold {
font-weight: bold !important;
}
/* colors */
.color-2 {
color: var(--rc-007AFF) !important;
}
/* profile page color palate */
.profile-bg-c-3 {
background: var(--sbt-page-header-bg) !important;
}
.profile-bg-c-4 {
background: var(--sb-profile-bg-c-4) !important;
color:var(--black);
}
.profile-bg-c-4 {
@include respond-below(md) {
margin: 0 2% calculateRem(24px) 2%;
border-radius: calculateRem(24px);
}
}
/* width */
.max-w-300 {
max-width: calculateRem(300px) !important;
}
.max-w-400 {
max-width: calculateRem(400px) !important;
}
.profile-label-container {
max-width: calculateRem(600px) !important;
.ui.basic.label:hover {
border: calculateRem(1px) solid var(--rc-f9f9f9) !important;
}
}
@media only screen and (max-width: 767px) {
.profile-label-container {
max-width: calculateRem(200px) !important;
}
.m-responsive-flex-dc {
flex-direction: column;
}
.m-responsive-mt-15 {
margin-top: calculateRem(15px);
}
}
.text-warm-grey {
color: var(--gray-300);
}
.name-info {
background-color: var(--gray-400);
-webkit-mask-image: url(../../../../../assets/images/info-icon.svg);
mask-image: url(../../../../../assets/images/info-icon.svg);
-webkit-mask-size: contain;
-webkit-mask-position: 50% 50%;
-webkit-mask-repeat: no-repeat;
mask-size: contain;
mask-position: 50% 50%;
mask-repeat: no-repeat;
width: calculateRem(20px);
height: calculateRem(20px);
margin-top: calculateRem(3px);
margin-left: calculateRem(5px);
display: inline-block;
}
::ng-deep {
.ui.popup {
.arrow {
display: none;
}
}
}
// TODO::need to move this to styles component(right now this is done to avoid shadow DOM)
.ui.semi-circular.dodger-blue.basic.label {
border-radius: calculateRem(18.5px);
font-size: 1.16rem;
padding: calculateRem(8px) calculateRem(16px);
color: var(--primary-color);
&:hover {
border: 0;
}
.icon {
margin: 0;
}
}
.ui.semi-circular.update.basic.label,
.ui.semi-circular.basic.label {
border: calculateRem(1px) solid var(--primary-color);
border-radius: calculateRem(18.5px);
font-size: 1.16rem;
padding: calculateRem(8px) calculateRem(16px);
color: var(--gray-300);
background: var(--sb-profile-page-basic-label-bg);
}
.ui.label>.recovery-img {
background-color: var(--gray-300);
-webkit-mask-image: url(/assets/images/Recovery.svg) no-repeat 50% 50%;
-webkit-mask: url(/assets/images/Recovery.svg) no-repeat 50% 50%;
mask: url(/assets/images/Recovery.svg) no-repeat 50% 50%;
-webkit-mask-size: cover;
mask-size: cover;
height: calculateRem(16px);
width: calculateRem(16px);
}
.avatar-container {
width: calculateRem(98px);
height: calculateRem(98px);
margin: 0 auto;
.avatar-tickmark {
width: calculateRem(32px);
height: calculateRem(32px);
position: absolute;
left: 67%;
}
}
.my-avatar.verified ::ng-deep .avatar-content {
border: calculateRem(1px) solid var(--secondary-color) !important;
}
@include respond-below(sm) {
.avatar-tickmark {
left: 67%;
}
}
.ui.label.dodger-blue>.recovery-img {
background-color: var(--primary-color);
}
.school-id-section {
color: var(--white);
}
.sb-btn-border {
border-radius: calculateRem(40px);
text-transform: none;
}
.profile-user-label {
font-size: calculateRem(32px);
}
.status-progress {
color: var(--primary-color);
}
.status-completed {
color: var(--secondary-color);
}
.no-text-transform {
text-transform: unset;
}
.self-declared-title{
font-size: calculateRem(12px);
font-weight: bold;
}
.sb-certificate-trained {
border: calculateRem(0.5px) solid var(--gray-100);
border-radius: calculateRem(4px);
background-color: var(--sb-profile-certificate-bg);
margin: 0 auto;
.sb-ct-list {
padding: calculateRem(16px);
display: flex;
flex-direction: row;
align-items: center;
@include respond-below(md) {
position: relative;
padding-right: calculateRem(8px);
flex-direction: column;
}
}
}
.sb-course-progress-status-label{
width: 100%;
border-radius:calculateRem(8px) calculateRem(8px) 0 0;
justify-content: space-between;
display: flex;
padding: calculateRem(8px) calculateRem(16px);
}
.sb-profile-page-container{
.ui.segment{
background: var(--sb-profile-page-container);
}
}
.content-preference {
@include respond-below(md) {
padding: 0 2%;
&__info {
background: var(--sb-profile-bg-c-4);
padding: calculateRem(16px) 0;
border-radius: calculateRem(24px);
width: 100%;
color: var(--black);
}
}
}
::ng-deep {
.avatar-container {
.my-avatar.verified .sb-avatar-list-item .sb-avatar__img {
border: 1px solid !important;
border-color: var(--secondary-color) !important;
}
.avatar-tickmark {
width: 2rem;
height: 2rem;
position: absolute;
right: 0%;
z-index: 9;
top: 0.2rem;
}
}
}