D360-Frontend/src/pages/ScoreCard.tsx
2026-01-15 14:25:07 +05:30

205 lines
8.6 KiB
TypeScript

import { useParams, useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { ArrowLeft, Download } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { dealers, getMonthlyProductScores } from "@/lib/mockData";
import { useToast } from "@/components/ui/use-toast";
import { useAuth } from "@/hooks/useAuth";
const ScoreCard = () => {
const { id } = useParams();
const navigate = useNavigate();
const { toast } = useToast();
const { user, userRole, loading } = useAuth();
const dealer = dealers.find((d) => d.id === id);
useEffect(() => {
if (!loading && !user) {
navigate('/login');
}
// Redirect bank customers away from scorecard
if (!loading && userRole === 'bank_customer') {
navigate(`/dealer/${id}`);
toast({
title: "Access Denied",
description: "Score card is not available for your role",
variant: "destructive",
});
}
}, [user, userRole, loading, navigate, id, toast]);
if (!dealer) {
return (
<div className="min-h-screen bg-background flex items-center justify-center">
<div className="text-center">
<h2 className="text-2xl font-bold mb-4">Dealer Not Found</h2>
<Button onClick={() => navigate("/")}>Back to Dashboard</Button>
</div>
</div>
);
}
const monthlyScores = getMonthlyProductScores(dealer.id);
const months = monthlyScores[0]?.months || [];
const handleDownload = () => {
toast({
title: "Download Started",
description: "Exporting score card as Excel...",
});
};
const getScoreColor = (score: number) => {
if (score >= 750) return "text-[#16A34A] bg-[#E8F5E9]";
if (score >= 500) return "text-[#F59E0B] bg-[#FEF3C7]";
return "text-[#EF4444] bg-[#FEE2E2]";
};
const getScoreColorText = (score: number) => {
if (score >= 750) return "text-[#16A34A]";
if (score >= 500) return "text-[#F59E0B]";
return "text-[#EF4444]";
};
const calculateProportionateScore = (productScore: number, overallScore: number) => {
// Adjust product score to be proportionate to overall credit score
const proportion = overallScore / 1000;
return Math.round(productScore * proportion);
};
if (loading) {
return (
<div className="min-h-screen bg-background flex items-center justify-center">
<div className="text-center">Loading...</div>
</div>
);
}
return (
<div className="min-h-screen bg-background font-poppins">
{/* Header */}
<header className="bg-[#E8F5E9] border-b border-border py-4 px-4 sm:px-8">
<div className="max-w-7xl mx-auto">
<div className="flex items-center justify-between">
<div className="flex items-center gap-4">
<Button variant="ghost" size="icon" onClick={() => navigate(`/dealer/${dealer.id}`)} className="rounded-full">
<ArrowLeft className="h-5 w-5" />
</Button>
<div>
<h1 className="text-xl sm:text-2xl font-bold text-foreground">Dealer Score Card</h1>
<p className="text-sm text-muted-foreground">Product-wise Performance Trends</p>
</div>
</div>
<Button variant="outline" onClick={handleDownload} className="h-9 px-3 sm:h-10 sm:px-4">
<Download className="h-4 w-4 sm:mr-2" />
<span className="hidden sm:inline">Download Excel</span>
</Button>
</div>
</div>
</header>
<main className="max-w-7xl mx-auto px-4 sm:px-8 py-4 sm:py-8 space-y-6">
{/* Card 1: Dealer Info Header */}
<Card className="p-4 sm:p-6">
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div>
<h2 className="text-xl sm:text-2xl font-bold text-foreground mb-1">{dealer.dealerName}</h2>
<div className="flex flex-wrap items-center gap-x-2 gap-y-1 text-xs sm:text-sm text-muted-foreground">
<span><strong>MFMS ID:</strong> {dealer.mfmsId}</span>
<span className="hidden sm:inline"></span>
<span><strong>Location:</strong> {dealer.city}, {dealer.state}</span>
</div>
</div>
<div className="text-left sm:text-right">
<p className="text-xs sm:text-sm text-muted-foreground mb-1">Overall Credit Score</p>
<p className={`text-3xl sm:text-4xl font-bold ${getScoreColorText(dealer.creditScore)}`}>
{dealer.creditScore}
</p>
</div>
</div>
</Card>
{/* Card 2: Table with Header */}
<Card className="p-4 sm:p-6">
<div className="mb-6">
<h3 className="text-lg sm:text-xl font-bold text-foreground mb-2">
Month-on-Month Product-wise Score Trends
</h3>
<p className="text-xs sm:text-sm text-muted-foreground">
Scores are calculated based on various performance metrics. Total weightage per product per month: 1000 points
</p>
</div>
<div className="overflow-x-auto">
<table className="w-full border-collapse">
<thead>
<tr className="bg-gray-50">
<th className="border border-gray-300 px-3 sm:px-6 py-3 sm:py-4 text-left font-semibold text-foreground text-xs sm:text-sm">
Product
</th>
{months.map((month: string, idx: number) => (
<th key={idx} className="border border-gray-300 px-3 sm:px-6 py-3 sm:py-4 text-center font-semibold text-foreground text-xs sm:text-sm">
{month}
</th>
))}
</tr>
</thead>
<tbody>
{monthlyScores.map((row: { product: string; m1: number; m2: number; m3: number; m4: number; m5: number }, idx: number) => (
<tr key={idx} className="hover:bg-gray-50 transition-colors">
<td className="border border-gray-300 px-3 sm:px-6 py-3 sm:py-4 text-xs sm:text-sm font-medium text-foreground">
{row.product}
</td>
{[row.m1, row.m2, row.m3, row.m4, row.m5].map((score, scoreIdx) => {
const cellScore = calculateProportionateScore(score, dealer.creditScore);
return (
<td key={scoreIdx} className="border border-gray-300 px-3 sm:px-6 py-3 sm:py-4 text-center">
<span className={`inline-block px-2 sm:px-3 py-1 rounded font-semibold text-[10px] sm:text-xs ${getScoreColor(cellScore)}`}>
{cellScore}
</span>
</td>
);
})}
</tr>
))}
</tbody>
</table>
</div>
</Card>
{/* Card 3: Legend */}
<Card className="p-4">
<div className="flex flex-wrap items-center gap-x-6 gap-y-3 text-xs sm:text-sm">
<div className="flex items-center gap-2">
<div className="w-3 h-3 sm:w-4 sm:h-4 bg-[#16A34A] rounded"></div>
<span className="text-foreground">Excellent (750-1000)</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 sm:w-4 sm:h-4 bg-[#F59E0B] rounded"></div>
<span className="text-foreground">Good (500-749)</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 sm:w-4 sm:h-4 bg-[#EF4444] rounded"></div>
<span className="text-foreground">Needs Attention (&lt;500)</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 sm:w-4 sm:h-4 bg-gray-300 rounded"></div>
<span className="text-foreground">No Data</span>
</div>
</div>
</Card>
{/* Card 4: Footer Note */}
<Card className="p-6">
<p className="text-sm text-muted-foreground">
<strong>Note:</strong> This score card provides a detailed view of product-wise performance trends over the last 6 months. Scores are calculated based on sales velocity, purchase consistency, stock management, and payment timeliness for each product category. Product scores are proportionally adjusted to reflect the dealer's overall credit score.
</p>
</Card>
</main>
</div>
);
};
export default ScoreCard;