Checking invitation link…
'use client'
import { useEffect, useState, type CSSProperties } from 'react'
import { useSearchParams, useRouter } from 'next/navigation'
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'
import { ToastProvider, useToast } from '../components/toast/toastComponent'
import Waves from '../components/background/waves'
import BlueBlurryBackground from '../components/background/blueblurry' // NEW
// NEW: inner component that actually uses useToast and all the logic
function RegisterPageInner() {
const searchParams = useSearchParams()
const refToken = searchParams.get('ref')
const [registered, setRegistered] = useState(false)
const [mode, setMode] = useState<'personal' | 'company'>('personal')
const router = useRouter()
const { showToast } = useToast()
// Auth state
const user = useAuthStore(state => state.user)
const logout = useAuthStore(state => state.logout)
// Session management
const [showSessionModal, setShowSessionModal] = useState(false)
const [sessionCleared, setSessionCleared] = useState(false)
// 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 after registration
useEffect(() => {
if (registered) {
const t = setTimeout(() => router.push('/login'), 4000)
return () => clearTimeout(t)
}
}, [registered, router])
// Validate referral token
useEffect(() => {
let cancelled = false
const validateRef = async () => {
if (!refToken) {
if (!cancelled) {
setInvalidRef(true)
setIsRefChecked(true)
}
showToast({
variant: 'error',
title: 'Invitation error',
message: 'No invitation token found in the link.'
})
return
}
const base = process.env.NEXT_PUBLIC_API_BASE_URL || ''
const url = `${base}/api/referral/info/${encodeURIComponent(refToken)}`
try {
const res = await fetch(url, { method: 'GET', credentials: 'include' })
const body = await res.json().catch(() => null)
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)
showToast({
variant: 'success',
title: 'Invitation verified',
message: 'Your invitation link is valid. You can register now.'
})
} else {
setInvalidRef(true)
showToast({
variant: 'error',
title: 'Invalid invitation',
message: 'This invitation link is invalid or no longer active.'
})
}
setIsRefChecked(true)
}
} catch {
if (!cancelled) {
setInvalidRef(true)
setIsRefChecked(true)
}
showToast({
variant: 'error',
title: 'Network error',
message: 'Could not validate the invitation link. Please try again.'
})
}
}
validateRef()
return () => {
cancelled = true
}
// showToast intentionally omitted to avoid effect re-run loops (provider value can change)
}, [refToken]) // note: showToast intentionally omitted to avoid effect re-run loops
// Detect existing logged-in session
useEffect(() => {
if (isRefChecked && !invalidRef && user && !sessionCleared) {
setShowSessionModal(true)
}
}, [isRefChecked, invalidRef, user, sessionCleared])
const handleLogout = async () => {
await logout()
setSessionCleared(true)
setShowSessionModal(false)
}
const handleCancel = () => {
setShowSessionModal(false)
router.push('/dashboard')
}
const [isMobile, setIsMobile] = useState(false)
useEffect(() => {
const mq = window.matchMedia('(max-width: 768px)')
const apply = () => setIsMobile(mq.matches)
apply()
mq.addEventListener?.('change', apply)
window.addEventListener('resize', apply, { passive: true })
return () => {
mq.removeEventListener?.('change', apply)
window.removeEventListener('resize', apply)
}
}, [])
const mainStyle: CSSProperties = {
paddingTop: isMobile
? 'calc(var(--pp-header-spacer, 0px) + clamp(1.25rem, 3.5vh, 2.25rem))'
: 'calc(var(--pp-header-spacer, 0px) + clamp(5rem, 8vh, 7rem))',
transition: 'padding-top 260ms ease, opacity 260ms ease',
willChange: 'padding-top, opacity',
opacity: 'var(--pp-page-shift-opacity, 1)',
}
const BackgroundShell = ({ children }: { children: React.ReactNode }) => {
return isMobile ? (
Checking invitation link…
Create your personal or company account with Profit Planet.