'use client' import { useState, useMemo, useRef, useEffect, useCallback } from 'react' import { useRouter } from 'next/navigation' import PageLayout from '../../../components/PageLayout' 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 city: string country: string accountHolder: string iban: string bic: string secondPhone: string emergencyName: string emergencyPhone: string } // 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 init: CompanyProfileData = { companyName: '', companyEmail: '', companyPhone: '', contactPersonName: '', contactPersonPhone: '', vatNumber: '', street: '', postalCode: '', city: '', country: '', accountHolder: '', iban: '', bic: '', secondPhone: '', emergencyName: '', emergencyPhone: '' } function ModernSelect({ label, placeholder = 'Select…', value, onChange, options, }: { label: string placeholder?: string value: string onChange: (next: string) => void options: { value: string; label: string }[] }) { const [open, setOpen] = useState(false) const [query, setQuery] = useState('') const btnRef = useRef(null) const [pos, setPos] = useState({ left: 16, top: 0, width: 320 }) const selected = useMemo(() => options.find(o => o.value === value) || null, [options, value]) const filtered = useMemo(() => { const q = query.trim().toLowerCase() if (!q) return options return options.filter(o => o.label.toLowerCase().includes(q)) }, [options, query]) useEffect(() => { if (!open) return const update = () => { const el = btnRef.current if (!el) return const r = el.getBoundingClientRect() const padding = 16 const width = Math.min(r.width, window.innerWidth - padding * 2) const left = Math.max(padding, Math.min(r.left, window.innerWidth - width - padding)) const top = r.bottom + 8 setPos({ left, top, width }) } update() window.addEventListener('resize', update) window.addEventListener('scroll', update, true) return () => { window.removeEventListener('resize', update) window.removeEventListener('scroll', update, true) } }, [open]) useEffect(() => { if (!open) return const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') setOpen(false) } window.addEventListener('keydown', onKey) return () => window.removeEventListener('keydown', onKey) }, [open]) return (
{open && ( <>
setOpen(false)} aria-hidden />
setQuery(e.target.value)} placeholder="Search…" className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-[#8D6B1D] focus:border-transparent" autoFocus />
{filtered.length === 0 ? (
No results
) : ( filtered.map(o => { const active = o.value === value return ( ) }) )}
)}
) } export default function CompanyAdditionalInformationPage() { const router = useRouter() const user = useAuthStore(s => s.user) // NEW const isAuthReady = useAuthStore(s => (s as any).isAuthReady) // NEW 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) const suppressAutoRedirectRef = useRef(false) const smoothReplace = useCallback((to: string) => { if (redirectOnceRef.current) return redirectOnceRef.current = true setRedirectTo(to) window.setTimeout(() => router.replace(to), 200) }, [router]) // NEW: hard block if step already done OR all steps done useEffect(() => { if (statusLoading || !userStatus) return if (suppressAutoRedirectRef.current) return const allDone = !!userStatus.email_verified && !!userStatus.documents_uploaded && !!userStatus.profile_completed && !!userStatus.contract_signed if (allDone) { smoothReplace('/dashboard') // CHANGED } else if (userStatus.profile_completed) { smoothReplace('/quickaction-dashboard') // CHANGED } }, [statusLoading, userStatus, smoothReplace]) // NEW: must be logged in useEffect(() => { if (!isAuthReady) return if (!user || !accessToken) smoothReplace('/login') }, [isAuthReady, user, accessToken, smoothReplace]) const handleChange = (e: React.ChangeEvent) => { const { name, value } = e.target setForm(p => ({ ...p, [name]: value })) setError('') } const validate = () => { const required: (keyof CompanyProfileData)[] = [ 'companyName','companyEmail','companyPhone','contactPersonName','contactPersonPhone', 'vatNumber','street','postalCode','city','country','accountHolder','iban' ] for (const k of required) { if (!form[k].trim()) { const msg = 'Bitte alle Pflichtfelder ausfüllen.' setError(msg) showToast({ variant: 'error', title: 'Missing information', message: msg, }) 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) showToast({ variant: 'error', title: 'Invalid IBAN', message: msg, }) return false } setError('') return true } const submit = async (e: React.FormEvent) => { e.preventDefault() if (loading || success) return if (!validate()) return if (!accessToken) { const msg = 'Not authenticated. Please log in again.' setError(msg) showToast({ variant: 'error', title: 'Authentication error', message: msg, }) return } 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: 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, country: form.country, registrationNumber: form.vatNumber, // Map VAT number to registration number businessType: 'company', // Default business type 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 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`, { method: 'POST', headers: { 'Authorization': `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify(profileData) }) if (!response.ok) { const errorData = await response.json().catch(() => ({ message: 'Save failed' })) throw new Error(errorData.message || 'Save failed') } setSuccess(true) showToast({ variant: 'success', title: 'Profile saved', message: 'Your company profile has been saved successfully.', }) // Refresh user status to update profile completion state suppressAutoRedirectRef.current = true await refreshStatus() // Redirect back to tutorial modal after short delay setTimeout(() => { smoothReplace('/quickaction-dashboard?tutorial=true') }, 1500) } catch (error: any) { console.error('Company profile save error:', error) const msg = error.message || 'Speichern fehlgeschlagen.' setError(msg) showToast({ variant: 'error', title: 'Save failed', message: msg, }) } finally { setLoading(false) } } const setField = (name: keyof CompanyProfileData, value: string) => { setForm(p => ({ ...p, [name]: value })) setError('') } return ( {/* NEW: smooth redirect overlay */} {redirectTo && (
Redirecting…
Please wait
)}
{/* Animated background (same as dashboard) */}
{/* Soft gradient blobs */}
{/* Subtle radial highlight */}

Complete Company Profile

{/* Company Details */}

Company Details

setField('country', v)} options={COUNTRIES.map(c => ({ value: c, label: c }))} />

{/* Bank Details */}

Bank Details


{/* Additional Information */}

Additional Information

{error && (
{error}
)} {success && (
Data saved. Redirecting shortly…
)}
) }