/* global React, PR */
const { useState, useMemo, useRef, useEffect } = React;
const { I, Avatar, StagePill } = PR;
// ============ Sidebar ============
function Sidebar({ active, setActive, theme, setTheme, data, user, onLogout }) {
const counts = useMemo(() => {
const c = { all: 0, active: 0, decision: 0, scale: 0, archive: 0 };
data.hypotheses.forEach(h => {
c.all++;
if (h.decision === "kill") c.archive++;
else if (h.decision === "scale") c.scale++;
else c.active++;
if (h.stage === "decision" && !h.decision) c.decision++;
});
return c;
}, [data]);
const NavItem = ({ id, icon, label, count }) => (
setActive(id)}>
{icon}
{label}
{count != null &&
{count}}
);
const userAuthor = user ? { name: user.full_name || user.username, color: user.color || "#7C8BA1" } : null;
return (
);
}
// ============ Topbar ============
function Topbar({ crumbs, onNew }) {
return (
{crumbs.map((c, i) => (
{i > 0 && /}
{c}
))}
{I.search}
Search hypotheses
⌘K
);
}
// ============ Filter chip with dropdown ============
function FilterChip({ label, value, options, onChange }) {
const [open, setOpen] = useState(false);
const ref = useRef(null);
useEffect(() => {
if (!open) return;
const handler = (e) => {
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
};
document.addEventListener("mousedown", handler);
return () => document.removeEventListener("mousedown", handler);
}, [open]);
const selected = options.find(o => o.value === value);
const isActive = !!value;
return (
setOpen(o => !o)}
>
{label}: {selected ? selected.label : "any"}
{isActive && (
{ e.stopPropagation(); onChange(""); setOpen(false); }}
style={{ marginLeft: 4, opacity: 0.65, cursor: "pointer" }}
>×
)}
{open && (
{ onChange(""); setOpen(false); }}
>
Any
{options.map(o => (
{ onChange(o.value); setOpen(false); }}
>
{o.label}
))}
)}
);
}
// ============ Page header with view switch ============
function PageHead({ title, sub, view, setView, filters, setFilters, filterOptions, currentUserId }) {
const set = (k, v) => setFilters(f => ({ ...f, [k]: v }));
return (
<>
{view !== undefined && (
)}
{filters && filterOptions && (
set("set", "all")}>All
set("set", "active")}>Active
{currentUserId && (
set("set", "mine")}>Mine
)}
set("stage", v)} />
set("genre", v)} />
set("author", v)} />
set("risk", v)} />
)}
>
);
}
window.PRShell = { Sidebar, Topbar, PageHead };