82 lines
1.8 KiB
TypeScript
82 lines
1.8 KiB
TypeScript
import { cn } from "@/lib/utils";
|
|
import { Check, Minus, X, Circle } from "lucide-react";
|
|
|
|
type ProblemStatus = "solved" | "partial" | "attempted" | "not_attempted";
|
|
|
|
interface ProblemStatusBadgeProps {
|
|
status: ProblemStatus;
|
|
score?: number;
|
|
maxScore?: number;
|
|
className?: string;
|
|
}
|
|
|
|
const statusConfig: Record<
|
|
ProblemStatus,
|
|
{
|
|
icon: typeof Check;
|
|
className: string;
|
|
bgClassName: string;
|
|
}
|
|
> = {
|
|
solved: {
|
|
icon: Check,
|
|
className: "text-success",
|
|
bgClassName: "bg-success/10",
|
|
},
|
|
partial: {
|
|
icon: Minus,
|
|
className: "text-warning",
|
|
bgClassName: "bg-warning/10",
|
|
},
|
|
attempted: {
|
|
icon: X,
|
|
className: "text-destructive",
|
|
bgClassName: "bg-destructive/10",
|
|
},
|
|
not_attempted: {
|
|
icon: Circle,
|
|
className: "text-muted-foreground",
|
|
bgClassName: "bg-muted",
|
|
},
|
|
};
|
|
|
|
export function ProblemStatusBadge({
|
|
status,
|
|
score,
|
|
maxScore,
|
|
className,
|
|
}: ProblemStatusBadgeProps) {
|
|
const config = statusConfig[status];
|
|
const Icon = config.icon;
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"inline-flex items-center justify-center gap-1 rounded-full px-2 py-1 text-xs font-medium",
|
|
config.bgClassName,
|
|
config.className,
|
|
className
|
|
)}
|
|
>
|
|
<Icon className="h-3 w-3" />
|
|
{score !== undefined && maxScore !== undefined && status !== "not_attempted" && (
|
|
<span>
|
|
{score}/{maxScore}
|
|
</span>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Helper to determine status from score
|
|
export function getProblemStatus(
|
|
score: number | undefined,
|
|
maxScore: number,
|
|
hasAttempted: boolean
|
|
): ProblemStatus {
|
|
if (score === undefined || !hasAttempted) return "not_attempted";
|
|
if (score === maxScore) return "solved";
|
|
if (score > 0) return "partial";
|
|
return "attempted";
|
|
}
|