vbv/client/src/components/header/MainNavigationBar.vue

221 lines
7.7 KiB
Vue

<script setup lang="ts">
import log from "loglevel";
import AccountMenu from "@/components/header/AccountMenu.vue";
import MobileMenu from "@/components/header/MobileMenu.vue";
import NotificationPopover from "@/components/notifications/NotificationPopover.vue";
import NotificationPopoverContent from "@/components/notifications/NotificationPopoverContent.vue";
import ItFullScreenModal from "@/components/ui/ItFullScreenModal.vue";
import { useCourseSessionsStore } from "@/stores/courseSessions";
import { useNotificationsStore } from "@/stores/notifications";
import { useUserStore } from "@/stores/user";
import { useRouteLookups } from "@/utils/route";
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/vue";
import { breakpointsTailwind, useBreakpoints } from "@vueuse/core";
import { computed, onMounted, reactive } from "vue";
import { useI18n } from "vue-i18n";
log.debug("MainNavigationBar created");
const breakpoints = useBreakpoints(breakpointsTailwind);
const userStore = useUserStore();
const courseSessionsStore = useCourseSessionsStore();
const notificationsStore = useNotificationsStore();
const { inCockpit, inCompetenceProfile, inCourse, inLearningPath } = useRouteLookups();
const { t } = useI18n();
const state = reactive({
showMobileNavigationMenu: false,
showMobileProfileMenu: false,
});
function popoverClick(event: Event) {
if (breakpoints.smaller("lg").value) {
event.preventDefault();
state.showMobileProfileMenu = true;
}
}
const selectedCourseSessionTitle = computed(() => {
return courseSessionsStore.currentCourseSession?.title;
});
onMounted(() => {
log.debug("MainNavigationBar mounted");
});
</script>
<template>
<div>
<Teleport to="body">
<MobileMenu
v-if="userStore.loggedIn"
:show="state.showMobileNavigationMenu"
:course-session="courseSessionsStore.currentCourseSession"
:media-url="courseSessionsStore.currentCourseSession?.media_library_url"
:user="userStore"
@closemodal="state.showMobileNavigationMenu = false"
@logout="userStore.handleLogout()"
/>
</Teleport>
<Teleport to="body">
<ItFullScreenModal
v-if="userStore.loggedIn"
:show="state.showMobileProfileMenu"
@closemodal="state.showMobileProfileMenu = false"
>
<AccountMenu />
</ItFullScreenModal>
</Teleport>
<Transition name="nav">
<nav class="bg-blue-900 text-white">
<div class="mx-auto px-4 lg:px-8">
<div class="relative flex h-16 justify-between">
<div class="absolute inset-y-0 left-0 flex items-center lg:hidden">
<!-- Mobile menu button -->
<div class="flex" @click="state.showMobileNavigationMenu = true">
<button
type="button"
class="h-8 w-8 text-white hover:text-sky-500 focus:text-sky-500 focus:outline-none"
>
<it-icon-menu class="h-8 w-8" />
</button>
</div>
</div>
<div class="flex flex-1 items-stretch justify-start">
<div class="hidden flex-shrink-0 items-center lg:flex">
<div class="flex items-center">
<router-link to="/" class="flex">
<it-icon-vbv class="-ml-3 -mt-6 mr-3 h-8 w-16" />
</router-link>
<router-link to="/" class="flex">
<div
class="ml-1 border-l border-white pl-3 pr-10 text-2xl text-white"
>
{{ t("general.title") }}
</div>
</router-link>
</div>
</div>
<div class="hidden space-x-8 lg:flex">
<!-- Navigation Links Desktop -->
<router-link
v-if="
inCourse() &&
courseSessionsStore.currentCourseSession &&
courseSessionsStore.hasCockpit
"
:to="`${courseSessionsStore.currentCourseSession.course_url}/cockpit`"
class="nav-item"
:class="{ 'nav-item--active': inCockpit() }"
>
{{ t("cockpit.title") }}
</router-link>
<router-link
v-if="inCourse() && courseSessionsStore.currentCourseSession"
:to="courseSessionsStore.currentCourseSession.learning_path_url"
class="nav-item"
:class="{ 'nav-item--active': inLearningPath() }"
>
{{ t("general.learningPath") }}
</router-link>
<router-link
v-if="inCourse() && courseSessionsStore.currentCourseSession"
:to="courseSessionsStore.currentCourseSession.competence_url"
class="nav-item"
:class="{ 'nav-item--active': inCompetenceProfile() }"
>
{{ t("competences.title") }}
</router-link>
</div>
</div>
<div class="flex items-stretch justify-start space-x-8">
<!-- Notification Bell & Menu -->
<div v-if="userStore.loggedIn" class="nav-item">
<NotificationPopover>
<template #toggleButtonContent>
<div class="flex">
<it-icon-notification class="h-6 w-6" />
<div
v-if="notificationsStore.hasUnread"
aria-label="unread notifications"
class="mt-1 h-1.5 w-1.5 rounded-full bg-sky-500"
/>
</div>
</template>
<template #popoverContent>
<NotificationPopoverContent />
</template>
</NotificationPopover>
</div>
<div
v-if="selectedCourseSessionTitle"
class="hidden items-center lg:inline-flex"
>
<div class="">
{{ selectedCourseSessionTitle }}
</div>
</div>
<div class="nav-item">
<div v-if="userStore.loggedIn" class="flex items-center">
<Popover class="relative">
<PopoverButton @click="popoverClick($event)">
<div v-if="userStore.avatar_url">
<img
class="inline-block h-8 w-8 rounded-full"
:src="userStore.avatar_url"
alt=""
/>
</div>
<div v-else>
{{ userStore.getFullName }}
</div>
</PopoverButton>
<PopoverPanel
class="absolute -right-2 top-8 z-50 w-[500px] bg-white shadow-lg"
>
<div class="p-4">
<AccountMenu />
</div>
</PopoverPanel>
</Popover>
</div>
<div v-else><a class="" href="/login">Login</a></div>
</div>
</div>
</div>
</div>
</nav>
</Transition>
</div>
</template>
<style lang="postcss" scoped>
.nav-item {
@apply inline-flex items-center border-b-4 border-transparent px-1 pt-1 text-white hover:text-sky-500;
}
.nav-item--active {
@apply border-sky-500;
}
.nav-enter-active,
.nav-leave-active {
transition: opacity 0.3s ease, transform 0.3s ease;
}
.nav-enter-from,
.nav-leave-to {
opacity: 0;
transform: translateY(-80px);
}
</style>