large update wip
This commit is contained in:
174
src/app/components/registration/registration.component.ts
Normal file
174
src/app/components/registration/registration.component.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
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<number | null>(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<File | null>(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),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
goBack(): void {
|
||||
this.router.navigate(['/landing']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user