112 lines
4.4 KiB
TypeScript
112 lines
4.4 KiB
TypeScript
import {
|
|
Stack,
|
|
Title,
|
|
Text,
|
|
SimpleGrid,
|
|
Card,
|
|
Group,
|
|
Badge,
|
|
Button,
|
|
ThemeIcon,
|
|
Box,
|
|
Progress,
|
|
ActionIcon,
|
|
Tooltip
|
|
} from '@mantine/core'
|
|
import { createFileRoute } from '@tanstack/react-router'
|
|
import { TbPlus, TbPackage, TbAlertTriangle, TbTrendingUp, TbPencil, TbTrash, TbArchive } from 'react-icons/tb'
|
|
import { StatsCard } from '@/frontend/components/StatsCard'
|
|
|
|
export const Route = createFileRoute('/apps/$appId/products')({
|
|
component: ProductsPage,
|
|
})
|
|
|
|
const mockProducts = [
|
|
{ id: 1, name: 'Premium Wireless Headphones', price: 'Rp 2.450.000', stock: 12, sales: 145, status: 'IN_STOCK' },
|
|
{ id: 2, name: 'Mechanical Keyboard RGB', price: 'Rp 1.150.000', stock: 4, sales: 89, status: 'LOW_STOCK' },
|
|
{ id: 3, name: 'Ultra-wide Monitor 34"', price: 'Rp 8.900.000', stock: 2, sales: 34, status: 'LOW_STOCK' },
|
|
{ id: 4, name: 'Ergonomic Gaming Chair', price: 'Rp 3.200.000', stock: 0, sales: 56, status: 'OUT_OF_STOCK' },
|
|
{ id: 5, name: 'USB-C Hub Multiport', price: 'Rp 450.000', stock: 45, sales: 231, status: 'IN_STOCK' },
|
|
{ id: 6, name: 'Webcam 4K Ultra HD', price: 'Rp 1.750.000', stock: 18, sales: 67, status: 'IN_STOCK' },
|
|
]
|
|
|
|
function ProductsPage() {
|
|
return (
|
|
<Stack gap="xl">
|
|
<SimpleGrid cols={{ base: 1, sm: 3 }} spacing="lg">
|
|
<StatsCard title="Total Inventory" value="452 Units" icon={TbPackage} color="brand-blue" />
|
|
<StatsCard title="Low Stock Alerts" value="8 Items" icon={TbAlertTriangle} color="orange" />
|
|
<StatsCard title="Top Performing" value="3 items" icon={TbTrendingUp} color="teal" />
|
|
</SimpleGrid>
|
|
|
|
<Group justify="space-between" align="center">
|
|
<Stack gap={0}>
|
|
<Title order={3}>Product Catalog</Title>
|
|
<Text size="sm" c="dimmed">Inventory management and performance monitoring center.</Text>
|
|
</Stack>
|
|
<Button variant="gradient" gradient={{ from: '#2563EB', to: '#7C3AED' }} leftSection={<TbPlus size={18} />} radius="md">
|
|
Add New Product
|
|
</Button>
|
|
</Group>
|
|
|
|
<SimpleGrid cols={{ base: 1, sm: 2, md: 3 }} spacing="xl">
|
|
{mockProducts.map((product) => (
|
|
<Card key={product.id} withBorder radius="2xl" p="md" className="glass h-full">
|
|
<Card.Section>
|
|
<Box h={160} style={{ background: 'rgba(255,255,255,0.03)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
<ThemeIcon variant="light" size={60} radius="xl" color="brand-blue">
|
|
<TbArchive size={34} />
|
|
</ThemeIcon>
|
|
</Box>
|
|
</Card.Section>
|
|
|
|
<Stack gap="xs" mt="md">
|
|
<Group justify="space-between" wrap="nowrap">
|
|
<Text fw={600} size="sm" truncate>{product.name}</Text>
|
|
<Badge
|
|
size="xs"
|
|
color={product.status === 'IN_STOCK' ? 'teal' : product.status === 'LOW_STOCK' ? 'orange' : 'red'}
|
|
variant="light"
|
|
>
|
|
{product.status.replace('_', ' ')}
|
|
</Badge>
|
|
</Group>
|
|
|
|
<Group justify="space-between" mt={4}>
|
|
<Text fw={700} size="lg" color="brand-blue">{product.price}</Text>
|
|
<Text size="xs" c="dimmed">{product.sales} Sales</Text>
|
|
</Group>
|
|
|
|
<Box mt="xs">
|
|
<Group justify="space-between" mb={4}>
|
|
<Text size="xs" c="dimmed">Stock Level</Text>
|
|
<Text size="xs" fw={700}>{product.stock}/50</Text>
|
|
</Group>
|
|
<Progress
|
|
value={(product.stock / 50) * 100}
|
|
color={product.stock > 10 ? 'teal' : product.stock > 0 ? 'orange' : 'red'}
|
|
size="xs"
|
|
radius="xl"
|
|
/>
|
|
</Box>
|
|
|
|
<Group justify="flex-end" mt="md" pt="sm" style={{ borderTop: '1px solid rgba(255,255,255,0.05)' }}>
|
|
<Tooltip label="Edit Product">
|
|
<ActionIcon variant="light" size="sm" color="blue">
|
|
<TbPencil size={14} />
|
|
</ActionIcon>
|
|
</Tooltip>
|
|
<Tooltip label="Remove">
|
|
<ActionIcon variant="light" size="sm" color="red">
|
|
<TbTrash size={14} />
|
|
</ActionIcon>
|
|
</Tooltip>
|
|
</Group>
|
|
</Stack>
|
|
</Card>
|
|
))}
|
|
</SimpleGrid>
|
|
</Stack>
|
|
)
|
|
}
|