Zion Boggan
repos/Drophawk/frontend/components/watchlist/WatchlistItem.tsx
zionboggan.com ↗
73 lines · tsx
History for this file →
1
"use client";
2
 
3
import { Trash2 } from "lucide-react";
4
import { motion } from "framer-motion";
5
import { Switch } from "@/components/ui/switch";
6
import { Button } from "@/components/ui/button";
7
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
8
import { usePatchWatch, useDeleteWatch } from "@/hooks/useWatchlist";
9
import { fadeUpItem } from "@/lib/motion";
10
import { cn } from "@/lib/utils";
11
import type { Priority, WatchlistRule } from "@/lib/types";
12
 
13
const PRIORITY_COLOR: Record<Priority, string> = {
14
  low: "var(--color-fg-tertiary)",
15
  normal: "var(--color-accent-blue)",
16
  high: "var(--color-accent-amber)",
17
  critical: "var(--color-accent-red)",
18
};
19
 
20
export function WatchlistItem({ rule }: { rule: WatchlistRule }) {
21
  const patch = usePatchWatch();
22
  const del = useDeleteWatch();
23
  const c = PRIORITY_COLOR[rule.priority];
24
 
25
  return (
26
    <motion.li
27
      variants={fadeUpItem}
28
      layout
29
      className={cn(
30
        "flex items-center gap-3 rounded-[var(--radius)] border border-[var(--color-border-subtle)] bg-[var(--color-bg-elevated)] p-3",
31
        !rule.active && "opacity-60",
32
      )}
33
    >
34
      <div className="min-w-0 flex-1">
35
        <div className="flex items-center gap-2">
36
          <span className="truncate text-sm font-medium text-[var(--color-fg-primary)]">{rule.label}</span>
37
          <span
38
            className="rounded-full px-1.5 py-0.5 text-[10px] font-medium capitalize"
39
            style={{ color: c, backgroundColor: `color-mix(in oklch, ${c} 14%, transparent)` }}
40
          >
41
            {rule.priority}
42
          </span>
43
        </div>
44
        <p className="mt-0.5 text-xs text-[var(--color-fg-tertiary)]">
45
          <span className="capitalize">{rule.kind}</span> · {rule.matches_30d} matches in 30d
46
        </p>
47
      </div>
48
 
49
      <Tooltip>
50
        <TooltipTrigger asChild>
51
          <span>
52
            <Switch
53
              checked={rule.active}
54
              onCheckedChange={(active) => patch.mutate({ id: rule.id, active })}
55
              aria-label={rule.active ? "Pause alerts" : "Resume alerts"}
56
            />
57
          </span>
58
        </TooltipTrigger>
59
        <TooltipContent>{rule.active ? "Alerts on" : "Paused"}</TooltipContent>
60
      </Tooltip>
61
 
62
      <Button
63
        variant="ghost"
64
        size="icon"
65
        aria-label={`Remove ${rule.label}`}
66
        onClick={() => del.mutate(rule.id)}
67
        className="text-[var(--color-fg-tertiary)] hover:text-[var(--color-accent-red)]"
68
      >
69
        <Trash2 className="h-4 w-4" aria-hidden />
70
      </Button>
71
    </motion.li>
72
  );
73
}