diff --git a/src/app/register/components/RegisterForm.tsx b/src/app/register/components/RegisterForm.tsx index d16c2e6..160b2ab 100644 --- a/src/app/register/components/RegisterForm.tsx +++ b/src/app/register/components/RegisterForm.tsx @@ -8,6 +8,7 @@ interface RegisterFormProps { setMode: (mode: 'personal' | 'company') => void refToken: string | null onRegistered: () => void + referrerEmail?: string } interface PersonalFormData { @@ -35,7 +36,8 @@ export default function RegisterForm({ mode, setMode, refToken, - onRegistered + onRegistered, + referrerEmail }: RegisterFormProps) { // Personal form state const [personalForm, setPersonalForm] = useState({ @@ -260,9 +262,10 @@ export default function RegisterForm({

Registrierung für Profit Planet

- {refToken && ( + {/* Replace generic invite with referrer email inside the form */} + {referrerEmail && (

- Du wurdest eingeladen! + Du wurdest von {referrerEmail} eingeladen!

)} diff --git a/src/app/register/components/invalidRefLinkModal.tsx b/src/app/register/components/invalidRefLinkModal.tsx new file mode 100644 index 0000000..c467aa2 --- /dev/null +++ b/src/app/register/components/invalidRefLinkModal.tsx @@ -0,0 +1,67 @@ +'use client' + +import React from 'react' +import { ExclamationTriangleIcon } from '@heroicons/react/24/outline' + +interface InvalidRefLinkModalProps { + open: boolean + inline?: boolean + token?: string | null + onClose?: () => void + onGoHome?: () => void +} + +export default function InvalidRefLinkModal({ + open, + inline = true, + token, + onClose, + onGoHome +}: InvalidRefLinkModalProps) { + if (!open) return null + + const Content = ( +
+
+ +
+

Invalid invitation link

+

+ This registration link is invalid or no longer active. Please request a new link. +

+ {token ? ( +

+ Token: {token} +

+ ) : null} +
+ + {onClose && ( + + )} +
+
+
+
+ ) + + if (inline) { + return ( +
+ {Content} +
+ ) + } + + return Content +} \ No newline at end of file diff --git a/src/app/register/page.tsx b/src/app/register/page.tsx index 3ede3f7..8dc485d 100644 --- a/src/app/register/page.tsx +++ b/src/app/register/page.tsx @@ -6,6 +6,7 @@ import useAuthStore from '../store/authStore' import RegisterForm from './components/RegisterForm' import PageLayout from '../components/PageLayout' import SessionDetectedModal from './components/SessionDetectedModal' +import InvalidRefLinkModal from './components/invalidRefLinkModal' export default function RegisterPage() { const searchParams = useSearchParams() @@ -22,6 +23,16 @@ export default function RegisterPage() { const [showSessionModal, setShowSessionModal] = useState(false) const [sessionCleared, setSessionCleared] = useState(false) + // NEW: Referral validation state + const [isRefChecked, setIsRefChecked] = useState(false) + const [invalidRef, setInvalidRef] = useState(false) + const [refInfo, setRefInfo] = useState<{ + referrerName?: string + referrerEmail?: string + isUnlimited?: boolean + usesRemaining?: number + } | null>(null) + // Redirect to login after simulated registration useEffect(() => { if (registered) { @@ -30,10 +41,68 @@ export default function RegisterPage() { } }, [registered, router]) - // Detect existing logged-in session + // NEW: Validate referral token (must exist and be valid) useEffect(() => { - if (user && !sessionCleared) setShowSessionModal(true) - }, [user, sessionCleared]) + let cancelled = false + + const validateRef = async () => { + if (!refToken) { + console.warn('⚠️ Register: Missing ?ref token in URL') + if (!cancelled) { + setInvalidRef(true) + setIsRefChecked(true) + } + return + } + + const base = process.env.NEXT_PUBLIC_API_BASE_URL || '' + const url = `${base}/api/referral/info/${encodeURIComponent(refToken)}` + console.log('🌐 Register: fetching referral info:', url) + + try { + const res = await fetch(url, { method: 'GET', credentials: 'include' }) + console.log('📡 Register: referral info status:', res.status) + const body = await res.json().catch(() => null) + console.log('📦 Register: referral info body:', body) + + const success = !!body?.success + const isUnlimited = !!body?.isUnlimited + const usesRemaining = typeof body?.usesRemaining === 'number' ? body.usesRemaining : 0 + + const isActive = success && (isUnlimited || usesRemaining > 0) + + if (!cancelled) { + if (isActive) { + setRefInfo({ + referrerName: body?.referrerName, + referrerEmail: body?.referrerEmail, + isUnlimited, + usesRemaining + }) + setInvalidRef(false) + } else { + console.warn('⛔ Register: referral not active/invalid') + setInvalidRef(true) + } + setIsRefChecked(true) + } + } catch (e) { + console.error('❌ Register: referral info fetch error:', e) + if (!cancelled) { + setInvalidRef(true) + setIsRefChecked(true) + } + } + } + + validateRef() + return () => { cancelled = true } + }, [refToken]) + + // Detect existing logged-in session (only if ref is valid) + useEffect(() => { + if (isRefChecked && !invalidRef && user && !sessionCleared) setShowSessionModal(true) + }, [isRefChecked, invalidRef, user, sessionCleared]) const handleLogout = async () => { await logout() @@ -46,11 +115,95 @@ export default function RegisterPage() { router.push('/dashboard') } + // NEW: Gate rendering until referral check is done + if (!isRefChecked) { + return ( + +
+
+
+

Überprüfe Einladungslink…

+
+
+
+ ) + } + + // NEW: Invalid referral link state — show modal instead of form with same background as register form + if (invalidRef) { + return ( + +
+
+ {/* Pattern */} + + + {/* Colored blur */} +
+
+ ) + } + return (
{/* Background section wrapper */} -
+
{/* Pattern */}