|
| 1 | +"use client" |
| 2 | + |
| 3 | +import * as React from "react" |
| 4 | +import { Area, AreaChart, CartesianGrid, XAxis } from "recharts" |
| 5 | + |
| 6 | +import { |
| 7 | + Card, |
| 8 | + CardContent, |
| 9 | + CardDescription, |
| 10 | + CardHeader, |
| 11 | + CardTitle, |
| 12 | +} from "@/components/ui/card" |
| 13 | +import { |
| 14 | + ChartContainer, |
| 15 | + ChartLegend, |
| 16 | + ChartLegendContent, |
| 17 | + ChartTooltip, |
| 18 | + ChartTooltipContent, |
| 19 | + type ChartConfig, |
| 20 | +} from "@/components/ui/chart" |
| 21 | +import { |
| 22 | + Select, |
| 23 | + SelectContent, |
| 24 | + SelectItem, |
| 25 | + SelectTrigger, |
| 26 | + SelectValue, |
| 27 | +} from "@/components/ui/select" |
| 28 | + |
| 29 | +export const description = "Email activity chart showing threats detected and emails scanned" |
| 30 | + |
| 31 | +const chartData = [ |
| 32 | + { date: "2024-10-01", threatsDetected: 222, emailsScanned: 150 }, |
| 33 | + { date: "2024-10-02", threatsDetected: 97, emailsScanned: 180 }, |
| 34 | + { date: "2024-10-03", threatsDetected: 167, emailsScanned: 120 }, |
| 35 | + { date: "2024-10-04", threatsDetected: 242, emailsScanned: 260 }, |
| 36 | + { date: "2024-10-05", threatsDetected: 373, emailsScanned: 290 }, |
| 37 | + { date: "2024-10-06", threatsDetected: 301, emailsScanned: 340 }, |
| 38 | + { date: "2024-10-07", threatsDetected: 245, emailsScanned: 180 }, |
| 39 | + { date: "2024-10-08", threatsDetected: 409, emailsScanned: 320 }, |
| 40 | + { date: "2024-10-09", threatsDetected: 59, emailsScanned: 110 }, |
| 41 | + { date: "2024-10-10", threatsDetected: 261, emailsScanned: 190 }, |
| 42 | + { date: "2024-10-11", threatsDetected: 327, emailsScanned: 350 }, |
| 43 | + { date: "2024-10-12", threatsDetected: 292, emailsScanned: 210 }, |
| 44 | + { date: "2024-10-13", threatsDetected: 342, emailsScanned: 380 }, |
| 45 | + { date: "2024-10-14", threatsDetected: 137, emailsScanned: 220 }, |
| 46 | + { date: "2024-10-15", threatsDetected: 120, emailsScanned: 170 }, |
| 47 | + { date: "2024-10-16", threatsDetected: 138, emailsScanned: 190 }, |
| 48 | + { date: "2024-10-17", threatsDetected: 446, emailsScanned: 360 }, |
| 49 | + { date: "2024-10-18", threatsDetected: 364, emailsScanned: 410 }, |
| 50 | + { date: "2024-10-19", threatsDetected: 243, emailsScanned: 180 }, |
| 51 | + { date: "2024-10-20", threatsDetected: 89, emailsScanned: 150 }, |
| 52 | + { date: "2024-10-21", threatsDetected: 137, emailsScanned: 200 }, |
| 53 | + { date: "2024-10-22", threatsDetected: 224, emailsScanned: 170 }, |
| 54 | + { date: "2024-10-23", threatsDetected: 138, emailsScanned: 230 }, |
| 55 | + { date: "2024-10-24", threatsDetected: 387, emailsScanned: 290 }, |
| 56 | + { date: "2024-10-25", threatsDetected: 215, emailsScanned: 250 }, |
| 57 | + { date: "2024-10-26", threatsDetected: 75, emailsScanned: 130 }, |
| 58 | + { date: "2024-10-27", threatsDetected: 383, emailsScanned: 420 }, |
| 59 | + { date: "2024-10-28", threatsDetected: 122, emailsScanned: 180 }, |
| 60 | + { date: "2024-10-29", threatsDetected: 315, emailsScanned: 240 }, |
| 61 | + { date: "2024-10-30", threatsDetected: 454, emailsScanned: 380 }, |
| 62 | + { date: "2024-10-31", threatsDetected: 165, emailsScanned: 220 }, |
| 63 | + { date: "2024-11-01", threatsDetected: 293, emailsScanned: 310 }, |
| 64 | + { date: "2024-11-02", threatsDetected: 247, emailsScanned: 190 }, |
| 65 | + { date: "2024-11-03", threatsDetected: 385, emailsScanned: 420 }, |
| 66 | + { date: "2024-11-04", threatsDetected: 481, emailsScanned: 390 }, |
| 67 | + { date: "2024-11-05", threatsDetected: 498, emailsScanned: 520 }, |
| 68 | + { date: "2024-11-06", threatsDetected: 388, emailsScanned: 300 }, |
| 69 | + { date: "2024-11-07", threatsDetected: 149, emailsScanned: 210 }, |
| 70 | + { date: "2024-11-08", threatsDetected: 227, emailsScanned: 180 }, |
| 71 | + { date: "2024-11-09", threatsDetected: 293, emailsScanned: 330 }, |
| 72 | + { date: "2024-11-10", threatsDetected: 335, emailsScanned: 270 }, |
| 73 | + { date: "2024-11-11", threatsDetected: 197, emailsScanned: 240 }, |
| 74 | + { date: "2024-11-12", threatsDetected: 197, emailsScanned: 160 }, |
| 75 | + { date: "2024-11-13", threatsDetected: 448, emailsScanned: 490 }, |
| 76 | + { date: "2024-11-14", threatsDetected: 473, emailsScanned: 380 }, |
| 77 | + { date: "2024-11-15", threatsDetected: 338, emailsScanned: 400 }, |
| 78 | + { date: "2024-11-16", threatsDetected: 499, emailsScanned: 420 }, |
| 79 | + { date: "2024-11-17", threatsDetected: 315, emailsScanned: 350 }, |
| 80 | + { date: "2024-11-18", threatsDetected: 235, emailsScanned: 180 }, |
| 81 | + { date: "2024-11-19", threatsDetected: 177, emailsScanned: 230 }, |
| 82 | + { date: "2024-11-20", threatsDetected: 82, emailsScanned: 140 }, |
| 83 | + { date: "2024-11-21", threatsDetected: 81, emailsScanned: 120 }, |
| 84 | + { date: "2024-11-22", threatsDetected: 252, emailsScanned: 290 }, |
| 85 | + { date: "2024-11-23", threatsDetected: 294, emailsScanned: 220 }, |
| 86 | + { date: "2024-11-24", threatsDetected: 201, emailsScanned: 250 }, |
| 87 | + { date: "2024-11-25", threatsDetected: 213, emailsScanned: 170 }, |
| 88 | + { date: "2024-11-26", threatsDetected: 420, emailsScanned: 460 }, |
| 89 | + { date: "2024-11-27", threatsDetected: 233, emailsScanned: 190 }, |
| 90 | + { date: "2024-11-28", threatsDetected: 78, emailsScanned: 130 }, |
| 91 | + { date: "2024-11-29", threatsDetected: 340, emailsScanned: 280 }, |
| 92 | + { date: "2024-11-30", threatsDetected: 178, emailsScanned: 230 }, |
| 93 | + { date: "2024-12-01", threatsDetected: 178, emailsScanned: 200 }, |
| 94 | + { date: "2024-12-02", threatsDetected: 470, emailsScanned: 410 }, |
| 95 | + { date: "2024-12-03", threatsDetected: 103, emailsScanned: 160 }, |
| 96 | + { date: "2024-12-04", threatsDetected: 439, emailsScanned: 380 }, |
| 97 | + { date: "2024-12-05", threatsDetected: 88, emailsScanned: 140 }, |
| 98 | + { date: "2024-12-06", threatsDetected: 294, emailsScanned: 250 }, |
| 99 | + { date: "2024-12-07", threatsDetected: 323, emailsScanned: 370 }, |
| 100 | + { date: "2024-12-08", threatsDetected: 385, emailsScanned: 320 }, |
| 101 | + { date: "2024-12-09", threatsDetected: 438, emailsScanned: 480 }, |
| 102 | + { date: "2024-12-10", threatsDetected: 155, emailsScanned: 200 }, |
| 103 | + { date: "2024-12-11", threatsDetected: 92, emailsScanned: 150 }, |
| 104 | + { date: "2024-12-12", threatsDetected: 492, emailsScanned: 420 }, |
| 105 | + { date: "2024-12-13", threatsDetected: 81, emailsScanned: 130 }, |
| 106 | + { date: "2024-12-14", threatsDetected: 426, emailsScanned: 380 }, |
| 107 | + { date: "2024-12-15", threatsDetected: 307, emailsScanned: 350 }, |
| 108 | + { date: "2024-12-16", threatsDetected: 371, emailsScanned: 310 }, |
| 109 | + { date: "2024-12-17", threatsDetected: 475, emailsScanned: 520 }, |
| 110 | + { date: "2024-12-18", threatsDetected: 107, emailsScanned: 170 }, |
| 111 | + { date: "2024-12-19", threatsDetected: 341, emailsScanned: 290 }, |
| 112 | + { date: "2024-12-20", threatsDetected: 408, emailsScanned: 450 }, |
| 113 | + { date: "2024-12-21", threatsDetected: 169, emailsScanned: 210 }, |
| 114 | + { date: "2024-12-22", threatsDetected: 317, emailsScanned: 270 }, |
| 115 | + { date: "2024-12-23", threatsDetected: 480, emailsScanned: 530 }, |
| 116 | + { date: "2024-12-24", threatsDetected: 132, emailsScanned: 180 }, |
| 117 | +] |
| 118 | + |
| 119 | +const chartConfig = { |
| 120 | + emailActivity: { |
| 121 | + label: "Email Activity", |
| 122 | + }, |
| 123 | + threatsDetected: { |
| 124 | + label: "Threats Detected", |
| 125 | + color: "hsl(0 84% 60%)", |
| 126 | + }, |
| 127 | + emailsScanned: { |
| 128 | + label: "Emails Scanned", |
| 129 | + color: "hsl(217 91% 60%)", |
| 130 | + }, |
| 131 | +} satisfies ChartConfig |
| 132 | + |
| 133 | +export function ChartAreaInteractive() { |
| 134 | + const [timeRange, setTimeRange] = React.useState("90d") |
| 135 | + |
| 136 | + const filteredData = chartData.filter((item) => { |
| 137 | + const date = new Date(item.date) |
| 138 | + const referenceDate = new Date("2024-12-24") |
| 139 | + let daysToSubtract = 90 |
| 140 | + if (timeRange === "30d") { |
| 141 | + daysToSubtract = 30 |
| 142 | + } else if (timeRange === "7d") { |
| 143 | + daysToSubtract = 7 |
| 144 | + } |
| 145 | + const startDate = new Date(referenceDate) |
| 146 | + startDate.setDate(startDate.getDate() - daysToSubtract) |
| 147 | + return date >= startDate |
| 148 | + }) |
| 149 | + |
| 150 | + return ( |
| 151 | + <Card className="pt-0 border-border"> |
| 152 | + <CardHeader className="flex items-center gap-2 space-y-0 border-b border-border py-5 sm:flex-row"> |
| 153 | + <div className="grid flex-1 gap-1"> |
| 154 | + <CardTitle className="text-foreground">Email Activity</CardTitle> |
| 155 | + <CardDescription> |
| 156 | + Showing email traffic for the last 3 months |
| 157 | + </CardDescription> |
| 158 | + </div> |
| 159 | + <Select value={timeRange} onValueChange={setTimeRange}> |
| 160 | + <SelectTrigger |
| 161 | + className="hidden w-[160px] rounded-lg sm:ml-auto sm:flex" |
| 162 | + aria-label="Select a value" |
| 163 | + > |
| 164 | + <SelectValue placeholder="Last 3 months" /> |
| 165 | + </SelectTrigger> |
| 166 | + <SelectContent className="rounded-xl"> |
| 167 | + <SelectItem value="90d" className="rounded-lg"> |
| 168 | + Last 3 months |
| 169 | + </SelectItem> |
| 170 | + <SelectItem value="30d" className="rounded-lg"> |
| 171 | + Last 30 days |
| 172 | + </SelectItem> |
| 173 | + <SelectItem value="7d" className="rounded-lg"> |
| 174 | + Last 7 days |
| 175 | + </SelectItem> |
| 176 | + </SelectContent> |
| 177 | + </Select> |
| 178 | + </CardHeader> |
| 179 | + <CardContent className="px-2 pt-4 sm:px-6 sm:pt-6"> |
| 180 | + <ChartContainer |
| 181 | + config={chartConfig} |
| 182 | + className="aspect-auto h-[250px] w-full" |
| 183 | + > |
| 184 | + <AreaChart data={filteredData}> |
| 185 | + <defs> |
| 186 | + <linearGradient id="fillThreats" x1="0" y1="0" x2="0" y2="1"> |
| 187 | + <stop |
| 188 | + offset="5%" |
| 189 | + stopColor="var(--color-threatsDetected)" |
| 190 | + stopOpacity={0.8} |
| 191 | + /> |
| 192 | + <stop |
| 193 | + offset="95%" |
| 194 | + stopColor="var(--color-threatsDetected)" |
| 195 | + stopOpacity={0.1} |
| 196 | + /> |
| 197 | + </linearGradient> |
| 198 | + <linearGradient id="fillEmails" x1="0" y1="0" x2="0" y2="1"> |
| 199 | + <stop |
| 200 | + offset="5%" |
| 201 | + stopColor="var(--color-emailsScanned)" |
| 202 | + stopOpacity={0.8} |
| 203 | + /> |
| 204 | + <stop |
| 205 | + offset="95%" |
| 206 | + stopColor="var(--color-emailsScanned)" |
| 207 | + stopOpacity={0.1} |
| 208 | + /> |
| 209 | + </linearGradient> |
| 210 | + </defs> |
| 211 | + <CartesianGrid vertical={false} strokeOpacity={0.1} /> |
| 212 | + <XAxis |
| 213 | + dataKey="date" |
| 214 | + tickLine={false} |
| 215 | + axisLine={false} |
| 216 | + tickMargin={8} |
| 217 | + minTickGap={32} |
| 218 | + tickFormatter={(value) => { |
| 219 | + const date = new Date(value) |
| 220 | + return date.toLocaleDateString("en-US", { |
| 221 | + month: "short", |
| 222 | + day: "numeric", |
| 223 | + }) |
| 224 | + }} |
| 225 | + /> |
| 226 | + <ChartTooltip |
| 227 | + cursor={false} |
| 228 | + content={ |
| 229 | + <ChartTooltipContent |
| 230 | + labelFormatter={(value) => { |
| 231 | + return new Date(value).toLocaleDateString("en-US", { |
| 232 | + month: "short", |
| 233 | + day: "numeric", |
| 234 | + }) |
| 235 | + }} |
| 236 | + indicator="dot" |
| 237 | + /> |
| 238 | + } |
| 239 | + /> |
| 240 | + <Area |
| 241 | + dataKey="threatsDetected" |
| 242 | + type="natural" |
| 243 | + fill="url(#fillThreats)" |
| 244 | + stroke="var(--color-threatsDetected)" |
| 245 | + stackId="a" |
| 246 | + /> |
| 247 | + <Area |
| 248 | + dataKey="emailsScanned" |
| 249 | + type="natural" |
| 250 | + fill="url(#fillEmails)" |
| 251 | + stroke="var(--color-emailsScanned)" |
| 252 | + stackId="a" |
| 253 | + /> |
| 254 | + <ChartLegend content={<ChartLegendContent />} /> |
| 255 | + </AreaChart> |
| 256 | + </ChartContainer> |
| 257 | + </CardContent> |
| 258 | + </Card> |
| 259 | + ) |
| 260 | +} |
0 commit comments