@sunbird-cb/toc 0.36.2 → 0.36.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/_collection/_common/content-toc/app-toc-content/app-toc-content.component.mjs +6 -4
- package/esm2022/lib/services/app-toc.service.mjs +4 -5
- package/esm2022/lib/services/viewer-util.service.mjs +43 -32
- package/fesm2022/sunbird-cb-toc.mjs +51 -39
- package/fesm2022/sunbird-cb-toc.mjs.map +1 -1
- package/lib/_collection/_common/content-toc/app-toc-content/app-toc-content.component.d.ts +3 -2
- package/lib/_collection/_common/content-toc/app-toc-content/app-toc-content.component.d.ts.map +1 -1
- package/lib/services/app-toc.service.d.ts.map +1 -1
- package/lib/services/viewer-util.service.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1254,10 +1254,10 @@ class AppTocService {
|
|
|
1254
1254
|
*/
|
|
1255
1255
|
safeCompletionStatus(value) {
|
|
1256
1256
|
const numValue = Number(value);
|
|
1257
|
-
if (isNaN(numValue)
|
|
1257
|
+
if (isNaN(numValue)) {
|
|
1258
1258
|
return 0;
|
|
1259
1259
|
}
|
|
1260
|
-
return numValue;
|
|
1260
|
+
return Math.min(Math.max(Math.round(numValue), 0), 2);
|
|
1261
1261
|
}
|
|
1262
1262
|
constructor(http, contentLangSvc, configSvc, widgetSvc) {
|
|
1263
1263
|
this.http = http;
|
|
@@ -2126,9 +2126,8 @@ class AppTocService {
|
|
|
2126
2126
|
};
|
|
2127
2127
|
}
|
|
2128
2128
|
this.createHirarchyProgressHashmap(hierarchyData, rootCourseCategory);
|
|
2129
|
-
// NOTE: computeMilestoneLockingStatus is called AFTER progress data is populated
|
|
2130
|
-
// in mapCompletionPercentageProgram, not here where completion data is still 0
|
|
2131
2129
|
this.hashmap = { ...this.hashmap };
|
|
2130
|
+
this.hashmapUpdated.next({ timestamp: Date.now(), hashmap: this.hashmap });
|
|
2132
2131
|
}
|
|
2133
2132
|
}
|
|
2134
2133
|
computeMilestoneLockingStatus(isEnrolled = true) {
|
|
@@ -9555,10 +9554,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
9555
9554
|
|
|
9556
9555
|
// import { NsAppToc } from '../models/app-toc.model'
|
|
9557
9556
|
class AppTocContentComponent {
|
|
9558
|
-
constructor(route, tocSvc, configSvc) {
|
|
9557
|
+
constructor(route, tocSvc, configSvc, cdr) {
|
|
9559
9558
|
this.route = route;
|
|
9560
9559
|
this.tocSvc = tocSvc;
|
|
9561
9560
|
this.configSvc = configSvc;
|
|
9561
|
+
this.cdr = cdr;
|
|
9562
9562
|
this.forPreview = false;
|
|
9563
9563
|
this.resumeData = null;
|
|
9564
9564
|
this.batchData = null;
|
|
@@ -9627,6 +9627,7 @@ class AppTocContentComponent {
|
|
|
9627
9627
|
if (update && update.hashmap) {
|
|
9628
9628
|
// Update hierarchyMapData with the latest hashmap from the service
|
|
9629
9629
|
this.hierarchyMapData = update.hashmap;
|
|
9630
|
+
this.cdr.detectChanges();
|
|
9630
9631
|
}
|
|
9631
9632
|
});
|
|
9632
9633
|
const instanceConfig = this.configSvc.instanceConfig;
|
|
@@ -9810,13 +9811,13 @@ class AppTocContentComponent {
|
|
|
9810
9811
|
return false;
|
|
9811
9812
|
return element.scrollHeight > element.clientHeight;
|
|
9812
9813
|
}
|
|
9813
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppTocContentComponent, deps: [{ token: i1$1.ActivatedRoute }, { token: AppTocService }, { token: i2$1.ConfigurationsService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9814
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppTocContentComponent, deps: [{ token: i1$1.ActivatedRoute }, { token: AppTocService }, { token: i2$1.ConfigurationsService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
9814
9815
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: AppTocContentComponent, selector: "ws-widget-app-toc-content", inputs: { batchId: "batchId", content: "content", forPreview: "forPreview", resumeData: "resumeData", batchData: "batchData", skeletonLoader: "skeletonLoader", tocStructure: "tocStructure", config: "config", hierarchyMapData: "hierarchyMapData", pathSet: "pathSet", componentName: "componentName", isPreAssessment: "isPreAssessment", baseContentReadData: "baseContentReadData", contentReadData: "contentReadData" }, usesOnChanges: true, ngImport: i0, template: "<div *ngIf=\"content?.courseCategory === 'Learning Pathway' && componentName !== 'viewer'\">\n <!-- Milestone / Learning Path UI -->\n <div class=\"milestone-wrapper\" role=\"group\" aria-label=\"Learning path milestones\">\n <!-- Learning Path Header -->\n <div class=\"learning-path-header\">\n <h3 class=\"learning-path-title\">Learning Path</h3>\n <p class=\"learning-path-subtitle\">Complete {{content?.children?.length - 1 || 3}} key milestones</p>\n </div>\n <ng-container *ngIf=\"content?.children?.length; else fallbackMilestones\">\n <ul class=\"milestone-list\">\n <li *ngFor=\"let m of content?.children; let i = index\" class=\"milestone-item\"\n [class.completed]=\"m?.completionStatus === 2 || getMilestoneCompletedOrNot(m?.identifier)\" role=\"listitem\">\n <div class=\"milestone-circle\" [attr.aria-label]=\"m?.name || ('Milestone ' + (i+1))\">\n <img *ngIf=\"m?.completionStatus === 2 || getMilestoneCompletedOrNot(m?.identifier)\" src=\"assets/icons/toc/tick-orange.svg\"\n class=\"milestone-checkmark\" alt=\"Completed\" />\n <span *ngIf=\"m?.completionStatus !== 2 && !getMilestoneCompletedOrNot(m?.identifier)\" class=\"milestone-index\"></span>\n </div>\n <div class=\"milestone-label\">\n <p class=\"mb-0 leading-none\">\n <span *ngIf=\"m?.contextCategory\">{{m?.contextCategory}}</span>\n <span *ngIf=\"m?.courseCategory\">{{m?.courseCategory}} {{ i}}</span>\n </p>\n <p #milestoneNameRef class=\"milestone-name-text leading-none\"\n [matTooltip]=\"isMultiLineTruncated(milestoneNameRef) ? m?.name : ''\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"multiline-tooltip\">\n {{ m?.name }}\n </p>\n </div>\n </li>\n </ul>\n </ng-container>\n <ng-template #fallbackMilestones>\n <ul class=\"milestone-list\">\n <li class=\"milestone-item completed\" role=\"listitem\">\n <div class=\"milestone-circle\" aria-label=\"Pre Assessment\">\n <img src=\"assets/icons/toc/tick-orange.svg\" class=\"milestone-checkmark\" alt=\"Completed\" />\n </div>\n <div class=\"milestone-label\">Pre Assessment</div>\n </li>\n <li class=\"milestone-item completed\" role=\"listitem\">\n <div class=\"milestone-circle\" aria-label=\"1. Foundation of Workplace Ethics\">\n <img src=\"assets/icons/toc/tick-orange.svg\" class=\"milestone-checkmark\" alt=\"Completed\" />\n </div>\n <div class=\"milestone-label\">1. Foundation of Workplace Ethics</div>\n </li>\n <li class=\"milestone-item\" role=\"listitem\">\n <div class=\"milestone-circle\" aria-label=\"2. Health and Productivity at Work\">\n <img src=\"assets/icons/toc/tick-orange.svg\" class=\"milestone-checkmark\" alt=\"Completed\" />\n </div>\n <div class=\"milestone-label\">2. Health and Productivity at Work</div>\n </li>\n <li class=\"milestone-item\" role=\"listitem\">\n <div class=\"milestone-circle\" aria-label=\"3. Health and Productivity at Work\">\n <span class=\"milestone-index\">4</span>\n </div>\n <div class=\"milestone-label\">3. Health and Productivity at Work</div>\n </li>\n </ul>\n </ng-template>\n </div>\n</div>\n<div class=\"bggrey\">\n <div class=\"py-4 content-container\" id=\"contentContainer\" *ngIf=\"!isPreAssessment\">\n <div class=\"main-container flex flex-col gap-4\">\n <ng-container *ngIf=\"content?.primaryCategory === nsContent?.EPrimaryCategory?.BLENDED_PROGRAM\">\n <div class=\"padding-left-m flex gap-4 tab-list\">\n <ng-container *ngFor=\"let type of typesOfContent\">\n <div class=\"tab-data\" (click)=\"!type.disabled && selectedTabType = type.id\"\n [ngClass]=\"{'active-tab': selectedTabType === type.id, 'disabled':type.disabled}\">\n <span>{{type.name}}</span>\n </div>\n </ng-container>\n </div>\n </ng-container>\n <ng-container\n *ngIf=\"selectedTabType === 'content' && content?.primaryCategory === nsContent?.EPrimaryCategory?.BLENDED_PROGRAM\">\n <ng-container [ngTemplateOutlet]=\"contentBlock\"></ng-container>\n </ng-container>\n <ng-container\n *ngIf=\"selectedTabType === 'session' && content?.primaryCategory === nsContent?.EPrimaryCategory?.BLENDED_PROGRAM\">\n <ws-widget-app-app-toc-sessions-new [batchData]=\"batchData\" [pathSet]=\"pathSet\" [rootId]=\"contextId\"\n [rootContentType]=\"contextPath\" [batchId]=\"batchId\" [config]=\"config\" [content]=\"content\">\n </ws-widget-app-app-toc-sessions-new>\n </ng-container>\n <ng-container *ngIf=\"content?.primaryCategory !== nsContent?.EPrimaryCategory?.BLENDED_PROGRAM\">\n <ng-container [ngTemplateOutlet]=\"contentBlock\"></ng-container>\n </ng-container>\n </div>\n </div>\n <!-- {{pathSet|json}} -->\n <ng-template #contentBlock>\n <ng-container *ngIf=\"!contentLoader\">\n <ng-container *ngIf=\"content?.children?.length; else noChildren\">\n <div class=\"content-card \"\n *ngFor=\"let card of content?.children; trackBy: contentTrackBy; let i = index;\"\n [ngClass]=\"{ 'content-active': pathSet && pathSet.has(card.identifier) && isEnrolled}\">\n <!-- {{card|json}} -->\n <ws-widget-app-toc-content-card-v2 [forPreview]=\"forPreview\" [expandAll]=\"expandAll\"\n [componentName]=\"componentName\" [expandActive]=\"true\" [rootId]=\"contextId\" [batchId]=\"batchId\"\n [rootContentType]=\"contextPath\" [content]=\"card\" [mlCourse]=\"content\" [index]=\"i+1\"\n [pathSet]=\"pathSet\" [hierarchyMapData]=\"hierarchyMapData\" [batchData]=\"batchData\"\n [baseContentReadData]=\"baseContentReadData\"></ws-widget-app-toc-content-card-v2>\n </div>\n </ng-container>\n <ng-template #noChildren>\n <div *ngIf=\"!isPlayable\"\n class=\"ws-mat-primary-default-text ws-mat-primary-lite-background px-6 py-8 font-normal text-base noChildren\">\n The preview for this type of content is unavailable. Please click on Start button above to view.\n </div>\n <!-- <ng-container *ngIf=\"isPlayable\" [sbUiResolverWidget]=\"contentPlayWidgetConfig\"></ng-container> -->\n </ng-template>\n </ng-container>\n\n <ng-container *ngIf=\"contentLoader\">\n <ws-widget-app-toc-content-card-v2-skeleton></ws-widget-app-toc-content-card-v2-skeleton>\n </ng-container>\n </ng-template>\n <div *ngIf=\"isPreAssessment\">\n <div class=\"content-card \"\n *ngFor=\"let card of content?.preEnrolmentResources; trackBy: identifier; let i = index;\"\n [ngClass]=\"{ 'content-active': pathSet && pathSet.has(card.identifier) && isEnrolled}\">\n <!-- {{card|json}} -->\n <ws-widget-app-toc-content-card-v2 [forPreview]=\"forPreview\" [expandAll]=\"expandAll\"\n [componentName]=\"componentName\" [expandActive]=\"true\" [rootId]=\"contextId\" [batchId]=\"batchId\"\n [rootContentType]=\"contextPath\" [isPreAssessment]=\"isPreAssessment\" [content]=\"card\"\n [mlCourse]=\"content\" [index]=\"i+1\" [pathSet]=\"pathSet\" [hierarchyMapData]=\"hierarchyMapData\"\n [batchData]=\"batchData\" [baseContentReadData]=\"baseContentReadData\"></ws-widget-app-toc-content-card-v2>\n </div>\n </div>\n</div>", styles: [".bggrey{background-color:#eff3f9}.content-container{min-height:800px}.content-accordion .content-panel{box-shadow:none}.content-accordion .content-header{padding:20px;background-color:#fff;border:none;box-shadow:none}.content-key-values{color:#0009}.content-key-values mat-icon{width:14px;height:14px;font-size:14px;color:#0006}.main-container{width:100%;box-sizing:border-box}.main-container .toc-section{display:flex;justify-content:space-between;padding-bottom:12px}.main-container .content-card{background:#fff;border:1px solid rgb(221,221,221);overflow:hidden;position:relative}.main-container .content-card.content-active{border:1px solid #1a4ca1}.main-container .noChildren{color:#222!important}@media only screen and (max-width: 959px){.main-container{width:100%;padding-right:0;margin-bottom:32px}}::ng-deep .mat-expansion-indicator{display:none!important}.mat-panel-indicator{width:28px;height:28px;font-size:28px}.tab-list .tab-data{border-radius:18px;border:1px solid rgba(0,0,0,.08);opacity:1;background-color:#e5e9ef;padding:6px 16px;cursor:pointer}.tab-list .tab-data span{opacity:1;color:#000000de;font-family:Lato-Regular;font-size:14px;font-weight:400;font-style:Regular;letter-spacing:.25px;text-align:left;line-height:20px}.tab-list .active-tab{border-radius:18px;border:1px solid rgb(27,76,161);opacity:1;background-color:#dee6f2}.tab-list .active-tab span{color:#1b4ca1}.tab-list .disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.milestone-wrapper{--milestone-size: 33px;--milestone-border: 3px;padding:16px;background:#fff;display:flex;align-items:center;margin-top:16px}.learning-path-header{padding-right:16px}.learning-path-title{font-size:18px;font-weight:700;color:#000000de;margin:0 0 4px;font-family:Lato-Bold,Lato,sans-serif}.learning-path-subtitle{font-size:14px;font-weight:400;color:#0009;margin:0;font-family:Lato-Regular,Lato,sans-serif}.milestone-list{display:flex;align-items:flex-start;justify-content:space-between;list-style:none;margin:0;gap:12px;flex:1}.milestone-item{display:flex;flex-direction:column;align-items:center;text-align:center;flex:1 1 0;position:relative}.milestone-item:after{content:\"\";position:absolute;top:calc(var(--milestone-size) / 2);left:50%;right:-50%;height:3px;background:#e0e0e0;border-top:3px dotted #BDBDBD;background:transparent;z-index:0}.milestone-item.completed:after{background:linear-gradient(90deg,#efa34f,#f3962f);border:none}.milestone-item:last-child:after{display:none}.milestone-circle{width:var(--milestone-size);height:var(--milestone-size);min-width:var(--milestone-size);border-radius:50%;background:#fff;border:var(--milestone-border) solid #F3962F;display:flex;align-items:center;justify-content:center;z-index:1;position:relative;box-shadow:0 2px 8px #00000014;transition:all .2s ease}.milestone-item.completed .milestone-circle{background:#fff;border-color:#f3962f;box-shadow:0 4px 12px #efa34f4d}.milestone-checkmark{width:80%;height:80%;object-fit:contain}.milestone-index{font-weight:700;font-size:18px;color:#757575}.milestone-item.completed .milestone-index{color:#fff}.milestone-label{margin-top:12px;font-size:14px;line-height:1.4;color:#000000de;word-wrap:break-word;white-space:normal;font-weight:500}.milestone-item:focus-within .milestone-circle,.milestone-item:hover .milestone-circle{transform:translateY(-2px) scale(1.05);box-shadow:0 6px 16px #00000026}.milestone-item.completed:hover .milestone-circle{box-shadow:0 6px 20px #efa34f66}@media (max-width: 768px){.milestone-wrapper{--milestone-size: 48px;padding:20px 12px 28px}.milestone-list{gap:8px;padding:0 8px}.milestone-label{font-size:12px;max-width:100px}.milestone-index{font-size:16px}}@media (max-width: 480px){.milestone-wrapper{--milestone-size: 40px;padding:16px 8px 24px}.milestone-list{gap:6px;padding:0 4px}.milestone-label{font-size:11px;max-width:80px;margin-top:8px}.milestone-index{font-size:14px}.milestone-item:after{height:2px;border-top-width:2px}}.milestone-name-text{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;line-height:1.4;word-break:break-word}::ng-deep .multiline-tooltip{white-space:pre-wrap!important;max-width:400px!important;word-break:break-word!important;line-height:1.4!important}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i5$2.MatLegacyTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { kind: "component", type: AppTocContentCardV2Component, selector: "ws-widget-app-toc-content-card-v2", inputs: ["content", "expandAll", "rootId", "rootContentType", "forPreview", "batchId", "componentName", "index", "pathSet", "expandActive", "hierarchyMapData", "batchData", "isPreAssessment", "baseContentReadData", "mlCourse", "parentMilestoneLocked"] }, { kind: "component", type: AppTocSessionsNewComponent, selector: "ws-widget-app-app-toc-sessions-new", inputs: ["batchData", "content", "forPreview", "config", "batchId", "rootId", "rootContentType", "pathSet"] }, { kind: "component", type: AppTocContentCardV2SkeletonComponent, selector: "ws-widget-app-toc-content-card-v2-skeleton" }] }); }
|
|
9815
9816
|
}
|
|
9816
9817
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppTocContentComponent, decorators: [{
|
|
9817
9818
|
type: Component,
|
|
9818
9819
|
args: [{ selector: 'ws-widget-app-toc-content', template: "<div *ngIf=\"content?.courseCategory === 'Learning Pathway' && componentName !== 'viewer'\">\n <!-- Milestone / Learning Path UI -->\n <div class=\"milestone-wrapper\" role=\"group\" aria-label=\"Learning path milestones\">\n <!-- Learning Path Header -->\n <div class=\"learning-path-header\">\n <h3 class=\"learning-path-title\">Learning Path</h3>\n <p class=\"learning-path-subtitle\">Complete {{content?.children?.length - 1 || 3}} key milestones</p>\n </div>\n <ng-container *ngIf=\"content?.children?.length; else fallbackMilestones\">\n <ul class=\"milestone-list\">\n <li *ngFor=\"let m of content?.children; let i = index\" class=\"milestone-item\"\n [class.completed]=\"m?.completionStatus === 2 || getMilestoneCompletedOrNot(m?.identifier)\" role=\"listitem\">\n <div class=\"milestone-circle\" [attr.aria-label]=\"m?.name || ('Milestone ' + (i+1))\">\n <img *ngIf=\"m?.completionStatus === 2 || getMilestoneCompletedOrNot(m?.identifier)\" src=\"assets/icons/toc/tick-orange.svg\"\n class=\"milestone-checkmark\" alt=\"Completed\" />\n <span *ngIf=\"m?.completionStatus !== 2 && !getMilestoneCompletedOrNot(m?.identifier)\" class=\"milestone-index\"></span>\n </div>\n <div class=\"milestone-label\">\n <p class=\"mb-0 leading-none\">\n <span *ngIf=\"m?.contextCategory\">{{m?.contextCategory}}</span>\n <span *ngIf=\"m?.courseCategory\">{{m?.courseCategory}} {{ i}}</span>\n </p>\n <p #milestoneNameRef class=\"milestone-name-text leading-none\"\n [matTooltip]=\"isMultiLineTruncated(milestoneNameRef) ? m?.name : ''\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"multiline-tooltip\">\n {{ m?.name }}\n </p>\n </div>\n </li>\n </ul>\n </ng-container>\n <ng-template #fallbackMilestones>\n <ul class=\"milestone-list\">\n <li class=\"milestone-item completed\" role=\"listitem\">\n <div class=\"milestone-circle\" aria-label=\"Pre Assessment\">\n <img src=\"assets/icons/toc/tick-orange.svg\" class=\"milestone-checkmark\" alt=\"Completed\" />\n </div>\n <div class=\"milestone-label\">Pre Assessment</div>\n </li>\n <li class=\"milestone-item completed\" role=\"listitem\">\n <div class=\"milestone-circle\" aria-label=\"1. Foundation of Workplace Ethics\">\n <img src=\"assets/icons/toc/tick-orange.svg\" class=\"milestone-checkmark\" alt=\"Completed\" />\n </div>\n <div class=\"milestone-label\">1. Foundation of Workplace Ethics</div>\n </li>\n <li class=\"milestone-item\" role=\"listitem\">\n <div class=\"milestone-circle\" aria-label=\"2. Health and Productivity at Work\">\n <img src=\"assets/icons/toc/tick-orange.svg\" class=\"milestone-checkmark\" alt=\"Completed\" />\n </div>\n <div class=\"milestone-label\">2. Health and Productivity at Work</div>\n </li>\n <li class=\"milestone-item\" role=\"listitem\">\n <div class=\"milestone-circle\" aria-label=\"3. Health and Productivity at Work\">\n <span class=\"milestone-index\">4</span>\n </div>\n <div class=\"milestone-label\">3. Health and Productivity at Work</div>\n </li>\n </ul>\n </ng-template>\n </div>\n</div>\n<div class=\"bggrey\">\n <div class=\"py-4 content-container\" id=\"contentContainer\" *ngIf=\"!isPreAssessment\">\n <div class=\"main-container flex flex-col gap-4\">\n <ng-container *ngIf=\"content?.primaryCategory === nsContent?.EPrimaryCategory?.BLENDED_PROGRAM\">\n <div class=\"padding-left-m flex gap-4 tab-list\">\n <ng-container *ngFor=\"let type of typesOfContent\">\n <div class=\"tab-data\" (click)=\"!type.disabled && selectedTabType = type.id\"\n [ngClass]=\"{'active-tab': selectedTabType === type.id, 'disabled':type.disabled}\">\n <span>{{type.name}}</span>\n </div>\n </ng-container>\n </div>\n </ng-container>\n <ng-container\n *ngIf=\"selectedTabType === 'content' && content?.primaryCategory === nsContent?.EPrimaryCategory?.BLENDED_PROGRAM\">\n <ng-container [ngTemplateOutlet]=\"contentBlock\"></ng-container>\n </ng-container>\n <ng-container\n *ngIf=\"selectedTabType === 'session' && content?.primaryCategory === nsContent?.EPrimaryCategory?.BLENDED_PROGRAM\">\n <ws-widget-app-app-toc-sessions-new [batchData]=\"batchData\" [pathSet]=\"pathSet\" [rootId]=\"contextId\"\n [rootContentType]=\"contextPath\" [batchId]=\"batchId\" [config]=\"config\" [content]=\"content\">\n </ws-widget-app-app-toc-sessions-new>\n </ng-container>\n <ng-container *ngIf=\"content?.primaryCategory !== nsContent?.EPrimaryCategory?.BLENDED_PROGRAM\">\n <ng-container [ngTemplateOutlet]=\"contentBlock\"></ng-container>\n </ng-container>\n </div>\n </div>\n <!-- {{pathSet|json}} -->\n <ng-template #contentBlock>\n <ng-container *ngIf=\"!contentLoader\">\n <ng-container *ngIf=\"content?.children?.length; else noChildren\">\n <div class=\"content-card \"\n *ngFor=\"let card of content?.children; trackBy: contentTrackBy; let i = index;\"\n [ngClass]=\"{ 'content-active': pathSet && pathSet.has(card.identifier) && isEnrolled}\">\n <!-- {{card|json}} -->\n <ws-widget-app-toc-content-card-v2 [forPreview]=\"forPreview\" [expandAll]=\"expandAll\"\n [componentName]=\"componentName\" [expandActive]=\"true\" [rootId]=\"contextId\" [batchId]=\"batchId\"\n [rootContentType]=\"contextPath\" [content]=\"card\" [mlCourse]=\"content\" [index]=\"i+1\"\n [pathSet]=\"pathSet\" [hierarchyMapData]=\"hierarchyMapData\" [batchData]=\"batchData\"\n [baseContentReadData]=\"baseContentReadData\"></ws-widget-app-toc-content-card-v2>\n </div>\n </ng-container>\n <ng-template #noChildren>\n <div *ngIf=\"!isPlayable\"\n class=\"ws-mat-primary-default-text ws-mat-primary-lite-background px-6 py-8 font-normal text-base noChildren\">\n The preview for this type of content is unavailable. Please click on Start button above to view.\n </div>\n <!-- <ng-container *ngIf=\"isPlayable\" [sbUiResolverWidget]=\"contentPlayWidgetConfig\"></ng-container> -->\n </ng-template>\n </ng-container>\n\n <ng-container *ngIf=\"contentLoader\">\n <ws-widget-app-toc-content-card-v2-skeleton></ws-widget-app-toc-content-card-v2-skeleton>\n </ng-container>\n </ng-template>\n <div *ngIf=\"isPreAssessment\">\n <div class=\"content-card \"\n *ngFor=\"let card of content?.preEnrolmentResources; trackBy: identifier; let i = index;\"\n [ngClass]=\"{ 'content-active': pathSet && pathSet.has(card.identifier) && isEnrolled}\">\n <!-- {{card|json}} -->\n <ws-widget-app-toc-content-card-v2 [forPreview]=\"forPreview\" [expandAll]=\"expandAll\"\n [componentName]=\"componentName\" [expandActive]=\"true\" [rootId]=\"contextId\" [batchId]=\"batchId\"\n [rootContentType]=\"contextPath\" [isPreAssessment]=\"isPreAssessment\" [content]=\"card\"\n [mlCourse]=\"content\" [index]=\"i+1\" [pathSet]=\"pathSet\" [hierarchyMapData]=\"hierarchyMapData\"\n [batchData]=\"batchData\" [baseContentReadData]=\"baseContentReadData\"></ws-widget-app-toc-content-card-v2>\n </div>\n </div>\n</div>", styles: [".bggrey{background-color:#eff3f9}.content-container{min-height:800px}.content-accordion .content-panel{box-shadow:none}.content-accordion .content-header{padding:20px;background-color:#fff;border:none;box-shadow:none}.content-key-values{color:#0009}.content-key-values mat-icon{width:14px;height:14px;font-size:14px;color:#0006}.main-container{width:100%;box-sizing:border-box}.main-container .toc-section{display:flex;justify-content:space-between;padding-bottom:12px}.main-container .content-card{background:#fff;border:1px solid rgb(221,221,221);overflow:hidden;position:relative}.main-container .content-card.content-active{border:1px solid #1a4ca1}.main-container .noChildren{color:#222!important}@media only screen and (max-width: 959px){.main-container{width:100%;padding-right:0;margin-bottom:32px}}::ng-deep .mat-expansion-indicator{display:none!important}.mat-panel-indicator{width:28px;height:28px;font-size:28px}.tab-list .tab-data{border-radius:18px;border:1px solid rgba(0,0,0,.08);opacity:1;background-color:#e5e9ef;padding:6px 16px;cursor:pointer}.tab-list .tab-data span{opacity:1;color:#000000de;font-family:Lato-Regular;font-size:14px;font-weight:400;font-style:Regular;letter-spacing:.25px;text-align:left;line-height:20px}.tab-list .active-tab{border-radius:18px;border:1px solid rgb(27,76,161);opacity:1;background-color:#dee6f2}.tab-list .active-tab span{color:#1b4ca1}.tab-list .disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.milestone-wrapper{--milestone-size: 33px;--milestone-border: 3px;padding:16px;background:#fff;display:flex;align-items:center;margin-top:16px}.learning-path-header{padding-right:16px}.learning-path-title{font-size:18px;font-weight:700;color:#000000de;margin:0 0 4px;font-family:Lato-Bold,Lato,sans-serif}.learning-path-subtitle{font-size:14px;font-weight:400;color:#0009;margin:0;font-family:Lato-Regular,Lato,sans-serif}.milestone-list{display:flex;align-items:flex-start;justify-content:space-between;list-style:none;margin:0;gap:12px;flex:1}.milestone-item{display:flex;flex-direction:column;align-items:center;text-align:center;flex:1 1 0;position:relative}.milestone-item:after{content:\"\";position:absolute;top:calc(var(--milestone-size) / 2);left:50%;right:-50%;height:3px;background:#e0e0e0;border-top:3px dotted #BDBDBD;background:transparent;z-index:0}.milestone-item.completed:after{background:linear-gradient(90deg,#efa34f,#f3962f);border:none}.milestone-item:last-child:after{display:none}.milestone-circle{width:var(--milestone-size);height:var(--milestone-size);min-width:var(--milestone-size);border-radius:50%;background:#fff;border:var(--milestone-border) solid #F3962F;display:flex;align-items:center;justify-content:center;z-index:1;position:relative;box-shadow:0 2px 8px #00000014;transition:all .2s ease}.milestone-item.completed .milestone-circle{background:#fff;border-color:#f3962f;box-shadow:0 4px 12px #efa34f4d}.milestone-checkmark{width:80%;height:80%;object-fit:contain}.milestone-index{font-weight:700;font-size:18px;color:#757575}.milestone-item.completed .milestone-index{color:#fff}.milestone-label{margin-top:12px;font-size:14px;line-height:1.4;color:#000000de;word-wrap:break-word;white-space:normal;font-weight:500}.milestone-item:focus-within .milestone-circle,.milestone-item:hover .milestone-circle{transform:translateY(-2px) scale(1.05);box-shadow:0 6px 16px #00000026}.milestone-item.completed:hover .milestone-circle{box-shadow:0 6px 20px #efa34f66}@media (max-width: 768px){.milestone-wrapper{--milestone-size: 48px;padding:20px 12px 28px}.milestone-list{gap:8px;padding:0 8px}.milestone-label{font-size:12px;max-width:100px}.milestone-index{font-size:16px}}@media (max-width: 480px){.milestone-wrapper{--milestone-size: 40px;padding:16px 8px 24px}.milestone-list{gap:6px;padding:0 4px}.milestone-label{font-size:11px;max-width:80px;margin-top:8px}.milestone-index{font-size:14px}.milestone-item:after{height:2px;border-top-width:2px}}.milestone-name-text{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;text-overflow:ellipsis;line-height:1.4;word-break:break-word}::ng-deep .multiline-tooltip{white-space:pre-wrap!important;max-width:400px!important;word-break:break-word!important;line-height:1.4!important}\n"] }]
|
|
9819
|
-
}], ctorParameters: function () { return [{ type: i1$1.ActivatedRoute }, { type: AppTocService }, { type: i2$1.ConfigurationsService }]; }, propDecorators: { batchId: [{
|
|
9820
|
+
}], ctorParameters: function () { return [{ type: i1$1.ActivatedRoute }, { type: AppTocService }, { type: i2$1.ConfigurationsService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { batchId: [{
|
|
9820
9821
|
type: Input
|
|
9821
9822
|
}], content: [{
|
|
9822
9823
|
type: Input
|
|
@@ -13726,17 +13727,20 @@ class ViewerUtilService {
|
|
|
13726
13727
|
this.http
|
|
13727
13728
|
.patch(`${this.API_ENDPOINTS.PROGRESS_UPDATE}/${contentId}`, req)
|
|
13728
13729
|
.subscribe(noop, noop);
|
|
13729
|
-
|
|
13730
|
-
|
|
13731
|
-
|
|
13732
|
-
|
|
13733
|
-
|
|
13734
|
-
|
|
13735
|
-
|
|
13736
|
-
|
|
13737
|
-
|
|
13738
|
-
|
|
13739
|
-
|
|
13730
|
+
const hashEntry = this.tocSvc.hashmap[contentId] || {};
|
|
13731
|
+
const currentStatus = hashEntry['completionStatus'];
|
|
13732
|
+
if (!currentStatus || currentStatus < 2) {
|
|
13733
|
+
this.tocSvc.hashmap[contentId] = {
|
|
13734
|
+
...hashEntry,
|
|
13735
|
+
identifier: contentId,
|
|
13736
|
+
completionPercentage: req.request.contents[0].completionPercentage,
|
|
13737
|
+
completionStatus: Number(req.request.contents[0].status) || 0,
|
|
13738
|
+
};
|
|
13739
|
+
this.tocSvc.hashmap = { ...this.tocSvc.hashmap };
|
|
13740
|
+
// Trigger milestone lock recomputation - it will emit hashmapUpdated with both progress and lock changes
|
|
13741
|
+
this.tocSvc.triggerMilestoneLockUpdate();
|
|
13742
|
+
// Emit to trigger viewer component refresh for Learning Pathways
|
|
13743
|
+
this.markAsCompleteSubject.next(true);
|
|
13740
13744
|
}
|
|
13741
13745
|
}
|
|
13742
13746
|
else {
|
|
@@ -13934,11 +13938,16 @@ class ViewerUtilService {
|
|
|
13934
13938
|
this.http
|
|
13935
13939
|
.patch(`${this.API_ENDPOINTS.PROGRESS_UPDATE}/${contentId}`, req)
|
|
13936
13940
|
.subscribe(noop, noop);
|
|
13937
|
-
if (this.tocSvc.hashmap &&
|
|
13938
|
-
const
|
|
13941
|
+
if (this.tocSvc.hashmap && req.request.contents[0]) {
|
|
13942
|
+
const hashEntry = this.tocSvc.hashmap[contentId] || {};
|
|
13943
|
+
const currentStatus = hashEntry['completionStatus'];
|
|
13939
13944
|
if (!currentStatus || currentStatus < 2) {
|
|
13940
|
-
this.tocSvc.hashmap[contentId]
|
|
13941
|
-
|
|
13945
|
+
this.tocSvc.hashmap[contentId] = {
|
|
13946
|
+
...hashEntry,
|
|
13947
|
+
identifier: contentId,
|
|
13948
|
+
completionPercentage: req.request.contents[0].completionPercentage,
|
|
13949
|
+
completionStatus: Number(req.request.contents[0].status) || 0,
|
|
13950
|
+
};
|
|
13942
13951
|
this.tocSvc.hashmap = { ...this.tocSvc.hashmap };
|
|
13943
13952
|
// Trigger milestone lock recomputation - it will emit hashmapUpdated with both progress and lock changes
|
|
13944
13953
|
if (this.tocSvc.triggerMilestoneLockUpdate) {
|
|
@@ -14010,23 +14019,26 @@ class ViewerUtilService {
|
|
|
14010
14019
|
return this.http.get(`/apis/proxies/v8/course/v1/hierarchy/${id}?mode=${type}`);
|
|
14011
14020
|
}
|
|
14012
14021
|
updateContentHashMapForAssesstent(contentId, contentProgress) {
|
|
14013
|
-
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14019
|
-
|
|
14020
|
-
|
|
14021
|
-
|
|
14022
|
-
|
|
14023
|
-
|
|
14024
|
-
|
|
14025
|
-
|
|
14026
|
-
|
|
14027
|
-
|
|
14028
|
-
|
|
14029
|
-
|
|
14022
|
+
const hashEntry = this.tocSvc.hashmap[contentId] || {};
|
|
14023
|
+
const currentStatus = hashEntry['completionStatus'] || 0;
|
|
14024
|
+
const newStatus = Number(contentProgress.status) || 0;
|
|
14025
|
+
// Update if not complete or if new status is higher
|
|
14026
|
+
if (currentStatus < 2 || newStatus >= currentStatus) {
|
|
14027
|
+
this.tocSvc.hashmap[contentId] = {
|
|
14028
|
+
...hashEntry,
|
|
14029
|
+
identifier: contentId,
|
|
14030
|
+
completionPercentage: contentProgress.completionPercentage,
|
|
14031
|
+
completionStatus: newStatus,
|
|
14032
|
+
status: newStatus,
|
|
14033
|
+
};
|
|
14034
|
+
// Create new hashmap reference for Angular change detection
|
|
14035
|
+
this.tocSvc.hashmap = { ...this.tocSvc.hashmap };
|
|
14036
|
+
// Trigger milestone lock recomputation - it will emit hashmapUpdated with both progress and lock changes
|
|
14037
|
+
if (this.tocSvc.triggerMilestoneLockUpdate) {
|
|
14038
|
+
this.tocSvc.triggerMilestoneLockUpdate();
|
|
14039
|
+
}
|
|
14040
|
+
// Emit to trigger viewer component refresh for Learning Pathways
|
|
14041
|
+
this.markAsCompleteSubject.next(true);
|
|
14030
14042
|
}
|
|
14031
14043
|
}
|
|
14032
14044
|
getFormById(formId) {
|