Add optional filename field to export dialog with automatic .json extension handling. Extract resolveFilename() for testability. Add tests for includeHistory flag, bundleToJson, and filename resolution. Add export format compatibility note to CLAUDE.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
106 lines
3.0 KiB
TypeScript
106 lines
3.0 KiB
TypeScript
import { Check, ClipboardCopy, Download, X } from "lucide-react";
|
|
import { useCallback, useState } from "react";
|
|
import { Button } from "./ui/button.js";
|
|
import { Dialog } from "./ui/dialog.js";
|
|
import { Input } from "./ui/input.js";
|
|
|
|
interface ExportMethodDialogProps {
|
|
open: boolean;
|
|
onDownload: (includeHistory: boolean, filename: string) => void;
|
|
onCopyToClipboard: (includeHistory: boolean) => void;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export function ExportMethodDialog({
|
|
open,
|
|
onDownload,
|
|
onCopyToClipboard,
|
|
onClose,
|
|
}: Readonly<ExportMethodDialogProps>) {
|
|
const [includeHistory, setIncludeHistory] = useState(false);
|
|
const [filename, setFilename] = useState("");
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
const handleClose = useCallback(() => {
|
|
setIncludeHistory(false);
|
|
setFilename("");
|
|
setCopied(false);
|
|
onClose();
|
|
}, [onClose]);
|
|
|
|
return (
|
|
<Dialog open={open} onClose={handleClose} className="w-80">
|
|
<div className="mb-4 flex items-center justify-between">
|
|
<h2 className="font-semibold text-lg">Export Encounter</h2>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon-sm"
|
|
onClick={handleClose}
|
|
className="text-muted-foreground"
|
|
>
|
|
<X className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
<div className="mb-3">
|
|
<Input
|
|
type="text"
|
|
value={filename}
|
|
onChange={(e) => setFilename(e.target.value)}
|
|
placeholder="Filename (optional)"
|
|
/>
|
|
</div>
|
|
<label className="mb-4 flex items-center gap-2 text-sm">
|
|
<input
|
|
type="checkbox"
|
|
checked={includeHistory}
|
|
onChange={(e) => setIncludeHistory(e.target.checked)}
|
|
className="accent-accent"
|
|
/>
|
|
<span className="text-foreground">Include undo/redo history</span>
|
|
</label>
|
|
<div className="flex flex-col gap-2">
|
|
<button
|
|
type="button"
|
|
className="flex items-center gap-3 rounded-lg border border-border px-4 py-3 text-left text-foreground text-sm hover:bg-hover-neutral-bg"
|
|
onClick={() => {
|
|
onDownload(includeHistory, filename);
|
|
handleClose();
|
|
}}
|
|
>
|
|
<Download className="h-5 w-5 text-muted-foreground" />
|
|
<div>
|
|
<div className="font-medium">Download file</div>
|
|
<div className="text-muted-foreground text-xs">
|
|
Save as a JSON file
|
|
</div>
|
|
</div>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="flex items-center gap-3 rounded-lg border border-border px-4 py-3 text-left text-foreground text-sm hover:bg-hover-neutral-bg"
|
|
onClick={() => {
|
|
onCopyToClipboard(includeHistory);
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 2000);
|
|
}}
|
|
>
|
|
{copied ? (
|
|
<Check className="h-5 w-5 text-green-400" />
|
|
) : (
|
|
<ClipboardCopy className="h-5 w-5 text-muted-foreground" />
|
|
)}
|
|
<div>
|
|
<div className="font-medium">
|
|
{copied ? "Copied!" : "Copy to clipboard"}
|
|
</div>
|
|
<div className="text-muted-foreground text-xs">
|
|
Copy JSON to your clipboard
|
|
</div>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</Dialog>
|
|
);
|
|
}
|