feat: improve requester combobox and admin cleanup flows

This commit is contained in:
Esdras Renan 2025-10-24 00:45:41 -03:00
parent 788f6928a1
commit 37c32149a6
13 changed files with 923 additions and 180 deletions

View file

@ -266,65 +266,67 @@ function AccountsTable({ initialAccounts }: { initialAccounts: AdminAccount[] })
</div>
<div className="overflow-x-auto">
<Table className="min-w-[64rem]">
<TableHeader>
<TableRow>
<TableHead>Usuário</TableHead>
<TableHead>Empresa</TableHead>
<TableHead>Papel</TableHead>
<TableHead>Último acesso</TableHead>
<TableHead className="text-right">Selecionar</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredAccounts.length === 0 ? (
<div className="min-w-[64rem] overflow-hidden rounded-lg border">
<Table className="w-full table-fixed text-sm">
<TableHeader className="bg-muted">
<TableRow>
<TableCell colSpan={5} className="text-center text-sm text-muted-foreground">
Nenhum usuário encontrado.
</TableCell>
<TableHead>Usuário</TableHead>
<TableHead>Empresa</TableHead>
<TableHead>Papel</TableHead>
<TableHead>Último acesso</TableHead>
<TableHead className="text-right">Selecionar</TableHead>
</TableRow>
) : (
filteredAccounts.map((account) => {
const initials = account.name
.split(" ")
.filter(Boolean)
.slice(0, 2)
.map((part) => part.charAt(0).toUpperCase())
.join("")
return (
<TableRow key={account.id} className="hover:bg-muted/40">
<TableCell>
<div className="flex items-center gap-3">
<Avatar className="size-9 border border-border/60">
<AvatarFallback>{initials || account.email.charAt(0).toUpperCase()}</AvatarFallback>
</Avatar>
<div className="min-w-0 space-y-1">
<p className="font-semibold text-foreground">{account.name}</p>
<p className="text-xs text-muted-foreground">{account.email}</p>
</TableHeader>
<TableBody>
{filteredAccounts.length === 0 ? (
<TableRow>
<TableCell colSpan={5} className="text-center text-sm text-muted-foreground">
Nenhum usuário encontrado.
</TableCell>
</TableRow>
) : (
filteredAccounts.map((account) => {
const initials = account.name
.split(" ")
.filter(Boolean)
.slice(0, 2)
.map((part) => part.charAt(0).toUpperCase())
.join("")
return (
<TableRow key={account.id} className="hover:bg-muted/40">
<TableCell>
<div className="flex items-center gap-3">
<Avatar className="size-9 border border-border/60">
<AvatarFallback>{initials || account.email.charAt(0).toUpperCase()}</AvatarFallback>
</Avatar>
<div className="min-w-0 space-y-1">
<p className="font-semibold text-foreground">{account.name}</p>
<p className="text-xs text-muted-foreground">{account.email}</p>
</div>
</div>
</div>
</TableCell>
<TableCell className="text-sm text-muted-foreground">
{account.companyName ?? <span className="italic text-muted-foreground/70">Sem empresa</span>}
</TableCell>
<TableCell className="text-sm">
<Badge variant="secondary">{ROLE_LABEL[account.role]}</Badge>
</TableCell>
<TableCell className="text-xs text-muted-foreground">{formatDate(account.lastSeenAt)}</TableCell>
<TableCell className="text-right">
<Checkbox
checked={rowSelection[account.id] ?? false}
onCheckedChange={(checked) =>
setRowSelection((prev) => ({ ...prev, [account.id]: Boolean(checked) }))
}
/>
</TableCell>
</TableRow>
)
})
)}
</TableBody>
</Table>
</TableCell>
<TableCell className="text-sm text-muted-foreground">
{account.companyName ?? <span className="italic text-muted-foreground/70">Sem empresa</span>}
</TableCell>
<TableCell className="text-sm">
<Badge variant="secondary">{ROLE_LABEL[account.role]}</Badge>
</TableCell>
<TableCell className="text-xs text-muted-foreground">{formatDate(account.lastSeenAt)}</TableCell>
<TableCell className="text-right">
<Checkbox
checked={rowSelection[account.id] ?? false}
onCheckedChange={(checked) =>
setRowSelection((prev) => ({ ...prev, [account.id]: Boolean(checked) }))
}
/>
</TableCell>
</TableRow>
)
})
)}
</TableBody>
</Table>
</div>
</div>
</CardContent>