diff --git a/apps/app/components.d.ts b/apps/app/components.d.ts index c581065..5ee9213 100644 --- a/apps/app/components.d.ts +++ b/apps/app/components.d.ts @@ -30,6 +30,7 @@ declare module 'vue' { ConfirmDialog: typeof import('./src/components/dialogs/ConfirmDialog.vue')['default'] CreateAppDialog: typeof import('./src/components/dialogs/CreateAppDialog.vue')['default'] CreateEventDialog: typeof import('./src/components/events/CreateEventDialog.vue')['default'] + CreatePersonDialog: typeof import('./src/components/persons/CreatePersonDialog.vue')['default'] CustomCheckboxes: typeof import('./src/@core/components/app-form-elements/CustomCheckboxes.vue')['default'] CustomCheckboxesWithIcon: typeof import('./src/@core/components/app-form-elements/CustomCheckboxesWithIcon.vue')['default'] CustomCheckboxesWithImage: typeof import('./src/@core/components/app-form-elements/CustomCheckboxesWithImage.vue')['default'] @@ -42,14 +43,17 @@ declare module 'vue' { EditEventDialog: typeof import('./src/components/events/EditEventDialog.vue')['default'] EditMemberRoleDialog: typeof import('./src/components/members/EditMemberRoleDialog.vue')['default'] EditOrganisationDialog: typeof import('./src/components/organisations/EditOrganisationDialog.vue')['default'] + EditPersonDialog: typeof import('./src/components/persons/EditPersonDialog.vue')['default'] EnableOneTimePasswordDialog: typeof import('./src/components/dialogs/EnableOneTimePasswordDialog.vue')['default'] ErrorHeader: typeof import('./src/components/ErrorHeader.vue')['default'] + EventTabsNav: typeof import('./src/components/events/EventTabsNav.vue')['default'] I18n: typeof import('./src/@core/components/I18n.vue')['default'] InviteMemberDialog: typeof import('./src/components/members/InviteMemberDialog.vue')['default'] MoreBtn: typeof import('./src/@core/components/MoreBtn.vue')['default'] Notifications: typeof import('./src/@core/components/Notifications.vue')['default'] OrganisationSwitcher: typeof import('./src/components/layout/OrganisationSwitcher.vue')['default'] PaymentProvidersDialog: typeof import('./src/components/dialogs/PaymentProvidersDialog.vue')['default'] + PersonDetailPanel: typeof import('./src/components/persons/PersonDetailPanel.vue')['default'] ProductDescriptionEditor: typeof import('./src/@core/components/ProductDescriptionEditor.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] diff --git a/apps/app/src/components/events/EventTabsNav.vue b/apps/app/src/components/events/EventTabsNav.vue new file mode 100644 index 0000000..fcf7d53 --- /dev/null +++ b/apps/app/src/components/events/EventTabsNav.vue @@ -0,0 +1,140 @@ + + + diff --git a/apps/app/src/components/layout/OrganisationSwitcher.vue b/apps/app/src/components/layout/OrganisationSwitcher.vue index 1949a38..07c9323 100644 --- a/apps/app/src/components/layout/OrganisationSwitcher.vue +++ b/apps/app/src/components/layout/OrganisationSwitcher.vue @@ -1,64 +1,111 @@ diff --git a/apps/app/src/components/persons/CreatePersonDialog.vue b/apps/app/src/components/persons/CreatePersonDialog.vue new file mode 100644 index 0000000..44df087 --- /dev/null +++ b/apps/app/src/components/persons/CreatePersonDialog.vue @@ -0,0 +1,199 @@ + + + diff --git a/apps/app/src/components/persons/EditPersonDialog.vue b/apps/app/src/components/persons/EditPersonDialog.vue new file mode 100644 index 0000000..7ab3819 --- /dev/null +++ b/apps/app/src/components/persons/EditPersonDialog.vue @@ -0,0 +1,205 @@ + + + diff --git a/apps/app/src/components/persons/PersonDetailPanel.vue b/apps/app/src/components/persons/PersonDetailPanel.vue new file mode 100644 index 0000000..994f8a0 --- /dev/null +++ b/apps/app/src/components/persons/PersonDetailPanel.vue @@ -0,0 +1,273 @@ + + + diff --git a/apps/app/src/composables/api/useCrowdTypes.ts b/apps/app/src/composables/api/useCrowdTypes.ts new file mode 100644 index 0000000..10a4e8d --- /dev/null +++ b/apps/app/src/composables/api/useCrowdTypes.ts @@ -0,0 +1,30 @@ +import { useQuery } from '@tanstack/vue-query' +import type { Ref } from 'vue' +import { apiClient } from '@/lib/axios' +import type { CrowdType } from '@/types/organisation' + +interface PaginatedResponse { + data: T[] + links: Record + meta: { + current_page: number + per_page: number + total: number + last_page: number + } +} + +export function useCrowdTypeList(orgId: Ref) { + return useQuery({ + queryKey: ['crowd-types', orgId], + queryFn: async () => { + const { data } = await apiClient.get>( + `/organisations/${orgId.value}/crowd-types`, + ) + + return data.data + }, + enabled: () => !!orgId.value, + staleTime: Infinity, + }) +} diff --git a/apps/app/src/composables/api/usePersons.ts b/apps/app/src/composables/api/usePersons.ts new file mode 100644 index 0000000..ba2d0ad --- /dev/null +++ b/apps/app/src/composables/api/usePersons.ts @@ -0,0 +1,129 @@ +import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query' +import type { Ref } from 'vue' +import { apiClient } from '@/lib/axios' +import type { CreatePersonPayload, Person, UpdatePersonPayload } from '@/types/person' + +interface ApiResponse { + success: boolean + data: T + message?: string +} + +interface PaginatedResponse { + data: T[] + links: Record + meta: { + current_page: number + per_page: number + total: number + last_page: number + total_approved: number + total_pending: number + total_rejected: number + } +} + +export function usePersonList( + eventId: Ref, + filters?: Ref<{ crowd_type_id?: string; status?: string }>, +) { + return useQuery({ + queryKey: ['persons', eventId, filters], + queryFn: async () => { + const params: Record = {} + if (filters?.value?.crowd_type_id) + params.crowd_type_id = filters.value.crowd_type_id + if (filters?.value?.status) + params.status = filters.value.status + + const { data } = await apiClient.get>( + `/events/${eventId.value}/persons`, + { params }, + ) + + return data + }, + enabled: () => !!eventId.value, + }) +} + +export function usePersonDetail(eventId: Ref, id: Ref) { + return useQuery({ + queryKey: ['persons', eventId, 'detail', id], + queryFn: async () => { + const { data } = await apiClient.get>( + `/events/${eventId.value}/persons/${id.value}`, + ) + + return data.data + }, + enabled: () => !!eventId.value && !!id.value, + }) +} + +export function useCreatePerson(eventId: Ref) { + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: async (payload: CreatePersonPayload) => { + const { data } = await apiClient.post>( + `/events/${eventId.value}/persons`, + payload, + ) + + return data.data + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['persons', eventId.value] }) + }, + }) +} + +export function useUpdatePerson(eventId: Ref) { + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: async ({ id, ...payload }: UpdatePersonPayload & { id: string }) => { + const { data } = await apiClient.put>( + `/events/${eventId.value}/persons/${id}`, + payload, + ) + + return data.data + }, + onSuccess: (_data, variables) => { + queryClient.invalidateQueries({ queryKey: ['persons', eventId.value] }) + queryClient.invalidateQueries({ queryKey: ['persons', eventId.value, 'detail', variables.id] }) + }, + }) +} + +export function useApprovePerson(eventId: Ref) { + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: async (id: string) => { + const { data } = await apiClient.post>( + `/events/${eventId.value}/persons/${id}/approve`, + ) + + return data.data + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['persons', eventId.value] }) + }, + }) +} + +export function useDeletePerson(eventId: Ref) { + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: async (id: string) => { + await apiClient.delete(`/events/${eventId.value}/persons/${id}`) + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['persons', eventId.value] }) + }, + }) +} diff --git a/apps/app/src/navigation/vertical/index.ts b/apps/app/src/navigation/vertical/index.ts index 4e29633..793ef58 100644 --- a/apps/app/src/navigation/vertical/index.ts +++ b/apps/app/src/navigation/vertical/index.ts @@ -1,27 +1,27 @@ export default [ { - title: "Dashboard", - to: { name: "dashboard" }, - icon: { icon: "tabler-smart-home" }, + title: 'Dashboard', + to: { name: 'dashboard' }, + icon: { icon: 'tabler-smart-home' }, }, { - title: "Events", - to: { name: "events" }, - icon: { icon: "tabler-calendar-event" }, + title: 'Events', + to: { name: 'events' }, + icon: { icon: 'tabler-calendar-event' }, }, { - heading: "Beheer", + heading: 'Beheer', }, { - title: "Mijn Organisatie", - to: { name: "organisation" }, - icon: { icon: "tabler-building" }, + title: 'Mijn Organisatie', + to: { name: 'organisation' }, + icon: { icon: 'tabler-building' }, }, { - title: "Leden", - to: { name: "organisation-members" }, - icon: { icon: "tabler-users-group" }, - action: "read", - subject: "members", + title: 'Leden', + to: { name: 'organisation-members' }, + icon: { icon: 'tabler-users-group' }, + action: 'read', + subject: 'members', }, -]; +] diff --git a/apps/app/src/pages/events/[id].vue b/apps/app/src/pages/events/[id].vue deleted file mode 100644 index 58d11a0..0000000 --- a/apps/app/src/pages/events/[id].vue +++ /dev/null @@ -1,241 +0,0 @@ - - - diff --git a/apps/app/src/pages/events/[id]/artists/index.vue b/apps/app/src/pages/events/[id]/artists/index.vue new file mode 100644 index 0000000..2d55255 --- /dev/null +++ b/apps/app/src/pages/events/[id]/artists/index.vue @@ -0,0 +1,19 @@ + + + diff --git a/apps/app/src/pages/events/[id]/briefings/index.vue b/apps/app/src/pages/events/[id]/briefings/index.vue new file mode 100644 index 0000000..2d55255 --- /dev/null +++ b/apps/app/src/pages/events/[id]/briefings/index.vue @@ -0,0 +1,19 @@ + + + diff --git a/apps/app/src/pages/events/[id]/index.vue b/apps/app/src/pages/events/[id]/index.vue new file mode 100644 index 0000000..a14b07c --- /dev/null +++ b/apps/app/src/pages/events/[id]/index.vue @@ -0,0 +1,68 @@ + + + diff --git a/apps/app/src/pages/events/[id]/persons/index.vue b/apps/app/src/pages/events/[id]/persons/index.vue new file mode 100644 index 0000000..b7494d2 --- /dev/null +++ b/apps/app/src/pages/events/[id]/persons/index.vue @@ -0,0 +1,420 @@ + + + diff --git a/apps/app/src/pages/events/[id]/sections/index.vue b/apps/app/src/pages/events/[id]/sections/index.vue new file mode 100644 index 0000000..2d55255 --- /dev/null +++ b/apps/app/src/pages/events/[id]/sections/index.vue @@ -0,0 +1,19 @@ + + + diff --git a/apps/app/src/pages/events/[id]/settings/index.vue b/apps/app/src/pages/events/[id]/settings/index.vue new file mode 100644 index 0000000..2d55255 --- /dev/null +++ b/apps/app/src/pages/events/[id]/settings/index.vue @@ -0,0 +1,19 @@ + + + diff --git a/apps/app/src/types/organisation.ts b/apps/app/src/types/organisation.ts index 5825408..9c40a1b 100644 --- a/apps/app/src/types/organisation.ts +++ b/apps/app/src/types/organisation.ts @@ -20,3 +20,20 @@ export interface UpdateOrganisationPayload { billing_status?: Organisation['billing_status'] settings?: Record } + +export interface CrowdType { + id: string + name: string + system_type: string + color: string + icon: string | null + is_active: boolean +} + +export interface Company { + id: string + name: string + type: string + contact_name: string | null + contact_email: string | null +} diff --git a/apps/app/src/types/person.ts b/apps/app/src/types/person.ts new file mode 100644 index 0000000..b8e3a6b --- /dev/null +++ b/apps/app/src/types/person.ts @@ -0,0 +1,39 @@ +import type { Company, CrowdType } from '@/types/organisation' + +export type PersonStatus = + | 'invited' + | 'applied' + | 'pending' + | 'approved' + | 'rejected' + | 'no_show' + +export interface Person { + id: string + name: string + email: string + phone: string | null + status: PersonStatus + is_blacklisted: boolean + admin_notes: string | null + custom_fields: Record | null + event_id: string + created_at: string + crowd_type: CrowdType | null + company: Company | null +} + +export interface CreatePersonPayload { + crowd_type_id: string + name: string + email: string + phone?: string + company_id?: string + status?: PersonStatus +} + +export interface UpdatePersonPayload extends Partial { + status?: PersonStatus + is_blacklisted?: boolean + admin_notes?: string +} diff --git a/apps/app/typed-router.d.ts b/apps/app/typed-router.d.ts index 48d10b7..d815517 100644 --- a/apps/app/typed-router.d.ts +++ b/apps/app/typed-router.d.ts @@ -23,6 +23,11 @@ declare module 'vue-router/auto-routes' { 'dashboard': RouteRecordInfo<'dashboard', '/dashboard', Record, Record>, 'events': RouteRecordInfo<'events', '/events', Record, Record>, 'events-id': RouteRecordInfo<'events-id', '/events/:id', { id: ParamValue }, { id: ParamValue }>, + 'events-id-artists': RouteRecordInfo<'events-id-artists', '/events/:id/artists', { id: ParamValue }, { id: ParamValue }>, + 'events-id-briefings': RouteRecordInfo<'events-id-briefings', '/events/:id/briefings', { id: ParamValue }, { id: ParamValue }>, + 'events-id-persons': RouteRecordInfo<'events-id-persons', '/events/:id/persons', { id: ParamValue }, { id: ParamValue }>, + 'events-id-sections': RouteRecordInfo<'events-id-sections', '/events/:id/sections', { id: ParamValue }, { id: ParamValue }>, + 'events-id-settings': RouteRecordInfo<'events-id-settings', '/events/:id/settings', { id: ParamValue }, { id: ParamValue }>, 'invitations-token': RouteRecordInfo<'invitations-token', '/invitations/:token', { token: ParamValue }, { token: ParamValue }>, 'login': RouteRecordInfo<'login', '/login', Record, Record>, 'organisation': RouteRecordInfo<'organisation', '/organisation', Record, Record>,