amati/apps/frontend/src/routes/_dashboardLayout/assessmentResult/index.lazy.tsx
2024-11-06 08:23:27 +07:00

710 lines
29 KiB
TypeScript

import { SetStateAction, useEffect, useRef, useState } from "react";
import html2pdf from "html2pdf.js";
import useAuth from "@/hooks/useAuth";
import { createLazyFileRoute } from "@tanstack/react-router";
import { getAllAspectsAverageScore, getAllSubAspectsAverageScore, getAllVerifiedAspectsAverageScore, getAllVerifiedSubAspectsAverageScore } from "@/modules/assessmentResult/queries/assessmentResultQueries";
import { useQuery } from "@tanstack/react-query";
import { getAssessmentResultByIdQueryOptions, getVerifiedAssessmentResultByIdQueryOptions } from "@/modules/assessmentResultsManagement/queries/assessmentResultsManagaementQueries";
import { PieChart, Pie, Label, BarChart, Bar, CartesianGrid, XAxis, YAxis } from "recharts";
import { PolarAngleAxis, PolarRadiusAxis, PolarGrid, Radar, RadarChart } from "recharts"
import {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from "@/shadcn/components/ui/card"
import {
ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/shadcn/components/ui/chart"
import { aspectQueryOptions } from "@/modules/aspectManagement/queries/aspectQueries";
import { TbChevronDown, TbChevronLeft, TbChevronUp } from "react-icons/tb";
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/shadcn/components/ui/dropdown-menu";
const getQueryParam = (param: string) => {
const urlParams = new URLSearchParams(window.location.search);
return urlParams.get(param);
};
export const Route = createLazyFileRoute("/_dashboardLayout/assessmentResult/")({
component: AssessmentResultPage,
});
export default function AssessmentResultPage() {
const { user } = useAuth();
const isSuperAdmin = user?.role === "super-admin";
const [assessmentId, setAssessmentId] = useState<string | undefined>(undefined);
useEffect(() => {
const id = getQueryParam("id");
setAssessmentId(id ?? undefined);
}, []);
const { data: aspectsData } = useQuery(aspectQueryOptions(0, 10));
const { data: assessmentResult } = useQuery(getAssessmentResultByIdQueryOptions(assessmentId));
const { data: verifiedAssessmentResult } = useQuery(getVerifiedAssessmentResultByIdQueryOptions(assessmentId));
const { data: allAspectsScoreData } = useQuery(getAllAspectsAverageScore(assessmentId));
const { data: allSubAspectsScoreData } = useQuery(getAllSubAspectsAverageScore(assessmentId));
const { data: allVerifiedAspectsScoreData } = useQuery(getAllVerifiedAspectsAverageScore(assessmentId));
const { data: allVerifiedSubAspectsScoreData } = useQuery(getAllVerifiedSubAspectsAverageScore(assessmentId));
const getAspectScore = (aspectId: string) => {
return allAspectsScoreData?.aspects?.find((score) => score.aspectId === aspectId)?.averageScore || undefined;
};
const getSubAspectScore = (subAspectId: string) => {
return allSubAspectsScoreData?.subAspects?.find((score) => score.subAspectId === subAspectId)?.averageScore || undefined;
};
const getVerifiedAspectScore = (aspectId: string) => {
return allVerifiedAspectsScoreData?.aspects?.find((score) => score.aspectId === aspectId)?.averageScore || undefined;
};
const getVerifiedSubAspectScore = (subAspectId: string) => {
return allVerifiedSubAspectsScoreData?.subAspects?.find((score) => score.subAspectId === subAspectId)?.averageScore || undefined;
};
const formatScore = (score: string | number | undefined) => {
if (score === null || score === undefined) return '0';
const parsedScore = typeof score === 'number' ? score : parseFloat(score || "NaN");
return !isNaN(parsedScore) ? parsedScore.toFixed(2) : '0';
};
const totalScore = parseFloat(formatScore(assessmentResult?.assessmentsResult));
const totalVerifiedScore = parseFloat(formatScore(verifiedAssessmentResult?.verifiedAssessmentsResult));
const getScoreStyleClass = (score: number | undefined, isBg: boolean = false) => {
if (score === undefined || score === null) return { color: 'grey' };
let colorVar = '--levelOne-color';
let textColor = 'white';
if (score >= 1.50 && score < 2.50) {
colorVar = '--levelTwo-color';
} else if (score >= 2.50 && score < 3.50) {
colorVar = '--levelThree-color';
} else if (score >= 3.50 && score < 4.49) {
colorVar = '--levelFour-color';
} else if (score >= 4.50 && score <= 5) {
colorVar = '--levelFive-color';
}
return isBg
? { backgroundColor: `var(${colorVar})`, color: textColor }
: { color: `var(${colorVar})` };
};
const aspectsColors = [
"#DBED9B",
"#FF3F9F",
"#877BDF",
"#CFAF49",
"#5FD4E7",
];
const chartData = aspectsData?.data?.map((aspect, index) => ({
aspectName: aspect.name,
score: Number(formatScore(getAspectScore(aspect.id))),
fill: aspectsColors[index % aspectsColors.length],
})) || [];
const verifiedChartData = aspectsData?.data?.map((aspect, index) => ({
aspectName: aspect.name,
score: Number(formatScore(getVerifiedAspectScore(aspect.id))),
fill: aspectsColors[index % aspectsColors.length],
})) || [];
const barChartData = aspectsData?.data?.flatMap((aspect) =>
aspect.subAspects.map((subAspect) => ({
subAspectName: subAspect.name,
score: Number(formatScore(getSubAspectScore(subAspect.id))),
fill: "#005BFF",
aspectId: aspect.id,
aspectName: aspect.name
}))
) || [];
const verifiedBarChartData = aspectsData?.data?.flatMap((aspect) =>
aspect.subAspects.map((subAspect) => ({
subAspectName: subAspect.name,
score: Number(formatScore(getVerifiedSubAspectScore(subAspect.id))),
fill: "#005BFF",
aspectId: aspect.id,
aspectName: aspect.name
}))
) || [];
const sortedBarChartData = barChartData.sort((a, b) => (a.aspectId ?? '').localeCompare(b.aspectId ?? ''));
const sortedVerifiedBarChartData = verifiedBarChartData.sort((a, b) => (a.aspectId ?? '').localeCompare(b.aspectId ?? ''));
const chartConfig = aspectsData?.data?.reduce((config, aspect, index) => {
config[aspect.name.toLowerCase()] = {
label: aspect.name,
color: aspectsColors[index % aspectsColors.length],
};
return config;
}, {} as ChartConfig) || {};
const barChartConfig = aspectsData?.data?.reduce((config, aspect, index) => {
aspect.subAspects.forEach((subAspect) => {
config[subAspect.name.toLowerCase()] = {
label: subAspect.name,
color: aspectsColors[index % aspectsColors.length],
};
});
return config;
}, {} as ChartConfig) || {};
const customizedAxisTick = (props: any) => {
const { x, y, payload } = props;
return (
<g transform={`translate(${x},${y})`}>
<text
x={0}
y={0}
dy={3}
textAnchor="end"
fill="#666"
transform="rotate(-90)"
fontSize={10}
>
{payload.value}
</text>
</g>
);
};
const [isOpen, setIsOpen] = useState(false);
const [selectedItem, setSelectedItem] = useState('Hasil Sementara');
const handleDropdownToggle = () => {
setIsOpen((prev) => !prev);
};
const handleItemClick = () => {
setSelectedItem(prev =>
prev === 'Hasil Sementara' ? 'Hasil Terverifikasi' : 'Hasil Sementara'
);
setIsOpen(false); // Tutup dropdown setelah klik item
};
// Pie Chart Component
function PieChartComponent({ chartData, totalScore, chartConfig }: { chartData: { aspectName: string, score: number, fill: string }[], totalScore: number, chartConfig: ChartConfig }) {
return (
<div className="flex flex-row w-full border-none">
<div className="flex-1 pb-0 w-72">
<ChartContainer
config={chartConfig}
className="mx-auto aspect-square max-h-64"
>
<PieChart>
<ChartTooltip
cursor={false}
content={<ChartTooltipContent hideLabel />}
/>
<Pie
data={chartData}
dataKey="score"
nameKey="aspectName"
innerRadius={50}
strokeWidth={5}
label={({ cx, cy, midAngle, innerRadius, outerRadius, index }) => {
const radius = innerRadius + (outerRadius - innerRadius) * 0.5;
const x = cx + radius * Math.cos(-midAngle * (Math.PI / 180));
const y = cy + radius * Math.sin(-midAngle * (Math.PI / 180));
return (
<text
x={x}
y={y}
fill="black"
textAnchor="middle"
dominantBaseline="middle"
fontSize={14}
>
{chartData[index]?.score || ""}
</text>
);
}}
labelLine={false}
>
<Label
content={({ viewBox }) => {
if (viewBox && "cx" in viewBox && "cy" in viewBox) {
return (
<text
x={viewBox.cx}
y={viewBox.cy}
textAnchor="middle"
dominantBaseline="middle"
>
<tspan
x={viewBox.cx}
y={viewBox.cy}
className="fill-foreground text-3xl font-bold"
>
{totalScore.toLocaleString()}
</tspan>
</text>
);
}
}}
/>
</Pie>
</PieChart>
</ChartContainer>
</div>
{/* Legend */}
<div className="flex-col gap-2 text-sm justify-center items-start">
{chartData.map((entry, index) => (
<div key={index} className="flex items-center gap-2">
<span
className="w-4 h-4"
style={{ backgroundColor: entry.fill }}
/>
<span className="font-medium">{entry.aspectName}</span>
</div>
))}
</div>
</div>
);
}
function RadarChartComponent({ chartData, chartConfig }: { chartData: { aspectName: string, score: number }[], chartConfig: ChartConfig }) {
return (
<div className="flex-1 pb-0">
<ChartContainer
config={chartConfig}
className="mx-auto max-h-[250px]"
>
<RadarChart data={chartData}>
<ChartTooltip
cursor={false}
content={({ active, payload }) => {
if (active && payload && payload.length > 0) {
const { aspectName, score } = payload[0].payload;
return (
<div className="tooltip bg-white p-1 rounded-md">
<p>{`${aspectName} : ${score}`}</p>
</div>
);
}
return null;
}}
/>
<PolarAngleAxis dataKey="aspectName" tick={{ fontSize: 10 }} stroke="black" />
<PolarRadiusAxis angle={90} domain={[0, 5]} tick={{ fontSize: 10 }} tickCount={6} stroke="black" />
<PolarGrid radialLines={true} />
<Radar
dataKey="score"
fillOpacity={0}
stroke="#007BFF"
strokeWidth={2}
/>
</RadarChart>
</ChartContainer>
</div>
);
}
function BarChartComponent({ barChartData, barChartConfig }: { barChartData: { subAspectName: string, score: number, fill: string, aspectId: string, aspectName: string }[], barChartConfig: ChartConfig }) {
return (
<div className="w-full">
<ChartContainer config={barChartConfig}>
<BarChart accessibilityLayer data={barChartData} margin={{ bottom: 120 }}>
<CartesianGrid vertical={false} horizontal={true} />
<XAxis
dataKey="subAspectName"
tickLine={false}
tickMargin={0}
axisLine={false}
interval={0}
tick={customizedAxisTick}
/>
<YAxis domain={[0, 5]} tickCount={6} />
<ChartTooltip
cursor={false}
content={({ active, payload }) => {
if (active && payload && payload.length > 0) {
const { subAspectName, score } = payload[0].payload;
return (
<div className="tooltip bg-white p-1 rounded-md shadow-lg">
<p>{`${subAspectName} : ${score}`}</p>
</div>
);
}
return null;
}}
/>
<Bar dataKey="score" radius={2} fill="#007BFF" />
</BarChart>
</ChartContainer>
</div>
);
}
const cardRef = useRef<HTMLDivElement | null>(null); // Create a ref for your component
const handlePrintPDF = async () => {
const element = cardRef.current;
if (element) {
// Sembunyikan elemen yang tidak ingin dicetak
const buttonPrint = document.getElementById("button-print");
const noPrint = document.getElementById("no-print");
if (buttonPrint) buttonPrint.style.visibility = 'hidden'; // Menggunakan visibility untuk tetap menjaga ruang
if (noPrint) noPrint.style.visibility = 'hidden'; // Menggunakan visibility untuk tetap menjaga ruang
// Pastikan elemen memiliki lebar 100%
element.style.width = '100%'; // Mengatur lebar konten
const options = {
margin: [0.4, 0.5, 0.4, 0], // Margin kecil untuk mengurangi ruang kosong
image: { type: 'jpeg', quality: 0.98 },
html2canvas: {
scale: 2, // Mengatur scale agar kualitas tinggi
width: element.scrollWidth,
height: element.scrollHeight,
},
jsPDF: {
unit: 'in',
format: 'a4',
orientation: 'landscape',
}
};
try {
const pdfBlob: Blob = await html2pdf()
.set(options)
.from(element)
.toPdf()
.get('pdf')
.then((pdf: any) => {
pdf.setProperties({
title: 'Hasil_Asesemen_Level_Maturitas',
});
return pdf.output('blob'); // Menghasilkan PDF sebagai blob dengan title
});
// Buat URL dari Blob dan buka di tab baru untuk pratinjau
const pdfURL = URL.createObjectURL(pdfBlob);
window.open(pdfURL, '_blank'); // Pratinjau di tab baru tanpa unduh
} catch (err) {
console.error("Error generating PDF:", err);
} finally {
// Tampilkan kembali elemen yang disembunyikan
if (buttonPrint) buttonPrint.style.visibility = 'visible'; // Mengembalikan visibility
if (noPrint) noPrint.style.visibility = 'visible'; // Mengembalikan visibility
element.style.width = ""; // Reset lebar setelah selesai
}
}
};
return (
<Card ref={cardRef} className="flex flex-row w-full h-full border-none shadow-none">
<div className="flex flex-col w-fit h-fit border-none shadow-none -ml-1 -pr-2">
<p className="font-bold mt-2 ml-2">Tingkatan Level Maturitas</p>
<div className="flex flex-col mr-5 -ml-5 h-full">
{[
{ level: 5, colorVar: '--levelFive-color', title: 'Implementasi Optimal', details: ['Otomatisasi', 'Terintegrasi', 'Membudaya'], textColor: 'white' },
{ level: 4, colorVar: '--levelFour-color', title: 'Implementasi Terkelola', details: ['Terorganisir', 'Review Berkala', 'Berkelanjutan'], textColor: 'white' },
{ level: 3, colorVar: '--levelThree-color', title: 'Implementasi Terdefinisi', details: ['Terorganisir', 'Konsisten', 'Review Berkala'], textColor: 'white' },
{ level: 2, colorVar: '--levelTwo-color', title: 'Implementasi Berulang', details: ['Terorganisir', 'Tidak Konsisten', 'Berulang'], textColor: 'white' },
{ level: 1, colorVar: '--levelOne-color', title: 'Implementasi Awal', details: ['Tidak Terukur', 'Tidak Konsisten', 'Risiko Tinggi'], textColor: 'white' }
].map(({ level, colorVar, title, details, textColor }, index) => (
<div key={level} className={`flex flex-row h-full border-none ${index > 0 ? '-mt-10' : ''}`}>
<svg className="w-30 h-32 pb-5" style={{ color: `var(${colorVar})` }} fill="currentColor" viewBox="0 0 24 24">
<polygon points="12,4 19,10 19,24 12,19 5,24 5,10" />
<text x="12" y="16" textAnchor="middle" fill={textColor} fontSize="3" fontWeight="bold">
Level {level}
</text>
</svg>
<div className="flex flex-col items-start justify-center -ml-4">
<p className="text-xs font-bold whitespace-nowrap">{title}</p>
{details.map((detail) => (
<p key={detail} className="text-xs">{detail}</p>
))}
</div>
</div>
))}
</div>
</div>
<Card className="flex flex-col w-full h-fit border-none shadow-none -mt-6 -mr-5 p-4 bg-stone-50 overflow-hidden">
<div className="flex flex-col w-full h-fit mb-6 justify-center items-start">
{/* Konten Header */}
<div className="flex justify-between items-center w-full">
{isSuperAdmin ? (
<div className="flex flex-col">
<button
className="flex items-center text-sm text-blue-600 gap-2 mb-2" id="no-print"
onClick={() => window.close()}
>
<TbChevronLeft size={20} className="mr-1" />
Kembali
</button>
<p className="text-2xl font-bold">Detail Hasil Asesmen</p>
<p className="text-xs text-muted-foreground">Kelola dan Pantau Semua Permohonan Asesmen Dengan Mudah</p>
</div>
) : (
<div className="flex flex-col">
<p className="text-2xl font-bold">Cyber Security Maturity Level Dashboard</p>
<p className="text-xs text-muted-foreground">Kelola dan Pantau Semua Permohonan Asesmen Dengan Mudah</p>
</div>
)}
<div className="flex flex-row gap-2" id="button-print">
<button
onClick={handlePrintPDF}
className="bg-blue-600 text-white flex w-fit p-2 rounded-sm text-sm items-start justify-between outline-none ring-offset-0"
>
Cetak ke PDF
</button>
<div className="flex">
<DropdownMenu>
<DropdownMenuTrigger
className="bg-blue-600 text-white flex w-44 p-2 pl-4 rounded-sm text-sm items-start justify-between outline-none ring-offset-0"
onClick={handleDropdownToggle}
>
{selectedItem}
{isOpen ? (
<TbChevronUp size={20} className="justify-center items-center" />
) : (
<TbChevronDown size={20} className="justify-center items-center" />
)}
</DropdownMenuTrigger>
{isOpen && (
<DropdownMenuContent className="bg-white text-black flex w-44 rounded-sm text-sm items-start">
<DropdownMenuItem className="w-full" onClick={handleItemClick}>
{selectedItem === 'Hasil Sementara' ? 'Hasil Terverifikasi' : 'Hasil Sementara'}
</DropdownMenuItem>
</DropdownMenuContent>
)}
</DropdownMenu>
</div>
</div>
</div>
</div>
{isSuperAdmin &&
<Card className="flex flex-col w-full h-full mb-6 justify-center items-start">
<div className="flex flex-row border-b w-full p-4 gap-4 items-center">
<div className="flex w-16 h-16 rounded-full bg-slate-300">
</div>
<div className="flex flex-col">
<p className="text-lg font-bold">{assessmentResult?.respondentName}</p>
<p className="text-sm">{assessmentResult?.position}</p>
</div>
</div>
<div className="flex lg:flex-row flex-col text-xs h-full w-full justify-between p-4">
<div className="flex flex-col gap-4">
<div>
<p className="text-muted-foreground">Username</p>
<p>{assessmentResult?.username}</p>
</div>
<div>
<p className="text-muted-foreground">Email</p>
<p>{assessmentResult?.email}</p>
</div>
</div>
<div className="flex flex-col gap-4">
<div>
<p className="text-muted-foreground">Nama Perusahaan</p>
<p>{assessmentResult?.companyName}</p>
</div>
<div>
<p className="text-muted-foreground">Pengalaman Kerja</p>
<p>{assessmentResult?.workExperience}</p>
</div>
</div>
<div className="flex flex-col gap-4">
<div>
<p className="text-muted-foreground">No. HP</p>
<p>{assessmentResult?.phoneNumber}</p>
</div>
<div>
<p className="text-muted-foreground">Alamat</p>
<p>{assessmentResult?.address}</p>
</div>
</div>
<div className="flex flex-col gap-4">
<div>
<p className="text-muted-foreground">Tanggal Assessment</p>
<p>
{assessmentResult?.assessmentDate ? (
new Intl.DateTimeFormat("id-ID", {
year: "numeric",
month: "long",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
hour12: true,
})
.format(new Date(assessmentResult.assessmentDate))
.replace(/\./g, ':')
.replace('pukul ', '')
) : (
'N/A'
)}
</p>
</div>
<div>
<p className="text-muted-foreground">Status Verifikasi</p>
<p>{assessmentResult?.statusAssessment}</p>
</div>
</div>
</div>
</Card>
}
{/* Conditional rendering based on selectedItem */}
{selectedItem === 'Hasil Sementara' ? (
<>
{/* Score Table */}
<p className="text-lg font-bold">Tabel Level Maturitas</p>
<Card className="flex flex-col w-full h-fit my-2 mb-8 overflow-hidden text-center">
<div className="flex flex-row w-full">
{aspectsData?.data?.map((aspect) => (
<div key={aspect.id} className="flex-col bg-white w-full h-full border-t border-x">
<div className="flex flex-col font-bold items-center justify-center p-2 h-full w-full border-b" style={getScoreStyleClass(getAspectScore(aspect.id))}>
<p className="text-sm text-black">{aspect.name}</p>
<span className="text-2xl">{formatScore(getAspectScore(aspect.id))}</span>
</div>
{aspect.subAspects.map((subAspect) => (
<div key={subAspect.id} className="flex flex-col gap-2 p-2 h-full w-full">
<div className="flex flex-row gap-2 justify-between h-full w-full">
<p className="text-xs text-muted-foreground text-left">{subAspect.name}</p>
<span className="text-xs font-bold">{formatScore(getSubAspectScore(subAspect.id))}</span>
</div>
</div>
))}
</div>
))}
</div>
{/* Total score */}
<div className="flex flex-row w-full h-fit p-3 justify-center gap-2 font-bold text-3xl" style={getScoreStyleClass(Number(totalScore), true)}>
<p className="text-center">Level Maturitas:</p>
<span>{totalScore}</span>
</div>
</Card>
</>
) : (
<>
{/* Verified Result Table */}
<p className="text-lg font-bold">Tabel Level Maturitas Terverifikasi</p>
<Card className="flex flex-col w-full h-fit my-2 mb-8 overflow-hidden border-y text-center">
<div className="flex flex-row">
{aspectsData?.data?.map((aspect) => (
<div key={aspect.id} className="flex-col bg-white w-full h-full border-x border-t">
<div className="flex flex-col font-bold items-center justify-center p-2 h-full w-full border-b" style={getScoreStyleClass(getAspectScore(aspect.id))}>
<p className="text-sm text-black">{aspect.name}</p>
<span className="text-2xl">{formatScore(getVerifiedAspectScore(aspect.id))}</span>
</div>
{aspect.subAspects.map((subAspect) => (
<div key={subAspect.id} className="flex flex-col gap-2 p-2 h-full w-full">
<div className="flex flex-row gap-2 justify-between h-full w-full">
<p className="text-xs text-muted-foreground text-left">{subAspect.name}</p>
<span className="text-xs font-bold">{formatScore(getVerifiedSubAspectScore(subAspect.id))}</span>
</div>
</div>
))}
</div>
))}
</div>
{/* Total verified score */}
<div className="flex flex-row w-full h-fit p-3 justify-center gap-2 font-bold text-3xl" style={getScoreStyleClass(Number(totalScore), true)}>
<p className="text-center">Level Maturitas:</p>
<span>{totalVerifiedScore}</span>
</div>
</Card>
</>
)}
<Card className="flex flex-col lg:flex-row gap-8 border-none shadow-none w-full">
{/* Pie Chart */}
{selectedItem === 'Hasil Sementara' ? (
<Card className="flex flex-col w-full">
<CardHeader className="items-start pb-0">
<CardTitle className="text-lg">Diagram Lingkaran</CardTitle>
</CardHeader>
<CardContent>
<PieChartComponent
chartData={chartData}
totalScore={totalScore}
chartConfig={chartConfig}
/>
</CardContent>
</Card>
) : (
<Card className="flex flex-col w-full">
<CardHeader className="items-start pb-0">
<CardTitle className="text-lg">Diagram Lingkaran Terverifikasi</CardTitle>
</CardHeader>
<CardContent>
<PieChartComponent
chartData={verifiedChartData}
totalScore={totalVerifiedScore}
chartConfig={chartConfig}
/>
</CardContent>
</Card>
)}
{/* Radar Chart */}
{selectedItem === 'Hasil Sementara' ? (
<Card className="flex flex-col w-full">
<CardHeader className="items-start pb-0">
<CardTitle className="text-lg">Diagram Radar</CardTitle>
</CardHeader>
<CardContent>
<RadarChartComponent chartData={chartData} chartConfig={chartConfig} />
</CardContent>
</Card>
) : (
<Card className="flex flex-col w-full">
<CardHeader className="items-start pb-0">
<CardTitle className="text-lg">Diagram Radar Terverifikasi</CardTitle>
</CardHeader>
<CardContent>
<RadarChartComponent chartData={verifiedChartData} chartConfig={chartConfig} />
</CardContent>
</Card>
)}
</Card>
<Card className="flex w-full h-fit border mt-8">
{/* Bar Chart */}
{selectedItem === 'Hasil Sementara' ? (
<>
<Card className="w-full">
<CardHeader className="items-start">
<CardTitle className="text-lg">Diagram Batang</CardTitle>
</CardHeader>
<CardContent>
<BarChartComponent barChartData={sortedBarChartData} barChartConfig={barChartConfig} />
</CardContent>
</Card>
</>
) : (
<>
<Card className="w-full">
<CardHeader className="items-start">
<CardTitle className="text-lg">Diagram Batang Terverifikasi</CardTitle>
</CardHeader>
<CardContent>
<BarChartComponent barChartData={sortedVerifiedBarChartData} barChartConfig={barChartConfig} />
</CardContent>
</Card>
</>
)}
</Card>
</Card>
</Card>
);
}