import { AfterViewInit, Component, ElementRef, inject, input, OnInit, QueryList, signal, ViewChildren } from '@angular/core'; import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatInputModule } from '@angular/material/input'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatFormFieldModule } from '@angular/material/form-field'; import { ImageInputComponent } from "../image-input/image-input.component"; import { CandidateDataService } from '../../services/candidate-data.service'; import "@maptiler/leaflet-maptilersdk"; import { LeafletMapComponent } from "../leaflet-map/leaflet-map.component"; import { CITY_LIST } from '../../shared/cities'; import { cityValidator } from '../../validators/city.validator'; import { ActivatedRoute, Router, RouterLink } from '@angular/router'; import { SocketIOService } from '../../services/socket-io.service'; const CITY_NAMES = CITY_LIST.map(c => c.name).sort(); const israeliPhoneRegex = /^(?:(?:(\+?972|\(\+?972\)|\+?\(972\))(?:\s|\.|-)?([1-9]\d?))|(0[23489]{1})|(0[57]{1}[0-9]))(?:\s|\.|-)?([^0\D]{1}\d{2}(?:\s|\.|-)?\d{4})$/; @Component({ selector: 'app-registration', imports: [ CommonModule, ReactiveFormsModule, MatInputModule, MatButtonModule, MatCardModule, MatFormFieldModule, ImageInputComponent, LeafletMapComponent, MatSnackBarModule, RouterLink ], templateUrl: './registration.component.html', styleUrls: ['./registration.component.scss'], }) export class RegistrationComponent implements OnInit { dataService = inject(CandidateDataService); fb = inject(FormBuilder); router = inject(Router); activatedRoute = inject(ActivatedRoute); snackBar = inject(MatSnackBar) socketService = inject(SocketIOService); previewUrl: string | ArrayBuffer | null = null; editMode = signal(false); applicationId = signal(null); form = this.fb.group({ fullName: ['', [Validators.required, Validators.minLength(3)]], email: ['', [Validators.required, Validators.email]], phoneNumber: ['', [Validators.required, Validators.pattern(israeliPhoneRegex)]], age: [0, [Validators.required, Validators.min(18), Validators.max(70)]], cityOrRegion: ['', [Validators.required, cityValidator(CITY_NAMES)]], hobbies: ['', [Validators.maxLength(300)]], justification: ['', [Validators.required, Validators.maxLength(300)]], profileImage: this.fb.control(null, Validators.required), }); ngOnInit(): void { const idParam = this.activatedRoute.snapshot.paramMap.get('id'); const url = this.activatedRoute.snapshot.url.map(s => s.path); if (url.includes('edit') && idParam) { this.editMode.set(true); this.applicationId.set(+idParam); this.loadCandidate(+idParam); } else { this.editMode.set(false); this.applicationId.set(null); } } loadCandidate(id: number) { this.dataService.getApplicationDetails(id).subscribe({ next: (candidate: any) => { this.form.patchValue({ fullName: candidate.fullName, email: candidate.email, phoneNumber: candidate.phoneNumber, age: candidate.age, cityOrRegion: candidate.cityOrRegion, hobbies: candidate.hobbies, justification: candidate.justification, }); if (candidate.profileImageUrl) { this.previewUrl = candidate.profileImageUrl; this.form.get('profileImage')?.clearValidators(); this.form.get('profileImage')?.updateValueAndValidity(); } }, error: err => console.error('Failed to load candidate', err), }); } scrollToFirstInvalidField() { for (const key of Object.keys(this.form.controls)) { const control = this.form.get(key); if (control && control.invalid) { const element = document.querySelector( `[formControlName="${key}"]` ) as HTMLElement; if (element) { element.scrollIntoView({ behavior: 'smooth', block: 'center' }); element.focus(); } break; } } } onSubmit() { if (!this.form.valid) { this.scrollToFirstInvalidField(); return; } const formData = new FormData(); const value = this.form.value; if (value.fullName) formData.append('fullName', value.fullName); if (value.email) formData.append('email', value.email); if (value.phoneNumber) formData.append('phoneNumber', value.phoneNumber); if (value.age !== null && value.age !== undefined) formData.append('age', value.age.toString()); if (value.cityOrRegion) formData.append('cityOrRegion', value.cityOrRegion); if (value.hobbies) formData.append('hobbies', value.hobbies); if (value.justification) formData.append('justification', value.justification); const imageFile = this.form.get('profileImage')?.value; if (imageFile) { formData.append('profileImage', imageFile); } if (this.editMode() && this.applicationId()) { this.dataService.updateCandidateForm(this.applicationId()!, formData).subscribe({ next: (updatedCandidate) => { this.snackBar.open('✅ Application updated!', 'Close', { duration: 5000, horizontalPosition: 'center', verticalPosition: 'top', }); this.socketService.socket.emit('candidateUpdated', updatedCandidate); this.router.navigate(['/application-list']); }, error: err => console.error('Error updating application', err), }); } else { this.dataService.submitCandidateForm(formData).subscribe({ next: (newCandidate) => { this.snackBar.open('✅ Application saved!', 'Close', { duration: 5000, horizontalPosition: 'center', verticalPosition: 'top', }); this.socketService.socket.emit('candidateRegistered', newCandidate); this.form.reset(); }, error: err => console.error('Error submitting form', err), }); } } }