From a8a2bc92d1e1e5b0bb39567ebaae240161eb1f37 Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Wed, 15 Apr 2026 00:59:45 +0200 Subject: [PATCH] feat: refactor organisation pages with tabs, members tab, and danger zone Organizer org page (/organisation): - Timestamps moved below title as muted caption - VTabs with Algemeen (details) and Leden (members) tabs - Members content embedded from separate page with full functionality: invite, edit role, change email, remove, pending invitations Platform org detail (/platform/organisations/[id]): - Timestamps moved below title alongside slug - VTabs with Algemeen and Leden tabs - Danger zone redesigned: type-to-confirm delete dialog, disabled Transfer Ownership button with "Nog niet beschikbaar" tooltip Navigation: - Removed standalone "Leden" menu item (now a tab on org page) Co-Authored-By: Claude Opus 4.6 (1M context) --- apps/app/src/navigation/vertical/index.ts | 7 - apps/app/src/pages/organisation/index.vue | 557 ++++++++++++++++-- .../src/pages/platform/organisations/[id].vue | 414 ++++++++----- 3 files changed, 775 insertions(+), 203 deletions(-) diff --git a/apps/app/src/navigation/vertical/index.ts b/apps/app/src/navigation/vertical/index.ts index 3f249a2f..2499467f 100644 --- a/apps/app/src/navigation/vertical/index.ts +++ b/apps/app/src/navigation/vertical/index.ts @@ -17,13 +17,6 @@ export const orgNavItems = [ to: { name: 'organisation' }, icon: { icon: 'tabler-building' }, }, - { - title: 'Leden', - to: { name: 'organisation-members' }, - icon: { icon: 'tabler-users-group' }, - action: 'read', - subject: 'members', - }, { title: 'Bedrijven', to: { name: 'organisation-companies' }, diff --git a/apps/app/src/pages/organisation/index.vue b/apps/app/src/pages/organisation/index.vue index 844c726b..7c7f4923 100644 --- a/apps/app/src/pages/organisation/index.vue +++ b/apps/app/src/pages/organisation/index.vue @@ -1,15 +1,24 @@ diff --git a/apps/app/src/pages/platform/organisations/[id].vue b/apps/app/src/pages/platform/organisations/[id].vue index a57441bb..ccdc676c 100644 --- a/apps/app/src/pages/platform/organisations/[id].vue +++ b/apps/app/src/pages/platform/organisations/[id].vue @@ -48,7 +48,23 @@ const roleOptions = [ { title: 'Lid', value: 'org_member' }, ] -// Edit dialog +// ─── Tabs ────────────────────────────────────────────────── +const tabs = [ + { value: 'algemeen', label: 'Algemeen', icon: 'tabler-building' }, + { value: 'leden', label: 'Leden', icon: 'tabler-users-group' }, +] + +const activeTab = computed({ + get: () => { + const tab = route.query.tab as string + return tabs.some(t => t.value === tab) ? tab : 'algemeen' + }, + set: (value: string) => { + router.replace({ query: { ...route.query, tab: value } }) + }, +}) + +// ─── Edit dialog ─────────────────────────────────────────── const isEditDialogOpen = ref(false) const editForm = ref({}) const { mutate: updateOrg, isPending: isUpdating } = useUpdateAdminOrganisation() @@ -75,11 +91,22 @@ function submitEdit() { ) } -// Delete +// ─── Delete (type-to-confirm) ────────────────────────────── const isDeleteDialogOpen = ref(false) +const deleteConfirmName = ref('') const { mutate: deleteOrg, isPending: isDeleting } = useDeleteAdminOrganisation() +const deleteConfirmValid = computed(() => + deleteConfirmName.value === org.value?.name, +) + +function openDeleteDialog() { + deleteConfirmName.value = '' + isDeleteDialogOpen.value = true +} + function confirmDelete() { + if (!deleteConfirmValid.value) return deleteOrg(orgId.value, { onSuccess: () => { router.push({ name: 'platform-organisations' }) @@ -87,14 +114,14 @@ function confirmDelete() { }) } -// Open as organiser +// ─── Open as organiser ───────────────────────────────────── function openAsOrganiser() { if (!org.value) return orgStore.setActiveOrganisation(org.value.id) router.push({ name: 'dashboard' }) } -// ─── Invite Member ────────────────────────────────────────── +// ─── Invite Member ───────────────────────────────────────── const isInviteDialogOpen = ref(false) const inviteForm = ref({ email: '', role: 'org_member' }) const inviteError = ref('') @@ -123,7 +150,7 @@ function submitInvite() { ) } -// ─── Remove Member ────────────────────────────────────────── +// ─── Remove Member ───────────────────────────────────────── const isRemoveDialogOpen = ref(false) const memberToRemove = ref<{ id: string; full_name: string } | null>(null) const { mutate: removeMember, isPending: isRemoving } = useRemoveOrganisationMember() @@ -147,7 +174,7 @@ function confirmRemove() { ) } -// ─── Update Member Role ───────────────────────────────────── +// ─── Update Member Role ──────────────────────────────────── const { mutate: updateMemberRole } = useUpdateOrganisationMemberRole() function onRoleChange(userId: string, newRole: string) { @@ -161,7 +188,7 @@ function onRoleChange(userId: string, newRole: string) { ) } -// ─── Snackbar ─────────────────────────────────────────────── +// ─── Snackbar ────────────────────────────────────────────── const snackbar = ref({ show: false, message: '', color: 'success' }) function showSnackbar(message: string, color: string) { @@ -206,7 +233,7 @@ function formatDate(iso: string): string { @@ -523,15 +623,28 @@ function formatDate(iso: string): string { - + - Weet je zeker dat je {{ org?.name }} wilt verwijderen? - Dit kan niet ongedaan worden gemaakt. + + Deze actie kan niet ongedaan worden gemaakt. Alle gegevens van + deze organisatie worden permanent verwijderd. + +

+ Typ {{ org?.name }} om te bevestigen: +

+
@@ -544,9 +657,10 @@ function formatDate(iso: string): string { - Verwijderen + Definitief verwijderen