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 user = useAuthStore((s) => s.user);
|
||||
const logout = useAuthStore((s) => s.logout);
|
||||
const accessToken = useAuthStore((s) => s.accessToken);
|
||||
const refreshAuthToken = useAuthStore((s) => s.refreshAuthToken);
|
||||
const router = useRouter();
|
||||
|
||||
// NEW: permission flag
|
||||
const [hasReferralPerm, setHasReferralPerm] = useState(false)
|
||||
|
||||
const handleLogout = async () => {
|
||||
try {
|
||||
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 userPresent = mounted && isLoggedIn
|
||||
|
||||
@ -145,12 +228,13 @@ export default function Header() {
|
||||
</button>
|
||||
</div>
|
||||
<PopoverGroup className="hidden lg:flex lg:gap-x-12">
|
||||
{/* Shop dropdown stays first */}
|
||||
<Popover>
|
||||
<PopoverButton className="flex items-center gap-x-1 text-sm/6 font-semibold text-gray-900 dark:text-white">
|
||||
Shop
|
||||
<ChevronDownIcon aria-hidden="true" className="size-5 flex-none text-gray-500" />
|
||||
</PopoverButton>
|
||||
{/* Redesigned mega menu panel */}
|
||||
{/* ...existing Shop PopoverPanel... */}
|
||||
<PopoverPanel
|
||||
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"
|
||||
@ -185,16 +269,39 @@ export default function Header() {
|
||||
</PopoverPanel>
|
||||
</Popover>
|
||||
|
||||
{navLinks.map(l => (
|
||||
{/* Affiliate Links */}
|
||||
<button
|
||||
onClick={() => router.push('/affiliate-links')}
|
||||
className="text-sm/6 font-semibold text-gray-900 dark:text-white hover:text-indigo-600 dark:hover:text-indigo-400 transition-colors"
|
||||
>
|
||||
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
|
||||
key={l.name}
|
||||
onClick={() => router.push(l.href)}
|
||||
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"
|
||||
>
|
||||
{l.name}
|
||||
Referral Management
|
||||
</button>
|
||||
))}
|
||||
{/* Removed user profile Popover from here (now on right side) */}
|
||||
)}
|
||||
|
||||
{/* 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>
|
||||
</PopoverGroup>
|
||||
<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 */}
|
||||
@ -267,6 +374,12 @@ export default function Header() {
|
||||
</button>
|
||||
</div>
|
||||
</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">
|
||||
<Transition
|
||||
appear
|
||||
@ -383,15 +496,36 @@ export default function Header() {
|
||||
))}
|
||||
</DisclosurePanel>
|
||||
</Disclosure>
|
||||
{navLinks.map(link => (
|
||||
{/* Affiliate Links */}
|
||||
<button
|
||||
onClick={() => { router.push('/affiliate-links'); 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"
|
||||
>
|
||||
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
|
||||
key={link.name}
|
||||
onClick={() => { router.push(link.href); setMobileMenuOpen(false); }}
|
||||
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"
|
||||
>
|
||||
{link.name}
|
||||
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>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
@ -414,15 +548,24 @@ export default function Header() {
|
||||
))}
|
||||
</DisclosurePanel>
|
||||
</Disclosure>
|
||||
{navLinks.map(link => (
|
||||
<button
|
||||
key={link.name}
|
||||
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"
|
||||
>
|
||||
{link.name}
|
||||
</button>
|
||||
))}
|
||||
<button
|
||||
onClick={() => { router.push('/affiliate-links'); 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"
|
||||
>
|
||||
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>
|
||||
<div className="px-3">
|
||||
<button
|
||||
onClick={() => { router.push('/login'); setMobileMenuOpen(false); }}
|
||||
@ -435,7 +578,7 @@ export default function Header() {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</DialogPanel>
|
||||
</DialogPanel>
|
||||
</Transition.Child>
|
||||
</Transition>
|
||||
</Dialog>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user