feat: register Backend link
This commit is contained in:
parent
943079d94f
commit
604556ca06
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline'
|
import { EyeIcon, EyeSlashIcon } from '@heroicons/react/24/outline'
|
||||||
|
import { useRegister } from '../hooks/useRegister'
|
||||||
|
|
||||||
interface RegisterFormProps {
|
interface RegisterFormProps {
|
||||||
mode: 'personal' | 'company'
|
mode: 'personal' | 'company'
|
||||||
@ -69,6 +70,9 @@ export default function RegisterForm({
|
|||||||
const [error, setError] = useState('')
|
const [error, setError] = useState('')
|
||||||
const [formFade, setFormFade] = useState('fade-in')
|
const [formFade, setFormFade] = useState('fade-in')
|
||||||
|
|
||||||
|
// Hook for backend calls
|
||||||
|
const { registerPersonalReferral, registerCompanyReferral, error: regError } = useRegister()
|
||||||
|
|
||||||
// Animate form when mode changes
|
// Animate form when mode changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFormFade('fade-out')
|
setFormFade('fade-out')
|
||||||
@ -108,7 +112,9 @@ export default function RegisterForm({
|
|||||||
const validatePersonalForm = (): boolean => {
|
const validatePersonalForm = (): boolean => {
|
||||||
if (!personalForm.firstName.trim() || !personalForm.lastName.trim() ||
|
if (!personalForm.firstName.trim() || !personalForm.lastName.trim() ||
|
||||||
!personalForm.email.trim() || !personalForm.confirmEmail.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')
|
setError('Alle Felder sind erforderlich')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -135,7 +141,9 @@ export default function RegisterForm({
|
|||||||
const validateCompanyForm = (): boolean => {
|
const validateCompanyForm = (): boolean => {
|
||||||
if (!companyForm.companyName.trim() || !companyForm.companyEmail.trim() ||
|
if (!companyForm.companyName.trim() || !companyForm.companyEmail.trim() ||
|
||||||
!companyForm.confirmCompanyEmail.trim() || !companyForm.contactPersonName.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')
|
setError('Alle Felder sind erforderlich')
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -167,16 +175,22 @@ export default function RegisterForm({
|
|||||||
if (!validatePersonalForm()) return
|
if (!validatePersonalForm()) return
|
||||||
|
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
setError('')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: Implement API call
|
const res = await registerPersonalReferral({
|
||||||
console.log('Personal registration:', { ...personalForm, refToken })
|
refToken: refToken || '',
|
||||||
|
firstName: personalForm.firstName,
|
||||||
// Simulate API delay
|
lastName: personalForm.lastName,
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
email: personalForm.email,
|
||||||
|
password: personalForm.password,
|
||||||
// For now, just call onRegistered
|
phone: personalForm.phoneNumber,
|
||||||
|
})
|
||||||
|
if (res.ok) {
|
||||||
onRegistered()
|
onRegistered()
|
||||||
|
} else {
|
||||||
|
setError(res.message || 'Registrierung fehlgeschlagen. Bitte versuche es erneut.')
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setError('Registrierung fehlgeschlagen. Bitte versuche es erneut.')
|
setError('Registrierung fehlgeschlagen. Bitte versuche es erneut.')
|
||||||
} finally {
|
} finally {
|
||||||
@ -191,16 +205,23 @@ export default function RegisterForm({
|
|||||||
if (!validateCompanyForm()) return
|
if (!validateCompanyForm()) return
|
||||||
|
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
setError('')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: Implement API call
|
const res = await registerCompanyReferral({
|
||||||
console.log('Company registration:', { ...companyForm, refToken })
|
refToken: refToken || '',
|
||||||
|
companyEmail: companyForm.companyEmail,
|
||||||
// Simulate API delay
|
password: companyForm.password,
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
companyName: companyForm.companyName,
|
||||||
|
companyPhone: companyForm.companyPhone,
|
||||||
// For now, just call onRegistered
|
contactPersonName: companyForm.contactPersonName,
|
||||||
|
contactPersonPhone: companyForm.contactPersonPhone,
|
||||||
|
})
|
||||||
|
if (res.ok) {
|
||||||
onRegistered()
|
onRegistered()
|
||||||
|
} else {
|
||||||
|
setError(res.message || 'Registrierung fehlgeschlagen. Bitte versuche es erneut.')
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setError('Registrierung fehlgeschlagen. Bitte versuche es erneut.')
|
setError('Registrierung fehlgeschlagen. Bitte versuche es erneut.')
|
||||||
} finally {
|
} 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
|
// Input change handlers
|
||||||
const handlePersonalChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handlePersonalChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { name, value } = e.target
|
const { name, value } = e.target
|
||||||
@ -375,7 +401,7 @@ export default function RegisterForm({
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="phoneNumber" className="block text-sm font-medium text-[#0F172A] mb-2">
|
<label htmlFor="phoneNumber" className="block text-sm font-medium text-[#0F172A] mb-2">
|
||||||
Telefonnummer
|
Telefonnummer *
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
@ -385,6 +411,7 @@ export default function RegisterForm({
|
|||||||
onChange={handlePersonalChange}
|
onChange={handlePersonalChange}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#8D6B1D] focus:border-transparent transition-colors text-primary"
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#8D6B1D] focus:border-transparent transition-colors text-primary"
|
||||||
placeholder="+49 123 456 7890"
|
placeholder="+49 123 456 7890"
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -522,7 +549,7 @@ export default function RegisterForm({
|
|||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="companyPhone" className="block text-sm font-medium text-[#0F172A] mb-2">
|
<label htmlFor="companyPhone" className="block text-sm font-medium text-[#0F172A] mb-2">
|
||||||
Firmen-Telefon
|
Firmen-Telefon *
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
@ -532,12 +559,13 @@ export default function RegisterForm({
|
|||||||
onChange={handleCompanyChange}
|
onChange={handleCompanyChange}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#8D6B1D] focus:border-transparent transition-colors text-primary"
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#8D6B1D] focus:border-transparent transition-colors text-primary"
|
||||||
placeholder="+49 123 456 7890"
|
placeholder="+49 123 456 7890"
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="contactPersonPhone" className="block text-sm font-medium text-[#0F172A] mb-2">
|
<label htmlFor="contactPersonPhone" className="block text-sm font-medium text-[#0F172A] mb-2">
|
||||||
Ansprechpartner-Telefon
|
Ansprechpartner-Telefon *
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="tel"
|
type="tel"
|
||||||
@ -547,6 +575,7 @@ export default function RegisterForm({
|
|||||||
onChange={handleCompanyChange}
|
onChange={handleCompanyChange}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#8D6B1D] focus:border-transparent transition-colors text-primary"
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-[#8D6B1D] focus:border-transparent transition-colors text-primary"
|
||||||
placeholder="+49 123 456 7890"
|
placeholder="+49 123 456 7890"
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
154
src/app/register/hooks/useRegister.ts
Normal file
154
src/app/register/hooks/useRegister.ts
Normal file
@ -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<T = any> = {
|
||||||
|
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<string>('')
|
||||||
|
|
||||||
|
const base = process.env.NEXT_PUBLIC_API_BASE_URL || ''
|
||||||
|
|
||||||
|
const registerPersonalReferral = async (payload: PersonalReferralPayload): Promise<RegisterResult> => {
|
||||||
|
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<RegisterResult> => {
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user