Files
HIPCTF2/frontend/src/app/features/admin/player-delete-modal.component.ts
T
2026-07-24 12:58:34 +02:00

97 lines
3.5 KiB
TypeScript

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.9);
backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; z-index: 1200; padding: 16px;
}
.modal {
background: #000000; color: #ffffff; border: 3px solid var(--neon-red);
padding: 24px; width: min(420px, 92vw);
box-shadow: 0 10px 40px rgba(0,0,0,0.9), 0 0 25px rgba(255, 0, 51, 0.35);
font-family: var(--font-mono);
}
h3 {
font-family: var(--font-heading, 'Chakra Petch', sans-serif);
font-size: 1.5rem; font-weight: 900; font-style: italic; text-transform: uppercase;
color: #ffffff; margin-bottom: 14px;
}
p { font-size: 0.95rem; color: #ddddee; margin-bottom: 16px; }
.actions { display: flex; justify-content: flex-end; gap: 12px; margin-top: 16px; }
.btn-cancel {
background: #000000; color: var(--neon-purple); border: 2px solid var(--neon-purple);
font-family: var(--font-mono); font-weight: 800; padding: 10px 20px; cursor: pointer;
}
.btn-cancel:hover { background: var(--neon-purple); color: #000000; }
.btn-ok {
background: var(--neon-red); color: #000000; border: 2px solid var(--neon-red);
font-family: var(--font-mono); font-weight: 800; padding: 10px 20px; cursor: pointer;
}
.btn-ok:hover:not([disabled]) { background: #000000; color: var(--neon-red); box-shadow: 0 0 15px rgba(255, 0, 51, 0.4); }
.error { color: var(--neon-red); margin-top: 8px; font-weight: bold; }
`],
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? All associated activity will be permanently wiped.</p>
@if (errorMessage(); as msg) {
<p class="error" role="alert" data-testid="player-delete-error">{{ msg }}</p>
}
<div class="actions">
<button type="button" class="btn-cancel" (click)="onCancel()" [disabled]="submitting()" data-testid="player-delete-cancel">CANCEL</button>
<button type="button" class="btn-ok" (click)="onConfirm()" [disabled]="submitting()" data-testid="player-delete-ok">
{{ submitting() ? 'DELETING...' : 'DELETE USER' }}
</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();
}
}