128
resources/js/Components/SecurityScoresOverviewBarChart.tsx
Normal file
128
resources/js/Components/SecurityScoresOverviewBarChart.tsx
Normal file
@ -0,0 +1,128 @@
|
||||
"use client"
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import { TrendingUp, TrendingDown } from "lucide-react";
|
||||
import { Bar, BarChart, CartesianGrid, LabelList, XAxis, YAxis } from "recharts";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/Components/ui/card";
|
||||
import {
|
||||
ChartConfig,
|
||||
ChartContainer,
|
||||
ChartTooltip,
|
||||
ChartTooltipContent,
|
||||
} from "@/Components/ui/chart";
|
||||
import { SecuritySummaryReportResultType } from "@/types/security-summary";
|
||||
|
||||
export default function SecurityScoresOverviewBarChart({ reportData }: { reportData: SecuritySummaryReportResultType }) {
|
||||
const chartData = useMemo(() => [
|
||||
{ metric: 'Services Exposure', score: reportData.servizi_esposti_score },
|
||||
{ metric: 'Data Leak', score: reportData.dataleak_score },
|
||||
{ metric: 'Email Leak', score: reportData.rapporto_leak_email_score },
|
||||
{ metric: 'Spoofing', score: reportData.spoofing_score },
|
||||
{ metric: 'Open Port', score: reportData.open_ports_score },
|
||||
{ metric: 'Blacklist', score: reportData.blacklist_score },
|
||||
{ metric: 'Certificate', score: reportData.certificate_score },
|
||||
{ metric: 'Active Vulnerability', score: reportData.vulnerability_score_active },
|
||||
{ metric: 'Passive Vulnerability', score: reportData.vulnerability_score_passive },
|
||||
|
||||
], [reportData]);
|
||||
|
||||
const chartConfig = {
|
||||
score: {
|
||||
label: "Score",
|
||||
color: "hsl(var(--chart-1))",
|
||||
},
|
||||
label: {
|
||||
color: "hsl(var(--background))",
|
||||
},
|
||||
} satisfies ChartConfig;
|
||||
|
||||
// Calculate average score and trend
|
||||
const averageScore = useMemo(() => {
|
||||
const sum = chartData.reduce((acc, curr) => acc + curr.score, 0);
|
||||
return Math.round(sum / chartData.length);
|
||||
}, [chartData]);
|
||||
|
||||
const isHighRisk = averageScore > 75;
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Security Scores Overview</CardTitle>
|
||||
<CardDescription>Security metrics analysis</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<ChartContainer config={chartConfig} className="max-h-[250px] w-full">
|
||||
<BarChart
|
||||
data={chartData}
|
||||
layout="vertical"
|
||||
margin={{
|
||||
right: 16,
|
||||
left: 16,
|
||||
top: 16,
|
||||
bottom: 16,
|
||||
}}
|
||||
height={250}
|
||||
>
|
||||
<CartesianGrid horizontal={false} />
|
||||
<YAxis
|
||||
dataKey="metric"
|
||||
type="category"
|
||||
tickLine={false}
|
||||
tickMargin={10}
|
||||
axisLine={false}
|
||||
width={100}
|
||||
/>
|
||||
<XAxis
|
||||
type="number"
|
||||
domain={[0, 100]}
|
||||
tickFormatter={(value) => `${value}%`}
|
||||
/>
|
||||
<ChartTooltip
|
||||
cursor={false}
|
||||
content={<ChartTooltipContent />}
|
||||
/>
|
||||
<Bar
|
||||
dataKey="score"
|
||||
fill="var(--color-score)"
|
||||
radius={4}
|
||||
>
|
||||
<LabelList
|
||||
dataKey="score"
|
||||
position="right"
|
||||
offset={8}
|
||||
className="fill-foreground"
|
||||
fontSize={12}
|
||||
formatter={(value: number) => `${value}%`}
|
||||
/>
|
||||
</Bar>
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
</CardContent>
|
||||
<CardFooter className="flex-col items-start gap-2 text-sm">
|
||||
<div className="flex gap-2 font-medium leading-none">
|
||||
{isHighRisk ? (
|
||||
<>
|
||||
High risk level detected
|
||||
<TrendingUp className="h-4 w-4 text-destructive" />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
Moderate risk level
|
||||
<TrendingDown className="h-4 w-4 text-success" />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="leading-none text-muted-foreground">
|
||||
Average security score: {averageScore}%
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user