174 lines
4.9 KiB
TypeScript
174 lines
4.9 KiB
TypeScript
|
|
|
|
import { AdminDataTable } from '@/components/admin/AdminDataTable';
|
|
import { AdminEmptyState } from '@/components/admin/AdminEmptyState';
|
|
import { AdminHeaderPanel } from '@/components/admin/AdminHeaderPanel';
|
|
import { AdminStatsPanel } from '@/components/admin/AdminStatsPanel';
|
|
import { AdminUsersTable } from '@/components/admin/AdminUsersTable';
|
|
import { BulkActionBar } from '@/components/admin/BulkActionBar';
|
|
import { UserFilters } from '@/components/admin/UserFilters';
|
|
import { TemplateProps } from '@/lib/contracts/components/ComponentContracts';
|
|
import { AdminUsersViewData } from '@/lib/view-data/AdminUsersViewData';
|
|
import { Box } from '@/ui/Box';
|
|
import { Button } from '@/ui/Button';
|
|
import { Container } from '@/ui/Container';
|
|
import { ErrorBanner } from '@/ui/ErrorBanner';
|
|
import { Stack } from '@/ui/Stack';
|
|
import { RefreshCw, ShieldAlert, Users } from 'lucide-react';
|
|
|
|
// We need to add InlineNotice to UIComponents if it's used
|
|
// For now I'll assume it's a component or I'll add it to UIComponents
|
|
|
|
interface AdminUsersTemplateProps extends TemplateProps<AdminUsersViewData> {
|
|
onRefresh: () => void;
|
|
onSearch: (search: string) => void;
|
|
onFilterRole: (role: string) => void;
|
|
onFilterStatus: (status: string) => void;
|
|
onClearFilters: () => void;
|
|
onUpdateStatus: (userId: string, status: string) => void;
|
|
onDeleteUser: (userId: string) => void;
|
|
search: string;
|
|
roleFilter: string;
|
|
statusFilter: string;
|
|
loading: boolean;
|
|
error: string | null;
|
|
deletingUser: string | null;
|
|
// Selection state passed from wrapper
|
|
selectedUserIds: string[];
|
|
onSelectUser: (userId: string) => void;
|
|
onSelectAll: () => void;
|
|
onClearSelection: () => void;
|
|
}
|
|
|
|
export function AdminUsersTemplate({
|
|
viewData,
|
|
onRefresh,
|
|
onSearch,
|
|
onFilterRole,
|
|
onFilterStatus,
|
|
onClearFilters,
|
|
onUpdateStatus,
|
|
onDeleteUser,
|
|
search,
|
|
roleFilter,
|
|
statusFilter,
|
|
loading,
|
|
error,
|
|
deletingUser,
|
|
selectedUserIds,
|
|
onSelectUser,
|
|
onSelectAll,
|
|
onClearSelection
|
|
}: AdminUsersTemplateProps) {
|
|
const stats = [
|
|
{
|
|
label: 'Total Users',
|
|
value: viewData.total,
|
|
icon: Users,
|
|
variant: 'blue' as const
|
|
},
|
|
{
|
|
label: 'Active Users',
|
|
value: viewData.activeUserCount,
|
|
icon: RefreshCw,
|
|
variant: 'green' as const
|
|
},
|
|
{
|
|
label: 'System Admins',
|
|
value: viewData.adminCount,
|
|
icon: ShieldAlert,
|
|
variant: 'purple' as const
|
|
}
|
|
];
|
|
|
|
const bulkActions = [
|
|
{
|
|
label: 'Suspend Selected',
|
|
onClick: () => {
|
|
console.log('Bulk suspend', selectedUserIds);
|
|
},
|
|
variant: 'secondary' as const
|
|
},
|
|
{
|
|
label: 'Delete Selected',
|
|
onClick: () => {
|
|
console.log('Bulk delete', selectedUserIds);
|
|
},
|
|
variant: 'danger' as const
|
|
}
|
|
];
|
|
|
|
return (
|
|
<Container size="lg">
|
|
<Box paddingY={8}>
|
|
<Stack gap={8}>
|
|
<AdminHeaderPanel
|
|
title="User Management"
|
|
description="Monitor and control system access"
|
|
isLoading={loading}
|
|
actions={
|
|
<Button
|
|
onClick={onRefresh}
|
|
disabled={loading}
|
|
variant="secondary"
|
|
size="sm"
|
|
icon={<Icon icon={RefreshCw} size={3} animate={loading ? 'spin' : 'none'} />}
|
|
>
|
|
Refresh Data
|
|
</Button>
|
|
}
|
|
/>
|
|
|
|
{/* error notice should be a component */}
|
|
{error && (
|
|
<ErrorBanner title="Operation Failed" message={error} />
|
|
)}
|
|
|
|
<AdminStatsPanel stats={stats} />
|
|
|
|
<UserFilters
|
|
search={search}
|
|
roleFilter={roleFilter}
|
|
statusFilter={statusFilter}
|
|
onSearch={onSearch}
|
|
onFilterRole={onFilterRole}
|
|
onFilterStatus={onFilterStatus}
|
|
onClearFilters={onClearFilters}
|
|
/>
|
|
|
|
<AdminDataTable>
|
|
{viewData.users.length === 0 && !loading ? (
|
|
<AdminEmptyState
|
|
icon={Users}
|
|
title="No users found"
|
|
description="Try adjusting your filters or search query"
|
|
action={
|
|
<Button variant="secondary" size="sm" onClick={onClearFilters}>
|
|
Clear All Filters
|
|
</Button>
|
|
}
|
|
/>
|
|
) : (
|
|
<AdminUsersTable
|
|
users={viewData.users}
|
|
selectedUserIds={selectedUserIds}
|
|
onSelectUser={onSelectUser}
|
|
onSelectAll={onSelectAll}
|
|
onUpdateStatus={onUpdateStatus}
|
|
onDeleteUser={onDeleteUser}
|
|
deletingUserId={deletingUser}
|
|
/>
|
|
)}
|
|
</AdminDataTable>
|
|
|
|
<BulkActionBar
|
|
selectedCount={selectedUserIds.length}
|
|
actions={bulkActions}
|
|
onClearSelection={onClearSelection}
|
|
/>
|
|
</Stack>
|
|
</Box>
|
|
</Container>
|
|
);
|
|
}
|