1import React from "react";
2import { Usage } from "../types";
3
4interface UsageDetailModalProps {
5 usage: Usage;
6 durationMs: number | null;
7 onClose: () => void;
8}
9
10function UsageDetailModal({ usage, durationMs, onClose }: UsageDetailModalProps) {
11 // Format duration in human-readable format
12 const formatDuration = (ms: number): string => {
13 if (ms < 1000) return `${ms}ms`;
14 if (ms < 60000) return `${(ms / 1000).toFixed(2)}s`;
15 return `${(ms / 60000).toFixed(2)}m`;
16 };
17
18 // Format timestamp for display
19 const formatTimestamp = (isoString: string): string => {
20 const date = new Date(isoString);
21 return date.toLocaleString(undefined, {
22 year: "numeric",
23 month: "short",
24 day: "numeric",
25 hour: "2-digit",
26 minute: "2-digit",
27 second: "2-digit",
28 });
29 };
30
31 // Close on escape key
32 React.useEffect(() => {
33 const handleEscape = (e: KeyboardEvent) => {
34 if (e.key === "Escape") {
35 onClose();
36 }
37 };
38 document.addEventListener("keydown", handleEscape);
39 return () => document.removeEventListener("keydown", handleEscape);
40 }, [onClose]);
41
42 return (
43 <div
44 style={{
45 position: "fixed",
46 top: 0,
47 left: 0,
48 right: 0,
49 bottom: 0,
50 backgroundColor: "rgba(0, 0, 0, 0.5)",
51 display: "flex",
52 alignItems: "center",
53 justifyContent: "center",
54 zIndex: 10001,
55 padding: "16px",
56 }}
57 onClick={onClose}
58 >
59 <div
60 style={{
61 backgroundColor: "#ffffff",
62 borderRadius: "8px",
63 padding: "24px",
64 maxWidth: "500px",
65 width: "100%",
66 boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
67 }}
68 onClick={(e) => e.stopPropagation()}
69 >
70 <div
71 style={{
72 display: "flex",
73 justifyContent: "space-between",
74 alignItems: "center",
75 marginBottom: "20px",
76 }}
77 >
78 <h2 style={{ fontSize: "18px", fontWeight: "600", color: "#1f2937", margin: 0 }}>
79 Usage Details
80 </h2>
81 <button
82 onClick={onClose}
83 style={{
84 background: "none",
85 border: "none",
86 fontSize: "24px",
87 color: "#6b7280",
88 cursor: "pointer",
89 padding: "0",
90 width: "32px",
91 height: "32px",
92 display: "flex",
93 alignItems: "center",
94 justifyContent: "center",
95 borderRadius: "4px",
96 }}
97 onMouseEnter={(e) => {
98 e.currentTarget.style.backgroundColor = "#f3f4f6";
99 }}
100 onMouseLeave={(e) => {
101 e.currentTarget.style.backgroundColor = "transparent";
102 }}
103 aria-label="Close"
104 >
105 ×
106 </button>
107 </div>
108 <div
109 style={{
110 display: "grid",
111 gridTemplateColumns: "auto 1fr",
112 gap: "12px 20px",
113 fontSize: "14px",
114 }}
115 >
116 {usage.model && (
117 <>
118 <div style={{ color: "#6b7280", fontWeight: "500" }}>Model:</div>
119 <div style={{ color: "#1f2937" }}>{usage.model}</div>
120 </>
121 )}
122 <div style={{ color: "#6b7280", fontWeight: "500" }}>Input Tokens:</div>
123 <div style={{ color: "#1f2937" }}>{usage.input_tokens.toLocaleString()}</div>
124 {usage.cache_read_input_tokens > 0 && (
125 <>
126 <div style={{ color: "#6b7280", fontWeight: "500" }}>Cache Read:</div>
127 <div style={{ color: "#1f2937" }}>
128 {usage.cache_read_input_tokens.toLocaleString()}
129 </div>
130 </>
131 )}
132 {usage.cache_creation_input_tokens > 0 && (
133 <>
134 <div style={{ color: "#6b7280", fontWeight: "500" }}>Cache Write:</div>
135 <div style={{ color: "#1f2937" }}>
136 {usage.cache_creation_input_tokens.toLocaleString()}
137 </div>
138 </>
139 )}
140 <div style={{ color: "#6b7280", fontWeight: "500" }}>Output Tokens:</div>
141 <div style={{ color: "#1f2937" }}>{usage.output_tokens.toLocaleString()}</div>
142 {usage.cost_usd > 0 && (
143 <>
144 <div style={{ color: "#6b7280", fontWeight: "500" }}>Cost:</div>
145 <div style={{ color: "#1f2937" }}>${usage.cost_usd.toFixed(4)}</div>
146 </>
147 )}
148 {durationMs !== null && (
149 <>
150 <div style={{ color: "#6b7280", fontWeight: "500" }}>Duration:</div>
151 <div style={{ color: "#1f2937" }}>{formatDuration(durationMs)}</div>
152 </>
153 )}
154 {usage.end_time && (
155 <>
156 <div style={{ color: "#6b7280", fontWeight: "500" }}>Timestamp:</div>
157 <div style={{ color: "#1f2937" }}>{formatTimestamp(usage.end_time)}</div>
158 </>
159 )}
160 </div>
161 </div>
162 </div>
163 );
164}
165
166export default UsageDetailModal;