File "ReportTabContent.tsx"
Full Path: /home/trinadezambia/public_html/student_panel/src/components/ui/pages/dashboard/ReportTabContent.tsx
File size: 13.12 KB
MIME-type: text/x-java
Charset: utf-8
'use client';
import React from 'react';
import {
PieChart,
Pie,
Cell,
ResponsiveContainer,
RadialBarChart,
RadialBar,
PolarAngleAxis,
} from 'recharts';
import { useTranslate } from '@/components/hooks/useTranslate';
// Generic item interface for assignments or exams
interface ReportItem {
id: string;
title: string;
feedback: string;
obtainedPoints: number;
totalPoints: number;
}
// Status data interface
interface StatusData {
name: string;
value: number;
color: string;
}
// Props for the ReportTabContent component
interface ReportTabContentProps {
// Title for the left card (e.g., "Total Assignments" or "Total Exams")
cardTitle: string;
// Total count for display (e.g., "1")
totalCount: string;
// Status data for the circular chart (Pending and Submitted/Completed)
statusData: StatusData[];
// Label for the second status (e.g., "Submitted" or "Completed")
statusLabel: string;
// Note text at the bottom of left card
noteText: string;
// Total points
totalPoints: number;
// Total obtained points
totalObtained: number;
// Percentage
percentage: number;
// Section title for the list (e.g., "Assignments Points" or "Exams Points")
sectionTitle: string;
// List of items (assignments or exams)
items: ReportItem[];
// Attempted text
attemptedText: string;
}
/**
* ReportTabContent Component
*
* Reusable component for displaying report data in tabs
* Shows circular progress charts and a list of items with points
*/
export default function ReportTabContent({
cardTitle,
totalCount,
statusData,
statusLabel,
noteText,
totalPoints,
totalObtained,
percentage,
sectionTitle,
items,
attemptedText,
}: ReportTabContentProps) {
const translate = useTranslate();
return (
<div className="p-3 sm:p-4 md:p-6 space-y-4 sm:space-y-6">
{/* Top Cards Section */}
<div className="grid grid-cols-1 xl:grid-cols-2 gap-4 sm:gap-6">
{/* Left Card - Total Items */}
<div className="bg-gray-50 rounded-lg p-2 sm:p-3 border border-gray-200 ">
<h3 className="text-sm sm:text-base font-medium text-center text-gray-900 mb-4 sm:mb-6">
{cardTitle} - > {totalCount}
</h3>
{/* Full Circular Progress Chart with layered rings */}
<div className="bg-white rounded-lg p-2 sm:p-3 border border-gray-200">
<div className="relative h-[180px] sm:h-[210px] mb-4 sm:mb-6 flex items-center justify-center">
<div className="relative w-full h-full">
<ResponsiveContainer width="100%" height="100%">
<PieChart>
{/* Outer ring - Pending (Red) */}
<Pie
data={[
{ value: statusData[0].value },
{ value: statusData[1].value },
]}
cx="50%"
cy="50%"
startAngle={270}
endAngle={650}
innerRadius="80%"
outerRadius="90%"
paddingAngle={0}
dataKey="value"
stroke="none"
>
<Cell fill="#EF4444" />
<Cell fill="#E5E7EB" />
</Pie>
{/* Inner ring - Submitted/Completed (Green) */}
<Pie
data={[
{ value: statusData[1].value },
{ value: statusData[0].value },
]}
cx="50%"
cy="50%"
startAngle={270}
endAngle={650}
innerRadius="60%"
outerRadius="70%"
paddingAngle={0}
dataKey="value"
stroke="none"
>
<Cell fill="#84CC16" />
<Cell fill="#E5E7EB" />
</Pie>
</PieChart>
</ResponsiveContainer>
</div>
</div>
{/* Status Legend */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
{/* Pending - Red background with red left border */}
<div className="bg-red-50 rounded-lg p-2.5 sm:p-3 border-l-4 border-red-500 flex items-center justify-between">
<div className="">
<p className="text-sm sm:text-base font-medium text-red-500">
{attemptedText}
</p>
</div>
<div>
<p className="text-xl sm:text-2xl font-bold text-gray-900">
{statusData[0].value}
</p>
</div>
</div>
{/* Submitted/Completed - Light green background */}
<div className="bg-lime-50 rounded-lg p-2.5 sm:p-3 border-l-4 border-lime-500 flex items-center justify-between">
<div className="">
<p className="text-sm sm:text-base font-medium text-lime-600">
{statusLabel}
</p>
</div>
<div>
<p className="text-xl sm:text-2xl font-bold text-gray-900">
{statusData[1].value}
</p>
</div>
</div>
</div>
{/* Note */}
<p className="text-xs sm:text-sm font-normal text-gray-500 mt-3 sm:mt-4">
{noteText}
</p>
</div>
</div>
{/* Right Card - Total Points */}
<div className="bg-gray-50 rounded-lg p-2 sm:p-3 border border-gray-200">
<h3 className="text-sm sm:text-base font-medium text-center text-gray-900 mb-4 sm:mb-6">
{translate('totalPoints')} - > {totalPoints}
</h3>
{/* Circular Progress Charts */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4 lg:gap-6">
{/* Obtained Points Chart */}
<div className="text-center bg-white rounded-[12px] p-4 sm:p-6 border border-gray-200 flex flex-col items-center">
<h4 className="text-lg sm:text-xl font-bold text-gray-700 mb-2 sm:mb-3">
{translate('obtainedPoints')}
</h4>
<div className="w-[200px] sm:w-[250px] h-[200px] sm:h-[250px] relative">
{/* Thin background trail circle */}
<ResponsiveContainer width="100%" height="100%">
<RadialBarChart
cx="50%"
cy="50%"
innerRadius="65%"
outerRadius="95%"
barSize={5}
data={[{ value: 100, fill: '#D1FAE5' }]}
startAngle={90}
endAngle={-270}
>
<PolarAngleAxis
type="number"
domain={[0, 100]}
angleAxisId={0}
tick={false}
/>
<RadialBar
dataKey="value"
background={false}
isAnimationActive={false}
/>
</RadialBarChart>
</ResponsiveContainer>
{/* Thick progress bar on top */}
<div className="absolute inset-0">
<ResponsiveContainer width="100%" height="100%">
<RadialBarChart
cx="50%"
cy="50%"
innerRadius="60%"
outerRadius="100%"
barSize={12}
data={[
{
value: (totalObtained / totalPoints) * 100,
fill: '#14B8A6',
},
]}
startAngle={90}
endAngle={-270}
>
<PolarAngleAxis
type="number"
domain={[0, 100]}
angleAxisId={0}
tick={false}
/>
<RadialBar
dataKey="value"
cornerRadius={10}
background={false}
/>
</RadialBarChart>
</ResponsiveContainer>
</div>
{/* Center text */}
<div className="absolute inset-0 flex items-center justify-center">
<p className="text-3xl sm:text-4xl font-bold">
{totalObtained}
</p>
</div>
</div>
</div>
{/* Percentage Chart */}
<div className="text-center bg-white rounded-[12px] p-4 sm:p-6 border border-gray-200 flex flex-col items-center">
<h4 className="text-lg sm:text-xl font-bold text-gray-700 mb-2 sm:mb-3">
{translate('percentage')}
</h4>
<div className="w-[200px] sm:w-[250px] h-[200px] sm:h-[250px] relative">
{/* Thin background trail circle */}
<ResponsiveContainer width="100%" height="100%">
<RadialBarChart
cx="50%"
cy="50%"
innerRadius="65%"
outerRadius="95%"
barSize={5}
data={[{ value: 100, fill: '#FED7AA' }]}
startAngle={90}
endAngle={-270}
>
<PolarAngleAxis
type="number"
domain={[0, 100]}
angleAxisId={0}
tick={false}
/>
<RadialBar
dataKey="value"
background={false}
isAnimationActive={false}
/>
</RadialBarChart>
</ResponsiveContainer>
{/* Thick progress bar on top */}
<div className="absolute inset-0">
<ResponsiveContainer width="100%" height="100%">
<RadialBarChart
cx="50%"
cy="50%"
innerRadius="60%"
outerRadius="100%"
barSize={12}
data={[{ value: percentage, fill: '#EA580C' }]}
startAngle={90}
endAngle={-270}
>
<PolarAngleAxis
type="number"
domain={[0, 100]}
angleAxisId={0}
tick={false}
/>
<RadialBar
dataKey="value"
cornerRadius={10}
background={false}
/>
</RadialBarChart>
</ResponsiveContainer>
</div>
{/* Center text */}
<div className="absolute inset-0 flex items-center justify-center">
<p className="text-3xl sm:text-4xl font-bold text-gray-900">
{percentage.toFixed(2)}%
</p>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Items Points Section */}
<div className="bg-white rounded-lg border border-gray-200 overflow-hidden">
<div className="p-3 sm:p-4 border-b border-gray-200 bg-[var(--light-primary-color)]">
<h3 className="text-sm sm:text-base font-semibold text-gray-900">
{sectionTitle}
</h3>
</div>
{/* Items List */}
<div className="divide-y divide-gray-200">
{items.map((item) => (
<div
key={item.id}
className="p-3 sm:p-4 hover:bg-gray-50 transition-colors"
>
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3 sm:gap-0">
{/* Item Info */}
<div className="flex-1">
<h4 className="text-sm sm:text-base font-medium text-gray-900 mb-1">
{item.title}
</h4>
<p className="text-xs sm:text-sm text-gray-600">
{item.feedback}
</p>
</div>
{/* Points Badge */}
<div className="sm:ml-4 bg-gray-100 rounded-lg px-3 sm:px-4 py-2 text-center min-w-[100px] sm:min-w-[120px] self-start">
<p className="text-xs sm:text-sm">
{translate('points')} -{' '}
<span className="font-semibold text-gray-900">
{item.obtainedPoints}
</span>{' '}
/ {item.totalPoints}
</p>
</div>
</div>
</div>
))}
</div>
</div>
</div>
);
}