From 604556ca06f6b0b1a7d5d65657fb9d8219bbcee1 Mon Sep 17 00:00:00 2001 From: DeathKaioken Date: Thu, 16 Oct 2025 08:48:43 +0200 Subject: [PATCH] feat: register Backend link --- src/app/register/components/RegisterForm.tsx | 75 ++++++--- src/app/register/hooks/useRegister.ts | 154 +++++++++++++++++++ 2 files changed, 206 insertions(+), 23 deletions(-) create mode 100644 src/app/register/hooks/useRegister.ts diff --git a/src/app/register/components/RegisterForm.tsx b/src/app/register/components/RegisterForm.tsx index 160b2ab..1cc2435 100644 --- a/src/app/register/components/RegisterForm.tsx +++ b/src/app/register/components/RegisterForm.tsx @@ -2,6 +2,7 @@ import { useState, useEffect } from 'react' import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline' +import { useRegister } from '../hooks/useRegister' interface RegisterFormProps { mode: 'personal' | 'company' @@ -69,6 +70,9 @@ export default function RegisterForm({ const [error, setError] = useState('') const [formFade, setFormFade] = useState('fade-in') + // Hook for backend calls + const { registerPersonalReferral, registerCompanyReferral, error: regError } = useRegister() + // Animate form when mode changes useEffect(() => { setFormFade('fade-out') @@ -108,7 +112,9 @@ export default function RegisterForm({ const validatePersonalForm = (): boolean => { if (!personalForm.firstName.trim() || !personalForm.lastName.trim() || !personalForm.email.trim() || !personalForm.confirmEmail.trim() || - !personalForm.password.trim() || !personalForm.confirmPassword.trim()) { + !personalForm.password.trim() || !personalForm.confirmPassword.trim() || + !personalForm.phoneNumber.trim() // now required by backend + ) { setError('Alle Felder sind erforderlich') return false } @@ -135,7 +141,9 @@ export default function RegisterForm({ const validateCompanyForm = (): boolean => { if (!companyForm.companyName.trim() || !companyForm.companyEmail.trim() || !companyForm.confirmCompanyEmail.trim() || !companyForm.contactPersonName.trim() || - !companyForm.password.trim() || !companyForm.confirmPassword.trim()) { + !companyForm.password.trim() || !companyForm.confirmPassword.trim() || + !companyForm.companyPhone.trim() || !companyForm.contactPersonPhone.trim() // now required + ) { setError('Alle Felder sind erforderlich') return false } @@ -167,16 +175,22 @@ export default function RegisterForm({ if (!validatePersonalForm()) return setLoading(true) - + setError('') + try { - // TODO: Implement API call - console.log('Personal registration:', { ...personalForm, refToken }) - - // Simulate API delay - await new Promise(resolve => setTimeout(resolve, 1000)) - - // For now, just call onRegistered - onRegistered() + const res = await registerPersonalReferral({ + refToken: refToken || '', + firstName: personalForm.firstName, + lastName: personalForm.lastName, + email: personalForm.email, + password: personalForm.password, + phone: personalForm.phoneNumber, + }) + if (res.ok) { + onRegistered() + } else { + setError(res.message || 'Registrierung fehlgeschlagen. Bitte versuche es erneut.') + } } catch (error) { setError('Registrierung fehlgeschlagen. Bitte versuche es erneut.') } finally { @@ -191,16 +205,23 @@ export default function RegisterForm({ if (!validateCompanyForm()) return setLoading(true) - + setError('') + try { - // TODO: Implement API call - console.log('Company registration:', { ...companyForm, refToken }) - - // Simulate API delay - await new Promise(resolve => setTimeout(resolve, 1000)) - - // For now, just call onRegistered - onRegistered() + const res = await registerCompanyReferral({ + refToken: refToken || '', + companyEmail: companyForm.companyEmail, + password: companyForm.password, + companyName: companyForm.companyName, + companyPhone: companyForm.companyPhone, + contactPersonName: companyForm.contactPersonName, + contactPersonPhone: companyForm.contactPersonPhone, + }) + if (res.ok) { + onRegistered() + } else { + setError(res.message || 'Registrierung fehlgeschlagen. Bitte versuche es erneut.') + } } catch (error) { setError('Registrierung fehlgeschlagen. Bitte versuche es erneut.') } finally { @@ -208,6 +229,11 @@ export default function RegisterForm({ } } + // Surface hook error if present and no local error + useEffect(() => { + if (regError && !error) setError(regError) + }, [regError]) // eslint-disable-line react-hooks/exhaustive-deps + // Input change handlers const handlePersonalChange = (e: React.ChangeEvent) => { const { name, value } = e.target @@ -375,7 +401,7 @@ export default function RegisterForm({
@@ -522,7 +549,7 @@ export default function RegisterForm({
diff --git a/src/app/register/hooks/useRegister.ts b/src/app/register/hooks/useRegister.ts new file mode 100644 index 0000000..8a37782 --- /dev/null +++ b/src/app/register/hooks/useRegister.ts @@ -0,0 +1,154 @@ +'use client' + +import { useState } from 'react' + +export type PersonalReferralPayload = { + refToken: string + firstName: string + lastName: string + email: string + password: string + phone: string + lang?: 'de' | 'en' +} + +export type CompanyReferralPayload = { + refToken: string + companyEmail: string + password: string + companyName: string + companyPhone: string + contactPersonName: string + contactPersonPhone: string + lang?: 'de' | 'en' +} + +type RegisterResult = { + ok: boolean + status: number + data?: T | null + message?: string +} + +function detectLang(): 'de' | 'en' { + if (typeof navigator !== 'undefined') { + const n = navigator.language || '' + if (n.toLowerCase().startsWith('de')) return 'de' + } + return 'en' +} + +function mapError(status: number): string { + switch (status) { + case 404: + return 'Referral token not found.' + case 410: + return 'Referral token expired or exhausted.' + case 403: + return 'Referral token is inactive.' + case 400: + return 'Invalid registration data or token validation failed.' + default: + return 'Registration failed. Please try again later.' + } +} + +// NEW: read ?ref from the URL as a fallback +function getRefTokenFromUrl(): string | null { + if (typeof window === 'undefined') return null + try { + const u = new URL(window.location.href) + return u.searchParams.get('ref') + } catch { + return null + } +} + +export function useRegister() { + const [loading, setLoading] = useState(false) + const [error, setError] = useState('') + + const base = process.env.NEXT_PUBLIC_API_BASE_URL || '' + + const registerPersonalReferral = async (payload: PersonalReferralPayload): Promise => { + setError('') + setLoading(true) + + // Resolve token: prefer payload, fallback to URL + const finalRefToken = (payload.refToken || '').trim() || getRefTokenFromUrl() || '' + const body = { ...payload, refToken: finalRefToken, lang: payload.lang || detectLang() } + + // NOTE: align with other endpoints using /api prefix + const url = `${base}/api/register/personal-referral` + console.log('🌐 useRegister: POST personal-referral', { url, refToken: finalRefToken ? `${finalRefToken.slice(0, 6)}…${finalRefToken.slice(-6)}` : null }) + + try { + const res = await fetch(url, { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + }) + const json = await res.json().catch(() => null) + console.log('📡 useRegister: personal status:', res.status, 'body:', json) + if (!res.ok) { + const msg = json?.message || mapError(res.status) + setError(msg) + return { ok: false, status: res.status, data: json, message: msg } + } + return { ok: true, status: res.status, data: json, message: json?.message } + } catch (e) { + console.error('❌ useRegister: personal error:', e) + const msg = 'Network error. Please try again later.' + setError(msg) + return { ok: false, status: 0, data: null, message: msg } + } finally { + setLoading(false) + } + } + + const registerCompanyReferral = async (payload: CompanyReferralPayload): Promise => { + setError('') + setLoading(true) + + // Resolve token: prefer payload, fallback to URL + const finalRefToken = (payload.refToken || '').trim() || getRefTokenFromUrl() || '' + const body = { ...payload, refToken: finalRefToken, lang: payload.lang || detectLang() } + + // NOTE: align with other endpoints using /api prefix + const url = `${base}/api/register/company-referral` + console.log('🌐 useRegister: POST company-referral', { url, refToken: finalRefToken ? `${finalRefToken.slice(0, 6)}…${finalRefToken.slice(-6)}` : null }) + + try { + const res = await fetch(url, { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body), + }) + const json = await res.json().catch(() => null) + console.log('📡 useRegister: company status:', res.status, 'body:', json) + if (!res.ok) { + const msg = json?.message || mapError(res.status) + setError(msg) + return { ok: false, status: res.status, data: json, message: msg } + } + return { ok: true, status: res.status, data: json, message: json?.message } + } catch (e) { + console.error('❌ useRegister: company error:', e) + const msg = 'Network error. Please try again later.' + setError(msg) + return { ok: false, status: 0, data: null, message: msg } + } finally { + setLoading(false) + } + } + + return { + loading, + error, + setError, + registerPersonalReferral, + registerCompanyReferral, + } +}