223 lines
8.5 KiB
TypeScript
223 lines
8.5 KiB
TypeScript
import {
|
|
ActionIcon,
|
|
Badge,
|
|
Button,
|
|
Card,
|
|
Container,
|
|
Group,
|
|
Stack,
|
|
Table,
|
|
Text,
|
|
TextInput,
|
|
Title,
|
|
Paper,
|
|
Tabs,
|
|
Avatar,
|
|
SimpleGrid,
|
|
ThemeIcon,
|
|
List,
|
|
Box,
|
|
Divider,
|
|
} from '@mantine/core'
|
|
import { createFileRoute } from '@tanstack/react-router'
|
|
import {
|
|
TbPlus,
|
|
TbSearch,
|
|
TbPencil,
|
|
TbTrash,
|
|
TbUserCheck,
|
|
TbShieldCheck,
|
|
TbAccessPoint,
|
|
TbCircleCheck,
|
|
TbClock,
|
|
TbApps,
|
|
} from 'react-icons/tb'
|
|
import { DashboardLayout } from '@/frontend/components/DashboardLayout'
|
|
import { StatsCard } from '@/frontend/components/StatsCard'
|
|
|
|
export const Route = createFileRoute('/users')({
|
|
component: UsersPage,
|
|
})
|
|
|
|
const mockUsers = [
|
|
{ id: 1, name: 'Amel', email: 'amel@company.com', role: 'SUPER_ADMIN', apps: 'All', status: 'Online', lastActive: 'Now' },
|
|
{ id: 2, name: 'John Doe', email: 'john@company.com', role: 'DEVELOPER', apps: 'Desa+, Fitness App', status: 'Offline', lastActive: '2h ago' },
|
|
{ id: 3, name: 'Jane Smith', email: 'jane@company.com', role: 'QA', apps: 'E-Commerce', status: 'Online', lastActive: '12m ago' },
|
|
{ id: 4, name: 'Rahmat Hidayat', email: 'rahmat@company.com', role: 'DEVELOPER', apps: 'Desa+', status: 'Online', lastActive: 'Now' },
|
|
]
|
|
|
|
const roles = [
|
|
{
|
|
name: 'SUPER_ADMIN',
|
|
count: 2,
|
|
color: 'red',
|
|
permissions: ['Full Access', 'User Mgmt', 'Role Mgmt', 'App Config', 'Logs & Errors']
|
|
},
|
|
{
|
|
name: 'DEVELOPER',
|
|
count: 12,
|
|
color: 'brand-blue',
|
|
permissions: ['View All Apps', 'Manage Assigned App', 'View Logs', 'Resolve Errors', 'Village Setup']
|
|
},
|
|
{
|
|
name: 'QA',
|
|
count: 5,
|
|
color: 'orange',
|
|
permissions: ['View All Apps', 'View Logs', 'Report Errors', 'Test App Features']
|
|
},
|
|
]
|
|
|
|
function UsersPage() {
|
|
return (
|
|
<DashboardLayout>
|
|
<Container size="xl" py="lg">
|
|
<Stack gap="xl">
|
|
<Group justify="space-between" align="center">
|
|
<Stack gap={0}>
|
|
<Title order={2} className="gradient-text">Users</Title>
|
|
<Text size="sm" c="dimmed">Manage system users, security roles, and application access control.</Text>
|
|
</Stack>
|
|
</Group>
|
|
|
|
<SimpleGrid cols={{ base: 1, sm: 3 }} spacing="lg">
|
|
<StatsCard title="Total Staff" value={24} icon={TbUserCheck} color="brand-blue" />
|
|
<StatsCard title="Active Now" value={18} icon={TbAccessPoint} color="teal" />
|
|
<StatsCard title="Security Roles" value={3} icon={TbShieldCheck} color="purple-primary" />
|
|
</SimpleGrid>
|
|
|
|
<Tabs defaultValue="users" color="brand-blue" variant="pills" radius="md">
|
|
<Tabs.List>
|
|
<Tabs.Tab value="users" leftSection={<TbUserCheck size={16} />}>User Management</Tabs.Tab>
|
|
<Tabs.Tab value="roles" leftSection={<TbShieldCheck size={16} />}>Role Management</Tabs.Tab>
|
|
</Tabs.List>
|
|
|
|
<Tabs.Panel value="users" pt="xl">
|
|
<Stack gap="md">
|
|
<Group justify="space-between">
|
|
<TextInput
|
|
placeholder="Search users..."
|
|
leftSection={<TbSearch size={16} />}
|
|
radius="md"
|
|
w={350}
|
|
variant="filled"
|
|
/>
|
|
<Button
|
|
variant="gradient"
|
|
gradient={{ from: '#2563EB', to: '#7C3AED', deg: 135 }}
|
|
leftSection={<TbPlus size={18} />}
|
|
radius="md"
|
|
>
|
|
Add New User
|
|
</Button>
|
|
</Group>
|
|
|
|
<Paper withBorder radius="2xl" className="glass" p={0} style={{ overflow: 'hidden' }}>
|
|
<Table className="data-table" verticalSpacing="md" highlightOnHover>
|
|
<Table.Thead>
|
|
<Table.Tr>
|
|
<Table.Th>Name & Contact</Table.Th>
|
|
<Table.Th>Role</Table.Th>
|
|
<Table.Th>Status</Table.Th>
|
|
<Table.Th>App Access</Table.Th>
|
|
<Table.Th>Actions</Table.Th>
|
|
</Table.Tr>
|
|
</Table.Thead>
|
|
<Table.Tbody>
|
|
{mockUsers.map((user) => (
|
|
<Table.Tr key={user.id}>
|
|
<Table.Td>
|
|
<Group gap="sm">
|
|
<Avatar size="sm" radius="xl" color="brand-blue">{user.name.charAt(0)}</Avatar>
|
|
<Stack gap={0}>
|
|
<Text fw={600} size="sm">{user.name}</Text>
|
|
<Text size="xs" c="dimmed">{user.email}</Text>
|
|
</Stack>
|
|
</Group>
|
|
</Table.Td>
|
|
<Table.Td>
|
|
<Badge variant="light" color={user.role === 'SUPER_ADMIN' ? 'red' : user.role === 'DEVELOPER' ? 'brand-blue' : 'orange'}>
|
|
{user.role}
|
|
</Badge>
|
|
</Table.Td>
|
|
<Table.Td>
|
|
<Group gap={6}>
|
|
<Box style={{ width: 6, height: 6, borderRadius: '50%', background: user.status === 'Online' ? '#10b981' : '#94a3b8' }} />
|
|
<Text size="xs" fw={500}>{user.status}</Text>
|
|
<Text size="xs" c="dimmed" ml="xs"><TbClock size={10} style={{ marginBottom: -2 }} /> {user.lastActive}</Text>
|
|
</Group>
|
|
</Table.Td>
|
|
<Table.Td>
|
|
<Group gap={4}>
|
|
<TbApps size={12} color="gray" />
|
|
<Text size="xs" fw={500}>{user.apps}</Text>
|
|
</Group>
|
|
</Table.Td>
|
|
<Table.Td>
|
|
<Group gap="xs">
|
|
<ActionIcon variant="light" size="sm" color="blue">
|
|
<TbPencil size={14} />
|
|
</ActionIcon>
|
|
<ActionIcon variant="light" size="sm" color="red">
|
|
<TbTrash size={14} />
|
|
</ActionIcon>
|
|
</Group>
|
|
</Table.Td>
|
|
</Table.Tr>
|
|
))}
|
|
</Table.Tbody>
|
|
</Table>
|
|
</Paper>
|
|
</Stack>
|
|
</Tabs.Panel>
|
|
|
|
<Tabs.Panel value="roles" pt="xl">
|
|
<SimpleGrid cols={{ base: 1, md: 3 }} spacing="lg">
|
|
{roles.map((role) => (
|
|
<Card key={role.name} withBorder radius="2xl" padding="xl" className="glass">
|
|
<Stack gap="md">
|
|
<Group justify="space-between">
|
|
<ThemeIcon size="xl" radius="md" color={role.color} variant="light">
|
|
<TbShieldCheck size={28} />
|
|
</ThemeIcon>
|
|
<Badge variant="default" size="lg" radius="sm">{role.count} Users</Badge>
|
|
</Group>
|
|
|
|
<Stack gap={4}>
|
|
<Title order={4}>{role.name.replace('_', ' ')}</Title>
|
|
<Text size="sm" c="dimmed">Core role for secure app management.</Text>
|
|
</Stack>
|
|
|
|
<Divider />
|
|
|
|
<Text size="xs" fw={700} c="dimmed" style={{ textTransform: 'uppercase' }}>Key Permissions</Text>
|
|
<List
|
|
spacing="xs"
|
|
size="sm"
|
|
center
|
|
icon={
|
|
<ThemeIcon color="teal" size={16} radius="xl">
|
|
<TbCircleCheck size={12} />
|
|
</ThemeIcon>
|
|
}
|
|
>
|
|
{role.permissions.map((p) => (
|
|
<List.Item key={p}>{p}</List.Item>
|
|
))}
|
|
</List>
|
|
|
|
<Button fullWidth variant="light" color={role.color} mt="md" radius="md">
|
|
Edit Permissions
|
|
</Button>
|
|
</Stack>
|
|
</Card>
|
|
))}
|
|
</SimpleGrid>
|
|
</Tabs.Panel>
|
|
</Tabs>
|
|
</Stack>
|
|
</Container>
|
|
</DashboardLayout>
|
|
)
|
|
}
|
|
|