98 lines
3.3 KiB
TypeScript
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>
|
|
);
|
|
}
|