diff --git a/src/app/quickaction-dashboard/register-additional-information/company/page.tsx b/src/app/quickaction-dashboard/register-additional-information/company/page.tsx index 4e278b3..c5b3f1c 100644 --- a/src/app/quickaction-dashboard/register-additional-information/company/page.tsx +++ b/src/app/quickaction-dashboard/register-additional-information/company/page.tsx @@ -7,9 +7,14 @@ import useAuthStore from '../../../store/authStore' import { useUserStatus } from '../../../hooks/useUserStatus' import { useToast } from '../../../components/toast/toastComponent' import { ChevronDownIcon } from '@heroicons/react/20/solid' // NEW +import TelephoneInput, { TelephoneInputHandle } from '../../../components/phone/telephoneInput' interface CompanyProfileData { companyName: string + companyEmail: string + companyPhone: string + contactPersonName: string + contactPersonPhone: string vatNumber: string street: string postalCode: string @@ -35,6 +40,10 @@ const COUNTRIES = [ const init: CompanyProfileData = { companyName: '', + companyEmail: '', + companyPhone: '', + contactPersonName: '', + contactPersonPhone: '', vatNumber: '', street: '', postalCode: '', @@ -175,12 +184,54 @@ export default function CompanyAdditionalInformationPage() { const { accessToken } = useAuthStore() const { userStatus, loading: statusLoading, refreshStatus } = useUserStatus() const { showToast } = useToast() + const companyPhoneRef = useRef(null) + const contactPhoneRef = useRef(null) + const secondPhoneRef = useRef(null) + const emergencyPhoneRef = useRef(null) const [form, setForm] = useState(init) const [loading, setLoading] = useState(false) const [success, setSuccess] = useState(false) const [error, setError] = useState('') + // Prefill form with existing profile/user data + useEffect(() => { + let abort = false + async function loadProfile() { + if (!accessToken) return + try { + const res = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/me`, { + method: 'GET', + headers: { Authorization: `Bearer ${accessToken}` } + }) + if (!res.ok) return + const data = await res.json().catch(() => null) + const profile = data?.profile + const me = data?.user + if ((!profile && !me) || abort) return + setForm(prev => ({ + ...prev, + companyName: profile?.company_name || me?.companyName || prev.companyName, + companyEmail: me?.email || prev.companyEmail, + companyPhone: profile?.phone || me?.companyPhone || prev.companyPhone, + contactPersonName: profile?.contact_person_name || me?.contactPersonName || prev.contactPersonName, + contactPersonPhone: profile?.contact_person_phone || me?.contactPersonPhone || prev.contactPersonPhone, + vatNumber: profile?.registration_number || prev.vatNumber, + street: profile?.address || prev.street, + postalCode: profile?.zip_code || prev.postalCode, + city: profile?.city || prev.city, + country: profile?.country || prev.country, + accountHolder: profile?.account_holder_name || prev.accountHolder, + iban: (me?.iban ?? prev.iban) as string, + })) + } catch (_) { + // ignore prefill errors; user can still fill manually + } + } + loadProfile() + return () => { abort = true } + }, [accessToken]) + // NEW: smooth redirect const [redirectTo, setRedirectTo] = useState(null) const redirectOnceRef = useRef(false) @@ -223,7 +274,8 @@ export default function CompanyAdditionalInformationPage() { const validate = () => { const required: (keyof CompanyProfileData)[] = [ - 'companyName','vatNumber','street','postalCode','city','country','accountHolder','iban' + 'companyName','companyEmail','companyPhone','contactPersonName','contactPersonPhone', + 'vatNumber','street','postalCode','city','country','accountHolder','iban' ] for (const k of required) { if (!form[k].trim()) { @@ -237,6 +289,77 @@ export default function CompanyAdditionalInformationPage() { return false } } + + const companyApi = companyPhoneRef.current + const contactApi = contactPhoneRef.current + const companyDialCode = companyApi?.getDialCode?.() + const contactDialCode = contactApi?.getDialCode?.() + const companyNumber = companyApi?.getNumber() || '' + const contactNumber = contactApi?.getNumber() || '' + const companyValid = companyApi?.isValid() ?? false + const contactValid = contactApi?.isValid() ?? false + + if (!companyDialCode || !contactDialCode) { + const msg = 'Please select country codes for company and contact phone numbers.' + setError(msg) + showToast({ + variant: 'error', + title: 'Missing country code', + message: msg, + }) + return false + } + if (!companyNumber || !contactNumber) { + const msg = 'Please enter both company and contact phone numbers.' + setError(msg) + showToast({ + variant: 'error', + title: 'Missing phone numbers', + message: msg, + }) + return false + } + if (!companyValid || !contactValid) { + const msg = 'Please enter valid phone numbers for company and contact person.' + setError(msg) + showToast({ + variant: 'error', + title: 'Invalid phone numbers', + message: msg, + }) + return false + } + + const optionalSecond = form.secondPhone.trim() + if (optionalSecond) { + const secondApi = secondPhoneRef.current + const ok = secondApi?.isValid?.() ?? false + if (!ok) { + const msg = 'Please enter a valid second phone number.' + setError(msg) + showToast({ + variant: 'error', + title: 'Invalid phone number', + message: msg, + }) + return false + } + } + const optionalEmergency = form.emergencyPhone.trim() + if (optionalEmergency) { + const emergencyApi = emergencyPhoneRef.current + const ok = emergencyApi?.isValid?.() ?? false + if (!ok) { + const msg = 'Please enter a valid emergency phone number.' + setError(msg) + showToast({ + variant: 'error', + title: 'Invalid phone number', + message: msg, + }) + return false + } + } if (!/^([A-Z]{2}\d{2}[A-Z0-9]{10,30})$/i.test(form.iban.replace(/\s+/g,''))) { const msg = 'Ungültige IBAN.' setError(msg) @@ -270,9 +393,17 @@ export default function CompanyAdditionalInformationPage() { setLoading(true) try { + const normalizedCompanyPhone = companyPhoneRef.current?.getNumber() || form.companyPhone + const normalizedContactPhone = contactPhoneRef.current?.getNumber() || form.contactPersonPhone + const normalizedSecondPhone = secondPhoneRef.current?.getNumber() || form.secondPhone + const normalizedEmergencyPhone = emergencyPhoneRef.current?.getNumber() || form.emergencyPhone + // Prepare data for backend with correct field names const profileData = { - companyName: user?.companyName || '', + companyName: form.companyName, + companyPhone: normalizedCompanyPhone, + contactPersonName: form.contactPersonName, + contactPersonPhone: normalizedContactPhone, address: form.street, // Backend expects 'address', not nested object zip_code: form.postalCode, // Backend expects 'zip_code' city: form.city, @@ -282,7 +413,10 @@ export default function CompanyAdditionalInformationPage() { branch: null, // Not collected in form, set to null numberOfEmployees: null, // Not collected in form, set to null accountHolderName: form.accountHolder, // Backend expects 'accountHolderName' - iban: form.iban.replace(/\s+/g, '') // Remove spaces from IBAN + iban: form.iban.replace(/\s+/g, ''), // Remove spaces from IBAN + secondPhone: normalizedSecondPhone || null, + emergencyContactName: form.emergencyName || null, + emergencyContactPhone: normalizedEmergencyPhone || null } const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/profile/company/complete`, { @@ -385,6 +519,57 @@ export default function CompanyAdditionalInformationPage() { required /> +
+ + +
+
+ + +
+
+ + +
+
+ + +
@@ -531,12 +716,12 @@ export default function CompanyAdditionalInformationPage() { -
diff --git a/src/app/quickaction-dashboard/register-additional-information/personal/page.tsx b/src/app/quickaction-dashboard/register-additional-information/personal/page.tsx index 77e5c87..428ba2a 100644 --- a/src/app/quickaction-dashboard/register-additional-information/personal/page.tsx +++ b/src/app/quickaction-dashboard/register-additional-information/personal/page.tsx @@ -7,8 +7,13 @@ import useAuthStore from '../../../store/authStore' import { useUserStatus } from '../../../hooks/useUserStatus' import { useToast } from '../../../components/toast/toastComponent' import { ChevronDownIcon } from '@heroicons/react/20/solid' +import TelephoneInput, { TelephoneInputHandle } from '../../../components/phone/telephoneInput' interface PersonalProfileData { + firstName: string + lastName: string + email: string + phone: string dob: string nationality: string street: string @@ -43,6 +48,10 @@ const COUNTRIES = [ ] const initialData: PersonalProfileData = { + firstName: '', + lastName: '', + email: '', + phone: '', dob: '', nationality: '', street: '', @@ -204,6 +213,9 @@ export default function PersonalAdditionalInformationPage() { const { accessToken } = useAuthStore() const { userStatus, loading: statusLoading, refreshStatus } = useUserStatus() const { showToast } = useToast() + const phoneRef = useRef(null) + const secondPhoneRef = useRef(null) + const emergencyPhoneRef = useRef(null) const [form, setForm] = useState(initialData) const [loading, setLoading] = useState(false) @@ -224,7 +236,7 @@ export default function PersonalAdditionalInformationPage() { const data = await res.json().catch(() => null) const profile = data?.profile const user = data?.user - if (!profile || abort) return + if ((!profile && !user) || abort) return const toDateInput = (d?: string) => { if (!d) return '' const dt = new Date(d) @@ -233,18 +245,22 @@ export default function PersonalAdditionalInformationPage() { } setForm(prev => ({ ...prev, - dob: toDateInput(profile.date_of_birth || profile.dateOfBirth), - nationality: profile.nationality || prev.nationality, - street: profile.address || prev.street, - postalCode: profile.zip_code || profile.zipCode || prev.postalCode, - city: profile.city || prev.city, - country: profile.country || prev.country, - accountHolder: profile.account_holder_name || profile.accountHolderName || prev.accountHolder, + firstName: user?.firstName || profile?.first_name || prev.firstName, + lastName: user?.lastName || profile?.last_name || prev.lastName, + email: user?.email || prev.email, + phone: user?.phone || profile?.phone || prev.phone, + dob: toDateInput(profile?.date_of_birth || profile?.dateOfBirth), + nationality: profile?.nationality || prev.nationality, + street: profile?.address || prev.street, + postalCode: profile?.zip_code || profile?.zipCode || prev.postalCode, + city: profile?.city || prev.city, + country: profile?.country || prev.country, + accountHolder: profile?.account_holder_name || profile?.accountHolderName || prev.accountHolder, // Prefer IBAN from users table (data.user.iban), fallback to profile if any - iban: (user?.iban ?? profile.iban ?? prev.iban) as string, - secondPhone: profile.phone_secondary || profile.phoneSecondary || prev.secondPhone, - emergencyName: profile.emergency_contact_name || profile.emergencyContactName || prev.emergencyName, - emergencyPhone: profile.emergency_contact_phone || profile.emergencyContactPhone || prev.emergencyPhone, + iban: (user?.iban ?? profile?.iban ?? prev.iban) as string, + secondPhone: profile?.phone_secondary || profile?.phoneSecondary || prev.secondPhone, + emergencyName: profile?.emergency_contact_name || profile?.emergencyContactName || prev.emergencyName, + emergencyPhone: profile?.emergency_contact_phone || profile?.emergencyContactPhone || prev.emergencyPhone, })) } catch (_) { // ignore prefill errors; user can still fill manually @@ -287,6 +303,7 @@ export default function PersonalAdditionalInformationPage() { const validate = () => { const requiredKeys: (keyof PersonalProfileData)[] = [ + 'firstName','lastName','email','phone', 'dob','nationality','street','postalCode','city','country','accountHolder','iban' ] for (const k of requiredKeys) { @@ -325,6 +342,72 @@ export default function PersonalAdditionalInformationPage() { }) return false } + + const phoneApi = phoneRef.current + const dialCode = phoneApi?.getDialCode?.() + const intlNumber = phoneApi?.getNumber() || '' + const valid = phoneApi?.isValid() ?? false + if (!dialCode) { + const msg = 'Please select a country code for your phone number.' + setError(msg) + showToast({ + variant: 'error', + title: 'Missing country code', + message: msg, + }) + return false + } + if (!intlNumber) { + const msg = 'Please enter your phone number.' + setError(msg) + showToast({ + variant: 'error', + title: 'Missing phone number', + message: msg, + }) + return false + } + if (!valid) { + const msg = 'Please enter a valid phone number.' + setError(msg) + showToast({ + variant: 'error', + title: 'Invalid phone number', + message: msg, + }) + return false + } + + const optionalSecond = form.secondPhone.trim() + if (optionalSecond) { + const secondApi = secondPhoneRef.current + const ok = secondApi?.isValid?.() ?? false + if (!ok) { + const msg = 'Please enter a valid second phone number.' + setError(msg) + showToast({ + variant: 'error', + title: 'Invalid phone number', + message: msg, + }) + return false + } + } + const optionalEmergency = form.emergencyPhone.trim() + if (optionalEmergency) { + const emergencyApi = emergencyPhoneRef.current + const ok = emergencyApi?.isValid?.() ?? false + if (!ok) { + const msg = 'Please enter a valid emergency phone number.' + setError(msg) + showToast({ + variant: 'error', + title: 'Invalid phone number', + message: msg, + }) + return false + } + } setError('') return true } @@ -348,17 +431,24 @@ export default function PersonalAdditionalInformationPage() { setLoading(true) try { + const normalizedPhone = phoneRef.current?.getNumber() || form.phone + const normalizedSecondPhone = secondPhoneRef.current?.getNumber() || form.secondPhone + const normalizedEmergencyPhone = emergencyPhoneRef.current?.getNumber() || form.emergencyPhone + // Prepare data for backend with correct field names const profileData = { + firstName: form.firstName, + lastName: form.lastName, + phone: normalizedPhone, dateOfBirth: form.dob, nationality: form.nationality, address: form.street, // Backend expects 'address', not nested object zip_code: form.postalCode, // Backend expects 'zip_code' city: form.city, country: form.country, - phoneSecondary: form.secondPhone || null, // Backend expects 'phoneSecondary' + phoneSecondary: normalizedSecondPhone || null, // Backend expects 'phoneSecondary' emergencyContactName: form.emergencyName || null, - emergencyContactPhone: form.emergencyPhone || null, + emergencyContactPhone: normalizedEmergencyPhone || null, accountHolderName: form.accountHolder, // Backend expects 'accountHolderName' iban: form.iban.replace(/\s+/g, '') // Remove spaces from IBAN } @@ -485,6 +575,56 @@ export default function PersonalAdditionalInformationPage() { Personal Information
+
+ + +
+
+ + +
+
+ + +
+
+ + +
@@ -633,12 +773,12 @@ export default function PersonalAdditionalInformationPage() { -