import "./dist-CYoGQ6PD.mjs";
import "./document-drive-BKF7N19I.mjs";
import "./chunk-VBDAOXYI-Dd3pepio.mjs";
import { b as driveCollectionId, c as useDocumentsInSelectedDrive, g as useSelectedDriveId, h as useSelectedDrive, i as setSelectedNode, r as getSwitchboardGatewayUrlFromDriveUrl, t as addDocument, v as useSetPHAppConfig, y as useSyncList } from "./dist-LFSG_0Q3.mjs";
import { t as DocumentBrowser } from "./DocumentBrowser-BXa-p16u.mjs";
import "./load-design-tokens-B8bpWdLf.mjs";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
//#region editors/funder-back-office/components/dashboard/constants.ts
const DOC_TYPE = {
	grantSystem: "rfp-hub/grant-system",
	grantPool: "rfp-hub/grant-pool",
	grantApplication: "rfp-hub/grant-application",
	governance: "rfp-hub/governance"
};
const POOL_LIFECYCLE_CLASS = {
	DRAFT: "rfp-status-draft",
	REQUEST_FOR_COMMENTS: "rfp-status-rfc",
	UPCOMING: "rfp-status-upcoming",
	OPEN: "rfp-status-open",
	CLOSED: "rfp-status-closed",
	AWARDED: "rfp-status-awarded",
	NOT_AWARDED: "rfp-status-rejected",
	CANCELLED: "rfp-status-cancelled"
};
const REVIEW_STAGE_CLASS = {
	DRAFT: "rfp-status-draft",
	SUBMITTED: "rfp-status-pending",
	OPENED: "rfp-status-pending",
	UNDER_REVIEW: "rfp-status-review",
	NEEDS_REVISION: "rfp-status-pending",
	REVISED: "rfp-status-review",
	APPROVED: "rfp-status-approved",
	CONDITIONALLY_APPROVED: "rfp-status-approved",
	REJECTED: "rfp-status-rejected",
	WITHDRAWN: "rfp-status-closed",
	FUNDED: "rfp-status-funded",
	COMPLETED: "rfp-status-completed"
};
const KANBAN_COLUMNS = [
	{
		key: "incoming",
		label: "Incoming",
		stages: ["SUBMITTED", "OPENED"]
	},
	{
		key: "inReview",
		label: "In review",
		stages: ["UNDER_REVIEW", "REVISED"]
	},
	{
		key: "needsRevision",
		label: "Needs revision",
		stages: ["NEEDS_REVISION"]
	},
	{
		key: "decided",
		label: "Decided",
		stages: [
			"APPROVED",
			"CONDITIONALLY_APPROVED",
			"REJECTED",
			"WITHDRAWN"
		]
	},
	{
		key: "active",
		label: "Active / Completed",
		stages: ["FUNDED", "COMPLETED"]
	}
];
function formatRelativeTime(iso) {
	if (!iso) return "—";
	const date = new Date(iso);
	const ms = Date.now() - date.getTime();
	if (Number.isNaN(ms)) return "—";
	const seconds = Math.floor(ms / 1e3);
	if (seconds < 60) return "just now";
	const minutes = Math.floor(seconds / 60);
	if (minutes < 60) return `${minutes}m ago`;
	const hours = Math.floor(minutes / 60);
	if (hours < 24) return `${hours}h ago`;
	const days = Math.floor(hours / 24);
	if (days < 30) return `${days}d ago`;
	return date.toLocaleDateString();
}
function daysSince(iso) {
	if (!iso) return null;
	const ms = Date.now() - new Date(iso).getTime();
	if (Number.isNaN(ms)) return null;
	return Math.max(0, Math.floor(ms / (1e3 * 60 * 60 * 24)));
}
function daysUntil(iso) {
	if (!iso) return null;
	const ms = new Date(iso).getTime() - Date.now();
	if (Number.isNaN(ms)) return null;
	return Math.floor(ms / (1e3 * 60 * 60 * 24));
}
//#endregion
//#region editors/funder-back-office/components/dashboard/StatsRow.tsx
function sumFundedUsd(apps) {
	return apps.reduce((acc, app) => {
		const usd = app.state.global.fundsApprovedInUSD;
		if (usd && typeof usd.value === "number") return acc + usd.value;
		return acc;
	}, 0);
}
function formatUsd$1(value) {
	if (value === 0) return "$0";
	if (value >= 1e6) return `$${(value / 1e6).toFixed(1)}M`;
	if (value >= 1e3) return `$${(value / 1e3).toFixed(1)}k`;
	return `$${value.toFixed(0)}`;
}
function StatsRow({ pools, applications, governance, onPoolsClick, onApplicationsClick }) {
	const openPools = pools.filter((p) => p.state.global.lifecycle === "OPEN");
	const closedPools = pools.filter((p) => [
		"CLOSED",
		"AWARDED",
		"NOT_AWARDED",
		"CANCELLED"
	].includes(p.state.global.lifecycle));
	const activeApps = applications.filter((a) => [
		"SUBMITTED",
		"OPENED",
		"UNDER_REVIEW",
		"REVISED",
		"NEEDS_REVISION"
	].includes(a.state.global.reviewStage));
	const fundedApps = applications.filter((a) => ["FUNDED", "COMPLETED"].includes(a.state.global.reviewStage));
	const fundedUsd = sumFundedUsd(applications);
	const openDisputes = governance.reduce((sum, g) => sum + (g.state.global.disputes ?? []).filter((d) => d.status === "OPEN" || d.status === "INVESTIGATING").length, 0);
	return /* @__PURE__ */ jsx("div", {
		className: "rfp-grid-4",
		children: [
			{
				label: "Pools",
				value: pools.length,
				sub: `${openPools.length} open · ${closedPools.length} closed`,
				onClick: onPoolsClick
			},
			{
				label: "Active applications",
				value: activeApps.length,
				sub: "Pending · in review · needs revision",
				onClick: onApplicationsClick
			},
			{
				label: "Funded",
				value: fundedApps.length,
				sub: formatUsd$1(fundedUsd)
			},
			{
				label: "Disputes",
				value: openDisputes,
				sub: openDisputes === 0 ? "All clear" : "Open governance items",
				danger: openDisputes > 0
			}
		].map((tile) => /* @__PURE__ */ jsxs("button", {
			type: "button",
			className: `rfp-stat-tile${tile.danger ? " rfp-stat-tile-danger" : ""}`,
			onClick: tile.onClick,
			style: {
				cursor: tile.onClick ? "pointer" : "default",
				textAlign: "left",
				border: 0,
				font: "inherit"
			},
			children: [
				/* @__PURE__ */ jsx("span", {
					className: "rfp-stat-tile-label",
					children: tile.label
				}),
				/* @__PURE__ */ jsx("span", {
					className: "rfp-stat-tile-value",
					children: tile.value
				}),
				/* @__PURE__ */ jsx("span", {
					className: "rfp-hint",
					children: tile.sub
				})
			]
		}, tile.label))
	});
}
//#endregion
//#region editors/funder-back-office/components/dashboard/ReviewKanban.tsx
const COLLAPSED_PER_COLUMN = 3;
function groupByColumn(apps) {
	const out = {};
	for (const col of KANBAN_COLUMNS) out[col.key] = [];
	for (const app of apps) {
		const stage = app.state.global.reviewStage;
		const col = KANBAN_COLUMNS.find((c) => c.stages.includes(stage));
		if (col) out[col.key].push(app);
	}
	return out;
}
function KanbanCard({ app }) {
	const state = app.state.global;
	const days = daysSince(state.submittedAt);
	return /* @__PURE__ */ jsxs("div", {
		className: "rfp-doc-card",
		onClick: () => setSelectedNode(app.header.id),
		role: "button",
		tabIndex: 0,
		onKeyDown: (e) => {
			if (e.key === "Enter" || e.key === " ") setSelectedNode(app.header.id);
		},
		children: [
			/* @__PURE__ */ jsx("span", {
				className: "rfp-doc-card-title",
				children: state.projectName ?? app.header.name ?? "Unnamed application"
			}),
			/* @__PURE__ */ jsxs("span", {
				className: "rfp-doc-card-meta",
				children: ["→ ", state.grantPoolName ?? "No pool linked"]
			}),
			/* @__PURE__ */ jsxs("div", {
				className: "rfp-row",
				style: {
					justifyContent: "space-between",
					gap: 6
				},
				children: [/* @__PURE__ */ jsx("span", {
					className: `rfp-status-badge ${REVIEW_STAGE_CLASS[state.reviewStage] ?? "rfp-status-draft"}`,
					children: state.reviewStage.replace(/_/g, " ").toLowerCase()
				}), /* @__PURE__ */ jsxs("span", {
					className: "rfp-doc-card-meta",
					children: [state.revisionCount > 0 ? `rev ${state.revisionCount} · ` : "", days !== null ? `${days}d` : "—"]
				})]
			})
		]
	});
}
function ReviewKanban({ applications, hasPools }) {
	const grouped = groupByColumn(applications);
	const [expandAll, setExpandAll] = useState(false);
	const [expandedColumns, setExpandedColumns] = useState(() => /* @__PURE__ */ new Set());
	const visibleTotal = KANBAN_COLUMNS.reduce((sum, col) => sum + (grouped[col.key]?.length ?? 0), 0);
	const overflowColumns = KANBAN_COLUMNS.filter((col) => (grouped[col.key]?.length ?? 0) > COLLAPSED_PER_COLUMN);
	const hasAnyOverflow = overflowColumns.length > 0;
	function toggleColumn(key) {
		setExpandedColumns((prev) => {
			const next = new Set(prev);
			if (next.has(key)) next.delete(key);
			else next.add(key);
			return next;
		});
	}
	function toggleAll() {
		if (expandAll) {
			setExpandAll(false);
			setExpandedColumns(/* @__PURE__ */ new Set());
		} else {
			setExpandAll(true);
			setExpandedColumns(new Set(overflowColumns.map((c) => c.key)));
		}
	}
	return /* @__PURE__ */ jsxs("section", {
		className: "rfp-card rfp-section",
		children: [
			/* @__PURE__ */ jsxs("div", {
				className: "rfp-row",
				style: { justifyContent: "space-between" },
				children: [/* @__PURE__ */ jsxs("h2", {
					className: "rfp-section-subtitle",
					children: ["Review queue · ", visibleTotal]
				}), /* @__PURE__ */ jsxs("div", {
					className: "rfp-row",
					style: { gap: 10 },
					children: [hasAnyOverflow ? /* @__PURE__ */ jsx("button", {
						type: "button",
						className: "rfp-link-button",
						onClick: toggleAll,
						children: expandAll ? "Collapse all" : "Expand all"
					}) : null, /* @__PURE__ */ jsx("span", {
						className: "rfp-meta",
						children: "DAOIP-5 GrantApplication"
					})]
				})]
			}),
			/* @__PURE__ */ jsx("hr", { className: "rfp-divider" }),
			!hasPools ? /* @__PURE__ */ jsx("p", {
				className: "rfp-locked-hint",
				children: "Applications appear once a grant pool is published and receives submissions."
			}) : visibleTotal === 0 ? /* @__PURE__ */ jsx("div", {
				className: "rfp-empty",
				children: "Waiting for the first application. Applicants submit through Fusion — new submissions land here automatically."
			}) : /* @__PURE__ */ jsx("div", {
				className: "rfp-kanban",
				children: KANBAN_COLUMNS.map((col) => {
					const apps = grouped[col.key];
					const hasOverflow = apps.length > COLLAPSED_PER_COLUMN;
					const isExpanded = expandedColumns.has(col.key);
					const visibleApps = hasOverflow && !isExpanded ? apps.slice(0, COLLAPSED_PER_COLUMN) : apps;
					const hiddenCount = apps.length - visibleApps.length;
					return /* @__PURE__ */ jsxs("div", {
						className: "rfp-stage-column",
						children: [/* @__PURE__ */ jsxs("div", {
							className: "rfp-stage-column-header",
							children: [/* @__PURE__ */ jsx("h3", {
								className: "rfp-stage-column-title",
								children: col.label
							}), /* @__PURE__ */ jsx("span", {
								className: "rfp-chip",
								children: apps.length
							})]
						}), apps.length === 0 ? /* @__PURE__ */ jsx("span", {
							className: "rfp-locked-hint",
							children: "Empty"
						}) : /* @__PURE__ */ jsxs(Fragment, { children: [visibleApps.map((app) => /* @__PURE__ */ jsx(KanbanCard, { app }, app.header.id)), hasOverflow ? /* @__PURE__ */ jsx("button", {
							type: "button",
							className: "rfp-link-button rfp-kanban-more",
							onClick: () => toggleColumn(col.key),
							children: isExpanded ? "Show less" : `Show ${hiddenCount} more`
						}) : null] })]
					}, col.key);
				})
			})
		]
	});
}
//#endregion
//#region editors/funder-back-office/components/dashboard/PoolsGrid.tsx
function formatUsd(value) {
	if (value == null || value === 0) return "USD not set";
	if (value >= 1e6) return `$${(value / 1e6).toFixed(1)}M`;
	if (value >= 1e3) return `$${(value / 1e3).toFixed(1)}k`;
	return `$${value.toFixed(0)}`;
}
function PoolCard({ pool, appCount }) {
	const state = pool.state.global;
	const lifecycle = state.lifecycle;
	const statusClass = POOL_LIFECYCLE_CLASS[lifecycle] ?? "rfp-status-draft";
	const closesInDays = daysUntil(state.closeDate);
	const usd = state.totalGrantPoolSizeInUSD?.value;
	return /* @__PURE__ */ jsxs("div", {
		className: "rfp-doc-card",
		onClick: () => setSelectedNode(pool.header.id),
		role: "button",
		tabIndex: 0,
		onKeyDown: (e) => {
			if (e.key === "Enter" || e.key === " ") setSelectedNode(pool.header.id);
		},
		style: { padding: "16px 18px" },
		children: [
			/* @__PURE__ */ jsxs("div", {
				className: "rfp-row",
				style: {
					justifyContent: "space-between",
					gap: 8
				},
				children: [/* @__PURE__ */ jsx("span", {
					className: "rfp-doc-card-title",
					children: state.name ?? pool.header.name ?? "Untitled pool"
				}), /* @__PURE__ */ jsx("span", {
					className: `rfp-status-badge ${statusClass}`,
					children: lifecycle.replace(/_/g, " ").toLowerCase()
				})]
			}),
			state.code ? /* @__PURE__ */ jsx("span", {
				className: "rfp-chip",
				style: { alignSelf: "flex-start" },
				children: state.code
			}) : null,
			state.description ? /* @__PURE__ */ jsx("span", {
				className: "rfp-doc-card-meta",
				style: {
					display: "-webkit-box",
					WebkitLineClamp: 2,
					WebkitBoxOrient: "vertical",
					overflow: "hidden"
				},
				children: state.description
			}) : null,
			/* @__PURE__ */ jsxs("div", {
				className: "rfp-row",
				style: {
					justifyContent: "space-between",
					gap: 6
				},
				children: [/* @__PURE__ */ jsx("span", {
					className: "rfp-doc-card-meta",
					children: formatUsd(usd)
				}), /* @__PURE__ */ jsxs("span", {
					className: "rfp-doc-card-meta",
					children: [
						appCount,
						" application",
						appCount === 1 ? "" : "s"
					]
				})]
			}),
			lifecycle === "OPEN" && closesInDays !== null ? /* @__PURE__ */ jsx("span", {
				className: "rfp-doc-card-meta",
				children: closesInDays > 0 ? `${closesInDays}d until close` : closesInDays === 0 ? "Closes today" : "Past close date"
			}) : null
		]
	});
}
function PoolsGrid({ pools, applications, onCreate, creating, canCreate }) {
	const appsByPool = /* @__PURE__ */ new Map();
	for (const app of applications) {
		const id = app.state.global.grantPoolId;
		if (id) appsByPool.set(id, (appsByPool.get(id) ?? 0) + 1);
	}
	return /* @__PURE__ */ jsxs("section", {
		className: "rfp-card rfp-section",
		children: [
			/* @__PURE__ */ jsxs("div", {
				className: "rfp-row",
				style: { justifyContent: "space-between" },
				children: [/* @__PURE__ */ jsxs("h2", {
					className: "rfp-section-subtitle",
					children: ["Grant pools · ", pools.length]
				}), /* @__PURE__ */ jsx("button", {
					type: "button",
					className: "rfp-btn-primary",
					disabled: creating || !canCreate,
					onClick: onCreate,
					children: creating ? "Creating…" : "+ Create pool"
				})]
			}),
			/* @__PURE__ */ jsx("hr", { className: "rfp-divider" }),
			pools.length === 0 ? /* @__PURE__ */ jsx("div", {
				className: "rfp-empty",
				children: "No grant pools yet. Create one to open a funding call — RFP, bounty, QF round, or retro."
			}) : /* @__PURE__ */ jsxs("div", {
				className: "rfp-grid-2",
				children: [pools.map((pool) => /* @__PURE__ */ jsx(PoolCard, {
					pool,
					appCount: appsByPool.get(pool.header.id) ?? 0
				}, pool.header.id)), /* @__PURE__ */ jsx("button", {
					type: "button",
					className: "rfp-doc-card",
					disabled: creating || !canCreate,
					onClick: onCreate,
					style: {
						border: "1.5px dashed var(--rfp-outline-variant)",
						background: "transparent",
						alignItems: "center",
						justifyContent: "center",
						minHeight: 140,
						cursor: canCreate && !creating ? "pointer" : "not-allowed",
						color: "var(--rfp-primary)",
						fontWeight: 600
					},
					children: creating ? "Creating…" : "+ New pool"
				})]
			})
		]
	});
}
//#endregion
//#region editors/funder-back-office/components/dashboard/GovernanceHealth.tsx
function GovernanceHealth({ governance, onCreate, creating, canCreate }) {
	const hasAny = governance.length > 0;
	const openDisputes = governance.reduce((sum, g) => sum + (g.state.global.disputes ?? []).filter((d) => d.status === "OPEN" || d.status === "INVESTIGATING").length, 0);
	const activeRfcs = governance.reduce((sum, g) => sum + (g.state.global.rfcs ?? []).filter((r) => ["PROPOSED", "UNDER_REVIEW"].includes(r.status)).length, 0);
	const publishedPolicies = governance.reduce((sum, g) => sum + (g.state.global.policies ?? []).filter((p) => !p.supersededAt).length, 0);
	return /* @__PURE__ */ jsxs("section", {
		className: "rfp-card rfp-section",
		children: [
			/* @__PURE__ */ jsxs("div", {
				className: "rfp-row",
				style: { justifyContent: "space-between" },
				children: [/* @__PURE__ */ jsx("h2", {
					className: "rfp-section-subtitle",
					children: "Governance health"
				}), !hasAny && canCreate ? /* @__PURE__ */ jsx("button", {
					type: "button",
					className: "rfp-btn-secondary",
					disabled: creating,
					onClick: onCreate,
					children: creating ? "Creating…" : "+ Create governance doc"
				}) : null]
			}),
			/* @__PURE__ */ jsx("hr", { className: "rfp-divider" }),
			!hasAny ? /* @__PURE__ */ jsx("div", {
				className: "rfp-empty",
				children: "No governance document yet. Create one to track disputes, RFCs, and policies in one place."
			}) : /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", {
				className: "rfp-grid-3",
				children: [
					/* @__PURE__ */ jsxs("button", {
						type: "button",
						className: `rfp-stat-tile${openDisputes > 0 ? " rfp-stat-tile-danger" : ""}`,
						onClick: () => setSelectedNode(governance[0].header.id),
						style: {
							cursor: "pointer",
							textAlign: "left",
							border: 0,
							font: "inherit"
						},
						children: [
							/* @__PURE__ */ jsx("span", {
								className: "rfp-stat-tile-label",
								children: "Open disputes"
							}),
							/* @__PURE__ */ jsx("span", {
								className: "rfp-stat-tile-value",
								children: openDisputes
							}),
							/* @__PURE__ */ jsx("span", {
								className: "rfp-hint",
								children: "Open · investigating"
							})
						]
					}),
					/* @__PURE__ */ jsxs("button", {
						type: "button",
						className: "rfp-stat-tile",
						onClick: () => setSelectedNode(governance[0].header.id),
						style: {
							cursor: "pointer",
							textAlign: "left",
							border: 0,
							font: "inherit"
						},
						children: [
							/* @__PURE__ */ jsx("span", {
								className: "rfp-stat-tile-label",
								children: "Active RFCs"
							}),
							/* @__PURE__ */ jsx("span", {
								className: "rfp-stat-tile-value",
								children: activeRfcs
							}),
							/* @__PURE__ */ jsx("span", {
								className: "rfp-hint",
								children: "Proposed · under review"
							})
						]
					}),
					/* @__PURE__ */ jsxs("button", {
						type: "button",
						className: "rfp-stat-tile",
						onClick: () => setSelectedNode(governance[0].header.id),
						style: {
							cursor: "pointer",
							textAlign: "left",
							border: 0,
							font: "inherit"
						},
						children: [
							/* @__PURE__ */ jsx("span", {
								className: "rfp-stat-tile-label",
								children: "Policies"
							}),
							/* @__PURE__ */ jsx("span", {
								className: "rfp-stat-tile-value",
								children: publishedPolicies
							}),
							/* @__PURE__ */ jsx("span", {
								className: "rfp-hint",
								children: "Currently in effect"
							})
						]
					})
				]
			}) })
		]
	});
}
//#endregion
//#region editors/funder-back-office/components/dashboard/ActivityFeed.tsx
const ACTIVITY_LIMIT = 50;
function docTitle(doc) {
	const type = doc.header.documentType;
	const fallback = doc.header.name?.trim();
	switch (type) {
		case "rfp-hub/grant-system": return doc.state.global.name?.trim() || fallback || "Unnamed organization";
		case "rfp-hub/grant-pool": return doc.state.global.name?.trim() || fallback || "Untitled pool";
		case "rfp-hub/grant-application": return doc.state.global.projectName?.trim() || fallback || "Unnamed application";
		case "rfp-hub/project": return doc.state.global.name?.trim() || fallback || "Unnamed project";
		default: return fallback || "Untitled document";
	}
}
function docKindLabel(type) {
	switch (type) {
		case "rfp-hub/grant-system": return "Grant system";
		case "rfp-hub/grant-pool": return "Grant pool";
		case "rfp-hub/grant-application": return "Application";
		case "rfp-hub/governance": return "Governance";
		case "rfp-hub/project": return "Project";
		default: return type.replace(/^rfp-hub\//, "").replace(/-/g, " ");
	}
}
/** Turn `SET_PROJECT_NAME` → `Set project name`. */
function humanizeActionType(actionType) {
	const raw = actionType.replace(/_/g, " ").toLowerCase();
	return raw.charAt(0).toUpperCase() + raw.slice(1);
}
/**
* Extract a tiny hint from the action input so the event reads in plain
* English. Keeps output short and safe for mixed / unknown inputs.
*/
function describeActionInput(actionType, input) {
	if (!input || typeof input !== "object") return null;
	const o = input;
	const pick = (...keys) => {
		for (const k of keys) {
			const v = o[k];
			if (typeof v === "string" && v.trim()) return v.trim();
			if (typeof v === "number") return String(v);
			if (typeof v === "boolean") return v ? "yes" : "no";
		}
		return null;
	};
	if (actionType === "ADD_FUNDS_ASKED" || actionType === "ADD_FUNDS_APPROVED") {
		const amount = o.amount;
		if (amount?.value != null && amount.unit) return `${amount.value.toLocaleString()} ${amount.unit}`;
	}
	if (actionType === "SET_FUNDS_ASKED_USD" || actionType === "SET_FUNDS_APPROVED_USD") {
		const usd = o.fundsAskedInUSD ?? o.fundsApprovedInUSD;
		if (usd?.value != null) return `$${usd.value.toLocaleString()} USD`;
	}
	const stage = pick("reviewStage", "stage", "lifecycle", "verificationState");
	if (stage) return stage.replace(/_/g, " ").toLowerCase();
	const shortFields = pick("name", "projectName", "grantPoolName", "applicantName", "email", "title");
	if (shortFields) return `"${shortFields.length > 48 ? `${shortFields.slice(0, 45)}…` : shortFields}"`;
	return null;
}
function ActivityFeed({ documents }) {
	const items = [];
	for (const doc of documents) {
		const title = docTitle(doc);
		const kind = docKindLabel(doc.header.documentType);
		const ops = doc.operations?.global ?? [];
		if (ops.length === 0) {
			const iso = doc.header.lastModifiedAtUtcIso ?? doc.header.createdAtUtcIso;
			if (iso) items.push({
				key: `${doc.header.id}:init`,
				docId: doc.header.id,
				title: `${kind} "${title}" created`,
				subtitle: kind,
				iso
			});
			continue;
		}
		for (const op of ops) {
			if (!op.timestampUtcMs) continue;
			const actionType = op.action?.type ?? "";
			if (!actionType) continue;
			const verb = humanizeActionType(actionType);
			const hint = describeActionInput(actionType, op.action?.input);
			const subtitle = hint ? `${kind} · ${hint}` : `${kind}`;
			items.push({
				key: `${doc.header.id}:${op.id}:${op.index}`,
				docId: doc.header.id,
				title: `${verb} — ${title}`,
				subtitle,
				iso: new Date(Number(op.timestampUtcMs)).toISOString()
			});
		}
	}
	items.sort((a, b) => new Date(b.iso).getTime() - new Date(a.iso).getTime());
	const visible = items.slice(0, ACTIVITY_LIMIT);
	return /* @__PURE__ */ jsxs("section", {
		className: "rfp-card rfp-section",
		children: [
			/* @__PURE__ */ jsxs("div", {
				className: "rfp-row",
				style: { justifyContent: "space-between" },
				children: [/* @__PURE__ */ jsxs("h2", {
					className: "rfp-section-subtitle",
					children: ["Recent activity ", items.length > 0 ? `· ${items.length}` : null]
				}), /* @__PURE__ */ jsx("span", {
					className: "rfp-meta",
					children: "Newest first"
				})]
			}),
			/* @__PURE__ */ jsx("hr", { className: "rfp-divider" }),
			visible.length === 0 ? /* @__PURE__ */ jsx("div", {
				className: "rfp-empty",
				children: "No activity yet."
			}) : /* @__PURE__ */ jsx("ul", {
				className: "rfp-list rfp-activity-scroll",
				style: { gap: 4 },
				children: visible.map((item) => /* @__PURE__ */ jsxs("li", {
					className: "rfp-activity-row",
					onClick: () => setSelectedNode(item.docId),
					role: "button",
					tabIndex: 0,
					onKeyDown: (e) => {
						if (e.key === "Enter" || e.key === " ") setSelectedNode(item.docId);
					},
					title: new Date(item.iso).toLocaleString(),
					children: [/* @__PURE__ */ jsx("span", { className: "rfp-activity-dot" }), /* @__PURE__ */ jsxs("div", {
						className: "rfp-activity-body",
						children: [/* @__PURE__ */ jsx("div", {
							className: "rfp-activity-title",
							children: item.title
						}), /* @__PURE__ */ jsxs("div", {
							className: "rfp-activity-meta",
							children: [
								item.subtitle,
								" · ",
								formatRelativeTime(item.iso)
							]
						})]
					})]
				}, item.key))
			})
		]
	});
}
//#endregion
//#region editors/funder-back-office/components/dashboard/OrgCard.tsx
const VERIFICATION_LABEL = {
	UNVERIFIED: "Unverified",
	PENDING_REVIEW: "Pending review",
	VERIFIED: "Verified",
	SUSPENDED: "Suspended",
	REVOKED: "Revoked"
};
const VERIFICATION_CLASS = {
	UNVERIFIED: "rfp-status-draft",
	PENDING_REVIEW: "rfp-status-pending",
	VERIFIED: "rfp-status-approved",
	SUSPENDED: "rfp-status-closed",
	REVOKED: "rfp-status-rejected"
};
function OrgCard({ system }) {
	const state = system.state.global;
	return /* @__PURE__ */ jsxs("button", {
		type: "button",
		className: "rfp-card",
		onClick: () => setSelectedNode(system.header.id),
		style: {
			display: "flex",
			alignItems: "center",
			justifyContent: "space-between",
			gap: 16,
			cursor: "pointer",
			textAlign: "left",
			border: 0,
			font: "inherit",
			padding: "16px 20px"
		},
		children: [/* @__PURE__ */ jsxs("div", {
			className: "rfp-col",
			style: { gap: 4 },
			children: [
				/* @__PURE__ */ jsx("span", {
					className: "rfp-meta",
					children: "Organization"
				}),
				/* @__PURE__ */ jsx("strong", {
					className: "rfp-body",
					style: { fontWeight: 600 },
					children: state.name ?? system.header.name ?? "Unnamed organization"
				}),
				/* @__PURE__ */ jsx("span", {
					className: "rfp-hint",
					children: state.type ? state.type.charAt(0) + state.type.slice(1).toLowerCase() : "Type not set"
				})
			]
		}), /* @__PURE__ */ jsx("span", {
			className: `rfp-status-badge ${VERIFICATION_CLASS[state.verificationState] ?? "rfp-status-draft"}`,
			children: VERIFICATION_LABEL[state.verificationState] ?? state.verificationState
		})]
	});
}
//#endregion
//#region editors/funder-back-office/hooks/useRemoteApplications.ts
/**
* Polls the switchboard's auto-registered `GrantApplication` subgraph for
* every application doc that exists in the reactor, then filters client-side
* down to those whose `state.global.grantPoolId` matches one of the pools the
* funder cares about.
*
* Needed because `useDocumentsInSelectedDrive` only returns docs in the
* *currently open drive*, so applications produced by `applyToPool` — which
* live in per-applicant drives — are invisible to the funder dashboard
* without this cross-drive fetch.
*/
const REFRESH_INTERVAL_MS = 15e3;
function narrowAmount(raw) {
	if (!raw || typeof raw !== "object") return null;
	const o = raw;
	if (typeof o.value !== "number") return null;
	if (typeof o.unit !== "string") return null;
	return {
		value: o.value,
		unit: o.unit
	};
}
const QUERY = `{
  GrantApplication {
    findDocuments {
      totalCount
      items {
        id
        name
        createdAtUtcIso
        lastModifiedAtUtcIso
        state {
          global {
            grantPoolId
            grantPoolName
            projectId
            projectName
            reviewStage
            createdAt
            submittedAt
            reviewedAt
            reviewedBy
            revisionCount
            isInactive
            fundsApprovedInUSD
            fundsAskedInUSD
          }
        }
      }
    }
  }
}`;
/**
* Reconstructs a partial `GrantApplicationDocument` from a `RemoteAppItem` so
* the rest of the dashboard (which is strongly typed against the full doc
* shape) can consume remote results side-by-side with local-drive ones.
* Only the fields the dashboard reads are filled in — operations, signatures,
* and header/meta extras are stubbed.
*/
function toApplicationDoc(item) {
	const globalState = item.state.global;
	return {
		header: {
			id: item.id,
			name: item.name ?? "",
			documentType: "rfp-hub/grant-application",
			createdAtUtcIso: item.createdAtUtcIso ?? "",
			lastModifiedAtUtcIso: item.lastModifiedAtUtcIso ?? "",
			revision: {
				global: 0,
				document: 0
			},
			slug: item.id,
			branch: "main",
			sig: {
				nonce: "",
				publicKey: {}
			},
			protocolVersions: {},
			meta: {}
		},
		state: {
			auth: {},
			document: {
				hash: {
					encoding: "base64",
					algorithm: "sha1"
				},
				version: 0
			},
			global: {
				createdAt: globalState.createdAt,
				fundsApproved: [],
				fundsApprovedInUSD: narrowAmount(globalState.fundsApprovedInUSD),
				fundsAsked: [],
				fundsAskedInUSD: narrowAmount(globalState.fundsAskedInUSD),
				grantPoolId: globalState.grantPoolId,
				grantPoolName: globalState.grantPoolName,
				isInactive: globalState.isInactive,
				projectId: globalState.projectId,
				projectName: globalState.projectName,
				reviewStage: globalState.reviewStage,
				reviewedAt: globalState.reviewedAt,
				reviewedBy: globalState.reviewedBy,
				revisionCount: globalState.revisionCount,
				submittedAt: globalState.submittedAt
			},
			local: {}
		},
		operations: {
			global: [],
			local: []
		},
		clipboard: [],
		initialState: {}
	};
}
/**
* Resolve the switchboard `/graphql` endpoint for the currently-selected
* drive. Priority:
*   1. The drive's own remote `GqlRequestChannel` URL (truth if the drive is
*      cloud-synced) stripped to `/graphql`.
*   2. `window.location.origin + '/graphql'` when the drive is local
*      (reasonable default in dev since `ph vetra` runs Connect on 3001 but
*      the switchboard on the same host at 4001 — see fallback below).
*   3. `http://localhost:4001/graphql` as the final local-dev fallback.
*/
function useSwitchboardGqlUrl() {
	const driveId = useSelectedDriveId();
	const syncList = useSyncList();
	return useMemo(() => {
		if (!driveId) return null;
		const driveUrl = (syncList.find((r) => r.collectionId === driveCollectionId("main", driveId))?.channel)?.config?.url;
		if (driveUrl) return getSwitchboardGatewayUrlFromDriveUrl(driveUrl);
		if (typeof window !== "undefined") return "http://localhost:4001/graphql";
		return null;
	}, [driveId, syncList]);
}
/**
* Fetch every GrantApplication on the switchboard and filter to those
* matching one of the provided `poolIds`. Re-fetches every 15 s and exposes
* a manual `refresh` for "applied just now" UX flows.
*/
function useRemoteApplicationsForPools(poolIds) {
	const url = useSwitchboardGqlUrl();
	const [applications, setApplications] = useState([]);
	const [loading, setLoading] = useState(false);
	const [error, setError] = useState(null);
	const poolIdsRef = useRef(poolIds);
	poolIdsRef.current = poolIds;
	const [tick, setTick] = useState(0);
	const refresh = () => setTick((t) => t + 1);
	useEffect(() => {
		if (!url) return;
		let cancelled = false;
		async function fetchOnce() {
			setLoading(true);
			setError(null);
			try {
				if (!url) return;
				const res = await fetch(url, {
					method: "POST",
					headers: { "Content-Type": "application/json" },
					body: JSON.stringify({ query: QUERY })
				});
				if (!res.ok) throw new Error(`HTTP ${res.status}`);
				const json = await res.json();
				if (json.errors?.length) throw new Error(json.errors[0].message ?? "GraphQL error");
				const items = json.data?.GrantApplication?.findDocuments?.items ?? [];
				const allowed = new Set(poolIdsRef.current);
				const matching = items.filter((i) => i.state.global.grantPoolId ? allowed.has(i.state.global.grantPoolId) : false).map(toApplicationDoc);
				if (!cancelled) setApplications(matching);
			} catch (e) {
				if (!cancelled) setError(e instanceof Error ? e.message : "Failed to fetch");
			} finally {
				if (!cancelled) setLoading(false);
			}
		}
		fetchOnce();
		const id = setInterval(fetchOnce, REFRESH_INTERVAL_MS);
		return () => {
			cancelled = true;
			clearInterval(id);
		};
	}, [url, tick]);
	return {
		applications,
		loading,
		error,
		refresh
	};
}
//#endregion
//#region editors/funder-back-office/components/BackOfficeDashboard.tsx
function isDocumentOfType(doc, type) {
	return doc.header.documentType === type;
}
function BackOfficeDashboard({ children }) {
	const showDocumentEditor = !!children;
	const documents = useDocumentsInSelectedDrive();
	const [selectedDrive] = useSelectedDrive();
	const [creatingType, setCreatingType] = useState(null);
	const driveId = selectedDrive?.header.id;
	const grantSystems = useMemo(() => (documents ?? []).filter((d) => isDocumentOfType(d, DOC_TYPE.grantSystem)), [documents]);
	const grantPools = useMemo(() => (documents ?? []).filter((d) => isDocumentOfType(d, DOC_TYPE.grantPool)), [documents]);
	const localApplications = useMemo(() => (documents ?? []).filter((d) => isDocumentOfType(d, DOC_TYPE.grantApplication)), [documents]);
	const { applications: remoteApplications } = useRemoteApplicationsForPools(useMemo(() => (documents ?? []).filter((d) => isDocumentOfType(d, DOC_TYPE.grantPool)).map((p) => p.header.id), [documents]));
	const applications = useMemo(() => {
		const byId = /* @__PURE__ */ new Map();
		for (const a of localApplications) byId.set(a.header.id, a);
		for (const a of remoteApplications) byId.set(a.header.id, a);
		return Array.from(byId.values());
	}, [localApplications, remoteApplications]);
	const governance = useMemo(() => (documents ?? []).filter((d) => isDocumentOfType(d, DOC_TYPE.governance)), [documents]);
	const hasGrantSystem = grantSystems.length > 0;
	const handleCreate = useCallback(async (documentType, name) => {
		if (!driveId || creatingType) return;
		setCreatingType(documentType);
		try {
			await addDocument(driveId, name, documentType);
		} catch (err) {
			console.error(`Failed to create ${documentType}:`, err);
		} finally {
			setCreatingType(null);
		}
	}, [driveId, creatingType]);
	return /* @__PURE__ */ jsxs("div", {
		style: {
			display: "flex",
			height: "100%"
		},
		children: [/* @__PURE__ */ jsx(DocumentBrowser, {
			mode: "funder",
			onCreate: handleCreate,
			creatingType,
			canCreate: !!driveId,
			extraDocuments: remoteApplications
		}), /* @__PURE__ */ jsx("div", {
			style: {
				flex: 1,
				overflowY: "auto"
			},
			children: showDocumentEditor ? children : /* @__PURE__ */ jsx("div", {
				className: "rfp-page",
				children: /* @__PURE__ */ jsx("div", {
					className: "rfp-page-inner",
					children: !hasGrantSystem ? /* @__PURE__ */ jsx(OnboardingHero, {
						isCreating: creatingType === DOC_TYPE.grantSystem,
						onCreate: () => handleCreate(DOC_TYPE.grantSystem, "Grant System")
					}) : /* @__PURE__ */ jsx(DashboardBody, {
						grantSystems,
						grantPools,
						applications,
						governance,
						documents: documents ?? [],
						creatingType,
						canCreate: !!driveId,
						onCreate: handleCreate
					})
				})
			})
		})]
	});
}
function DashboardBody({ grantSystems, grantPools, applications, governance, documents, creatingType, canCreate, onCreate }) {
	const primarySystem = grantSystems[0];
	return /* @__PURE__ */ jsxs(Fragment, { children: [
		/* @__PURE__ */ jsx("header", {
			className: "rfp-header",
			children: /* @__PURE__ */ jsxs("div", {
				className: "rfp-header-row",
				children: [/* @__PURE__ */ jsxs("div", {
					className: "rfp-col",
					style: { gap: 6 },
					children: [
						/* @__PURE__ */ jsx("span", {
							className: "rfp-meta",
							children: "RFP Hub · Back office"
						}),
						/* @__PURE__ */ jsx("h1", {
							className: "rfp-h1",
							children: "Funder dashboard"
						}),
						/* @__PURE__ */ jsx("p", {
							className: "rfp-hint",
							style: { maxWidth: 640 },
							children: "Set up pools, review applications, and manage governance from one control center."
						})
					]
				}), primarySystem ? /* @__PURE__ */ jsx("div", {
					style: {
						minWidth: 260,
						maxWidth: 360
					},
					children: /* @__PURE__ */ jsx(OrgCard, { system: primarySystem })
				}) : null]
			})
		}),
		/* @__PURE__ */ jsx(StatsRow, {
			pools: grantPools,
			applications,
			governance
		}),
		/* @__PURE__ */ jsx(ReviewKanban, {
			applications,
			hasPools: grantPools.length > 0
		}),
		/* @__PURE__ */ jsx(PoolsGrid, {
			pools: grantPools,
			applications,
			creating: creatingType === DOC_TYPE.grantPool,
			canCreate,
			onCreate: () => onCreate(DOC_TYPE.grantPool, `Grant pool ${grantPools.length + 1}`)
		}),
		/* @__PURE__ */ jsxs("div", {
			className: "rfp-grid-2",
			children: [/* @__PURE__ */ jsx(GovernanceHealth, {
				governance,
				creating: creatingType === DOC_TYPE.governance,
				canCreate,
				onCreate: () => onCreate(DOC_TYPE.governance, "Governance")
			}), /* @__PURE__ */ jsx(ActivityFeed, { documents })]
		})
	] });
}
function OnboardingHero({ isCreating, onCreate }) {
	return /* @__PURE__ */ jsx("div", {
		style: { padding: "48px 0" },
		children: /* @__PURE__ */ jsxs("div", {
			className: "rfp-hero",
			children: [
				/* @__PURE__ */ jsx("span", {
					className: "rfp-hero-badge",
					children: "Stage 1 of 4"
				}),
				/* @__PURE__ */ jsx("h2", {
					className: "rfp-hero-title",
					children: "Set up your organization"
				}),
				/* @__PURE__ */ jsxs("p", {
					className: "rfp-hero-body",
					children: [
						"Welcome to the Funder Back Office. Before you can publish a grant pool or review applications, publish your organization identity as a ",
						/* @__PURE__ */ jsx("code", { children: "rfp-hub/grant-system" }),
						" document. This becomes the parent record for everything you fund."
					]
				}),
				/* @__PURE__ */ jsx("button", {
					type: "button",
					className: "rfp-btn-primary-lg",
					onClick: onCreate,
					disabled: isCreating,
					children: isCreating ? "Creating…" : "Create your Grant System →"
				})
			]
		})
	});
}
//#endregion
//#region editors/funder-back-office/config.ts
/** Editor config for the <%= pascalCaseAppName %> */
const editorConfig = {
	isDragAndDropEnabled: true,
	allowedDocumentTypes: [
		"rfp-hub/grant-system",
		"rfp-hub/grant-pool",
		"rfp-hub/grant-application",
		"rfp-hub/governance"
	]
};
//#endregion
//#region editors/funder-back-office/editor.tsx
function Editor(props) {
	useSetPHAppConfig(editorConfig);
	return /* @__PURE__ */ jsx("div", {
		className: "rfp-scope",
		style: { height: "100%" },
		children: /* @__PURE__ */ jsx(BackOfficeDashboard, { ...props })
	});
}
//#endregion
export { Editor as default };

//# sourceMappingURL=editor-CHA3rD97.mjs.map