Updated navigation system for new stuff

This commit is contained in:
2026-03-21 23:22:41 -04:00
parent b40e4f3ec7
commit 676e09aef5

View File

@@ -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">