82 lines
2.2 KiB
Vue
82 lines
2.2 KiB
Vue
<script setup lang="ts">
|
|
import { t } from '@/i18n'
|
|
|
|
import InviteStatusBadge from '@/components/InviteStatusBadge.vue'
|
|
import RoleBadge from '@/components/RoleBadge.vue'
|
|
import UserRowAction from '@/components/UserRowAction.vue'
|
|
import UserEmailCell from '@/components/UserEmailCell.vue'
|
|
import { formatCreatedDate } from '@/lib/relativeDate'
|
|
import {
|
|
USER_SKELETON_ROWS,
|
|
userDisplayName,
|
|
userRole,
|
|
userRowKey,
|
|
type UserListItem,
|
|
} from '@/composables/useUsers'
|
|
|
|
defineProps<{
|
|
items: UserListItem[]
|
|
loading: boolean
|
|
sessionUserId?: number
|
|
highlightedKey?: string
|
|
canManage?: boolean
|
|
busyKeys?: string[]
|
|
}>()
|
|
|
|
const emit = defineEmits<{
|
|
cancel: [item: UserListItem]
|
|
renew: [item: UserListItem]
|
|
}>()
|
|
|
|
function rowKey(item: UserListItem) {
|
|
return userRowKey(item.kind, item.id)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<ul class="-mx-4 border-y border-default bg-default" :aria-busy="loading ? 'true' : undefined">
|
|
<template v-if="loading">
|
|
<li
|
|
v-for="n in USER_SKELETON_ROWS"
|
|
:key="n"
|
|
class="flex min-h-17 flex-col justify-center gap-1.5 border-b border-default px-4 py-3"
|
|
>
|
|
<USkeleton class="h-3.5 w-[55%] rounded-none bg-accented" />
|
|
<USkeleton class="h-3 w-[40%] rounded-none bg-accented" />
|
|
</li>
|
|
</template>
|
|
<template v-else>
|
|
<li
|
|
v-for="item in items"
|
|
:key="rowKey(item)"
|
|
data-testid="user-card"
|
|
class="flex min-h-17 flex-col justify-center gap-1.5 border-b border-default px-4 py-3"
|
|
:class="{ 'bg-elevated': rowKey(item) === highlightedKey }"
|
|
>
|
|
<UserEmailCell
|
|
:email="item.email"
|
|
:is-you="item.kind === 'user' && item.id === sessionUserId"
|
|
large
|
|
/>
|
|
<span v-if="userDisplayName(item)" class="text-toned">{{
|
|
userDisplayName(item)
|
|
}}</span>
|
|
<div class="flex items-center gap-2 text-xs text-muted">
|
|
<RoleBadge :role="userRole(item)" />
|
|
<InviteStatusBadge :status="item.status" size="sm" />
|
|
<span>{{ t('Created') }} {{ formatCreatedDate(item.created_at) }}</span>
|
|
</div>
|
|
<div v-if="canManage && item.kind === 'invite'" class="flex pt-1">
|
|
<UserRowAction
|
|
:item="item"
|
|
large
|
|
:busy="busyKeys?.includes(rowKey(item))"
|
|
@cancel="emit('cancel', item)"
|
|
@renew="emit('renew', item)"
|
|
/>
|
|
</div>
|
|
</li>
|
|
</template>
|
|
</ul>
|
|
</template>
|