@sunbird-cb/toc 0.0.14 → 0.0.15

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.
@@ -2032,6 +2032,17 @@ class AppTocService {
2032
2032
  child.mimeType === 'application/vnd.sunbird.questionset';
2033
2033
  if (isAssessment) {
2034
2034
  }
2035
+ // Debug: Log when adding item with isPreAssessment flag to hashmap
2036
+ if (child.isPreAssessment === true) {
2037
+ console.log('🔍 [HASHMAP BUILD] Adding pre-assessment to hashmap:', {
2038
+ id: child.identifier,
2039
+ name: child.name,
2040
+ isPreAssessment: localMap.isPreAssessment,
2041
+ parent: localMap.parent,
2042
+ completionStatus: localMap.completionStatus,
2043
+ status: localMap.status
2044
+ });
2045
+ }
2035
2046
  this.hashmap[child.identifier] = localMap;
2036
2047
  });
2037
2048
  }
@@ -2158,6 +2169,8 @@ class AppTocService {
2158
2169
  * ═══════════════════════════════════════════════════════════════════════════
2159
2170
  */
2160
2171
  computeMilestoneLockingStatus(isEnrolled = true) {
2172
+ console.log('🚀 [MILESTONE LOCK] computeMilestoneLockingStatus CALLED with isEnrolled:', isEnrolled);
2173
+ console.log('🚀 [MILESTONE LOCK] Hashmap size:', Object.keys(this.hashmap).length);
2161
2174
  if (!this.hashmap || Object.keys(this.hashmap).length === 0) {
2162
2175
  console.warn('âš ī¸ Hashmap is empty - cannot compute milestone locking');
2163
2176
  return;
@@ -2355,7 +2368,17 @@ class AppTocService {
2355
2368
  });
2356
2369
  // STEP 6: Trigger hashmap update
2357
2370
  console.log('✅ Milestone locking computation COMPLETE');
2371
+ // Debug: Log final lock status for all milestones
2372
+ const milestonesFinal = Object.keys(this.hashmap).filter(key => this.hashmap[key].isMilestone ||
2373
+ this.hashmap[key].primaryCategory === 'Milestone' ||
2374
+ this.hashmap[key].courseCategory === 'Milestone');
2375
+ console.log('📊 [FINAL LOCK STATUS] All milestones:');
2376
+ milestonesFinal.forEach((id, i) => {
2377
+ const m = this.hashmap[id];
2378
+ console.log(` ${i + 1}. ${m.name}: computedIsLocked=${m.computedIsLocked}, unlockMessage="${m.unlockMessage || 'N/A'}"`);
2379
+ });
2358
2380
  this.hashmap = { ...this.hashmap };
2381
+ console.log('📡 [SERVICE] Broadcasting hashmap update with computedIsLocked values');
2359
2382
  this.hashmapUpdated.next({ timestamp: Date.now(), hashmap: this.hashmap });
2360
2383
  }
2361
2384
  /**
@@ -2366,13 +2389,17 @@ class AppTocService {
2366
2389
  // Check if we have a Learning Pathway in the hashmap
2367
2390
  const hasLearningPathway = Object.keys(this.hashmap).some(key => {
2368
2391
  const item = this.hashmap[key];
2369
- return item.isLearningPathway && item.courseCategory === 'Learning Pathway';
2392
+ // Check using OR condition - either flag indicates Learning Pathway
2393
+ return item.isLearningPathway === true || item.courseCategory === 'Learning Pathway';
2370
2394
  });
2371
2395
  if (hasLearningPathway) {
2372
- console.log('🔄 Triggering milestone lock recomputation after progress update');
2396
+ console.log('🔄 [TRIGGER] Triggering milestone lock recomputation after progress update');
2373
2397
  // Assume enrolled since progress was just updated
2374
2398
  this.computeMilestoneLockingStatus(true);
2375
2399
  }
2400
+ else {
2401
+ console.log('âš ī¸ [TRIGGER] No Learning Pathway found in hashmap - skipping milestone lock update');
2402
+ }
2376
2403
  }
2377
2404
  /**
2378
2405
  * Check if pre-assessment (preliminary assessment) is completed
@@ -2380,6 +2407,7 @@ class AppTocService {
2380
2407
  */
2381
2408
  checkPreAssessmentCompletion() {
2382
2409
  console.log('🔍 [PRE-ASSESSMENT] Starting pre-assessment completion check');
2410
+ console.log('🔍 [PRE-ASSESSMENT] Hashmap keys:', Object.keys(this.hashmap).length);
2383
2411
  // Find the Learning Pathway root - check multiple conditions
2384
2412
  let learningPathwayId = null;
2385
2413
  for (const key of Object.keys(this.hashmap)) {
@@ -2397,12 +2425,21 @@ class AppTocService {
2397
2425
  console.log('âš ī¸ [PRE-ASSESSMENT] Learning Pathway root NOT FOUND - returning false to keep milestones locked');
2398
2426
  return false;
2399
2427
  }
2400
- // 1. Look for items explicitly marked as pre-assessment (isPreAssessment flag)
2401
- console.log('🔍 [PRE-ASSESSMENT] Step 1: Looking for items with isPreAssessment flag...');
2428
+ // Step 1: Look for items explicitly marked as pre-assessment (isPreAssessment flag)
2429
+ console.log('🔍 [PRE-ASSESSMENT] Step 1: Looking for items with isPreAssessment=true flag...');
2430
+ console.log('🔍 [PRE-ASSESSMENT] Dumping all hashmap items for debugging:');
2431
+ for (const key of Object.keys(this.hashmap)) {
2432
+ const item = this.hashmap[key];
2433
+ if (item.isPreAssessment || item.primaryCategory === 'Course Assessment' || item.primaryCategory === 'Standalone Assessment') {
2434
+ console.log(` 📄 ${key}: isPreAssessment=${item.isPreAssessment}, primaryCategory=${item.primaryCategory}, parent=${item.parent}, completionStatus=${item.completionStatus}, status=${item.status}, completionPercentage=${item.completionPercentage}`);
2435
+ }
2436
+ }
2437
+ let foundPreAssessmentFlag = false;
2402
2438
  for (const key of Object.keys(this.hashmap)) {
2403
2439
  const item = this.hashmap[key];
2404
2440
  if (item.isPreAssessment === true) {
2405
- console.log('🔍 [PRE-ASSESSMENT] Found pre-assessment item:', {
2441
+ foundPreAssessmentFlag = true;
2442
+ console.log('🔍 [PRE-ASSESSMENT] Found item with isPreAssessment=true:', {
2406
2443
  id: key,
2407
2444
  name: item.name,
2408
2445
  completionStatus: item.completionStatus,
@@ -2410,16 +2447,29 @@ class AppTocService {
2410
2447
  completionPercentage: item.completionPercentage,
2411
2448
  progress: item.progress
2412
2449
  });
2413
- const isCompleted = (item.completionStatus === 2 || item.status === 2 ||
2414
- (item.completionPercentage !== undefined && item.completionPercentage >= 100) ||
2415
- (item.progress !== undefined && item.progress >= 100));
2416
- console.log('🔍 [PRE-ASSESSMENT] Pre-assessment completion result:', isCompleted ? '✅ COMPLETED' : '❌ NOT COMPLETED');
2450
+ // STRICT CHECK: Only return true if completionStatus is EXACTLY 2 (not undefined, null, or 0)
2451
+ // completionPercentage check must be >= 100 AND be a number
2452
+ const completionStatus = Number(item.completionStatus);
2453
+ const status = Number(item.status);
2454
+ const completionPercentage = Number(item.completionPercentage);
2455
+ const progress = Number(item.progress);
2456
+ const isCompleted = (completionStatus === 2 || status === 2 ||
2457
+ (completionPercentage >= 100 && !isNaN(completionPercentage)) ||
2458
+ (progress >= 100 && !isNaN(progress)));
2459
+ console.log('🔍 [PRE-ASSESSMENT] Pre-assessment completion result:', isCompleted ? '✅ COMPLETED' : '❌ NOT COMPLETED', {
2460
+ completionStatusCheck: completionStatus === 2,
2461
+ statusCheck: status === 2,
2462
+ completionPercentageCheck: completionPercentage >= 100,
2463
+ progressCheck: progress >= 100
2464
+ });
2417
2465
  return isCompleted;
2418
2466
  }
2419
2467
  }
2420
- // 2. Find pre-assessment in hashmap - direct child of Learning Pathway that is NOT a milestone
2421
- // This is a fallback for cases where isPreAssessment flag is not set
2422
- console.log('🔍 [PRE-ASSESSMENT] Step 2: Looking for non-milestone direct children of Learning Pathway...');
2468
+ if (!foundPreAssessmentFlag) {
2469
+ console.log('âš ī¸ [PRE-ASSESSMENT] No item with isPreAssessment=true found in hashmap');
2470
+ }
2471
+ // Step 2: Fallback - Look for Course Assessment that is a direct child of Learning Pathway (not a milestone child)
2472
+ console.log('🔍 [PRE-ASSESSMENT] Step 2: Looking for Course Assessment direct child of Learning Pathway...');
2423
2473
  for (const key of Object.keys(this.hashmap)) {
2424
2474
  const item = this.hashmap[key];
2425
2475
  // Must be a direct child of the Learning Pathway
@@ -2428,7 +2478,10 @@ class AppTocService {
2428
2478
  // Skip milestones
2429
2479
  if (item.isMilestone || item.primaryCategory === 'Milestone' || item.courseCategory === 'Milestone')
2430
2480
  continue;
2431
- console.log('🔍 [PRE-ASSESSMENT] Found non-milestone child:', {
2481
+ // Must be a Course Assessment or Standalone Assessment
2482
+ if (item.primaryCategory !== 'Course Assessment' && item.primaryCategory !== 'Standalone Assessment')
2483
+ continue;
2484
+ console.log('🔍 [PRE-ASSESSMENT] Found Course Assessment child of Learning Pathway:', {
2432
2485
  id: key,
2433
2486
  name: item.name,
2434
2487
  primaryCategory: item.primaryCategory,
@@ -2436,14 +2489,24 @@ class AppTocService {
2436
2489
  status: item.status,
2437
2490
  completionPercentage: item.completionPercentage
2438
2491
  });
2439
- const isCompleted = (item.completionStatus === 2 || item.status === 2 ||
2440
- (item.completionPercentage !== undefined && item.completionPercentage >= 100) ||
2441
- (item.progress !== undefined && item.progress >= 100));
2442
- console.log('🔍 [PRE-ASSESSMENT] Non-milestone child completion result:', isCompleted ? '✅ COMPLETED' : '❌ NOT COMPLETED');
2492
+ // STRICT CHECK: Only return true if completionStatus is EXACTLY 2
2493
+ const completionStatus = Number(item.completionStatus);
2494
+ const status = Number(item.status);
2495
+ const completionPercentage = Number(item.completionPercentage);
2496
+ const progress = Number(item.progress);
2497
+ const isCompleted = (completionStatus === 2 || status === 2 ||
2498
+ (completionPercentage >= 100 && !isNaN(completionPercentage)) ||
2499
+ (progress >= 100 && !isNaN(progress)));
2500
+ console.log('🔍 [PRE-ASSESSMENT] Course Assessment completion result:', isCompleted ? '✅ COMPLETED' : '❌ NOT COMPLETED', {
2501
+ completionStatusCheck: completionStatus === 2,
2502
+ statusCheck: status === 2,
2503
+ completionPercentageCheck: completionPercentage >= 100,
2504
+ progressCheck: progress >= 100
2505
+ });
2443
2506
  return isCompleted;
2444
2507
  }
2445
- // 3. If we reach here, no pre-assessment found - enforce M1 locked
2446
- console.log('âš ī¸ [PRE-ASSESSMENT] No pre-assessment found - returning false to keep M1 locked');
2508
+ // Step 3: If no pre-assessment found at all, keep milestones LOCKED (fail-safe)
2509
+ console.log('âš ī¸ [PRE-ASSESSMENT] No pre-assessment found in hashmap - returning FALSE to keep milestones LOCKED');
2447
2510
  return false;
2448
2511
  }
2449
2512
  /**
@@ -6326,7 +6389,7 @@ i0.ÉĩÉĩngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
6326
6389
  }] });
6327
6390
 
6328
6391
  class AppTocContentCardV2Component {
6329
- constructor(events, dialog, renderer, certificateService, appTocSvc, contentLangSvc, resourceDownloadHelperSvc, configSvc, snackBar) {
6392
+ constructor(events, dialog, renderer, certificateService, appTocSvc, contentLangSvc, resourceDownloadHelperSvc, configSvc, snackBar, cdr) {
6330
6393
  this.events = events;
6331
6394
  this.dialog = dialog;
6332
6395
  this.renderer = renderer;
@@ -6336,6 +6399,7 @@ class AppTocContentCardV2Component {
6336
6399
  this.resourceDownloadHelperSvc = resourceDownloadHelperSvc;
6337
6400
  this.configSvc = configSvc;
6338
6401
  this.snackBar = snackBar;
6402
+ this.cdr = cdr;
6339
6403
  this.content = null;
6340
6404
  this.expandAll = false;
6341
6405
  this.forPreview = false;
@@ -6381,7 +6445,8 @@ class AppTocContentCardV2Component {
6381
6445
  this._cachedIsModule = false;
6382
6446
  this._cachedIsResource = false;
6383
6447
  this._cachedIsMilestone = false;
6384
- this._cachedIsMilestoneLocked = false;
6448
+ // IMPORTANT: Default to TRUE (locked) - milestones should be locked until explicitly unlocked
6449
+ this._cachedIsMilestoneLocked = true;
6385
6450
  this._cachedIsParentMilestoneLocked = false;
6386
6451
  this._cachedIsContentUnlocked = true;
6387
6452
  this._cachedCheckForCuratedProgram = false;
@@ -6402,10 +6467,20 @@ class AppTocContentCardV2Component {
6402
6467
  // Subscribe to hashmap updates to recompute cached properties when progress changes
6403
6468
  this.hashmapUpdatedSubscription = this.appTocSvc.hashmapUpdated$.subscribe((update) => {
6404
6469
  if (update && update.hashmap) {
6470
+ console.log('📡 [CONTENT CARD] Received hashmap update for:', this.content?.identifier, this.content?.name);
6405
6471
  // IMPORTANT: Update hierarchyMapData with the latest hashmap from the service
6406
6472
  // This ensures the component uses the updated data, not the stale @Input reference
6407
6473
  this.hierarchyMapData = update.hashmap;
6474
+ const prevLockState = this._cachedIsMilestoneLocked;
6408
6475
  this.computeAllCachedProperties();
6476
+ console.log('📡 [CONTENT CARD] Lock state change:', {
6477
+ id: this.content?.identifier,
6478
+ previousLockState: prevLockState,
6479
+ newLockState: this._cachedIsMilestoneLocked,
6480
+ isMilestone: this._cachedIsMilestone
6481
+ });
6482
+ // Force Angular change detection to update the view
6483
+ this.cdr.detectChanges();
6409
6484
  }
6410
6485
  });
6411
6486
  }
@@ -6531,20 +6606,22 @@ class AppTocContentCardV2Component {
6531
6606
  }
6532
6607
  // Check if hashmap has pre-computed locking status (preferred - computed by service)
6533
6608
  const hashData = this.hierarchyMapData && this.hierarchyMapData[this.content.identifier];
6534
- console.log(`computeIsMilestoneLocked for ${this.content.identifier} (${this.content.name}):`, {
6535
- hashData,
6609
+ console.log(`🔒 [MILESTONE LOCK CHECK] ${this.content.identifier} (${this.content.name}):`, {
6610
+ hasHashData: !!hashData,
6536
6611
  computedIsLocked: hashData?.computedIsLocked,
6612
+ hasComputedIsLocked: hashData?.computedIsLocked !== undefined,
6537
6613
  contentIsLocked: this.content.isLocked
6538
6614
  });
6615
+ // CRITICAL: Only use computedIsLocked from hashmap - this is the SINGLE SOURCE OF TRUTH
6616
+ // The service computes this value based on pre-assessment/milestone completion
6539
6617
  if (hashData && hashData.computedIsLocked !== undefined) {
6618
+ console.log(` ✅ Using hashmap computedIsLocked: ${hashData.computedIsLocked}`);
6540
6619
  return hashData.computedIsLocked;
6541
6620
  }
6542
- // If milestone has isLocked flag explicitly set to false, it's unlocked
6543
- if (this.content.isLocked === false) {
6544
- return false;
6545
- }
6546
- // Fallback: All milestones are locked by default until computed otherwise
6547
- // This ensures proper locking until the hashmap is updated with progress
6621
+ // IMPORTANT: If no computedIsLocked value exists, default to LOCKED
6622
+ // This ensures milestones stay locked until the service explicitly unlocks them
6623
+ // DO NOT use this.content.isLocked as it may be false by default from API
6624
+ console.log(` âš ī¸ No computedIsLocked in hashmap - defaulting to LOCKED`);
6548
6625
  return true;
6549
6626
  }
6550
6627
  computeIsParentMilestoneLocked() {
@@ -6557,7 +6634,7 @@ class AppTocContentCardV2Component {
6557
6634
  if (!this.content || !this.hierarchyMapData) {
6558
6635
  return false;
6559
6636
  }
6560
- // Check hashmap for pre-computed value
6637
+ // Check hashmap for pre-computed value (set by computeMilestoneLockingStatus)
6561
6638
  const hashData = this.hierarchyMapData[this.content.identifier];
6562
6639
  if (hashData && hashData.isParentMilestoneLocked !== undefined) {
6563
6640
  return hashData.isParentMilestoneLocked;
@@ -6569,8 +6646,10 @@ class AppTocContentCardV2Component {
6569
6646
  while (currentParentId && depth < maxDepth) {
6570
6647
  const parentData = this.hierarchyMapData[currentParentId];
6571
6648
  if (parentData) {
6649
+ // CRITICAL: Only check computedIsLocked (computed by service), NOT isLocked (API default)
6650
+ // isLocked from API may be false even when milestone should be locked
6572
6651
  if ((parentData.isMilestone || parentData.primaryCategory === 'Milestone' || parentData.courseCategory === 'Milestone') &&
6573
- (parentData.computedIsLocked || parentData.isLocked)) {
6652
+ parentData.computedIsLocked === true) {
6574
6653
  return true;
6575
6654
  }
6576
6655
  currentParentId = parentData.parent;
@@ -7454,7 +7533,7 @@ class AppTocContentCardV2Component {
7454
7533
  return false;
7455
7534
  return element.scrollHeight > element.clientHeight;
7456
7535
  }
7457
- static { this.Éĩfac = i0.ÉĩÉĩngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppTocContentCardV2Component, deps: [{ token: i2$1.EventService }, { token: i1$3.MatLegacyDialog }, { token: i0.Renderer2 }, { token: CertificateService }, { token: AppTocService }, { token: i5.ContentLanguageService }, { token: ResourceDownloadHelperService }, { token: i2$1.ConfigurationsService }, { token: i7.MatLegacySnackBar }], target: i0.ÉĩÉĩFactoryTarget.Component }); }
7536
+ static { this.Éĩfac = i0.ÉĩÉĩngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: AppTocContentCardV2Component, deps: [{ token: i2$1.EventService }, { token: i1$3.MatLegacyDialog }, { token: i0.Renderer2 }, { token: CertificateService }, { token: AppTocService }, { token: i5.ContentLanguageService }, { token: ResourceDownloadHelperService }, { token: i2$1.ConfigurationsService }, { token: i7.MatLegacySnackBar }, { token: i0.ChangeDetectorRef }], target: i0.ÉĩÉĩFactoryTarget.Component }); }
7458
7537
  static { this.Éĩcmp = i0.ÉĩÉĩngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: AppTocContentCardV2Component, selector: "ws-widget-app-toc-content-card-v2", inputs: { content: "content", expandAll: "expandAll", rootId: "rootId", rootContentType: "rootContentType", forPreview: "forPreview", batchId: "batchId", componentName: "componentName", index: "index", pathSet: "pathSet", expandActive: "expandActive", hierarchyMapData: "hierarchyMapData", batchData: "batchData", isPreAssessment: "isPreAssessment", baseContentReadData: "baseContentReadData", mlCourse: "mlCourse", parentMilestoneLocked: "parentMilestoneLocked" }, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"content && !isPreAssessment\">\n <ng-container *ngIf=\"isCollection && !isModule\">\n <ng-container [ngTemplateOutlet]=\"collectionTemplate\">\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"isCollection && isModule\">\n <ng-container *ngIf=\"content?.moduleResourseCount\">\n <ng-container [ngTemplateOutlet]=\"collectionTemplate\">\n </ng-container>\n </ng-container>\n </ng-container>\n\n <div *ngIf=\"isResource\" class=\"resource-container\"\n [ngClass]=\"pathSet?.has(content?.identifier) && isEnrolled ? 'content-active-resource': 'content-not-active-resource'\">\n <div class=\"resource flex sm:flex-row flex-start width-expand w-100 sm:pr-4 sm:w-auto\"\n [ngClass]=\"{'activeResource': pathSet?.has(content?.identifier) && isEnrolled}\">\n <!-- Lock message for curated programs only (shown above content) -->\n <ng-container *ngIf=\"content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT && checkForCuratedProgram &&\n !isContentUnlocked\">\n <div class=\"content-locking flex w-full flex-middle mb-2 gap-3\">\n <mat-icon class=\"lock-icon\">lock</mat-icon>\n <span class=\"lock-message mat-body-2\">\n The content is locked. Complete program or all courses to view this module\n </span>\n </div>\n </ng-container>\n <ng-container *ngIf=\"content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT && checkForCuratedProgram &&\n isContentUnlocked\">\n <div class=\"content-locking flex w-full flex-middle mb-2 gap-3\">\n <mat-icon class=\"unlock-icon\">lock_open_right</mat-icon>\n <span class=\"unlock-message mat-body-2\">\n This content is unlocked.\n </span>\n </div>\n </ng-container>\n <div class=\"flex flex-wrap items-start justify-start sm:justify-end\">\n <!-- <button *ngIf=\"!forPreview && content?.artifactUrl && !isXSmall && isAllowed && isEnabled\" type=\"button\"\n mat-icon-button class=\"\" [matMenuTriggerFor]=\"buttonMenu\">\n <mat-icon>more_vertical</mat-icon>\n </button> -->\n <ng-container *ngIf=\"isEnrolled && !isMilestoneLocked && !isParentMilestoneLocked\">\n <ng-container\n *ngIf=\"!forPreview && content?.identifier && getCompletionPercentage(content?.identifier) ; else elseBlock\">\n\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) == 2\">\n <div class=\"completed\">\n <div>\n <mat-icon class=\"completed-icon\" [color]=\"blue\">check_circle</mat-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) < 2\">\n <circle-progress class=\"flex items-center progress\"\n [percent]=\"getCompletionPercentage(content?.identifier)\" [radius]=\"10\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [space]=\"-2\"\n [outerStrokeColor]=\"progressColor2()\" [innerStrokeColor]=\"'rgba(0, 0, 0, 0.16)'\"\n [animation]=\"true\" [animationDuration]=\"250\" [showTitle]=\"false\" [showUnits]=\"false\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\"\n [backgroundOpacity]=\"0\" [backgroundGradient]=\"false\" [backgroundStrokeWidth]=\"3\"\n matTooltip=\"In progress\" [showZeroOuterStroke]=false [backgroundPadding]=\"-9\"\n [startFromZero]=\"false\" [backgroundPadding]=\"0\" [imageHeight]=\"22\" [imageWidth]=\"22\"\n [showBackground]=\"false\" [outerStrokeLinecap]=\"'butt'\">\n </circle-progress>\n <!-- <ws-widget-content-progress *ngIf=\"content?.identifier\" [forPreview]=\"forPreview\"\n [contentId]=\"content?.identifier\" class=\"progress-bar-thin\" [progress]=\"content?.completionPercentage\"\n [progressType]=\"'percentage'\">\n </ws-widget-content-progress> -->\n </ng-container>\n </ng-container>\n <ng-template #elseBlock>\n <circle-progress class=\"flex items-center progress\" [percent]=\"0\" [radius]=\"11\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [outerStrokeColor]=\"'#808080'\"\n [innerStrokeColor]=\"'#808080'\" [animation]=\"true\" [space]=\"-2\" [showUnits]=\"false\"\n [animationDuration]=\"250\" [showTitle]=\"false\" [backgroundPadding]=\"0\"\n [backgroundPadding]=\"-9\" [outerStrokeLinecap]=\"'butt'\" matTooltip=\"Not started\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\" [imageHeight]=\"22\"\n [imageWidth]=\"22\" [showBackground]=\"false\"></circle-progress>\n <!-- <p>no data</p> -->\n </ng-template>\n </ng-container>\n </div>\n <!-- deactivated as per NIC CEO requirement to access course wthout login -->\n <!-- For locked assessments: show content but make it non-clickable -->\n <div class=\"width-expand\" *ngIf=\"isMilestoneAssessmentLocked && isEnrolled; else clickableContent\"\n [ngClass]=\"{'ml-3': isEnrolled}\">\n <div class=\"text-truncate opacity-60\">\n <div class=\"flex flex-col sm:flex-row flex-wrap\">\n <div class=\"flex items-center gap-2 w-full\">\n <mat-icon class=\"text-gray-500\">lock</mat-icon>\n <p class=\"margin-remove text-truncate mat-body-2 flex-auto font-bold nodtranslate text-gray-600\"\n [matTooltip]=\"(content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT) ? ' - ' + content?.contextCategory : '')).length > 50 ? (content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT) ? ' - ' + content?.contextCategory : '')) : ''\"\n matTooltipPosition=\"above\">\n {{ (content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT )? ' - ' + content?.contextCategory : '')) | truncate:50 }}\n </p>\n </div>\n <span class=\"content-type optional-span nodtranslate\" *ngIf=\"content?.optionalReading\">{{\n 'playerbrief.optional' | translate | titlecase}} </span>\n </div>\n <!-- for default grey icons -->\n <ng-container *ngIf=\"!pathSet?.has(content?.identifier) || !isEnrolled\">\n <div class=\"resicons ws-mat-black60-text\">\n <img src=\"/assets/icons/content/grey/video.svg\" alt=\"Video\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'video/mp4' || content?.mimeType === 'video/x-youtube' ||\n content?.mimeType ==='application/x-mpegURL'\">\n <img src=\"/assets/icons/content/grey/audio.svg\" alt=\"Audio\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'audio/mpeg'\">\n <img src=\"/assets/icons/content/grey/pdf.svg\" alt=\"PDF\" class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/pdf'\">\n <img src=\"/assets/icons/content/grey/link.svg\" alt=\"InteractiveContent\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/vnd.ekstep.html-archive' || content?.mimeType === 'text/x-url'\">\n <img src=\"/assets/icons/content/grey/assessment.svg\" alt=\"Assessment\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/json' || content?.mimeType === 'application/quiz' || content?.mimeType === 'application/vnd.sunbird.questionset'\">\n <img src=\"/assets/icons/content/grey/image.svg\" alt=\"Image\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'image/png' || content?.mimeType === 'image/jpeg'\">\n <img src=\"/assets/icons/content/grey/content_copy.svg\" class=\"contenticon\" alt=\"Course\"\n *ngIf=\"content.mimeType === 'application/vnd.ekstep.content-collection' || content?.mimeType === 'application/survey'\">\n <img src=\"/assets/icons/content/grey/module.svg\" class=\"float-left margin-right-xs\"\n alt=\"offline sessions\" *ngIf=\"content.mimeType === 'application/offline'\">\n\n <ng-container *ngIf=\"content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ content?.maxQuestions\n }} {{ 'playerbrief.questions' | translate | titlecase}}</span>\n </ng-container>\n <ng-container *ngIf=\"!(content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE)\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ (content?.duration||\n hierarchyMapData[content?.identifier]?.expectedDuration || 0)|\n pipeDurationTransform:\n 'hms'\n }}</span>\n </ng-container>\n </div>\n </ng-container>\n </div>\n \n <!-- Lock message displayed BELOW assessment details when locked -->\n <div class=\"content-locking flex w-full flex-middle mt-2 gap-2 px-2 py-1 bg-orange-50 border-l-4 border-orange-400\">\n <mat-icon class=\"lock-icon text-orange-600\" style=\"font-size: 18px; width: 18px; height: 18px;\">lock</mat-icon>\n <span class=\"lock-message mat-body-2 text-orange-800\" style=\"font-size: 13px;\">\n This content is locked. Complete all mandatory items to unlock the assessment.\n </span>\n </div>\n </div>\n \n <!-- Clickable content template (when NOT locked) -->\n <ng-template #clickableContent>\n <a class=\"width-expand\"\n [class.disabled]=\"(forPreview || !isEnabled || !isEnrolled || !isBatchInProgess || !isContentUnlocked || isParentMilestoneLocked) ? true : null\"\n [ngClass]=\"{'ml-3': isEnrolled}\"\n [routerLink]=\"(isAllowed && !forPreview && isEnabled && !isParentMilestoneLocked) ? resourceLink.url : null\"\n [queryParams]=\"(isAllowed && !forPreview && isEnabled && !isParentMilestoneLocked) ? resourceLink.queryParams : null\"\n [matTooltip]=\"isParentMilestoneLocked ? 'This content is locked. Complete previous milestone to view this content.' : ''\"\n matTooltipPosition=\"above\">\n <div [ngClass]=\"{'resource-active': pathSet?.has(content?.identifier) && isEnrolled}\"></div>\n <div class=\"text-truncate \" [ngClass]=\"{'cursor-pointer': !isEnabled && isEnrolled}\"\n (click)=\"content.viewChildren = !content.viewChildren; raiseTelemetry(); changeResource()\">\n <div class=\"flex flex-col sm:flex-row flex-wrap\">\n <p class=\"margin-remove text-truncate mat-body-2 flex-auto font-bold nodtranslate\"\n [ngClass]=\"{'text-active': pathSet?.has(content?.identifier) && isEnrolled}\"\n [matTooltip]=\"(content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT) ? ' - ' + content?.contextCategory : '')).length > 50 ? (content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT) ? ' - ' + content?.contextCategory : '')) : ''\"\n matTooltipPosition=\"above\">\n {{ (content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT)? ' - ' + content?.contextCategory : '')) | truncate:50 }}\n </p>\n <span class=\"content-type optional-span nodtranslate\" *ngIf=\"content?.optionalReading\">{{\n 'playerbrief.optional' | translate | titlecase}} </span>\n </div>\n <!-- for default grey icons -->\n <ng-container *ngIf=\"!pathSet?.has(content?.identifier) || !isEnrolled\">\n <div class=\"resicons ws-mat-black60-text\">\n <img src=\"/assets/icons/content/grey/video.svg\" alt=\"Video\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'video/mp4' || content?.mimeType === 'video/x-youtube' ||\n content?.mimeType ==='application/x-mpegURL'\">\n <img src=\"/assets/icons/content/grey/audio.svg\" alt=\"Audio\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'audio/mpeg'\">\n <img src=\"/assets/icons/content/grey/pdf.svg\" alt=\"PDF\" class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/pdf'\">\n <img src=\"/assets/icons/content/grey/link.svg\" alt=\"InteractiveContent\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/vnd.ekstep.html-archive' || content?.mimeType === 'text/x-url'\">\n <img src=\"/assets/icons/content/grey/assessment.svg\" alt=\"Assessment\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/json' || content?.mimeType === 'application/quiz' || content?.mimeType === 'application/vnd.sunbird.questionset'\">\n <img src=\"/assets/icons/content/grey/image.svg\" alt=\"Image\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'image/png' || content?.mimeType === 'image/jpeg'\">\n <img src=\"/assets/icons/content/grey/content_copy.svg\" class=\"contenticon\" alt=\"Course\"\n *ngIf=\"content.mimeType === 'application/vnd.ekstep.content-collection' || content?.mimeType === 'application/survey'\">\n <img src=\"/assets/icons/content/grey/module.svg\" class=\"float-left margin-right-xs\"\n alt=\"offline sessions\" *ngIf=\"content.mimeType === 'application/offline'\">\n\n <ng-container *ngIf=\"content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ content?.maxQuestions\n }} {{ 'playerbrief.questions' | translate | titlecase}}</span>\n </ng-container>\n <ng-container *ngIf=\"!(content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE)\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ (content?.duration||\n hierarchyMapData[content?.identifier]?.expectedDuration || 0)|\n pipeDurationTransform:\n 'hms'\n }}</span>\n </ng-container>\n </div>\n </ng-container>\n\n <!-- for white icons when content highlighted -->\n <ng-container *ngIf=\"pathSet?.has(content?.identifier) && isEnrolled\">\n <div class=\"resicons ws-mat-white-text\">\n <img src=\"/assets/icons/content/white/video.svg\" alt=\"Video\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'video/mp4' || content?.mimeType === 'video/x-youtube' ||\n content?.mimeType ==='application/x-mpegURL'\">\n <img src=\"/assets/icons/content/white/audio.svg\" alt=\"Audio\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'audio/mpeg'\">\n <img src=\"/assets/icons/content/white/pdf.svg\" alt=\"PDF\" class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/pdf'\">\n <img src=\"/assets/icons/content/white/link.svg\" alt=\"InteractiveContent\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/vnd.ekstep.html-archive' || content?.mimeType === 'text/x-url'\">\n <img src=\"/assets/icons/content/white/assessment.svg\" alt=\"Assessment\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/json' || content?.mimeType === 'application/quiz' || content?.mimeType === 'application/vnd.sunbird.questionset'\">\n <img src=\"/assets/icons/content/grey/image.svg\" alt=\"Image\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'image/png' || content?.mimeType === 'image/jpeg'\">\n <img src=\"/assets/icons/content/white/content_copy.svg\" class=\"contenticon\" alt=\"Course\"\n *ngIf=\"content.mimeType === 'application/vnd.ekstep.content-collection' || content?.mimeType === 'application/survey'\">\n <img src=\"/assets/icons/content/white/module.svg\" class=\"float-left margin-right-xs\"\n alt=\"offline sessions\" *ngIf=\"content.mimeType === 'application/offline'\">\n <ng-container *ngIf=\"content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ content?.maxQuestions\n }} {{ 'playerbrief.questions' | translate | titlecase}}</span>\n </ng-container>\n <ng-container *ngIf=\"!(content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE)\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ (content?.duration||\n hierarchyMapData[content?.identifier]?.expectedDuration || 0)|\n pipeDurationTransform:\n 'hms'\n }}</span>\n </ng-container>\n </div>\n </ng-container>\n\n <!-- Download button for pdf resources -->\n <ng-container *ngIf=\"shouldShowDownloadButton(content)\">\n <div class=\"download-btn mat-body-2 mt-2 sm:mt-1\" (click)=\"downloadContent(content, $event)\"\n [ngClass]=\"{'active': pathSet?.has(content?.identifier)}\">\n <a class=\"download-link flex items-center\">\n <span class=\"\">Download</span>\n </a>\n </div>\n </ng-container>\n </div>\n </a>\n </ng-template>\n </div>\n </div>\n</ng-container>\n\n<mat-menu #buttonMenu=\"matMenu\">\n <a mat-menu-item [routerLink]=\"'../' + content?.identifier + '/overview'\" [queryParams]=\"contextPath\"\n class=\"flex flex-middle\">\n <mat-icon>toc</mat-icon>\n <h3 class=\"margin-remove nodtranslate\">\n View Details\n </h3>\n </a>\n</mat-menu>\n\n<ng-template #collectionTemplate>\n <ng-container *ngIf=\"isCollection\">\n <div class=\"collection-wrapper p-4 flex flex-col position-relative\" [ngClass]=\"{'open': check(content),\n 'close': !content.viewChildren,\n 'course':!isModule, 'module': isModule,\n 'content-active': pathSet?.has(content.identifier) && isEnrolled}\">\n <div class=\"card-collection w-auto sm:w-100 padding-right-xl\">\n <!-- <img class=\"card-thumbnail ws-mat-primary-lite-background\" [src]=\"content?.appIcon\" alt=\"Thumbnail\"\n (click)=\"content.viewChildren = !content.viewChildren\" [wsUtilsDefaultThumbnail]=\"defaultThumbnail\" /> -->\n <div class=\"flex flex-col flex-wrap flex-between width-expand pr-0 w-100 \">\n <div class=\"text-truncate\" [ngClass]=\"{'cursor-pointer': !isEnabled}\"\n (click)=\"content.viewChildren = !content.viewChildren\">\n <div class=\"flex items-center justify-center mb-1 sm:flex-row\">\n <ng-container\n *ngIf=\"isModule && isEnrolled && !isMilestoneLocked && !isParentMilestoneLocked\">\n <ng-container\n *ngIf=\"!forPreview && content?.identifier && getCompletionPercentage(content?.identifier) ; else elseBlock\">\n\n <ng-container *ngIf=\"getCompletionStatus(content.identifier) == 2\">\n <div class=\"completed mr-2\">\n <div>\n <mat-icon class=\"completed-icon\" [color]=\"blue\">check_circle</mat-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) < 2\">\n <circle-progress class=\"flex items-center progress mr-1\"\n [percent]=\"getCompletionPercentage(content?.identifier)\" [radius]=\"10\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [space]=\"-2\"\n [outerStrokeColor]=\"progressColor2()\"\n [innerStrokeColor]=\"'rgba(0, 0, 0, 0.16)'\" [animation]=\"true\"\n [animationDuration]=\"250\" [showTitle]=\"false\" [showUnits]=\"false\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\"\n [backgroundOpacity]=\"0\" [backgroundGradient]=\"false\"\n [backgroundStrokeWidth]=\"3\" matTooltip=\"In progress\"\n [showZeroOuterStroke]=false [backgroundPadding]=\"-7\" [startFromZero]=\"false\"\n [backgroundPadding]=\"0\" [imageHeight]=\"18\" [imageWidth]=\"18\"\n [showBackground]=\"false\" [outerStrokeLinecap]=\"'butt'\">\n </circle-progress>\n </ng-container>\n </ng-container>\n <ng-template #elseBlock>\n <circle-progress class=\"flex items-center progress mr-1\" [percent]=\"0\" [radius]=\"11\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [outerStrokeColor]=\"'#808080'\"\n [innerStrokeColor]=\"'#808080'\" [animation]=\"true\" [space]=\"-2\"\n [showUnits]=\"false\" [animationDuration]=\"250\" [showTitle]=\"false\"\n [backgroundPadding]=\"0\" [backgroundPadding]=\"-9\" [outerStrokeLinecap]=\"'butt'\"\n matTooltip=\"Not started\" [showSubtitle]=\"false\" [showInnerStroke]=\"true\"\n [clockwise]=\"true\" [imageHeight]=\"22\" [imageWidth]=\"22\"\n [showBackground]=\"false\"></circle-progress>\n </ng-template>\n </ng-container>\n <div\n [ngClass]=\"{'collection-active-class': pathSet?.has(content?.identifier) && isEnrolled}\">\n </div>\n <img *ngIf=\"isMilestoneLocked\" src=\"assets/icons/hubs/lock.svg\" alt=\"Locked\"\n class=\"lock-icon mr-2 margin-bottom-xxs\">\n <div class=\"flex-auto flex flex-col\" style=\"min-width: 0;\">\n <p class=\"margin-remove text-truncate mat-subheading-1 font-bold nodtranslate\"\n [ngClass]=\"{'text-active': pathSet?.has(content.identifier) && isEnrolled}\"\n [matTooltip]=\"content?.name?.length > 50 ? content?.name : ''\"\n matTooltipPosition=\"above\">\n <span>{{isMilestone ? index -1 : index}}. </span>{{ content?.name | truncate:50 }}\n </p>\n <div class=\"mt-1\" *ngIf=\"isMilestone && isMilestoneLocked\">\n <span class=\"locked-text\">Locked</span>\n </div>\n <div class=\"mt-1\" *ngIf=\"content?.isMandatory\">\n <span class=\"mandatory-text mat-caption\">Mandatory</span>\n </div>\n </div>\n \n <div class=\"type-container resource mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Resource'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Resource</span>\n </div>\n <div class=\"type-container module mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Collection'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Module</span>\n </div>\n <div class=\"type-container course mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Course'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Course</span>\n </div>\n </div>\n <!-- Milestone Badge -->\n <div *ngIf=\"isMilestone\" class=\"milestone-badge mt-2 mb-2\">\n <span class=\"milestone-badge-text nodtranslate\">Milestone {{index - 1}}</span>\n </div>\n <!-- Milestone Description (2 lines with ellipsis) -->\n <p #milestoneDescRef *ngIf=\"isMilestone && content?.description\" class=\"milestone-description mt-2 nodtranslate\"\n [matTooltip]=\"isMultiLineTruncated(milestoneDescRef) ? content?.description : ''\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"multiline-tooltip\">\n {{ content?.description }}\n </p>\n <div class=\"flex flex-row gap-3 items-center content-key-values mt-2\">\n <mat-icon *ngIf=\"!isModule\" alt=\"course\"\n class=\"time-icon icon-color\">video_library</mat-icon>\n <img *ngIf=\"isModule\" alt=\"Module\" class=\"time-icon\"\n src=\"/assets/icons/content/grey/module.svg\">\n <div class=\"text-xs nodtranslate\">{{ (hierarchyMapData[content?.identifier]?.duration ||\n 120)|\n pipeDurationTransform: 'hms' }}</div>\n\n <ng-container *ngIf=\"content?.moduleCount\">\n <div class=\"flex items-center\">\n <span class=\"period\"></span>\n </div>\n <div class=\"text-xs nodtranslate\">{{content?.moduleCount}} {{content?.moduleCount > 1?\n 'modules' :\n 'module'}}</div>\n </ng-container>\n <ng-container *ngIf=\"content?.leafNodesCount\">\n <div class=\"flex items-center\">\n <span class=\"period\"></span>\n </div>\n <div class=\"text-xs nodtranslate\">{{content?.leafNodesCount}} {{content?.leafNodesCount\n >1 ? 'items':\n 'item'}}</div>\n </ng-container>\n </div>\n <!-- Milestone Completion Progress -->\n <div *ngIf=\"isMilestone && isEnrolled && !isMilestoneLocked\" class=\"milestone-progress mt-2 flex flex-col gap-2\">\n <div class=\"flex items-center justify-start gap-4 w-100\">\n <span class=\"milestone-progress-text nodtranslate\">{{getMilestoneCompletedCount()}} of {{content?.leafNodesCount || 0}} completed</span>\n <!-- View Achievement Button for completed milestones - Always visible when completed -->\n <ng-container *ngIf=\"getCompletionPercentage(content?.identifier) >= 100 || getCompletionStatus(content?.identifier) === 2\">\n <button type=\"button\" class=\"view-achievement-btn ml-4\" [disabled]=\"achievementLoading\"\n (click)=\"viewMilestoneAchievement($event)\">\n <span *ngIf=\"!achievementLoading\">View Achievement</span>\n <mat-spinner *ngIf=\"achievementLoading\" [diameter]=\"16\" [strokeWidth]=\"2\" color=\"primary\" class=\"inline-spinner\"></mat-spinner>\n </button>\n </ng-container>\n </div>\n </div>\n <!-- Unlock Criteria Message for Locked Milestones -->\n <div *ngIf=\"isMilestone && isEnrolled && isMilestoneLocked\" class=\"milestone-locked-message mt-2\">\n <span class=\"locked-criteria-text mat-caption\">\n {{ getMilestoneUnlockMessage() }}\n </span>\n </div>\n \n </div>\n <!-- For course progress to be shown -->\n <ng-container *ngIf=\"isEnrolled && !isMilestoneLocked && !isParentMilestoneLocked\">\n <ng-container\n *ngIf=\"!forPreview && content?.identifier && getCompletionPercentage(content?.identifier) && content.primaryCategory === 'Course'\">\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) == 2\">\n <div class=\"flex flex-1\">\n <div class=\"mt-2 mr-4 flex flex-1 flex-col progress-container\">\n <div class=\"flex flex-row justify-end w-full \">\n <span class=\"mat-body-2 nodtranslate \">\n {{getCompletionPercentage(content?.identifier)}}%</span>\n </div>\n\n <ws-widget-content-progress [contentId]=\"content?.progress\"\n [progress]=\"getCompletionPercentage(content?.identifier)\"\n [progressType]=\"'percentage'\" [customClassName]=\"'viewer-progress'\">\n </ws-widget-content-progress>\n </div>\n <ng-container *ngIf=\"content?.issuedCertificatesId\">\n <a class=\"ml-5 certificate-btn\"\n [ngClass]=\"{'disable-btn': downloadCertificateLoading || content?.issuedCertificatesId}\"\n (click)=\"!downloadCertificateLoading && downloadCertificate(content?.issuedCertificatesId);$event.stopPropagation()\">\n <!-- <img src=\"fusion-assets/images/certificate-ico.svg\" width=\"24\" height=\"24\"> -->\n <span class=\"nodtranslate\">Certificate</span>\n <mat-icon *ngIf=\"!downloadCertificateLoading\"\n class=\"ml-2\">arrow_downward</mat-icon>\n <div class=\"center flex flex-middle certificate-loader\"\n *ngIf=\"downloadCertificateLoading\">\n <mat-spinner strokeWidth=\"2\" stroke=\"'white'\" class=\"white-spinner\"\n [diameter]=\"16\"></mat-spinner>\n </div>\n </a>\n </ng-container>\n </div>\n <!-- <circle-progress class=\"flex items-center progress\" [percent]=\"100\" [radius]=\"12\"\n [outerStrokeWidth]=\"3\" [innerStrokeWidth]=\"3\" [space]=\"-3\"\n [outerStrokeColor]=\"progressColor()\" [innerStrokeColor]=\"'rgba(0,0,0,.16)'\"\n [animation]=\"true\" [animationDuration]=\"300\" [showTitle]=\"false\" [showUnits]=\"false\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\"\n [backgroundOpacity]=\"0\" [backgroundGradient]=\"false\" [backgroundStrokeWidth]=\"3\"\n [showZeroOuterStroke]=false [backgroundPadding]=\"-9\" [startFromZero]=\"false\"\n [backgroundPadding]=\"0\" [imageHeight]=\"24\" [imageWidth]=\"24\" [showBackground]=\"false\"\n [outerStrokeLinecap]=\"'butt'\">\n </circle-progress> -->\n </ng-container>\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) < 2\">\n <div class=\"flex flex-1\">\n <div class=\"mt-2 mr-4 flex flex-1 flex-col progress-container\">\n <div class=\"flex flex-row justify-end w-full ws-mat-black-text\">\n <span class=\"mat-body-2 ws-mat-black-text nodtranslate\">\n {{getCompletionPercentage(content?.identifier)}}%</span>\n </div>\n\n <ws-widget-content-progress [contentId]=\"content?.progress\"\n [progress]=\"getCompletionPercentage(content?.identifier)\"\n [progressType]=\"'percentage'\" [customClassName]=\"'viewer-progress'\">\n </ws-widget-content-progress>\n </div>\n <ng-container *ngIf=\"content?.issuedCertificatesId\">\n <a class=\"ml-5 certificate-btn\"\n [ngClass]=\"{'disable-btn': downloadCertificateLoading || content?.issuedCertificatesId}\"\n (click)=\"!downloadCertificateLoading && downloadCertificate(content?.issuedCertificatesId);$event.stopPropagation()\">\n <!-- <img src=\"fusion-assets/images/certificate-ico.svg\" width=\"24\" height=\"24\"> -->\n <span class=\"nodtranslate\">Certificate</span>\n <mat-icon *ngIf=\"!downloadCertificateLoading\"\n class=\"ml-2\">arrow_downward</mat-icon>\n <div class=\"center flex flex-middle certificate-loader\"\n *ngIf=\"downloadCertificateLoading\">\n <mat-spinner strokeWidth=\"2\" stroke=\"'white'\" class=\"white-spinner\"\n [diameter]=\"16\"></mat-spinner>\n </div>\n </a>\n </ng-container>\n </div>\n </ng-container>\n </ng-container>\n </ng-container>\n\n <div class=\"see-all-container\">\n <a href=\"javascript:void(0)\" role=\"button\"\n (click)=\"content.viewChildren = !content.viewChildren; expandActive = false\"\n class=\"see-all-btn tab custom-chevron customicon\" mat-button>\n <mat-icon *ngIf=\"!content.viewChildren && !isModule\">keyboard_arrow_down</mat-icon>\n <mat-icon *ngIf=\"content.viewChildren && !isModule\">keyboard_arrow_up</mat-icon>\n <mat-icon *ngIf=\"!content.viewChildren && isModule\">add</mat-icon>\n <mat-icon *ngIf=\"content.viewChildren && isModule\">remove</mat-icon>\n </a>\n </div>\n </div>\n </div>\n </div>\n <div class=\"child-wrapper \" *ngIf=\"content.viewChildren\" [ngClass]=\"{'open': content.viewChildren,\n 'close': !content.viewChildren,\n 'course':!isModule,\n 'module': isModule}\" [@panelInOut]>\n <div class=\"children-container\" [ngClass]=\"{'module': isModule, '': !isModule}\">\n <ws-widget-app-toc-content-card-v2 [forPreview]=\"forPreview\" [componentName]=\"componentName\"\n [content]=\"child\" [expandAll]=\"expandAll\" [rootId]=\"rootId\" [batchId]=\"batchId\"\n [rootContentType]=\"rootContentType\" [index]=\"j+1\" [baseContentReadData]=\"baseContentReadData\"\n [pathSet]=\"pathSet\" [hierarchyMapData]=\"hierarchyMapData\" [batchData]=\"batchData\"\n [mlCourse]=\"mlCourse\" [parentMilestoneLocked]=\"isMilestoneLocked || isParentMilestoneLocked\"\n *ngFor=\"let child of content?.children; trackBy: contentTrackBy; let j= index;let isFirst = first\"\n [ngClass]=\"{'moduleCard': checkIsModule(child), 'resourceCard': !checkIsModule(child), 'first': isFirst}\">\n </ws-widget-app-toc-content-card-v2>\n </div>\n </div>\n </ng-container>\n</ng-template>\n\n\n<ng-container *ngIf=\"isPreAssessment\">\n <div class=\"collection-wrapper p-4 flex flex-col position-relative\" [ngClass]=\"{'open': check(content),\n 'course':!isModule, 'module': isModule,\n 'content-active': pathSet?.has(content.identifier)}\">\n <div class=\"card-collection w-auto sm:w-100 padding-right-xl\">\n <!-- <img class=\"card-thumbnail ws-mat-primary-lite-background\" [src]=\"content?.appIcon\" alt=\"Thumbnail\"\n (click)=\"content.viewChildren = !content.viewChildren\" [wsUtilsDefaultThumbnail]=\"defaultThumbnail\" /> -->\n <div class=\"flex flex-col flex-wrap flex-between width-expand pr-0 w-100 \">\n\n <div class=\"text-truncate\" [ngClass]=\"{'cursor-pointer': !isEnabled}\"\n (click)=\"content.viewChildren = !content.viewChildren\">\n <div class=\"flex sm:flex-row flex-wrap\">\n <ng-container>\n <ng-container\n *ngIf=\"!forPreview && content?.identifier && getCompletionPercentage(content?.identifier) ; else elseBlock\">\n\n <ng-container *ngIf=\"getCompletionStatus(content.identifier) == 2\">\n <div class=\"completed mr-2\">\n <div>\n <mat-icon class=\"completed-icon\" [color]=\"blue\">check_circle</mat-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) < 2\">\n\n <circle-progress class=\"flex items-center progress mr-1\"\n [percent]=\"getCompletionPercentage(content?.identifier)\" [radius]=\"10\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [space]=\"-2\"\n [outerStrokeColor]=\"progressColor2()\" [innerStrokeColor]=\"'rgba(0, 0, 0, 0.16)'\"\n [animation]=\"true\" [animationDuration]=\"250\" [showTitle]=\"false\"\n [showUnits]=\"false\" [showSubtitle]=\"false\" [showInnerStroke]=\"true\"\n [clockwise]=\"true\" [backgroundOpacity]=\"0\" [backgroundGradient]=\"false\"\n [backgroundStrokeWidth]=\"3\" matTooltip=\"In progress\" [showZeroOuterStroke]=false\n [backgroundPadding]=\"-7\" [startFromZero]=\"false\" [backgroundPadding]=\"0\"\n [imageHeight]=\"18\" [imageWidth]=\"18\" [showBackground]=\"false\"\n [outerStrokeLinecap]=\"'butt'\">\n </circle-progress>\n </ng-container>\n </ng-container>\n <ng-template #elseBlock>\n <circle-progress class=\"flex items-center progress mr-1\" [percent]=\"0\" [radius]=\"11\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [outerStrokeColor]=\"'#808080'\"\n [innerStrokeColor]=\"'#808080'\" [animation]=\"true\" [space]=\"-2\" [showUnits]=\"false\"\n [animationDuration]=\"250\" [showTitle]=\"false\" [backgroundPadding]=\"0\"\n [backgroundPadding]=\"-9\" [outerStrokeLinecap]=\"'butt'\" matTooltip=\"Not started\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\"\n [imageHeight]=\"22\" [imageWidth]=\"22\" [showBackground]=\"false\"></circle-progress>\n </ng-template>\n </ng-container>\n <div [ngClass]=\"{'collection-active-class': pathSet?.has(content?.identifier)}\"></div>\n <!-- <p class=\"margin-remove text-truncate mat-subheading-1 flex-auto font-bold nodtranslate\"\n [ngClass]=\"{'text-active': pathSet?.has(content.identifier)}\">\n {{index}}. {{ content?.name | truncate:50 }}\n </p> -->\n <a class=\"margin-remove text-truncate mat-subheading-1 flex-auto font-bold nodtranslate\"\n [class.disabled]=\"null\" [ngClass]=\"{'ml-3': isEnrolled}\"\n [routerLink]=\"(isAllowed && !forPreview && isEnabled) ? resourceLink.url : null\"\n [queryParams]=\"computedQueryParams\">\n <!-- {{content?.courseCategory}} -->\n <div [ngClass]=\"{'resource-active': pathSet?.has(content?.identifier)}\"></div>\n <div class=\"text-truncate \" [ngClass]=\"{'cursor-pointer': !isEnabled}\"\n (click)=\"raiseTelemetry(); changeResource()\">\n <div class=\"flex flex-col sm:flex-row flex-wrap\">\n <p class=\"margin-remove text-truncate mat-body-2 flex-auto font-bold nodtranslate\"\n [ngClass]=\"{'text-active': pathSet?.has(content?.identifier)}\"\n [matTooltip]=\"content?.name?.length > 50 ? content?.name : ''\"\n matTooltipPosition=\"above\">\n <!-- <mat-icon class=\"margin-right-xs radiobtn time-icon\">radio_button_unchecked </mat-icon> -->\n {{index}}. {{ content?.name | truncate:50 }}\n\n </p>\n <span class=\"content-type optional-span nodtranslate\"\n *ngIf=\"content?.optionalReading\">{{ 'playerbrief.optional' | translate |\n titlecase}} </span>\n </div>\n <!-- for default grey icons -->\n <ng-container *ngIf=\"!pathSet?.has(content?.identifier)\">\n <div class=\"resicons ws-mat-black60-text\">\n <img src=\"/assets/icons/content/grey/video.svg\" alt=\"Video\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'video/mp4' || content?.mimeType === 'video/x-youtube' ||\n content?.mimeType ==='application/x-mpegURL'\">\n <img src=\"/assets/icons/content/grey/audio.svg\" alt=\"Audio\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'audio/mpeg'\">\n <img src=\"/assets/icons/content/grey/pdf.svg\" alt=\"PDF\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/pdf'\">\n <!-- <img src=\"/assets/icons/content/grey/resource.svg\" alt=\"Survey\" class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/survey'\"> -->\n <img src=\"/assets/icons/content/grey/link.svg\" alt=\"InteractiveContent\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/vnd.ekstep.html-archive' || content?.mimeType === 'text/x-url'\">\n <img src=\"/assets/icons/content/grey/assessment.svg\" alt=\"Assessment\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/json' || content?.mimeType === 'application/quiz' || content?.mimeType === 'application/vnd.sunbird.questionset'\">\n <img src=\"/assets/icons/content/grey/image.svg\" alt=\"Image\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'image/png' || content?.mimeType === 'image/jpeg'\">\n <img src=\"/assets/icons/content/grey/content_copy.svg\" class=\"contenticon\"\n alt=\"Course\"\n *ngIf=\"content.mimeType === 'application/vnd.ekstep.content-collection' || content?.mimeType === 'application/survey'\">\n <img src=\"/assets/icons/content/grey/module.svg\"\n class=\"float-left margin-right-xs\" alt=\"offline sessions\"\n *ngIf=\"content.mimeType === 'application/offline'\">\n\n <ng-container *ngIf=\"content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE\">\n\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{\n content?.maxQuestions }} {{ 'playerbrief.questions' | translate |\n titlecase}}</span>\n </ng-container>\n <ng-container *ngIf=\"!(content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE)\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{\n (content?.duration||\n hierarchyMapData[content?.identifier]?.expectedDuration || 0)|\n pipeDurationTransform:\n 'hms'\n }}</span>\n </ng-container>\n </div>\n </ng-container>\n\n <!-- for white icons when content highlighted -->\n <ng-container *ngIf=\"pathSet?.has(content?.identifier)\">\n <div class=\"resicons ws-mat-white-text\">\n <img src=\"/assets/icons/content/white/video.svg\" alt=\"Video\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'video/mp4' || content?.mimeType === 'video/x-youtube' ||\n content?.mimeType ==='application/x-mpegURL'\">\n <img src=\"/assets/icons/content/white/audio.svg\" alt=\"Audio\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'audio/mpeg'\">\n <img src=\"/assets/icons/content/white/pdf.svg\" alt=\"PDF\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/pdf'\">\n <!-- <img src=\"/assets/icons/content/white/resource.svg\" alt=\"Survey\" class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/survey'\"> -->\n <img src=\"/assets/icons/content/white/link.svg\" alt=\"InteractiveContent\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/vnd.ekstep.html-archive' || content?.mimeType === 'text/x-url'\">\n <img src=\"/assets/icons/content/white/assessment.svg\" alt=\"Assessment\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/json' || content?.mimeType === 'application/quiz' || content?.mimeType === 'application/vnd.sunbird.questionset'\">\n <img src=\"/assets/icons/content/grey/image.svg\" alt=\"Image\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'image/png' || content?.mimeType === 'image/jpeg'\">\n <img src=\"/assets/icons/content/white/content_copy.svg\" class=\"contenticon\"\n alt=\"Course\"\n *ngIf=\"content.mimeType === 'application/vnd.ekstep.content-collection' || content?.mimeType === 'application/survey'\">\n <img src=\"/assets/icons/content/white/module.svg\"\n class=\"float-left margin-right-xs\" alt=\"offline sessions\"\n *ngIf=\"content.mimeType === 'application/offline'\">\n <ng-container *ngIf=\"content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE\">\n <span class=\"resourceDuration ws-mat-white-text nodtranslate\">{{\n content?.maxQuestions }} {{ 'playerbrief.questions' | translate |\n titlecase}}</span>\n </ng-container>\n <ng-container *ngIf=\"!(content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE)\">\n <span class=\"resourceDuration ws-mat-white-text nodtranslate\">{{\n (content?.duration||\n hierarchyMapData[content?.identifier]?.expectedDuration || 0)|\n pipeDurationTransform:\n 'hms'\n }}</span>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </a>\n <!-- <div class=\"type-container resource mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Resource'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Resource</span>\n </div>\n <div class=\"type-container module mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Collection'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Module</span>\n </div>\n <div class=\"type-container course mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Course'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Course</span>\n </div> -->\n </div>\n\n </div>\n <!-- For course progress to be shown -->\n <ng-container>\n <ng-container\n *ngIf=\"!forPreview && content?.identifier && getCompletionPercentage(content?.identifier)\">\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) == 2\">\n <div class=\"flex flex-1\">\n <div class=\"mt-2 mr-4 flex flex-1 flex-col progress-container\">\n <div class=\"flex flex-row justify-end w-full \">\n <span class=\"mat-body-2 nodtranslate \">\n {{getCompletionPercentage(content?.identifier)}}%</span>\n </div>\n\n <ws-widget-content-progress [contentId]=\"content?.progress\"\n [progress]=\"getCompletionPercentage(content?.identifier)\"\n [progressType]=\"'percentage'\" [customClassName]=\"'viewer-progress'\">\n </ws-widget-content-progress>\n </div>\n <ng-container *ngIf=\"content?.issuedCertificatesId\">\n <a class=\"ml-5 certificate-btn\"\n [ngClass]=\"{'disable-btn': downloadCertificateLoading || content?.issuedCertificatesId}\"\n (click)=\"!downloadCertificateLoading && downloadCertificate(content?.issuedCertificatesId);$event.stopPropagation()\">\n <!-- <img src=\"fusion-assets/images/certificate-ico.svg\" width=\"24\" height=\"24\"> -->\n <span class=\"nodtranslate\">Certificate</span>\n <mat-icon *ngIf=\"!downloadCertificateLoading\"\n class=\"ml-2\">arrow_downward</mat-icon>\n <div class=\"center flex flex-middle certificate-loader\"\n *ngIf=\"downloadCertificateLoading\">\n <mat-spinner strokeWidth=\"2\" stroke=\"'white'\" class=\"white-spinner\"\n [diameter]=\"16\"></mat-spinner>\n </div>\n </a>\n </ng-container>\n </div>\n <!-- <circle-progress class=\"flex items-center progress\" [percent]=\"100\" [radius]=\"12\"\n [outerStrokeWidth]=\"3\" [innerStrokeWidth]=\"3\" [space]=\"-3\"\n [outerStrokeColor]=\"progressColor()\" [innerStrokeColor]=\"'rgba(0,0,0,.16)'\"\n [animation]=\"true\" [animationDuration]=\"300\" [showTitle]=\"false\" [showUnits]=\"false\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\"\n [backgroundOpacity]=\"0\" [backgroundGradient]=\"false\" [backgroundStrokeWidth]=\"3\"\n [showZeroOuterStroke]=false [backgroundPadding]=\"-9\" [startFromZero]=\"false\"\n [backgroundPadding]=\"0\" [imageHeight]=\"24\" [imageWidth]=\"24\" [showBackground]=\"false\"\n [outerStrokeLinecap]=\"'butt'\">\n </circle-progress> -->\n </ng-container>\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) < 2\">\n <div class=\"flex flex-1\">\n <div class=\"mt-2 mr-4 flex flex-1 flex-col progress-container\">\n <div class=\"flex flex-row justify-end w-full ws-mat-black-text\">\n <span class=\"mat-body-2 ws-mat-black-text nodtranslate\">\n {{getCompletionPercentage(content?.identifier)}}%</span>\n </div>\n\n <ws-widget-content-progress [contentId]=\"content?.progress\"\n [progress]=\"getCompletionPercentage(content?.identifier)\"\n [progressType]=\"'percentage'\" [customClassName]=\"'viewer-progress'\">\n </ws-widget-content-progress>\n </div>\n <ng-container *ngIf=\"content?.issuedCertificatesId\">\n <a class=\"ml-5 certificate-btn\"\n [ngClass]=\"{'disable-btn': downloadCertificateLoading || content?.issuedCertificatesId}\"\n (click)=\"!downloadCertificateLoading && downloadCertificate(content?.issuedCertificatesId);$event.stopPropagation()\">\n <!-- <img src=\"fusion-assets/images/certificate-ico.svg\" width=\"24\" height=\"24\"> -->\n <span class=\"nodtranslate\">Certificate</span>\n <mat-icon *ngIf=\"!downloadCertificateLoading\"\n class=\"ml-2\">arrow_downward</mat-icon>\n <div class=\"center flex flex-middle certificate-loader\"\n *ngIf=\"downloadCertificateLoading\">\n <mat-spinner strokeWidth=\"2\" stroke=\"'white'\" class=\"white-spinner\"\n [diameter]=\"16\"></mat-spinner>\n </div>\n </a>\n </ng-container>\n </div>\n </ng-container>\n </ng-container>\n </ng-container>\n\n <!-- <div class=\"see-all-container\">\n <a href=\"javascript:void(0)\" role=\"button\"\n (click)=\"content.viewChildren = !content.viewChildren; expandActive = false\"\n class=\"see-all-btn tab custom-chevron customicon\" mat-button>\n <mat-icon *ngIf=\"!content.viewChildren && !isModule\">keyboard_arrow_down</mat-icon>\n <mat-icon *ngIf=\"content.viewChildren && !isModule\">keyboard_arrow_up</mat-icon>\n <mat-icon *ngIf=\"!content.viewChildren && isModule\">add</mat-icon>\n <mat-icon *ngIf=\"content.viewChildren && isModule\">remove</mat-icon>\n </a>\n </div> -->\n </div>\n </div>\n </div>\n\n</ng-container>", styles: [".customicon{position:absolute;top:-.5em;right:0}.customicon .mat-icon{color:#1a4ca1}a.disabled{pointer-events:none;cursor:default}span.optional-span{margin-left:8px;padding:0 6px;border-radius:2px;display:inline-block;background-color:#0074b6;color:#fff;font-size:12px}.card-collection{display:flex;align-items:center;border-radius:8px}.card-collection .card-thumbnail{height:100%;margin-right:12px;cursor:pointer;border-radius:8px 0 0}@media only screen and (max-width: 469px){.card-collection{flex-direction:column;align-items:flex-start!important}.card-collection .card-thumbnail{height:100%!important;width:100%!important}.card-collection .text-truncate{white-space:unset!important}}.tab:focus{outline:1px solid!important}.custom-chevron:focus{outline:0px solid!important}.resource-container{display:flex;align-items:flex-start;flex-direction:column}.resource-container .resource{padding:16px 16px 16px 0;width:100%}.resource-container .card-thumbnail{height:100%;cursor:pointer}.resource-container .img-container{position:relative;margin-right:12px}.resource-container .img-container ws-widget-content-progress{position:absolute;left:0;right:0;bottom:5px}@media only screen and (max-width: 469px){.resource-container{flex-direction:column;align-items:flex-start!important}.resource-container .card-thumbnail{height:100%!important;width:100%!important}.resource-container .text-truncate{white-space:unset!important}}.child-meta-container{margin-top:8px;display:flex}.child-meta-container .child-structure{display:flex;align-items:center;flex-wrap:wrap}.child-meta-container .child-structure span{margin-right:12px;text-align:center;margin-bottom:8px}.child-meta-container .child-structure .structure-icon{margin-right:12px}@media only screen and (max-width: 469px){.child-meta-container{margin-left:.5rem;justify-content:space-between}}.resource-container{display:flex;align-items:center}.resource-container ws-display-content-type-icon{display:flex;align-items:center}.resource-container .resource-meta{margin-left:12px;display:flex;justify-content:space-between;align-items:center}.completed-icon{color:#1a4ca1}.collection-wrapper{padding:1rem}.collection-wrapper.course.content-active{background-color:#1a4ca1;color:#fff}.collection-wrapper.course.content-active .period{background:#fff}.collection-wrapper.course.content-active .text-active,.collection-wrapper.course.content-active .icon-color,.collection-wrapper.course.content-active .customicon .mat-icon{color:#fff}.collection-wrapper.course.content-active .progress-container span{color:#fff!important}.collection-wrapper.course.content-active .milestone-description,.collection-wrapper.course.content-active .milestone-progress-text{color:#fff}.text-active{color:#1a4ca1}.text-active.font-bold{font-weight:600}.activeResource{background-color:#1a4ca1;color:#fff;padding-top:1rem!important;padding-bottom:1rem!important}.activeResource .text-active{color:#fff}.activeResource .text-active.font-bold{font-weight:600}.activeResource .resourceDuration,.activeResource .completed-icon{color:#fff}.collection-wrapper.open{border-bottom:1px solid rgba(0,0,0,.16)}.collection-wrapper.close{border:none}.child-wrapper.open{border-radius:0 0 8px 8px}.children-container .mat-subheading-1{font:500 16px/24px Lato!important}.children-container .resource-container{margin-bottom:16px}.children-container .resource-container .resource{padding:0}.children-container .resource-container .card-thumbnail{height:65px;align-self:center}.first.resourceCard:nth-child(1) .resource{margin-top:16px!important}.first.resourceCard:nth-child(1) .activeResource{margin-top:0!important}.children-container .resourceCard:last-child .resource-container:has(.activeResource){margin-bottom:0!important}.moduleCard:not(:last-child)>.collection-wrapper.close.module{border-bottom:4px solid rgba(0,0,0,.08);border-radius:0}.moduleCard:not(:last-child)>.collection-wrapper.open.module+.child-wrapper.open{border-bottom:4px solid rgba(0,0,0,.08);border-radius:0}.collection-wrapper.open.course+.child-wrapper.open .collection-wrapper.open.module+.child-wrapper.open{background-color:#eff3f9;border-bottom:4px solid rgba(0,0,0,.08);border-radius:0}.collection-wrapper.open.module+.child-wrapper.open{background-color:#eff3f9;border-radius:0;padding-bottom:8px}.content-heading{letter-spacing:0px;color:#222}.content-type{letter-spacing:0px}.time-icon{height:16px;width:16px;font-size:16px;vertical-align:middle}.time-icon.icon-color{color:#0009}.period{width:3px;height:3px;background:#0009;border-radius:4px}.time-value{letter-spacing:0px;color:#222;text-transform:lowercase}.see-all-container{position:absolute;right:16px;top:24px}.oval-white{background:#fff 0% 0% no-repeat padding-box;border-radius:8px;padding:2px 8px}.type-container{letter-spacing:0px;display:flex;align-items:center}.type-container .rotate-90{transform:rotate(-90deg)}.type-container .custom-icon{width:18px;height:18px;font-size:18px;margin-right:8px}.type-container.resource{color:#00a9f4}.type-container.module{color:#34d6a4}.type-container.course{color:#f58634}.no-mb{margin-bottom:0!important}.w-100{width:100%}.w-auto{width:auto}.progress-bar-thin{height:5px!important}.progress-bar-thin ::ng-deep .mat-progress-bar{height:5px}.progress-bar-thin ::ng-deep .theme-igot.day-mode .mat-progress-bar-buffer{background-color:transparent!important}.progress-bar-thin ::ng-deep .theme-igot.day-mode .mat-progress-bar-background{fill:transparent}.radiobtn{color:#00000029}.resicons img{width:22px;opacity:.5;margin-top:2px;vertical-align:sub}.certificate-btn{height:24px;background:#1a4ca1;display:flex;justify-content:center;align-items:center;padding:4px 11px;color:#fff;border-radius:20px;border:1px solid white;font:400 12px/16px Lato;cursor:pointer}.certificate-btn .mat-icon{fill:#fff;color:#fff;font-size:16px;height:auto;width:auto}.view-certificate-wrapper{display:flex;border-radius:4px;border:1.5px solid rgb(0,116,182);opacity:1;padding:8px}.collection-wrapper.course,.collection-wrapper.module,.resource-container .resource{padding-left:16px;box-sizing:border-box;width:100%;overflow:hidden}.children-container.module .resource-container .resource,.course .collection-wrapper.module{padding-left:24px;box-sizing:border-box;width:100%}.course .children-container.module .resource-container .resource{padding-left:32px;box-sizing:border-box;width:100%}.course .resource-container .resource{padding-left:24px}::ng-deep .white-spinner{stroke:#fff!important}.certificate-loader ::ng-deep .mat-progress-spinner circle,.mat-spinner circle{stroke:#fff}.lock-message{background:#fff4ec;color:#d13924;padding:10px;border-radius:4px;display:block!important;width:100%}.content-locking{padding:8px 12px;margin-top:8px;margin-left:0;margin-right:0;border-radius:4px;background:#fff4ec;display:flex!important;align-items:center;gap:8px;width:100%;box-sizing:border-box}.lock-icon{color:#f3962f;font-size:20px;flex-shrink:0}.unlock-message{background:#efffec;color:#0c9600;padding:10px}.unlock-icon{color:#0c9600}.download-btn{padding:4px 12px;text-underline-position:from-font;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none;cursor:pointer;border-radius:40px;color:#1b4ca1;font-weight:700;border:1px solid #1B4CA1;display:inline-block;pointer-events:auto;position:relative;z-index:1}.activeResource .download-btn.active{color:#fff;border:1px solid #fff}.milestone-badge{display:inline-block;background-color:#fefaf4;border:1px solid #EF951E;border-radius:16px;padding:2px 12px}.milestone-badge-text{font-size:12px;font-weight:500;color:#212121}.milestone-description{font-size:14px;line-height:1.5;color:#000000b3;margin:0;display:-webkit-box!important;-webkit-line-clamp:2!important;-webkit-box-orient:vertical!important;overflow:hidden!important;text-overflow:ellipsis!important;word-break:break-word!important;white-space:normal!important;max-width:100%!important}.milestone-progress{display:flex;align-items:center}.milestone-progress-text{font-size:14px;font-weight:500;color:#0009}.milestone-locked-message{display:flex;align-items:center;padding:8px 12px;background-color:#f3962f1a;border-left:3px solid #F3962F;border-radius:4px}.locked-criteria-text{font-size:13px;font-weight:400;color:#000000b3;line-height:1.4}.locked-text{font-size:14px;font-weight:500;color:#f3962f}.mandatory-text{color:#d13924!important}.view-achievement-container{display:flex;align-items:center}.view-achievement-btn{background-color:transparent;border:1.5px solid #1a4ca1;color:#1a4ca1;border-radius:20px;padding:6px 16px;font-size:14px;font-weight:500;cursor:pointer;display:flex;align-items:center;gap:8px;transition:all .2s ease;min-width:150px}.view-achievement-btn:hover:not(:disabled){background-color:#1a4ca1;color:#fff}.view-achievement-btn:disabled{opacity:.6;cursor:not-allowed}.view-achievement-btn .inline-spinner{display:inline-block}::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: i1$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i3.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i5$3.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i5$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "component", type: i10$2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "component", type: ContentProgressComponent, selector: "ws-widget-content-progress", inputs: ["contentId", "progress", "progressType", "forPreview", "className", "customClassName"] }, { kind: "component", type: i1$4.CircleProgressComponent, selector: "circle-progress", inputs: ["name", "class", "backgroundGradient", "backgroundColor", "backgroundGradientStopColor", "backgroundOpacity", "backgroundStroke", "backgroundStrokeWidth", "backgroundPadding", "radius", "space", "percent", "toFixed", "maxPercent", "renderOnClick", "units", "unitsFontSize", "unitsFontWeight", "unitsColor", "outerStrokeGradient", "outerStrokeWidth", "outerStrokeColor", "outerStrokeGradientStopColor", "outerStrokeLinecap", "innerStrokeColor", "innerStrokeWidth", "titleFormat", "title", "titleColor", "titleFontSize", "titleFontWeight", "subtitleFormat", "subtitle", "subtitleColor", "subtitleFontSize", "subtitleFontWeight", "imageSrc", "imageHeight", "imageWidth", "animation", "animateTitle", "animateSubtitle", "animationDuration", "showTitle", "showSubtitle", "showUnits", "showImage", "showBackground", "showInnerStroke", "clockwise", "responsive", "startFromZero", "showZeroOuterStroke", "lazy", "options"], outputs: ["onClick"] }, { 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: "pipe", type: i2.TitleCasePipe, name: "titlecase" }, { kind: "pipe", type: i2$1.PipeDurationTransformPipe, name: "pipeDurationTransform" }, { kind: "pipe", type: i1$2.TranslatePipe, name: "translate" }, { kind: "pipe", type: TruncatePipe, name: "truncate" }], animations: [
7459
7538
  trigger('panelInOut', [
7460
7539
  transition('void => *', [
@@ -7480,7 +7559,7 @@ i0.ÉĩÉĩngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
7480
7559
  ])
7481
7560
  ])
7482
7561
  ], template: "<ng-container *ngIf=\"content && !isPreAssessment\">\n <ng-container *ngIf=\"isCollection && !isModule\">\n <ng-container [ngTemplateOutlet]=\"collectionTemplate\">\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"isCollection && isModule\">\n <ng-container *ngIf=\"content?.moduleResourseCount\">\n <ng-container [ngTemplateOutlet]=\"collectionTemplate\">\n </ng-container>\n </ng-container>\n </ng-container>\n\n <div *ngIf=\"isResource\" class=\"resource-container\"\n [ngClass]=\"pathSet?.has(content?.identifier) && isEnrolled ? 'content-active-resource': 'content-not-active-resource'\">\n <div class=\"resource flex sm:flex-row flex-start width-expand w-100 sm:pr-4 sm:w-auto\"\n [ngClass]=\"{'activeResource': pathSet?.has(content?.identifier) && isEnrolled}\">\n <!-- Lock message for curated programs only (shown above content) -->\n <ng-container *ngIf=\"content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT && checkForCuratedProgram &&\n !isContentUnlocked\">\n <div class=\"content-locking flex w-full flex-middle mb-2 gap-3\">\n <mat-icon class=\"lock-icon\">lock</mat-icon>\n <span class=\"lock-message mat-body-2\">\n The content is locked. Complete program or all courses to view this module\n </span>\n </div>\n </ng-container>\n <ng-container *ngIf=\"content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT && checkForCuratedProgram &&\n isContentUnlocked\">\n <div class=\"content-locking flex w-full flex-middle mb-2 gap-3\">\n <mat-icon class=\"unlock-icon\">lock_open_right</mat-icon>\n <span class=\"unlock-message mat-body-2\">\n This content is unlocked.\n </span>\n </div>\n </ng-container>\n <div class=\"flex flex-wrap items-start justify-start sm:justify-end\">\n <!-- <button *ngIf=\"!forPreview && content?.artifactUrl && !isXSmall && isAllowed && isEnabled\" type=\"button\"\n mat-icon-button class=\"\" [matMenuTriggerFor]=\"buttonMenu\">\n <mat-icon>more_vertical</mat-icon>\n </button> -->\n <ng-container *ngIf=\"isEnrolled && !isMilestoneLocked && !isParentMilestoneLocked\">\n <ng-container\n *ngIf=\"!forPreview && content?.identifier && getCompletionPercentage(content?.identifier) ; else elseBlock\">\n\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) == 2\">\n <div class=\"completed\">\n <div>\n <mat-icon class=\"completed-icon\" [color]=\"blue\">check_circle</mat-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) < 2\">\n <circle-progress class=\"flex items-center progress\"\n [percent]=\"getCompletionPercentage(content?.identifier)\" [radius]=\"10\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [space]=\"-2\"\n [outerStrokeColor]=\"progressColor2()\" [innerStrokeColor]=\"'rgba(0, 0, 0, 0.16)'\"\n [animation]=\"true\" [animationDuration]=\"250\" [showTitle]=\"false\" [showUnits]=\"false\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\"\n [backgroundOpacity]=\"0\" [backgroundGradient]=\"false\" [backgroundStrokeWidth]=\"3\"\n matTooltip=\"In progress\" [showZeroOuterStroke]=false [backgroundPadding]=\"-9\"\n [startFromZero]=\"false\" [backgroundPadding]=\"0\" [imageHeight]=\"22\" [imageWidth]=\"22\"\n [showBackground]=\"false\" [outerStrokeLinecap]=\"'butt'\">\n </circle-progress>\n <!-- <ws-widget-content-progress *ngIf=\"content?.identifier\" [forPreview]=\"forPreview\"\n [contentId]=\"content?.identifier\" class=\"progress-bar-thin\" [progress]=\"content?.completionPercentage\"\n [progressType]=\"'percentage'\">\n </ws-widget-content-progress> -->\n </ng-container>\n </ng-container>\n <ng-template #elseBlock>\n <circle-progress class=\"flex items-center progress\" [percent]=\"0\" [radius]=\"11\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [outerStrokeColor]=\"'#808080'\"\n [innerStrokeColor]=\"'#808080'\" [animation]=\"true\" [space]=\"-2\" [showUnits]=\"false\"\n [animationDuration]=\"250\" [showTitle]=\"false\" [backgroundPadding]=\"0\"\n [backgroundPadding]=\"-9\" [outerStrokeLinecap]=\"'butt'\" matTooltip=\"Not started\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\" [imageHeight]=\"22\"\n [imageWidth]=\"22\" [showBackground]=\"false\"></circle-progress>\n <!-- <p>no data</p> -->\n </ng-template>\n </ng-container>\n </div>\n <!-- deactivated as per NIC CEO requirement to access course wthout login -->\n <!-- For locked assessments: show content but make it non-clickable -->\n <div class=\"width-expand\" *ngIf=\"isMilestoneAssessmentLocked && isEnrolled; else clickableContent\"\n [ngClass]=\"{'ml-3': isEnrolled}\">\n <div class=\"text-truncate opacity-60\">\n <div class=\"flex flex-col sm:flex-row flex-wrap\">\n <div class=\"flex items-center gap-2 w-full\">\n <mat-icon class=\"text-gray-500\">lock</mat-icon>\n <p class=\"margin-remove text-truncate mat-body-2 flex-auto font-bold nodtranslate text-gray-600\"\n [matTooltip]=\"(content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT) ? ' - ' + content?.contextCategory : '')).length > 50 ? (content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT) ? ' - ' + content?.contextCategory : '')) : ''\"\n matTooltipPosition=\"above\">\n {{ (content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT )? ' - ' + content?.contextCategory : '')) | truncate:50 }}\n </p>\n </div>\n <span class=\"content-type optional-span nodtranslate\" *ngIf=\"content?.optionalReading\">{{\n 'playerbrief.optional' | translate | titlecase}} </span>\n </div>\n <!-- for default grey icons -->\n <ng-container *ngIf=\"!pathSet?.has(content?.identifier) || !isEnrolled\">\n <div class=\"resicons ws-mat-black60-text\">\n <img src=\"/assets/icons/content/grey/video.svg\" alt=\"Video\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'video/mp4' || content?.mimeType === 'video/x-youtube' ||\n content?.mimeType ==='application/x-mpegURL'\">\n <img src=\"/assets/icons/content/grey/audio.svg\" alt=\"Audio\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'audio/mpeg'\">\n <img src=\"/assets/icons/content/grey/pdf.svg\" alt=\"PDF\" class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/pdf'\">\n <img src=\"/assets/icons/content/grey/link.svg\" alt=\"InteractiveContent\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/vnd.ekstep.html-archive' || content?.mimeType === 'text/x-url'\">\n <img src=\"/assets/icons/content/grey/assessment.svg\" alt=\"Assessment\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/json' || content?.mimeType === 'application/quiz' || content?.mimeType === 'application/vnd.sunbird.questionset'\">\n <img src=\"/assets/icons/content/grey/image.svg\" alt=\"Image\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'image/png' || content?.mimeType === 'image/jpeg'\">\n <img src=\"/assets/icons/content/grey/content_copy.svg\" class=\"contenticon\" alt=\"Course\"\n *ngIf=\"content.mimeType === 'application/vnd.ekstep.content-collection' || content?.mimeType === 'application/survey'\">\n <img src=\"/assets/icons/content/grey/module.svg\" class=\"float-left margin-right-xs\"\n alt=\"offline sessions\" *ngIf=\"content.mimeType === 'application/offline'\">\n\n <ng-container *ngIf=\"content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ content?.maxQuestions\n }} {{ 'playerbrief.questions' | translate | titlecase}}</span>\n </ng-container>\n <ng-container *ngIf=\"!(content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE)\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ (content?.duration||\n hierarchyMapData[content?.identifier]?.expectedDuration || 0)|\n pipeDurationTransform:\n 'hms'\n }}</span>\n </ng-container>\n </div>\n </ng-container>\n </div>\n \n <!-- Lock message displayed BELOW assessment details when locked -->\n <div class=\"content-locking flex w-full flex-middle mt-2 gap-2 px-2 py-1 bg-orange-50 border-l-4 border-orange-400\">\n <mat-icon class=\"lock-icon text-orange-600\" style=\"font-size: 18px; width: 18px; height: 18px;\">lock</mat-icon>\n <span class=\"lock-message mat-body-2 text-orange-800\" style=\"font-size: 13px;\">\n This content is locked. Complete all mandatory items to unlock the assessment.\n </span>\n </div>\n </div>\n \n <!-- Clickable content template (when NOT locked) -->\n <ng-template #clickableContent>\n <a class=\"width-expand\"\n [class.disabled]=\"(forPreview || !isEnabled || !isEnrolled || !isBatchInProgess || !isContentUnlocked || isParentMilestoneLocked) ? true : null\"\n [ngClass]=\"{'ml-3': isEnrolled}\"\n [routerLink]=\"(isAllowed && !forPreview && isEnabled && !isParentMilestoneLocked) ? resourceLink.url : null\"\n [queryParams]=\"(isAllowed && !forPreview && isEnabled && !isParentMilestoneLocked) ? resourceLink.queryParams : null\"\n [matTooltip]=\"isParentMilestoneLocked ? 'This content is locked. Complete previous milestone to view this content.' : ''\"\n matTooltipPosition=\"above\">\n <div [ngClass]=\"{'resource-active': pathSet?.has(content?.identifier) && isEnrolled}\"></div>\n <div class=\"text-truncate \" [ngClass]=\"{'cursor-pointer': !isEnabled && isEnrolled}\"\n (click)=\"content.viewChildren = !content.viewChildren; raiseTelemetry(); changeResource()\">\n <div class=\"flex flex-col sm:flex-row flex-wrap\">\n <p class=\"margin-remove text-truncate mat-body-2 flex-auto font-bold nodtranslate\"\n [ngClass]=\"{'text-active': pathSet?.has(content?.identifier) && isEnrolled}\"\n [matTooltip]=\"(content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT) ? ' - ' + content?.contextCategory : '')).length > 50 ? (content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT) ? ' - ' + content?.contextCategory : '')) : ''\"\n matTooltipPosition=\"above\">\n {{ (content?.name + (content?.contextCategory && (content?.primaryCategory === primaryCategory.FINAL_ASSESSMENT)? ' - ' + content?.contextCategory : '')) | truncate:50 }}\n </p>\n <span class=\"content-type optional-span nodtranslate\" *ngIf=\"content?.optionalReading\">{{\n 'playerbrief.optional' | translate | titlecase}} </span>\n </div>\n <!-- for default grey icons -->\n <ng-container *ngIf=\"!pathSet?.has(content?.identifier) || !isEnrolled\">\n <div class=\"resicons ws-mat-black60-text\">\n <img src=\"/assets/icons/content/grey/video.svg\" alt=\"Video\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'video/mp4' || content?.mimeType === 'video/x-youtube' ||\n content?.mimeType ==='application/x-mpegURL'\">\n <img src=\"/assets/icons/content/grey/audio.svg\" alt=\"Audio\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'audio/mpeg'\">\n <img src=\"/assets/icons/content/grey/pdf.svg\" alt=\"PDF\" class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/pdf'\">\n <img src=\"/assets/icons/content/grey/link.svg\" alt=\"InteractiveContent\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/vnd.ekstep.html-archive' || content?.mimeType === 'text/x-url'\">\n <img src=\"/assets/icons/content/grey/assessment.svg\" alt=\"Assessment\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/json' || content?.mimeType === 'application/quiz' || content?.mimeType === 'application/vnd.sunbird.questionset'\">\n <img src=\"/assets/icons/content/grey/image.svg\" alt=\"Image\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'image/png' || content?.mimeType === 'image/jpeg'\">\n <img src=\"/assets/icons/content/grey/content_copy.svg\" class=\"contenticon\" alt=\"Course\"\n *ngIf=\"content.mimeType === 'application/vnd.ekstep.content-collection' || content?.mimeType === 'application/survey'\">\n <img src=\"/assets/icons/content/grey/module.svg\" class=\"float-left margin-right-xs\"\n alt=\"offline sessions\" *ngIf=\"content.mimeType === 'application/offline'\">\n\n <ng-container *ngIf=\"content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ content?.maxQuestions\n }} {{ 'playerbrief.questions' | translate | titlecase}}</span>\n </ng-container>\n <ng-container *ngIf=\"!(content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE)\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ (content?.duration||\n hierarchyMapData[content?.identifier]?.expectedDuration || 0)|\n pipeDurationTransform:\n 'hms'\n }}</span>\n </ng-container>\n </div>\n </ng-container>\n\n <!-- for white icons when content highlighted -->\n <ng-container *ngIf=\"pathSet?.has(content?.identifier) && isEnrolled\">\n <div class=\"resicons ws-mat-white-text\">\n <img src=\"/assets/icons/content/white/video.svg\" alt=\"Video\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'video/mp4' || content?.mimeType === 'video/x-youtube' ||\n content?.mimeType ==='application/x-mpegURL'\">\n <img src=\"/assets/icons/content/white/audio.svg\" alt=\"Audio\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'audio/mpeg'\">\n <img src=\"/assets/icons/content/white/pdf.svg\" alt=\"PDF\" class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/pdf'\">\n <img src=\"/assets/icons/content/white/link.svg\" alt=\"InteractiveContent\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/vnd.ekstep.html-archive' || content?.mimeType === 'text/x-url'\">\n <img src=\"/assets/icons/content/white/assessment.svg\" alt=\"Assessment\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/json' || content?.mimeType === 'application/quiz' || content?.mimeType === 'application/vnd.sunbird.questionset'\">\n <img src=\"/assets/icons/content/grey/image.svg\" alt=\"Image\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'image/png' || content?.mimeType === 'image/jpeg'\">\n <img src=\"/assets/icons/content/white/content_copy.svg\" class=\"contenticon\" alt=\"Course\"\n *ngIf=\"content.mimeType === 'application/vnd.ekstep.content-collection' || content?.mimeType === 'application/survey'\">\n <img src=\"/assets/icons/content/white/module.svg\" class=\"float-left margin-right-xs\"\n alt=\"offline sessions\" *ngIf=\"content.mimeType === 'application/offline'\">\n <ng-container *ngIf=\"content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ content?.maxQuestions\n }} {{ 'playerbrief.questions' | translate | titlecase}}</span>\n </ng-container>\n <ng-container *ngIf=\"!(content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE)\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{ (content?.duration||\n hierarchyMapData[content?.identifier]?.expectedDuration || 0)|\n pipeDurationTransform:\n 'hms'\n }}</span>\n </ng-container>\n </div>\n </ng-container>\n\n <!-- Download button for pdf resources -->\n <ng-container *ngIf=\"shouldShowDownloadButton(content)\">\n <div class=\"download-btn mat-body-2 mt-2 sm:mt-1\" (click)=\"downloadContent(content, $event)\"\n [ngClass]=\"{'active': pathSet?.has(content?.identifier)}\">\n <a class=\"download-link flex items-center\">\n <span class=\"\">Download</span>\n </a>\n </div>\n </ng-container>\n </div>\n </a>\n </ng-template>\n </div>\n </div>\n</ng-container>\n\n<mat-menu #buttonMenu=\"matMenu\">\n <a mat-menu-item [routerLink]=\"'../' + content?.identifier + '/overview'\" [queryParams]=\"contextPath\"\n class=\"flex flex-middle\">\n <mat-icon>toc</mat-icon>\n <h3 class=\"margin-remove nodtranslate\">\n View Details\n </h3>\n </a>\n</mat-menu>\n\n<ng-template #collectionTemplate>\n <ng-container *ngIf=\"isCollection\">\n <div class=\"collection-wrapper p-4 flex flex-col position-relative\" [ngClass]=\"{'open': check(content),\n 'close': !content.viewChildren,\n 'course':!isModule, 'module': isModule,\n 'content-active': pathSet?.has(content.identifier) && isEnrolled}\">\n <div class=\"card-collection w-auto sm:w-100 padding-right-xl\">\n <!-- <img class=\"card-thumbnail ws-mat-primary-lite-background\" [src]=\"content?.appIcon\" alt=\"Thumbnail\"\n (click)=\"content.viewChildren = !content.viewChildren\" [wsUtilsDefaultThumbnail]=\"defaultThumbnail\" /> -->\n <div class=\"flex flex-col flex-wrap flex-between width-expand pr-0 w-100 \">\n <div class=\"text-truncate\" [ngClass]=\"{'cursor-pointer': !isEnabled}\"\n (click)=\"content.viewChildren = !content.viewChildren\">\n <div class=\"flex items-center justify-center mb-1 sm:flex-row\">\n <ng-container\n *ngIf=\"isModule && isEnrolled && !isMilestoneLocked && !isParentMilestoneLocked\">\n <ng-container\n *ngIf=\"!forPreview && content?.identifier && getCompletionPercentage(content?.identifier) ; else elseBlock\">\n\n <ng-container *ngIf=\"getCompletionStatus(content.identifier) == 2\">\n <div class=\"completed mr-2\">\n <div>\n <mat-icon class=\"completed-icon\" [color]=\"blue\">check_circle</mat-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) < 2\">\n <circle-progress class=\"flex items-center progress mr-1\"\n [percent]=\"getCompletionPercentage(content?.identifier)\" [radius]=\"10\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [space]=\"-2\"\n [outerStrokeColor]=\"progressColor2()\"\n [innerStrokeColor]=\"'rgba(0, 0, 0, 0.16)'\" [animation]=\"true\"\n [animationDuration]=\"250\" [showTitle]=\"false\" [showUnits]=\"false\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\"\n [backgroundOpacity]=\"0\" [backgroundGradient]=\"false\"\n [backgroundStrokeWidth]=\"3\" matTooltip=\"In progress\"\n [showZeroOuterStroke]=false [backgroundPadding]=\"-7\" [startFromZero]=\"false\"\n [backgroundPadding]=\"0\" [imageHeight]=\"18\" [imageWidth]=\"18\"\n [showBackground]=\"false\" [outerStrokeLinecap]=\"'butt'\">\n </circle-progress>\n </ng-container>\n </ng-container>\n <ng-template #elseBlock>\n <circle-progress class=\"flex items-center progress mr-1\" [percent]=\"0\" [radius]=\"11\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [outerStrokeColor]=\"'#808080'\"\n [innerStrokeColor]=\"'#808080'\" [animation]=\"true\" [space]=\"-2\"\n [showUnits]=\"false\" [animationDuration]=\"250\" [showTitle]=\"false\"\n [backgroundPadding]=\"0\" [backgroundPadding]=\"-9\" [outerStrokeLinecap]=\"'butt'\"\n matTooltip=\"Not started\" [showSubtitle]=\"false\" [showInnerStroke]=\"true\"\n [clockwise]=\"true\" [imageHeight]=\"22\" [imageWidth]=\"22\"\n [showBackground]=\"false\"></circle-progress>\n </ng-template>\n </ng-container>\n <div\n [ngClass]=\"{'collection-active-class': pathSet?.has(content?.identifier) && isEnrolled}\">\n </div>\n <img *ngIf=\"isMilestoneLocked\" src=\"assets/icons/hubs/lock.svg\" alt=\"Locked\"\n class=\"lock-icon mr-2 margin-bottom-xxs\">\n <div class=\"flex-auto flex flex-col\" style=\"min-width: 0;\">\n <p class=\"margin-remove text-truncate mat-subheading-1 font-bold nodtranslate\"\n [ngClass]=\"{'text-active': pathSet?.has(content.identifier) && isEnrolled}\"\n [matTooltip]=\"content?.name?.length > 50 ? content?.name : ''\"\n matTooltipPosition=\"above\">\n <span>{{isMilestone ? index -1 : index}}. </span>{{ content?.name | truncate:50 }}\n </p>\n <div class=\"mt-1\" *ngIf=\"isMilestone && isMilestoneLocked\">\n <span class=\"locked-text\">Locked</span>\n </div>\n <div class=\"mt-1\" *ngIf=\"content?.isMandatory\">\n <span class=\"mandatory-text mat-caption\">Mandatory</span>\n </div>\n </div>\n \n <div class=\"type-container resource mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Resource'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Resource</span>\n </div>\n <div class=\"type-container module mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Collection'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Module</span>\n </div>\n <div class=\"type-container course mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Course'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Course</span>\n </div>\n </div>\n <!-- Milestone Badge -->\n <div *ngIf=\"isMilestone\" class=\"milestone-badge mt-2 mb-2\">\n <span class=\"milestone-badge-text nodtranslate\">Milestone {{index - 1}}</span>\n </div>\n <!-- Milestone Description (2 lines with ellipsis) -->\n <p #milestoneDescRef *ngIf=\"isMilestone && content?.description\" class=\"milestone-description mt-2 nodtranslate\"\n [matTooltip]=\"isMultiLineTruncated(milestoneDescRef) ? content?.description : ''\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"multiline-tooltip\">\n {{ content?.description }}\n </p>\n <div class=\"flex flex-row gap-3 items-center content-key-values mt-2\">\n <mat-icon *ngIf=\"!isModule\" alt=\"course\"\n class=\"time-icon icon-color\">video_library</mat-icon>\n <img *ngIf=\"isModule\" alt=\"Module\" class=\"time-icon\"\n src=\"/assets/icons/content/grey/module.svg\">\n <div class=\"text-xs nodtranslate\">{{ (hierarchyMapData[content?.identifier]?.duration ||\n 120)|\n pipeDurationTransform: 'hms' }}</div>\n\n <ng-container *ngIf=\"content?.moduleCount\">\n <div class=\"flex items-center\">\n <span class=\"period\"></span>\n </div>\n <div class=\"text-xs nodtranslate\">{{content?.moduleCount}} {{content?.moduleCount > 1?\n 'modules' :\n 'module'}}</div>\n </ng-container>\n <ng-container *ngIf=\"content?.leafNodesCount\">\n <div class=\"flex items-center\">\n <span class=\"period\"></span>\n </div>\n <div class=\"text-xs nodtranslate\">{{content?.leafNodesCount}} {{content?.leafNodesCount\n >1 ? 'items':\n 'item'}}</div>\n </ng-container>\n </div>\n <!-- Milestone Completion Progress -->\n <div *ngIf=\"isMilestone && isEnrolled && !isMilestoneLocked\" class=\"milestone-progress mt-2 flex flex-col gap-2\">\n <div class=\"flex items-center justify-start gap-4 w-100\">\n <span class=\"milestone-progress-text nodtranslate\">{{getMilestoneCompletedCount()}} of {{content?.leafNodesCount || 0}} completed</span>\n <!-- View Achievement Button for completed milestones - Always visible when completed -->\n <ng-container *ngIf=\"getCompletionPercentage(content?.identifier) >= 100 || getCompletionStatus(content?.identifier) === 2\">\n <button type=\"button\" class=\"view-achievement-btn ml-4\" [disabled]=\"achievementLoading\"\n (click)=\"viewMilestoneAchievement($event)\">\n <span *ngIf=\"!achievementLoading\">View Achievement</span>\n <mat-spinner *ngIf=\"achievementLoading\" [diameter]=\"16\" [strokeWidth]=\"2\" color=\"primary\" class=\"inline-spinner\"></mat-spinner>\n </button>\n </ng-container>\n </div>\n </div>\n <!-- Unlock Criteria Message for Locked Milestones -->\n <div *ngIf=\"isMilestone && isEnrolled && isMilestoneLocked\" class=\"milestone-locked-message mt-2\">\n <span class=\"locked-criteria-text mat-caption\">\n {{ getMilestoneUnlockMessage() }}\n </span>\n </div>\n \n </div>\n <!-- For course progress to be shown -->\n <ng-container *ngIf=\"isEnrolled && !isMilestoneLocked && !isParentMilestoneLocked\">\n <ng-container\n *ngIf=\"!forPreview && content?.identifier && getCompletionPercentage(content?.identifier) && content.primaryCategory === 'Course'\">\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) == 2\">\n <div class=\"flex flex-1\">\n <div class=\"mt-2 mr-4 flex flex-1 flex-col progress-container\">\n <div class=\"flex flex-row justify-end w-full \">\n <span class=\"mat-body-2 nodtranslate \">\n {{getCompletionPercentage(content?.identifier)}}%</span>\n </div>\n\n <ws-widget-content-progress [contentId]=\"content?.progress\"\n [progress]=\"getCompletionPercentage(content?.identifier)\"\n [progressType]=\"'percentage'\" [customClassName]=\"'viewer-progress'\">\n </ws-widget-content-progress>\n </div>\n <ng-container *ngIf=\"content?.issuedCertificatesId\">\n <a class=\"ml-5 certificate-btn\"\n [ngClass]=\"{'disable-btn': downloadCertificateLoading || content?.issuedCertificatesId}\"\n (click)=\"!downloadCertificateLoading && downloadCertificate(content?.issuedCertificatesId);$event.stopPropagation()\">\n <!-- <img src=\"fusion-assets/images/certificate-ico.svg\" width=\"24\" height=\"24\"> -->\n <span class=\"nodtranslate\">Certificate</span>\n <mat-icon *ngIf=\"!downloadCertificateLoading\"\n class=\"ml-2\">arrow_downward</mat-icon>\n <div class=\"center flex flex-middle certificate-loader\"\n *ngIf=\"downloadCertificateLoading\">\n <mat-spinner strokeWidth=\"2\" stroke=\"'white'\" class=\"white-spinner\"\n [diameter]=\"16\"></mat-spinner>\n </div>\n </a>\n </ng-container>\n </div>\n <!-- <circle-progress class=\"flex items-center progress\" [percent]=\"100\" [radius]=\"12\"\n [outerStrokeWidth]=\"3\" [innerStrokeWidth]=\"3\" [space]=\"-3\"\n [outerStrokeColor]=\"progressColor()\" [innerStrokeColor]=\"'rgba(0,0,0,.16)'\"\n [animation]=\"true\" [animationDuration]=\"300\" [showTitle]=\"false\" [showUnits]=\"false\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\"\n [backgroundOpacity]=\"0\" [backgroundGradient]=\"false\" [backgroundStrokeWidth]=\"3\"\n [showZeroOuterStroke]=false [backgroundPadding]=\"-9\" [startFromZero]=\"false\"\n [backgroundPadding]=\"0\" [imageHeight]=\"24\" [imageWidth]=\"24\" [showBackground]=\"false\"\n [outerStrokeLinecap]=\"'butt'\">\n </circle-progress> -->\n </ng-container>\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) < 2\">\n <div class=\"flex flex-1\">\n <div class=\"mt-2 mr-4 flex flex-1 flex-col progress-container\">\n <div class=\"flex flex-row justify-end w-full ws-mat-black-text\">\n <span class=\"mat-body-2 ws-mat-black-text nodtranslate\">\n {{getCompletionPercentage(content?.identifier)}}%</span>\n </div>\n\n <ws-widget-content-progress [contentId]=\"content?.progress\"\n [progress]=\"getCompletionPercentage(content?.identifier)\"\n [progressType]=\"'percentage'\" [customClassName]=\"'viewer-progress'\">\n </ws-widget-content-progress>\n </div>\n <ng-container *ngIf=\"content?.issuedCertificatesId\">\n <a class=\"ml-5 certificate-btn\"\n [ngClass]=\"{'disable-btn': downloadCertificateLoading || content?.issuedCertificatesId}\"\n (click)=\"!downloadCertificateLoading && downloadCertificate(content?.issuedCertificatesId);$event.stopPropagation()\">\n <!-- <img src=\"fusion-assets/images/certificate-ico.svg\" width=\"24\" height=\"24\"> -->\n <span class=\"nodtranslate\">Certificate</span>\n <mat-icon *ngIf=\"!downloadCertificateLoading\"\n class=\"ml-2\">arrow_downward</mat-icon>\n <div class=\"center flex flex-middle certificate-loader\"\n *ngIf=\"downloadCertificateLoading\">\n <mat-spinner strokeWidth=\"2\" stroke=\"'white'\" class=\"white-spinner\"\n [diameter]=\"16\"></mat-spinner>\n </div>\n </a>\n </ng-container>\n </div>\n </ng-container>\n </ng-container>\n </ng-container>\n\n <div class=\"see-all-container\">\n <a href=\"javascript:void(0)\" role=\"button\"\n (click)=\"content.viewChildren = !content.viewChildren; expandActive = false\"\n class=\"see-all-btn tab custom-chevron customicon\" mat-button>\n <mat-icon *ngIf=\"!content.viewChildren && !isModule\">keyboard_arrow_down</mat-icon>\n <mat-icon *ngIf=\"content.viewChildren && !isModule\">keyboard_arrow_up</mat-icon>\n <mat-icon *ngIf=\"!content.viewChildren && isModule\">add</mat-icon>\n <mat-icon *ngIf=\"content.viewChildren && isModule\">remove</mat-icon>\n </a>\n </div>\n </div>\n </div>\n </div>\n <div class=\"child-wrapper \" *ngIf=\"content.viewChildren\" [ngClass]=\"{'open': content.viewChildren,\n 'close': !content.viewChildren,\n 'course':!isModule,\n 'module': isModule}\" [@panelInOut]>\n <div class=\"children-container\" [ngClass]=\"{'module': isModule, '': !isModule}\">\n <ws-widget-app-toc-content-card-v2 [forPreview]=\"forPreview\" [componentName]=\"componentName\"\n [content]=\"child\" [expandAll]=\"expandAll\" [rootId]=\"rootId\" [batchId]=\"batchId\"\n [rootContentType]=\"rootContentType\" [index]=\"j+1\" [baseContentReadData]=\"baseContentReadData\"\n [pathSet]=\"pathSet\" [hierarchyMapData]=\"hierarchyMapData\" [batchData]=\"batchData\"\n [mlCourse]=\"mlCourse\" [parentMilestoneLocked]=\"isMilestoneLocked || isParentMilestoneLocked\"\n *ngFor=\"let child of content?.children; trackBy: contentTrackBy; let j= index;let isFirst = first\"\n [ngClass]=\"{'moduleCard': checkIsModule(child), 'resourceCard': !checkIsModule(child), 'first': isFirst}\">\n </ws-widget-app-toc-content-card-v2>\n </div>\n </div>\n </ng-container>\n</ng-template>\n\n\n<ng-container *ngIf=\"isPreAssessment\">\n <div class=\"collection-wrapper p-4 flex flex-col position-relative\" [ngClass]=\"{'open': check(content),\n 'course':!isModule, 'module': isModule,\n 'content-active': pathSet?.has(content.identifier)}\">\n <div class=\"card-collection w-auto sm:w-100 padding-right-xl\">\n <!-- <img class=\"card-thumbnail ws-mat-primary-lite-background\" [src]=\"content?.appIcon\" alt=\"Thumbnail\"\n (click)=\"content.viewChildren = !content.viewChildren\" [wsUtilsDefaultThumbnail]=\"defaultThumbnail\" /> -->\n <div class=\"flex flex-col flex-wrap flex-between width-expand pr-0 w-100 \">\n\n <div class=\"text-truncate\" [ngClass]=\"{'cursor-pointer': !isEnabled}\"\n (click)=\"content.viewChildren = !content.viewChildren\">\n <div class=\"flex sm:flex-row flex-wrap\">\n <ng-container>\n <ng-container\n *ngIf=\"!forPreview && content?.identifier && getCompletionPercentage(content?.identifier) ; else elseBlock\">\n\n <ng-container *ngIf=\"getCompletionStatus(content.identifier) == 2\">\n <div class=\"completed mr-2\">\n <div>\n <mat-icon class=\"completed-icon\" [color]=\"blue\">check_circle</mat-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) < 2\">\n\n <circle-progress class=\"flex items-center progress mr-1\"\n [percent]=\"getCompletionPercentage(content?.identifier)\" [radius]=\"10\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [space]=\"-2\"\n [outerStrokeColor]=\"progressColor2()\" [innerStrokeColor]=\"'rgba(0, 0, 0, 0.16)'\"\n [animation]=\"true\" [animationDuration]=\"250\" [showTitle]=\"false\"\n [showUnits]=\"false\" [showSubtitle]=\"false\" [showInnerStroke]=\"true\"\n [clockwise]=\"true\" [backgroundOpacity]=\"0\" [backgroundGradient]=\"false\"\n [backgroundStrokeWidth]=\"3\" matTooltip=\"In progress\" [showZeroOuterStroke]=false\n [backgroundPadding]=\"-7\" [startFromZero]=\"false\" [backgroundPadding]=\"0\"\n [imageHeight]=\"18\" [imageWidth]=\"18\" [showBackground]=\"false\"\n [outerStrokeLinecap]=\"'butt'\">\n </circle-progress>\n </ng-container>\n </ng-container>\n <ng-template #elseBlock>\n <circle-progress class=\"flex items-center progress mr-1\" [percent]=\"0\" [radius]=\"11\"\n [outerStrokeWidth]=\"2\" [innerStrokeWidth]=\"2\" [outerStrokeColor]=\"'#808080'\"\n [innerStrokeColor]=\"'#808080'\" [animation]=\"true\" [space]=\"-2\" [showUnits]=\"false\"\n [animationDuration]=\"250\" [showTitle]=\"false\" [backgroundPadding]=\"0\"\n [backgroundPadding]=\"-9\" [outerStrokeLinecap]=\"'butt'\" matTooltip=\"Not started\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\"\n [imageHeight]=\"22\" [imageWidth]=\"22\" [showBackground]=\"false\"></circle-progress>\n </ng-template>\n </ng-container>\n <div [ngClass]=\"{'collection-active-class': pathSet?.has(content?.identifier)}\"></div>\n <!-- <p class=\"margin-remove text-truncate mat-subheading-1 flex-auto font-bold nodtranslate\"\n [ngClass]=\"{'text-active': pathSet?.has(content.identifier)}\">\n {{index}}. {{ content?.name | truncate:50 }}\n </p> -->\n <a class=\"margin-remove text-truncate mat-subheading-1 flex-auto font-bold nodtranslate\"\n [class.disabled]=\"null\" [ngClass]=\"{'ml-3': isEnrolled}\"\n [routerLink]=\"(isAllowed && !forPreview && isEnabled) ? resourceLink.url : null\"\n [queryParams]=\"computedQueryParams\">\n <!-- {{content?.courseCategory}} -->\n <div [ngClass]=\"{'resource-active': pathSet?.has(content?.identifier)}\"></div>\n <div class=\"text-truncate \" [ngClass]=\"{'cursor-pointer': !isEnabled}\"\n (click)=\"raiseTelemetry(); changeResource()\">\n <div class=\"flex flex-col sm:flex-row flex-wrap\">\n <p class=\"margin-remove text-truncate mat-body-2 flex-auto font-bold nodtranslate\"\n [ngClass]=\"{'text-active': pathSet?.has(content?.identifier)}\"\n [matTooltip]=\"content?.name?.length > 50 ? content?.name : ''\"\n matTooltipPosition=\"above\">\n <!-- <mat-icon class=\"margin-right-xs radiobtn time-icon\">radio_button_unchecked </mat-icon> -->\n {{index}}. {{ content?.name | truncate:50 }}\n\n </p>\n <span class=\"content-type optional-span nodtranslate\"\n *ngIf=\"content?.optionalReading\">{{ 'playerbrief.optional' | translate |\n titlecase}} </span>\n </div>\n <!-- for default grey icons -->\n <ng-container *ngIf=\"!pathSet?.has(content?.identifier)\">\n <div class=\"resicons ws-mat-black60-text\">\n <img src=\"/assets/icons/content/grey/video.svg\" alt=\"Video\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'video/mp4' || content?.mimeType === 'video/x-youtube' ||\n content?.mimeType ==='application/x-mpegURL'\">\n <img src=\"/assets/icons/content/grey/audio.svg\" alt=\"Audio\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'audio/mpeg'\">\n <img src=\"/assets/icons/content/grey/pdf.svg\" alt=\"PDF\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/pdf'\">\n <!-- <img src=\"/assets/icons/content/grey/resource.svg\" alt=\"Survey\" class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/survey'\"> -->\n <img src=\"/assets/icons/content/grey/link.svg\" alt=\"InteractiveContent\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/vnd.ekstep.html-archive' || content?.mimeType === 'text/x-url'\">\n <img src=\"/assets/icons/content/grey/assessment.svg\" alt=\"Assessment\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/json' || content?.mimeType === 'application/quiz' || content?.mimeType === 'application/vnd.sunbird.questionset'\">\n <img src=\"/assets/icons/content/grey/image.svg\" alt=\"Image\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'image/png' || content?.mimeType === 'image/jpeg'\">\n <img src=\"/assets/icons/content/grey/content_copy.svg\" class=\"contenticon\"\n alt=\"Course\"\n *ngIf=\"content.mimeType === 'application/vnd.ekstep.content-collection' || content?.mimeType === 'application/survey'\">\n <img src=\"/assets/icons/content/grey/module.svg\"\n class=\"float-left margin-right-xs\" alt=\"offline sessions\"\n *ngIf=\"content.mimeType === 'application/offline'\">\n\n <ng-container *ngIf=\"content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE\">\n\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{\n content?.maxQuestions }} {{ 'playerbrief.questions' | translate |\n titlecase}}</span>\n </ng-container>\n <ng-container *ngIf=\"!(content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE)\">\n <span class=\"resourceDuration ws-mat-black60-text nodtranslate\">{{\n (content?.duration||\n hierarchyMapData[content?.identifier]?.expectedDuration || 0)|\n pipeDurationTransform:\n 'hms'\n }}</span>\n </ng-container>\n </div>\n </ng-container>\n\n <!-- for white icons when content highlighted -->\n <ng-container *ngIf=\"pathSet?.has(content?.identifier)\">\n <div class=\"resicons ws-mat-white-text\">\n <img src=\"/assets/icons/content/white/video.svg\" alt=\"Video\"\n class=\"float-left margin-right-xs\" *ngIf=\"content?.mimeType === 'video/mp4' || content?.mimeType === 'video/x-youtube' ||\n content?.mimeType ==='application/x-mpegURL'\">\n <img src=\"/assets/icons/content/white/audio.svg\" alt=\"Audio\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'audio/mpeg'\">\n <img src=\"/assets/icons/content/white/pdf.svg\" alt=\"PDF\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/pdf'\">\n <!-- <img src=\"/assets/icons/content/white/resource.svg\" alt=\"Survey\" class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/survey'\"> -->\n <img src=\"/assets/icons/content/white/link.svg\" alt=\"InteractiveContent\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/vnd.ekstep.html-archive' || content?.mimeType === 'text/x-url'\">\n <img src=\"/assets/icons/content/white/assessment.svg\" alt=\"Assessment\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'application/json' || content?.mimeType === 'application/quiz' || content?.mimeType === 'application/vnd.sunbird.questionset'\">\n <img src=\"/assets/icons/content/grey/image.svg\" alt=\"Image\"\n class=\"float-left margin-right-xs\"\n *ngIf=\"content?.mimeType === 'image/png' || content?.mimeType === 'image/jpeg'\">\n <img src=\"/assets/icons/content/white/content_copy.svg\" class=\"contenticon\"\n alt=\"Course\"\n *ngIf=\"content.mimeType === 'application/vnd.ekstep.content-collection' || content?.mimeType === 'application/survey'\">\n <img src=\"/assets/icons/content/white/module.svg\"\n class=\"float-left margin-right-xs\" alt=\"offline sessions\"\n *ngIf=\"content.mimeType === 'application/offline'\">\n <ng-container *ngIf=\"content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE\">\n <span class=\"resourceDuration ws-mat-white-text nodtranslate\">{{\n content?.maxQuestions }} {{ 'playerbrief.questions' | translate |\n titlecase}}</span>\n </ng-container>\n <ng-container *ngIf=\"!(content.primaryCategory === primaryCategory.FINAL_ASSESSMENT ||\n content.primaryCategory === primaryCategory.COMP_ASSESSMENT ||\n content.primaryCategory === primaryCategory.STANDALONE_ASSESSMENT ||\n content.primaryCategory === primaryCategory.PRACTICE_RESOURCE)\">\n <span class=\"resourceDuration ws-mat-white-text nodtranslate\">{{\n (content?.duration||\n hierarchyMapData[content?.identifier]?.expectedDuration || 0)|\n pipeDurationTransform:\n 'hms'\n }}</span>\n </ng-container>\n </div>\n </ng-container>\n </div>\n </a>\n <!-- <div class=\"type-container resource mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Resource'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Resource</span>\n </div>\n <div class=\"type-container module mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Collection'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Module</span>\n </div>\n <div class=\"type-container course mt-2 sm:mt-0\" *ngIf=\"content?.category === 'Course'\">\n <mat-icon class=\"mr-1 custom-icon rotate-90\">call_to_action</mat-icon>\n <span class=\"nodtranslate\">Course</span>\n </div> -->\n </div>\n\n </div>\n <!-- For course progress to be shown -->\n <ng-container>\n <ng-container\n *ngIf=\"!forPreview && content?.identifier && getCompletionPercentage(content?.identifier)\">\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) == 2\">\n <div class=\"flex flex-1\">\n <div class=\"mt-2 mr-4 flex flex-1 flex-col progress-container\">\n <div class=\"flex flex-row justify-end w-full \">\n <span class=\"mat-body-2 nodtranslate \">\n {{getCompletionPercentage(content?.identifier)}}%</span>\n </div>\n\n <ws-widget-content-progress [contentId]=\"content?.progress\"\n [progress]=\"getCompletionPercentage(content?.identifier)\"\n [progressType]=\"'percentage'\" [customClassName]=\"'viewer-progress'\">\n </ws-widget-content-progress>\n </div>\n <ng-container *ngIf=\"content?.issuedCertificatesId\">\n <a class=\"ml-5 certificate-btn\"\n [ngClass]=\"{'disable-btn': downloadCertificateLoading || content?.issuedCertificatesId}\"\n (click)=\"!downloadCertificateLoading && downloadCertificate(content?.issuedCertificatesId);$event.stopPropagation()\">\n <!-- <img src=\"fusion-assets/images/certificate-ico.svg\" width=\"24\" height=\"24\"> -->\n <span class=\"nodtranslate\">Certificate</span>\n <mat-icon *ngIf=\"!downloadCertificateLoading\"\n class=\"ml-2\">arrow_downward</mat-icon>\n <div class=\"center flex flex-middle certificate-loader\"\n *ngIf=\"downloadCertificateLoading\">\n <mat-spinner strokeWidth=\"2\" stroke=\"'white'\" class=\"white-spinner\"\n [diameter]=\"16\"></mat-spinner>\n </div>\n </a>\n </ng-container>\n </div>\n <!-- <circle-progress class=\"flex items-center progress\" [percent]=\"100\" [radius]=\"12\"\n [outerStrokeWidth]=\"3\" [innerStrokeWidth]=\"3\" [space]=\"-3\"\n [outerStrokeColor]=\"progressColor()\" [innerStrokeColor]=\"'rgba(0,0,0,.16)'\"\n [animation]=\"true\" [animationDuration]=\"300\" [showTitle]=\"false\" [showUnits]=\"false\"\n [showSubtitle]=\"false\" [showInnerStroke]=\"true\" [clockwise]=\"true\"\n [backgroundOpacity]=\"0\" [backgroundGradient]=\"false\" [backgroundStrokeWidth]=\"3\"\n [showZeroOuterStroke]=false [backgroundPadding]=\"-9\" [startFromZero]=\"false\"\n [backgroundPadding]=\"0\" [imageHeight]=\"24\" [imageWidth]=\"24\" [showBackground]=\"false\"\n [outerStrokeLinecap]=\"'butt'\">\n </circle-progress> -->\n </ng-container>\n <ng-container *ngIf=\"getCompletionStatus(content?.identifier) < 2\">\n <div class=\"flex flex-1\">\n <div class=\"mt-2 mr-4 flex flex-1 flex-col progress-container\">\n <div class=\"flex flex-row justify-end w-full ws-mat-black-text\">\n <span class=\"mat-body-2 ws-mat-black-text nodtranslate\">\n {{getCompletionPercentage(content?.identifier)}}%</span>\n </div>\n\n <ws-widget-content-progress [contentId]=\"content?.progress\"\n [progress]=\"getCompletionPercentage(content?.identifier)\"\n [progressType]=\"'percentage'\" [customClassName]=\"'viewer-progress'\">\n </ws-widget-content-progress>\n </div>\n <ng-container *ngIf=\"content?.issuedCertificatesId\">\n <a class=\"ml-5 certificate-btn\"\n [ngClass]=\"{'disable-btn': downloadCertificateLoading || content?.issuedCertificatesId}\"\n (click)=\"!downloadCertificateLoading && downloadCertificate(content?.issuedCertificatesId);$event.stopPropagation()\">\n <!-- <img src=\"fusion-assets/images/certificate-ico.svg\" width=\"24\" height=\"24\"> -->\n <span class=\"nodtranslate\">Certificate</span>\n <mat-icon *ngIf=\"!downloadCertificateLoading\"\n class=\"ml-2\">arrow_downward</mat-icon>\n <div class=\"center flex flex-middle certificate-loader\"\n *ngIf=\"downloadCertificateLoading\">\n <mat-spinner strokeWidth=\"2\" stroke=\"'white'\" class=\"white-spinner\"\n [diameter]=\"16\"></mat-spinner>\n </div>\n </a>\n </ng-container>\n </div>\n </ng-container>\n </ng-container>\n </ng-container>\n\n <!-- <div class=\"see-all-container\">\n <a href=\"javascript:void(0)\" role=\"button\"\n (click)=\"content.viewChildren = !content.viewChildren; expandActive = false\"\n class=\"see-all-btn tab custom-chevron customicon\" mat-button>\n <mat-icon *ngIf=\"!content.viewChildren && !isModule\">keyboard_arrow_down</mat-icon>\n <mat-icon *ngIf=\"content.viewChildren && !isModule\">keyboard_arrow_up</mat-icon>\n <mat-icon *ngIf=\"!content.viewChildren && isModule\">add</mat-icon>\n <mat-icon *ngIf=\"content.viewChildren && isModule\">remove</mat-icon>\n </a>\n </div> -->\n </div>\n </div>\n </div>\n\n</ng-container>", styles: [".customicon{position:absolute;top:-.5em;right:0}.customicon .mat-icon{color:#1a4ca1}a.disabled{pointer-events:none;cursor:default}span.optional-span{margin-left:8px;padding:0 6px;border-radius:2px;display:inline-block;background-color:#0074b6;color:#fff;font-size:12px}.card-collection{display:flex;align-items:center;border-radius:8px}.card-collection .card-thumbnail{height:100%;margin-right:12px;cursor:pointer;border-radius:8px 0 0}@media only screen and (max-width: 469px){.card-collection{flex-direction:column;align-items:flex-start!important}.card-collection .card-thumbnail{height:100%!important;width:100%!important}.card-collection .text-truncate{white-space:unset!important}}.tab:focus{outline:1px solid!important}.custom-chevron:focus{outline:0px solid!important}.resource-container{display:flex;align-items:flex-start;flex-direction:column}.resource-container .resource{padding:16px 16px 16px 0;width:100%}.resource-container .card-thumbnail{height:100%;cursor:pointer}.resource-container .img-container{position:relative;margin-right:12px}.resource-container .img-container ws-widget-content-progress{position:absolute;left:0;right:0;bottom:5px}@media only screen and (max-width: 469px){.resource-container{flex-direction:column;align-items:flex-start!important}.resource-container .card-thumbnail{height:100%!important;width:100%!important}.resource-container .text-truncate{white-space:unset!important}}.child-meta-container{margin-top:8px;display:flex}.child-meta-container .child-structure{display:flex;align-items:center;flex-wrap:wrap}.child-meta-container .child-structure span{margin-right:12px;text-align:center;margin-bottom:8px}.child-meta-container .child-structure .structure-icon{margin-right:12px}@media only screen and (max-width: 469px){.child-meta-container{margin-left:.5rem;justify-content:space-between}}.resource-container{display:flex;align-items:center}.resource-container ws-display-content-type-icon{display:flex;align-items:center}.resource-container .resource-meta{margin-left:12px;display:flex;justify-content:space-between;align-items:center}.completed-icon{color:#1a4ca1}.collection-wrapper{padding:1rem}.collection-wrapper.course.content-active{background-color:#1a4ca1;color:#fff}.collection-wrapper.course.content-active .period{background:#fff}.collection-wrapper.course.content-active .text-active,.collection-wrapper.course.content-active .icon-color,.collection-wrapper.course.content-active .customicon .mat-icon{color:#fff}.collection-wrapper.course.content-active .progress-container span{color:#fff!important}.collection-wrapper.course.content-active .milestone-description,.collection-wrapper.course.content-active .milestone-progress-text{color:#fff}.text-active{color:#1a4ca1}.text-active.font-bold{font-weight:600}.activeResource{background-color:#1a4ca1;color:#fff;padding-top:1rem!important;padding-bottom:1rem!important}.activeResource .text-active{color:#fff}.activeResource .text-active.font-bold{font-weight:600}.activeResource .resourceDuration,.activeResource .completed-icon{color:#fff}.collection-wrapper.open{border-bottom:1px solid rgba(0,0,0,.16)}.collection-wrapper.close{border:none}.child-wrapper.open{border-radius:0 0 8px 8px}.children-container .mat-subheading-1{font:500 16px/24px Lato!important}.children-container .resource-container{margin-bottom:16px}.children-container .resource-container .resource{padding:0}.children-container .resource-container .card-thumbnail{height:65px;align-self:center}.first.resourceCard:nth-child(1) .resource{margin-top:16px!important}.first.resourceCard:nth-child(1) .activeResource{margin-top:0!important}.children-container .resourceCard:last-child .resource-container:has(.activeResource){margin-bottom:0!important}.moduleCard:not(:last-child)>.collection-wrapper.close.module{border-bottom:4px solid rgba(0,0,0,.08);border-radius:0}.moduleCard:not(:last-child)>.collection-wrapper.open.module+.child-wrapper.open{border-bottom:4px solid rgba(0,0,0,.08);border-radius:0}.collection-wrapper.open.course+.child-wrapper.open .collection-wrapper.open.module+.child-wrapper.open{background-color:#eff3f9;border-bottom:4px solid rgba(0,0,0,.08);border-radius:0}.collection-wrapper.open.module+.child-wrapper.open{background-color:#eff3f9;border-radius:0;padding-bottom:8px}.content-heading{letter-spacing:0px;color:#222}.content-type{letter-spacing:0px}.time-icon{height:16px;width:16px;font-size:16px;vertical-align:middle}.time-icon.icon-color{color:#0009}.period{width:3px;height:3px;background:#0009;border-radius:4px}.time-value{letter-spacing:0px;color:#222;text-transform:lowercase}.see-all-container{position:absolute;right:16px;top:24px}.oval-white{background:#fff 0% 0% no-repeat padding-box;border-radius:8px;padding:2px 8px}.type-container{letter-spacing:0px;display:flex;align-items:center}.type-container .rotate-90{transform:rotate(-90deg)}.type-container .custom-icon{width:18px;height:18px;font-size:18px;margin-right:8px}.type-container.resource{color:#00a9f4}.type-container.module{color:#34d6a4}.type-container.course{color:#f58634}.no-mb{margin-bottom:0!important}.w-100{width:100%}.w-auto{width:auto}.progress-bar-thin{height:5px!important}.progress-bar-thin ::ng-deep .mat-progress-bar{height:5px}.progress-bar-thin ::ng-deep .theme-igot.day-mode .mat-progress-bar-buffer{background-color:transparent!important}.progress-bar-thin ::ng-deep .theme-igot.day-mode .mat-progress-bar-background{fill:transparent}.radiobtn{color:#00000029}.resicons img{width:22px;opacity:.5;margin-top:2px;vertical-align:sub}.certificate-btn{height:24px;background:#1a4ca1;display:flex;justify-content:center;align-items:center;padding:4px 11px;color:#fff;border-radius:20px;border:1px solid white;font:400 12px/16px Lato;cursor:pointer}.certificate-btn .mat-icon{fill:#fff;color:#fff;font-size:16px;height:auto;width:auto}.view-certificate-wrapper{display:flex;border-radius:4px;border:1.5px solid rgb(0,116,182);opacity:1;padding:8px}.collection-wrapper.course,.collection-wrapper.module,.resource-container .resource{padding-left:16px;box-sizing:border-box;width:100%;overflow:hidden}.children-container.module .resource-container .resource,.course .collection-wrapper.module{padding-left:24px;box-sizing:border-box;width:100%}.course .children-container.module .resource-container .resource{padding-left:32px;box-sizing:border-box;width:100%}.course .resource-container .resource{padding-left:24px}::ng-deep .white-spinner{stroke:#fff!important}.certificate-loader ::ng-deep .mat-progress-spinner circle,.mat-spinner circle{stroke:#fff}.lock-message{background:#fff4ec;color:#d13924;padding:10px;border-radius:4px;display:block!important;width:100%}.content-locking{padding:8px 12px;margin-top:8px;margin-left:0;margin-right:0;border-radius:4px;background:#fff4ec;display:flex!important;align-items:center;gap:8px;width:100%;box-sizing:border-box}.lock-icon{color:#f3962f;font-size:20px;flex-shrink:0}.unlock-message{background:#efffec;color:#0c9600;padding:10px}.unlock-icon{color:#0c9600}.download-btn{padding:4px 12px;text-underline-position:from-font;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none;cursor:pointer;border-radius:40px;color:#1b4ca1;font-weight:700;border:1px solid #1B4CA1;display:inline-block;pointer-events:auto;position:relative;z-index:1}.activeResource .download-btn.active{color:#fff;border:1px solid #fff}.milestone-badge{display:inline-block;background-color:#fefaf4;border:1px solid #EF951E;border-radius:16px;padding:2px 12px}.milestone-badge-text{font-size:12px;font-weight:500;color:#212121}.milestone-description{font-size:14px;line-height:1.5;color:#000000b3;margin:0;display:-webkit-box!important;-webkit-line-clamp:2!important;-webkit-box-orient:vertical!important;overflow:hidden!important;text-overflow:ellipsis!important;word-break:break-word!important;white-space:normal!important;max-width:100%!important}.milestone-progress{display:flex;align-items:center}.milestone-progress-text{font-size:14px;font-weight:500;color:#0009}.milestone-locked-message{display:flex;align-items:center;padding:8px 12px;background-color:#f3962f1a;border-left:3px solid #F3962F;border-radius:4px}.locked-criteria-text{font-size:13px;font-weight:400;color:#000000b3;line-height:1.4}.locked-text{font-size:14px;font-weight:500;color:#f3962f}.mandatory-text{color:#d13924!important}.view-achievement-container{display:flex;align-items:center}.view-achievement-btn{background-color:transparent;border:1.5px solid #1a4ca1;color:#1a4ca1;border-radius:20px;padding:6px 16px;font-size:14px;font-weight:500;cursor:pointer;display:flex;align-items:center;gap:8px;transition:all .2s ease;min-width:150px}.view-achievement-btn:hover:not(:disabled){background-color:#1a4ca1;color:#fff}.view-achievement-btn:disabled{opacity:.6;cursor:not-allowed}.view-achievement-btn .inline-spinner{display:inline-block}::ng-deep .multiline-tooltip{white-space:pre-wrap!important;max-width:400px!important;word-break:break-word!important;line-height:1.4!important}\n"] }]
7483
- }], ctorParameters: function () { return [{ type: i2$1.EventService }, { type: i1$3.MatLegacyDialog }, { type: i0.Renderer2 }, { type: CertificateService }, { type: AppTocService }, { type: i5.ContentLanguageService }, { type: ResourceDownloadHelperService }, { type: i2$1.ConfigurationsService }, { type: i7.MatLegacySnackBar }]; }, propDecorators: { content: [{
7562
+ }], ctorParameters: function () { return [{ type: i2$1.EventService }, { type: i1$3.MatLegacyDialog }, { type: i0.Renderer2 }, { type: CertificateService }, { type: AppTocService }, { type: i5.ContentLanguageService }, { type: ResourceDownloadHelperService }, { type: i2$1.ConfigurationsService }, { type: i7.MatLegacySnackBar }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { content: [{
7484
7563
  type: Input
7485
7564
  }], expandAll: [{
7486
7565
  type: Input
@@ -12505,17 +12584,46 @@ class ViewerUtilService {
12505
12584
  return this.http.get(`/apis/proxies/v8/action/content/v3/hierarchy/${id}?mode=${type}`);
12506
12585
  }
12507
12586
  updateContentHashMapForAssesstent(contentId, contentProgress) {
12508
- if (this.tocSvc.hashmap[contentId] &&
12509
- (!this.tocSvc.hashmap[contentId]['completionStatus'] || this.tocSvc.hashmap[contentId]['completionStatus'] < 2)) {
12510
- this.tocSvc.hashmap[contentId]['completionPercentage'] = contentProgress.completionPercentage;
12511
- this.tocSvc.hashmap[contentId]['completionStatus'] = Number(contentProgress.status) || 0;
12512
- this.tocSvc.hashmap = { ...this.tocSvc.hashmap };
12513
- // Trigger milestone lock recomputation - it will emit hashmapUpdated with both progress and lock changes
12514
- if (this.tocSvc.triggerMilestoneLockUpdate) {
12515
- this.tocSvc.triggerMilestoneLockUpdate();
12587
+ console.log('📊 [UPDATE HASHMAP] Updating assessment in hashmap:', {
12588
+ contentId,
12589
+ incomingProgress: contentProgress,
12590
+ currentHashmapData: this.tocSvc.hashmap[contentId] ? {
12591
+ completionPercentage: this.tocSvc.hashmap[contentId]['completionPercentage'],
12592
+ completionStatus: this.tocSvc.hashmap[contentId]['completionStatus'],
12593
+ status: this.tocSvc.hashmap[contentId]['status']
12594
+ } : 'not found'
12595
+ });
12596
+ if (this.tocSvc.hashmap[contentId]) {
12597
+ const currentStatus = this.tocSvc.hashmap[contentId]['completionStatus'] || 0;
12598
+ const newStatus = Number(contentProgress.status) || 0;
12599
+ // Update if not complete or if new status is higher
12600
+ if (currentStatus < 2 || newStatus >= currentStatus) {
12601
+ this.tocSvc.hashmap[contentId]['completionPercentage'] = contentProgress.completionPercentage;
12602
+ this.tocSvc.hashmap[contentId]['completionStatus'] = newStatus;
12603
+ this.tocSvc.hashmap[contentId]['status'] = newStatus;
12604
+ console.log('✅ [UPDATE HASHMAP] Updated assessment:', {
12605
+ contentId,
12606
+ name: this.tocSvc.hashmap[contentId]['name'],
12607
+ completionPercentage: contentProgress.completionPercentage,
12608
+ completionStatus: newStatus,
12609
+ status: newStatus
12610
+ });
12611
+ // Create new hashmap reference for Angular change detection
12612
+ this.tocSvc.hashmap = { ...this.tocSvc.hashmap };
12613
+ // Trigger milestone lock recomputation - it will emit hashmapUpdated with both progress and lock changes
12614
+ if (this.tocSvc.triggerMilestoneLockUpdate) {
12615
+ console.log('🔄 [UPDATE HASHMAP] Triggering milestone lock update after assessment update');
12616
+ this.tocSvc.triggerMilestoneLockUpdate();
12617
+ }
12618
+ // Emit to trigger viewer component refresh for Learning Pathways
12619
+ this.markAsCompleteSubject.next(true);
12620
+ }
12621
+ else {
12622
+ console.log('â„šī¸ [UPDATE HASHMAP] Skipping update - already complete or lower status');
12516
12623
  }
12517
- // Emit to trigger viewer component refresh for Learning Pathways
12518
- this.markAsCompleteSubject.next(true);
12624
+ }
12625
+ else {
12626
+ console.log('âš ī¸ [UPDATE HASHMAP] Content not found in hashmap:', contentId);
12519
12627
  }
12520
12628
  }
12521
12629
  getFormById(formId) {
@@ -12631,16 +12739,33 @@ class ViewerUtilService {
12631
12739
  .patch(`${this.API_ENDPOINTS.PRE_ASSESSMENT_STATE_UPDATE}`, req)
12632
12740
  .subscribe(noop, noop);
12633
12741
  }
12634
- if (this.tocSvc.hashmap && this.tocSvc.hashmap[contentId] && req.request.contents[0]) {
12635
- // Update hashmap if status changed
12636
- if (this.tocSvc.hashmap[contentId] &&
12637
- (!this.tocSvc.hashmap[contentId]['completionStatus'] || this.tocSvc.hashmap[contentId]['completionStatus'] < 2)) {
12742
+ console.log('đŸŽ¯ [PRE-ASSESSMENT QUIZ] Updating progress for:', contentId);
12743
+ console.log(' Status:', status, 'Completion:', req.request.contents[0].completionPercentage);
12744
+ // Update hashmap - create entry if it doesn't exist
12745
+ if (this.tocSvc.hashmap) {
12746
+ if (!this.tocSvc.hashmap[contentId]) {
12747
+ // Create new entry for pre-assessment if it doesn't exist
12748
+ console.log(' Creating new hashmap entry for pre-assessment');
12749
+ this.tocSvc.hashmap[contentId] = {
12750
+ identifier: contentId,
12751
+ completionPercentage: req.request.contents[0].completionPercentage,
12752
+ completionStatus: Number(req.request.contents[0].status) || 0,
12753
+ status: Number(req.request.contents[0].status) || 0,
12754
+ isPreAssessment: true
12755
+ };
12756
+ }
12757
+ else {
12758
+ // Update existing entry
12759
+ console.log(' Updating existing hashmap entry');
12638
12760
  this.tocSvc.hashmap[contentId]['completionPercentage'] = req.request.contents[0].completionPercentage;
12639
12761
  this.tocSvc.hashmap[contentId]['completionStatus'] = Number(req.request.contents[0].status) || 0;
12640
- this.tocSvc.hashmap = { ...this.tocSvc.hashmap };
12762
+ this.tocSvc.hashmap[contentId]['status'] = Number(req.request.contents[0].status) || 0;
12641
12763
  }
12764
+ console.log(' Hashmap entry after update:', this.tocSvc.hashmap[contentId]);
12765
+ this.tocSvc.hashmap = { ...this.tocSvc.hashmap };
12642
12766
  // ALWAYS trigger milestone lock recomputation when pre-assessment completes
12643
12767
  // This ensures milestone 1 unlocks immediately after pre-assessment completion
12768
+ console.log('🔄 [PRE-ASSESSMENT QUIZ] Triggering milestone lock update');
12644
12769
  if (this.tocSvc.triggerMilestoneLockUpdate) {
12645
12770
  this.tocSvc.triggerMilestoneLockUpdate();
12646
12771
  }
@@ -15587,9 +15712,19 @@ class AppTocV2Service {
15587
15712
  contentHeirarchy['preliminaryAssessmentDetail'].parent = contentHeirarchy.identifier;
15588
15713
  // Mark this as the pre-assessment for milestone locking logic
15589
15714
  contentHeirarchy['preliminaryAssessmentDetail'].isPreAssessment = true;
15715
+ console.log('🔍 [CONSTRUCT HIERARCHY] Setting isPreAssessment=true on preliminaryAssessmentDetail:', {
15716
+ id: contentHeirarchy['preliminaryAssessmentDetail'].identifier,
15717
+ name: contentHeirarchy['preliminaryAssessmentDetail'].name,
15718
+ isPreAssessment: contentHeirarchy['preliminaryAssessmentDetail'].isPreAssessment,
15719
+ parent: contentHeirarchy['preliminaryAssessmentDetail'].parent,
15720
+ primaryCategory: contentHeirarchy['preliminaryAssessmentDetail'].primaryCategory
15721
+ });
15590
15722
  contentHeirarchy['children'].push(contentHeirarchy['preliminaryAssessmentDetail']);
15591
15723
  leafNodes.push(contentReadData?.preliminaryAssessment || contentReadData?.preliminaryAssessmentDetail?.identifier);
15592
15724
  }
15725
+ else {
15726
+ console.log('âš ī¸ [CONSTRUCT HIERARCHY] No preliminaryAssessmentDetail found in contentReadData');
15727
+ }
15593
15728
  // Track milestone index for proper locking logic
15594
15729
  // All milestones are locked by default - unlocking is computed based on progress
15595
15730
  let milestoneIndex = 0;
@@ -21311,6 +21446,14 @@ class AppTocHomeV2Component {
21311
21446
  };
21312
21447
  this.tocSvc.getSelectedBatchData(this.batchData);
21313
21448
  this.tocSvc.mapSessionCompletionPercentage(this.batchData);
21449
+ // CRITICAL: For Learning Pathways, compute milestone locking status after enrollment
21450
+ // This ensures milestones are properly locked until pre-assessment is completed
21451
+ if (this.baseContentReadData?.courseCategory === 'Learning Pathway') {
21452
+ console.log('🔐 [ENROLLMENT] Computing milestone locking for Learning Pathway after enrollment');
21453
+ this.tocSvc.callHirarchyProgressHashmap(this.content);
21454
+ this.tocSvc.computeMilestoneLockingStatus(true);
21455
+ this.syncMilestoneLockStatus();
21456
+ }
21314
21457
  this.routerChangeHandler(true);
21315
21458
  this.openSnackbar('Enrolled Successfully!');
21316
21459
  this.disableEnrollBtn = false;