Skip to content

Commit

Permalink
feat: update
Browse files Browse the repository at this point in the history
  • Loading branch information
qin-guan committed Jan 6, 2024
1 parent 69eb3a1 commit ab0c981
Show file tree
Hide file tree
Showing 12 changed files with 86 additions and 41 deletions.
2 changes: 1 addition & 1 deletion components/admin/event/create-popup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const schema = z.object({
endDateTime: z.string()
.transform(d => $dayjs(d).unix().toString()),
}).refine((val) => {
return $dayjs(val.startDateTime).isBefore(val.endDateTime)
return Number.parseInt(val.startDateTime) < Number.parseInt(val.endDateTime)
}, {
message: 'Event must end after it starts',
path: ['endDateTime'],
Expand Down
5 changes: 2 additions & 3 deletions composables/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,10 @@ export function useUpdateEventMutation(id: string) {
})
}

export function useUpdateEventUsersMutation(id: string) {
export function useAddEventUsersMutation(id: string) {
const queryClient = useQueryClient()
return useMutation({
// TODO @qin-guan
mutationFn: (body: Pick<Event, 'id'>) => $api(`/api/event/${id}/users`, { method: 'PUT', body }),
mutationFn: (body: { userId: string }[]) => $api(`/api/event/${id}/attendees`, { method: 'post', body }),
onSuccess() {
queryClient.invalidateQueries({
queryKey: queryKeyFactory.events,
Expand Down
2 changes: 1 addition & 1 deletion composables/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ export function useUserSignOutMutation() {

export function useBulkCreateUserMutation() {
return useMutation({
mutationFn: (body: Partial<User>) => $api('/api/user/bulk', { method: 'post', body }),
mutationFn: (body: Partial<User>[]) => $api('/api/user/bulk', { method: 'post', body }),
})
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@vueuse/core": "^10.7.1",
"@vueuse/integrations": "^10.7.1",
"@vueuse/nuxt": "^10.7.1",
"better-sqlite3": "^9.2.2",
"dayjs": "^1.11.10",
"dotenv": "^16.3.1",
"drizzle-kit": "^0.19.13",
Expand Down
71 changes: 59 additions & 12 deletions pages/admin/events/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import type { User } from '~/shared/types'
const route = useRoute()
const toast = useToast()
const { data: event, isPending: eventIsPending } = useEvent(route.params.id as string)
const { mutate: createUsersMutate, isPending: createUsersIsPending } = useBulkCreateUserMutation()
const { mutate: addEventUsersMutate, isPending: addEventUsersIsPending } = useAddEventUsersMutation(route.params.id as string)
const showPending = computed(() => createUsersIsPending.value || addEventUsersIsPending.value)
const links = computed(() => [
{
Expand All @@ -18,8 +22,11 @@ const links = computed(() => [
type CsvRow = Pick<User, 'name' | 'email' | 'memberType' | 'graduationYear'>
const userUploadPreview = ref<CsvRow[]>([])
let users: CsvRow[] = []
async function parseCsvFile(event: Event) {
users = []
const target = event.target as HTMLInputElement
if (!target.files || target.files.length < 1) {
return toast.add({
Expand All @@ -28,7 +35,6 @@ async function parseCsvFile(event: Event) {
}
const { parse } = await import('papaparse')
const users: CsvRow[] = []
parse<{ name: string, email: string, memberType: string, graduationYear: string }>(target.files[0], {
header: true,
Expand Down Expand Up @@ -64,7 +70,38 @@ async function parseCsvFile(event: Event) {
}
function uploadUsers() {
createUsersMutate(users, {
onSuccess(r) {
addEventUsersMutate(
r.map(u => ({
userId: u.id,
})),
{
onSuccess() {
toast.add({
color: 'green',
title: 'Users added',
description: 'Users have been added to the event',
})
},
onError(error) {
console.error(error)
toast.add({
title: 'Error adding users to event',
description: error.message,
})
},
},
)
},
onError(error) {
console.error(error)
toast.add({
title: 'Error adding users to event',
description: error.message,
})
},
})
}
</script>

Expand Down Expand Up @@ -94,20 +131,30 @@ function uploadUsers() {
</div>

<section class="space-y-4">
<div class="space-y-4">
<h2 class="text-lg font-semibold">
Attendees
</h2>
<h2 class="text-lg font-semibold">
Attendees
</h2>

<UFormGroup label="Add attendees">
<input as="input" type="file" @change="parseCsvFile">
</UFormGroup>

<div v-if="userUploadPreview.length > 0" class="space-y-4">
<span class="font-semibold">CSV preview</span>

<template v-if="userUploadPreview.length > 0">
<UTable :rows="userUploadPreview" />
<UButton @click="uploadUsers">
Save
</UButton>
</template>
<UTable :rows="userUploadPreview" />

<UAlert
variant="subtle" color="yellow" title="Info"
description="If a user with the specified email already exists, a new user will not be created. The existing user will be added to the event."
/>

<UButton :pending="showPending" @click="uploadUsers">
Add users
</UButton>
</div>

<UTable v-else-if="event?.attendees" :rows="event.attendees" />
</section>
</div>
</div>
Expand Down
16 changes: 14 additions & 2 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { createId } from '@paralleldrive/cuid2'
import { z } from 'zod'
import { usersToEvents } from '~/server/db/schema'

const bulkCreateEventUserRequestBody = z.array(
z.object({
userId: z.string().nonempty(),
eventId: z.string().nonempty(),
userId: z.string().cuid2(),
}),
)

Expand All @@ -24,19 +22,12 @@ export default defineProtectedEventHandler(async (event) => {
.values(
data.map(user => ({
userId: user.userId,
eventId: user.eventId,
admissionKey: createId(),
eventId: event.context.params!.id,
})),
)
.onConflictDoNothing()
.returning()

if (createdUsers.length !== data.length) {
throw createError({
statusCode: 500,
statusMessage: 'Internal server error',
})
}

return createdUsers
}, {
restrictTo: ['exco'],
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
13 changes: 4 additions & 9 deletions server/api/user/bulk.post.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { eq, or } from 'drizzle-orm'
import { z } from 'zod'
import { users } from '~/server/db/schema'

const bulkCreateUserRequestBody = z.array(
z.object({
memberId: z.string().min(1),
name: z.string().min(1),
email: z.string().email(),
graduationYear: z.number().int().min(2011),
Expand All @@ -28,7 +28,7 @@ export default defineProtectedEventHandler(async (event) => {

const { data } = result

const createdUsers = await event.context.database.insert(users)
await event.context.database.insert(users)
.values(
data.map(user => ({
name: user.name,
Expand All @@ -40,14 +40,9 @@ export default defineProtectedEventHandler(async (event) => {
.onConflictDoNothing()
.returning()

if (createdUsers.length !== data.length) {
throw createError({
statusCode: 500,
statusMessage: 'Internal server error',
})
}
const query = or(...data.map(u => eq(users.email, u.email)))

return createdUsers
return await event.context.database.select().from(users).where(query)
}, {
restrictTo: ['exco'],
})
2 changes: 1 addition & 1 deletion server/db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const events = sqliteTable('events', {
export const usersToEvents = sqliteTable('users_events', {
userId: text('user_id').notNull().references(() => users.id, { onDelete: 'cascade', onUpdate: 'cascade' }),
eventId: text('event_id').notNull().references(() => events.id, { onDelete: 'cascade', onUpdate: 'cascade' }),
admissionKey: text('admission_key').notNull(),
admissionKey: text('admission_key').notNull().$defaultFn(() => createId()),
}, t => ({
pk: primaryKey(t.userId, t.eventId),
}))
Expand Down

0 comments on commit ab0c981

Please sign in to comment.