feat: referral Management nav in Header if permission there
This commit is contained in:
parent
d0bf865552
commit
09083e066a
@ -48,8 +48,13 @@ export default function Header() {
|
|||||||
const [mounted, setMounted] = useState(false) // added
|
const [mounted, setMounted] = useState(false) // added
|
||||||
const user = useAuthStore((s) => s.user);
|
const user = useAuthStore((s) => s.user);
|
||||||
const logout = useAuthStore((s) => s.logout);
|
const logout = useAuthStore((s) => s.logout);
|
||||||
|
const accessToken = useAuthStore((s) => s.accessToken);
|
||||||
|
const refreshAuthToken = useAuthStore((s) => s.refreshAuthToken);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
// NEW: permission flag
|
||||||
|
const [hasReferralPerm, setHasReferralPerm] = useState(false)
|
||||||
|
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
try {
|
try {
|
||||||
await logout();
|
await logout();
|
||||||
@ -101,6 +106,84 @@ export default function Header() {
|
|||||||
})
|
})
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// Fetch user permissions and set hasReferralPerm
|
||||||
|
useEffect(() => {
|
||||||
|
let cancelled = false
|
||||||
|
|
||||||
|
const fetchPermissions = async () => {
|
||||||
|
if (!mounted) {
|
||||||
|
console.log('⏸️ Header: not mounted yet, skipping permissions fetch')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!user) {
|
||||||
|
console.log('ℹ️ Header: no user, clearing permission flag')
|
||||||
|
if (!cancelled) setHasReferralPerm(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const uid = (user as any)?.id ?? (user as any)?._id ?? (user as any)?.userId
|
||||||
|
if (!uid) {
|
||||||
|
console.warn('⚠️ Header: user id missing, cannot fetch permissions', user)
|
||||||
|
if (!cancelled) setHasReferralPerm(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const base = process.env.NEXT_PUBLIC_API_BASE_URL || ''
|
||||||
|
const url = `${base}/api/users/${uid}/permissions`
|
||||||
|
console.log('🌐 Header: fetching permissions:', { url, uid })
|
||||||
|
|
||||||
|
// Ensure we have a token (try refresh if needed)
|
||||||
|
let tokenToUse = accessToken
|
||||||
|
try {
|
||||||
|
if (!tokenToUse && refreshAuthToken) {
|
||||||
|
const ok = await refreshAuthToken()
|
||||||
|
if (ok) tokenToUse = useAuthStore.getState().accessToken
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('❌ Header: refreshAuthToken error:', e)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
credentials: 'include',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(tokenToUse ? { Authorization: `Bearer ${tokenToUse}` } : {})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
console.log('📡 Header: permissions status:', res.status)
|
||||||
|
const body = await res.json().catch(() => null)
|
||||||
|
console.log('📦 Header: permissions body:', body)
|
||||||
|
|
||||||
|
// Try common shapes
|
||||||
|
const permsSrc =
|
||||||
|
body?.data?.permissions ??
|
||||||
|
body?.permissions ??
|
||||||
|
body
|
||||||
|
|
||||||
|
let can = false
|
||||||
|
if (Array.isArray(permsSrc)) {
|
||||||
|
// Could be array of strings or objects
|
||||||
|
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('✅ Header: can_create_referrals =', can)
|
||||||
|
if (!cancelled) setHasReferralPerm(!!can)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('❌ Header: fetch permissions error:', e)
|
||||||
|
if (!cancelled) setHasReferralPerm(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchPermissions()
|
||||||
|
return () => { cancelled = true }
|
||||||
|
}, [mounted, user, accessToken, refreshAuthToken])
|
||||||
|
|
||||||
const isLoggedIn = !!user
|
const isLoggedIn = !!user
|
||||||
const userPresent = mounted && isLoggedIn
|
const userPresent = mounted && isLoggedIn
|
||||||
|
|
||||||
@ -145,12 +228,13 @@ export default function Header() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<PopoverGroup className="hidden lg:flex lg:gap-x-12">
|
<PopoverGroup className="hidden lg:flex lg:gap-x-12">
|
||||||
|
{/* Shop dropdown stays first */}
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverButton className="flex items-center gap-x-1 text-sm/6 font-semibold text-gray-900 dark:text-white">
|
<PopoverButton className="flex items-center gap-x-1 text-sm/6 font-semibold text-gray-900 dark:text-white">
|
||||||
Shop
|
Shop
|
||||||
<ChevronDownIcon aria-hidden="true" className="size-5 flex-none text-gray-500" />
|
<ChevronDownIcon aria-hidden="true" className="size-5 flex-none text-gray-500" />
|
||||||
</PopoverButton>
|
</PopoverButton>
|
||||||
{/* Redesigned mega menu panel */}
|
{/* ...existing Shop PopoverPanel... */}
|
||||||
<PopoverPanel
|
<PopoverPanel
|
||||||
transition
|
transition
|
||||||
className="absolute left-0 right-0 top-full z-50 rounded-b-2xl shadow-xl shadow-black/40 ring-1 ring-white/10 dark:ring-white/15 overflow-hidden data-closed:-translate-y-1 data-closed:opacity-0 data-enter:duration-200 data-enter:ease-out data-leave:duration-150 data-leave:ease-in"
|
className="absolute left-0 right-0 top-full z-50 rounded-b-2xl shadow-xl shadow-black/40 ring-1 ring-white/10 dark:ring-white/15 overflow-hidden data-closed:-translate-y-1 data-closed:opacity-0 data-enter:duration-200 data-enter:ease-out data-leave:duration-150 data-leave:ease-in"
|
||||||
@ -185,16 +269,39 @@ export default function Header() {
|
|||||||
</PopoverPanel>
|
</PopoverPanel>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|
||||||
{navLinks.map(l => (
|
{/* Affiliate Links */}
|
||||||
<button
|
<button
|
||||||
key={l.name}
|
onClick={() => router.push('/affiliate-links')}
|
||||||
onClick={() => router.push(l.href)}
|
|
||||||
className="text-sm/6 font-semibold text-gray-900 dark:text-white hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors"
|
className="text-sm/6 font-semibold text-gray-900 dark:text-white hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors"
|
||||||
>
|
>
|
||||||
{l.name}
|
Affiliate-Links
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Memberships */}
|
||||||
|
<button
|
||||||
|
onClick={() => router.push('/memberships')}
|
||||||
|
className="text-sm/6 font-semibold text-gray-900 dark:text-white hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors"
|
||||||
|
>
|
||||||
|
Memberships
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{/* Referral Management - match others (no highlight) */}
|
||||||
|
{userPresent && hasReferralPerm && (
|
||||||
|
<button
|
||||||
|
onClick={() => { console.log('🧭 Header: navigate to /referral-management'); router.push('/referral-management') }}
|
||||||
|
className="text-sm/6 font-semibold text-gray-900 dark:text-white hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors"
|
||||||
|
>
|
||||||
|
Referral Management
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* About us */}
|
||||||
|
<button
|
||||||
|
onClick={() => router.push('/about-us')}
|
||||||
|
className="text-sm/6 font-semibold text-gray-900 dark:text-white hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors"
|
||||||
|
>
|
||||||
|
About us
|
||||||
</button>
|
</button>
|
||||||
))}
|
|
||||||
{/* Removed user profile Popover from here (now on right side) */}
|
|
||||||
</PopoverGroup>
|
</PopoverGroup>
|
||||||
<div className="hidden lg:flex lg:flex-1 lg:justify-end lg:items-center lg:gap-x-4">
|
<div className="hidden lg:flex lg:flex-1 lg:justify-end lg:items-center lg:gap-x-4">
|
||||||
{/* Stable auth slot to avoid SSR/CSR structural drift */}
|
{/* Stable auth slot to avoid SSR/CSR structural drift */}
|
||||||
@ -267,6 +374,12 @@ export default function Header() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
{/* REMOVE sub header bar */}
|
||||||
|
{/* ...existing code... */}
|
||||||
|
{/* Deleted previous Sub header nav for Referral Management */}
|
||||||
|
{/* ...existing code... */}
|
||||||
|
|
||||||
<Dialog open={mobileMenuOpen} onClose={setMobileMenuOpen} className="lg:hidden">
|
<Dialog open={mobileMenuOpen} onClose={setMobileMenuOpen} className="lg:hidden">
|
||||||
<Transition
|
<Transition
|
||||||
appear
|
appear
|
||||||
@ -383,15 +496,36 @@ export default function Header() {
|
|||||||
))}
|
))}
|
||||||
</DisclosurePanel>
|
</DisclosurePanel>
|
||||||
</Disclosure>
|
</Disclosure>
|
||||||
{navLinks.map(link => (
|
{/* Affiliate Links */}
|
||||||
<button
|
<button
|
||||||
key={link.name}
|
onClick={() => { router.push('/affiliate-links'); setMobileMenuOpen(false); }}
|
||||||
onClick={() => { router.push(link.href); setMobileMenuOpen(false); }}
|
|
||||||
className="block rounded-lg px-3 py-2 text-base/7 font-semibold text-gray-900 dark:text-white hover:bg-white/5 w-full text-left"
|
className="block rounded-lg px-3 py-2 text-base/7 font-semibold text-gray-900 dark:text-white hover:bg-white/5 w-full text-left"
|
||||||
>
|
>
|
||||||
{link.name}
|
Affiliate-Links
|
||||||
|
</button>
|
||||||
|
{/* Memberships */}
|
||||||
|
<button
|
||||||
|
onClick={() => { router.push('/memberships'); setMobileMenuOpen(false); }}
|
||||||
|
className="block rounded-lg px-3 py-2 text-base/7 font-semibold text-gray-900 dark:text-white hover:bg-white/5 w-full text-left"
|
||||||
|
>
|
||||||
|
Memberships
|
||||||
|
</button>
|
||||||
|
{/* Referral Management - match others (no highlight) */}
|
||||||
|
{hasReferralPerm && (
|
||||||
|
<button
|
||||||
|
onClick={() => { console.log('🧭 Header Mobile: navigate to /referral-management'); router.push('/referral-management'); setMobileMenuOpen(false); }}
|
||||||
|
className="block rounded-lg px-3 py-2 text-base/7 font-semibold text-gray-900 dark:text-white hover:bg-white/5 w-full text-left"
|
||||||
|
>
|
||||||
|
Referral Management
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{/* About us */}
|
||||||
|
<button
|
||||||
|
onClick={() => { router.push('/about-us'); setMobileMenuOpen(false); }}
|
||||||
|
className="block rounded-lg px-3 py-2 text-base/7 font-semibold text-gray-900 dark:text-white hover:bg-white/5 w-full text-left"
|
||||||
|
>
|
||||||
|
About us
|
||||||
</button>
|
</button>
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
@ -414,15 +548,24 @@ export default function Header() {
|
|||||||
))}
|
))}
|
||||||
</DisclosurePanel>
|
</DisclosurePanel>
|
||||||
</Disclosure>
|
</Disclosure>
|
||||||
{navLinks.map(link => (
|
|
||||||
<button
|
<button
|
||||||
key={link.name}
|
onClick={() => { router.push('/affiliate-links'); setMobileMenuOpen(false); }}
|
||||||
onClick={() => { router.push(link.href); setMobileMenuOpen(false); }}
|
|
||||||
className="block rounded-lg px-3 py-2 text-base/7 font-semibold text-gray-900 dark:text-white hover:bg-white/5 w-full text-left"
|
className="block rounded-lg px-3 py-2 text-base/7 font-semibold text-gray-900 dark:text-white hover:bg-white/5 w-full text-left"
|
||||||
>
|
>
|
||||||
{link.name}
|
Affiliate-Links
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => { router.push('/memberships'); setMobileMenuOpen(false); }}
|
||||||
|
className="block rounded-lg px-3 py-2 text-base/7 font-semibold text-gray-900 dark:text-white hover:bg-white/5 w-full text-left"
|
||||||
|
>
|
||||||
|
Memberships
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => { router.push('/about-us'); setMobileMenuOpen(false); }}
|
||||||
|
className="block rounded-lg px-3 py-2 text-base/7 font-semibold text-gray-900 dark:text-white hover:bg-white/5 w-full text-left"
|
||||||
|
>
|
||||||
|
About us
|
||||||
</button>
|
</button>
|
||||||
))}
|
|
||||||
<div className="px-3">
|
<div className="px-3">
|
||||||
<button
|
<button
|
||||||
onClick={() => { router.push('/login'); setMobileMenuOpen(false); }}
|
onClick={() => { router.push('/login'); setMobileMenuOpen(false); }}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user