refactor: align codebase with EventCrew domain and trim legacy band stack
- Update API: events, users, policies, routes, resources, migrations - Remove deprecated models/resources (customers, setlists, invitations, etc.) - Refresh admin app and docs; remove apps/band Made-with: Cursor
This commit is contained in:
@@ -1,176 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { $api } from '@/utils/api'
|
||||
import type { User, ApiResponse } from '@/types/events'
|
||||
|
||||
const props = defineProps<{
|
||||
isDialogOpen: boolean
|
||||
eventId: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:isDialogOpen', val: boolean): void
|
||||
(e: 'invited'): void
|
||||
}>()
|
||||
|
||||
const selectedUserIds = ref<string[]>([])
|
||||
const availableUsers = ref<User[]>([])
|
||||
const isLoading = ref(false)
|
||||
const isInviting = ref(false)
|
||||
const searchQuery = ref('')
|
||||
|
||||
const isDialogOpenModel = computed({
|
||||
get: () => props.isDialogOpen,
|
||||
set: (val) => emit('update:isDialogOpen', val),
|
||||
})
|
||||
|
||||
// Fetch available users (members)
|
||||
async function fetchUsers() {
|
||||
isLoading.value = true
|
||||
try {
|
||||
// TODO: Replace with actual users/members endpoint when available
|
||||
// For now, this will fail gracefully and show an empty list
|
||||
// Expected endpoint: GET /users or GET /members with filters for type=member
|
||||
const response = await $api<ApiResponse<User[]>>('/users', {
|
||||
method: 'GET',
|
||||
query: {
|
||||
type: 'member',
|
||||
status: 'active',
|
||||
},
|
||||
})
|
||||
availableUsers.value = response.data
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch users. Make sure a /users endpoint exists:', err)
|
||||
// Set empty array on error so UI doesn't break
|
||||
availableUsers.value = []
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Watch dialog open to fetch users
|
||||
watch(() => props.isDialogOpen, (isOpen) => {
|
||||
if (isOpen) {
|
||||
fetchUsers()
|
||||
selectedUserIds.value = []
|
||||
}
|
||||
})
|
||||
|
||||
async function handleInvite() {
|
||||
if (selectedUserIds.value.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
isInviting.value = true
|
||||
try {
|
||||
await $api(`/events/${props.eventId}/invite`, {
|
||||
method: 'POST',
|
||||
body: {
|
||||
user_ids: selectedUserIds.value,
|
||||
},
|
||||
})
|
||||
emit('invited')
|
||||
isDialogOpenModel.value = false
|
||||
} catch (err) {
|
||||
console.error('Failed to invite members:', err)
|
||||
} finally {
|
||||
isInviting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const filteredUsers = computed(() => {
|
||||
if (!searchQuery.value) {
|
||||
return availableUsers.value
|
||||
}
|
||||
const query = searchQuery.value.toLowerCase()
|
||||
return availableUsers.value.filter(
|
||||
user =>
|
||||
user.name.toLowerCase().includes(query) ||
|
||||
user.email.toLowerCase().includes(query)
|
||||
)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VDialog
|
||||
v-model="isDialogOpenModel"
|
||||
max-width="600"
|
||||
>
|
||||
<VCard>
|
||||
<VCardTitle>Invite Members to Event</VCardTitle>
|
||||
|
||||
<VDivider />
|
||||
|
||||
<VCardText>
|
||||
<AppTextField
|
||||
v-model="searchQuery"
|
||||
placeholder="Search members..."
|
||||
prepend-inner-icon="tabler-search"
|
||||
class="mb-4"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-if="isLoading"
|
||||
class="text-center py-8"
|
||||
>
|
||||
<VProgressCircular
|
||||
indeterminate
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="member-list"
|
||||
style="max-height: 400px; overflow-y: auto;"
|
||||
>
|
||||
<VCheckbox
|
||||
v-for="user in filteredUsers"
|
||||
:key="user.id"
|
||||
v-model="selectedUserIds"
|
||||
:value="user.id"
|
||||
class="mb-2"
|
||||
>
|
||||
<template #label>
|
||||
<div>
|
||||
<div class="text-body-1">
|
||||
{{ user.name }}
|
||||
</div>
|
||||
<div class="text-body-2 text-medium-emphasis">
|
||||
{{ user.email }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</VCheckbox>
|
||||
|
||||
<VAlert
|
||||
v-if="filteredUsers.length === 0"
|
||||
type="info"
|
||||
>
|
||||
No members found
|
||||
</VAlert>
|
||||
</div>
|
||||
</VCardText>
|
||||
|
||||
<VDivider />
|
||||
|
||||
<VCardActions>
|
||||
<VSpacer />
|
||||
<VBtn
|
||||
variant="text"
|
||||
@click="isDialogOpenModel = false"
|
||||
>
|
||||
Cancel
|
||||
</VBtn>
|
||||
<VBtn
|
||||
color="primary"
|
||||
:disabled="selectedUserIds.length === 0"
|
||||
:loading="isInviting"
|
||||
@click="handleInvite"
|
||||
>
|
||||
Invite {{ selectedUserIds.length }} Member(s)
|
||||
</VBtn>
|
||||
</VCardActions>
|
||||
</VCard>
|
||||
</VDialog>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user