Bin
2025-12-17 1d710f844b65d9bfdf986a71a3b924cd70598a41
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
 * StateHistoryPopoverContent - Popover content for displaying state history as a timeline
 */
 
import { Button, Typography } from "@humansignal/ui";
import { IconSync, IconError, IconHistoryRewind, IconCross } from "@humansignal/icons";
import { useStateHistory, type StateHistoryItem } from "../../hooks/useStateHistory";
import { StateHistoryTimeline } from "./StateHistoryTimeline";
 
export interface StateHistoryPopoverContentProps {
  entityType: "task" | "annotation" | "project";
  entityId: number;
  isOpen: boolean;
  onClose?: () => void;
}
 
export function StateHistoryPopoverContent({ entityType, entityId, isOpen, onClose }: StateHistoryPopoverContentProps) {
  const { data, isLoading, isError, error, refetch } = useStateHistory({
    entityType,
    entityId,
    enabled: isOpen,
  });
 
  const history = (data?.results || []) as StateHistoryItem[];
 
  return (
    <div
      className="flex flex-col w-[360px] max-h-[400px] bg-neutral-background rounded-lg shadow-lg"
      onClick={(e) => e.stopPropagation()}
    >
      {/* Header */}
      <div className="px-4 py-3 border-b border-neutral-border">
        <div className="flex items-center justify-between">
          <div className="flex items-center gap-2">
            <IconHistoryRewind className="w-4 h-4" />
            <Typography variant="body" size="small" className="font-medium text-neutral-foreground">
              State History
            </Typography>
          </div>
          {onClose && (
            <Button
              onClick={(e) => {
                e.stopPropagation();
                onClose();
              }}
              leading={<IconCross />}
              look="string"
              size="small"
              aria-label="Close"
            />
          )}
        </div>
      </div>
 
      {/* Content */}
      <div className="flex-1 overflow-y-auto p-4">
        {isLoading && (
          <div className="flex flex-col items-center justify-center py-8 gap-3">
            <IconSync className="w-8 h-8 text-primary-icon animate-spin" />
            <Typography variant="body" size="small" className="text-neutral-content-subtle">
              Loading...
            </Typography>
          </div>
        )}
 
        {isError && (
          <div className="flex flex-col items-center justify-center py-8 gap-3">
            <IconError className="w-8 h-8 text-negative-icon" />
            <Typography variant="body" size="small" className="text-neutral-foreground">
              Failed to load history
            </Typography>
            <Typography variant="body" size="smallest" className="text-neutral-content-subtle text-center">
              {error instanceof Error ? error.message : "Unknown error"}
            </Typography>
            <Button
              onClick={(e) => {
                e.stopPropagation();
                refetch();
              }}
              className="mt-tight"
              size="smaller"
              variant="primary"
              type="button"
            >
              Retry
            </Button>
          </div>
        )}
 
        {!isLoading && !isError && history.length === 0 && (
          <div className="flex flex-col items-center justify-center py-8 gap-3">
            <IconHistoryRewind className="w-8 h-8 text-neutral-content-subtler" />
            <Typography variant="body" size="small" className="text-neutral-content-subtle">
              No history available
            </Typography>
          </div>
        )}
 
        {!isLoading && !isError && history.length > 0 && <StateHistoryTimeline history={history} />}
      </div>
    </div>
  );
}