84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
'use client';
|
|
|
|
import {proportional} from '@astryxdesign/core/Table';
|
|
import type {TableColumn} from '@astryxdesign/core/Table';
|
|
import {VStack, HStack} from '@astryxdesign/core/Layout';
|
|
import {Text} from '@astryxdesign/core/Text';
|
|
import {Avatar} from '@astryxdesign/core/Avatar';
|
|
import {Badge} from '@astryxdesign/core/Badge';
|
|
import {PanelCard} from '@/shared/components/patterns/PanelCard';
|
|
import {ResponsiveTable} from '@/shared/components/patterns/ResponsiveTable';
|
|
import {SkeletonRows} from '@/shared/components/patterns/LoadingState';
|
|
import {EmptyPanel} from '@/shared/components/patterns/EmptyPanel';
|
|
import type {TeamMember} from '@/features/team/types/team';
|
|
import type {Resource} from '@/shared/hooks/useResource';
|
|
|
|
interface Row extends Record<string, unknown> {
|
|
id: string;
|
|
name: string;
|
|
email: string;
|
|
role: string;
|
|
}
|
|
|
|
const COLUMNS: TableColumn<Row>[] = [
|
|
{
|
|
key: 'name',
|
|
header: 'Person',
|
|
width: proportional(1),
|
|
renderCell: (row) => (
|
|
<HStack gap={2} vAlign="center">
|
|
<Avatar name={row.name} size="sm" tooltip={false} />
|
|
<VStack gap={0}>
|
|
<Text size="sm" weight="medium">
|
|
{row.name}
|
|
</Text>
|
|
<Text size="xsm" color="secondary">
|
|
{row.email}
|
|
</Text>
|
|
</VStack>
|
|
</HStack>
|
|
),
|
|
},
|
|
{
|
|
key: 'role',
|
|
header: 'Role',
|
|
align: 'end',
|
|
// Role IS an enumerated state, which is what a Badge is for — unlike a
|
|
// status, which is a dot.
|
|
renderCell: (row) => <Badge variant="neutral" label={row.role} />,
|
|
},
|
|
];
|
|
|
|
export function TeamTable({resource}: {resource: Resource<TeamMember[]>}) {
|
|
return (
|
|
<PanelCard
|
|
title="Team"
|
|
subtitle="Who can sign in to this console, and at what privilege"
|
|
resource={resource}
|
|
loading={<SkeletonRows count={5} height={44} />}
|
|
empty={
|
|
<EmptyPanel
|
|
icon="staff"
|
|
title="No team members"
|
|
description="People appear here once they accept an invitation."
|
|
/>
|
|
}
|
|
>
|
|
{(members) => (
|
|
<ResponsiveTable
|
|
data={members.map((m) => ({
|
|
id: m.id,
|
|
name: m.name,
|
|
email: m.email,
|
|
role: m.role,
|
|
}))}
|
|
columns={COLUMNS}
|
|
idKey="id"
|
|
primaryKey="name"
|
|
density="balanced"
|
|
/>
|
|
)}
|
|
</PanelCard>
|
|
);
|
|
}
|