This registration link is invalid or no longer active. Please request a new link.
+ )}
+
{onClose && (
@@ -55,13 +57,7 @@ export default function InvalidRefLinkModal({
)
- if (inline) {
- return (
-
- {Content}
-
- )
- }
+ 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 143e462..300fcf7 100644
--- a/src/app/register/page.tsx
+++ b/src/app/register/page.tsx
@@ -1,20 +1,23 @@
'use client'
-import { useEffect, useState } from 'react'
+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 } from '../components/toast/toastComponent'
+import { ToastProvider, useToast } from '../components/toast/toastComponent'
+import Waves from '../components/waves'
-export default function RegisterPage() {
+// 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)
@@ -24,7 +27,7 @@ export default function RegisterPage() {
const [showSessionModal, setShowSessionModal] = useState(false)
const [sessionCleared, setSessionCleared] = useState(false)
- // NEW: Referral validation state
+ // Referral validation state
const [isRefChecked, setIsRefChecked] = useState(false)
const [invalidRef, setInvalidRef] = useState(false)
const [refInfo, setRefInfo] = useState<{
@@ -34,42 +37,43 @@ export default function RegisterPage() {
usesRemaining?: number
} | null>(null)
- // Redirect to login after simulated registration
+ // Redirect after registration
useEffect(() => {
if (registered) {
- const t = setTimeout(() => router.push('/login'), 4000) // was 1200
+ const t = setTimeout(() => router.push('/login'), 4000)
return () => clearTimeout(t)
}
}, [registered, router])
- // NEW: Validate referral token (must exist and be valid)
+ // Validate referral token
useEffect(() => {
let cancelled = false
const validateRef = async () => {
if (!refToken) {
- console.warn('⚠️ Register: Missing ?ref token in URL')
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)}`
- 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 usesRemaining =
+ typeof body?.usesRemaining === 'number' ? body.usesRemaining : 0
const isActive = success && (isUnlimited || usesRemaining > 0)
if (!cancelled) {
@@ -81,28 +85,46 @@ export default function RegisterPage() {
usesRemaining
})
setInvalidRef(false)
+ showToast({
+ variant: 'success',
+ title: 'Invitation verified',
+ message: 'Your invitation link is valid. You can register now.'
+ })
} else {
- console.warn('⛔ Register: referral not active/invalid')
setInvalidRef(true)
+ showToast({
+ variant: 'error',
+ title: 'Invalid invitation',
+ message: 'This invitation link is invalid or no longer active.'
+ })
}
setIsRefChecked(true)
}
- } catch (e) {
- console.error('❌ Register: referral info fetch error:', e)
+ } 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 }
- }, [refToken])
+ 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 (only if ref is valid)
+ // Detect existing logged-in session
useEffect(() => {
- if (isRefChecked && !invalidRef && user && !sessionCleared) setShowSessionModal(true)
+ if (isRefChecked && !invalidRef && user && !sessionCleared) {
+ setShowSessionModal(true)
+ }
}, [isRefChecked, invalidRef, user, sessionCleared])
const handleLogout = async () => {
@@ -116,79 +138,110 @@ export default function RegisterPage() {
router.push('/dashboard')
}
- // NEW: Gate rendering until referral check is done
+ 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)',
+ }
+
+ // --- Render branches (unchanged except classNames) ---
+
if (!isRefChecked) {
return (
-
-
-
-
-
-
Checking invitation link…
+
+
+
+
+
+
+
+
+
+
Checking invitation link…
+
+
-
-
+
+
)
}
- // NEW: Invalid referral link state — show modal instead of form with same background as register form
if (invalidRef) {
return (
-
-
-
- {/* make wrapper flex-1 so background reaches the footer */}
-
- {/* Pattern */}
-
-
- {/* Colored blur */}
+
+
+
+
+
-
- {/* Additional background layers */}
-
-
-
-
-
+
)
}
+ // normal register
return (
-
-
-
- {/* Background section wrapper */}
- {/* make wrapper flex-1 so background reaches the footer */}
-
- {/* Pattern */}
-
-
- {/* Colored blur */}
+
+
+
+
+
+
+
+
+
+ Register now
+
+
+ Create your personal or company account with Profit Planet.
+
+
- {/* Additional background layers */}
-
-
-
-
- {/* Heading (optional – adjusted to registration context) */}
-
-
- Register now
-
-
- Create your personal or company account with Profit Planet.
-
-
-
- {/* Content area */}
-
- {showSessionModal ? (
-
-
-
- ) : (
- <>
- {/* Register form (only if ref valid) */}
- {(!user || sessionCleared) && (
-
setRegistered(true)}
- referrerEmail={refInfo?.referrerEmail}
+
+ {showSessionModal ? (
+
+
- )}
- {registered && (
-
- Registration successful – redirecting...
-
- )}
- >
- )}
+
+ ) : (
+ <>
+ {(!user || sessionCleared) && (
+
setRegistered(true)}
+ referrerEmail={refInfo?.referrerEmail}
+ />
+ )}
+ {registered && (
+
+ Registration successful – redirecting...
+
+ )}
+ >
+ )}
+
-
+
+
+ )
+}
+
+// NEW: default export only provides the ToastProvider wrapper
+export default function RegisterPage() {
+ return (
+
+
)
}
\ No newline at end of file
diff --git a/src/app/utils/phoneUtils.ts b/src/app/utils/phoneUtils.ts
index 7342419..14952d1 100644
--- a/src/app/utils/phoneUtils.ts
+++ b/src/app/utils/phoneUtils.ts
@@ -11,15 +11,16 @@
const ITI_CDN_CSS =
'https://cdn.jsdelivr.net/npm/intl-tel-input@25.15.0/build/css/intlTelInput.css'
+
+// Use the official bundle that includes utils to avoid "getCoreNumber" being undefined.
const ITI_CDN_JS =
- 'https://cdn.jsdelivr.net/npm/intl-tel-input@25.15.0/build/js/intlTelInput.min.js'
-const ITI_CDN_UTILS =
- 'https://cdn.jsdelivr.net/npm/intl-tel-input@25.15.0/build/js/utils.js'
+ 'https://cdn.jsdelivr.net/npm/intl-tel-input@25.15.0/build/js/intlTelInputWithUtils.min.js'
export type IntlTelInputInstance = {
destroy: () => void
getNumber: () => string
isValidNumber: () => boolean
+ setNumber?: (number: string) => void
getValidationError?: () => number
getSelectedCountryData?: () => { name: string; iso2: string; dialCode: string }
promise?: Promise
@@ -27,7 +28,9 @@ export type IntlTelInputInstance = {
declare global {
interface Window {
- intlTelInput?: (input: HTMLInputElement, options: any) => IntlTelInputInstance
+ intlTelInput?: ((input: HTMLInputElement, options: any) => IntlTelInputInstance) & {
+ getInstance?: (input: HTMLInputElement) => IntlTelInputInstance | null
+ }
}
}
@@ -70,26 +73,36 @@ async function loadIntlTelInputFromCdn(): Promise<
document.head.appendChild(style)
}
- // JS once
+ // JS once (but replace if the existing script points to a different bundle)
if (window.intlTelInput) {
console.log('[phoneUtils] intl-tel-input already loaded on window')
return window.intlTelInput
}
- console.log('[phoneUtils] Loading intl-tel-input core (no utils) from CDN…')
+ console.log('[phoneUtils] Loading intl-tel-input (with utils) from CDN…')
await new Promise((resolve, reject) => {
const existing = document.querySelector(
'script[data-intl-tel-input-js="true"]'
)
+
if (existing) {
- console.log('[phoneUtils] Reusing existing intl-tel-input