feat: Add nationality and country selection with validation for date of birth
This commit is contained in:
parent
ab69142c34
commit
8798979fe9
@ -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>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user