Files
govoplan-views/webui/src/components/ViewSelector.tsx

71 lines
2.1 KiB
TypeScript

import { Eye, LockKeyhole } from "lucide-react";
import { useState } from "react";
import {
dispatchPlatformViewChanged,
useUnsavedChanges,
type ViewSelectorProps
} from "@govoplan/core-webui";
import { selectEffectiveView } from "../api/views";
export default function ViewSelector({
settings,
projection
}: ViewSelectorProps) {
const [busy, setBusy] = useState(false);
const [error, setError] = useState("");
const { requestNavigation } = useUnsavedChanges();
const options = projection?.availableViews ?? [];
if (!projection?.activeViewId && options.length === 0) return null;
async function performSelect(viewId: string) {
setBusy(true);
setError("");
try {
await selectEffectiveView(settings, viewId || null);
dispatchPlatformViewChanged();
} catch (caught) {
setError(caught instanceof Error ? caught.message : "View selection failed");
} finally {
setBusy(false);
}
}
function select(viewId: string) {
requestNavigation(() => {
void performSelect(viewId);
});
}
const locked = Boolean(projection?.locked);
const diagnostic = projection?.diagnostics.find((item) => item.severity === "error")
?? projection?.diagnostics[0];
const title = error || diagnostic?.message || (
locked
? "This View is required by an administrator."
: "Choose which parts of GovOPlaN are shown."
);
return (
<label className="titlebar-view-selector" title={title}>
{locked
? <LockKeyhole size={16} aria-hidden="true" />
: <Eye size={16} aria-hidden="true" />}
<span className="sr-only">Current View</span>
<select
value={projection?.activeViewId ?? ""}
disabled={busy || locked}
aria-label="Current View"
aria-invalid={Boolean(error) || undefined}
onChange={(event) => select(event.target.value)}
>
{!locked && <option value="">Full interface</option>}
{options.map((option) => (
<option key={option.id} value={option.id}>{option.name}</option>
))}
</select>
</label>
);
}