diff --git a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts index 97bd272d4..51bc76502 100644 --- a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts +++ b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts @@ -29,6 +29,7 @@ import { import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; +import { AccessPermission } from '@prisma/client'; import { StatusCodes } from 'http-status-codes'; import { EMPTY, catchError } from 'rxjs'; @@ -52,7 +53,7 @@ import { CreateOrUpdateAccessDialogParams } from './interfaces/interfaces'; }) export class GfCreateOrUpdateAccessDialogComponent implements OnInit { protected accessForm: FormGroup; - protected mode: 'create' | 'update'; + protected readonly mode: 'create' | 'update'; private readonly changeDetectorRef = inject(ChangeDetectorRef); @@ -69,21 +70,25 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { private readonly notificationService = inject(NotificationService); public constructor() { - this.mode = this.data.access?.id ? 'update' : 'create'; + this.mode = this.data.access ? 'update' : 'create'; } public ngOnInit() { - const isPublic = this.data.access.type === 'PUBLIC'; + const access = this.data?.access; + const isPublic = access?.type === 'PUBLIC'; this.accessForm = this.formBuilder.group({ - alias: [this.data.access.alias], + alias: [access?.alias ?? ''], granteeUserId: [ - this.data.access.grantee, + access?.grantee ?? null, isPublic ? null : Validators.required ], - permissions: [this.data.access.permissions[0], Validators.required], + permissions: [ + access?.permissions[0] ?? AccessPermission.READ_RESTRICTED, + Validators.required + ], type: [ - { disabled: this.mode === 'update', value: this.data.access.type }, + { disabled: this.mode === 'update', value: access?.type ?? 'PRIVATE' }, Validators.required ] }); @@ -100,7 +105,9 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { } else { granteeUserIdControl?.clearValidators(); granteeUserIdControl?.setValue(null); - permissionsControl?.setValue(this.data.access.permissions[0]); + permissionsControl?.setValue( + access?.permissions[0] ?? AccessPermission.READ_RESTRICTED + ); } granteeUserIdControl?.updateValueAndValidity(); @@ -109,11 +116,11 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { }); } - public onCancel() { + protected onCancel() { this.dialogRef.close(); } - public async onSubmit() { + protected async onSubmit() { if (this.mode === 'create') { await this.createAccess(); } else { @@ -158,10 +165,16 @@ export class GfCreateOrUpdateAccessDialogComponent implements OnInit { } private async updateAccess() { + const accessId = this.data.access?.id; + + if (!accessId) { + return; + } + const access: UpdateAccessDto = { alias: this.accessForm.get('alias')?.value, granteeUserId: this.accessForm.get('granteeUserId')?.value, - id: this.data.access.id, + id: accessId, permissions: [this.accessForm.get('permissions')?.value] }; diff --git a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/interfaces/interfaces.ts index b7850fb38..8d1ac0ba9 100644 --- a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/interfaces/interfaces.ts @@ -1,5 +1,5 @@ import { Access } from '@ghostfolio/common/interfaces'; export interface CreateOrUpdateAccessDialogParams { - access: Access; + access?: Access; } diff --git a/apps/client/src/app/components/user-account-access/user-account-access.component.ts b/apps/client/src/app/components/user-account-access/user-account-access.component.ts index e6686e80f..985dba2cb 100644 --- a/apps/client/src/app/components/user-account-access/user-account-access.component.ts +++ b/apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -12,12 +12,19 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + computed, CUSTOM_ELEMENTS_SCHEMA, DestroyRef, + inject, OnInit } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms'; +import { + FormControl, + FormGroup, + ReactiveFormsModule, + Validators +} from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog, MatDialogModule } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -53,30 +60,35 @@ import { CreateOrUpdateAccessDialogParams } from './create-or-update-access-dial templateUrl: './user-account-access.html' }) export class GfUserAccountAccessComponent implements OnInit { - public accessesGet: Access[]; - public accessesGive: Access[]; - public deviceType: string; - public hasPermissionToCreateAccess: boolean; - public hasPermissionToDeleteAccess: boolean; - public hasPermissionToUpdateOwnAccessToken: boolean; - public isAccessTokenHidden = true; - public updateOwnAccessTokenForm = this.formBuilder.group({ - accessToken: ['', Validators.required] + protected accessesGet: Access[]; + protected accessesGive: Access[]; + protected hasPermissionToCreateAccess: boolean; + protected hasPermissionToDeleteAccess: boolean; + protected hasPermissionToUpdateOwnAccessToken: boolean; + protected isAccessTokenHidden = true; + protected readonly updateOwnAccessTokenForm = new FormGroup({ + accessToken: new FormControl('', { + nonNullable: true, + validators: [Validators.required] + }) }); - public user: User; + protected user: User; + + private readonly deviceType = computed( + () => this.deviceDetectorService.deviceInfo().deviceType + ); + + private readonly changeDetectorRef = inject(ChangeDetectorRef); + private readonly dataService = inject(DataService); + private readonly destroyRef = inject(DestroyRef); + private readonly deviceDetectorService = inject(DeviceDetectorService); + private readonly dialog = inject(MatDialog); + private readonly notificationService = inject(NotificationService); + private readonly route = inject(ActivatedRoute); + private readonly router = inject(Router); + private readonly userService = inject(UserService); - public constructor( - private changeDetectorRef: ChangeDetectorRef, - private dataService: DataService, - private destroyRef: DestroyRef, - private deviceDetectorService: DeviceDetectorService, - private dialog: MatDialog, - private formBuilder: FormBuilder, - private notificationService: NotificationService, - private route: ActivatedRoute, - private router: Router, - private userService: UserService - ) { + public constructor() { const { globalPermissions } = this.dataService.fetchInfo(); this.hasPermissionToDeleteAccess = hasPermission( @@ -123,12 +135,10 @@ export class GfUserAccountAccessComponent implements OnInit { } public ngOnInit() { - this.deviceType = this.deviceDetectorService.getDeviceInfo().deviceType; - this.update(); } - public onDeleteAccess(aId: string) { + protected onDeleteAccess(aId: string) { this.dataService .deleteAccess(aId) .pipe(takeUntilDestroyed(this.destroyRef)) @@ -139,12 +149,13 @@ export class GfUserAccountAccessComponent implements OnInit { }); } - public onGenerateAccessToken() { + protected onGenerateAccessToken() { this.notificationService.confirm({ confirmFn: () => { this.dataService .updateOwnAccessToken({ - accessToken: this.updateOwnAccessTokenForm.get('accessToken').value + accessToken: + this.updateOwnAccessTokenForm.controls.accessToken.value }) .pipe( catchError(() => { @@ -173,7 +184,7 @@ export class GfUserAccountAccessComponent implements OnInit { }); } - public onUpdateAccess(aId: string) { + protected onUpdateAccess(aId: string) { this.router.navigate([], { queryParams: { accessId: aId, editDialog: true } }); @@ -184,17 +195,9 @@ export class GfUserAccountAccessComponent implements OnInit { GfCreateOrUpdateAccessDialogComponent, CreateOrUpdateAccessDialogParams >(GfCreateOrUpdateAccessDialogComponent, { - data: { - access: { - alias: '', - grantee: null, - id: null, - permissions: ['READ_RESTRICTED'], - type: 'PRIVATE' - } - }, - height: this.deviceType === 'mobile' ? '98vh' : undefined, - width: this.deviceType === 'mobile' ? '100vw' : '50rem' + data: {} satisfies CreateOrUpdateAccessDialogParams, + height: this.deviceType() === 'mobile' ? '98vh' : undefined, + width: this.deviceType() === 'mobile' ? '100vw' : '50rem' }); dialogRef.afterClosed().subscribe((access: CreateAccessDto | null) => { @@ -222,14 +225,14 @@ export class GfUserAccountAccessComponent implements OnInit { data: { access: { alias: access.alias, - grantee: access.grantee === 'Public' ? null : access.grantee, + grantee: access.grantee === 'Public' ? undefined : access.grantee, id: access.id, permissions: access.permissions, type: access.type } - }, - height: this.deviceType === 'mobile' ? '98vh' : undefined, - width: this.deviceType === 'mobile' ? '100vw' : '50rem' + } satisfies CreateOrUpdateAccessDialogParams, + height: this.deviceType() === 'mobile' ? '98vh' : undefined, + width: this.deviceType() === 'mobile' ? '100vw' : '50rem' }); dialogRef.afterClosed().subscribe((result) => { @@ -244,9 +247,9 @@ export class GfUserAccountAccessComponent implements OnInit { private update() { this.accessesGet = this.user.access.map(({ alias, id, permissions }) => { return { - alias, id, permissions, + alias: alias ?? '', grantee: $localize`Me`, type: 'PRIVATE' };