qa-dashboard #2

Merged
Seazn merged 6 commits from qa-dashboard into dev 2025-10-12 12:09:51 +00:00
Showing only changes of commit 8798979fe9 - Show all commits

View File

@ -20,6 +20,26 @@ interface PersonalProfileData {
emergencyPhone: string emergencyPhone: string
} }
// Common nationalities list
const NATIONALITIES = [
'German', 'Austrian', 'Swiss', 'Italian', 'French', 'Spanish', 'Portuguese', 'Dutch',
'Belgian', 'Polish', 'Czech', 'Hungarian', 'Croatian', 'Slovenian', 'Slovak',
'British', 'Irish', 'Swedish', 'Norwegian', 'Danish', 'Finnish', 'Russian',
'Turkish', 'Greek', 'Romanian', 'Bulgarian', 'Serbian', 'Albanian', 'Bosnian',
'American', 'Canadian', 'Brazilian', 'Argentinian', 'Mexican', 'Chinese',
'Japanese', 'Indian', 'Pakistani', 'Australian', 'South African', 'Other'
]
// Common countries list
const COUNTRIES = [
'Germany', 'Austria', 'Switzerland', 'Italy', 'France', 'Spain', 'Portugal', 'Netherlands',
'Belgium', 'Poland', 'Czech Republic', 'Hungary', 'Croatia', 'Slovenia', 'Slovakia',
'United Kingdom', 'Ireland', 'Sweden', 'Norway', 'Denmark', 'Finland', 'Russia',
'Turkey', 'Greece', 'Romania', 'Bulgaria', 'Serbia', 'Albania', 'Bosnia and Herzegovina',
'United States', 'Canada', 'Brazil', 'Argentina', 'Mexico', 'China', 'Japan',
'India', 'Pakistan', 'Australia', 'South Africa', 'Other'
]
const initialData: PersonalProfileData = { const initialData: PersonalProfileData = {
dob: '', dob: '',
nationality: '', nationality: '',
@ -44,12 +64,37 @@ export default function PersonalAdditionalInformationPage() {
const [success, setSuccess] = useState(false) const [success, setSuccess] = useState(false)
const [error, setError] = useState('') const [error, setError] = useState('')
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
const { name, value } = e.target const { name, value } = e.target
setForm(p => ({ ...p, [name]: value })) setForm(p => ({ ...p, [name]: value }))
setError('') setError('')
} }
const validateDateOfBirth = (dob: string) => {
if (!dob) return false
const birthDate = new Date(dob)
const today = new Date()
// Check if date is valid
if (isNaN(birthDate.getTime())) return false
// Check if birth date is not in the future
if (birthDate > today) return false
// Check minimum age (18 years)
const minDate = new Date()
minDate.setFullYear(today.getFullYear() - 18)
if (birthDate > minDate) return false
// Check maximum age (120 years)
const maxDate = new Date()
maxDate.setFullYear(today.getFullYear() - 120)
if (birthDate < maxDate) return false
return true
}
const validate = () => { const validate = () => {
const requiredKeys: (keyof PersonalProfileData)[] = [ const requiredKeys: (keyof PersonalProfileData)[] = [
'dob','nationality','street','postalCode','city','country','accountHolder','iban' 'dob','nationality','street','postalCode','city','country','accountHolder','iban'
@ -60,6 +105,13 @@ export default function PersonalAdditionalInformationPage() {
return false return false
} }
} }
// Date of birth validation
if (!validateDateOfBirth(form.dob)) {
setError('Ungültiges Geburtsdatum. Sie müssen mindestens 18 Jahre alt sein.')
return false
}
// very loose IBAN check // very loose IBAN check
if (!/^([A-Z]{2}\d{2}[A-Z0-9]{10,30})$/i.test(form.iban.replace(/\s+/g,''))) { if (!/^([A-Z]{2}\d{2}[A-Z0-9]{10,30})$/i.test(form.iban.replace(/\s+/g,''))) {
setError('Ungültige IBAN.') setError('Ungültige IBAN.')
@ -175,6 +227,8 @@ export default function PersonalAdditionalInformationPage() {
name="dob" name="dob"
value={form.dob} value={form.dob}
onChange={handleChange} onChange={handleChange}
min={new Date(new Date().getFullYear() - 120, 0, 1).toISOString().split('T')[0]}
max={new Date(new Date().getFullYear() - 18, 11, 31).toISOString().split('T')[0]}
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent" className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
required required
/> />
@ -183,14 +237,20 @@ export default function PersonalAdditionalInformationPage() {
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">
Nationality * Nationality *
</label> </label>
<input <select
name="nationality" name="nationality"
value={form.nationality} value={form.nationality}
onChange={handleChange} onChange={handleChange}
placeholder="e.g. German"
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent" className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
required required
/> >
<option value="">Select nationality...</option>
{NATIONALITIES.map(nationality => (
<option key={nationality} value={nationality}>
{nationality}
</option>
))}
</select>
</div> </div>
<div className="sm:col-span-2 lg:col-span-3"> <div className="sm:col-span-2 lg:col-span-3">
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">
@ -235,14 +295,20 @@ export default function PersonalAdditionalInformationPage() {
<label className="block text-sm font-medium text-gray-700 mb-1"> <label className="block text-sm font-medium text-gray-700 mb-1">
Country * Country *
</label> </label>
<input <select
name="country" name="country"
value={form.country} value={form.country}
onChange={handleChange} onChange={handleChange}
placeholder="e.g. Germany"
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent" className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
required required
/> >
<option value="">Select country...</option>
{COUNTRIES.map(country => (
<option key={country} value={country}>
{country}
</option>
))}
</select>
</div> </div>
</div> </div>
</section> </section>