Files
caddy-proxy-manager/app/(dashboard)/OverviewClient.tsx
fuomag9 2096ebf1ed fix: replace Outlined icon variants with filled equivalents for visual consistency
Replace DeleteOutline→Delete, CheckCircleOutline→CheckCircle, ErrorOutline→Error,
RemoveCircleOutline→RemoveCircle, InfoOutlined→Info across all dashboard components.
Replace custom SVG bar chart in OverviewClient with BarChartIcon.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 15:25:19 +01:00

190 lines
6.3 KiB
TypeScript

"use client";
import Link from "next/link";
import Grid from "@mui/material/Grid";
import { Card, CardActionArea, CardContent, Paper, Stack, Typography, Box } from "@mui/material";
import BarChartIcon from "@mui/icons-material/BarChart";
import { ReactNode } from "react";
type StatCard = {
label: string;
icon: ReactNode;
count: number;
href: string;
};
type RecentEvent = {
summary: string;
created_at: string;
};
type TrafficSummary = {
totalRequests: number;
blockedPercent: number;
} | null;
export default function OverviewClient({
userName,
stats,
trafficSummary,
recentEvents
}: {
userName: string;
stats: StatCard[];
trafficSummary: TrafficSummary;
recentEvents: RecentEvent[];
}) {
return (
<Stack spacing={5}>
<Stack spacing={1.5}>
<Typography variant="overline" sx={{ color: "rgba(148, 163, 184, 0.6)", letterSpacing: 4 }}>
Control Center
</Typography>
<Typography
variant="h4"
sx={{
fontWeight: 700,
background: "linear-gradient(120deg, rgba(127, 91, 255, 1) 0%, rgba(34, 211, 238, 0.9) 80%)",
WebkitBackgroundClip: "text",
color: "transparent"
}}
>
Welcome back, {userName}
</Typography>
<Typography color="text.secondary" sx={{ maxWidth: 560 }}>
Everything you need to orchestrate Caddy proxies, certificates, and secure edge services lives here.
</Typography>
</Stack>
<Grid container spacing={3}>
{stats.map((stat) => (
<Grid key={stat.label} size={{ xs: 12, sm: 6, md: 4, lg: 3 }}>
<Card
elevation={0}
sx={{
height: "100%",
border: "1px solid rgba(148, 163, 184, 0.14)"
}}
>
<CardActionArea
component={Link}
href={stat.href}
sx={{
height: "100%",
p: 0,
"&:hover": {
background: "linear-gradient(135deg, rgba(127, 91, 255, 0.16), rgba(34, 211, 238, 0.08))"
}
}}
>
<CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
<Box
sx={{
color: "rgba(127, 91, 255, 0.8)",
display: "flex",
alignItems: "center"
}}
>
{stat.icon}
</Box>
<Typography variant="h4" sx={{ fontWeight: 700, letterSpacing: "-0.03em" }}>
{stat.count}
</Typography>
<Typography color="text.secondary" sx={{ fontWeight: 500 }}>
{stat.label}
</Typography>
</CardContent>
</CardActionArea>
</Card>
</Grid>
))}
{/* Traffic (24h) card */}
<Grid size={{ xs: 12, sm: 6, md: 4, lg: 3 }}>
<Card elevation={0} sx={{ height: "100%", border: "1px solid rgba(148, 163, 184, 0.14)" }}>
<CardActionArea
component={Link}
href="/analytics"
sx={{
height: "100%",
p: 0,
"&:hover": {
background: "linear-gradient(135deg, rgba(127, 91, 255, 0.16), rgba(34, 211, 238, 0.08))"
}
}}
>
<CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
<Box sx={{ color: "rgba(127, 91, 255, 0.8)", display: "flex", alignItems: "center" }}>
<BarChartIcon fontSize="large" />
</Box>
{trafficSummary ? (
<>
<Typography variant="h4" sx={{ fontWeight: 700, letterSpacing: "-0.03em" }}>
{trafficSummary.totalRequests.toLocaleString()}
</Typography>
<Typography color="text.secondary" sx={{ fontWeight: 500 }}>
Traffic (24h)
{trafficSummary.totalRequests > 0 && (
<Box component="span" sx={{ ml: 1, color: trafficSummary.blockedPercent > 0 ? "error.light" : "text.secondary", fontSize: "0.8em" }}>
· {trafficSummary.blockedPercent}% blocked
</Box>
)}
</Typography>
</>
) : (
<>
<Typography variant="h4" sx={{ fontWeight: 700, letterSpacing: "-0.03em" }}></Typography>
<Typography color="text.secondary" sx={{ fontWeight: 500 }}>Traffic (24h)</Typography>
</>
)}
</CardContent>
</CardActionArea>
</Card>
</Grid>
</Grid>
<Stack spacing={2}>
<Typography variant="h6" sx={{ fontWeight: 600, letterSpacing: -0.2 }}>
Recent Activity
</Typography>
{recentEvents.length === 0 ? (
<Paper
elevation={0}
sx={{
p: 4,
textAlign: "center",
color: "text.secondary",
background: "rgba(12, 18, 30, 0.7)"
}}
>
No activity recorded yet.
</Paper>
) : (
<Stack spacing={1.5}>
{recentEvents.map((event, index) => (
<Paper
key={`${event.created_at}-${index}`}
elevation={0}
sx={{
p: 3,
display: "flex",
justifyContent: "space-between",
alignItems: "center",
gap: 2,
background: "linear-gradient(120deg, rgba(17, 25, 40, 0.9), rgba(15, 23, 42, 0.7))",
border: "1px solid rgba(148, 163, 184, 0.08)"
}}
>
<Typography fontWeight={500}>{event.summary}</Typography>
<Typography variant="body2" color="text.secondary">
{new Date(event.created_at).toLocaleString()}
</Typography>
</Paper>
))}
</Stack>
)}
</Stack>
</Stack>
);
}