Files
ACVE/components/courses/CourseProgressCard.tsx
2026-03-15 13:52:11 +00:00

98 lines
3.3 KiB
TypeScript

import Link from "next/link";
import { cn } from "@/lib/utils";
type CourseAction = {
label: string;
href?: string;
disabled?: boolean;
};
type CourseProgressCardProps = {
progressPercent: number;
completedLessons: number;
totalLessons: number;
instructor: string;
durationLabel: string;
stageLabel: string;
availabilityLabel: string;
primaryAction: CourseAction;
secondaryAction?: CourseAction;
helperText?: string;
};
function ActionButton({ action, secondary = false }: { action: CourseAction; secondary?: boolean }) {
const classes = cn(
"inline-flex w-full items-center justify-center rounded-xl px-4 py-3 text-sm font-semibold transition-colors",
secondary
? "border border-border bg-card text-foreground hover:bg-accent"
: "acve-button-primary hover:brightness-105",
action.disabled && "cursor-not-allowed opacity-55 hover:brightness-100",
);
if (!action.href || action.disabled) {
return (
<button className={classes} disabled type="button">
{action.label}
</button>
);
}
return (
<Link className={classes} href={action.href}>
{action.label}
</Link>
);
}
export default function CourseProgressCard({
progressPercent,
completedLessons,
totalLessons,
instructor,
durationLabel,
stageLabel,
availabilityLabel,
primaryAction,
secondaryAction,
helperText,
}: CourseProgressCardProps) {
return (
<aside className="acve-panel p-5 md:p-6">
<p className="text-xs font-semibold uppercase tracking-[0.14em] text-muted-foreground">Seguimiento</p>
<p className="mt-3 text-3xl font-semibold text-foreground">{progressPercent}%</p>
<p className="mt-1 text-sm text-muted-foreground">
{completedLessons}/{totalLessons} lecciones completadas
</p>
<div className="mt-3 h-2 w-full rounded-full bg-primary/15">
<div className="h-2 rounded-full bg-primary transition-all" style={{ width: `${Math.max(0, Math.min(100, progressPercent))}%` }} />
</div>
<dl className="mt-5 space-y-3 border-t border-border/70 pt-4 text-sm">
<div className="flex items-start justify-between gap-3">
<dt className="text-muted-foreground">Instructor</dt>
<dd className="text-right font-medium text-foreground">{instructor}</dd>
</div>
<div className="flex items-start justify-between gap-3">
<dt className="text-muted-foreground">Duración</dt>
<dd className="text-right font-medium text-foreground">{durationLabel}</dd>
</div>
<div className="flex items-start justify-between gap-3">
<dt className="text-muted-foreground">Etapa</dt>
<dd className="text-right font-medium text-foreground">{stageLabel}</dd>
</div>
<div className="flex items-start justify-between gap-3">
<dt className="text-muted-foreground">Disponibilidad</dt>
<dd className="text-right font-medium text-foreground">{availabilityLabel}</dd>
</div>
</dl>
<div className="mt-5 space-y-2">
<ActionButton action={primaryAction} />
{secondaryAction ? <ActionButton action={secondaryAction} secondary /> : null}
</div>
{helperText ? <p className="mt-3 text-xs leading-relaxed text-muted-foreground">{helperText}</p> : null}
</aside>
);
}