1- import { Component , OnInit } from '@angular/core' ;
1+ import { Component , OnInit , OnDestroy } from '@angular/core' ;
22import { equalArray } from 'src/app/util/util' ;
33import { LoaderService } from 'src/app/service/loader/data-loader.service' ;
44import * as d3 from 'd3' ;
5- import { Router } from '@angular/router' ;
5+ import { Router , ActivatedRoute } from '@angular/router' ;
6+ import { Location } from '@angular/common' ;
67import { MatChip } from '@angular/material/chips' ;
8+ import { Subject } from 'rxjs' ;
9+ import { takeUntil , distinctUntilChanged } from 'rxjs/operators' ;
710import * as md from 'markdown-it' ;
811import {
912 ModalMessageComponent ,
@@ -30,7 +33,7 @@ import { SettingsService } from 'src/app/service/settings/settings.service';
3033 templateUrl : './circular-heatmap.component.html' ,
3134 styleUrls : [ './circular-heatmap.component.css' ] ,
3235} )
33- export class CircularHeatmapComponent implements OnInit {
36+ export class CircularHeatmapComponent implements OnInit , OnDestroy {
3437 Routing : string = '/activity-description' ;
3538 markdown : md = md ( ) ;
3639 showOverlay : boolean = false ;
@@ -59,11 +62,16 @@ export class CircularHeatmapComponent implements OnInit {
5962 theme : string ;
6063 theme_colors ! : Record < string , string > ;
6164
65+ private destroy$ = new Subject < void > ( ) ;
66+
6267 constructor (
6368 private loader : LoaderService ,
6469 private sectorService : SectorService ,
6570 private settings : SettingsService ,
6671 private themeService : ThemeService ,
72+ private router : Router ,
73+ private route : ActivatedRoute ,
74+ private location : Location ,
6775 public modal : ModalMessageComponent
6876 ) {
6977 this . theme = this . themeService . getTheme ( ) ;
@@ -118,6 +126,9 @@ export class CircularHeatmapComponent implements OnInit {
118126 // For now, just draw the sectors (no activities yet)
119127 this . loadCircularHeatMap ( '#chart' , this . allSectors , this . dimensionLabels , this . maxLevel ) ;
120128 console . log ( `${ perfNow ( ) } : Page loaded: Circular Heatmap` ) ;
129+
130+ // Check if there's a URL fragment and open the corresponding activity
131+ this . checkUrlFragmentForActivity ( ) ;
121132 } )
122133 . catch ( err => {
123134 this . displayMessage ( new DialogInfo ( err . message , 'An error occurred' ) ) ;
@@ -127,7 +138,7 @@ export class CircularHeatmapComponent implements OnInit {
127138 } ) ;
128139 } ) ;
129140 // Reactively handle theme changes (if user toggles later)
130- this . themeService . theme$ . subscribe ( ( theme : string ) => {
141+ this . themeService . theme$ . pipe ( takeUntil ( this . destroy$ ) ) . subscribe ( ( theme : string ) => {
131142 const css = getComputedStyle ( document . body ) ;
132143 this . theme_colors = {
133144 background : css . getPropertyValue ( '--heatmap-background' ) . trim ( ) ,
@@ -141,6 +152,22 @@ export class CircularHeatmapComponent implements OnInit {
141152 } ) ;
142153 }
143154
155+ ngOnDestroy ( ) : void {
156+ this . destroy$ . next ( ) ;
157+ this . destroy$ . complete ( ) ;
158+ }
159+
160+ checkUrlFragmentForActivity ( ) {
161+ // Check if there's a URL fragment that might be an activity UUID
162+ this . route . fragment
163+ . pipe ( takeUntil ( this . destroy$ ) , distinctUntilChanged ( ) )
164+ . subscribe ( fragment => {
165+ if ( fragment && this . dataStore ) {
166+ this . navigateToActivityByUuid ( fragment ) ;
167+ }
168+ } ) ;
169+ }
170+
144171 displayMessage ( dialogInfo : DialogInfo ) {
145172 this . modal . openDialog ( dialogInfo ) ;
146173 }
@@ -245,6 +272,14 @@ export class CircularHeatmapComponent implements OnInit {
245272 return this . sectorService . getSectorProgress ( sector . activities ) ;
246273 }
247274
275+ onDependencyClicked ( activityName : string ) {
276+ console . log ( `${ perfNow ( ) } : Heat: Dependency clicked: '${ activityName } '` ) ;
277+ const activity = this . dataStore ?. activityStore ?. getActivityByName ( activityName ) ;
278+ if ( activity ?. uuid ) {
279+ this . navigateToActivityByUuid ( activity . uuid ) ;
280+ }
281+ }
282+
248283 loadCircularHeatMap (
249284 dom_element_to_append_to : string ,
250285 dataset : any ,
@@ -548,38 +583,71 @@ export class CircularHeatmapComponent implements OnInit {
548583 console . log ( `${ perfNow ( ) } : Heat: Card Panel closed: '${ activity . name } '` ) ;
549584 }
550585
551- openActivityDetails ( dimension : string , activityName : string ) {
586+ openActivityDetails ( uuid : string ) {
552587 // Find the activity in the selected sector
553- console . log ( `${ perfNow ( ) } : Heat: Open Overlay: '${ activityName } '` ) ;
554- if ( ! this . dataStore ) {
555- console . error ( `Data store is not initialized. Cannot open activity ${ activityName } ` ) ;
588+ if ( ! this . dataStore || ! this . dataStore . activityStore ) {
589+ console . error ( `Data store is not initialized. Cannot open activity ${ uuid } ` ) ;
556590 return ;
557591 }
558592 if ( ! this . showActivityCard || ! this . showActivityCard . activities ) {
559593 this . showOverlay = true ;
560594 return ;
561595 }
562- const activity = this . showActivityCard . activities . find (
563- ( a : any ) => a . activityName === activityName || a . name === activityName
564- ) ;
596+
597+ const activity : Activity = this . dataStore . activityStore . getActivityByUuid ( uuid ) ;
565598 if ( ! activity ) {
566599 this . showOverlay = true ;
567600 return ;
568601 }
602+
569603 // Prepare navigationExtras and details
570604 /* eslint-disable */
605+ console . log ( `${ perfNow ( ) } : Heat: Open Overlay: '${ activity . name } '` ) ;
571606 this . showActivityDetails = activity ;
572607 this . KnowledgeLabel = this . dataStore . getMetaString ( 'knowledgeLabels' , activity . difficultyOfImplementation . knowledge ) ;
573608 this . TimeLabel = this . dataStore . getMetaString ( 'labels' , activity . difficultyOfImplementation . time ) ;
574609 this . ResourceLabel = this . dataStore . getMetaString ( 'labels' , activity . difficultyOfImplementation . resources ) ;
575610 this . UsefulnessLabel = this . dataStore . getMetaString ( 'labels' , activity . usefulness ) ;
576611 this . showOverlay = true ;
612+
613+ // Update URL with activity UUID as fragment
614+ if ( activity . uuid ) {
615+ this . router . navigate ( [ ] , {
616+ relativeTo : this . route ,
617+ fragment : activity . uuid ,
618+ queryParamsHandling : 'preserve'
619+ } ) ;
620+ }
577621 /* eslint-enable */
578622 }
579623
624+ navigateToActivityByUuid ( uuid : string ) {
625+ console . log ( `${ perfNow ( ) } : Heat: Attempting to open activity with UUID: ${ uuid } ` ) ;
626+ if ( ! this . dataStore || ! this . dataStore . activityStore ) {
627+ console . error ( 'Data store is not initialized. Cannot open activity by UUID' ) ;
628+ return ;
629+ }
630+ const activity : Activity = this . dataStore . activityStore . getActivityByUuid ( uuid ) ;
631+ const sector = this . allSectors . find ( s => s . activities . some ( a => a . uuid === uuid ) ) ;
632+ if ( activity && sector ) {
633+ this . selectedSector = sector ;
634+ this . showActivityCard = sector ;
635+ this . openActivityDetails ( activity . uuid ) ;
636+ } else {
637+ // Only close the overlay, do not update the URL
638+ this . showOverlay = false ;
639+ console . warn ( `Heat: Activity with UUID ${ uuid } not found.` ) ;
640+ }
641+ }
642+
580643 closeOverlay ( ) {
644+ // Clear the URL fragment when closing overlay
645+ this . router . navigate ( [ ] , {
646+ relativeTo : this . route ,
647+ fragment : undefined ,
648+ queryParamsHandling : 'preserve' ,
649+ } ) ;
581650 this . showOverlay = false ;
582- // console.log(`${perfNow()}: Heat: Close Overlay: '${this.old_activityDetails.name}'`);
583651 }
584652
585653 toggleFilters ( ) {
0 commit comments