feat: add create organisation button and dialog on platform page
Add "Nieuwe organisatie" button to the platform organisations list page. Dialog with name field (auto-generates slug) and slug field. Uses the existing POST /organisations endpoint. On success, navigates to the new organisation's detail page. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import type {
|
|||||||
AdminOrganisationDetail,
|
AdminOrganisationDetail,
|
||||||
AdminOrganisationMember,
|
AdminOrganisationMember,
|
||||||
AdminUser,
|
AdminUser,
|
||||||
|
CreateOrganisationPayload,
|
||||||
ImpersonationResponse,
|
ImpersonationResponse,
|
||||||
InviteMemberPayload,
|
InviteMemberPayload,
|
||||||
PlatformStats,
|
PlatformStats,
|
||||||
@@ -77,6 +78,23 @@ export function useUpdateAdminOrganisation() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useCreateOrganisation() {
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async (payload: CreateOrganisationPayload) => {
|
||||||
|
const { data } = await apiClient.post<ApiResponse<AdminOrganisation>>(
|
||||||
|
'/organisations',
|
||||||
|
payload,
|
||||||
|
)
|
||||||
|
return data.data
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['admin', 'organisations'] })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function useDeleteAdminOrganisation() {
|
export function useDeleteAdminOrganisation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useAdminOrganisations } from '@/composables/api/useAdmin'
|
import { useAdminOrganisations, useCreateOrganisation } from '@/composables/api/useAdmin'
|
||||||
import type { AdminOrganisation, BillingStatus } from '@/types/admin'
|
import type { AdminOrganisation, BillingStatus, CreateOrganisationPayload } from '@/types/admin'
|
||||||
|
|
||||||
definePage({
|
definePage({
|
||||||
meta: {
|
meta: {
|
||||||
@@ -76,6 +76,44 @@ function onUpdateOptions(options: { page: number; itemsPerPage: number; sortBy:
|
|||||||
sortDirection.value = options.sortBy[0].order as 'asc' | 'desc'
|
sortDirection.value = options.sortBy[0].order as 'asc' | 'desc'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Create organisation ────────────────────────────────────
|
||||||
|
const isCreateDialogOpen = ref(false)
|
||||||
|
const createForm = ref<CreateOrganisationPayload>({ name: '', slug: '' })
|
||||||
|
const createError = ref('')
|
||||||
|
const { mutate: createOrganisation, isPending: isCreating } = useCreateOrganisation()
|
||||||
|
|
||||||
|
function slugify(text: string): string {
|
||||||
|
return text
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(/[^a-z0-9]+/g, '-')
|
||||||
|
.replace(/^-+|-+$/g, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
function openCreateDialog() {
|
||||||
|
createForm.value = { name: '', slug: '' }
|
||||||
|
createError.value = ''
|
||||||
|
isCreateDialogOpen.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function onNameInput(name: string) {
|
||||||
|
createForm.value.name = name
|
||||||
|
createForm.value.slug = slugify(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitCreate() {
|
||||||
|
createError.value = ''
|
||||||
|
createOrganisation(createForm.value, {
|
||||||
|
onSuccess: (org) => {
|
||||||
|
isCreateDialogOpen.value = false
|
||||||
|
router.push({ name: 'platform-organisations-id', params: { id: org.id } })
|
||||||
|
},
|
||||||
|
onError: (err: unknown) => {
|
||||||
|
const error = err as { response?: { data?: { message?: string } } }
|
||||||
|
createError.value = error.response?.data?.message ?? 'Er is een fout opgetreden.'
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -89,6 +127,12 @@ function onUpdateOptions(options: { page: number; itemsPerPage: number; sortBy:
|
|||||||
Alle organisaties op het platform
|
Alle organisaties op het platform
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<VBtn
|
||||||
|
prepend-icon="tabler-plus"
|
||||||
|
@click="openCreateDialog"
|
||||||
|
>
|
||||||
|
Nieuwe organisatie
|
||||||
|
</VBtn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Error -->
|
<!-- Error -->
|
||||||
@@ -174,5 +218,58 @@ function onUpdateOptions(options: { page: number; itemsPerPage: number; sortBy:
|
|||||||
</template>
|
</template>
|
||||||
</VDataTableServer>
|
</VDataTableServer>
|
||||||
</VCard>
|
</VCard>
|
||||||
|
|
||||||
|
<!-- Create Dialog -->
|
||||||
|
<VDialog
|
||||||
|
v-model="isCreateDialogOpen"
|
||||||
|
max-width="500"
|
||||||
|
>
|
||||||
|
<VCard title="Nieuwe organisatie">
|
||||||
|
<VCardText>
|
||||||
|
<VAlert
|
||||||
|
v-if="createError"
|
||||||
|
type="error"
|
||||||
|
variant="tonal"
|
||||||
|
class="mb-4"
|
||||||
|
density="comfortable"
|
||||||
|
>
|
||||||
|
{{ createError }}
|
||||||
|
</VAlert>
|
||||||
|
<VRow>
|
||||||
|
<VCol cols="12">
|
||||||
|
<AppTextField
|
||||||
|
:model-value="createForm.name"
|
||||||
|
label="Naam"
|
||||||
|
@update:model-value="onNameInput"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12">
|
||||||
|
<AppTextField
|
||||||
|
v-model="createForm.slug"
|
||||||
|
label="Slug"
|
||||||
|
hint="Wordt automatisch gegenereerd"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VCardText>
|
||||||
|
<VCardActions>
|
||||||
|
<VSpacer />
|
||||||
|
<VBtn
|
||||||
|
variant="tonal"
|
||||||
|
@click="isCreateDialogOpen = false"
|
||||||
|
>
|
||||||
|
Annuleren
|
||||||
|
</VBtn>
|
||||||
|
<VBtn
|
||||||
|
color="primary"
|
||||||
|
:loading="isCreating"
|
||||||
|
:disabled="!createForm.name || !createForm.slug"
|
||||||
|
@click="submitCreate"
|
||||||
|
>
|
||||||
|
Aanmaken
|
||||||
|
</VBtn>
|
||||||
|
</VCardActions>
|
||||||
|
</VCard>
|
||||||
|
</VDialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -96,6 +96,12 @@ export interface UpdateMemberRolePayload {
|
|||||||
role: string
|
role: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CreateOrganisationPayload {
|
||||||
|
name: string
|
||||||
|
slug: string
|
||||||
|
billing_status?: BillingStatus
|
||||||
|
}
|
||||||
|
|
||||||
export interface UpdateAdminOrganisationPayload {
|
export interface UpdateAdminOrganisationPayload {
|
||||||
name?: string
|
name?: string
|
||||||
slug?: string
|
slug?: string
|
||||||
|
|||||||
Reference in New Issue
Block a user