11import { ChangeDetectorRef , Component , Inject , OnChanges , SimpleChanges , OnInit } from '@angular/core' ;
2- import { Observable , of as observableOf , Subscription , tap } from 'rxjs' ;
2+ import { Observable , of as observableOf , Subscription , tap , Subject } from 'rxjs' ;
33import { Field , Option , SubmissionCcLicence } from '../../../core/submission/models/submission-cc-license.model' ;
44import {
55 getFirstCompletedRemoteData , getFirstSucceededRemoteDataPayload ,
66 getRemoteDataPayload
77} from '../../../core/shared/operators' ;
8- import { distinctUntilChanged , filter , map , take } from 'rxjs/operators' ;
8+ import { distinctUntilChanged , filter , map , take , debounceTime , switchMap , startWith , shareReplay } from 'rxjs/operators' ;
99import { SubmissionCcLicenseDataService } from '../../../core/submission/submission-cc-license-data.service' ;
1010import { NgbModal , NgbModalRef } from '@ng-bootstrap/ng-bootstrap' ;
1111import { renderSectionFor } from '../sections-decorator' ;
@@ -89,6 +89,11 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
8989 */
9090 private _isLastPage : boolean ;
9191
92+ /**
93+ * Subject to trigger CC license link updates with debouncing
94+ */
95+ private ccLicenseLinkTrigger$ = new Subject < void > ( ) ;
96+
9297 /**
9398 * The Creative Commons link saved in the workspace item.
9499 */
@@ -129,14 +134,20 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
129134
130135 ngOnInit ( ) : void {
131136 super . ngOnInit ( ) ;
132- if ( hasNoValue ( this . ccLicenseLink$ ) ) {
133- this . ccLicenseLink$ = this . getCcLicenseLink$ ( ) ;
134- }
137+ // Initialize the debounced license link observable
138+ this . ccLicenseLink$ = this . ccLicenseLinkTrigger$ . pipe (
139+ startWith ( undefined ) , // Start with initial trigger
140+ debounceTime ( 300 ) , // Debounce rapid clicks
141+ switchMap ( ( ) => this . getCcLicenseLink$ ( ) || observableOf ( null ) ) ,
142+ shareReplay ( 1 ) , // Cache the latest result
143+ distinctUntilChanged ( )
144+ ) ;
135145 }
136146
137147 ngOnChanges ( changes : SimpleChanges ) : void {
138148 if ( hasValue ( changes . sectionData ) || hasValue ( changes . submissionCcLicenses ) ) {
139- this . ccLicenseLink$ = this . getCcLicenseLink$ ( ) ;
149+ // Trigger the debounced license link update
150+ this . ccLicenseLinkTrigger$ . next ( ) ;
140151 }
141152 }
142153
@@ -164,7 +175,8 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
164175 } ,
165176 uri : undefined ,
166177 } ) ;
167- this . ccLicenseLink$ = this . getCcLicenseLink$ ( ) ;
178+ // Trigger the debounced license link update
179+ this . ccLicenseLinkTrigger$ . next ( ) ;
168180 }
169181
170182 /**
@@ -196,7 +208,8 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
196208 } ,
197209 accepted : false ,
198210 } ) ;
199- this . ccLicenseLink$ = this . getCcLicenseLink$ ( ) ;
211+ // Trigger the debounced license link update
212+ this . ccLicenseLinkTrigger$ . next ( ) ;
200213 }
201214
202215 /**
@@ -272,6 +285,8 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
272285 */
273286 onSectionDestroy ( ) : void {
274287 this . subscriptions . forEach ( ( subscription ) => subscription . unsubscribe ( ) ) ;
288+ // Complete the subject to prevent memory leaks
289+ this . ccLicenseLinkTrigger$ . complete ( ) ;
275290 }
276291
277292 /**
@@ -284,18 +299,35 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
284299 filter ( ( sectionState ) => {
285300 return isNotEmpty ( sectionState ) && ( isNotEmpty ( sectionState . data ) || isNotEmpty ( sectionState . errorsToShow ) ) ;
286301 } ) ,
287- distinctUntilChanged ( ) ,
302+ distinctUntilChanged ( ( prev , curr ) => {
303+ // More precise comparison to prevent unnecessary updates
304+ const prevData = prev ?. data as WorkspaceitemSectionCcLicenseObject ;
305+ const currData = curr ?. data as WorkspaceitemSectionCcLicenseObject ;
306+ return prevData ?. accepted === currData ?. accepted &&
307+ prevData ?. uri === currData ?. uri &&
308+ JSON . stringify ( prevData ?. ccLicense ) === JSON . stringify ( currData ?. ccLicense ) ;
309+ } ) ,
288310 map ( ( sectionState ) => sectionState . data as WorkspaceitemSectionCcLicenseObject ) ,
289311 ) . subscribe ( ( data ) => {
290- if ( this . data . accepted !== data . accepted ) {
312+ const wasAccepted = this . data . accepted ;
313+ const wasUri = this . data . uri ;
314+
315+ // Only process if acceptance state actually changed
316+ if ( wasAccepted !== data . accepted && data . accepted !== undefined ) {
291317 const path = this . pathCombiner . getPath ( 'uri' ) ;
292- if ( data . accepted ) {
293- this . getCcLicenseLink$ ( ) . pipe (
294- take ( 1 ) ,
295- ) . subscribe ( ( link ) => {
296- this . operationsBuilder . add ( path , link . toString ( ) , false , true ) ;
297- } ) ;
298- } else if ( ! ! this . data . uri ) {
318+ if ( data . accepted && ! wasAccepted ) {
319+ // Only add URI if we're switching from not accepted to accepted
320+ const licenseLink$ = this . getCcLicenseLink$ ( ) ;
321+ if ( licenseLink$ ) {
322+ licenseLink$ . pipe (
323+ take ( 1 ) ,
324+ filter ( link => ! ! link && link !== wasUri ) // Only proceed if link exists and is different
325+ ) . subscribe ( ( link ) => {
326+ this . operationsBuilder . add ( path , link . toString ( ) , false , true ) ;
327+ } ) ;
328+ }
329+ } else if ( ! data . accepted && wasAccepted && ! ! this . data . uri ) {
330+ // Only remove URI if we're switching from accepted to not accepted
299331 this . operationsBuilder . remove ( path ) ;
300332 }
301333 }
@@ -305,12 +337,12 @@ export class SubmissionSectionCcLicensesComponent extends SectionModelComponent
305337 getFirstCompletedRemoteData ( ) ,
306338 getRemoteDataPayload ( )
307339 ) . subscribe ( ( remoteData ) => {
308- if ( remoteData === undefined || remoteData . values . length === 0 ) {
309- // No value configured, use blank value (International jurisdiction)
310- this . defaultJurisdiction = '' ;
311- } else {
312- this . defaultJurisdiction = remoteData . values [ 0 ] ;
313- }
340+ if ( remoteData === undefined || remoteData . values . length === 0 ) {
341+ // No value configured, use blank value (International jurisdiction)
342+ this . defaultJurisdiction = '' ;
343+ } else {
344+ this . defaultJurisdiction = remoteData . values [ 0 ] ;
345+ }
314346 } )
315347 ) ;
316348 this . loadCcLicences ( ) ;
0 commit comments