Files
monitoring-app/src/frontend/routes/apps.$appId.products.tsx
2026-04-02 10:30:21 +08:00

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>
)
}