From f8fddc0e144f8a8a4fb8a7476da10798d8dd9da1 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Tue, 12 May 2026 00:43:54 +0200 Subject: [PATCH] feat(appshell): add user-info card to sidebar bottom; remove topbar avatar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidates the user menu into a single sidebar-bottom location. SidebarUserCard.vue shows avatar (initial), full name, role (Dutch label mapped from org pivot role or 'Super Admin' fallback) and a chevron-up that opens a PrimeVue Menu with "Mijn Profiel" and "Uitloggen". The Menu uses popup mode; PrimeVue v4's absolutePosition logic auto-flips above the trigger when the panel would overflow the viewport bottom — verify in Phase C. AppShell loses the topbar avatar Button + Menu and the associated state (userMenuRef, userInitial, userMenuItems, toggleUserMenu) plus its imports (Avatar, Menu, useAuthStore, computed). The component is now a pure layout shell with no auth-store coupling. The topbar's right side is intentionally empty in this commit; B4 fills it with breadcrumb / notification bell / help icon. Layout: nav uses min-h-0 flex-1 overflow-y-auto so it shrinks under viewport pressure and lets the user card stay pinned at the bottom of the sidebar. Mobile Drawer's content pt-override sets the same flex-column behaviour so the user card sits flush at the bottom of the drawer overlay. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/app/src/layouts/components/AppShell.vue | 71 ++--------- .../layouts/components/SidebarUserCard.vue | 113 ++++++++++++++++++ 2 files changed, 123 insertions(+), 61 deletions(-) create mode 100644 apps/app/src/layouts/components/SidebarUserCard.vue diff --git a/apps/app/src/layouts/components/AppShell.vue b/apps/app/src/layouts/components/AppShell.vue index 20ad13e5..1e9e8ac1 100644 --- a/apps/app/src/layouts/components/AppShell.vue +++ b/apps/app/src/layouts/components/AppShell.vue @@ -16,14 +16,11 @@ // PrimeVue Drawer overlay. Content area renders the default slot // (a RouterView from the wrapping layout file). -import { computed, ref } from 'vue' +import { ref } from 'vue' import { useRouter } from 'vue-router' import Drawer from 'primevue/drawer' import Button from 'primevue/button' -import Avatar from 'primevue/avatar' -import Menu from 'primevue/menu' import Icon from '@/components/Icon.vue' -import { useAuthStore } from '@/stores/useAuthStore' interface NavHeading { heading: string @@ -45,37 +42,8 @@ withDefaults(defineProps(), { }) const router = useRouter() -const authStore = useAuthStore() const mobileNavOpen = ref(false) -const userMenuRef = ref | null>(null) - -const userInitial = computed(() => { - const name = authStore.user?.full_name ?? '' - - return name.charAt(0).toUpperCase() || '?' -}) - -const userMenuItems = computed(() => [ - { - label: authStore.user?.full_name ?? 'Gebruiker', - items: [ - { - label: 'Mijn Profiel', - icon: 'tabler-user', - command: () => router.push({ name: 'account-settings' }), - }, - { - label: 'Uitloggen', - icon: 'tabler-logout', - command: async () => { - await authStore.logout() - await router.push('/login') - }, - }, - ], - }, -]) function isHeading(item: NavItem): item is NavHeading { return 'heading' in item @@ -85,10 +53,6 @@ function navigate(item: NavLink) { mobileNavOpen.value = false router.push(item.to) } - -function toggleUserMenu(event: Event) { - userMenuRef.value?.toggle(event) -}