Skip to content

Commit

Permalink
feat: add team ModalInvite component
Browse files Browse the repository at this point in the history
  • Loading branch information
enya-yy committed Oct 17, 2023
1 parent 707291e commit 5916667
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 5 deletions.
95 changes: 95 additions & 0 deletions components/ModalInvite.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<script lang="ts" setup>
import type { User } from '@prisma/client'
const props = withDefaults(defineProps<{
teamId?: string
}>(), {
teamId: '',
})
const emit = defineEmits(['success'])
const { $client } = useNuxtApp()
const toast = useToast()
const modelValue = defineModel<boolean>({ default: false })
const loading = ref(false)
const users = ref<Array<User>>([])
const selected = ref([])
function onInput(e: Event) {
const value = (e.target as HTMLInputElement).value
if (!value)
return
fetchUserList(value)
}
async function fetchUserList(keyword: string) {
if (!keyword)
return
try {
loading.value = true
const data = await $client.protected.userList.query({
teamId: props.teamId,
keyword,
})
users.value = data
}
catch (error) {
if (error instanceof Error) {
toast.add({ title: error.message, color: 'red' })
return
}
console.error(error)
toast.add({ title: 'Unknown error', color: 'red' })
}
finally {
loading.value = false
}
}
function onInvite() {
// TODO: send email
modelValue.value = false
users.value = []
emit('success')
}
</script>

<template>
<div class="w-28">
<UModal v-model="modelValue" class="text-red" prevent-close>
<UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
<template #header>
<div class="flex items-center justify-between">
<h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white">
Invite member
</h3>
<UButton color="gray" variant="ghost" icon="i-heroicons-x-mark-20-solid" class="-my-1" @click="modelValue = false" />
</div>
</template>
<UCommandPalette
v-model="selected"
placeholder="Search by username or email address"
multiple
nullable
:autoclear="false"
:autoselect="false"
group-attribute="username"
command-attribute="username"
:groups="[{ key: 'users', commands: users }]"
:fuse="{ resultLimit: 6, fuseOptions: { threshold: 0.1 } }"
@input="onInput"
/>
<div class="mt-4 text-right">
<UButton class="" :disabled="!selected.length" @click="onInvite">
Invite
</UButton>
<UButton variant="outline" class="ml-4" @click="modelValue = false">
Cancel
</UButton>
</div>
</UCard>
</UModal>
</div>
</template>
14 changes: 10 additions & 4 deletions components/TeamMembers.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
<script setup lang="ts">
interface ProjectListProp {
const props = withDefaults(defineProps<{
teamId: string
}
const props = withDefaults(defineProps<ProjectListProp>(), {
}>(), {
teamId: '',
})
const { $client } = useNuxtApp()
// fetch team members
const { pending, error, data: members } = $client.protected.teamMembers.useQuery({
teamId: props.teamId,
})
const modalInvite = ref(false)
function inviteMembers() {
modalInvite.value = true
}
</script>

<template>
<ModalInvite v-model="modalInvite" :team-id="props.teamId" />
<div class="flex items-center my-8">
<UInput class="w-44 mr-4" icon="i-heroicons-magnifying-glass-20-solid" size="sm" color="white" :trailing="false" />
<UButton @click="() => {}">
<UButton @click="inviteMembers">
Invite Members
</UButton>
</div>
Expand Down
2 changes: 1 addition & 1 deletion layouts/entrySidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ async function onTeamDelete(id: string) {
</script>

<template>
<ModalTeamCreate v-model="modalTeamCreate" @success="naviteToTeam" />
<div class="flex w-screen h-screen overflow-hidden">
<ModalTeamCreate v-model="modalTeamCreate" @success="naviteToTeam" />
<div class="relative w-[280px] h-screen px-4 py-8 border-r border-gray-200 dark:border-gray-800">
<!-- logo -->
<div class="flex items-center">
Expand Down
40 changes: 40 additions & 0 deletions server/trpc/routers/protected.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,46 @@ export const protectedRouter = router({
.mutation(async (event) => {
await event.ctx.session.clear()
}),
userList: protectedProcedure
.input(
z.object({
teamId: z.string(),
keyword: z.string(),
}),
)
.query(async (event) => {
const { ctx, input } = event
const users = await ctx.prisma.user.findMany({
where: {
AND: [
{
OR: [
{
username: {
contains: input.keyword,
},
},
{
email: {
contains: input.keyword,
},
},
],
},
{
NOT: {
TeamMember: {
some: {
teamId: input.teamId,
},
},
},
},
],
},
})
return users
}),
// TODO: pagination
projectList: protectedProcedure
.input(
Expand Down

0 comments on commit 5916667

Please sign in to comment.