pushy

Signed-off-by: Kenneth Obsequio <k80308392@gmail.com>
This commit is contained in:
2026-06-28 11:30:01 +08:00
parent b03b204861
commit bac7168b1e
100 changed files with 5958 additions and 1976 deletions
@@ -1,19 +1,24 @@
import { useState, useEffect } from "react";
import { Badge } from "@/components/ui/badge";
import { Layers, CheckCheck, RefreshCw, SendHorizonal, Lock, Zap, Info } from "lucide-react";
import { Layers, CheckCheck, RefreshCw, SendHorizonal, Lock, Zap, Info, Tag } from "lucide-react";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import { Progress } from "@/components/ui/progress";
import ResponsiveModal from "@/components/generic/ResponsiveModal";
import { Button } from "@/components/ui/button";
import { useNavigate } from "react-router-dom";
import api from "@/utils/api.util";
import { useClientTiers } from "@/contexts/ClientTiersProvider";
import { resolveTierBadge } from "@/utils/tierBadge.util";
function TierBadge({ tier }) {
if (tier === 'premium')
return <Badge className="gap-1 bg-gradient-to-r from-fuchsia-600 to-purple-600 text-white border-0 w-fit shrink-0"><Lock className="size-3" /> Premium</Badge>;
if (tier === 'exclusive')
return <Badge className="gap-1 bg-gradient-to-r from-rose-500 to-red-600 text-white border-0 w-fit shrink-0"><Lock className="size-3" /> Exclusive</Badge>;
return null;
const { tierMap } = useClientTiers();
const { rank, label, cls } = resolveTierBadge(tier ?? 'free', tierMap);
return (
<Badge className={`gap-1 ${cls} w-fit shrink-0`}>
{rank > 0 ? <Lock className="size-3" /> : <Tag className="size-3" />}
{label}
</Badge>
);
}
const ReadUnit = ({ title = "Read Units", units = [], groupId, taskListId, taskId }) => {
@@ -172,10 +177,36 @@ const ReadUnit = ({ title = "Read Units", units = [], groupId, taskListId, taskI
<div className="flex items-center gap-1.5">
<Layers className="size-3.5 text-muted-foreground shrink-0" />
<span className="text-xs text-muted-foreground font-medium">Unit</span>
<div className="ml-auto">
{info?.course?.subscription
? <TierBadge tier={info.course.subscription} />
: isFetching && <Badge variant="secondary" className="opacity-40 text-xs">Loading…</Badge>
}
</div>
</div>
{info?.course?.title && (
<p className="text-xs text-muted-foreground truncate -mt-1">
from <span className="text-foreground/70 font-medium">{info.course.title}</span>
</p>
)}
<div>
<h1 className="text-base font-semibold leading-snug line-clamp-2 group-hover:text-blue-700 dark:group-hover:text-blue-400 transition-colors">
<h1
onClick={(e) => {
if (!taskId || !groupId || !taskListId) return;
e.stopPropagation();
navigate(
`/group/${groupId}/view/${taskListId}/task/${taskId}/requirement`,
{ state: { unit } }
);
}}
className={`text-base font-semibold leading-snug line-clamp-2 transition-colors ${
taskId
? 'text-blue-600 dark:text-blue-400 hover:underline cursor-pointer'
: 'group-hover:text-blue-700 dark:group-hover:text-blue-400'
}`}
>
{unit.title}
</h1>
<p className="text-sm text-muted-foreground leading-relaxed line-clamp-2 mt-1">