@sunbird-cb/toc 0.0.11 ā 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/_collection/_common/content-toc/app-toc-content-card-v2/app-toc-content-card-v2.component.mjs +20 -6
- package/esm2022/lib/_services/widget-content.service.mjs +3 -3
- package/esm2022/lib/components/app-toc-home-v2/app-toc-home-v2.component.mjs +6 -12
- package/esm2022/lib/services/app-toc-v2.service.mjs +2 -12
- package/esm2022/lib/services/app-toc.service.mjs +130 -99
- package/fesm2022/sunbird-cb-toc.mjs +156 -127
- package/fesm2022/sunbird-cb-toc.mjs.map +1 -1
- package/lib/_collection/_common/content-toc/app-toc-content-card-v2/app-toc-content-card-v2.component.d.ts +2 -0
- package/lib/_collection/_common/content-toc/app-toc-content-card-v2/app-toc-content-card-v2.component.d.ts.map +1 -1
- package/lib/components/app-toc-home-v2/app-toc-home-v2.component.d.ts.map +1 -1
- package/lib/services/app-toc-v2.service.d.ts.map +1 -1
- package/lib/services/app-toc.service.d.ts +2 -1
- package/lib/services/app-toc.service.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -701,11 +701,11 @@ class WidgetContentService {
|
|
|
701
701
|
const forPreview = window.location.href.includes('/public/') || window.location.href.includes('&preview=true');
|
|
702
702
|
if (primaryCategory && this.isResource(primaryCategory)) {
|
|
703
703
|
if (!forPreview) {
|
|
704
|
-
url = `/apis/proxies/v8/
|
|
704
|
+
url = `/apis/proxies/v8/action/content/v3/read/${contentId}`;
|
|
705
705
|
}
|
|
706
706
|
else {
|
|
707
707
|
if (window.location.href.includes('editMode=true') && window.location.href.includes('_rc')) {
|
|
708
|
-
url = `/apis/proxies/v8/
|
|
708
|
+
url = `/apis/proxies/v8/action/content/v3/read/${contentId}`;
|
|
709
709
|
}
|
|
710
710
|
else {
|
|
711
711
|
url = `/api/content/v1/read/${contentId}`;
|
|
@@ -1635,7 +1635,6 @@ class AppTocService {
|
|
|
1635
1635
|
resetContentData() {
|
|
1636
1636
|
this.hashmap = {};
|
|
1637
1637
|
this.hashmapUpdated.next(null);
|
|
1638
|
-
console.log('Content data cleared - hashmap reset');
|
|
1639
1638
|
}
|
|
1640
1639
|
fetchContentParents(contentId) {
|
|
1641
1640
|
// return this.http.get<NsContent.IContentMinimal[]>(
|
|
@@ -1977,7 +1976,14 @@ class AppTocService {
|
|
|
1977
1976
|
child.primaryCategory === NsContent.EPrimaryCategory.COMP_ASSESSMENT;
|
|
1978
1977
|
const isLearningPathway = rootCourseCategory === 'Learning Pathway';
|
|
1979
1978
|
// Check if content is mandatory (isMandatory flag or mandatory property)
|
|
1980
|
-
|
|
1979
|
+
// By default, courses are mandatory unless isMandatory is explicitly false
|
|
1980
|
+
let isMandatory = true;
|
|
1981
|
+
if (typeof child.isMandatory !== 'undefined') {
|
|
1982
|
+
isMandatory = child.isMandatory !== false;
|
|
1983
|
+
}
|
|
1984
|
+
else if (typeof child.mandatory !== 'undefined') {
|
|
1985
|
+
isMandatory = child.mandatory !== false;
|
|
1986
|
+
}
|
|
1981
1987
|
// Use passed parentId (from iteration context) or fallback to child?.parent (from API)
|
|
1982
1988
|
// This ensures nested children (e.g., assessments inside courses) have correct parent references
|
|
1983
1989
|
const correctParentId = hierarchyData.identifier || child?.parent;
|
|
@@ -2023,14 +2029,6 @@ class AppTocService {
|
|
|
2023
2029
|
child.primaryCategory === 'Standalone Assessment' ||
|
|
2024
2030
|
child.mimeType === 'application/vnd.sunbird.questionset';
|
|
2025
2031
|
if (isAssessment) {
|
|
2026
|
-
console.log(`š Adding assessment to hashmap: "${child.name}"`, {
|
|
2027
|
-
identifier: child.identifier,
|
|
2028
|
-
primaryCategory: child.primaryCategory,
|
|
2029
|
-
parent: correctParentId,
|
|
2030
|
-
originalParent: child?.parent,
|
|
2031
|
-
parentName: hierarchyData.name,
|
|
2032
|
-
parentCategory: hierarchyData.primaryCategory
|
|
2033
|
-
});
|
|
2034
2032
|
}
|
|
2035
2033
|
this.hashmap[child.identifier] = localMap;
|
|
2036
2034
|
});
|
|
@@ -2162,11 +2160,6 @@ class AppTocService {
|
|
|
2162
2160
|
console.warn('ā ļø Hashmap is empty - cannot compute milestone locking');
|
|
2163
2161
|
return;
|
|
2164
2162
|
}
|
|
2165
|
-
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
2166
|
-
console.log('š MILESTONE LOCKING COMPUTATION START');
|
|
2167
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
2168
|
-
console.log('User enrolled:', isEnrolled);
|
|
2169
|
-
console.log('Hashmap size:', Object.keys(this.hashmap).length);
|
|
2170
2163
|
// STEP 1: Find all milestones and sort by index
|
|
2171
2164
|
const milestoneEntries = Object.keys(this.hashmap)
|
|
2172
2165
|
.filter(key => {
|
|
@@ -2184,11 +2177,8 @@ class AppTocService {
|
|
|
2184
2177
|
return numA - numB;
|
|
2185
2178
|
});
|
|
2186
2179
|
if (milestoneEntries.length === 0) {
|
|
2187
|
-
console.log('ā¹ļø No milestones found - skipping milestone locking');
|
|
2188
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
2189
2180
|
return;
|
|
2190
2181
|
}
|
|
2191
|
-
console.log(`\nš Found ${milestoneEntries.length} milestones:`);
|
|
2192
2182
|
milestoneEntries.forEach((id, i) => {
|
|
2193
2183
|
console.log(` M${i + 1}: ${this.hashmap[id].name || id}`);
|
|
2194
2184
|
});
|
|
@@ -2207,32 +2197,30 @@ class AppTocService {
|
|
|
2207
2197
|
});
|
|
2208
2198
|
this.hashmap = { ...this.hashmap };
|
|
2209
2199
|
this.hashmapUpdated.next({ timestamp: Date.now(), hashmap: this.hashmap });
|
|
2210
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
2211
2200
|
return;
|
|
2212
2201
|
}
|
|
2213
2202
|
// STEP 3: Check pre-assessment completion
|
|
2214
2203
|
const isPreAssessmentCompleted = this.checkPreAssessmentCompletion();
|
|
2215
|
-
console.log(
|
|
2204
|
+
console.log('š [MILESTONE LOCK] Pre-assessment completed:', isPreAssessmentCompleted ? 'ā
YES' : 'ā NO');
|
|
2216
2205
|
// STEP 4: Compute locking for each milestone
|
|
2217
|
-
console.log('\nš Computing milestone locks:');
|
|
2218
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
2219
2206
|
milestoneEntries.forEach((milestoneId, index) => {
|
|
2220
2207
|
const milestone = this.hashmap[milestoneId];
|
|
2221
2208
|
if (!milestone)
|
|
2222
2209
|
return;
|
|
2223
2210
|
const milestoneNum = index + 1;
|
|
2224
|
-
console.log(`\nš Milestone ${milestoneNum} (${milestone.name || milestoneId}):`);
|
|
2225
2211
|
// MILESTONE 1: Unlocks when pre-assessment complete
|
|
2226
2212
|
if (index === 0) {
|
|
2227
2213
|
const isLocked = !isPreAssessmentCompleted;
|
|
2228
2214
|
this.hashmap[milestoneId].computedIsLocked = isLocked;
|
|
2229
2215
|
this.hashmap[milestoneId].unlockMessage = isLocked ?
|
|
2230
2216
|
'Complete the preliminary assessment to unlock this milestone' : '';
|
|
2231
|
-
console.log(
|
|
2232
|
-
|
|
2217
|
+
console.log(`š [MILESTONE 1] ${milestone.name}:`, {
|
|
2218
|
+
isPreAssessmentCompleted,
|
|
2219
|
+
isLocked: isLocked ? 'š LOCKED' : 'š UNLOCKED',
|
|
2220
|
+
unlockMessage: this.hashmap[milestoneId].unlockMessage
|
|
2221
|
+
});
|
|
2233
2222
|
// For unlocked M1, check assessment locking
|
|
2234
2223
|
if (!isLocked) {
|
|
2235
|
-
console.log(` ā Checking assessment lock...`);
|
|
2236
2224
|
this.computeAssessmentLockingInMilestone(milestoneId);
|
|
2237
2225
|
}
|
|
2238
2226
|
else {
|
|
@@ -2251,27 +2239,38 @@ class AppTocService {
|
|
|
2251
2239
|
const prevStatus = Number(previousMilestone.status) || 0;
|
|
2252
2240
|
const prevCompletedLeafNodes = Number(previousMilestone.completedLeafNodesCount) || 0;
|
|
2253
2241
|
const prevLeafNodesCount = Number(previousMilestone.leafNodesCount) || 0;
|
|
2242
|
+
console.log(`š [MILESTONE ${milestoneNum}] Checking if previous M${index} is complete:`, {
|
|
2243
|
+
previousMilestoneName: previousMilestone.name,
|
|
2244
|
+
completionPercentage: prevCompletionPct,
|
|
2245
|
+
completionStatus: prevCompletionStatus,
|
|
2246
|
+
status: prevStatus,
|
|
2247
|
+
completedLeafNodes: prevCompletedLeafNodes,
|
|
2248
|
+
leafNodesCount: prevLeafNodesCount
|
|
2249
|
+
});
|
|
2254
2250
|
let previousMilestoneComplete = prevCompletionPct >= 100 ||
|
|
2255
2251
|
prevCompletionStatus === 2 ||
|
|
2256
2252
|
prevStatus === 2 ||
|
|
2257
2253
|
(prevLeafNodesCount > 0 && prevCompletedLeafNodes >= prevLeafNodesCount);
|
|
2254
|
+
console.log(` Primary check result: ${previousMilestoneComplete ? 'ā
COMPLETE' : 'ā INCOMPLETE'}`);
|
|
2258
2255
|
// Fallback: Check individual items
|
|
2259
2256
|
if (!previousMilestoneComplete) {
|
|
2257
|
+
console.log(` Running fallback check (mandatory content + assessment)...`);
|
|
2260
2258
|
const isPreviousMilestoneAssessmentComplete = this.checkMilestoneAssessmentComplete(previousMilestoneId);
|
|
2261
2259
|
const isPreviousMilestoneMandatoryComplete = this.checkMilestoneMandatoryContentComplete(previousMilestoneId);
|
|
2262
2260
|
previousMilestoneComplete = isPreviousMilestoneAssessmentComplete && isPreviousMilestoneMandatoryComplete;
|
|
2263
|
-
console.log(` Fallback check: mandatory=${isPreviousMilestoneMandatoryComplete}, assessment=${isPreviousMilestoneAssessmentComplete}`);
|
|
2261
|
+
console.log(` Fallback check: mandatory=${isPreviousMilestoneMandatoryComplete}, assessment=${isPreviousMilestoneAssessmentComplete}, result=${previousMilestoneComplete}`);
|
|
2264
2262
|
}
|
|
2265
2263
|
const isLocked = !previousMilestoneComplete;
|
|
2266
2264
|
this.hashmap[milestoneId].computedIsLocked = isLocked;
|
|
2267
2265
|
this.hashmap[milestoneId].unlockMessage = isLocked ?
|
|
2268
2266
|
`Complete all mandatory content and assessment in Milestone ${index} to unlock this milestone` : '';
|
|
2269
|
-
console.log(` ${
|
|
2270
|
-
|
|
2271
|
-
|
|
2267
|
+
console.log(` š [MILESTONE ${milestoneNum}] ${milestone.name}:`, {
|
|
2268
|
+
previousMilestoneComplete: previousMilestoneComplete ? 'ā
YES' : 'ā NO',
|
|
2269
|
+
isLocked: isLocked ? 'š LOCKED' : 'š UNLOCKED',
|
|
2270
|
+
unlockMessage: this.hashmap[milestoneId].unlockMessage
|
|
2271
|
+
});
|
|
2272
2272
|
// For unlocked milestones, check assessment locking
|
|
2273
2273
|
if (!isLocked) {
|
|
2274
|
-
console.log(` ā Checking assessment lock...`);
|
|
2275
2274
|
this.computeAssessmentLockingInMilestone(milestoneId);
|
|
2276
2275
|
}
|
|
2277
2276
|
else {
|
|
@@ -2285,6 +2284,43 @@ class AppTocService {
|
|
|
2285
2284
|
console.log(` š LOCKED (previous milestone not found)`);
|
|
2286
2285
|
}
|
|
2287
2286
|
});
|
|
2287
|
+
// STEP 4.5: Debug log milestone leaf nodes and their completion status
|
|
2288
|
+
console.log('\nš Milestone Leaf Nodes Completion Status:');
|
|
2289
|
+
milestoneEntries.forEach((milestoneId, index) => {
|
|
2290
|
+
const milestone = this.hashmap[milestoneId];
|
|
2291
|
+
if (!milestone)
|
|
2292
|
+
return;
|
|
2293
|
+
console.log(` Leaf Nodes Array:`, milestone.leafNodes);
|
|
2294
|
+
console.log(` Leaf Nodes Count: ${milestone.leafNodesCount}`);
|
|
2295
|
+
console.log(` Completed Leaf Nodes Count: ${milestone.completedLeafNodesCount || 0}`);
|
|
2296
|
+
console.log(` Completion %: ${milestone.completionPercentage}%`);
|
|
2297
|
+
if (milestone.leafNodes && milestone.leafNodes.length > 0) {
|
|
2298
|
+
console.log(` Individual Leaf Node Status:`);
|
|
2299
|
+
milestone.leafNodes.forEach((leafId, i) => {
|
|
2300
|
+
const leafData = this.hashmap[leafId];
|
|
2301
|
+
if (leafData) {
|
|
2302
|
+
const isComplete = leafData.completionStatus === 2 ||
|
|
2303
|
+
leafData.status === 2 ||
|
|
2304
|
+
(leafData.completionPercentage && leafData.completionPercentage >= 100) ||
|
|
2305
|
+
(leafData.progress && leafData.progress >= 100);
|
|
2306
|
+
console.log(` ${i + 1}. ${leafData.name || leafId} [${leafData.primaryCategory}]:`, {
|
|
2307
|
+
id: leafId,
|
|
2308
|
+
completionStatus: leafData.completionStatus,
|
|
2309
|
+
status: leafData.status,
|
|
2310
|
+
completionPercentage: leafData.completionPercentage,
|
|
2311
|
+
progress: leafData.progress,
|
|
2312
|
+
isComplete: isComplete ? 'ā
' : 'ā'
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2315
|
+
else {
|
|
2316
|
+
console.log(` ${i + 1}. ā ļø Leaf node ${leafId} NOT FOUND in hashmap`);
|
|
2317
|
+
}
|
|
2318
|
+
});
|
|
2319
|
+
}
|
|
2320
|
+
else {
|
|
2321
|
+
console.log(` ā ļø No leaf nodes defined for this milestone`);
|
|
2322
|
+
}
|
|
2323
|
+
});
|
|
2288
2324
|
// STEP 5: Compute parent milestone lock status for ALL children
|
|
2289
2325
|
console.log('\nš Computing parent milestone locks for all children...');
|
|
2290
2326
|
Object.keys(this.hashmap).forEach(key => {
|
|
@@ -2316,9 +2352,7 @@ class AppTocService {
|
|
|
2316
2352
|
}
|
|
2317
2353
|
});
|
|
2318
2354
|
// STEP 6: Trigger hashmap update
|
|
2319
|
-
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
2320
2355
|
console.log('ā
Milestone locking computation COMPLETE');
|
|
2321
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
2322
2356
|
this.hashmap = { ...this.hashmap };
|
|
2323
2357
|
this.hashmapUpdated.next({ timestamp: Date.now(), hashmap: this.hashmap });
|
|
2324
2358
|
}
|
|
@@ -2343,6 +2377,7 @@ class AppTocService {
|
|
|
2343
2377
|
* Pre-assessment is typically a Course Assessment at the root level of Learning Pathway (before milestones)
|
|
2344
2378
|
*/
|
|
2345
2379
|
checkPreAssessmentCompletion() {
|
|
2380
|
+
console.log('š [PRE-ASSESSMENT] Starting pre-assessment completion check');
|
|
2346
2381
|
// Find the Learning Pathway root
|
|
2347
2382
|
let learningPathwayId = null;
|
|
2348
2383
|
for (const key of Object.keys(this.hashmap)) {
|
|
@@ -2352,100 +2387,79 @@ class AppTocService {
|
|
|
2352
2387
|
break;
|
|
2353
2388
|
}
|
|
2354
2389
|
}
|
|
2355
|
-
|
|
2356
|
-
// PRIORITY 1: Look for items explicitly marked as pre-assessment
|
|
2390
|
+
// 1. Look for items explicitly marked as pre-assessment
|
|
2357
2391
|
for (const key of Object.keys(this.hashmap)) {
|
|
2358
2392
|
const item = this.hashmap[key];
|
|
2359
2393
|
if (item.isPreAssessment === true) {
|
|
2360
|
-
// Must check for actual completion - not just any value
|
|
2361
2394
|
const isCompleted = (item.completionStatus === 2 || item.status === 2 ||
|
|
2362
2395
|
(item.completionPercentage !== undefined && item.completionPercentage >= 100) ||
|
|
2363
2396
|
(item.progress !== undefined && item.progress >= 100));
|
|
2364
|
-
console.log(`ā
Pre-assessment found (isPreAssessment flag): ${key}`, {
|
|
2365
|
-
name: item.name,
|
|
2366
|
-
completionStatus: item.completionStatus,
|
|
2367
|
-
status: item.status,
|
|
2368
|
-
completionPercentage: item.completionPercentage,
|
|
2369
|
-
progress: item.progress,
|
|
2370
|
-
isCompleted,
|
|
2371
|
-
// Show ALL fields to debug what's available
|
|
2372
|
-
allData: JSON.stringify(item, null, 2)
|
|
2373
|
-
});
|
|
2374
|
-
// Pre-assessment exists - return its completion status (true/false)
|
|
2375
2397
|
return isCompleted;
|
|
2376
2398
|
}
|
|
2377
2399
|
}
|
|
2378
|
-
//
|
|
2379
|
-
// Check for first non-milestone child of Learning Pathway
|
|
2400
|
+
// 2. Find pre-assessment in hashmap - direct child of Learning Pathway that is NOT a milestone
|
|
2380
2401
|
for (const key of Object.keys(this.hashmap)) {
|
|
2381
2402
|
const item = this.hashmap[key];
|
|
2382
|
-
// Check if this is a direct child of the Learning Pathway
|
|
2383
2403
|
if (item.parent !== learningPathwayId)
|
|
2384
2404
|
continue;
|
|
2385
|
-
|
|
2386
|
-
if (item.isMilestone)
|
|
2405
|
+
if (item.isMilestone || item.primaryCategory === 'Milestone')
|
|
2387
2406
|
continue;
|
|
2388
|
-
// This is a non-milestone direct child - it's the pre-assessment
|
|
2389
|
-
// Must check for actual completion - not just any value
|
|
2390
2407
|
const isCompleted = (item.completionStatus === 2 || item.status === 2 ||
|
|
2391
2408
|
(item.completionPercentage !== undefined && item.completionPercentage >= 100) ||
|
|
2392
2409
|
(item.progress !== undefined && item.progress >= 100));
|
|
2393
|
-
console.log(`ā
Pre-assessment found (first non-milestone child): ${key}`, {
|
|
2394
|
-
name: item.name,
|
|
2395
|
-
completionStatus: item.completionStatus,
|
|
2396
|
-
status: item.status,
|
|
2397
|
-
completionPercentage: item.completionPercentage,
|
|
2398
|
-
progress: item.progress,
|
|
2399
|
-
isCompleted,
|
|
2400
|
-
// Show ALL fields to debug what's available
|
|
2401
|
-
allData: JSON.stringify(item, null, 2)
|
|
2402
|
-
});
|
|
2403
|
-
// Pre-assessment exists - return its completion status (true/false)
|
|
2404
2410
|
return isCompleted;
|
|
2405
2411
|
}
|
|
2406
|
-
//
|
|
2407
|
-
// This
|
|
2408
|
-
|
|
2409
|
-
// 2. The hashmap hasn't been populated yet (should lock M1 until data is ready)
|
|
2410
|
-
// To be safe, check if ANY children exist at all
|
|
2411
|
-
const hasAnyChildren = Object.keys(this.hashmap).some(key => this.hashmap[key].parent === learningPathwayId);
|
|
2412
|
-
if (!hasAnyChildren) {
|
|
2413
|
-
// Hashmap not populated yet - lock M1 until data is ready
|
|
2414
|
-
console.log('ā ļø No children found in hashmap yet - locking M1 until data is ready');
|
|
2415
|
-
return false;
|
|
2416
|
-
}
|
|
2417
|
-
// Hashmap is populated but no pre-assessment found - allow M1 to unlock
|
|
2418
|
-
console.log('No pre-assessment found in fully populated hashmap - allowing M1 to be unlocked by default');
|
|
2419
|
-
return true;
|
|
2412
|
+
// 3. If we reach here, enforce: M1 is always locked until pre-assessment is completed
|
|
2413
|
+
// This prevents accidental unlocking if pre-assessment node is missing or not flagged
|
|
2414
|
+
return false;
|
|
2420
2415
|
}
|
|
2421
2416
|
/**
|
|
2422
2417
|
* Check if a milestone's assessment is completed
|
|
2423
|
-
*
|
|
2418
|
+
* ONLY checks the milestone assessment (Course Assessment that is a direct child of the milestone)
|
|
2419
|
+
* Does NOT check assessments nested inside courses within the milestone
|
|
2424
2420
|
*/
|
|
2425
2421
|
checkMilestoneAssessmentComplete(milestoneId) {
|
|
2426
2422
|
const milestone = this.hashmap[milestoneId];
|
|
2427
|
-
|
|
2423
|
+
let foundMilestoneAssessment = false;
|
|
2424
|
+
let isMilestoneAssessmentComplete = false;
|
|
2425
|
+
console.log(`š Checking milestone assessment for: ${milestoneId}`);
|
|
2426
|
+
// Check all items in hashmap that are DIRECT children of this milestone
|
|
2428
2427
|
for (const key of Object.keys(this.hashmap)) {
|
|
2429
2428
|
const item = this.hashmap[key];
|
|
2430
|
-
//
|
|
2431
|
-
|
|
2429
|
+
// CRITICAL: Only check DIRECT children (parent === milestoneId)
|
|
2430
|
+
if (item.parent !== milestoneId)
|
|
2431
|
+
continue;
|
|
2432
|
+
// Check if this is a milestone assessment (Course Assessment as direct child of milestone)
|
|
2433
|
+
const isMilestoneAssessment = item.primaryCategory === 'Course Assessment' ||
|
|
2432
2434
|
item.primaryCategory === 'Final Assessment' ||
|
|
2433
|
-
item.primaryCategory === '
|
|
2434
|
-
|
|
2435
|
-
item.courseCategory === 'Final Assessment' ||
|
|
2436
|
-
(item.name && item.name.toLowerCase().includes('assessment'));
|
|
2437
|
-
if (!isAssessmentType)
|
|
2435
|
+
item.primaryCategory === 'Standalone Assessment';
|
|
2436
|
+
if (!isMilestoneAssessment)
|
|
2438
2437
|
continue;
|
|
2439
|
-
//
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2438
|
+
// Found the milestone assessment
|
|
2439
|
+
foundMilestoneAssessment = true;
|
|
2440
|
+
const isCompleted = item.completionStatus === 2 || item.status === 2 || item.completionPercentage >= 100 || item.progress >= 100;
|
|
2441
|
+
console.log(`š Found milestone assessment (direct child): ${item.name || key}`, {
|
|
2442
|
+
milestoneId,
|
|
2443
|
+
assessmentId: key,
|
|
2444
|
+
completionStatus: item.completionStatus,
|
|
2445
|
+
status: item.status,
|
|
2446
|
+
completionPercentage: item.completionPercentage,
|
|
2447
|
+
isCompleted
|
|
2448
|
+
});
|
|
2449
|
+
if (isCompleted) {
|
|
2450
|
+
isMilestoneAssessmentComplete = true;
|
|
2445
2451
|
}
|
|
2452
|
+
// Usually only one milestone assessment per milestone, but check all just in case
|
|
2446
2453
|
}
|
|
2447
|
-
//
|
|
2448
|
-
|
|
2454
|
+
// CRITICAL LOGIC:
|
|
2455
|
+
// - If NO milestone assessment found ā consider complete (no assessment requirement)
|
|
2456
|
+
// - If milestone assessment found ā it must be completed
|
|
2457
|
+
if (!foundMilestoneAssessment) {
|
|
2458
|
+
console.log(`ā¹ļø No milestone assessment (direct child) found for ${milestoneId} - considering as complete`);
|
|
2459
|
+
return true;
|
|
2460
|
+
}
|
|
2461
|
+
console.log(`${isMilestoneAssessmentComplete ? 'ā
' : 'ā'} Milestone ${milestoneId} assessment: ${isMilestoneAssessmentComplete ? 'COMPLETE' : 'INCOMPLETE'}`);
|
|
2462
|
+
return isMilestoneAssessmentComplete;
|
|
2449
2463
|
}
|
|
2450
2464
|
/**
|
|
2451
2465
|
* Check if a milestone's mandatory content is completed
|
|
@@ -2455,6 +2469,7 @@ class AppTocService {
|
|
|
2455
2469
|
const milestone = this.hashmap[milestoneId];
|
|
2456
2470
|
let mandatoryCount = 0;
|
|
2457
2471
|
let completedMandatoryCount = 0;
|
|
2472
|
+
console.log(`š Checking mandatory content for milestone: ${milestoneId}`);
|
|
2458
2473
|
// Check all items in hashmap that are direct children of this milestone (courses)
|
|
2459
2474
|
for (const key of Object.keys(this.hashmap)) {
|
|
2460
2475
|
const item = this.hashmap[key];
|
|
@@ -2467,20 +2482,36 @@ class AppTocService {
|
|
|
2467
2482
|
// Skip assessments - they're checked separately
|
|
2468
2483
|
const isAssessment = item.primaryCategory === 'Course Assessment' ||
|
|
2469
2484
|
item.primaryCategory === 'Final Assessment' ||
|
|
2485
|
+
item.primaryCategory === 'Standalone Assessment' ||
|
|
2470
2486
|
item.courseCategory === 'Course Assessment' ||
|
|
2471
2487
|
(item.name && item.name.toLowerCase().includes('assessment'));
|
|
2472
2488
|
if (isAssessment)
|
|
2473
2489
|
continue;
|
|
2474
|
-
// Check if this content is mandatory
|
|
2475
|
-
|
|
2490
|
+
// CRITICAL: Check if this content is mandatory
|
|
2491
|
+
// By default, courses ARE mandatory unless explicitly marked as optional (isMandatory: false)
|
|
2492
|
+
const isMandatory = item.isMandatory !== false;
|
|
2493
|
+
if (isMandatory) {
|
|
2476
2494
|
mandatoryCount++;
|
|
2477
2495
|
const isCompleted = item.completionStatus === 2 || item.status === 2 || item.completionPercentage >= 100 || item.progress >= 100;
|
|
2496
|
+
console.log(` š Mandatory item: ${item.name || key}`, {
|
|
2497
|
+
isMandatory: item.isMandatory,
|
|
2498
|
+
completionStatus: item.completionStatus,
|
|
2499
|
+
status: item.status,
|
|
2500
|
+
completionPercentage: item.completionPercentage,
|
|
2501
|
+
progress: item.progress,
|
|
2502
|
+
isCompleted,
|
|
2503
|
+
hasCompletionStatus: item.completionStatus !== undefined,
|
|
2504
|
+
hasStatus: item.status !== undefined,
|
|
2505
|
+
hasCompletionPercentage: item.completionPercentage !== undefined,
|
|
2506
|
+
hasProgress: item.progress !== undefined
|
|
2507
|
+
});
|
|
2478
2508
|
if (isCompleted) {
|
|
2479
2509
|
completedMandatoryCount++;
|
|
2480
2510
|
}
|
|
2481
2511
|
}
|
|
2482
2512
|
}
|
|
2483
2513
|
const allComplete = mandatoryCount === 0 || completedMandatoryCount >= mandatoryCount;
|
|
2514
|
+
console.log(`š Milestone ${milestoneId} mandatory status: ${completedMandatoryCount}/${mandatoryCount} complete = ${allComplete ? 'ā
ALL COMPLETE' : 'ā INCOMPLETE'}`);
|
|
2484
2515
|
return allComplete;
|
|
2485
2516
|
}
|
|
2486
2517
|
/**
|
|
@@ -6318,6 +6349,7 @@ class AppTocContentCardV2Component {
|
|
|
6318
6349
|
this._cachedIsMilestoneAssessment = false;
|
|
6319
6350
|
this._cachedIsMilestoneAssessmentLocked = false;
|
|
6320
6351
|
this._cachedResourceLink = { url: '', queryParams: {} };
|
|
6352
|
+
this._cachedMilestoneCompletedCount = 0;
|
|
6321
6353
|
this._cacheInitialized = false;
|
|
6322
6354
|
}
|
|
6323
6355
|
ngOnInit() {
|
|
@@ -6331,7 +6363,6 @@ class AppTocContentCardV2Component {
|
|
|
6331
6363
|
// Subscribe to hashmap updates to recompute cached properties when progress changes
|
|
6332
6364
|
this.hashmapUpdatedSubscription = this.appTocSvc.hashmapUpdated$.subscribe((update) => {
|
|
6333
6365
|
if (update && update.hashmap) {
|
|
6334
|
-
console.log('š Hashmap updated, recomputing cached properties for:', this.content?.identifier);
|
|
6335
6366
|
// IMPORTANT: Update hierarchyMapData with the latest hashmap from the service
|
|
6336
6367
|
// This ensures the component uses the updated data, not the stale @Input reference
|
|
6337
6368
|
this.hierarchyMapData = update.hashmap;
|
|
@@ -6385,6 +6416,7 @@ class AppTocContentCardV2Component {
|
|
|
6385
6416
|
this._cachedIsMilestoneAssessment = this.computeIsMilestoneAssessment();
|
|
6386
6417
|
this._cachedIsMilestoneAssessmentLocked = this.computeIsMilestoneAssessmentLocked();
|
|
6387
6418
|
this._cachedResourceLink = this.computeResourceLink();
|
|
6419
|
+
this._cachedMilestoneCompletedCount = this.computeMilestoneCompletedCount();
|
|
6388
6420
|
this._cacheInitialized = true;
|
|
6389
6421
|
}
|
|
6390
6422
|
computeIsResource() {
|
|
@@ -7189,6 +7221,12 @@ class AppTocContentCardV2Component {
|
|
|
7189
7221
|
return this.computeIsMilestone();
|
|
7190
7222
|
}
|
|
7191
7223
|
getMilestoneCompletedCount() {
|
|
7224
|
+
if (this._cacheInitialized) {
|
|
7225
|
+
return this._cachedMilestoneCompletedCount;
|
|
7226
|
+
}
|
|
7227
|
+
return this.computeMilestoneCompletedCount();
|
|
7228
|
+
}
|
|
7229
|
+
computeMilestoneCompletedCount() {
|
|
7192
7230
|
if (!this.content || !this.hierarchyMapData) {
|
|
7193
7231
|
return 0;
|
|
7194
7232
|
}
|
|
@@ -7199,8 +7237,15 @@ class AppTocContentCardV2Component {
|
|
|
7199
7237
|
let completedCount = 0;
|
|
7200
7238
|
milestoneData.leafNodes.forEach((leafId) => {
|
|
7201
7239
|
const leafData = this.hierarchyMapData[leafId];
|
|
7202
|
-
if (leafData
|
|
7203
|
-
|
|
7240
|
+
if (leafData) {
|
|
7241
|
+
// CRITICAL: Check multiple completion indicators
|
|
7242
|
+
const isCompleted = leafData.completionStatus === 2 ||
|
|
7243
|
+
leafData.status === 2 ||
|
|
7244
|
+
(leafData.completionPercentage && leafData.completionPercentage >= 100) ||
|
|
7245
|
+
(leafData.progress && leafData.progress >= 100);
|
|
7246
|
+
if (isCompleted) {
|
|
7247
|
+
completedCount++;
|
|
7248
|
+
}
|
|
7204
7249
|
}
|
|
7205
7250
|
});
|
|
7206
7251
|
return completedCount;
|
|
@@ -7371,7 +7416,7 @@ class AppTocContentCardV2Component {
|
|
|
7371
7416
|
return element.scrollHeight > element.clientHeight;
|
|
7372
7417
|
}
|
|
7373
7418
|
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 }); }
|
|
7374
|
-
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 items-center justify-between\">\n <div>\n <span class=\"milestone-progress-text nodtranslate\">{{getMilestoneCompletedCount()}} of\n {{content?.leafNodesCount || 0}} completed</span>\n </div>\n <!-- View Achievement Button for completed milestones - Outside clickable area -->\n <div *ngIf=\"isMilestone && isEnrolled && (getCompletionPercentage(content?.identifier) >= 100 || getCompletionStatus(content?.identifier) === 2)\"\n class=\"view-achievement-container mt-2\">\n <button type=\"button\" class=\"view-achievement-btn\" [disabled]=\"achievementLoading\"\n (click)=\"viewMilestoneAchievement($event)\">\n <span *ngIf=\"!achievementLoading\">View Achievement</span>\n <mat-spinner *ngIf=\"achievementLoading\" [diameter]=\"16\" \n [strokeWidth]=\"2\" color=\"primary\" class=\"inline-spinner\"></mat-spinner>\n </button>\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: [
|
|
7419
|
+
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: [
|
|
7375
7420
|
trigger('panelInOut', [
|
|
7376
7421
|
transition('void => *', [
|
|
7377
7422
|
style({ transform: 'translateY(-10%)', opacity: '0' }),
|
|
@@ -7395,7 +7440,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
7395
7440
|
animate(200, style({ transform: 'translateY(-10%)', opacity: '0' }))
|
|
7396
7441
|
])
|
|
7397
7442
|
])
|
|
7398
|
-
], 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 items-center justify-between\">\n <div>\n <span class=\"milestone-progress-text nodtranslate\">{{getMilestoneCompletedCount()}} of\n {{content?.leafNodesCount || 0}} completed</span>\n </div>\n <!-- View Achievement Button for completed milestones - Outside clickable area -->\n <div *ngIf=\"isMilestone && isEnrolled && (getCompletionPercentage(content?.identifier) >= 100 || getCompletionStatus(content?.identifier) === 2)\"\n class=\"view-achievement-container mt-2\">\n <button type=\"button\" class=\"view-achievement-btn\" [disabled]=\"achievementLoading\"\n (click)=\"viewMilestoneAchievement($event)\">\n <span *ngIf=\"!achievementLoading\">View Achievement</span>\n <mat-spinner *ngIf=\"achievementLoading\" [diameter]=\"16\" \n [strokeWidth]=\"2\" color=\"primary\" class=\"inline-spinner\"></mat-spinner>\n </button>\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"] }]
|
|
7443
|
+
], 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"] }]
|
|
7399
7444
|
}], 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: [{
|
|
7400
7445
|
type: Input
|
|
7401
7446
|
}], expandAll: [{
|
|
@@ -15567,7 +15612,7 @@ class AppTocV2Service {
|
|
|
15567
15612
|
milestoneIndex++;
|
|
15568
15613
|
});
|
|
15569
15614
|
contentHeirarchy['leafNodes'] = [...leafNodes];
|
|
15570
|
-
|
|
15615
|
+
contentHeirarchy['leafNodesCount'] = leafNodes.length;
|
|
15571
15616
|
return contentHeirarchy;
|
|
15572
15617
|
}
|
|
15573
15618
|
mapModuleCount(content) {
|
|
@@ -15583,9 +15628,6 @@ class AppTocV2Service {
|
|
|
15583
15628
|
}
|
|
15584
15629
|
}
|
|
15585
15630
|
mapContentHierarchyProgressUpdate(contentHeirarchyData, enrollmentListData) {
|
|
15586
|
-
console.log('=== mapContentHierarchyProgressUpdate ===');
|
|
15587
|
-
console.log('Content hierarchy:', contentHeirarchyData?.name, contentHeirarchyData?.identifier);
|
|
15588
|
-
console.log('Enrollment list data:', enrollmentListData);
|
|
15589
15631
|
if (contentHeirarchyData && contentHeirarchyData.children) {
|
|
15590
15632
|
let totalLeafNodes = 0;
|
|
15591
15633
|
let totalCompletedLeafNodes = 0;
|
|
@@ -15702,13 +15744,6 @@ class AppTocV2Service {
|
|
|
15702
15744
|
}
|
|
15703
15745
|
// Try both contentId and collectionId as the API response may use either field
|
|
15704
15746
|
const nodeEnrollData = enrollment?.contentList?.find((ele) => ele?.contentId === node.identifier || ele?.collectionId === node.identifier);
|
|
15705
|
-
console.log(`Updating node progress for ${node.identifier} (${node.name}):`, {
|
|
15706
|
-
hasEnrollment: !!enrollment,
|
|
15707
|
-
hasNodeEnrollData: !!nodeEnrollData,
|
|
15708
|
-
nodeEnrollData,
|
|
15709
|
-
currentCompletionStatus: node.completionStatus,
|
|
15710
|
-
currentCompletionPercentage: node.completionPercentage
|
|
15711
|
-
});
|
|
15712
15747
|
if (enrollment && nodeEnrollData && nodeEnrollData.status < 2) {
|
|
15713
15748
|
node.completionPercentage = nodeEnrollData.completionPercentage || nodeEnrollData.progress || 0;
|
|
15714
15749
|
node.completionStatus = Number(nodeEnrollData.status) || 0;
|
|
@@ -20842,7 +20877,6 @@ class AppTocHomeV2Component {
|
|
|
20842
20877
|
}
|
|
20843
20878
|
}
|
|
20844
20879
|
if (this.baseContentReadData?.courseCategory === 'Learning Pathway') {
|
|
20845
|
-
console.log('User enrolled in LP - computing milestone locks with isEnrolled=true');
|
|
20846
20880
|
this.tocSvc.callHirarchyProgressHashmap(this.content);
|
|
20847
20881
|
this.tocSvc.computeMilestoneLockingStatus(true);
|
|
20848
20882
|
this.syncMilestoneLockStatus();
|
|
@@ -20875,7 +20909,6 @@ class AppTocHomeV2Component {
|
|
|
20875
20909
|
this.tocSvc.callHirarchyProgressHashmap(this.content);
|
|
20876
20910
|
// For Learning Pathways, compute milestone locking when not enrolled (all locked)
|
|
20877
20911
|
if (this.baseContentReadData?.courseCategory === 'Learning Pathway') {
|
|
20878
|
-
console.log('User not enrolled - computing milestone locks');
|
|
20879
20912
|
this.tocSvc.computeMilestoneLockingStatus(false);
|
|
20880
20913
|
this.syncMilestoneLockStatus();
|
|
20881
20914
|
}
|
|
@@ -21509,7 +21542,6 @@ class AppTocHomeV2Component {
|
|
|
21509
21542
|
this.hashmapUpdatedSubscription = this.tocSvc.hashmapUpdated$.subscribe((update) => {
|
|
21510
21543
|
if (update && this.baseContentReadData?.courseCategory === 'Learning Pathway') {
|
|
21511
21544
|
const isEnrolled = this.userEnrollmentList && this.userEnrollmentList.length > 0;
|
|
21512
|
-
console.log('Hashmap updated at:', update.timestamp, 'Enrolled:', isEnrolled, 'Syncing milestone lock status...');
|
|
21513
21545
|
// Sync content tree's isLocked with the updated hashmap values
|
|
21514
21546
|
this.syncMilestoneLockStatus();
|
|
21515
21547
|
}
|
|
@@ -21633,18 +21665,17 @@ class AppTocHomeV2Component {
|
|
|
21633
21665
|
if (this.baseContentReadData?.courseCategory === 'Learning Pathway') {
|
|
21634
21666
|
return new Promise((resolve) => {
|
|
21635
21667
|
const content = this.baseContentReadData;
|
|
21668
|
+
// STEP 1: Construct hierarchy structure
|
|
21636
21669
|
this.content = this.appTocV2Svc.constructHeirarchyData(content);
|
|
21637
|
-
// Update progress with latest enrollment data
|
|
21670
|
+
// STEP 2: Update progress with latest enrollment data
|
|
21638
21671
|
this.appTocV2Svc.mapContentHierarchyProgressUpdate(this.content, this.userEnrollmentList);
|
|
21639
|
-
// Create hashmap
|
|
21672
|
+
// STEP 3: Create hashmap from updated hierarchy (this should preserve completion status)
|
|
21640
21673
|
this.tocSvc.callHirarchyProgressHashmap(this.content);
|
|
21641
|
-
console.log('Learning Pathway hashmap updated:', this.tocSvc.hashmap);
|
|
21642
21674
|
// Check if user is enrolled
|
|
21643
21675
|
const isEnrolled = this.userEnrollmentList && this.userEnrollmentList.length > 0;
|
|
21644
|
-
// Compute milestone locking status with enrollment status and updated progress data
|
|
21676
|
+
// STEP 4: Compute milestone locking status with enrollment status and updated progress data
|
|
21645
21677
|
this.tocSvc.computeMilestoneLockingStatus(isEnrolled);
|
|
21646
|
-
|
|
21647
|
-
// Sync content tree's isLocked with computed values
|
|
21678
|
+
// STEP 5: Sync content tree's isLocked with computed values
|
|
21648
21679
|
this.syncMilestoneLockStatus();
|
|
21649
21680
|
this.getOrgIdForShare();
|
|
21650
21681
|
this.getTocStructure();
|
|
@@ -21728,7 +21759,6 @@ class AppTocHomeV2Component {
|
|
|
21728
21759
|
if (oldLocked !== child.isLocked) {
|
|
21729
21760
|
hasChanges = true;
|
|
21730
21761
|
}
|
|
21731
|
-
console.log(`Synced lock status for ${child.name} (${child.identifier}): isLocked=${child.isLocked}`);
|
|
21732
21762
|
}
|
|
21733
21763
|
}
|
|
21734
21764
|
});
|
|
@@ -21743,7 +21773,6 @@ class AppTocHomeV2Component {
|
|
|
21743
21773
|
return;
|
|
21744
21774
|
}
|
|
21745
21775
|
try {
|
|
21746
|
-
console.log('š Refreshing milestone locks from hashmap...');
|
|
21747
21776
|
// Check if user is enrolled
|
|
21748
21777
|
const isEnrolled = this.userEnrollmentList && this.userEnrollmentList.length > 0;
|
|
21749
21778
|
// Recompute milestone locking status from existing hashmap
|