AI Implementation feature(867): Admin Area Players Management (#56)

This commit was merged in pull request #56.
This commit is contained in:
2026-07-23 08:08:50 +00:00
parent 705530e71f
commit e4ccf0fe13
27 changed files with 2039 additions and 218 deletions
@@ -0,0 +1,75 @@
import {
ChangeDetectionStrategy,
Component,
HostListener,
input,
output,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { AdminUser } from '../../core/services/admin.service';
@Component({
selector: 'app-player-delete-modal',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [CommonModule],
styles: [`
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.4); display: flex; align-items: center; justify-content: center; z-index: 70; }
.modal { background: var(--color-surface, #fff); padding: 16px; border-radius: 8px; width: min(420px, 90vw); }
.actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; }
.error { color: var(--color-danger, #f00); margin-top: 8px; }
.spinner { display: inline-block; width: 12px; height: 12px; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: spin 0.6s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
`],
template: `
@if (open()) {
<div class="modal-overlay" data-testid="player-delete-overlay" (click)="onCancel()">
<div
class="modal"
role="dialog"
aria-modal="true"
aria-labelledby="pd-title"
data-testid="player-delete-modal"
(click)="$event.stopPropagation()"
>
<h3 id="pd-title">Delete user</h3>
<p>Delete this user?</p>
@if (errorMessage(); as msg) {
<p class="error" role="alert" data-testid="player-delete-error">{{ msg }}</p>
}
<div class="actions">
<button type="button" (click)="onCancel()" [disabled]="submitting()" data-testid="player-delete-cancel">Cancel</button>
<button type="button" (click)="onConfirm()" [disabled]="submitting()" data-testid="player-delete-ok">
<span *ngIf="submitting()" class="spinner" aria-hidden="true"></span>
Delete
</button>
</div>
</div>
</div>
}
`,
})
export class PlayerDeleteModalComponent {
readonly open = input(false);
readonly user = input<AdminUser | null>(null);
readonly errorMessage = input<string | null>(null);
readonly submitting = input(false);
readonly cancel = output<void>();
readonly confirm = output<void>();
@HostListener('document:keydown.escape')
onEscape(): void {
if (this.open() && !this.submitting()) this.onCancel();
}
onCancel(): void {
if (this.submitting()) return;
this.cancel.emit();
}
onConfirm(): void {
if (this.submitting()) return;
this.confirm.emit();
}
}