This commit is contained in:
2025-08-19 18:44:53 +03:00
parent 95654933ee
commit 5326e545a8
17 changed files with 571 additions and 363 deletions

View File

@@ -0,0 +1,115 @@
<div class="registration-container">
<h2 class="title">🚀 Spaceflight Candidate Registration</h2>
<form [formGroup]="form" (ngSubmit)="onSubmit()" class="form">
<!-- <div class="upload-section">
<input
type="file"
accept="image/*"
(change)="onFileSelected($event)"
/>
<mat-label>Candidate Profile Picture</mat-label>
<div class="preview">
<img [src]="previewUrl" alt="Preview" />
</div>
</div> -->
<app-image-input></app-image-input>
<mat-form-field appearance="outline" class="full-width">
<mat-label>Full Name</mat-label>
<input matInput formControlName="fullName" />
@if (form.get('fullName')?.hasError('required')) {
<mat-error>
Name is required
</mat-error>
}
</mat-form-field>
<mat-form-field appearance="outline" class="full-width">
<mat-label>Email</mat-label>
<input matInput formControlName="email" />
@if (form.get('email')?.hasError('email')) {
<mat-error>
Invalid email
</mat-error>
}
</mat-form-field>
<mat-form-field appearance="outline" class="full-width">
<mat-label>Phone Number</mat-label>
<input matInput formControlName="phone" placeholder="+972-XXXXXXX"/>
@if (form.get('phone')?.hasError('required')) {
<mat-error>
Phone number is required
</mat-error>
}
@if (form.get('phone')?.hasError('pattern')){
<mat-error>
Invalid phone number
</mat-error>
}
</mat-form-field>
<mat-form-field appearance="outline" class="full-width">
<mat-label>Age</mat-label>
<input matInput type="number" formControlName="age" />
@if (form.get('age')?.hasError('min') || form.get('age')?.hasError('max')) {
<mat-error>
Only aplicants of age 18 - 70 allowed
</mat-error>
}
</mat-form-field>
<mat-form-field appearance="outline" class="full-width">
<mat-label>City / Region</mat-label>
<input matInput formControlName="city" />
@if (form.get('city')?.hasError('required')) {
<mat-error>
Field is required
</mat-error>
}
</mat-form-field>
<mat-form-field appearance="outline" class="full-width">
<mat-label>Hobbies</mat-label>
<textarea matInput rows="2" formControlName="hobbies"></textarea>
@if (form.get('hobbies')?.hasError('maxLength')) {
<mat-error>
Maximum length is 300 characters
</mat-error>
}
</mat-form-field>
<mat-form-field appearance="outline" class="full-width">
<mat-label>Why I am the perfect candidate</mat-label>
<textarea matInput rows="4" formControlName="reason"></textarea>
@if (form.get('reason')?.hasError('required')) {
<mat-error>
Field is required
</mat-error>
}
@if (form.get('reason')?.hasError('maxLength')) {
<mat-error>
Maximum length is 300 characters
</mat-error>
}
</mat-form-field>
<button
mat-raised-button
color="accent"
class="full-width"
type="submit"
[disabled]="form.invalid"
>
Submit Application
</button>
<button
mat-raised-button
(click)="onCheckErrors()">
check
</button>
</form>
</div>

View File

