feat: login+Permission protection referral Management

This commit is contained in:
DeathKaioken 2025-10-16 08:00:20 +02:00
parent 09083e066a
commit ffd7daeb11

View File

@ -8,8 +8,16 @@ import DeactivateReferralLinkModal from './components/deactivateReferralLinkModa
import ReferralStatisticWidget from './components/referralStatisticWidget'
import GenerateReferralLinkWidget from './components/generateReferralLinkWidget'
import ReferralLinksListWidget from './components/referralLinksListWidget'
import { useRouter } from 'next/navigation'
import useAuthStore from '../store/authStore'
export default function ReferralManagementPage() {
const router = useRouter()
const user = useAuthStore(s => s.user)
const isAuthReady = useAuthStore(s => s.isAuthReady)
const accessToken = useAuthStore(s => s.accessToken)
const refreshAuthToken = useAuthStore(s => s.refreshAuthToken)
// Replace mock stats with backend-aligned shape
const [stats, setStats] = useState({
activeLinks: 0,
@ -50,6 +58,96 @@ export default function ReferralManagementPage() {
}
}
// Permission gate state
const [isPermChecked, setIsPermChecked] = useState(false)
const [hasReferralPerm, setHasReferralPerm] = useState(false)
// Auth + permission guard
useEffect(() => {
let cancelled = false
const run = async () => {
if (!isAuthReady) return
if (!user) {
console.log('🔐 referral-management: no user, redirect to /login')
router.replace('/login')
return
}
// Resolve user id
const uid = (user as any)?.id ?? (user as any)?._id ?? (user as any)?.userId
if (!uid) {
console.warn('⚠️ referral-management: user id missing, denying access')
if (!cancelled) {
setHasReferralPerm(false)
setIsPermChecked(true)
}
router.replace('/dashboard')
return
}
// Ensure token
let tokenToUse = accessToken
try {
if (!tokenToUse && refreshAuthToken) {
const ok = await refreshAuthToken()
if (ok) tokenToUse = useAuthStore.getState().accessToken
}
} catch (e) {
console.error('❌ referral-management: refreshAuthToken error:', e)
}
const base = process.env.NEXT_PUBLIC_API_BASE_URL || ''
const url = `${base}/api/users/${uid}/permissions`
console.log('🌐 referral-management: fetching permissions:', { url, uid })
try {
const res = await fetch(url, {
method: 'GET',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...(tokenToUse ? { Authorization: `Bearer ${tokenToUse}` } : {})
}
})
console.log('📡 referral-management: permissions status:', res.status)
const body = await res.json().catch(() => null)
console.log('📦 referral-management: permissions body:', body)
const permsSrc = body?.data?.permissions ?? body?.permissions ?? body
let can = false
if (Array.isArray(permsSrc)) {
can =
permsSrc.includes?.('can_create_referrals') ||
permsSrc.some?.((p: any) => p?.name === 'can_create_referrals' || p?.key === 'can_create_referrals')
} else if (permsSrc && typeof permsSrc === 'object') {
can = !!permsSrc.can_create_referrals
}
console.log('✅ referral-management: can_create_referrals =', can)
if (!cancelled) {
setHasReferralPerm(!!can)
setIsPermChecked(true)
}
if (!can) {
console.log('⛔ referral-management: missing permission, redirect to /dashboard')
router.replace('/dashboard')
}
} catch (e) {
console.error('❌ referral-management: fetch permissions error:', e)
if (!cancelled) {
setHasReferralPerm(false)
setIsPermChecked(true)
}
router.replace('/dashboard')
}
}
run()
return () => { cancelled = true }
}, [isAuthReady, user, accessToken, refreshAuthToken, router])
// Helper: normalize list payload shapes
const normalizeList = (raw: any): any[] => {
const arr = Array.isArray(raw)
@ -106,10 +204,26 @@ export default function ReferralManagementPage() {
}
}
// Remove previous effect and use loadData
// Load data only when permission is granted
useEffect(() => {
if (isPermChecked && hasReferralPerm) {
loadData()
}, [])
}
}, [isPermChecked, hasReferralPerm])
// Gate rendering until auth + permission resolved
if (!isAuthReady || !user || !isPermChecked || !hasReferralPerm) {
return (
<PageLayout>
<div className="min-h-screen flex items-center justify-center">
<div className="text-center">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-[#8D6B1D] mx-auto mb-4"></div>
<p className="text-slate-700">Loading...</p>
</div>
</div>
</PageLayout>
)
}
return (
<PageLayout>