feat: UsersTable and UserCardList get Email, Display name (dash when empty), Role (new RoleBadge), Invite status and Created

This commit is contained in:
fsylvain committed 2026-09-30 02:00:46 +02:00
1 parent 153fd8719a
commit 1ece778caf
19 files changed
+485 -204

No files matched your search

@@ -0,0 +1,34 @@
import { describe, expect, it } from 'vitest'
import { userRole, type UserListItem } from '@/composables/useUsers'
describe('userRole', () => {
it.each([['owner' as const], ['admin' as const]])('passes a user role %s through', (role) => {
const item: UserListItem = {
kind: 'user',
id: 1,
username: 'u',
display_name: '',
email: 'u@renew.example',
role,
status: 'accepted',
created_at: '2026-03-12T00:00:00Z',
}
expect(userRole(item)).toBe(role)
})
it.each([['pending' as const], ['expired' as const]])(
'returns admin for a %s invite',
(status) => {
const item: UserListItem = {
kind: 'invite',
id: 2,
email: 'i@renew.example',
status,
created_at: '2026-03-12T00:00:00Z',
}
expect(userRole(item)).toBe('admin')
},
)
})
+5
View File
@@ -21,12 +21,15 @@ export class NetworkError extends Error {
}
}
export type UserRole = 'owner' | 'admin'
export interface MeResult {
id?: number
verified: boolean
username?: string
email?: string
displayName: string
role?: UserRole
}
export type OnUnauthorized = 'redirect' | 'passthrough'
@@ -135,6 +138,7 @@ export function useApi() {
username?: string
email?: string
display_name?: string | null
role?: string
}>('/v1/auth/me', { onUnauthorized: 'passthrough' })
return {
id: body.id,
@@ -142,6 +146,7 @@ export function useApi() {
username: body.username,
email: body.email,
displayName: body.display_name ?? '',
role: body.role as UserRole | undefined,
}
}
+11
View File
@@ -6,6 +6,8 @@ export type UserListItem =
id: number
username: string
display_name: string
email: string
role: 'owner' | 'admin'
status: 'accepted'
created_at: string
}
@@ -13,6 +15,7 @@ export type UserListItem =
kind: 'invite'
id: number
email: string
display_name?: string
status: 'pending' | 'expired'
created_at: string
}
@@ -23,6 +26,14 @@ export function userRowKey(kind: UserListItem['kind'], id: number) {
return `${kind}-${id}`
}
export function userDisplayName(item: UserListItem) {
return item.display_name ?? ''
}
export function userRole(item: UserListItem): 'owner' | 'admin' {
return item.kind === 'user' ? item.role : 'admin'
}
export interface CreatedInvite {
id: number
kind: 'invite'