function dashboardAppPath(path) { return window.EA_APP?.path ? window.EA_APP.path(path) : path; }
const DASH_GUESTS_KEY = "everafter-guests";
function guestsBackupKey(projectId) { return DASH_GUESTS_KEY + "-" + projectId; }
function loadGuestsBackup(projectId) {
    try {
        const rows = JSON.parse(localStorage.getItem(guestsBackupKey(projectId)) || "null");
        return Array.isArray(rows) ? rows : null;
    }
    catch (_) {
        return null;
    }
}
function saveGuestsBackup(projectId, guests) {
    try {
        localStorage.setItem(guestsBackupKey(projectId), JSON.stringify(guests));
        return true;
    }
    catch (_) {
        return false;
    }
}
function clearGuestsBackup(projectId) {
    try {
        localStorage.removeItem(guestsBackupKey(projectId));
    }
    catch (_) { }
}
function normalizeRsvps(rows) {
    return rows.map(r => ({
        id: r.id,
        n: r.guest_name,
        status: r.response,
        plus: Math.max(0, (r.headcount || 1) - 1),
        events: r.events || [],
        note: r.message || "",
        when: new Date(r.created_at).getTime(),
        diet: r.dietary || "—",
    }));
}
function parseDashDate(value) {
    if (!value || !/^\d{4}-\d{2}-\d{2}$/.test(String(value)))
        return null;
    const [year, month, day] = String(value).split("-").map(Number);
    const date = new Date(year, month - 1, day);
    if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day)
        return null;
    date.setHours(0, 0, 0, 0);
    return date;
}
function formatDashDate(value) {
    const date = parseDashDate(value);
    if (!date)
        return "";
    return date.toLocaleDateString("en-IN", { day: "numeric", month: "short", year: "numeric" });
}
function Dashboard({ goTo, t, user, onSignOut, openSignIn, projectId: routeProjectId }) {
    const accountIdentity = user?.id || user?.email || "";
    const [activeTab, setActiveTab] = React.useState("overview");
    const [projects, setProjects] = React.useState([]);
    const [project, setProject] = React.useState(null);
    const [projectId, setProjectId] = React.useState(null);
    const [guests, setGuests] = React.useState(null);
    const [rsvps, setRsvps] = React.useState(null);
    const [analytics, setAnalytics] = React.useState(null);
    const [projLoading, setProjLoading] = React.useState(true);
    const [projectError, setProjectError] = React.useState("");
    const [analyticsError, setAnalyticsError] = React.useState("");
    const [analyticsRetry, setAnalyticsRetry] = React.useState(0);
    const [rsvpError, setRsvpError] = React.useState("");
    const [reload, setReload] = React.useState(0);
    const loadSequence = React.useRef(0);
    const [guestSaveError, setGuestSaveError] = React.useState("");
    const [guestSaving, setGuestSaving] = React.useState(false);
    const guestSaveLock = React.useRef(false);
    const contentRef = React.useRef(null);
    const [detailUnavailable, setDetailUnavailable] = React.useState(false);
    React.useEffect(() => {
        let container = contentRef.current;
        while (container) {
            container.scrollTop = 0;
            container.scrollLeft = 0;
            container = container.parentElement;
        }
        if (document.scrollingElement)
            document.scrollingElement.scrollTop = 0;
        window.scrollTo({ top: 0, left: 0, behavior: "instant" });
    }, [activeTab]);
    const eff = React.useMemo(() => {
        const cfg = project?.config || {};
        const couple = cfg.couple || project?.couple || {};
        const firstEvent = Array.isArray(cfg.events)
            ? cfg.events.find((event) => event && (event.date || event.venue || event.name || event.title))
            : null;
        const template = TemplateCatalog.get(project?.template_id);
        const status = project?.status || "not_started";
        const published = status === "published";
        return {
            name: user?.name || couple.bride || "there",
            coupleA: couple.bride || cfg.from || "",
            coupleB: couple.groom || cfg.to || "",
            isApology: template?.experienceType === 'apology',
            email: user?.email || "—",
            plan: published ? "Published invitation" : (project ? "Draft invitation" : "No invitation yet"),
            domain: project?.slug ? (window.location.host + dashboardAppPath("/p/" + encodeURIComponent(project.slug))) : "",
            paidAt: user?.paidAt || null,
            slug: project?.slug || "",
            status,
            templateId: project?.template_id || template?.id || "",
            templateName: template?.name || project?.template_id || "Wedding invitation",
            weddingDate: project ? (couple.date || firstEvent?.date || "") : "",
            weddingTime: couple.timeLabel || couple.time || firstEvent?.time || "",
            venue: project ? (couple.venue || firstEvent?.venue || "") : "",
        };
    }, [user, t, project]);
    React.useEffect(() => {
        if (eff.isApology && ['guests', 'rsvps'].includes(activeTab))
            setActiveTab('overview');
    }, [eff.isApology, activeTab]);
    const loadDashboardProject = React.useCallback(async (pid, summaries = []) => {
        const sequence = ++loadSequence.current;
        setProjLoading(true);
        setAnalytics(null);
        setAnalyticsError("");
        setRsvpError("");
        setGuestSaveError("");
        if (!pid) {
            setProject(null);
            setProjectId(null);
            setGuests([]);
            setRsvps([]);
            setProjLoading(false);
            return;
        }
        const summary = summaries.find((item) => item.id === pid) || null;
        let p = summary;
        let detailOk = false;
        try {
            const full = await window.EA.getProject(pid);
            if (sequence !== loadSequence.current)
                return;
            if (full.project) {
                p = full.project;
                detailOk = true;
            }
            else
                p = summary;
        }
        catch (_) {
            p = summary;
        }
        if (sequence !== loadSequence.current)
            return;
        setDetailUnavailable(!detailOk);
        setGuestSaveError(detailOk ? "" : "Could not fully load this project — guest list editing is paused so nothing gets overwritten. Reload to retry.");
        setProject(p);
        setProjectId(pid);
        const dbGuests = Array.isArray(p?.config?.guests) ? p.config.guests : [];
        const backup = detailOk ? loadGuestsBackup(pid) : null;
        if (backup !== null) {
            setGuests(backup);
            setGuestSaveError("Unsaved guest changes were restored from this device. Save them to your account, or discard them to use the last saved list.");
        }
        else {
            setGuests(dbGuests);
        }
        try {
            const r = await window.EA.listRSVPs(pid);
            if (sequence !== loadSequence.current)
                return;
            setRsvps(normalizeRsvps(r.rsvps || []));
        }
        catch (error) {
            if (sequence !== loadSequence.current)
                return;
            setRsvps([]);
            setRsvpError(error.message || "Guest responses could not be loaded. Try again.");
        }
        setProjLoading(false);
    }, []);
    React.useEffect(() => {
        let cancelled = false;
        if (!window.EA?.isLoggedIn()) {
            setProjects([]);
            setProject(null);
            setProjectId(null);
            setGuests([]);
            setRsvps([]);
            setProjLoading(false);
            return;
        }
        setProjLoading(true);
        setProjectError("");
        window.EA.listProjects()
            .then(async (res) => {
            if (cancelled)
                return;
            const projects = res.projects || [];
            setProjects(projects);
            const summary = (routeProjectId ? projects.find((item) => item.id === routeProjectId) : null) ||
                projects.find((item) => item.status === "published") ||
                projects[0] ||
                null;
            const pid = summary?.id || null;
            await loadDashboardProject(pid, projects);
        })
            .catch(err => {
            if (cancelled)
                return;
            setProjectError(err.message || "Your projects could not be loaded. Please retry.");
            setProjects([]);
            setProject(null);
            setProjectId(null);
            setGuests([]);
            setRsvps([]);
        })
            .finally(() => { if (!cancelled)
            setProjLoading(false); });
        return () => { cancelled = true; loadSequence.current++; };
    }, [accountIdentity, routeProjectId, loadDashboardProject, reload]);
    React.useEffect(() => {
        if (activeTab !== "analytics" || !projectId || analytics !== null || !window.EA?.isLoggedIn())
            return;
        let cancelled = false;
        setAnalyticsError("");
        window.EA.getAnalytics(projectId)
            .then(data => { if (!cancelled)
            setAnalytics(data); })
            .catch(error => { if (!cancelled)
            setAnalyticsError(error.message || "Analytics could not be loaded. Try again."); });
        return () => { cancelled = true; };
    }, [activeTab, projectId, analyticsRetry]);
    const persistGuests = async (newGuests) => {
        if (guestSaveLock.current)
            return false;
        if (!projectId || !window.EA?.isLoggedIn()) {
            setGuestSaveError("Sign in and select a project to save your guest list.");
            return false;
        }
        if (detailUnavailable) {
            setGuestSaveError("Load the invitation again before editing guests, so the saved list stays safe.");
            return false;
        }
        guestSaveLock.current = true;
        setGuestSaving(true);
        setGuests(newGuests);
        const sequence = loadSequence.current;
        try {
            const cfg = { ...(project?.config || {}), guests: newGuests };
            await window.EA.saveProject(projectId, cfg, project?.name);
            clearGuestsBackup(projectId);
            if (sequence === loadSequence.current) {
                setProject(p => p?.id === projectId ? { ...p, config: cfg } : p);
                setGuestSaveError("");
            }
            return true;
        }
        catch (_) {
            const backedUp = saveGuestsBackup(projectId, newGuests);
            if (sequence === loadSequence.current)
                setGuestSaveError(backedUp
                    ? "Guest changes are kept on this device, but are not saved to your account yet. Check your connection and try saving again."
                    : "Guest changes could not be saved. Keep this page open and try saving again, or export a CSV to keep a copy.");
            return false;
        }
        finally {
            guestSaveLock.current = false;
            setGuestSaving(false);
        }
    };
    const updateSharedProject = React.useCallback(updater => {
        setProject(updater);
        setProjects(items => items.map(item => item.id === projectId ? updater(item) : item));
    }, [projectId]);
    const deleteDashboardProject = React.useCallback(async (targetProject) => {
        if (!targetProject?.id || !window.EA?.isLoggedIn())
            return { ok: false, reason: "not_ready" };
        setProjLoading(true);
        try {
            await window.EA.deleteProject(targetProject.id);
            const remaining = projects.filter((item) => item.id !== targetProject.id);
            setProjects(remaining);
            if (targetProject.id === projectId) {
                const next = remaining[0] || null;
                if (next) {
                    window.history.replaceState({ view: "dashboard", projectId: next.id }, "", dashboardAppPath(`/dashboard?project=${encodeURIComponent(next.id)}`));
                    await loadDashboardProject(next.id, remaining);
                }
                else {
                    window.history.replaceState({ view: "dashboard", projectId: null }, "", dashboardAppPath("/dashboard"));
                    setProject(null);
                    setProjectId(null);
                    setGuests([]);
                    setRsvps([]);
                    setAnalytics(null);
                }
            }
            return { ok: true };
        }
        catch (err) {
            return { ok: false, reason: err.message || "Delete failed" };
        }
        finally {
            setProjLoading(false);
        }
    }, [projects, projectId, loadDashboardProject]);
    const guestList = guests ?? [];
    const rsvpList = rsvps ?? [];
    if (!user && !window.EA?.isLoggedIn()) {
        return (React.createElement("div", { className: "account-pages account-welcome" },
            React.createElement("div", { className: "account-welcome-card" },
                React.createElement("div", { className: "account-monogram", "aria-hidden": "true" }, "e"),
                React.createElement("h1", { className: "serif" }, "Your invitations, all together."),
                React.createElement("p", { className: "muted", style: { fontSize: 14, lineHeight: 1.6, marginBottom: 24 } }, "Sign in to return to your designs, share your guest link, and keep track of RSVPs."),
                React.createElement("button", { className: "btn btn-primary", onClick: () => openSignIn && openSignIn("dashboard") }, "Sign in to your account"),
                React.createElement("button", { className: "account-text-button", onClick: () => goTo("gallery") }, "Explore templates first"))));
    }
    return (React.createElement("div", { className: "account-pages dashboard-page" },
        React.createElement("div", { className: "dashboard-layout" },
            React.createElement(DashSidebar, { activeTab: activeTab, setActiveTab: setActiveTab, eff: eff, onSignOut: onSignOut }),
            React.createElement("main", { ref: contentRef, className: "dashboard-content", "aria-busy": projLoading },
                projLoading && React.createElement("div", { className: "account-state", role: "status" },
                    React.createElement("span", { className: "account-monogram", "aria-hidden": "true" }, "e"),
                    React.createElement("h2", { className: "serif" }, "Opening your invitations\u2026"),
                    React.createElement("p", null, "Your saved designs and guest responses will appear here.")),
                projectError && React.createElement("div", { className: "account-alert", role: "alert" },
                    projectError,
                    " ",
                    React.createElement("button", { className: "btn btn-ghost", onClick: () => setReload(v => v + 1) }, "Try again")),
                guestSaveError && (React.createElement("div", { role: "alert", className: "account-alert" },
                    React.createElement("span", null, guestSaveError),
                    detailUnavailable ? React.createElement("button", { className: "btn btn-ghost", onClick: () => loadDashboardProject(projectId, projects) }, "Reload invitation") : React.createElement(React.Fragment, null,
                        React.createElement("button", { className: "btn btn-ghost", disabled: guestSaving, onClick: () => persistGuests(guestList) }, guestSaving ? "Saving…" : "Save guest changes"),
                        React.createElement("button", { className: "btn btn-ghost", disabled: guestSaving, onClick: () => { clearGuestsBackup(projectId); setGuests(project?.config?.guests || []); setGuestSaveError(""); } }, "Discard unsaved changes")))),
                !projLoading && !projectError && React.createElement(React.Fragment, null,
                    rsvpError && React.createElement("div", { className: "account-alert", role: "alert" },
                        rsvpError,
                        " ",
                        React.createElement("button", { className: "btn btn-ghost", onClick: () => loadDashboardProject(projectId, projects) }, "Retry responses")),
                    activeTab === "projects" && React.createElement(DashProjects, { projects: projects, projectId: projectId, loadProject: loadDashboardProject, deleteProject: deleteDashboardProject, goTo: goTo }),
                    activeTab === "overview" && React.createElement(DashOverview, { eff: eff, project: project, goTo: goTo, setActiveTab: setActiveTab, guests: guestList, rsvps: rsvpList, rsvpsUnavailable: Boolean(rsvpError) }),
                    activeTab === "design" && React.createElement(DashDesign, { key: projectId, goTo: goTo, eff: eff, project: project }),
                    !project && ["share", "guests", "rsvps", "analytics"].includes(activeTab) && React.createElement(DashboardEmpty, { goTo: goTo }),
                    project && activeTab === "share" && React.createElement(DashShare, { key: projectId, eff: eff, projectId: projectId, project: project, setProject: updateSharedProject, guests: guestList }),
                    project && activeTab === "guests" && React.createElement(DashGuests, { key: projectId, guests: guestList, persistGuests: persistGuests, saving: guestSaving, unavailable: detailUnavailable, eff: eff }),
                    project && activeTab === "rsvps" && !rsvpError && React.createElement(DashRsvps, { rsvps: rsvpList, guests: guestList }),
                    project && activeTab === "analytics" && (analyticsError ? React.createElement("div", { className: "account-alert", role: "alert" },
                        analyticsError,
                        React.createElement("button", { className: "btn btn-ghost", onClick: () => setAnalyticsRetry(v => v + 1) }, "Try again")) : analytics === null ? React.createElement("div", { className: "account-state", role: "status" }, "Loading invitation analytics\u2026") : !rsvpError && React.createElement(DashAnalytics, { analytics: analytics, rsvps: rsvpList })),
                    activeTab === "billing" && React.createElement(DashBilling, null),
                    activeTab === "settings" && React.createElement(DashSettings, { eff: eff, goTo: goTo, project: project }))))));
}
function DashSidebar({ activeTab, setActiveTab, eff, onSignOut }) {
    const items = [
        { id: "projects", label: "Invitations", icon: "◇" },
        { id: "overview", label: "Overview", icon: "◐" },
        { id: "design", label: "Design", icon: "✦" },
        { id: "share", label: "Share", icon: "↗" },
        { id: "domain", label: "Domain", icon: "◉" },
        { id: "guests", label: "Guests", icon: "◇" },
        { id: "rsvps", label: "RSVPs", icon: "◈" },
        { id: "analytics", label: "Analytics", icon: "◔" },
        { id: "events", label: "Events", icon: "◯" },
        { id: "messages", label: "Messages", icon: "✉" },
        { id: "billing", label: "Payments", icon: "₹" },
        { id: "settings", label: "Settings", icon: "◌" },
    ].filter((item) => !["domain", "events", "messages"].includes(item.id) && !(eff.isApology && ['guests', 'rsvps'].includes(item.id)));
    return (React.createElement("div", { className: "dash-sidebar" },
        React.createElement("div", { className: "dash-user-card" },
            React.createElement("div", { className: "dash-user-avatar" }, (eff.name || "?").charAt(0).toUpperCase()),
            React.createElement("div", { style: { flex: 1, minWidth: 0 } },
                React.createElement("div", { className: "serif", style: { fontSize: 20, fontWeight: 500 } }, [eff.coupleA, eff.coupleB].filter(Boolean).join(" & ") || "Your invitations"),
                React.createElement("div", { style: { fontSize: 11, color: "var(--ink-soft)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, eff.email))),
        React.createElement("label", { className: "dashboard-mobile-switch" },
            React.createElement("span", null, "Invitation workspace"),
            React.createElement("select", { value: activeTab, onChange: event => setActiveTab(event.target.value) }, items.map(item => React.createElement("option", { key: item.id, value: item.id }, item.label)))),
        React.createElement("nav", { className: "dash-nav", "aria-label": "Invitation workspace" }, items.map((it) => (React.createElement("button", { key: it.id, onClick: () => setActiveTab(it.id), className: "dash-nav-item " + (activeTab === it.id ? "active" : ""), "aria-current": activeTab === it.id ? "page" : undefined },
            React.createElement("span", { className: "dash-nav-icon", "aria-hidden": "true" }, it.icon),
            it.label)))),
        React.createElement("div", { className: "dash-sidebar-foot" },
            React.createElement("div", { style: { fontSize: 11, color: "var(--ink-soft)" } },
                React.createElement("div", null,
                    "Status: ",
                    React.createElement("strong", { style: { color: "var(--ink)" } }, eff.plan)),
                React.createElement("div", { style: { marginTop: 4, overflow: "hidden", textOverflow: "ellipsis" } }, eff.domain || "Publish to create a guest link")),
            onSignOut && (React.createElement("button", { className: "dash-sign-out", onClick: onSignOut }, "Sign out")))));
}
function dashTemplateFor(templateId) {
    return TemplateCatalog.get(templateId);
}
function dashProjectTitle(project) {
    const couple = project?.config?.couple || project?.couple || {};
    const names = [couple.bride, couple.groom].filter(Boolean).join(" & ");
    return project?.name || names || "Wedding invitation";
}
function dashSlugPart(value) {
    return String(value || "")
        .trim()
        .toLowerCase()
        .replace(/&/g, " and ")
        .replace(/[^a-z0-9]+/g, "-")
        .replace(/^-+|-+$/g, "");
}
function dashUniqueInviteName(project, eff, projectId) {
    const title = dashSlugPart(dashProjectTitle(project) || [eff?.coupleA, eff?.coupleB].filter(Boolean).join(" and "));
    const template = dashSlugPart(eff?.templateName || project?.template_id || "invite");
    const rawCode = String(project?.slug || project?.id || projectId || "");
    const code = rawCode.replace(/[^a-z0-9]/gi, "").slice(-8).toLowerCase() || "new";
    return [title || "wedding", template || "invite", code].join("-");
}
function copyTextToClipboard(text) {
    const value = String(text || "");
    if (!value)
        return Promise.resolve(false);
    const fallback = () => new Promise((resolve) => {
        const el = document.createElement("textarea");
        el.value = value;
        el.setAttribute("readonly", "");
        el.style.position = "fixed";
        el.style.top = "0";
        el.style.left = "-9999px";
        el.style.opacity = "0";
        document.body.appendChild(el);
        el.focus();
        el.select();
        el.setSelectionRange(0, el.value.length);
        let ok = false;
        try {
            ok = document.execCommand("copy");
        }
        catch (_) {
            ok = false;
        }
        el.remove();
        resolve(ok);
    });
    if (navigator.clipboard && window.isSecureContext) {
        return navigator.clipboard.writeText(value).then(() => true).catch(fallback);
    }
    return fallback();
}
function useDashboardDialog(active, onClose, busy = false) {
    const ref = React.useRef(null), close = React.useRef(onClose), locked = React.useRef(busy);
    close.current = onClose;
    locked.current = busy;
    React.useEffect(() => {
        if (!active)
            return;
        const previous = document.activeElement, overflow = document.body.style.overflow;
        document.body.style.overflow = 'hidden';
        const timer = setTimeout(() => (ref.current?.querySelector('[data-dialog-initial], input, button') || ref.current)?.focus(), 0);
        const onKey = event => {
            if (event.key === 'Escape' && !locked.current) {
                event.preventDefault();
                close.current?.();
            }
            if (event.key !== 'Tab')
                return;
            const controls = Array.from(ref.current?.querySelectorAll('button:not([disabled]), input:not([disabled]), select:not([disabled]), a[href]') || []);
            const first = controls[0], last = controls[controls.length - 1];
            if (!first) {
                event.preventDefault();
                ref.current?.focus();
            }
            else if (event.shiftKey && (document.activeElement === first || !ref.current.contains(document.activeElement))) {
                event.preventDefault();
                last.focus();
            }
            else if (!event.shiftKey && (document.activeElement === last || !ref.current.contains(document.activeElement))) {
                event.preventDefault();
                first.focus();
            }
        };
        document.addEventListener('keydown', onKey);
        return () => { clearTimeout(timer); document.removeEventListener('keydown', onKey); document.body.style.overflow = overflow; previous?.focus?.(); };
    }, [active]);
    return ref;
}
function DashProjects({ projects, projectId, loadProject, deleteProject, goTo }) {
    const [deletingId, setDeletingId] = React.useState(null);
    const [deleteTarget, setDeleteTarget] = React.useState(null);
    const [deleteMsg, setDeleteMsg] = React.useState("");
    const templates = TemplateCatalog.list("builder");
    const sorted = [...(projects || [])].sort((a, b) => new Date(b.updated_at || b.created_at || 0) - new Date(a.updated_at || a.created_at || 0));
    const openProject = (project) => {
        loadProject(project.id, projects);
        window.history.replaceState({ view: "dashboard", projectId: project.id }, "", dashboardAppPath(`/dashboard?project=${encodeURIComponent(project.id)}`));
    };
    const editProject = (project) => {
        const template = dashTemplateFor(project.template_id);
        goTo("builder", { template, projectId: project.id });
    };
    const createNew = (template) => goTo("builder", { template, projectId: null });
    const requestDelete = (project) => {
        if (deletingId)
            return;
        setDeleteMsg("");
        setDeleteTarget(project);
    };
    const closeDelete = () => {
        if (!deletingId)
            setDeleteTarget(null);
    };
    const deleteDialog = useDashboardDialog(Boolean(deleteTarget), closeDelete, Boolean(deletingId));
    const removeProject = async () => {
        const project = deleteTarget;
        if (!project || deletingId)
            return;
        setDeleteMsg("");
        setDeletingId(project.id);
        const result = await deleteProject(project);
        setDeletingId(null);
        if (!result?.ok) {
            setDeleteMsg(result?.reason || "Could not delete invitation.");
            return;
        }
        setDeleteTarget(null);
    };
    React.useEffect(() => {
        if (!deleteTarget)
            return undefined;
        const onKeyDown = (event) => {
            if (event.key === "Escape" && !deletingId)
                setDeleteTarget(null);
        };
        window.addEventListener("keydown", onKeyDown);
        return () => window.removeEventListener("keydown", onKeyDown);
    }, [deleteTarget, deletingId]);
    return (React.createElement("div", null,
        React.createElement("div", { className: "dash-header" },
            React.createElement("div", null,
                React.createElement("div", { className: "eyebrow" }, "Projects"),
                React.createElement("h1", { className: "serif", style: { fontSize: 34, fontWeight: 500, marginTop: 6 } }, "Your invitations"),
                React.createElement("p", { className: "muted", style: { fontSize: 14 } }, "Each invitation has its own data, public link, RSVPs, and analytics."))),
        React.createElement("div", { className: "dash-panel", style: { marginBottom: 20 } },
            React.createElement("div", { className: "dash-panel-hdr" },
                React.createElement("h3", { className: "serif", style: { fontSize: 18, fontWeight: 500 } }, "Create another invitation")),
            React.createElement("div", { className: "dashboard-template-options" }, templates.map((template) => (React.createElement("button", { key: template.id, className: "btn btn-ghost", style: { background: "var(--bg)", justifyContent: "space-between", padding: "14px 16px" }, onClick: () => createNew(template) },
                React.createElement("span", null, template.name),
                React.createElement("span", { style: { color: "var(--accent)" } }, "Start")))))),
        React.createElement("div", { className: "dash-panel dashboard-projects-table", style: { padding: 0, overflow: "hidden" } },
            React.createElement("div", { className: "dash-table-head", style: { gridTemplateColumns: "2fr 1.1fr 1fr 1.3fr 1.7fr", padding: "14px 20px" } },
                React.createElement("span", null, "Invitation"),
                React.createElement("span", null, "Template"),
                React.createElement("span", null, "Status"),
                React.createElement("span", null, "Updated"),
                React.createElement("span", null)),
            deleteMsg && (React.createElement("div", { style: { padding: "12px 20px", color: "#b91c1c", background: "#fee2e2", fontSize: 12 } }, deleteMsg)),
            sorted.length === 0 && (React.createElement("div", { style: { padding: "32px 24px", color: "var(--ink-soft)", fontSize: 13 } }, "No invitations yet. Pick a template above, fill the builder, and publish when ready.")),
            sorted.map((project, index) => {
                const template = dashTemplateFor(project.template_id);
                const isActive = project.id === projectId;
                const published = project.status === "published";
                const updated = project.updated_at || project.created_at;
                return (React.createElement("div", { key: project.id, className: "dash-table-row", "data-last": index === sorted.length - 1, style: { gridTemplateColumns: "2fr 1.1fr 1fr 1.3fr 1.7fr", padding: "16px 20px", background: isActive ? "color-mix(in oklab, var(--gold) 10%, var(--bg))" : undefined } },
                    React.createElement("span", null,
                        React.createElement("strong", { style: { display: "block", fontSize: 13 } }, dashProjectTitle(project)),
                        React.createElement("span", { style: { display: "block", color: "var(--ink-soft)", fontSize: 11, overflow: "hidden", textOverflow: "ellipsis" } }, project.slug ? window.location.host + dashboardAppPath(`/p/${encodeURIComponent(project.slug)}`) : "Link will appear after publishing")),
                    React.createElement("span", { "data-label": "Template" }, template?.name || project.template_id),
                    React.createElement("span", { "data-label": "Status" },
                        React.createElement("span", { className: "dash-rsvp-badge " + (published ? "good" : "neutral") }, published ? "Live" : "Draft")),
                    React.createElement("span", { "data-label": "Updated", style: { color: "var(--ink-soft)" } }, updated ? new Date(updated).toLocaleString("en-IN") : "-"),
                    React.createElement("span", { className: "dashboard-row-actions", style: { display: "flex", justifyContent: "flex-end", gap: 8 } },
                        React.createElement("button", { className: "dash-link", onClick: () => openProject(project) }, isActive ? "Selected" : "Select"),
                        React.createElement("button", { className: "dash-link", onClick: () => editProject(project) }, "Edit"),
                        published && project.slug && React.createElement("button", { className: "dash-link", onClick: () => window.open(dashboardAppPath(`/p/${encodeURIComponent(project.slug)}`), "_blank", "noopener") }, "View \u2197"),
                        React.createElement("button", { className: "dash-link danger", onClick: () => requestDelete(project), disabled: deletingId === project.id }, deletingId === project.id ? "Deleting..." : "Delete"))));
            })),
        deleteTarget && (React.createElement("div", { className: "dash-confirm-overlay", onMouseDown: (event) => event.target === event.currentTarget && closeDelete() },
            React.createElement("div", { ref: deleteDialog, tabIndex: -1, className: "dash-confirm-modal", role: "dialog", "aria-modal": "true", "aria-labelledby": "delete-project-title" },
                React.createElement("button", { className: "dash-confirm-close", onClick: closeDelete, disabled: !!deletingId, "aria-label": "Close delete confirmation" }, "\u00D7"),
                React.createElement("div", { className: "eyebrow" }, "Delete invitation"),
                React.createElement("h2", { id: "delete-project-title", className: "serif" },
                    "Delete ",
                    dashProjectTitle(deleteTarget),
                    "?"),
                React.createElement("p", null, "This will remove the invitation, public link, RSVP responses, and analytics for this project. This action cannot be undone."),
                React.createElement("div", { className: "dash-confirm-summary" },
                    React.createElement("span", null, "Template"),
                    React.createElement("strong", null, dashTemplateFor(deleteTarget.template_id)?.name || deleteTarget.template_id || "Wedding invitation"),
                    React.createElement("span", null, "Public link"),
                    React.createElement("strong", null, deleteTarget.slug ? window.location.host + dashboardAppPath(`/p/${encodeURIComponent(deleteTarget.slug)}`) : "Not published yet")),
                React.createElement("div", { className: "dash-confirm-actions" },
                    React.createElement("button", { "data-dialog-initial": true, className: "btn btn-ghost", onClick: closeDelete, disabled: !!deletingId }, "Cancel"),
                    React.createElement("button", { className: "btn btn-primary dash-confirm-delete", onClick: removeProject, disabled: !!deletingId }, deletingId ? "Deleting..." : "Delete invitation")))))));
}
function DashboardEmpty({ goTo }) {
    return React.createElement("section", { className: "account-empty" },
        React.createElement("div", { className: "account-monogram", "aria-hidden": "true" }, "e"),
        React.createElement("h1", { className: "serif" }, "A beautiful beginning."),
        React.createElement("p", null, "Choose a design and make it yours. Your saved invitation, guest list, and RSVPs will live here."),
        React.createElement("button", { className: "btn btn-primary", onClick: () => goTo("builder", { projectId: null }) }, "Create your first invitation"),
        React.createElement("button", { className: "account-text-button", onClick: () => goTo("gallery") }, "Explore templates"));
}
function DashOverview({ eff, project, goTo, setActiveTab, guests, rsvps, rsvpsUnavailable = false }) {
    if (!project)
        return React.createElement(DashboardEmpty, { goTo: goTo });
    if (eff.isApology)
        return React.createElement("div", null,
            React.createElement("div", { className: "dash-header" },
                React.createElement("div", null,
                    React.createElement("div", { className: "eyebrow" }, "Your personal keepsake"),
                    React.createElement("h1", { className: "serif", style: { fontSize: 34, fontWeight: 500, marginTop: 6 } }, dashProjectTitle(project)),
                    React.createElement("p", { className: "muted" },
                        "Your words, photographs and a little courage, kept together in ",
                        eff.templateName,
                        "."))),
            React.createElement("div", { className: "dash-panel" },
                React.createElement("h2", { className: "serif" }, eff.status === 'published' ? 'Ready for someone special' : 'Make it feel like you'),
                React.createElement("p", null, eff.status === 'published' ? 'Your link opens the complete experience with your saved words and memories. You can return to the builder to update them.' : 'Add your message and favourite photographs, then preview the opening before you publish.'),
                React.createElement("div", { style: { display: 'flex', gap: 12, flexWrap: 'wrap', marginTop: 20 } },
                    React.createElement("button", { className: "btn btn-primary", onClick: () => goTo('builder', { template: dashTemplateFor(project.template_id), projectId: project.id }) }, "Continue editing"),
                    eff.status === 'published' && React.createElement("button", { className: "btn btn-secondary", onClick: () => setActiveTab('share') }, "Share your keepsake"))));
    const acceptedGuests = guests.filter(g => g.status === "yes");
    const pendingGuests = guests.filter(g => g.status === "pending");
    const acceptedRsvps = rsvps.filter(r => r.status === "yes");
    const declinedRsvps = rsvps.filter(r => r.status === "no");
    const plusOnes = acceptedRsvps.reduce((sum, r) => sum + (r.plus || 0), 0);
    const targetDate = parseDashDate(eff.weddingDate);
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const days = targetDate ? Math.max(0, Math.ceil((targetDate.getTime() - today.getTime()) / 86400000)) : null;
    const weddingDateLabel = targetDate
        ? [formatDashDate(eff.weddingDate), eff.weddingTime ? `around ${eff.weddingTime}` : ""].filter(Boolean).join(" · ")
        : "Set wedding date in builder";
    const headcount = acceptedRsvps.reduce((sum, r) => sum + 1 + (r.plus || 0), 0);
    const pending = pendingGuests;
    const stats = [
        { l: "Guest list", v: String(guests.length), d: guests.length ? `${acceptedGuests.length} accepted · ${pending.length} pending` : "Add guests or import a CSV" },
        { l: "RSVPs received", v: rsvpsUnavailable ? "—" : String(rsvps.length), d: rsvpsUnavailable ? "Responses could not be loaded" : `${acceptedRsvps.length} accepted · ${declinedRsvps.length} declined` },
        { l: "Attending headcount", v: rsvpsUnavailable ? "—" : String(headcount), d: rsvpsUnavailable ? "Responses could not be loaded" : `includes ${plusOnes} plus-one${plusOnes === 1 ? "" : "s"}` },
        { l: "Days to go", v: targetDate ? String(days) : "—", d: weddingDateLabel },
    ];
    const recent = rsvps.slice(0, 5);
    const currentTemplate = dashTemplateFor(project?.template_id || eff.templateId);
    const editCurrentProject = () => goTo("builder", { template: currentTemplate, projectId: project?.id || null });
    return (React.createElement("div", null,
        React.createElement("div", { className: "dash-header" },
            React.createElement("div", null,
                React.createElement("div", { className: "eyebrow" }, "Overview"),
                React.createElement("h1", { className: "serif", style: { fontSize: 34, fontWeight: 500, marginTop: 6 } },
                    "Hello, ",
                    (eff.name || "there").split(" ")[0],
                    "."),
                React.createElement("p", { className: "muted", style: { fontSize: 14 } }, "Your invitation, guests, RSVPs, and public link live here.")),
            React.createElement("div", { style: { display: "flex", gap: 8 } },
                React.createElement("button", { className: "btn btn-ghost", style: { background: "var(--bg)" }, onClick: () => eff.status === "published" && eff.slug ? window.open(dashboardAppPath(`/p/${encodeURIComponent(eff.slug)}`), "_blank", "noopener") : editCurrentProject() }, eff.status === "published" && eff.slug ? "View invitation" : "Edit invitation"),
                React.createElement("button", { className: "btn btn-primary", onClick: () => setActiveTab("guests") }, guests.length ? "Manage guests" : "Add guests"))),
        React.createElement("div", { className: "dash-stats" }, stats.map((s) => (React.createElement("div", { key: s.l, className: "dash-stat-card" },
            React.createElement("div", { className: "eyebrow", style: { fontSize: 10, marginBottom: 10 } }, s.l),
            React.createElement("div", { className: "serif", style: { fontSize: 38, fontWeight: 400, color: "var(--ink)", lineHeight: 1 } }, s.v),
            React.createElement("div", { style: { fontSize: 12, color: "var(--ink-soft)", marginTop: 6 } }, s.d))))),
        React.createElement("div", { className: "dashboard-overview-grid" },
            React.createElement("div", { className: "dash-panel" },
                React.createElement("div", { className: "dash-panel-hdr" },
                    React.createElement("h3", { className: "serif", style: { fontSize: 18, fontWeight: 500 } }, "Recent RSVPs"),
                    React.createElement("button", { className: "dash-link", onClick: () => setActiveTab("rsvps") }, "View all \u2192")),
                recent.length === 0 && (React.createElement("div", { style: { padding: "24px 0", color: "var(--ink-soft)", fontSize: 14 } }, rsvpsUnavailable ? "Retry loading your guest responses above." : "Once you share your invitation, guest responses will appear here.")),
                recent.map((r, i) => (React.createElement("div", { key: r.id, className: "dash-row", "data-first": i === 0 },
                    React.createElement("div", { className: "dash-row-avatar " + (r.status === "yes" ? "good" : "neutral") }, r.n[0]),
                    React.createElement("div", { style: { flex: 1, minWidth: 0 } },
                        React.createElement("div", { style: { fontSize: 13, fontWeight: 500 } },
                            r.n,
                            r.plus ? React.createElement("span", { style: { color: "var(--ink-soft)", fontWeight: 400 } },
                                " +",
                                r.plus) : null),
                        React.createElement("div", { style: { fontSize: 12, color: "var(--ink-soft)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } },
                            r.status === "yes" ? "Joyfully accepted" : "Regretfully declined",
                            " \u00B7 ",
                            r.events.join(", ") || "—")),
                    React.createElement("div", { style: { fontSize: 11, color: "var(--ink-soft)" } }, relativeTime(r.when)))))),
            React.createElement("div", { className: "dash-panel" },
                React.createElement("div", { className: "dash-panel-hdr" },
                    React.createElement("h3", { className: "serif", style: { fontSize: 18, fontWeight: 500 } }, "Next up")),
                [
                    { d: project ? "Invitation project saved" : "Create your invitation project", t: project ? eff.templateName : "Choose a template and open the builder", due: project ? "ready" : "open builder", done: Boolean(project), action: "design" },
                    { d: eff.status === "published" ? "Invitation is published" : "Publish the invitation", t: eff.domain || "Create the guest link", due: eff.domain ? "share" : "dashboard", done: eff.status === "published", action: "share" },
                    { d: guests.length ? "Guest list started" : "Add your first guests", t: guests.length ? `${guests.length} saved guests` : "Manual entry or CSV import", due: guests.length ? "saved" : "add guests", done: guests.length > 0, action: "guests" },
                    { d: rsvps.length ? "Review RSVP responses" : "Wait for guest RSVPs", t: rsvps.length ? `${rsvps.length} received` : "Responses appear here after sharing", due: rsvps.length ? "review" : "after share", done: rsvps.length > 0, action: "rsvps" },
                ].map((task, i) => (React.createElement("button", { key: i, type: "button", className: "dash-row dashboard-next-action", "data-first": i === 0, onClick: () => setActiveTab(task.action) },
                    React.createElement("span", { className: "dash-checkbox", "aria-hidden": "true" }, task.done ? "✓" : ""),
                    React.createElement("div", { style: { flex: 1 } },
                        React.createElement("div", { style: { fontSize: 13, fontWeight: 500 } }, task.d),
                        React.createElement("div", { style: { fontSize: 12, color: "var(--ink-soft)" } }, task.t)))))))));
}
function parseCsvRows(text) {
    const rows = [];
    let row = [];
    let cell = "";
    let quoted = false;
    for (let i = 0; i < text.length; i++) {
        const ch = text[i];
        const next = text[i + 1];
        if (ch === '"') {
            if (quoted && next === '"') {
                cell += '"';
                i++;
            }
            else
                quoted = !quoted;
        }
        else if (ch === "," && !quoted) {
            row.push(cell);
            cell = "";
        }
        else if ((ch === "\n" || ch === "\r") && !quoted) {
            if (ch === "\r" && next === "\n")
                i++;
            row.push(cell);
            if (row.some((value) => String(value).trim()))
                rows.push(row);
            row = [];
            cell = "";
        }
        else {
            cell += ch;
        }
    }
    row.push(cell);
    if (row.some((value) => String(value).trim()))
        rows.push(row);
    return rows;
}
function normalizeGuestSide(value) {
    const v = String(value || "").trim().toLowerCase();
    if (v.startsWith("groom") || v === "g")
        return "Groom";
    if (v.startsWith("bride") || v === "b")
        return "Bride";
    return "Bride";
}
function normalizeGuestStatus(value) {
    const v = String(value || "").trim().toLowerCase();
    if (["yes", "accepted", "accept", "attending"].includes(v))
        return "yes";
    if (["no", "declined", "decline", "not attending"].includes(v))
        return "no";
    return "pending";
}
function csvEscape(value) {
    const text = String(value ?? "");
    return /[",\r\n]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text;
}
function downloadCsvFile(filename, rows) {
    const csv = rows.map((row) => row.map(csvEscape).join(",")).join("\r\n");
    const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    a.remove();
    setTimeout(() => URL.revokeObjectURL(url), 1000);
}
function guestCsvRows(guests) {
    const header = ["Name", "Email", "Phone", "Side", "Group", "Status", "Events", "Plus Ones", "Diet"];
    const rows = guests.map((g) => [
        g.n || "",
        g.email || "",
        g.phone || "",
        normalizeGuestSide(g.side),
        g.group || "Other",
        g.status || "pending",
        g.events ?? 0,
        g.plus ?? 0,
        g.diet || "-",
    ]);
    return [header, ...rows];
}
function downloadGuestSample() {
    downloadCsvFile("everafter-guest-import-sample.csv", [
        ["Name", "Email", "Phone", "Side", "Group", "Status", "Events", "Plus Ones", "Diet"],
        ["Anjali Mehta", "anjali@example.com", "+91 98201 12345", "Bride", "Family", "pending", "0", "0", "Veg"],
        ["Vikram Shah", "vikram@example.com", "+91 98765 43210", "Groom", "College", "pending", "0", "1", "Jain"],
    ]);
}
function parseGuestCsv(text) {
    const rows = parseCsvRows(text);
    if (!rows.length)
        return [];
    const header = rows[0].map(h => String(h || "").toLowerCase().trim().replace(/^"|"$/g, ""));
    const col = (row, names) => {
        for (const n of names) {
            const i = header.indexOf(n);
            if (i >= 0 && row[i] !== undefined && String(row[i]).trim())
                return String(row[i]).trim();
        }
        return "";
    };
    return rows.slice(1).map((row, idx) => {
        const name = col(row, ["name", "full name", "guest name", "guest"]);
        if (!name)
            return null;
        return {
            id: "csv-" + idx + "-" + Date.now(),
            n: name,
            email: col(row, ["email", "email address"]),
            phone: col(row, ["phone", "mobile", "phone number", "whatsapp"]),
            side: normalizeGuestSide(col(row, ["side", "family side", "bride or groom side"])),
            group: col(row, ["group", "category"]) || "Other",
            status: normalizeGuestStatus(col(row, ["status", "rsvp status", "response"])),
            events: parseInt(col(row, ["events", "event count"]) || "0", 10) || 0,
            plus: parseInt(col(row, ["plus", "plus ones", "plus-ones", "plus one"]) || "0", 10) || 0,
            diet: col(row, ["diet", "dietary", "food"]) || "-",
        };
    }).filter(Boolean);
}
function DashGuests({ guests, persistGuests, saving = false, unavailable = false }) {
    const [filter, setFilter] = React.useState("All");
    const [editing, setEditing] = React.useState(null);
    const [addOpen, setAddOpen] = React.useState(false);
    const [csvMsg, setCsvMsg] = React.useState("");
    const csvRef = React.useRef(null);
    const [importing, setImporting] = React.useState(false);
    const busy = saving || importing || unavailable;
    const brideCount = guests.filter(g => normalizeGuestSide(g.side) === "Bride").length;
    const groomCount = guests.filter(g => normalizeGuestSide(g.side) === "Groom").length;
    const importCsv = (e) => {
        const file = e.target.files[0];
        if (!file)
            return;
        if (busy)
            return;
        if (file.size > 2 * 1024 * 1024) {
            setCsvMsg("Choose a CSV smaller than 2 MB.");
            e.target.value = "";
            return;
        }
        setImporting(true);
        const reader = new FileReader();
        reader.onload = async (ev) => {
            try {
                const parsed = parseGuestCsv(ev.target.result);
                if (!parsed.length) {
                    setCsvMsg("No valid rows found. Ensure the file has a 'Name' column.");
                    return;
                }
                const merged = [...guests];
                let added = 0;
                parsed.forEach(g => {
                    if (!merged.some(x => x.n.toLowerCase() === g.n.toLowerCase())) {
                        merged.push(g);
                        added++;
                    }
                });
                const saved = await persistGuests(merged);
                setCsvMsg(saved ? `Imported and saved ${added} guest${added !== 1 ? "s" : ""} (${parsed.length - added} duplicates skipped).` : "Imported on this page. Your account has not been updated yet; use Save guest changes above to retry.");
            }
            catch (_) {
                setCsvMsg("This CSV could not be imported. Check the sample format and try again.");
            }
            finally {
                setImporting(false);
            }
        };
        reader.onerror = () => { setCsvMsg("This file could not be read. Choose it again and retry."); setImporting(false); };
        reader.readAsText(file);
        e.target.value = "";
    };
    const exportGuests = () => {
        downloadCsvFile("everafter-guests-export.csv", guestCsvRows(guests));
        setCsvMsg(`Exported ${guests.length} guest${guests.length !== 1 ? "s" : ""}.`);
        setTimeout(() => setCsvMsg(""), 2500);
    };
    const accept = guests.filter(g => g.status === "yes").length;
    const filtered = guests.filter((g) => {
        if (filter === "All")
            return true;
        if (filter === "Pending")
            return g.status === "pending";
        if (filter === "Accepted")
            return g.status === "yes";
        if (filter === "Declined")
            return g.status === "no";
        if (filter === "Bride's side")
            return normalizeGuestSide(g.side) === "Bride";
        if (filter === "Groom's side")
            return normalizeGuestSide(g.side) === "Groom";
        return true;
    });
    const updateStatus = (id, status) => {
        persistGuests(guests.map(g => g.id === id ? { ...g, status } : g));
    };
    const saveGuest = (g) => {
        if (g.id)
            persistGuests(guests.map(x => x.id === g.id ? g : x));
        else
            persistGuests([...guests, { ...g, id: "g" + Date.now() }]);
        setEditing(null);
        setAddOpen(false);
    };
    const removeGuest = (id) => {
        if (!window.confirm("Remove this guest?"))
            return;
        persistGuests(guests.filter(g => g.id !== id));
        setEditing(null);
    };
    return (React.createElement("div", null,
        React.createElement("div", { className: "dash-header" },
            React.createElement("div", null,
                React.createElement("div", { className: "eyebrow" }, "Guests"),
                React.createElement("h1", { className: "serif", style: { fontSize: 30, fontWeight: 500 } }, "Your guest list"),
                React.createElement("p", { className: "muted" },
                    guests.length,
                    " ",
                    guests.length === 1 ? "guest" : "guests",
                    " \u00B7 ",
                    accept,
                    " accepted")),
            React.createElement("div", { style: { display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap", justifyContent: "flex-end" } },
                React.createElement("input", { ref: csvRef, type: "file", accept: ".csv,text/csv,application/vnd.ms-excel", onChange: importCsv, style: { display: "none" } }),
                React.createElement("button", { className: "btn btn-ghost", style: { background: "var(--bg)" }, onClick: downloadGuestSample }, "Download sample CSV"),
                React.createElement("button", { className: "btn btn-ghost", style: { background: "var(--bg)" }, onClick: exportGuests, disabled: !guests.length }, "Export CSV"),
                React.createElement("button", { className: "btn btn-ghost", style: { background: "var(--bg)" }, disabled: busy, onClick: () => csvRef.current?.click() }, importing ? "Importing…" : "Import CSV"),
                React.createElement("button", { className: "btn btn-primary", disabled: busy, onClick: () => setAddOpen(true) }, "+ Add guest")),
            csvMsg && React.createElement("div", { role: "status", style: { marginTop: 8, fontSize: 13, color: "var(--accent)", fontWeight: 500 } }, csvMsg)),
        saving && React.createElement("p", { className: "account-feedback", role: "status" }, "Saving guest changes\u2026"),
        React.createElement("div", { className: "dash-stats", style: { marginBottom: 16 } },
            React.createElement("div", { className: "dash-stat-card" },
                React.createElement("div", { className: "eyebrow", style: { fontSize: 10, marginBottom: 8 } }, "Bride side"),
                React.createElement("div", { className: "serif", style: { fontSize: 30, fontWeight: 400 } }, brideCount)),
            React.createElement("div", { className: "dash-stat-card" },
                React.createElement("div", { className: "eyebrow", style: { fontSize: 10, marginBottom: 8 } }, "Groom side"),
                React.createElement("div", { className: "serif", style: { fontSize: 30, fontWeight: 400 } }, groomCount))),
        React.createElement("div", { style: { display: "flex", gap: 8, marginBottom: 16, flexWrap: "wrap" } }, ["All", "Pending", "Accepted", "Declined", "Bride's side", "Groom's side"].map((f) => (React.createElement("button", { key: f, "aria-pressed": filter === f, onClick: () => setFilter(f), className: "dash-filter " + (filter === f ? "active" : "") }, f)))),
        React.createElement("div", { className: "dash-table dashboard-guests-table" },
            React.createElement("div", { className: "dash-table-head" },
                React.createElement("span", null, "Name"),
                React.createElement("span", null, "Side"),
                React.createElement("span", null, "Group"),
                React.createElement("span", null, "Status"),
                React.createElement("span", null, "Events"),
                React.createElement("span", null, "Diet"),
                React.createElement("span", null)),
            guests.length === 0 && (React.createElement("div", { style: { padding: "28px 20px", textAlign: "center", color: "var(--ink-soft)", fontSize: 13 } }, "No guests yet. Add one manually or import a CSV to start sending invitations.")),
            filtered.map((g, i) => (React.createElement("div", { key: g.id, className: "dash-table-row", "data-last": i === filtered.length - 1 },
                React.createElement("span", { style: { fontWeight: 500 } },
                    g.n,
                    g.plus ? React.createElement("span", { style: { color: "var(--ink-soft)", fontWeight: 400 } },
                        " +",
                        g.plus) : null,
                    g.email && React.createElement("div", { className: "muted", style: { fontSize: 11 } }, g.email)),
                React.createElement("span", { "data-label": "Side", style: { color: "var(--ink-soft)" } }, g.side),
                React.createElement("span", { "data-label": "Group", style: { color: "var(--ink-soft)" } }, g.group),
                React.createElement("span", { "data-label": "Response" },
                    React.createElement("select", { "aria-label": `Response for ${g.n}`, disabled: busy, value: g.status, onChange: (e) => updateStatus(g.id, e.target.value), className: "dash-status-select status-" + g.status },
                        React.createElement("option", { value: "pending" }, "Pending"),
                        React.createElement("option", { value: "yes" }, "Accepted"),
                        React.createElement("option", { value: "no" }, "Declined"))),
                React.createElement("span", { "data-label": "Events", style: { color: "var(--ink-soft)" } }, g.events || 0),
                React.createElement("span", { "data-label": "Diet", style: { color: "var(--ink-soft)" } }, g.diet),
                React.createElement("span", { className: "dashboard-row-actions", style: { display: "flex", gap: 6, justifyContent: "flex-end" } },
                    React.createElement("button", { className: "dash-icon-btn", disabled: busy, onClick: () => setEditing(g), title: "Edit", "aria-label": `Edit ${g.n}` }, "\u270E"),
                    React.createElement("button", { className: "dash-icon-btn", disabled: busy, onClick: () => removeGuest(g.id), title: "Remove", "aria-label": `Remove ${g.n}` }, "\u00D7"))))),
            guests.length > 0 && filtered.length === 0 && (React.createElement("div", { style: { padding: "32px 20px", textAlign: "center", color: "var(--ink-soft)", fontSize: 13 } },
                "No guests match \"",
                filter,
                "\"."))),
        (editing || addOpen) && (React.createElement(GuestEditModal, { initial: editing, onClose: () => { setEditing(null); setAddOpen(false); }, onSave: saveGuest }))));
}
function GuestEditModal({ initial, onClose, onSave }) {
    const [g, setG] = React.useState(initial || { n: "", side: "Bride", group: "Family", status: "pending", events: 0, plus: 0, diet: "—", email: "", phone: "" });
    const update = (k, v) => setG({ ...g, [k]: v });
    const dialog = useDashboardDialog(true, onClose);
    return (React.createElement("div", { className: "signin-overlay account-auth-overlay", onClick: (e) => { if (e.target === e.currentTarget)
            onClose(); } },
        React.createElement("div", { ref: dialog, tabIndex: -1, className: "signin-modal account-auth-modal", style: { maxWidth: 520 }, role: "dialog", "aria-modal": "true", "aria-labelledby": "guest-dialog-title" },
            React.createElement("button", { className: "signin-close", onClick: onClose, "aria-label": "Close guest details" }, "\u00D7"),
            React.createElement("h2", { id: "guest-dialog-title", className: "serif", style: { fontSize: 28, fontWeight: 500, marginBottom: 24 } }, initial ? "Edit guest" : "Add guest"),
            React.createElement("form", { onSubmit: event => { event.preventDefault(); if (g.n.trim())
                    onSave({ ...g, n: g.n.trim() }); } },
                React.createElement("div", { className: "dash-form-grid" },
                    React.createElement(DashField, { label: "Name", value: g.n, onChange: (v) => update("n", v) }),
                    React.createElement(DashField, { label: "Email", type: "email", value: g.email || "", onChange: (v) => update("email", v) }),
                    React.createElement(DashField, { label: "Phone", type: "tel", value: g.phone || "", onChange: (v) => update("phone", v), placeholder: "+91 \u2026" }),
                    React.createElement(DashSelect, { label: "Side", value: g.side, onChange: (v) => update("side", v), options: ["Bride", "Groom"] }),
                    React.createElement(DashSelect, { label: "Group", value: g.group, onChange: (v) => update("group", v), options: ["Family", "College", "Work", "School", "Other"] }),
                    React.createElement(DashSelect, { label: "Status", value: g.status, onChange: (v) => update("status", v), options: [["pending", "Pending"], ["yes", "Accepted"], ["no", "Declined"]] }),
                    React.createElement(DashSelect, { label: "Diet", value: g.diet, onChange: (v) => update("diet", v), options: ["—", "Veg", "Vegan", "Jain", "Halal", "Kosher"] }),
                    React.createElement(DashField, { label: "Plus-ones", type: "number", value: String(g.plus), onChange: (v) => update("plus", Math.max(0, parseInt(v || "0", 10) || 0)) })),
                React.createElement("div", { style: { display: "flex", gap: 8, marginTop: 18, justifyContent: "flex-end" } },
                    React.createElement("button", { type: "button", className: "btn btn-ghost", onClick: onClose }, "Cancel"),
                    React.createElement("button", { type: "submit", className: "btn btn-primary", disabled: !g.n.trim() }, initial ? "Save changes" : "Add guest"))))));
}
function DashField({ label, value, onChange, type = "text", placeholder = "" }) {
    return (React.createElement("label", { className: "dash-field" },
        React.createElement("span", null, label),
        React.createElement("input", { type: type, min: type === "number" ? 0 : undefined, value: value || "", onChange: (e) => onChange(e.target.value), placeholder: placeholder })));
}
function DashSelect({ label, value, onChange, options }) {
    const selectedValue = value ?? "";
    const hasCurrentOption = options.some(option => String(Array.isArray(option) ? option[0] : option) === String(selectedValue));
    return (React.createElement("label", { className: "dash-field" },
        React.createElement("span", null, label),
        React.createElement("select", { value: selectedValue, onChange: (e) => onChange(e.target.value) },
            !hasCurrentOption && React.createElement("option", { value: selectedValue }, selectedValue || "—"),
            options.map((o) => {
                const [v, l] = Array.isArray(o) ? o : [o, o];
                return React.createElement("option", { key: v, value: v }, l);
            }))));
}
function DashRsvps({ rsvps, guests = [] }) {
    const [filter, setFilter] = React.useState("All");
    const responseLabel = (status) => status === "yes" ? "Accepted" : (status === "maybe" ? "Maybe" : "Declined");
    const responseDetail = (r) => {
        if (r.events.length)
            return r.events.join(", ");
        if (r.status === "yes")
            return "Attending";
        if (r.status === "maybe")
            return "Maybe attending";
        return "Will not attend";
    };
    const sideByName = new Map(guests
        .filter((g) => g.n)
        .map((g) => [String(g.n).trim().toLowerCase(), normalizeGuestSide(g.side)]));
    const enriched = rsvps.map((r) => ({
        ...r,
        side: sideByName.get(String(r.n || "").trim().toLowerCase()) || "Unassigned",
    }));
    const brideRsvps = enriched.filter((r) => r.side === "Bride");
    const groomRsvps = enriched.filter((r) => r.side === "Groom");
    const filtered = enriched.filter((r) => {
        if (filter === "All")
            return true;
        if (filter === "Accepted")
            return r.status === "yes";
        if (filter === "Declined")
            return r.status === "no";
        if (filter === "Bride's side")
            return r.side === "Bride";
        if (filter === "Groom's side")
            return r.side === "Groom";
        return true;
    });
    const eventCounts = enriched.reduce((acc, r) => {
        (r.events || []).forEach((name) => { acc[name] = (acc[name] || 0) + 1; });
        return acc;
    }, {});
    const eventStats = Object.entries(eventCounts).map(([l, v]) => ({ l, v, t: "responses" }));
    if (!eventStats.length) {
        eventStats.push({ l: "Accepted", v: enriched.filter(r => r.status === "yes").length, t: "responses" }, { l: "Declined", v: enriched.filter(r => r.status === "no").length, t: "responses" }, { l: "Maybe", v: enriched.filter(r => r.status === "maybe").length, t: "responses" }, { l: "Total", v: enriched.length, t: "responses" });
    }
    const sideStats = [
        { l: "Bride side", v: brideRsvps.length, d: `${brideRsvps.filter(r => r.status === "yes").length} accepted` },
        { l: "Groom side", v: groomRsvps.length, d: `${groomRsvps.filter(r => r.status === "yes").length} accepted` },
    ];
    return (React.createElement("div", null,
        React.createElement("div", { className: "dash-header" },
            React.createElement("div", null,
                React.createElement("div", { className: "eyebrow" }, "RSVPs"),
                React.createElement("h1", { className: "serif", style: { fontSize: 30, fontWeight: 500 } }, "Guest responses")),
            React.createElement("div", { style: { fontSize: 12, color: "var(--ink-soft)", display: "inline-flex", alignItems: "center", gap: 8 } }, "Refresh the page to check for new responses.")),
        React.createElement("div", { className: "dash-stats", style: { marginBottom: 18 } }, eventStats.map((e) => (React.createElement("div", { key: e.l, className: "dash-stat-card" },
            React.createElement("div", { className: "eyebrow", style: { fontSize: 10, marginBottom: 8 } }, e.l),
            React.createElement("div", { style: { display: "flex", alignItems: "baseline", gap: 6 } },
                React.createElement("span", { className: "serif", style: { fontSize: 30, fontWeight: 400 } }, e.v),
                React.createElement("span", { style: { fontSize: 12, color: "var(--ink-soft)" } }, e.t)))))),
        React.createElement("div", { className: "dash-panel", style: { marginBottom: 18 } },
            React.createElement("div", { className: "dash-panel-hdr" },
                React.createElement("h3", { className: "serif", style: { fontSize: 18, fontWeight: 500 } }, "Side breakdown"),
                React.createElement("span", { style: { fontSize: 11, color: "var(--ink-soft)" } }, "matched from guest list")),
            React.createElement("div", { className: "dash-stats" }, sideStats.map((s) => (React.createElement("div", { key: s.l, className: "dash-stat-card" },
                React.createElement("div", { className: "eyebrow", style: { fontSize: 10, marginBottom: 8 } }, s.l),
                React.createElement("div", { className: "serif", style: { fontSize: 30, fontWeight: 400 } }, s.v),
                React.createElement("div", { style: { fontSize: 12, color: "var(--ink-soft)", marginTop: 4 } }, s.d)))))),
        React.createElement("div", { style: { display: "flex", gap: 8, marginBottom: 16, flexWrap: "wrap" } }, ["All", "Accepted", "Declined", "Bride's side", "Groom's side"].map((f) => (React.createElement("button", { key: f, "aria-pressed": filter === f, onClick: () => setFilter(f), className: "dash-filter " + (filter === f ? "active" : "") }, f)))),
        React.createElement("div", { className: "dash-rsvp-inbox" },
            filtered.map((r) => (React.createElement("div", { key: r.id, className: "dash-rsvp-item" },
                React.createElement("div", { className: "dash-rsvp-avatar " + (r.status === "yes" ? "good" : "neutral") }, (r.n || "?")[0]),
                React.createElement("div", { style: { flex: 1, minWidth: 0 } },
                    React.createElement("div", { style: { display: "flex", alignItems: "baseline", gap: 8, flexWrap: "wrap" } },
                        React.createElement("strong", { style: { fontSize: 14 } }, r.n),
                        r.plus ? React.createElement("span", { style: { fontSize: 12, color: "var(--ink-soft)" } },
                            "+ ",
                            r.plus,
                            " plus-one",
                            r.plus > 1 ? "s" : "") : null,
                        React.createElement("span", { className: "dash-rsvp-badge " + (r.status === "yes" ? "good" : "neutral") }, responseLabel(r.status)),
                        React.createElement("span", { className: "dash-rsvp-badge neutral" }, r.side)),
                    React.createElement("div", { style: { fontSize: 12, color: "var(--ink-soft)", margin: "4px 0 6px" } },
                        responseDetail(r),
                        " - ",
                        relativeTime(r.when)),
                    r.note && (React.createElement("div", { className: "dash-rsvp-note" },
                        "\"",
                        r.note,
                        "\"")))))),
            filtered.length === 0 && (React.createElement("div", { style: { padding: 32, textAlign: "center", color: "var(--ink-soft)", fontSize: 13 } }, rsvps.length ? "No responses match this filter." : "No responses yet.")))));
}
function DashAnalytics({ analytics, rsvps }) {
    const [range, setRange] = React.useState("30");
    const [activeMetric, setActiveMetric] = React.useState("Views");
    const [activeEvent, setActiveEvent] = React.useState(null);
    const [activeResponse, setActiveResponse] = React.useState("yes");
    const rangeDays = range === "7" ? 7 : (range === "30" ? 30 : null);
    const now = Date.now();
    const scopedRsvps = rsvps.filter((r) => !rangeDays || (r.when && r.when >= now - rangeDays * 86400000));
    const accepts = scopedRsvps.filter(r => r.status === "yes").length;
    const declines = scopedRsvps.filter(r => r.status === "no").length;
    const maybes = scopedRsvps.filter(r => r.status === "maybe").length;
    const totalResponses = scopedRsvps.length;
    const headcount = scopedRsvps.reduce((sum, r) => sum + (r.status === "yes" ? 1 + (r.plus || 0) : 0), 0);
    const totalViews = analytics ? parseInt(analytics.summary?.views || 0, 10) : null;
    const uniqueVisitors = analytics ? parseInt(analytics.summary?.unique_views || 0, 10) : null;
    const fmt = (v) => v === null || Number.isNaN(v) ? "-" : Number(v).toLocaleString("en-IN");
    const rangeLabel = range === "all" ? "Since launch" : `Last ${range} days`;
    const rawEvents = (analytics?.events || []).map((row) => ({
        l: row.event_type || "event",
        v: parseInt(row.count || 0, 10) || 0,
        unique: parseInt(row.unique_visitors || 0, 10) || 0,
    }));
    const eventRows = rawEvents.length ? rawEvents : [{ l: "No events yet", v: 0, unique: 0 }];
    const maxEventCount = Math.max(1, ...eventRows.map((row) => row.v));
    const topEvent = rawEvents[0] || null;
    const metrics = [
        { l: "Views", v: totalViews || 0, d: totalViews !== null ? "invite opens since launch" : "No data yet", tone: "#2a2520" },
        { l: "Unique visitors", v: uniqueVisitors || 0, d: uniqueVisitors !== null ? "distinct devices since launch" : "No data yet", tone: "#8a6c78" },
        { l: "RSVPs", v: totalResponses, d: `${rangeLabel.toLowerCase()} responses`, tone: "#7d6aa8" },
        { l: "Attending headcount", v: headcount, d: `${accepts} accepted guests plus ones`, tone: "#2f8f60" },
    ];
    const maxMetric = Math.max(1, ...metrics.map((m) => m.v));
    const selectedMetric = metrics.find((m) => m.l === activeMetric) || metrics[0];
    const trendDays = rangeDays || 30;
    const trend = Array.from({ length: trendDays }, (_, i) => {
        const date = new Date(now - (trendDays - 1 - i) * 86400000);
        const key = date.toISOString().slice(0, 10);
        const count = scopedRsvps.filter((r) => {
            if (!r.when)
                return false;
            return new Date(r.when).toISOString().slice(0, 10) === key;
        }).length;
        return { key, label: date.toLocaleDateString("en-IN", { day: "2-digit", month: "short" }), count };
    });
    const maxTrend = Math.max(1, ...trend.map((d) => d.count));
    const responseRows = [
        { key: "yes", label: "Accepted", v: accepts, color: "#2f8f60" },
        { key: "no", label: "Declined", v: declines, color: "#a95c51" },
        { key: "maybe", label: "Maybe", v: maybes, color: "#b98a3b" },
    ];
    const responseTotal = responseRows.reduce((sum, row) => sum + row.v, 0);
    const activeResponseRow = responseRows.find((row) => row.key === activeResponse) || responseRows[0];
    const radius = 42;
    const circumference = 2 * Math.PI * radius;
    let donutOffset = 0;
    const insights = [
        {
            title: "Best signal",
            body: topEvent ? `${topEvent.l} is the top tracked action with ${topEvent.v} events.` : "Share the invitation link to start collecting analytics.",
        },
        {
            title: "Guest replies",
            body: `${totalResponses} RSVP${totalResponses === 1 ? "" : "s"} ${rangeLabel.toLowerCase()}. Views and unique visitors show totals since launch.`,
        },
        {
            title: "Next action",
            body: totalResponses ? "Follow up with pending guests from the Guests tab." : "Send the invite link or QR code to begin collecting responses.",
        },
    ];
    return (React.createElement("div", null,
        React.createElement("div", { className: "dash-header analytics-header" },
            React.createElement("div", null,
                React.createElement("div", { className: "eyebrow" }, "Analytics"),
                React.createElement("h1", { className: "serif", style: { fontSize: 30, fontWeight: 500 } }, "How your invite is performing"),
                React.createElement("p", { className: "muted" }, "Filter guest responses by date. Views and visitor totals cover the life of your invitation.")),
            React.createElement("div", { className: "analytics-range", role: "group", "aria-label": "RSVP date range" }, [
                ["7", "7 days"],
                ["30", "30 days"],
                ["all", "Since launch"],
            ].map(([value, label]) => (React.createElement("button", { key: value, "aria-pressed": range === value, className: range === value ? "active" : "", onClick: () => setRange(value) }, label))))),
        React.createElement("div", { className: "analytics-score-grid" }, metrics.map((m) => (React.createElement("button", { key: m.l, className: "analytics-score-card " + (activeMetric === m.l ? "active" : ""), "aria-pressed": activeMetric === m.l, onMouseEnter: () => setActiveMetric(m.l), onFocus: () => setActiveMetric(m.l), onClick: () => setActiveMetric(m.l), style: { "--tone": m.tone } },
            React.createElement("span", { className: "eyebrow" }, m.l),
            React.createElement("strong", { className: "serif" }, fmt(m.v)),
            React.createElement("span", null, m.d))))),
        React.createElement("div", { className: "analytics-grid-main" },
            React.createElement("section", { className: "analytics-card analytics-card-large" },
                React.createElement("div", { className: "analytics-card-head" },
                    React.createElement("div", null,
                        React.createElement("h3", { className: "serif" }, "Engagement pulse"),
                        React.createElement("p", null,
                            selectedMetric.l,
                            ": ",
                            fmt(selectedMetric.v),
                            " - ",
                            selectedMetric.d)),
                    React.createElement("span", null, "Invitation activity")),
                React.createElement("div", { className: "analytics-metric-bars", role: "group", "aria-label": "Engagement metrics" }, metrics.map((m) => (React.createElement("button", { key: m.l, className: activeMetric === m.l ? "active" : "", "aria-label": `${m.l}: ${fmt(m.v)}`, "aria-pressed": activeMetric === m.l, onMouseEnter: () => setActiveMetric(m.l), onFocus: () => setActiveMetric(m.l), onClick: () => setActiveMetric(m.l), style: { "--bar": m.tone, height: `${(m.v / maxMetric) * 100}%`, minHeight: m.v ? 12 : 0 } },
                    React.createElement("span", null, fmt(m.v)))))),
                React.createElement("div", { className: "analytics-axis" }, metrics.map((m) => React.createElement("span", { key: m.l }, m.l)))),
            React.createElement("section", { className: "analytics-card" },
                React.createElement("div", { className: "analytics-card-head" },
                    React.createElement("div", null,
                        React.createElement("h3", { className: "serif" }, "RSVP response mix"),
                        React.createElement("p", null, responseTotal ? `${responseTotal} responses` : "No responses yet"))),
                React.createElement("div", { className: "analytics-donut-wrap" },
                    React.createElement("svg", { className: "analytics-donut", viewBox: "0 0 120 120", "aria-label": "RSVP response donut chart" },
                        React.createElement("circle", { cx: "60", cy: "60", r: radius, fill: "none", stroke: "rgba(42,31,16,.08)", strokeWidth: "16" }),
                        responseRows.map((row) => {
                            const length = responseTotal ? (row.v / responseTotal) * circumference : 0;
                            const segment = (React.createElement("circle", { key: row.key, cx: "60", cy: "60", r: radius, fill: "none", stroke: row.color, strokeWidth: "16", strokeDasharray: `${length} ${circumference - length}`, strokeDashoffset: -donutOffset, strokeLinecap: "round", onMouseEnter: () => setActiveResponse(row.key), onFocus: () => setActiveResponse(row.key) }));
                            donutOffset += length;
                            return segment;
                        })),
                    React.createElement("div", { className: "analytics-donut-center" },
                        React.createElement("strong", { className: "serif" }, responseTotal ? fmt(activeResponseRow.v) : "0"),
                        React.createElement("span", null, responseTotal ? activeResponseRow.label : "No RSVPs"))),
                React.createElement("div", { className: "analytics-legend" }, responseRows.map((row) => (React.createElement("button", { key: row.key, onMouseEnter: () => setActiveResponse(row.key), onClick: () => setActiveResponse(row.key) },
                    React.createElement("i", { style: { background: row.color } }),
                    " ",
                    row.label,
                    " ",
                    React.createElement("strong", null, row.v))))))),
        React.createElement("div", { className: "analytics-grid-main analytics-grid-secondary" },
            React.createElement("section", { className: "analytics-card" },
                React.createElement("div", { className: "analytics-card-head" },
                    React.createElement("div", null,
                        React.createElement("h3", { className: "serif" }, "Tracked events"),
                        React.createElement("p", null, rawEvents.length ? "Hover any bar for details" : "Events appear after guests interact"))),
                React.createElement("div", { className: "analytics-event-list" }, eventRows.map((row) => {
                    const pct = Math.round((row.v / maxEventCount) * 100);
                    const active = (activeEvent || eventRows[0]?.l) === row.l;
                    return (React.createElement("button", { key: row.l, className: active ? "active" : "", onMouseEnter: () => setActiveEvent(row.l), onFocus: () => setActiveEvent(row.l), onClick: () => setActiveEvent(row.l) },
                        React.createElement("span", null, row.l),
                        React.createElement("div", null,
                            React.createElement("i", { style: { width: `${pct}%` } })),
                        React.createElement("strong", null, row.v),
                        React.createElement("small", null,
                            row.unique,
                            " unique")));
                }))),
            React.createElement("section", { className: "analytics-card" },
                React.createElement("div", { className: "analytics-card-head" },
                    React.createElement("div", null,
                        React.createElement("h3", { className: "serif" }, "RSVP trend"),
                        React.createElement("p", null,
                            "Daily guest responses",
                            range === "all" ? " · latest 30 days" : ""))),
                React.createElement("div", { className: "analytics-trend" }, trend.map((day) => (React.createElement("div", { key: day.key, role: "img", "aria-label": `${day.label}: ${day.count} RSVP${day.count === 1 ? "" : "s"}`, title: `${day.label}: ${day.count} RSVP${day.count === 1 ? "" : "s"}`, style: { flex: 1, height: "100%", display: "flex", alignItems: "flex-end" } },
                    React.createElement("span", { style: { width: "100%", height: `${(day.count / maxTrend) * 100}%`, borderRadius: "999px 999px 0 0", background: "var(--accent)" } }))))),
                React.createElement("div", { className: "analytics-trend-labels" },
                    React.createElement("span", null, trend[0]?.label),
                    React.createElement("span", null, trend[trend.length - 1]?.label)))),
        React.createElement("div", { className: "analytics-insights" }, insights.map((item) => (React.createElement("div", { key: item.title },
            React.createElement("span", { className: "eyebrow" }, item.title),
            React.createElement("p", null, item.body)))))));
}
const DASH_TEMPLATE_CONFIG_KEYS = INVITE_CONFIG_KEYS;
function DashDesignPhonePreview({ project, template }) {
    const [previewSrc, setPreviewSrc] = React.useState("");
    const iframeRef = React.useRef(null);
    const hideIframeScrollbars = React.useCallback(() => {
        const frame = iframeRef.current;
        try {
            const doc = frame?.contentDocument;
            if (!doc || doc.getElementById("dash-preview-scrollbar-hide"))
                return;
            const style = doc.createElement("style");
            style.id = "dash-preview-scrollbar-hide";
            style.textContent = `
        html, body, * { scrollbar-width: none !important; -ms-overflow-style: none !important; }
        html::-webkit-scrollbar, body::-webkit-scrollbar, *::-webkit-scrollbar {
          display: none !important;
          width: 0 !important;
          height: 0 !important;
        }
      `;
            doc.head.appendChild(style);
        }
        catch (_) { }
    }, []);
    React.useEffect(() => {
        setPreviewSrc("");
        if (!project || !template?.builderTemplatePath)
            return;
        const configKey = (typeof INVITE_CONFIG_KEYS !== "undefined" && INVITE_CONFIG_KEYS[project.template_id])
            || DASH_TEMPLATE_CONFIG_KEYS[project.template_id];
        if (configKey && project.config) {
            try {
                window.sessionStorage.setItem(builderDraftKey(configKey, project.id), JSON.stringify(project.config));
            }
            catch (_) { }
        }
        const url = new URL(dashboardAppPath(template.builderTemplatePath), window.location.origin + "/");
        url.searchParams.set("builder", "1");
        url.searchParams.set("dashboard", "1");
        url.searchParams.set("silentPreview", "1");
        url.searchParams.set("skipIntro", "1");
        url.searchParams.set("project", project.id);
        if (configKey)
            url.searchParams.set('draftKey', builderDraftKey(configKey, project.id));
        url.searchParams.set("v", String(Date.now()));
        setPreviewSrc(url.href);
    }, [project?.id, project?.updated_at, template?.builderTemplatePath]);
    if (!project || !template) {
        return (React.createElement("div", { className: "dash-design-empty" },
            React.createElement("div", { className: "dash-design-empty-icon" }, "+"),
            React.createElement("div", { className: "eyebrow" }, "New design"),
            React.createElement("div", { className: "serif" }, "Choose a template and start building.")));
    }
    return (React.createElement("div", { className: "dash-design-preview-wrap" },
        React.createElement("div", { className: "dash-design-phone" },
            React.createElement("span", { className: "dash-design-phone-btn mute" }),
            React.createElement("span", { className: "dash-design-phone-btn up" }),
            React.createElement("span", { className: "dash-design-phone-btn down" }),
            React.createElement("span", { className: "dash-design-phone-btn power" }),
            React.createElement("div", { className: "dash-design-phone-screen" },
                React.createElement("span", { className: "dash-design-island" }),
                previewSrc ? (React.createElement("iframe", { ref: iframeRef, title: `${template.name} mobile preview`, src: previewSrc, allow: "autoplay 'none'", onLoad: hideIframeScrollbars })) : (React.createElement("div", { className: "dash-design-loading" }, "Loading"))))));
}
function DashDesign({ goTo, eff, project }) {
    const templates = TemplateCatalog.list("builder");
    const template = project ? dashTemplateFor(project.template_id || eff.templateId) : (templates[0] || dashTemplateFor(eff.templateId));
    const hasLink = project?.status === "published" && Boolean(eff.slug);
    const [copyMessage, setCopyMessage] = React.useState("");
    const copyLink = async () => {
        if (!hasLink)
            return;
        const copied = await copyTextToClipboard(window.location.origin + dashboardAppPath("/p/" + encodeURIComponent(eff.slug)));
        setCopyMessage(copied ? "Invitation link copied." : "Copy did not complete. Select and copy the link above.");
    };
    if (!project) {
        return (React.createElement("div", null,
            React.createElement("div", { className: "eyebrow" }, "Design"),
            React.createElement("h1", { className: "serif", style: { fontSize: 30, fontWeight: 500, marginBottom: 24 } }, "New design"),
            React.createElement("div", { className: "dash-new-design-panel" },
                React.createElement("div", { className: "dash-new-design-preview" },
                    React.createElement(DashDesignPhonePreview, { project: null, template: null })),
                React.createElement("div", { className: "dash-new-design-copy" },
                    React.createElement("span", { className: "dash-live-dot" }),
                    React.createElement("div", { className: "eyebrow" }, "Start here"),
                    React.createElement("h2", { className: "serif" }, "Create your first wedding invitation"),
                    React.createElement("p", null, "Pick a template, edit the names and events, then save it as a draft. Drafts stay in Projects until you publish and share the guest link."),
                    React.createElement("div", { className: "dash-new-design-options" }, templates.slice(0, 3).map((item) => (React.createElement("button", { key: item.id, type: "button", onClick: () => goTo("builder", { template: item, projectId: null }) },
                        React.createElement("strong", null, item.name),
                        React.createElement("span", null, item.badge || item.subtitle || "Wedding invitation"))))),
                    React.createElement("button", { className: "btn btn-primary", onClick: () => goTo("builder", { projectId: null }) }, "Choose a design")))));
    }
    return (React.createElement("div", null,
        React.createElement("div", { className: "eyebrow" }, "Design"),
        React.createElement("h1", { className: "serif", style: { fontSize: 30, fontWeight: 500, marginBottom: 24 } }, "Your invitation"),
        React.createElement("div", { className: "dash-design-grid" },
            React.createElement("div", { className: "dash-panel", style: { padding: 0, overflow: "hidden" } },
                React.createElement(DashDesignPhonePreview, { project: project, template: template }),
                React.createElement("div", { className: "dashboard-design-caption", style: { padding: "20px 24px", display: "flex", justifyContent: "space-between", alignItems: "center" } },
                    React.createElement("div", null,
                        React.createElement("div", { className: "serif", style: { fontSize: 20, fontWeight: 500 } }, eff.templateName),
                        React.createElement("div", { style: { fontSize: 12, color: "var(--ink-soft)" } }, project?.updated_at ? `Last saved ${new Date(project.updated_at).toLocaleString("en-IN")}` : "Choose a template to start")),
                    React.createElement("button", { className: "btn btn-primary", onClick: () => goTo("builder", { template, projectId: project?.id || null }) }, "Edit design \u2192"))),
            React.createElement("div", null,
                React.createElement("div", { className: "dash-panel", style: { marginBottom: 16 } },
                    React.createElement("div", { className: "dash-panel-hdr" },
                        React.createElement("h3", { className: "serif", style: { fontSize: 18, fontWeight: 500 } }, "Your link")),
                    React.createElement("div", { className: "dash-domain-bar", style: { marginBottom: 14 } },
                        React.createElement("span", { className: "dash-domain-host" }, window.location.host + dashboardAppPath("/p/")),
                        React.createElement("code", { style: { flex: 1, fontFamily: "ui-monospace, monospace", fontSize: 13 } }, eff.slug || "publish-first")),
                    React.createElement("button", { className: "btn btn-ghost", style: { width: "100%", justifyContent: "center" }, onClick: copyLink, disabled: !hasLink }, hasLink ? "Copy link" : "Publish to create link"),
                    copyMessage && React.createElement("p", { className: "account-feedback", role: "status" }, copyMessage)),
                React.createElement("div", { className: "dash-panel" },
                    React.createElement("div", { className: "dash-panel-hdr" },
                        React.createElement("h3", { className: "serif", style: { fontSize: 22, fontWeight: 500 } }, "Make every detail yours")),
                    React.createElement("p", { className: "muted" }, "Check your names, celebration dates, and venue before sharing. Open the editor to make changes and preview your invitation."))))));
}
function DashBilling() {
    const [orders, setOrders] = React.useState([]), [loading, setLoading] = React.useState(true), [error, setError] = React.useState(''), [retry, setRetry] = React.useState(0);
    React.useEffect(() => { let cancelled = false; setLoading(true); setError(''); window.EA.listOrders().then(result => { if (!cancelled)
        setOrders(result.orders || []); }).catch(err => { if (!cancelled)
        setError(err.message || 'Payments could not be loaded.'); }).finally(() => { if (!cancelled)
        setLoading(false); }); return () => { cancelled = true; }; }, [retry]);
    return React.createElement("section", { className: "dashboard-billing" },
        React.createElement("h1", { className: "serif" }, "Payments"),
        React.createElement("p", { className: "muted" }, "Your invitation purchases and their latest payment status."),
        loading && React.createElement("div", { className: "account-state", role: "status" }, "Loading payments\u2026"),
        error && React.createElement("div", { className: "account-alert", role: "alert" },
            error,
            " ",
            React.createElement("button", { className: "btn btn-ghost", onClick: () => setRetry(v => v + 1) }, "Try again")),
        !loading && !error && !orders.length && React.createElement("div", { className: "account-state" },
            React.createElement("h2", { className: "serif" }, "No payments yet"),
            React.createElement("p", null, "You can design and save a draft before purchasing. Choose Publish in the builder when your invitation is ready.")),
        !loading && !error && orders.map(order => React.createElement("article", { className: "dash-panel dashboard-payment", key: order.id },
            React.createElement("div", null,
                React.createElement("strong", null, TemplateCatalog.get(order.template_id)?.name || order.project_name || 'Wedding invitation'),
                React.createElement("p", { className: "muted" }, order.created_at ? new Date(order.created_at).toLocaleString('en-IN') : ''),
                order.promo_code && Number(order.discount_paise) > 0 && React.createElement("p", { className: "muted" },
                    order.promo_code,
                    ": saved ",
                    new Intl.NumberFormat('en-IN', { style: 'currency', currency: order.currency || 'INR' }).format(Number(order.discount_paise) / 100))),
            React.createElement("div", { className: "dashboard-payment-amount" },
                React.createElement("strong", null, new Intl.NumberFormat('en-IN', { style: 'currency', currency: order.currency || 'INR' }).format(Number(order.amount_paise || 0) / 100)),
                React.createElement("span", { className: "dash-rsvp-badge neutral" }, order.payment_provider === 'promotion' ? 'Promo applied' : String(order.status || 'Pending').replace(/_/g, ' '))),
            React.createElement("small", null,
                "Order ",
                order.id))));
}
function DashSettings({ eff, goTo, project }) {
    const [name, setName] = React.useState(''), [phone, setPhone] = React.useState(''), [loading, setLoading] = React.useState(true), [busy, setBusy] = React.useState(false), [message, setMessage] = React.useState(''), [error, setError] = React.useState(''), [loaded, setLoaded] = React.useState(false), [retry, setRetry] = React.useState(0);
    React.useEffect(() => { let cancelled = false; setLoading(true); setError(''); window.EA.me().then(({ user }) => { if (!cancelled) {
        setName(user.name || '');
        setPhone(user.phone || '');
        setLoaded(true);
    } }).catch(err => { if (!cancelled)
        setError(err.message || 'Account could not be loaded.'); }).finally(() => { if (!cancelled)
        setLoading(false); }); return () => { cancelled = true; }; }, [retry]);
    const save = async (event) => { event.preventDefault(); setBusy(true); setError(''); setMessage(''); try {
        const result = await window.EA.updateProfile({ name: name.trim(), phone: phone.trim() });
        if (result.user && typeof saveUser === 'function')
            saveUser(result.user);
        setMessage('Your account details are saved.');
    }
    catch (err) {
        setError(err.message || 'Account could not be saved.');
    }
    finally {
        setBusy(false);
    } };
    return React.createElement("section", { className: "dashboard-settings", style: { maxWidth: 720 } },
        React.createElement("h1", { className: "serif" }, "Your account"),
        React.createElement("p", { className: "muted" }, eff.email),
        loading && React.createElement("p", { className: "account-state", role: "status" }, "Loading account\u2026"),
        React.createElement("form", { className: "dash-panel", onSubmit: save },
            React.createElement("fieldset", { disabled: loading || busy || !loaded, style: { border: 0, padding: 0 } },
                React.createElement("label", { className: "signin-field" },
                    React.createElement("span", null, "Name"),
                    React.createElement("input", { required: true, minLength: 2, maxLength: 120, value: name, onChange: e => setName(e.target.value), autoComplete: "name" })),
                React.createElement("label", { className: "signin-field" },
                    React.createElement("span", null, "Phone (optional)"),
                    React.createElement("input", { type: "tel", value: phone, maxLength: 25, onChange: e => setPhone(e.target.value), autoComplete: "tel" })),
                React.createElement("button", { type: "submit", className: "btn btn-primary" }, busy ? 'Saving…' : 'Save account details'))),
        error && React.createElement("div", { className: "account-alert", role: "alert" },
            error,
            !loaded && React.createElement("button", { className: "btn btn-ghost", onClick: () => setRetry(value => value + 1) }, "Try again")),
        message && React.createElement("p", { className: "account-feedback", role: "status" }, message),
        project && React.createElement("div", { className: "dash-panel", style: { marginTop: 24 } },
            React.createElement("h2", { className: "serif" }, "Invitation details"),
            React.createElement("p", null, [eff.coupleA, eff.coupleB].filter(Boolean).join(' & ')),
            React.createElement("p", { className: "muted" }, [formatDashDate(eff.weddingDate), eff.venue].filter(Boolean).join(' · ')),
            React.createElement("button", { className: "btn btn-ghost", onClick: () => goTo('builder', { template: TemplateCatalog.get(project.template_id), projectId: project.id }) }, "Edit invitation")));
}
function relativeTime(ms) {
    const d = Math.max(0, Math.floor((Date.now() - ms) / 1000));
    if (d < 60)
        return d + "s ago";
    if (d < 3600)
        return Math.floor(d / 60) + "m ago";
    if (d < 86400)
        return Math.floor(d / 3600) + "h ago";
    return Math.floor(d / 86400) + "d ago";
}
function DashShare({ eff, projectId, project, setProject, guests }) {
    const isPublished = project?.status === "published";
    const slug = project?.slug || eff.slug;
    const origin = window.location.origin;
    const inviteUrl = slug ? origin + dashboardAppPath(`/p/${encodeURIComponent(slug)}`) : null;
    const qrUrl = inviteUrl
        ? `https://api.qrserver.com/v1/create-qr-code/?size=180x180&data=${encodeURIComponent(inviteUrl)}&bgcolor=faf6f1&color=2a1f10&margin=12`
        : null;
    const [copied, setCopied] = React.useState(false);
    const [copiedName, setCopiedName] = React.useState(false);
    const [publishing, setPub] = React.useState(false);
    const [pubMsg, setPubMsg] = React.useState("");
    const [pubError, setPubError] = React.useState(false);
    const [qrFailed, setQrFailed] = React.useState(false);
    const publishLock = React.useRef(false);
    const uniqueName = dashUniqueInviteName(project, eff, projectId);
    const copy = () => {
        if (!inviteUrl)
            return;
        copyTextToClipboard(inviteUrl).then((ok) => {
            if (!ok) {
                setPubError(true);
                setPubMsg("Copy did not complete. Select and copy the invitation link below.");
                return;
            }
            setCopied(true);
            setTimeout(() => setCopied(false), 2200);
        });
    };
    const copyName = () => {
        copyTextToClipboard(uniqueName).then((ok) => {
            if (!ok) {
                setPubError(true);
                setPubMsg("Copy did not complete. Select and copy the invitation name above.");
                return;
            }
            setCopiedName(true);
            setTimeout(() => setCopiedName(false), 1800);
        });
    };
    const whatsapp = () => {
        if (!inviteUrl)
            return;
        const msg = `You're invited! View our wedding invitation:\n${inviteUrl}`;
        window.open(`https://wa.me/?text=${encodeURIComponent(msg)}`, "_blank", "noopener");
    };
    const togglePublish = async () => {
        if (publishLock.current)
            return;
        if (!projectId) {
            setPubMsg("No project found. Build your invitation first.");
            return;
        }
        publishLock.current = true;
        setPub(true);
        setPubMsg("");
        setPubError(false);
        try {
            const newStatus = isPublished ? "draft" : "published";
            if (newStatus === "published") {
                if (typeof window.checkoutProject !== "function")
                    throw new Error("Payment checkout is unavailable. Please refresh.");
                await window.checkoutProject({ projectId, templateId: project.template_id });
            }
            const res = await window.EA.saveProject(projectId, null, null, newStatus);
            setProject(p => p ? { ...p, status: newStatus, slug: res.project?.slug || p.slug } : p);
            setPubMsg(newStatus === "published" ? "Your invitation is now live!" : "Invitation set to draft.");
        }
        catch (err) {
            setPubError(true);
            setPubMsg(err.message || "Your invitation could not be updated. Please try again.");
        }
        publishLock.current = false;
        setPub(false);
    };
    const guestWhatsApp = (guest) => {
        if (!inviteUrl)
            return;
        const phone = (guest.phone || "").replace(/\D/g, "");
        const coupleName = [eff.coupleA, eff.coupleB].filter(Boolean).join(" & ");
        const msg = `Hi ${guest.n}! You're invited${coupleName ? ` to ${coupleName}'s wedding` : " to our celebration"}. View the invitation here:\n${inviteUrl}`;
        const url = phone
            ? `https://wa.me/${phone}?text=${encodeURIComponent(msg)}`
            : `https://wa.me/?text=${encodeURIComponent(msg)}`;
        window.open(url, "_blank", "noopener");
    };
    const sectionBorder = "1px solid rgba(42,31,16,.08)";
    const H = ({ children }) => (React.createElement("h3", { style: { fontFamily: "'Cormorant Garamond',serif", fontSize: 20, fontWeight: 500, color: "#2a1f10", margin: "0 0 18px" } }, children));
    const Section = ({ children, last = false }) => (React.createElement("div", { style: { padding: last ? "22px 0 0" : "22px 0", borderTop: sectionBorder } }, children));
    return (React.createElement("div", { className: "dashboard-share", style: { maxWidth: 700 } },
        React.createElement("h1", { className: "serif" }, "Share your invitation"),
        React.createElement("p", { className: "muted", style: { marginBottom: 24 } }, "Publish when you are ready, then send the same guest link wherever you like."),
        React.createElement("div", { className: "dashboard-share-card", style: { background: "#fff", borderRadius: 14, padding: "26px 28px 30px", boxShadow: "0 2px 16px -8px rgba(42,31,16,.12)", border: "1px solid color-mix(in oklab, var(--ink) 8%, transparent)", marginBottom: 24 } },
            React.createElement("div", { style: { paddingBottom: 22 } },
                React.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 18, flexWrap: "wrap" } },
                    React.createElement("div", { style: { minWidth: 0, flex: 1 } },
                        React.createElement("div", { className: "eyebrow", style: { marginBottom: 8 } }, "Unique invitation name"),
                        React.createElement("div", { style: { fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace", fontSize: 13, color: "#2a1f10", background: "#f6f0e6", borderRadius: 8, padding: "10px 12px", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, uniqueName),
                        React.createElement("p", { style: { fontSize: 12, color: "#6b5d52", margin: "10px 0 0" } }, "This stays different for every invitation, even before the public link is live.")),
                    React.createElement("button", { onClick: copyName, className: "btn btn-ghost" }, copiedName ? "Copied" : "Copy name"))),
            React.createElement(Section, null,
                React.createElement("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 16, flexWrap: "wrap", padding: "18px 20px", borderRadius: 10, background: isPublished ? "#edf3e8" : "#f5e9e1", border: `1px solid ${isPublished ? "#bed2bf" : "#e3d2c6"}` } },
                    React.createElement("div", null,
                        React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 10, marginBottom: 4 } },
                            React.createElement("span", { style: { width: 10, height: 10, borderRadius: "50%", background: isPublished ? "#22c55e" : "#f4c470", display: "inline-block" } }),
                            React.createElement("strong", { style: { fontSize: 15, color: "#2a1f10" } }, isPublished ? "Your invitation is live" : "Draft · visible only to you")),
                        React.createElement("p", { style: { fontSize: 13, color: "#6b5d52", margin: 0 } }, isPublished
                            ? "Guests can view and RSVP using your invite link."
                            : "Publish to make your invitation accessible to guests."),
                        pubMsg && React.createElement("p", { role: pubError ? "alert" : "status", style: { fontSize: 14, color: pubError ? "#813b31" : "#466348", marginTop: 10, marginBottom: 0 } }, pubMsg)),
                    React.createElement("button", { onClick: togglePublish, disabled: publishing || !window.EA?.isLoggedIn(), className: "btn " + (isPublished ? "btn-ghost" : "btn-primary") }, publishing ? "Updating…" : isPublished ? "Unpublish" : "Publish invitation"))),
            isPublished && inviteUrl && (React.createElement(React.Fragment, null,
                React.createElement(Section, null,
                    React.createElement(H, null, "Invite link"),
                    React.createElement("div", { className: "dashboard-share-link", style: { display: "flex", gap: 8, marginBottom: 16 } },
                        React.createElement("input", { "aria-label": "Invitation link", readOnly: true, value: inviteUrl, onFocus: event => event.currentTarget.select() }),
                        React.createElement("button", { className: "btn btn-primary", onClick: copy }, copied ? "Copied!" : "Copy")),
                    React.createElement("button", { className: "dashboard-whatsapp", onClick: whatsapp }, "Share on WhatsApp \u2197")),
                React.createElement(Section, { last: !guests?.length },
                    React.createElement(H, null, "QR Code"),
                    React.createElement("div", { style: { display: "flex", gap: 32, alignItems: "flex-start", flexWrap: "wrap" } },
                        React.createElement("div", { style: { padding: 10, background: "#fff", borderRadius: 12, boxShadow: "0 4px 16px -6px rgba(42,31,16,.15)", flexShrink: 0 } }, qrFailed ? React.createElement("p", { role: "status", style: { maxWidth: 180, margin: 0 } }, "QR code could not load. Your invitation link above still works.") : React.createElement("img", { src: qrUrl, alt: "Scan to open your invitation", width: "180", height: "180", onError: () => setQrFailed(true), style: { display: "block", borderRadius: 6 } })),
                        React.createElement("div", { style: { flex: "1 1 240px" } },
                            React.createElement("p", { style: { fontSize: 14, color: "#6b5d52", lineHeight: 1.6, margin: "0 0 16px" } }, "Print this QR code and include it on physical save-the-dates, gift boxes, or venue displays. Guests scan to open the invitation instantly."),
                            React.createElement("a", { href: qrUrl.replace("size=180x180", "size=600x600"), target: "_blank", rel: "noreferrer", style: { display: "inline-block", padding: "9px 18px", background: "#f6f0e6", borderRadius: 8, fontSize: 13, color: "#2a1f10", textDecoration: "none", fontWeight: 600 } }, "Open QR to save \u2197")))))),
            isPublished && inviteUrl && guests?.length > 0 && (React.createElement(Section, { last: true },
                React.createElement(H, null, "Send invites to guests"),
                React.createElement("p", { style: { fontSize: 13, color: "#6b5d52", marginTop: -10, marginBottom: 16 } }, "Click to open a pre-filled WhatsApp message for each guest."),
                React.createElement("div", { style: { display: "grid", gap: 8 } }, guests.map((g) => (React.createElement("div", { className: "dashboard-guest-share", key: g.id },
                    React.createElement("div", { style: { minWidth: 0, overflowWrap: "anywhere" } },
                        React.createElement("div", { style: { fontSize: 14, fontWeight: 500, color: "#2a1f10" } }, g.n),
                        React.createElement("div", { style: { fontSize: 12, color: "#a09080" } }, g.phone || "No phone saved")),
                    React.createElement("button", { className: "dashboard-whatsapp", onClick: () => guestWhatsApp(g) }, "Open WhatsApp \u2197")))))))),
        !window.EA?.isLoggedIn() && (React.createElement("div", { style: { background: "#fff", borderRadius: 14, padding: "24px 28px", boxShadow: "0 2px 16px -8px rgba(42,31,16,.12)", marginBottom: 24, textAlign: "center" } },
            React.createElement("p", { style: { color: "#6b5d52", marginBottom: 0 } }, "Sign in to publish your invitation and get a shareable link.")))));
}
Object.assign(window, { Dashboard });
