esfiles / frontend /src /components /DocumentViewer.tsx
Besjon Cifliku
feat: simplify the workflow and search patterns
9f87ec0
import { useState, type ReactNode } from "react";
import { api, getErrorMessage } from "../api";
interface Props {
docId: string;
children: ReactNode;
}
export default function DocumentViewer({ docId, children }: Props) {
const [expanded, setExpanded] = useState(false);
const [fullText, setFullText] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
async function handleClick() {
if (expanded) {
setExpanded(false);
return;
}
if (fullText !== null) {
setExpanded(true);
return;
}
setLoading(true); setError("");
try {
const res = await api.getDocument(docId);
setFullText(res.text);
setExpanded(true);
} catch (err) {
setError(getErrorMessage(err));
} finally {
setLoading(false);
}
}
return (
<div>
<div onClick={handleClick}>
{children}
</div>
{loading && (
<div style={{ padding: "8px 12px", color: "var(--text-dim)", fontSize: "0.85rem" }}>
Loading document...
</div>
)}
{error && (
<div style={{ padding: "8px 12px", color: "var(--danger)", fontSize: "0.85rem" }}>
{error}
</div>
)}
{expanded && fullText !== null && (
<div style={{
background: "var(--bg-elevated, #0d1117)",
border: "1px solid var(--border)",
borderTop: "none",
borderRadius: "0 0 var(--radius) var(--radius)",
padding: "12px 16px",
marginTop: -4,
marginBottom: 8,
maxHeight: 400,
overflowY: "auto",
fontSize: "0.82rem",
lineHeight: 1.7,
whiteSpace: "pre-wrap",
wordBreak: "break-word",
color: "var(--text)",
}}>
<div style={{ display: "flex", justifyContent: "space-between", marginBottom: 8 }}>
<span style={{ fontWeight: 600 }}>{docId}</span>
<button
onClick={(e) => { e.stopPropagation(); setExpanded(false); }}
style={{
background: "none", border: "none", color: "var(--text-dim)",
cursor: "pointer", fontSize: "0.8rem",
}}>
Close
</button>
</div>
{fullText}
</div>
)}
</div>
);
}