129 lines
6.0 KiB
TypeScript
129 lines
6.0 KiB
TypeScript
import { Card, CardContent, CardHeader, CardTitle } from "./ui/card";
|
|
import { Progress } from "./ui/progress";
|
|
import { Gift, Clock, Sparkles, Zap, Timer } from "lucide-react";
|
|
import { cn } from "../lib/utils";
|
|
import { Skeleton } from "./ui/skeleton";
|
|
|
|
export interface LootdropData {
|
|
rewardAmount: number;
|
|
currency: string;
|
|
createdAt: string;
|
|
expiresAt: string | null;
|
|
}
|
|
|
|
export interface LootdropState {
|
|
monitoredChannels: number;
|
|
hottestChannel: {
|
|
id: string;
|
|
messages: number;
|
|
progress: number;
|
|
cooldown: boolean;
|
|
} | null;
|
|
config: {
|
|
requiredMessages: number;
|
|
dropChance: number;
|
|
};
|
|
}
|
|
|
|
interface LootdropCardProps {
|
|
drop?: LootdropData | null;
|
|
state?: LootdropState;
|
|
isLoading?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
export function LootdropCard({ drop, state, isLoading, className }: LootdropCardProps) {
|
|
if (isLoading) {
|
|
return (
|
|
<Card className={cn("glass-card border-none bg-card/40", className)}>
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
<CardTitle className="text-sm font-medium">Lootdrop Status</CardTitle>
|
|
<Gift className="h-4 w-4 text-muted-foreground" />
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="space-y-3">
|
|
<Skeleton className="h-8 w-[120px]" />
|
|
<Skeleton className="h-4 w-[80px]" />
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|
|
|
|
const isActive = !!drop;
|
|
const progress = state?.hottestChannel?.progress || 0;
|
|
const isCooldown = state?.hottestChannel?.cooldown || false;
|
|
|
|
return (
|
|
<Card className={cn(
|
|
"glass-card border-none transition-all duration-500 overflow-hidden relative",
|
|
isActive ? "bg-primary/5 border-primary/20 hover-glow ring-1 ring-primary/20" : "bg-card/40",
|
|
className
|
|
)}>
|
|
{/* Ambient Background Effect */}
|
|
{isActive && (
|
|
<div className="absolute -right-4 -top-4 w-24 h-24 bg-primary/20 blur-3xl rounded-full pointer-events-none animate-pulse" />
|
|
)}
|
|
|
|
<CardHeader className="flex flex-row items-center justify-between pb-2 relative z-10">
|
|
<CardTitle className="text-sm font-medium flex items-center gap-2">
|
|
{isActive ? "Active Lootdrop" : "Lootdrop Potential"}
|
|
{isActive && (
|
|
<span className="relative flex h-2 w-2">
|
|
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
|
|
<span className="relative inline-flex rounded-full h-2 w-2 bg-primary"></span>
|
|
</span>
|
|
)}
|
|
</CardTitle>
|
|
<Gift className={cn("h-4 w-4 transition-colors", isActive ? "text-primary " : "text-muted-foreground")} />
|
|
</CardHeader>
|
|
<CardContent className="relative z-10">
|
|
{isActive ? (
|
|
<div className="space-y-3 animate-in fade-in slide-up">
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-2xl font-bold text-primary flex items-center gap-2">
|
|
<Sparkles className="w-5 h-5 text-yellow-500 fill-yellow-500 animate-pulse" />
|
|
{drop.rewardAmount.toLocaleString()} {drop.currency}
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
<Clock className="w-3 h-3" />
|
|
<span>Dropped {new Date(drop.createdAt).toLocaleTimeString()}</span>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-4">
|
|
{isCooldown ? (
|
|
<div className="flex flex-col items-center justify-center py-2 text-muted-foreground space-y-1">
|
|
<Timer className="w-6 h-6 text-yellow-500 opacity-80" />
|
|
<p className="text-sm font-medium text-yellow-500/80">Cooling Down...</p>
|
|
<p className="text-xs opacity-50">Channels are recovering.</p>
|
|
</div>
|
|
) : (
|
|
<div className="space-y-2">
|
|
<div className="flex items-center justify-between text-xs text-muted-foreground">
|
|
<div className="flex items-center gap-1.5">
|
|
<Zap className={cn("w-3 h-3", progress > 80 ? "text-yellow-500" : "text-muted-foreground")} />
|
|
<span>Next Drop Chance</span>
|
|
</div>
|
|
<span className="font-mono">{Math.round(progress)}%</span>
|
|
</div>
|
|
<Progress value={progress} className="h-1.5" indicatorClassName={cn(progress > 80 ? "bg-yellow-500" : "bg-primary")} />
|
|
{state?.hottestChannel ? (
|
|
<p className="text-[10px] text-muted-foreground text-right opacity-70">
|
|
{state.hottestChannel.messages} / {state.config.requiredMessages} msgs
|
|
</p>
|
|
) : (
|
|
<p className="text-[10px] text-muted-foreground text-center opacity-50 pt-1">
|
|
No recent activity
|
|
</p>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|