import {AfterViewInit, Component, ElementRef, OnInit, Renderer2, signal} from '@angular/core'; import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms'; import {AppealsService, HistoryService, MinecraftAppeal, PunishmentHistory} from '@api'; import {HeaderComponent} from '@header/header.component'; import {NgOptimizedImage} from '@angular/common'; import {MatButtonModule} from '@angular/material/button'; import {MatIconModule} from '@angular/material/icon'; import {AuthService} from '@services/auth.service'; import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; import {MatFormFieldModule} from '@angular/material/form-field'; import {MatSelectModule} from '@angular/material/select'; import {MatInputModule} from '@angular/material/input'; @Component({ selector: 'app-appeal', imports: [ HeaderComponent, NgOptimizedImage, MatButtonModule, MatIconModule, MatProgressSpinnerModule, MatFormFieldModule, MatSelectModule, MatInputModule, ReactiveFormsModule, ], templateUrl: './appeal.component.html', styleUrl: './appeal.component.scss' }) export class AppealComponent implements OnInit, AfterViewInit { public form: FormGroup; private resizeObserver: ResizeObserver | null = null; private boundHandleResize: any; protected history = signal(null); protected selectedPunishment = signal(null); constructor( private appealApi: AppealsService, private historyApi: HistoryService, protected authService: AuthService, private elementRef: ElementRef, private renderer: Renderer2 ) { this.form = new FormGroup({ email: new FormControl('', {nonNullable: true, validators: [Validators.required, Validators.email]}), appeal: new FormControl('', {nonNullable: true, validators: [Validators.required, Validators.minLength(10)]}) }); } ngOnInit() { const uuid = this.authService.getUuid(); if (uuid === null) { throw new Error('JWT subject is null, are you logged in?'); } this.historyApi.getAllHistoryForUUID(uuid).subscribe(history => { this.history.set(history); }) } ngAfterViewInit() { this.setupResizeObserver(); this.updateContainerHeight(); this.boundHandleResize = this.handleResize.bind(this); window.addEventListener('resize', this.boundHandleResize); setTimeout(() => this.updateContainerHeight(), 0); } ngOnDestroy() { if (this.resizeObserver) { this.resizeObserver.disconnect(); this.resizeObserver = null; } if (this.boundHandleResize) { window.removeEventListener('resize', this.boundHandleResize); } } private handleResize() { this.updateContainerHeight(); } private setupResizeObserver() { this.resizeObserver = new ResizeObserver(() => { this.updateContainerHeight(); }); const headerElement = document.querySelector('app-header'); if (headerElement) { this.resizeObserver.observe(headerElement); } const footerElement = document.querySelector('footer'); if (footerElement) { this.resizeObserver.observe(footerElement); } } private updateContainerHeight() { const headerElement = document.querySelector('app-header'); const footerElement = document.querySelector('footer'); const container = this.elementRef.nativeElement.querySelector('.appeal-container'); if (headerElement && footerElement && container) { const headerHeight = headerElement.getBoundingClientRect().height; const footerHeight = footerElement.getBoundingClientRect().height; const calculatedHeight = `calc(100vh - ${headerHeight}px - ${footerHeight}px)`; this.renderer.setStyle(container, 'min-height', calculatedHeight); } } public onSubmit() { if (this.form === undefined) { console.error('Form is undefined'); return } if (this.form.valid) { this.sendForm() } else { Object.keys(this.form.controls).forEach(field => { const control = this.form!.get(field); if (!(control instanceof FormGroup)) { console.error('Control [' + control + '] is not a FormGroup'); return; } control.markAsTouched({onlySelf: true}); }); } } private sendForm() { const rawValue = this.form.getRawValue(); const uuid = this.authService.getUuid(); if (uuid === null) { throw new Error('JWT subject is null, are you logged in?'); } const appeal: MinecraftAppeal = { appeal: rawValue.appeal, email: rawValue.email, punishmentId: this.selectedPunishment()!.id, username: this.authService.username()!, uuid: uuid } this.appealApi.submitMinecraftAppeal(appeal).subscribe() } public currentPageIndex: number = 0; public totalPages: number[] = [0]; public goToPage(pageIndex: number): void { if (pageIndex >= 0 && pageIndex < this.totalPages.length) { this.currentPageIndex = pageIndex; } } public previousPage() { this.goToPage(this.currentPageIndex - 1); } public nextPage() { if (this.currentPageIndex === this.totalPages.length - 1) { console.log('Adding page'); this.totalPages.push(this.currentPageIndex + 1); console.log(this.totalPages); } this.goToPage(this.currentPageIndex + 1); } public isFirstPage(): boolean { return this.currentPageIndex === 0; } public isLastPage(): boolean { return this.currentPageIndex === this.totalPages.length - 1; } protected readonly length = length; onPunishmentSelected($event: PunishmentHistory) { this.selectedPunishment.set($event); } } interface Appeal { email: FormControl; appeal: FormControl; }