@@ -0,0 +1,164 @@
/* Cosmic-themed container styling */
.registration-container {
max-width: 900px;
margin: 2rem auto;
padding: 2.5rem;
background: linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%);
color: #e0e0e0;
border-radius: 16px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
position: relative;
overflow: hidden;
}
/* Cosmic background overlay */
.registration-container::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0) 70%);
opacity: 0.3;
pointer-events: none;
}
/* Form title with space theme */
.title {
text-align: center;
font-size: 2.2rem;
font-weight: 700;
color: #00d4ff;
margin-bottom: 2.5rem;
text-transform: uppercase;
letter-spacing: 3px;
text-shadow: 0 0 12px rgba(0, 212, 255, 0.6);
animation: glow 2s ease-in-out infinite alternate;
}
/* Glowing title animation */
@keyframes glow {
from {
text-shadow: 0 0 8px rgba(0, 212, 255, 0.4);
}
to {
text-shadow: 0 0 16px rgba(0, 212, 255, 0.8);
}
}
/* Form styling */
.form {
display: flex;
flex-direction: column;
gap: 2rem;
}
/* Full-width form fields */
.full-width {
width: 100%;
}
// /* Material form field customization */
// ::ng-deep .mat-form-field {
// .mat-form-field-label {
// color: #b0bec5;
// font-weight: 500;
// }
// .mat-form-field-underline {
// background-color: #00d4ff !important;
// }
// .mat-form-field-ripple {
// background-color: #00d4ff !important;
// }
// input, textarea {
// color: #e0e0e0;
// background-color: rgba(255, 255, 255, 0.08);
// border-radius: 6px;
// padding: 0.75rem;
// transition: background-color 0.3s ease;
// }
// input:focus, textarea:focus {
// background-color: rgba(255, 255, 255, 0.12);
// }
// textarea {
// resize: vertical;
// min-height: 80px;
// }
// }
/* Error message styling */
// ::ng-deep .mat-error {
// color: #ff6b6b;
// font-size: 0.9rem;
// }
/* Upload section */
.upload-section {
align-items: center;
margin: 2rem 0;
display: flex;
flex-direction: column;
gap: 1.5rem;
.preview {
margin-top: 1.5rem;
}
img {
width: 250px;
height: 250px;
border: 4px solid #00d4ff;
box-shadow: 0 0 20px rgba(0, 212, 255, 0.4);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
img:hover {
transform: scale(1.1);
box-shadow: 0 0 25px rgba(0, 212, 255, 0.6);
}
}
/* Responsive design */
@media (max-width: 768px) {
.registration-container {
margin: 1.5rem;
padding: 2rem;
}
.title {
font-size: 1.8rem;
margin-bottom: 2rem;
}
.upload-section img {
max-width: 140px;
}
// ::ng-deep .mat-raised-button {
// padding: 0.75rem 1.5rem;
// font-size: 0.95rem;
// }
}
@media (max-width: 480px) {
.registration-container {
margin: 1rem;
padding: 1.5rem;
}
.title {
font-size: 1.4rem;
margin-bottom: 1.5rem;
}
.upload-section img {
max-width: 120px;
}
}

View File

@@ -0,0 +1,86 @@
import { Component, inject, OnInit } from '@angular/core';
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
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";
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
],
templateUrl: './registration.component.html',
styleUrls: ['./registration.component.scss'],
})
export class RegistrationComponent implements OnInit {
fb = inject(FormBuilder);
previewUrl: string | ArrayBuffer | null = null;
form = this.fb.group({
fullName: ['', [Validators.required, Validators.minLength(3)]],
email: ['', [Validators.required, Validators.email]],
phone: ['', [Validators.required, Validators.pattern(israeliPhoneRegex)]],
age: [0, [Validators.required, Validators.min(18), Validators.max(70)]],
city: ['', Validators.required],
hobbies: ['', [Validators.maxLength(300)]],
reason: ['', [Validators.required, Validators.maxLength(300)]],
profileImage: this.fb.control<string | null>(null, Validators.required),
});
ngOnInit(): void {
const savedData = localStorage.getItem('registration');
if (!savedData) return;
const parsed = JSON.parse(savedData);
const dayMilliseconds = 1000 * 60 * 60 * 24;
if (Date.now() - parsed.timestamp < dayMilliseconds * 3) {
this.form.patchValue(parsed.data);
this.previewUrl = parsed.data.profileImage;
} else {
localStorage.removeItem('registration');
}
}
onFileSelected(event: any) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
if (typeof reader.result === 'string') {
this.previewUrl = reader.result;
this.form.patchValue({ profileImage: reader.result });
}
};
reader.readAsDataURL(file);
}
}
onSubmit() {
if (this.form.valid) {
localStorage.setItem(
'registration',
JSON.stringify({
data: this.form.value,
timestamp: Date.now(),
})
);
alert('✅ Application saved! You can re-edit within 3 days.');
}
}
onCheckErrors() {
console.log(this.form.controls.age.errors);
}
}