From 79e779190aec358ab48f1c86fdcb613f0a6f8e6e Mon Sep 17 00:00:00 2001 From: Erwin <111194281+Erwin-N@users.noreply.github.com> Date: Sun, 22 Mar 2026 08:40:41 +0100 Subject: [PATCH 1/4] Task/eliminate OnDestroy lifecycle hook from create or update activity dialog component (#6623) * Eliminate OnDestroy lifecycle hook --- ...ate-or-update-activity-dialog.component.ts | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts index c7cd63191..9cc312b25 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts @@ -20,9 +20,10 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - Inject, - OnDestroy + DestroyRef, + Inject } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormBuilder, FormGroup, @@ -46,8 +47,8 @@ import { AssetClass, Tag, Type } from '@prisma/client'; import { isAfter, isToday } from 'date-fns'; import { addIcons } from 'ionicons'; import { calendarClearOutline, refreshOutline } from 'ionicons/icons'; -import { EMPTY, Subject } from 'rxjs'; -import { catchError, delay, takeUntil } from 'rxjs/operators'; +import { EMPTY } from 'rxjs'; +import { catchError, delay } from 'rxjs/operators'; import { CreateOrUpdateActivityDialogParams } from './interfaces/interfaces'; import { ActivityType } from './types/activity-type.type'; @@ -75,7 +76,7 @@ import { ActivityType } from './types/activity-type.type'; styleUrls: ['./create-or-update-activity-dialog.scss'], templateUrl: 'create-or-update-activity-dialog.html' }) -export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { +export class GfCreateOrUpdateActivityDialogComponent { public activityForm: FormGroup; public assetClassOptions: AssetClassSelectorOption[] = Object.keys(AssetClass) @@ -101,13 +102,12 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { public typesTranslationMap = new Map(); public Validators = Validators; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateActivityDialogParams, private dataService: DataService, private dateAdapter: DateAdapter, + private destroyRef: DestroyRef, public dialogRef: MatDialogRef, private formBuilder: FormBuilder, @Inject(MAT_DATE_LOCALE) private locale: string, @@ -133,7 +133,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.dataService .fetchPortfolioHoldings() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ holdings }) => { this.defaultLookupItems = holdings .filter(({ assetSubClass }) => { @@ -237,7 +237,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { // Slightly delay until the more specific form control value changes have // completed delay(300), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(async () => { if ( @@ -284,7 +284,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.activityForm .get('assetClass') - .valueChanges.pipe(takeUntil(this.unsubscribeSubject)) + .valueChanges.pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((assetClass) => { const assetSubClasses = ASSET_CLASS_MAPPING.get(assetClass) ?? []; @@ -335,7 +335,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { if (newTag && this.hasPermissionToCreateOwnTag) { this.dataService .postTag({ ...newTag, userId: this.data.user.id }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((tag) => { this.activityForm.get('tags').setValue( tags.map((currentTag) => { @@ -349,7 +349,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); }); } @@ -357,7 +357,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.activityForm .get('type') - .valueChanges.pipe(takeUntil(this.unsubscribeSubject)) + .valueChanges.pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((type: ActivityType) => { if ( type === 'VALUABLE' || @@ -465,7 +465,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { dataSource: this.data.activity?.SymbolProfile?.dataSource, symbol: this.data.activity?.SymbolProfile?.symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ marketPrice }) => { this.currentMarketPrice = marketPrice; @@ -557,11 +557,6 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { } } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private updateAssetProfile() { this.isLoading = true; this.changeDetectorRef.markForCheck(); @@ -581,7 +576,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { return EMPTY; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(({ currency, dataSource, marketPrice }) => { if (this.mode === 'create') { From 31e74080e59d986ee6b39a3f015a95a34b8a2069 Mon Sep 17 00:00:00 2001 From: Erwin <111194281+Erwin-N@users.noreply.github.com> Date: Sun, 22 Mar 2026 08:43:59 +0100 Subject: [PATCH 2/4] Task/eliminate OnDestroy lifecycle hook from user account registration dialog component (#6620) * Eliminate OnDestroy lifecycle hook --- ...r-account-registration-dialog.component.ts | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts b/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts index 4cc0f52f8..cbbe2d29c 100644 --- a/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts +++ b/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts @@ -8,10 +8,11 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, + DestroyRef, Inject, - OnDestroy, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCheckboxModule } from '@angular/material/checkbox'; @@ -27,8 +28,6 @@ import { checkmarkOutline, copyOutline } from 'ionicons/icons'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; import { UserAccountRegistrationDialogParams } from './interfaces/interfaces'; @@ -53,7 +52,7 @@ import { UserAccountRegistrationDialogParams } from './interfaces/interfaces'; styleUrls: ['./user-account-registration-dialog.scss'], templateUrl: 'user-account-registration-dialog.html' }) -export class GfUserAccountRegistrationDialogComponent implements OnDestroy { +export class GfUserAccountRegistrationDialogComponent { @ViewChild(MatStepper) stepper!: MatStepper; public accessToken: string; @@ -64,12 +63,11 @@ export class GfUserAccountRegistrationDialogComponent implements OnDestroy { public routerLinkAboutTermsOfService = publicRoutes.about.subRoutes.termsOfService.routerLink; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: UserAccountRegistrationDialogParams, - private dataService: DataService + private dataService: DataService, + private destroyRef: DestroyRef ) { addIcons({ arrowForwardOutline, checkmarkOutline, copyOutline }); } @@ -77,7 +75,7 @@ export class GfUserAccountRegistrationDialogComponent implements OnDestroy { public createAccount() { this.dataService .postUser() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ accessToken, authToken, role }) => { this.accessToken = accessToken; this.authToken = authToken; @@ -96,9 +94,4 @@ export class GfUserAccountRegistrationDialogComponent implements OnDestroy { public onChangeDislaimerChecked() { this.isDisclaimerChecked = !this.isDisclaimerChecked; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } From 8e56841eed5f935fd9d7da07deed0d6817fe2de3 Mon Sep 17 00:00:00 2001 From: Erwin <111194281+Erwin-N@users.noreply.github.com> Date: Sun, 22 Mar 2026 08:44:35 +0100 Subject: [PATCH 3/4] Task/eliminate OnDestroy lifecycle hook from import activities dialog component (#6621) * Eliminate OnDestroy lifecycle hook --- .../import-activities-dialog.component.ts | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts index 1a84e9f31..00f0508fe 100644 --- a/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts @@ -21,9 +21,10 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - Inject, - OnDestroy + DestroyRef, + Inject } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormBuilder, FormGroup, @@ -52,7 +53,6 @@ import { cloudUploadOutline, warningOutline } from 'ionicons/icons'; import { isArray, sortBy } from 'lodash'; import ms from 'ms'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, takeUntil } from 'rxjs'; import { ImportStep } from './enums/import-step'; import { ImportActivitiesDialogParams } from './interfaces/interfaces'; @@ -81,7 +81,7 @@ import { ImportActivitiesDialogParams } from './interfaces/interfaces'; styleUrls: ['./import-activities-dialog.scss'], templateUrl: 'import-activities-dialog.html' }) -export class GfImportActivitiesDialogComponent implements OnDestroy { +export class GfImportActivitiesDialogComponent { public accounts: CreateAccountWithBalancesDto[] = []; public activities: Activity[] = []; public assetProfileForm: FormGroup; @@ -104,12 +104,11 @@ export class GfImportActivitiesDialogComponent implements OnDestroy { public tags: CreateTagDto[] = []; public totalItems: number; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: ImportActivitiesDialogParams, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private formBuilder: FormBuilder, public dialogRef: MatDialogRef, @@ -152,7 +151,7 @@ export class GfImportActivitiesDialogComponent implements OnDestroy { ], range: 'max' }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ holdings }) => { this.holdings = sortBy(holdings, ({ name }) => { return name.toLowerCase(); @@ -237,7 +236,7 @@ export class GfImportActivitiesDialogComponent implements OnDestroy { dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ activities }) => { this.activities = activities; this.dataSource = new MatTableDataSource(activities.reverse()); @@ -284,11 +283,6 @@ export class GfImportActivitiesDialogComponent implements OnDestroy { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private async handleFile({ file, stepper From 3f7a503bfadcb4131580e46f4774b807a66f900d Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sun, 22 Mar 2026 09:43:55 +0100 Subject: [PATCH 4/4] Bugfix/add missing guard in hasReadRestrictedAccessPermission() (#6569) * Add missing guard in hasReadRestrictedAccessPermission() * Update changelog --- CHANGELOG.md | 4 ++++ libs/common/src/lib/permissions.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 338b67f96..46beae7ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the language localization for Polish (`pl`) - Upgraded `@trivago/prettier-plugin-sort-imports` from version `5.2.2` to `6.0.2` +### Fixed + +- Fixed an issue by adding a missing guard in the public access for portfolio sharing + ## 2.250.0 - 2026-03-17 ### Added diff --git a/libs/common/src/lib/permissions.ts b/libs/common/src/lib/permissions.ts index a70e61bac..f9cb19562 100644 --- a/libs/common/src/lib/permissions.ts +++ b/libs/common/src/lib/permissions.ts @@ -195,7 +195,7 @@ export function hasReadRestrictedAccessPermission({ return false; } - const access = user.accessesGet?.find(({ id }) => { + const access = user?.accessesGet?.find(({ id }) => { return id === impersonationId; });