Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions src/Turnierplan.App/Client/src/app/i18n/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ export const de = {
},
DeleteUser: {
Title: 'Benutzer löschen',
Info: 'Wenn Sie eine Benutzer löschen, werden die Organisationen des Benutzers nicht mitgelöscht und bleiben weiterhin für alle Administratoren sichtbar.',
Info: 'Wenn Sie einen Benutzer löschen, werden die Organisationen des Benutzers nicht mitgelöscht und bleiben weiterhin für alle Administratoren sichtbar.',
IdConfirmation: 'Benutzer-ID:',
SuccessToast: {
Title: 'Benutzer wurde gelöscht',
Expand Down Expand Up @@ -245,9 +245,14 @@ export const de = {
Expired: 'Dieser API-Schlüssel ist abgelaufen',
NoApiKeys: 'Keine API-Schlüssel vorhanden',
ViewCharts: 'Aufrufstatistik',
DeleteToast: {
Title: 'API-Schlüssel wurde gelöscht',
Message: 'Der API-Schlüssel wurde gelöscht und kann nun nicht mehr für Anfragen verwendet werden.'
Delete: {
Title: 'API-Schlüssel löschen',
Info: 'Wenn Sie eine API-Schlüssel löschen, kann dieser Schlüssel nicht mehr für neue Anfragen verwendet werden. Außerdem sind alle vorherigen Anfragen, welche mit diesem Schlüssel getätigt wurden, nicht mehr nachvollziehbar.',
IdConfirmation: 'API-Schlüssel ID:',
SuccessToast: {
Title: 'API-Schlüssel wurde gelöscht',
Message: 'Der API-Schlüssel wurde gelöscht und kann nun nicht mehr für Anfragen verwendet werden.'
}
}
},
RbacWidget: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<tp-offcanvas-wrapper #offcanvasWrapper>
@if (targetObjectName && targetObjectId) {
<tp-delete-widget
[translationKey]="translationKey"
[thinLayout]="true"
[targetObjectName]="targetObjectName"
(deleteClick)="confirmed()" />
<div class="mt-3 small text-secondary">
<span [translate]="translationKey + '.IdConfirmation'"></span><br />
<span>{{ targetObjectId }}</span>
</div>
}
</tp-offcanvas-wrapper>
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { DeleteWidgetComponent } from '../delete-widget/delete-widget.component';
import { TranslateDirective } from '@ngx-translate/core';
import { OffcanvasWrapperComponent } from '../offcanvas-wrapper/offcanvas-wrapper.component';

@Component({
selector: 'tp-delete-offcanvas',
imports: [DeleteWidgetComponent, TranslateDirective, OffcanvasWrapperComponent],
templateUrl: './delete-offcanvas.component.html'
})
export class DeleteOffcanvasComponent {
@Input()
public translationKey: string = '';

@Output()
public deleteClick = new EventEmitter<string>();

@ViewChild('offcanvasWrapper')
protected offcanvasWrapper!: OffcanvasWrapperComponent;

protected targetObjectName?: string;
protected targetObjectId?: string;

public show(targetObjectId: string, targetObjectName: string): void {
if (this.offcanvasWrapper.isOpen) {
return;
}

this.targetObjectName = targetObjectName;
this.targetObjectId = targetObjectId;

this.offcanvasWrapper.show();
}

protected confirmed(): void {
this.offcanvasWrapper.close();

if (this.targetObjectId) {
this.deleteClick.emit(this.targetObjectId);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<ng-template #offcanvasTemplate>
<div class="p-3">
<div class="mb-4">
<tp-action-button [title]="'Portal.General.Cancel'" [icon]="'x-circle'" [type]="'outline-secondary'" (buttonClick)="close()" />
</div>
<ng-content />
</div>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Component, inject, OnDestroy, TemplateRef, ViewChild } from '@angular/core';
import { ActionButtonComponent } from '../action-button/action-button.component';
import { NgbOffcanvas, NgbOffcanvasRef } from '@ng-bootstrap/ng-bootstrap';

@Component({
selector: 'tp-offcanvas-wrapper',
imports: [ActionButtonComponent],
templateUrl: './offcanvas-wrapper.component.html'
})
export class OffcanvasWrapperComponent implements OnDestroy {
@ViewChild('offcanvasTemplate')
protected offcanvasTemplate!: TemplateRef<any>;

private readonly offcanvasService = inject(NgbOffcanvas);
private offcanvasRef?: NgbOffcanvasRef;

public get isOpen(): boolean {
return this.offcanvasRef !== undefined;
}

public ngOnDestroy(): void {
// Ensure the offcanvas is closed when this component is destroyed
this.close();
}

public show(): void {
if (this.offcanvasRef) {
return;
}

this.offcanvasRef = this.offcanvasService.open(this.offcanvasTemplate, { position: 'end' });

this.offcanvasRef.hidden.subscribe({
next: () => {
this.offcanvasRef = undefined;
}
});
}

public close(): void {
if (!this.offcanvasRef) {
return;
}

// This will cause the 'hidden' observable to emit which will set the variable to undefined
this.offcanvasRef.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@
[icon]="'pencil'"
[type]="'outline-secondary'"
[mode]="'IconOnly'"
(buttonClick)="editButtonClicked(user.id, editUserCanvas)" />
(buttonClick)="editButtonClicked(user.id)" />
<div [ngClass]="{ 'tp-cursor-not-allowed': isCurrentUser }">
<tp-action-button
[icon]="'trash'"
[type]="'outline-danger'"
[mode]="'IconOnly'"
[disabled]="isCurrentUser"
(buttonClick)="deleteButtonClicked(user.id, deleteConfirmationCanvas)" />
(buttonClick)="deleteUserOffcanvas.show(user.id, user.userName)" />
</div>
</div>
</td>
Expand All @@ -68,127 +68,97 @@
</tp-page-frame>
</ng-container>

<ng-template #editUserCanvas>
<div class="p-3">
<div class="mb-3">
<tp-action-button
[title]="'Portal.General.Cancel'"
[icon]="'x-circle'"
[type]="'outline-secondary'"
(buttonClick)="currentOffcanvas?.close()" />
</div>
@if (userSelectedForEditing) {
<div class="fw-bold mb-3" translate="Portal.Administration.EditUser.Title"></div>
<div class="mb-4" translate="Portal.Administration.EditUser.Info"></div>
<tp-offcanvas-wrapper #editUserOffcanvas>
@if (userSelectedForEditing) {
<div class="fw-bold mb-3" translate="Portal.Administration.EditUser.Title"></div>
<div class="mb-4" translate="Portal.Administration.EditUser.Info"></div>

<form [formGroup]="editUserForm">
<div class="form-group mb-3">
@let userNameControl = editUserForm.get('userName')!;
<label class="form-label" for="userName" translate="Portal.Administration.EditUser.UserName"></label>
<input
class="form-control"
id="userName"
type="text"
formControlName="userName"
[ngClass]="userNameControl.dirty ? (userNameControl.invalid ? 'is-invalid' : 'is-valid') : ''" />
<div class="invalid-feedback" translate="Portal.Administration.EditUser.UserNameInvalid"></div>
</div>
<form [formGroup]="editUserForm">
<div class="form-group mb-3">
@let userNameControl = editUserForm.get('userName')!;
<label class="form-label" for="userName" translate="Portal.Administration.EditUser.UserName"></label>
<input
class="form-control"
id="userName"
type="text"
formControlName="userName"
[ngClass]="userNameControl.dirty ? (userNameControl.invalid ? 'is-invalid' : 'is-valid') : ''" />
<div class="invalid-feedback" translate="Portal.Administration.EditUser.UserNameInvalid"></div>
</div>

<div class="form-group mb-3">
@let fullNameControl = editUserForm.get('fullName')!;
<label class="form-label" for="fullName" translate="Portal.Administration.EditUser.FullName"></label>
<input
class="form-control"
id="fullName"
type="text"
formControlName="fullName"
[ngClass]="fullNameControl.dirty ? (fullNameControl.invalid ? 'is-invalid' : 'is-valid') : ''" />
<div class="invalid-feedback" translate="Portal.Administration.EditUser.FullNameInvalid"></div>
</div>
<div class="form-group mb-3">
@let fullNameControl = editUserForm.get('fullName')!;
<label class="form-label" for="fullName" translate="Portal.Administration.EditUser.FullName"></label>
<input
class="form-control"
id="fullName"
type="text"
formControlName="fullName"
[ngClass]="fullNameControl.dirty ? (fullNameControl.invalid ? 'is-invalid' : 'is-valid') : ''" />
<div class="invalid-feedback" translate="Portal.Administration.EditUser.FullNameInvalid"></div>
</div>

<div class="form-group mb-3">
@let eMailNameControl = editUserForm.get('eMail')!;
<label class="form-label" for="eMail" translate="Portal.Administration.EditUser.Email"></label>
<input
class="form-control"
id="eMail"
type="email"
formControlName="eMail"
[ngClass]="eMailNameControl.dirty ? (eMailNameControl.invalid ? 'is-invalid' : 'is-valid') : ''" />
<div class="invalid-feedback" translate="Portal.Administration.EditUser.EmailInvalid"></div>
</div>
<div class="form-group mb-3">
@let eMailNameControl = editUserForm.get('eMail')!;
<label class="form-label" for="eMail" translate="Portal.Administration.EditUser.Email"></label>
<input
class="form-control"
id="eMail"
type="email"
formControlName="eMail"
[ngClass]="eMailNameControl.dirty ? (eMailNameControl.invalid ? 'is-invalid' : 'is-valid') : ''" />
<div class="invalid-feedback" translate="Portal.Administration.EditUser.EmailInvalid"></div>
</div>

<div class="form-check mb-3">
<input class="form-check-input" id="isAdministrator" type="checkbox" formControlName="isAdministrator" />
<label class="form-check-label" for="isAdministrator" translate="Portal.Administration.EditUser.IsAdministrator"></label>
</div>
<div class="form-check mb-3">
<input class="form-check-input" id="isAdministrator" type="checkbox" formControlName="isAdministrator" />
<label class="form-check-label" for="isAdministrator" translate="Portal.Administration.EditUser.IsAdministrator"></label>
</div>

@let isAdministratorControl = editUserForm.get('isAdministrator')!;
@if (!userSelectedForEditing.isAdministrator && isAdministratorControl.value) {
<tp-alert
[margin]="'mb-3'"
[type]="'warning'"
[icon]="'exclamation-triangle'"
[text]="'Portal.Administration.EditUser.AdministratorWarning'" />
}
@let isAdministratorControl = editUserForm.get('isAdministrator')!;
@if (!userSelectedForEditing.isAdministrator && isAdministratorControl.value) {
<tp-alert
[margin]="'mb-3'"
[type]="'warning'"
[icon]="'exclamation-triangle'"
[text]="'Portal.Administration.EditUser.AdministratorWarning'" />
}

<div class="form-check mb-3">
<div class="form-check mb-3">
<input
class="form-check-input"
id="updatePassword"
type="checkbox"
formControlName="updatePassword"
(change)="updatePasswordToggled()" />
<label class="form-check-label" for="updatePassword" translate="Portal.Administration.EditUser.UpdatePassword"></label>
</div>

@let updatePasswordControl = editUserForm.get('updatePassword')!;
@if (updatePasswordControl.value) {
<div class="form-group mb-3">
@let passwordControl = editUserForm.get('password')!;
<label class="form-label" for="password" translate="Portal.Administration.EditUser.Password"></label>
<input
class="form-check-input"
id="updatePassword"
type="checkbox"
formControlName="updatePassword"
(change)="updatePasswordToggled()" />
<label class="form-check-label" for="updatePassword" translate="Portal.Administration.EditUser.UpdatePassword"></label>
class="form-control"
id="password"
type="password"
formControlName="password"
[ngClass]="passwordControl.dirty ? (passwordControl.invalid ? 'is-invalid' : 'is-valid') : ''" />
<div class="invalid-feedback" translate="Portal.Administration.EditUser.PasswordInvalid"></div>
</div>
}
</form>

@let updatePasswordControl = editUserForm.get('updatePassword')!;
@if (updatePasswordControl.value) {
<div class="form-group mb-3">
@let passwordControl = editUserForm.get('password')!;
<label class="form-label" for="password" translate="Portal.Administration.EditUser.Password"></label>
<input
class="form-control"
id="password"
type="password"
formControlName="password"
[ngClass]="passwordControl.dirty ? (passwordControl.invalid ? 'is-invalid' : 'is-valid') : ''" />
<div class="invalid-feedback" translate="Portal.Administration.EditUser.PasswordInvalid"></div>
</div>
}
</form>

<div class="mt-4 d-flex flex-row">
<tp-action-button
[type]="'outline-success'"
[icon]="'floppy'"
[title]="'Portal.General.Save'"
[disabled]="editUserForm.invalid"
(buttonClick)="editConfirmed(userSelectedForEditing.id)" />
</div>
}
</div>
</ng-template>

<ng-template #deleteConfirmationCanvas>
<div class="p-3">
<div class="mb-3">
<div class="mt-4 d-flex flex-row">
<tp-action-button
[title]="'Portal.General.Cancel'"
[icon]="'x-circle'"
[type]="'outline-secondary'"
(buttonClick)="currentOffcanvas?.close()" />
[type]="'outline-success'"
[icon]="'floppy'"
[title]="'Portal.General.Save'"
[disabled]="editUserForm.invalid"
(buttonClick)="editConfirmed(userSelectedForEditing.id)" />
</div>
@if (userSelectedForDeletion) {
<tp-delete-widget
[translationKey]="'Portal.Administration.DeleteUser'"
[thinLayout]="true"
[targetObjectName]="userSelectedForDeletion.userName"
(deleteClick)="deleteConfirmed(userSelectedForDeletion.id)" />
<div class="mt-3 small text-secondary">
<span translate="Portal.Administration.DeleteUser.IdConfirmation"></span><br />
<span>{{ userSelectedForDeletion.id }}</span>
</div>
}
</div>
</ng-template>
}
</tp-offcanvas-wrapper>

<tp-delete-offcanvas #deleteUserOffcanvas [translationKey]="'Portal.Administration.DeleteUser'" (deleteClick)="deleteConfirmed($event)" />
Loading
Loading