Updated navigation system for new stuff
This commit is contained in:
@@ -1,171 +1,180 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouterLink, useRouter } from 'vue-router';
|
import { RouterLink, useRouter } from 'vue-router';
|
||||||
import Separator from '../ui/separator/Separator.vue';
|
import Separator from '../ui/separator/Separator.vue';
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
|
import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '../ui/dropdown-menu';
|
} from '../ui/dropdown-menu';
|
||||||
import { useUserStore } from '@/stores/user';
|
import { useUserStore } from '@/stores/user';
|
||||||
import Button from '../ui/button/Button.vue';
|
import Button from '../ui/button/Button.vue';
|
||||||
import NavigationMenu from '../ui/navigation-menu/NavigationMenu.vue';
|
import NavigationMenu from '../ui/navigation-menu/NavigationMenu.vue';
|
||||||
import NavigationMenuList from '../ui/navigation-menu/NavigationMenuList.vue';
|
import NavigationMenuList from '../ui/navigation-menu/NavigationMenuList.vue';
|
||||||
import NavigationMenuItem from '../ui/navigation-menu/NavigationMenuItem.vue';
|
import NavigationMenuItem from '../ui/navigation-menu/NavigationMenuItem.vue';
|
||||||
import NavigationMenuLink from '../ui/navigation-menu/NavigationMenuLink.vue';
|
import NavigationMenuLink from '../ui/navigation-menu/NavigationMenuLink.vue';
|
||||||
import NavigationMenuTrigger from '../ui/navigation-menu/NavigationMenuTrigger.vue';
|
import NavigationMenuTrigger from '../ui/navigation-menu/NavigationMenuTrigger.vue';
|
||||||
import NavigationMenuContent from '../ui/navigation-menu/NavigationMenuContent.vue';
|
import NavigationMenuContent from '../ui/navigation-menu/NavigationMenuContent.vue';
|
||||||
import { navigationMenuTriggerStyle } from '../ui/navigation-menu/'
|
import { navigationMenuTriggerStyle } from '../ui/navigation-menu/'
|
||||||
import { useAuth } from '@/composables/useAuth';
|
import { useAuth } from '@/composables/useAuth';
|
||||||
import { ArrowUpRight, ChevronDown, ChevronUp, CircleArrowOutUpRight, LogIn, LogOut, Menu, Settings, X } from 'lucide-vue-next';
|
import { ArrowUpRight, ChevronDown, ChevronUp, CircleArrowOutUpRight, LogIn, LogOut, Menu, Settings, X } from 'lucide-vue-next';
|
||||||
import DropdownMenuGroup from '../ui/dropdown-menu/DropdownMenuGroup.vue';
|
import DropdownMenuGroup from '../ui/dropdown-menu/DropdownMenuGroup.vue';
|
||||||
import DropdownMenuSeparator from '../ui/dropdown-menu/DropdownMenuSeparator.vue';
|
import DropdownMenuSeparator from '../ui/dropdown-menu/DropdownMenuSeparator.vue';
|
||||||
import { MemberState } from '@shared/types/member';
|
import { MemberState } from '@shared/types/member';
|
||||||
import { computed, nextTick, ref } from 'vue';
|
import { computed, nextTick, ref } from 'vue';
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const auth = useAuth();
|
const auth = useAuth();
|
||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
const APIHOST = import.meta.env.VITE_APIHOST;
|
const APIHOST = import.meta.env.VITE_APIHOST;
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
const DOCHOST = import.meta.env.VITE_DOCHOST;
|
const DOCHOST = import.meta.env.VITE_DOCHOST;
|
||||||
|
|
||||||
async function logout() {
|
async function logout() {
|
||||||
userStore.user = null;
|
userStore.user = null;
|
||||||
window.location.href = APIHOST + "/logout";
|
window.location.href = APIHOST + "/logout";
|
||||||
}
|
}
|
||||||
|
|
||||||
function blurAfter() {
|
function blurAfter() {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
(document.activeElement as HTMLElement)?.blur();
|
(document.activeElement as HTMLElement)?.blur();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
type NavItem = {
|
type NavItem = {
|
||||||
title: string;
|
title: string;
|
||||||
to?: string;
|
to?: string;
|
||||||
href?: string;
|
href?: string;
|
||||||
status?: 'member' | 'guest';
|
status?: 'member' | 'guest';
|
||||||
isExternal?: boolean;
|
isExternal?: boolean;
|
||||||
roles?: string[];
|
roles?: string[];
|
||||||
items?: NavItem[];
|
items?: NavItem[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const navConfig: NavItem[] = [
|
const navConfig: NavItem[] = [
|
||||||
{
|
{
|
||||||
title: 'Calendar',
|
title: 'Calendar',
|
||||||
to: '/calendar',
|
to: '/calendar',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Documents',
|
title: 'Documents',
|
||||||
href: 'https://docs.iceberg-gaming.com',
|
href: 'https://docs.iceberg-gaming.com',
|
||||||
status: 'member',
|
status: 'member',
|
||||||
isExternal: true
|
isExternal: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Forms',
|
title: 'Forms',
|
||||||
status: 'member',
|
status: 'member',
|
||||||
items: [
|
items: [
|
||||||
{ title: 'Leave of Absence', to: '/loa' },
|
{ title: 'Leave of Absence', to: '/loa' },
|
||||||
{ title: 'Training Report', to: '/trainingReport' },
|
{ title: 'Training Report', to: '/trainingReport' },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Administration',
|
title: 'Administration',
|
||||||
status: 'member',
|
status: 'member',
|
||||||
roles: ['17th Administrator', '17th HQ', '17th Command', 'Recruiter'],
|
roles: ['17th Administrator', '17th HQ', '17th Command', 'Recruiter'],
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
title: 'Leave of Absence',
|
title: 'Leave of Absence',
|
||||||
to: '/administration/loa',
|
to: '/administration/loa',
|
||||||
roles: ['17th Administrator', '17th HQ', '17th Command']
|
roles: ['17th Administrator', '17th HQ', '17th Command']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Promotions',
|
title: 'Promotions',
|
||||||
to: '/administration/rankChange',
|
to: '/administration/rankChange',
|
||||||
roles: ['17th Administrator', '17th HQ', '17th Command']
|
roles: ['17th Administrator', '17th HQ', '17th Command']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Recruitment',
|
title: 'Recruitment',
|
||||||
to: '/administration/applications',
|
to: '/administration/applications',
|
||||||
roles: ['Recruiter']
|
roles: ['Recruiter']
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Role Management',
|
title: 'Member Management',
|
||||||
to: '/administration/roles',
|
to: '/administration/members',
|
||||||
roles: ['17th Administrator']
|
},
|
||||||
},
|
{
|
||||||
]
|
title: 'Role Management',
|
||||||
},
|
to: '/administration/roles',
|
||||||
{
|
roles: ['17th Administrator']
|
||||||
title: 'Join',
|
},
|
||||||
to: '/join',
|
]
|
||||||
status: 'guest',
|
},
|
||||||
},
|
{
|
||||||
];
|
title: 'Developer',
|
||||||
|
to: '/developer',
|
||||||
|
roles: ['Dev']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Join',
|
||||||
|
to: '/join',
|
||||||
|
status: 'guest',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const filteredNav = computed(() => {
|
const filteredNav = computed(() => {
|
||||||
return navConfig.flatMap(item => {
|
return navConfig.flatMap(item => {
|
||||||
const filtered: NavItem[] = [];
|
const filtered: NavItem[] = [];
|
||||||
|
|
||||||
// 1. Check Login Requirements
|
// 1. Check Login Requirements
|
||||||
const isLoggedIn = userStore.isLoggedIn;
|
const isLoggedIn = userStore.isLoggedIn;
|
||||||
|
|
||||||
// 2. Determine visibility based on status
|
// 2. Determine visibility based on status
|
||||||
let shouldShow = false;
|
let shouldShow = false;
|
||||||
|
|
||||||
if (!item.status) {
|
if (!item.status) {
|
||||||
// Public items - always show
|
// Public items - always show
|
||||||
shouldShow = true;
|
shouldShow = true;
|
||||||
} else if (item.status === 'guest') {
|
} else if (item.status === 'guest') {
|
||||||
// Show if NOT logged in OR logged in as guest (but NOT a member)
|
// Show if NOT logged in OR logged in as guest (but NOT a member)
|
||||||
shouldShow = !isLoggedIn || auth.accountStatus.value === 'guest';
|
shouldShow = !isLoggedIn || auth.accountStatus.value === MemberState.Guest;
|
||||||
} else if (item.status === 'member') {
|
} else if (item.status === 'member') {
|
||||||
// Show ONLY if logged in as member
|
// Show ONLY if logged in as member
|
||||||
shouldShow = isLoggedIn && auth.accountStatus.value === 'member';
|
shouldShow = isLoggedIn && auth.accountStatus.value === MemberState.Member;
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Check Role Requirements (if status check passed)
|
|
||||||
if (shouldShow && item.roles) {
|
|
||||||
shouldShow = auth.hasAnyRole(item.roles);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldShow) {
|
|
||||||
if (item.items) {
|
|
||||||
const filteredItems = item.items.filter(subItem =>
|
|
||||||
!subItem.roles || auth.hasAnyRole(subItem.roles)
|
|
||||||
);
|
|
||||||
filtered.push({ ...item, items: filteredItems });
|
|
||||||
} else {
|
|
||||||
filtered.push(item);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return filtered;
|
// 3. Check Role Requirements (if status check passed)
|
||||||
});
|
if (shouldShow && item.roles) {
|
||||||
})
|
shouldShow = auth.hasAnyRole(item.roles);
|
||||||
|
}
|
||||||
|
|
||||||
const isMobileMenuOpen = ref(false);
|
if (shouldShow) {
|
||||||
const expandedMenu = ref(null);
|
if (item.items) {
|
||||||
|
const filteredItems = item.items.filter(subItem =>
|
||||||
|
!subItem.roles || auth.hasAnyRole(subItem.roles)
|
||||||
|
);
|
||||||
|
filtered.push({ ...item, items: filteredItems });
|
||||||
|
} else {
|
||||||
|
filtered.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const router = useRouter();
|
return filtered;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
function openMobileMenu() {
|
const isMobileMenuOpen = ref(false);
|
||||||
expandedMenu.value = null;
|
const expandedMenu = ref(null);
|
||||||
isMobileMenuOpen.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeMobileMenu() {
|
const router = useRouter();
|
||||||
isMobileMenuOpen.value = false;
|
|
||||||
expandedMenu.value = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function mobileNavigateTo(to: string) {
|
function openMobileMenu() {
|
||||||
closeMobileMenu();
|
expandedMenu.value = null;
|
||||||
router.push(to);
|
isMobileMenuOpen.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function closeMobileMenu() {
|
||||||
|
isMobileMenuOpen.value = false;
|
||||||
|
expandedMenu.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mobileNavigateTo(to: string) {
|
||||||
|
closeMobileMenu();
|
||||||
|
router.push(to);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -177,7 +186,8 @@ function mobileNavigateTo(to: string) {
|
|||||||
<img src="/17RBN_Logo.png" class="w-10 h-10 object-contain"></img>
|
<img src="/17RBN_Logo.png" class="w-10 h-10 object-contain"></img>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
<!-- Member navigation -->
|
<!-- Member navigation -->
|
||||||
<div v-if="auth.accountStatus.value == MemberState.Member" class="h-15 flex items-center justify-center">
|
<div v-if="auth.accountStatus.value == MemberState.Member"
|
||||||
|
class="h-15 flex items-center justify-center">
|
||||||
<NavigationMenu>
|
<NavigationMenu>
|
||||||
<NavigationMenuList class="gap-3">
|
<NavigationMenuList class="gap-3">
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user