window.EA_BUILDER_API_CONTEXT = typeof React.createContext === 'function' ? React.createContext(null) : null;
const ADMIN_PAGE_SIZE = 25;
const ADMIN_SECTIONS = [
    ['users', 'Users', 'Find an account, help with an invitation, or manage access.'],
    ['projects', 'Invitations', 'Review saved designs and control what guests can open.'],
    ['orders', 'Payments', 'Review charges, discounts and refunds.'],
    ['promos', 'Promo codes', 'Offer a discount at the final payment step.'],
    ['audit', 'Activity', 'A record of administrator changes and their reasons.'],
    ['templates', 'Template library', 'The designs available across your invitation product.']
];
const ADMIN_FILTERS = {
    users: [['all', 'All users'], ['active', 'Active'], ['blocked', 'Blocked']],
    projects: [['all', 'All invitations'], ['draft', 'Draft'], ['published', 'Published'], ['archived', 'Archived'], ['removed', 'Removed'], ['blocked', 'Under review']],
    orders: [['all', 'All payments'], ['paid', 'Paid'], ['pending', 'Pending'], ['failed', 'Failed'], ['refunded', 'Refunded']],
    promos: [['all', 'All promo codes'], ['active', 'Enabled'], ['inactive', 'Disabled']]
};
function adminMoney(value) { return new Intl.NumberFormat('en-IN', { style: 'currency', currency: 'INR', maximumFractionDigits: 2 }).format(Number(value || 0) / 100); }
function adminDate(value) { return value && Number.isFinite(new Date(value).getTime()) ? new Intl.DateTimeFormat('en-IN', { day: 'numeric', month: 'short', year: 'numeric' }).format(new Date(value)) : '—'; }
function adminRupees(value, label, optional = false) {
    const raw = String(value ?? '').trim();
    if (optional && !raw)
        return null;
    if (!/^\d+(\.\d{1,2})?$/.test(raw))
        throw new Error(label + ' must be a rupee amount with up to two decimal places.');
    const [whole, decimal = ''] = raw.split('.');
    const paise = Number(whole) * 100 + Number(decimal.padEnd(2, '0'));
    if (!Number.isSafeInteger(paise))
        throw new Error(label + ' is too large.');
    return paise;
}
function adminOptionalInteger(value, label) {
    if (String(value ?? '').trim() === '')
        return null;
    if (!/^\d+$/.test(String(value)) || !Number.isSafeInteger(Number(value)) || Number(value) < 1)
        throw new Error(label + ' must be a positive whole number.');
    return Number(value);
}
function adminLocalDate(value) {
    if (!value)
        return '';
    const date = new Date(value);
    return Number.isFinite(date.getTime()) ? new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().slice(0, 16) : '';
}
function adminPromoDraft(promo = {}) {
    return {
        version: promo.version || null,
        code: promo.code || '', label: promo.label || '', discount_type: promo.discount_type || 'percent',
        discount_value: promo.discount_value == null ? '' : String(promo.discount_type === 'fixed' ? Number(promo.discount_value) / 100 : promo.discount_value),
        active: promo.active !== false, starts_at: adminLocalDate(promo.starts_at), ends_at: adminLocalDate(promo.ends_at),
        max_redemptions: promo.max_redemptions == null ? '' : String(promo.max_redemptions),
        per_user_limit: promo.id && promo.per_user_limit == null ? '' : String(promo.per_user_limit ?? 1),
        min_subtotal: String(Number(promo.min_subtotal_paise || 0) / 100),
        max_discount: promo.max_discount_paise == null ? '' : String(Number(promo.max_discount_paise) / 100),
        template_ids: [...(promo.template_ids || [])], reason: ''
    };
}
function adminPromoPayload(draft) {
    const code = draft.code.trim().toUpperCase(), reason = draft.reason.trim();
    if (!/^[A-Z0-9][A-Z0-9_-]{2,39}$/.test(code))
        throw new Error('Use 3–40 letters, numbers, hyphens or underscores, starting with a letter or number.');
    if (reason.length < 4 || reason.length > 500)
        throw new Error('Add a reason between 4 and 500 characters.');
    const percent = draft.discount_type === 'percent';
    const amount = percent ? adminOptionalInteger(draft.discount_value, 'Percentage') : adminRupees(draft.discount_value, 'Discount');
    if (!amount || (percent && amount > 100))
        throw new Error(percent ? 'Percentage must be between 1 and 100.' : 'The discount must be greater than zero.');
    function iso(value) { if (!value)
        return null; const date = new Date(value); if (!Number.isFinite(date.getTime()))
        throw new Error('Choose a valid start and end date.'); return date.toISOString(); }
    const starts_at = iso(draft.starts_at), ends_at = iso(draft.ends_at);
    if (starts_at && ends_at && starts_at >= ends_at)
        throw new Error('The end date must be after the start date.');
    return { code, label: draft.label.trim() || code, discount_type: draft.discount_type, discount_value: amount, active: draft.active, ...(draft.version ? { expected_version: draft.version } : {}),
        starts_at, ends_at, max_redemptions: adminOptionalInteger(draft.max_redemptions, 'Total uses'), per_user_limit: adminOptionalInteger(draft.per_user_limit, 'Uses per user'),
        min_subtotal_paise: adminRupees(draft.min_subtotal || '0', 'Minimum price'), max_discount_paise: adminRupees(draft.max_discount, 'Maximum discount', true), template_ids: [...new Set(draft.template_ids)], reason };
}
function adminPromoStatus(promo, now = Date.now()) {
    if (!promo.active)
        return 'Disabled';
    if (promo.ends_at && new Date(promo.ends_at).getTime() <= now)
        return 'Expired';
    if (promo.starts_at && new Date(promo.starts_at).getTime() > now)
        return 'Scheduled';
    if (promo.max_redemptions != null && Number(promo.total_uses || 0) >= Number(promo.max_redemptions))
        return 'Limit reached';
    return 'Active';
}
function adminTemplateName(id) { return TemplateCatalog.get(id)?.name || id || 'Invitation'; }
function adminAuditTarget(row) {
    const template = String(row.action || '').startsWith('template.') && (row.after_state?.name || row.before_state?.name || row.after_state?.template_id || row.before_state?.template_id);
    return row.target_email || row.project_id || template || row.after_state?.code || row.before_state?.code || '—';
}
function adminProjectState(project) { return project.deleted_at ? 'Removed' : project.owner_blocked_at ? 'Owner blocked' : project.moderation_blocked ? 'Under review' : project.status === 'published' ? 'Published' : project.status === 'archived' ? 'Archived' : 'Draft'; }
function adminPublicHref(project) {
    const slug = project.slug;
    if (project.status !== 'published' || !project.entitled || project.deleted_at || project.owner_blocked_at || project.moderation_blocked || typeof slug !== 'string' || slug.length < 3 || slug.length > 100 || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug))
        return null;
    return window.EA_APP.path('/p/' + encodeURIComponent(slug));
}
function adminPaymentVerification(order) {
    if (order.payment_provider === 'promotion' && Number(order.amount_paise) === 0)
        return 'Promo unlock';
    return ['paid', 'refunded'].includes(order.status) ? order.payment_verified_at ? 'Verified payment' : 'Unverified legacy record' : '';
}
function AdminStatus({ children, tone = '' }) { return React.createElement("span", { className: 'admin-status' + (tone ? ' is-' + tone : '') }, children); }
function AdminIcon({ name }) {
    const paths = { users: 'M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2 M16 3a4 4 0 0 1 0 8 M22 21v-2a4 4 0 0 0-3-3.87', projects: 'M4 5h16v14H4z M4 6l8 7 8-7', orders: 'M3 5h18v14H3z M3 10h18 M7 15h3', promos: 'M4 4h8l9 9-8 8-9-9z M8 8h.01', audit: 'M9 5h12 M9 12h12 M9 19h12 M3 5h.01 M3 12h.01 M3 19h.01', templates: 'M3 3h7v7H3z M14 3h7v7h-7z M3 14h7v7H3z M14 14h7v7h-7z' };
    return React.createElement("svg", { viewBox: "0 0 24 24", width: "20", height: "20", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true" },
        React.createElement("path", { d: paths[name] || paths.projects }),
        name === 'users' && React.createElement("circle", { cx: "9", cy: "7", r: "4" }));
}
function AdminDialog({ title, busy, onClose, children }) {
    const ref = React.useRef(null);
    React.useEffect(() => { const dialog = ref.current, previous = document.activeElement; if (dialog && !dialog.open)
        dialog.showModal(); return () => { if (dialog?.open)
        dialog.close(); if (previous?.isConnected)
        previous.focus?.(); }; }, []);
    return React.createElement("dialog", { ref: ref, className: "admin-dialog", "aria-labelledby": "admin-dialog-title", onCancel: event => { event.preventDefault(); if (!busy)
            onClose(); } },
        React.createElement("div", { className: "admin-dialog-heading" },
            React.createElement("h2", { id: "admin-dialog-title" }, title),
            React.createElement("button", { type: "button", className: "admin-icon-button", "aria-label": "Close dialog", disabled: busy, onClick: onClose }, "\u00D7")),
        children);
}
function AdminProjectMenu({ project, busy, onAction }) {
    return React.createElement("label", { className: "admin-row-select" },
        React.createElement("span", { className: "sr-only" },
            "Manage ",
            project.name || 'invitation'),
        React.createElement("select", { value: "", disabled: busy, onChange: event => { const kind = event.target.value; if (kind)
                onAction(kind, project); } },
            React.createElement("option", { value: "" }, "Manage invitation"),
            project.deleted_at ? React.createElement("option", { value: "restore" }, "Restore as draft") : React.createElement(React.Fragment, null,
                !project.owner_blocked_at && React.createElement("option", { value: "edit" }, "Edit invitation"),
                React.createElement("option", { value: "moderate" }, "Review visibility"),
                React.createElement("option", { value: project.admin_granted ? 'revoke' : 'grant' }, project.admin_granted ? 'Revoke complimentary access' : 'Grant complimentary access'),
                React.createElement("option", { value: "remove" }, "Remove invitation"))));
}
function AdminTemplateMenu({ template, busy, editable, onAction }) {
    const canChange = editable && template.availability_editable === true;
    return React.createElement("label", { className: "admin-row-select" },
        React.createElement("span", { className: "sr-only" },
            "Manage ",
            template.name),
        React.createElement("select", { value: "", disabled: busy || !canChange, onChange: event => { if (canChange && event.target.value)
                onAction(event.target.value, template); } },
            React.createElement("option", { value: "" }, canChange ? 'Change availability' : 'Unavailable in this release'),
            canChange && React.createElement("option", { value: template.enabled ? 'template-disable' : 'template-enable' }, template.enabled ? 'Disable template' : 'Enable template')));
}
function AdminProjectRows({ projects, onAction, busy, owners = false }) {
    return React.createElement("table", { className: "admin-records" },
        React.createElement("caption", { className: "sr-only" }, "Invitations"),
        React.createElement("thead", null,
            React.createElement("tr", null,
                React.createElement("th", { scope: "col" }, "Invitation"),
                owners && React.createElement("th", { scope: "col" }, "Owner"),
                React.createElement("th", { scope: "col" }, "Status"),
                React.createElement("th", { scope: "col" }, "Publishing access"),
                React.createElement("th", { scope: "col" }, "Actions"))),
        React.createElement("tbody", null, projects.map(project => React.createElement("tr", { key: project.id },
            React.createElement("td", { "data-label": "Invitation" },
                React.createElement("strong", null, project.name || 'Untitled invitation'),
                React.createElement("small", null, adminTemplateName(project.template_id)),
                adminPublicHref(project) && React.createElement("a", { className: "admin-text-button admin-public-link", href: adminPublicHref(project), target: "_blank", rel: "noopener noreferrer" }, "Open published invitation")),
            owners && React.createElement("td", { "data-label": "Owner" },
                React.createElement("span", null, project.owner_name || project.owner_email || 'Account'),
                project.owner_name && React.createElement("small", null, project.owner_email)),
            React.createElement("td", { "data-label": "Status" },
                React.createElement(AdminStatus, { tone: project.deleted_at || project.owner_blocked_at || project.moderation_blocked ? 'warning' : project.status === 'published' ? 'good' : '' }, adminProjectState(project))),
            React.createElement("td", { "data-label": "Publishing access" }, project.admin_granted ? 'Complimentary' : project.entitled ? 'Purchased' : 'Not unlocked'),
            React.createElement("td", { "data-label": "Actions" },
                React.createElement(AdminProjectMenu, { project: project, onAction: onAction, busy: busy }))))));
}
function AdminPromoForm({ value, onChange, templates, editing }) {
    const set = (key, next) => onChange({ ...value, [key]: next });
    return React.createElement(React.Fragment, null,
        React.createElement("div", { className: "admin-form-grid" },
            React.createElement("label", { className: "admin-field" },
                React.createElement("span", null, "Promo code"),
                React.createElement("input", { autoFocus: true, required: true, maxLength: 40, pattern: '[A-Za-z0-9][A-Za-z0-9_\\-]{2,39}', autoComplete: "off", spellCheck: "false", value: value.code, disabled: editing, onChange: event => set('code', event.target.value.toUpperCase()), placeholder: "WEDDING20" }),
                React.createElement("small", null, editing ? 'The code stays the same for existing orders.' : 'Customers enter this at checkout.')),
            React.createElement("label", { className: "admin-field" },
                React.createElement("span", null,
                    "Internal name ",
                    React.createElement("small", null, "(optional)")),
                React.createElement("input", { maxLength: 100, value: value.label, onChange: event => set('label', event.target.value), placeholder: "Wedding season offer" })),
            React.createElement("label", { className: "admin-field" },
                React.createElement("span", null, "Discount type"),
                React.createElement("select", { value: value.discount_type, onChange: event => set('discount_type', event.target.value) },
                    React.createElement("option", { value: "percent" }, "Percentage"),
                    React.createElement("option", { value: "fixed" }, "Fixed amount in \u20B9"))),
            React.createElement("label", { className: "admin-field" },
                React.createElement("span", null, value.discount_type === 'percent' ? 'Percentage off' : 'Discount amount (₹)'),
                React.createElement("input", { required: true, type: "number", min: value.discount_type === 'percent' ? '1' : '0.01', max: value.discount_type === 'percent' ? '100' : undefined, step: value.discount_type === 'percent' ? '1' : '0.01', inputMode: "decimal", value: value.discount_value, onChange: event => set('discount_value', event.target.value) })),
            React.createElement("label", { className: "admin-field" },
                React.createElement("span", null, "Availability"),
                React.createElement("select", { value: value.active ? 'enabled' : 'disabled', onChange: event => set('active', event.target.value === 'enabled') },
                    React.createElement("option", { value: "enabled" }, "Enabled"),
                    React.createElement("option", { value: "disabled" }, "Disabled"))),
            React.createElement("label", { className: "admin-field" },
                React.createElement("span", null, "Uses per user"),
                React.createElement("input", { type: "number", min: "1", step: "1", inputMode: "numeric", value: value.per_user_limit, onChange: event => set('per_user_limit', event.target.value), placeholder: "No limit" }),
                React.createElement("small", null, "Leave empty for no per-user limit."))),
        React.createElement("details", { className: "admin-advanced" },
            React.createElement("summary", null, "Schedule, usage limits and eligible templates"),
            React.createElement("div", { className: "admin-form-grid" },
                React.createElement("label", { className: "admin-field" },
                    React.createElement("span", null,
                        "Starts at ",
                        React.createElement("small", null, "(local time)")),
                    React.createElement("input", { type: "datetime-local", value: value.starts_at, onChange: event => set('starts_at', event.target.value) }),
                    React.createElement("small", null, "Leave empty to start immediately.")),
                React.createElement("label", { className: "admin-field" },
                    React.createElement("span", null,
                        "Ends at ",
                        React.createElement("small", null, "(local time)")),
                    React.createElement("input", { type: "datetime-local", value: value.ends_at, onChange: event => set('ends_at', event.target.value) }),
                    React.createElement("small", null, "Leave empty for no end date.")),
                React.createElement("label", { className: "admin-field" },
                    React.createElement("span", null, "Total uses"),
                    React.createElement("input", { type: "number", min: "1", step: "1", inputMode: "numeric", value: value.max_redemptions, onChange: event => set('max_redemptions', event.target.value), placeholder: "No limit" })),
                React.createElement("label", { className: "admin-field" },
                    React.createElement("span", null, "Minimum invitation price (\u20B9)"),
                    React.createElement("input", { type: "number", min: "0", step: "0.01", inputMode: "decimal", value: value.min_subtotal, onChange: event => set('min_subtotal', event.target.value) })),
                React.createElement("label", { className: "admin-field" },
                    React.createElement("span", null, "Maximum discount (\u20B9)"),
                    React.createElement("input", { type: "number", min: "0.01", step: "0.01", inputMode: "decimal", value: value.max_discount, onChange: event => set('max_discount', event.target.value), placeholder: "No cap" })),
                React.createElement("label", { className: "admin-field" },
                    React.createElement("span", null, "Eligible templates"),
                    React.createElement("select", { value: "", onChange: event => { if (event.target.value)
                            set('template_ids', [...value.template_ids, event.target.value]); } },
                        React.createElement("option", { value: "" }, value.template_ids.length ? 'Add another template' : 'All templates · choose to restrict'),
                        templates.filter(template => !value.template_ids.includes(template.id)).map(template => React.createElement("option", { key: template.id, value: template.id }, template.name))),
                    React.createElement("small", null, value.template_ids.length ? 'Only the selected templates qualify.' : 'Applies to every purchasable template.'))),
            value.template_ids.length > 0 && React.createElement("ul", { className: "admin-template-tags", "aria-label": "Eligible templates" }, value.template_ids.map(id => React.createElement("li", { key: id },
                adminTemplateName(id),
                React.createElement("button", { type: "button", "aria-label": 'Remove ' + adminTemplateName(id) + ' restriction', onClick: () => set('template_ids', value.template_ids.filter(item => item !== id)) }, "\u00D7"))))),
        React.createElement("p", { className: "admin-help" }, "Completed purchases and pending payments count toward limits. Changes affect new checkouts; amounts already issued for payment are honoured."));
}
function Admin({ openSignIn, user, goTo } = {}) {
    const [verified, setVerified] = React.useState(false), [checking, setChecking] = React.useState(true), [accessError, setAccessError] = React.useState(''), [accessRetry, setAccessRetry] = React.useState(0);
    const [overview, setOverview] = React.useState(null), [resource, setResource] = React.useState('users'), [records, setRecords] = React.useState(null), [offset, setOffset] = React.useState(0);
    const [search, setSearch] = React.useState(''), [query, setQuery] = React.useState(''), [status, setStatus] = React.useState('all'), [userFilter, setUserFilter] = React.useState(null);
    const [retry, setRetry] = React.useState(0), [notice, setNotice] = React.useState('');
    const [userId, setUserId] = React.useState(''), [detailRecord, setDetailRecord] = React.useState(null);
    const [action, setAction] = React.useState(null), [form, setForm] = React.useState({}), [saving, setSaving] = React.useState(false), [actionError, setActionError] = React.useState('');
    const [templatesEditable, setTemplatesEditable] = React.useState(false), [createTemplates, setCreateTemplates] = React.useState([]), [templatesLoading, setTemplatesLoading] = React.useState(false), [templatesError, setTemplatesError] = React.useState('');
    const savingRef = React.useRef(false), detailRef = React.useRef(null), identityRef = React.useRef(''), accessVersion = React.useRef(0), actionVersion = React.useRef(0);
    const listKey = JSON.stringify([resource, offset, query, status, userFilter?.id || null, retry, accessVersion.current]);
    const currentRecords = records?.key === listKey ? records : null;
    const rows = currentRecords?.rows || [], total = currentRecords?.total || 0;
    const loading = !currentRecords, error = currentRecords?.error || '';
    const detailKey = JSON.stringify([userId, retry, accessVersion.current]);
    const currentDetail = detailRecord?.key === detailKey ? detailRecord : null;
    const detail = currentDetail?.data || null, detailLoading = Boolean(userId && !currentDetail), detailError = currentDetail?.error || '';
    const promoTemplates = TemplateCatalog.all;
    const denyAccess = error => {
        if (![401, 403].includes(error.status))
            return false;
        accessVersion.current++;
        actionVersion.current++;
        identityRef.current = '';
        setVerified(false);
        setChecking(false);
        setRecords(null);
        setOverview(null);
        setDetailRecord(null);
        setUserId('');
        setAction(null);
        setNotice('');
        setCreateTemplates([]);
        setTemplatesEditable(false);
        setAccessError(error.message || 'Administrator access is required. Sign in with an authorised administrator account.');
        return true;
    };
    React.useEffect(() => {
        let cancelled = false;
        const version = ++accessVersion.current;
        setVerified(false);
        setChecking(true);
        setAccessError('');
        window.EA.me().then(({ user }) => { if (cancelled || version !== accessVersion.current)
            return; if (user?.isAdmin !== true)
            throw new Error('Administrator access is required. Sign in with an authorised administrator account.'); identityRef.current = user.id; setVerified(true); })
            .catch(err => { if (!cancelled && version === accessVersion.current) {
            setVerified(false);
            setRecords(null);
            setDetailRecord(null);
            setAccessError(err.message || 'Administrator access could not be verified.');
        } })
            .finally(() => { if (!cancelled && version === accessVersion.current)
            setChecking(false); });
        return () => { cancelled = true; if (version === accessVersion.current) {
            accessVersion.current++;
            actionVersion.current++;
        } };
    }, [accessRetry, user?.id, user?.isAdmin]);
    React.useEffect(() => {
        const onSession = event => {
            const user = event.detail?.user;
            if (user?.isAdmin === true && (!identityRef.current || identityRef.current === user.id))
                return;
            accessVersion.current++;
            actionVersion.current++;
            identityRef.current = '';
            setVerified(false);
            setChecking(false);
            setRecords(null);
            setOverview(null);
            setDetailRecord(null);
            setUserId('');
            setAction(null);
            setNotice('');
            setCreateTemplates([]);
            setTemplatesEditable(false);
            setAccessError('Sign in with an authorised administrator account to continue.');
            if (user?.isAdmin === true)
                setAccessRetry(value => value + 1);
        };
        window.addEventListener?.('everafter:session', onSession);
        return () => window.removeEventListener?.('everafter:session', onSession);
    }, []);
    React.useEffect(() => {
        if (!verified)
            return;
        let cancelled = false;
        const version = accessVersion.current;
        setRecords(null);
        Promise.all([window.EA.adminOverview(), window.EA.adminList(resource, { limit: ADMIN_PAGE_SIZE, offset, q: query, status, ...(userFilter ? { user_id: userFilter.id } : {}) })])
            .then(([summary, result]) => {
            if (cancelled || version !== accessVersion.current)
                return;
            const nextRows = result[resource], nextTotal = Number(result.total ?? nextRows?.length);
            if (!Array.isArray(nextRows) || !Number.isSafeInteger(nextTotal) || nextTotal < 0)
                throw new Error('Records could not be confirmed. Try again.');
            setOverview(summary);
            if (resource !== 'templates' && offset > 0 && offset >= nextTotal) {
                setOffset(Math.max(0, Math.floor((nextTotal - 1) / ADMIN_PAGE_SIZE) * ADMIN_PAGE_SIZE));
                return;
            }
            setRecords({ key: listKey, rows: nextRows, total: nextTotal });
            if (resource === 'templates')
                setTemplatesEditable(result.editable === true);
        })
            .catch(err => { if (!cancelled && version === accessVersion.current && !denyAccess(err))
            setRecords({ key: listKey, rows: [], total: 0, error: err.message || 'Records could not be loaded. Try again.' }); });
        return () => { cancelled = true; };
    }, [verified, listKey]);
    React.useEffect(() => {
        if (!verified || !userId) {
            setDetailRecord(null);
            return;
        }
        let cancelled = false;
        const version = accessVersion.current;
        setDetailRecord(null);
        window.EA.adminGetUser(userId).then(result => {
            if (cancelled || version !== accessVersion.current)
                return;
            if (result?.user?.id !== userId)
                throw new Error('Account details could not be confirmed. Try again.');
            setDetailRecord({ key: detailKey, data: result });
        }).catch(err => { if (!cancelled && version === accessVersion.current && !denyAccess(err))
            setDetailRecord({ key: detailKey, error: err.message || 'Account details could not be loaded.' }); });
        return () => { cancelled = true; };
    }, [verified, detailKey]);
    React.useEffect(() => { if (userId)
        detailRef.current?.focus?.(); }, [userId]);
    const chooseResource = (next, filter = null) => { if (savingRef.current)
        return; setResource(next); setOffset(0); setSearch(''); setQuery(''); setStatus('all'); setUserFilter(filter); setUserId(''); setDetailRecord(null); setNotice(''); };
    const loadCreateTemplates = async (version) => {
        setTemplatesLoading(true);
        setTemplatesError('');
        setCreateTemplates([]);
        try {
            const result = await window.EA.adminList('templates');
            if (version !== actionVersion.current)
                return;
            if (!Array.isArray(result.templates))
                throw new Error('Template availability could not be checked. Please try again.');
            const available = result.templates.filter(template => template.admin_creatable === true || (template.admin_creatable === undefined && TemplateCatalog.all.some(release => release.id === template.id && release.enabled && release.showInBuilder)));
            setCreateTemplates(available);
            setForm(previous => ({ ...previous, template_id: available.some(template => template.id === previous.template_id) ? previous.template_id : available[0]?.id || '' }));
        }
        catch (err) {
            if (version === actionVersion.current)
                setTemplatesError(err.message || 'Template availability could not be checked. Please try again.');
        }
        finally {
            if (version === actionVersion.current)
                setTemplatesLoading(false);
        }
    };
    const openAction = (kind, target) => {
        if (savingRef.current)
            return;
        if (kind === 'edit') {
            goTo?.('admin-builder', { projectId: target.id });
            return;
        }
        const version = ++actionVersion.current;
        setAction({ kind, target });
        setActionError('');
        setTemplatesError('');
        setForm(kind === 'promo' ? adminPromoDraft(target || {}) : { reason: '', visibility: target?.moderation_blocked ? 'draft' : target?.status === 'published' ? 'blocked' : 'published', template_id: '', name: '', email: target?.email || '', customer_name: '' });
        if (kind === 'create')
            loadCreateTemplates(version);
    };
    const closeAction = () => { if (!savingRef.current) {
        actionVersion.current++;
        setAction(null);
        setActionError('');
    } };
    const saveAction = async (event) => {
        event.preventDefault();
        if (!action || savingRef.current)
            return;
        const reason = String(form.reason || '').trim();
        if (reason.length < 4 || reason.length > 500) {
            setActionError('Add a reason between 4 and 500 characters.');
            return;
        }
        if (action.kind === 'create' && (templatesLoading || templatesError || !createTemplates.some(template => template.id === form.template_id))) {
            setActionError('Choose an available template before adding an invitation.');
            return;
        }
        const version = accessVersion.current;
        savingRef.current = true;
        setSaving(true);
        setActionError('');
        setNotice('');
        try {
            const { kind, target } = action;
            if (kind === 'block' || kind === 'unblock')
                await window.EA.adminBlockUser(target.id, { blocked: kind === 'block', reason });
            else if (kind === 'remove' || kind === 'restore')
                await window.EA.adminRemoveProject(target.id, { removed: kind === 'remove', reason });
            else if (kind === 'grant' || kind === 'revoke')
                await window.EA.adminProjectAccess(target.id, { active: kind === 'grant', reason });
            else if (kind === 'moderate')
                await window.EA.adminModerateProject(target.id, { published: form.visibility === 'published', blocked: form.visibility === 'blocked', reason });
            else if (kind === 'create') {
                const email = String(form.email || '').trim().toLowerCase();
                if (!target?.id && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email))
                    throw new Error('Enter a valid customer email address.');
                const result = await window.EA.adminCreateProject({ ...(target?.id ? { user_id: target.id } : { email, ...(form.customer_name.trim() ? { customer_name: form.customer_name.trim() } : {}) }), template_id: form.template_id, name: form.name.trim(), reason });
                if (version !== accessVersion.current)
                    return;
                if (!result?.project?.id || !result?.owner?.id || result.project.user_id !== result.owner.id)
                    throw new Error('The new invitation could not be confirmed. Refresh invitations before trying again.');
                setAction(null);
                setRetry(value => value + 1);
                setNotice('Complimentary invitation created for ' + result.owner.email + '.');
                goTo?.('admin-builder', { projectId: result.project.id, adminReason: reason });
                return;
            }
            else if (kind === 'promo') {
                const payload = adminPromoPayload(form);
                if (target?.id)
                    await window.EA.adminUpdatePromo(target.id, payload);
                else
                    await window.EA.adminCreatePromo(payload);
            }
            else if (kind === 'template-disable' || kind === 'template-enable') {
                const enabled = kind === 'template-enable';
                const result = await window.EA.adminTemplateAvailability(target.id, { enabled, expected_enabled: target.enabled === true, reason });
                if (version !== accessVersion.current)
                    return;
                if (result?.template?.id !== target.id || result.template.enabled !== enabled)
                    throw new Error('Template availability was not confirmed. Refresh the library and try again.');
                window.dispatchEvent?.(new CustomEvent('everafter:templates-changed', { detail: { template: result.template } }));
            }
            if (version !== accessVersion.current)
                return;
            const notices = { block: 'User blocked. Active sessions have been revoked.', unblock: 'User unblocked. They can sign in again.', remove: 'Invitation removed. Its public link is unavailable.', restore: 'Invitation restored as a draft.', grant: 'Complimentary publishing access granted.', revoke: 'Complimentary access revoked. Any paid access is retained.', moderate: 'Invitation visibility updated.', create: 'Invitation added to the user’s account.', promo: 'Promo code saved.' };
            const message = kind === 'template-disable' ? target.name + ' disabled for new invitations. Existing invitations still work.' : kind === 'template-enable' ? target.name + ' enabled for new invitations.' : notices[kind];
            setNotice(message + ' The change is recorded in Activity.');
            setAction(null);
            setRetry(value => value + 1);
        }
        catch (err) {
            if (version === accessVersion.current)
                setActionError(err.message || 'The change could not be saved. Please try again.');
        }
        finally {
            savingRef.current = false;
            setSaving(false);
        }
    };
    if (checking)
        return React.createElement("main", { className: "admin-studio admin-access" },
            React.createElement("div", { className: "admin-access-inner" },
                React.createElement("h1", null, "Everafter administration"),
                React.createElement("p", { role: "status" }, "Verifying administrator access\u2026")));
    if (!verified)
        return React.createElement("main", { className: "admin-studio admin-access" },
            React.createElement("div", { className: "admin-access-inner" },
                React.createElement("h1", null, "Administrator access"),
                React.createElement("p", { role: "alert" }, accessError || 'Administrator access is required.'),
                typeof openSignIn === 'function' && React.createElement("button", { className: "admin-button is-primary", onClick: () => openSignIn('admin') }, "Sign in to administration"),
                React.createElement("button", { className: "admin-button", onClick: () => setAccessRetry(value => value + 1) }, "Retry access check"),
                React.createElement("a", { className: "admin-button", href: window.EA_APP.path('/dashboard') }, "Go to my account")));
    const section = ADMIN_SECTIONS.find(([id]) => id === resource);
    const titles = { block: 'Block this user?', unblock: 'Unblock this user?', remove: 'Remove this invitation?', restore: 'Restore this invitation?', grant: 'Grant complimentary access?', revoke: 'Revoke complimentary access?', moderate: 'Review invitation visibility', create: 'Create for a customer', promo: action?.target?.id ? 'Edit promo code' : 'Create a promo code' };
    const impacts = { block: 'This user will be signed out, cannot sign in or make changes, and their public invitations will be unavailable until you unblock them.', unblock: 'This user can sign in again. Previously published invitations become available unless individually removed or under review.', remove: 'The invitation disappears from the user’s account and its public link stops working. Its content and payment records are retained so you can restore it.', restore: 'The invitation returns to the user’s account as a draft. Restoring it does not publish it.', grant: 'This invitation can be published without a payment. The grant is recorded separately from revenue and does not publish it automatically.', revoke: 'Remove only the complimentary grant for this invitation. A confirmed paid purchase remains valid.', moderate: 'Publishing requires valid content, publishing access and an active owner. Under review prevents owner publishing. Allow owner publishing clears that restriction and keeps the invitation as a draft.', create: 'Create a complimentary draft for this customer, then personalise it in the full builder.' };
    titles['template-disable'] = 'Disable this template?';
    titles['template-enable'] = 'Enable this template?';
    impacts['template-disable'] = 'This template will be hidden from the storefront and cannot be used for new invitations. Existing saved invitations, payments and published links will keep working. You can enable it again at any time.';
    impacts['template-enable'] = 'This template will appear in the storefront again and customers can use it for new invitations. Existing invitations stay unchanged.';
    return React.createElement("main", { className: "admin-studio" },
        React.createElement("div", { className: "admin-shell" },
            React.createElement("aside", { className: "admin-sidebar" },
                React.createElement("div", { className: "admin-brand" },
                    React.createElement("span", { className: "admin-brand-mark", "aria-hidden": "true" }, "E"),
                    React.createElement("div", null,
                        React.createElement("strong", null, "Everafter"),
                        React.createElement("span", null, "Administration"))),
                React.createElement("nav", { "aria-label": "Administration sections" }, ADMIN_SECTIONS.map(([id, label]) => React.createElement("button", { key: id, type: "button", disabled: saving, "aria-current": resource === id ? 'page' : undefined, onClick: () => chooseResource(id) },
                    React.createElement(AdminIcon, { name: id }),
                    React.createElement("span", null, label)))),
                React.createElement("div", { className: "admin-sidebar-note" },
                    React.createElement("strong", null, "Your invitation business"),
                    React.createElement("p", null, "Account support, publishing and offers in one place."),
                    React.createElement("a", { href: window.EA_APP.path('/templates') }, "Open storefront"))),
            React.createElement("section", { className: "admin-workspace", "aria-labelledby": "admin-page-title" },
                React.createElement("header", { className: "admin-page-heading" },
                    React.createElement("div", null,
                        React.createElement("h1", { id: "admin-page-title" }, section[1]),
                        React.createElement("p", null, section[2])),
                    ['users', 'projects'].includes(resource) && React.createElement("button", { className: "admin-button is-primary", onClick: () => openAction('create', null) }, "Create for customer"),
                    resource === 'promos' && React.createElement("button", { className: "admin-button is-primary", onClick: () => openAction('promo', null) }, "Create promo code"),
                    resource === 'templates' && React.createElement("button", { className: "admin-button", disabled: loading || saving, onClick: () => setRetry(value => value + 1) }, "Refresh library")),
                overview && React.createElement("dl", { className: "admin-overview" }, [['Users', overview.users], ['Live invitations', overview.published], ['Paid orders', overview.paidOrders], ['Confirmed net revenue', adminMoney(overview.revenuePaise)]].map(([label, value]) => React.createElement("div", { key: label },
                    React.createElement("dt", null, label),
                    React.createElement("dd", null, value ?? 0)))),
                notice && React.createElement("p", { className: "admin-notice", role: "status" }, notice),
                userId && React.createElement("section", { className: "admin-user-detail", ref: detailRef, tabIndex: -1, "aria-label": "Selected user details" },
                    React.createElement("div", { className: "admin-detail-top" },
                        React.createElement("h2", null, detail?.user?.name || 'Account details'),
                        React.createElement("button", { className: "admin-button", type: "button", onClick: () => { setUserId(''); setDetailRecord(null); } }, "Close details")),
                    detailLoading && React.createElement("p", { role: "status" }, "Loading this account\u2026"),
                    detailError && React.createElement("p", { className: "admin-error", role: "alert" },
                        detailError,
                        " ",
                        React.createElement("button", { className: "admin-text-button", onClick: () => setRetry(value => value + 1) }, "Try again")),
                    detail && React.createElement(React.Fragment, null,
                        React.createElement("div", { className: "admin-user-identity" },
                            React.createElement("div", null,
                                React.createElement("p", null, detail.user.email),
                                React.createElement("small", null,
                                    detail.user.phone || 'No phone number',
                                    " \u00B7 Joined ",
                                    adminDate(detail.user.created_at))),
                            React.createElement(AdminStatus, { tone: detail.user.blocked_at ? 'warning' : 'good' }, detail.user.blocked_at ? 'Blocked' : detail.user.isAdmin ? 'Administrator' : 'Active')),
                        detail.user.blocked_at && React.createElement("p", { className: "admin-help" },
                            "Block reason: ",
                            detail.user.block_reason || 'No reason recorded'),
                        React.createElement("div", { className: "admin-detail-actions" },
                            React.createElement("button", { className: "admin-button is-primary", disabled: Boolean(detail.user.blocked_at), onClick: () => openAction('create', detail.user) }, "Add invitation"),
                            React.createElement("button", { className: "admin-button", disabled: detail.user.isAdmin === true, onClick: () => openAction(detail.user.blocked_at ? 'unblock' : 'block', detail.user) }, detail.user.blocked_at ? 'Unblock user' : 'Block user'),
                            detail.user.isAdmin && React.createElement("small", null, "Administrator accounts cannot be blocked.")),
                        React.createElement("div", { className: "admin-subheading" },
                            React.createElement("h3", null, "Recent invitations"),
                            React.createElement("button", { className: "admin-text-button", onClick: () => chooseResource('projects', detail.user) }, "View all invitations")),
                        detail.projects?.length ? React.createElement("div", { className: "admin-record-scroll" },
                            React.createElement(AdminProjectRows, { projects: detail.projects, onAction: openAction, busy: saving })) : React.createElement("p", { className: "admin-empty-small" }, "This user has no invitations yet."),
                        React.createElement("div", { className: "admin-subheading" },
                            React.createElement("h3", null, "Recent payments"),
                            React.createElement("button", { className: "admin-text-button", onClick: () => chooseResource('orders', detail.user) }, "View all payments")),
                        detail.orders?.length ? React.createElement("ul", { className: "admin-recent-orders" }, detail.orders.slice(0, 5).map(order => React.createElement("li", { key: order.id },
                            React.createElement("div", null,
                                React.createElement("strong", null, adminTemplateName(order.template_id)),
                                React.createElement("small", null, adminDate(order.created_at))),
                            React.createElement("span", null, adminMoney(order.amount_paise)),
                            React.createElement(AdminStatus, { tone: order.status === 'paid' ? 'good' : '' }, order.status)))) : React.createElement("p", { className: "admin-empty-small" }, "No payments recorded."))),
                React.createElement("div", { className: "admin-record-area" },
                    resource !== 'templates' && React.createElement("form", { className: "admin-toolbar", role: "search", onSubmit: event => { event.preventDefault(); setOffset(0); setQuery(search.trim()); } },
                        React.createElement("label", { className: "admin-search" },
                            React.createElement("span", { className: "sr-only" },
                                "Search ",
                                section[1].toLowerCase()),
                            React.createElement("input", { type: "search", "aria-label": "Search " + section[1].toLowerCase(), value: search, maxLength: 100, onChange: event => setSearch(event.target.value), placeholder: resource === 'users' ? 'Search name or email' : resource === 'promos' ? 'Search code or name' : resource === 'audit' ? 'Search actions or reasons' : 'Search records' }),
                            React.createElement("button", { type: "submit", className: "admin-button", disabled: loading }, "Search")),
                        ADMIN_FILTERS[resource] && React.createElement("label", { className: "admin-filter" },
                            React.createElement("span", { className: "sr-only" },
                                "Filter ",
                                section[1].toLowerCase()),
                            React.createElement("select", { value: status, onChange: event => { setOffset(0); setStatus(event.target.value); } }, ADMIN_FILTERS[resource].map(([value, label]) => React.createElement("option", { value: value, key: value }, label)))),
                        React.createElement("button", { className: "admin-icon-button", "aria-label": "Refresh records", title: "Refresh records", type: "button", disabled: loading, onClick: () => setRetry(value => value + 1) }, "\u21BB")),
                    userFilter && React.createElement("p", { className: "admin-filter-note" },
                        "Showing records for ",
                        React.createElement("strong", null, userFilter.email || userFilter.name),
                        React.createElement("button", { className: "admin-text-button", onClick: () => { setUserFilter(null); setOffset(0); } }, "Show all accounts")),
                    resource === 'templates' && React.createElement("p", { className: "admin-filter-note" }, "Choose Change availability to enable or disable a design. Disabled templates are hidden from the storefront and unavailable for new invitations. Existing saved and published invitations keep working."),
                    resource === 'promos' && React.createElement("p", { className: "admin-filter-note" }, "Usage includes completed purchases and reserved payment orders. A disabled or expired code cannot start a new checkout."),
                    error && React.createElement("p", { className: "admin-error", role: "alert" },
                        error,
                        " ",
                        React.createElement("button", { className: "admin-text-button", onClick: () => setRetry(value => value + 1) }, "Try again")),
                    loading && React.createElement("p", { className: "admin-loading", role: "status" },
                        "Loading ",
                        section[1].toLowerCase(),
                        "\u2026"),
                    !loading && !error && rows.length > 0 && React.createElement("div", { className: "admin-record-scroll", role: "region", "aria-label": section[1] + ' records', tabIndex: 0 }, resource === 'projects' ? React.createElement(AdminProjectRows, { projects: rows, onAction: openAction, busy: saving, owners: true }) : React.createElement("table", { className: "admin-records" },
                        React.createElement("caption", { className: "sr-only" }, section[1]),
                        React.createElement("thead", null,
                            React.createElement("tr", null, (resource === 'users' ? ['User', 'Status', 'Joined', 'Actions'] : resource === 'orders' ? ['Payment', 'Customer', 'Amount', 'Status', 'Date'] : resource === 'promos' ? ['Code', 'Discount', 'Availability', 'Usage', 'Actions'] : resource === 'audit' ? ['Change', 'Account / invitation', 'Reason', 'Administrator', 'Date'] : ['Template', 'Price', 'Availability', 'Demo', 'Builder', 'Actions']).map(label => React.createElement("th", { scope: "col", key: label }, label)))),
                        React.createElement("tbody", null, rows.map(row => React.createElement("tr", { key: row.id }, resource === 'users' ? React.createElement(React.Fragment, null,
                            React.createElement("td", { "data-label": "User" },
                                React.createElement("strong", null, row.name || 'Unnamed account'),
                                React.createElement("small", null, row.email)),
                            React.createElement("td", { "data-label": "Status" },
                                React.createElement(AdminStatus, { tone: row.blocked_at ? 'warning' : row.isAdmin ? 'good' : '' }, row.blocked_at ? 'Blocked' : row.isAdmin ? 'Administrator' : 'Active')),
                            React.createElement("td", { "data-label": "Joined" }, adminDate(row.created_at)),
                            React.createElement("td", { "data-label": "Actions" },
                                React.createElement("button", { type: "button", className: "admin-button", "aria-expanded": userId === row.id, onClick: () => setUserId(row.id) }, "Manage user"))) :
                            resource === 'orders' ? React.createElement(React.Fragment, null,
                                React.createElement("td", { "data-label": "Payment" },
                                    React.createElement("strong", null, adminTemplateName(row.template_id)),
                                    React.createElement("small", { className: "admin-id" },
                                        "Order: ",
                                        row.id),
                                    row.payment_order_id && React.createElement("small", { className: "admin-id" },
                                        "Provider order: ",
                                        row.payment_order_id),
                                    row.payment_id && React.createElement("small", { className: "admin-id" },
                                        "Payment: ",
                                        row.payment_id),
                                    row.promo_code && React.createElement("small", null,
                                        "Code: ",
                                        row.promo_code)),
                                React.createElement("td", { "data-label": "Customer" }, row.owner_email || row.user_id || '—'),
                                React.createElement("td", { "data-label": "Amount" },
                                    React.createElement("strong", null, adminMoney(row.amount_paise)),
                                    Number(row.discount_paise) > 0 && React.createElement("small", null,
                                        adminMoney(row.discount_paise),
                                        " discount"),
                                    Number(row.refunded_paise) > 0 && React.createElement("small", null,
                                        adminMoney(row.refunded_paise),
                                        " refunded")),
                                React.createElement("td", { "data-label": "Status" },
                                    React.createElement(AdminStatus, { tone: row.status === 'paid' && (row.payment_verified_at || row.payment_provider === 'promotion') ? 'good' : '' }, row.status),
                                    adminPaymentVerification(row) && React.createElement("small", null, adminPaymentVerification(row))),
                                React.createElement("td", { "data-label": "Date" }, adminDate(row.created_at))) :
                                resource === 'promos' ? React.createElement(React.Fragment, null,
                                    React.createElement("td", { "data-label": "Code" },
                                        React.createElement("strong", null, row.code),
                                        row.label && React.createElement("small", null, row.label)),
                                    React.createElement("td", { "data-label": "Discount" },
                                        React.createElement("strong", null,
                                            row.discount_type === 'percent' ? row.discount_value + '%' : adminMoney(row.discount_value),
                                            " off"),
                                        React.createElement("small", null, row.template_ids?.length ? row.template_ids.length + ' selected templates' : 'All templates')),
                                    React.createElement("td", { "data-label": "Availability" },
                                        React.createElement(AdminStatus, { tone: adminPromoStatus(row) === 'Active' ? 'good' : '' }, adminPromoStatus(row)),
                                        row.ends_at && React.createElement("small", null,
                                            "Ends ",
                                            adminDate(row.ends_at))),
                                    React.createElement("td", { "data-label": "Usage" },
                                        React.createElement("strong", null,
                                            Number(row.redeemed_count || 0),
                                            " redeemed"),
                                        React.createElement("small", null,
                                            Number(row.reserved_count || 0),
                                            " reserved",
                                            row.max_redemptions ? ' / ' + row.max_redemptions + ' total limit' : '')),
                                    React.createElement("td", { "data-label": "Actions" },
                                        React.createElement("button", { className: "admin-button", onClick: () => openAction('promo', row) }, "Edit code"))) :
                                    resource === 'audit' ? React.createElement(React.Fragment, null,
                                        React.createElement("td", { "data-label": "Change" },
                                            React.createElement("strong", null, String(row.action || '').replace(/[_:.]+/g, ' '))),
                                        React.createElement("td", { "data-label": "Account / invitation" }, adminAuditTarget(row)),
                                        React.createElement("td", { "data-label": "Reason" },
                                            React.createElement("span", { className: "admin-audit-reason" }, row.reason)),
                                        React.createElement("td", { "data-label": "Administrator" }, row.actor_email || 'Administrator'),
                                        React.createElement("td", { "data-label": "Date" }, adminDate(row.created_at))) : React.createElement(React.Fragment, null,
                                        React.createElement("td", { "data-label": "Template" },
                                            React.createElement("strong", null, row.name),
                                            React.createElement("small", null, row.category || 'Invitation')),
                                        React.createElement("td", { "data-label": "Price" }, adminMoney(Number(row.price || 0) * 100)),
                                        React.createElement("td", { "data-label": "Availability" },
                                            React.createElement(AdminStatus, { tone: row.enabled ? 'good' : '' }, row.enabled ? 'Enabled' : 'Disabled')),
                                        React.createElement("td", { "data-label": "Demo" }, row.enabled && row.showInDemo ? 'Available' : 'Hidden'),
                                        React.createElement("td", { "data-label": "Builder" }, row.enabled && row.showInBuilder ? 'Available' : 'Hidden'),
                                        React.createElement("td", { "data-label": "Actions" },
                                            React.createElement(AdminTemplateMenu, { template: row, busy: saving, editable: templatesEditable, onAction: openAction })))))))),
                    !loading && !error && !rows.length && React.createElement("div", { className: "admin-empty" },
                        React.createElement(AdminIcon, { name: resource }),
                        React.createElement("h2", null, query || status !== 'all' ? 'No matching records' : resource === 'promos' ? 'Your first offer starts here' : 'No ' + section[1].toLowerCase() + ' yet'),
                        React.createElement("p", null, query || status !== 'all' ? 'Try another search or choose a different filter.' : resource === 'promos' ? 'Create a code customers can apply before they pay.' : 'Records will appear here when they become available.'),
                        resource === 'promos' && !query && React.createElement("button", { className: "admin-button is-primary", onClick: () => openAction('promo', null) }, "Create promo code")),
                    resource !== 'templates' && !error && React.createElement("div", { className: "admin-pagination" },
                        React.createElement("span", { "aria-live": "polite" }, loading ? 'Loading records…' : `${rows.length ? offset + 1 : 0}–${Math.min(offset + rows.length, total)} of ${total}`),
                        React.createElement("div", null,
                            React.createElement("button", { className: "admin-button", disabled: !offset || loading || saving, onClick: () => setOffset(value => Math.max(0, value - ADMIN_PAGE_SIZE)) }, "Previous"),
                            React.createElement("button", { className: "admin-button", disabled: loading || saving || !rows.length || offset + rows.length >= total, onClick: () => setOffset(value => value + ADMIN_PAGE_SIZE) }, "Next")))))),
        action && React.createElement(AdminDialog, { title: titles[action.kind], busy: saving, onClose: closeAction },
            React.createElement("form", { onSubmit: saveAction },
                React.createElement("fieldset", { disabled: saving },
                    action.kind !== 'promo' && React.createElement(React.Fragment, null,
                        React.createElement("p", { className: "admin-action-target" }, action.target?.email || action.target?.name || (action.target?.template_id ? adminTemplateName(action.target.template_id) : '')),
                        React.createElement("p", { className: "admin-action-impact" }, impacts[action.kind])),
                    action.kind === 'moderate' && React.createElement("label", { className: "admin-field" },
                        React.createElement("span", null, "Visibility"),
                        React.createElement("select", { value: form.visibility, onChange: event => setForm({ ...form, visibility: event.target.value }) },
                            React.createElement("option", { value: "blocked" }, "Unpublish and place under review"),
                            React.createElement("option", { value: "draft" }, "Allow owner publishing \u00B7 keep as draft"),
                            React.createElement("option", { value: "published" }, "Publish and clear review"))),
                    action.kind === 'create' && React.createElement("div", { className: "admin-form-grid" },
                        React.createElement("label", { className: "admin-field admin-field-wide" },
                            React.createElement("span", null, "Customer email"),
                            React.createElement("input", { type: "email", required: true, maxLength: 254, autoComplete: "off", value: form.email, readOnly: Boolean(action.target?.id), onChange: event => setForm({ ...form, email: event.target.value }), placeholder: "customer@example.com" }),
                            React.createElement("small", null, action.target?.id ? 'Assigned directly to this account.' : 'An account is prepared automatically if needed. The customer verifies this email through normal sign-in; no password or message is sent.')),
                        !action.target?.id && React.createElement("label", { className: "admin-field admin-field-wide" },
                            React.createElement("span", null,
                                "Customer name ",
                                React.createElement("small", null, "(optional)")),
                            React.createElement("input", { maxLength: 100, value: form.customer_name, onChange: event => setForm({ ...form, customer_name: event.target.value }), placeholder: "Used only for a new account" })),
                        React.createElement("label", { className: "admin-field admin-field-wide" },
                            React.createElement("span", null, "Template"),
                            React.createElement("select", { required: true, disabled: templatesLoading || Boolean(templatesError) || !createTemplates.length, value: form.template_id, onChange: event => setForm({ ...form, template_id: event.target.value }) },
                                React.createElement("option", { value: "", disabled: true }, templatesLoading ? 'Loading designs...' : createTemplates.length ? 'Choose a template' : 'No templates available'),
                                createTemplates.map(template => React.createElement("option", { value: template.id, key: template.id },
                                    template.name,
                                    !template.enabled ? ' (hidden from storefront)' : ''))),
                            React.createElement("small", null, "Administration can use released designs even when hidden from the storefront.")),
                        React.createElement("label", { className: "admin-field admin-field-wide" },
                            React.createElement("span", null,
                                "Invitation name ",
                                React.createElement("small", null, "(optional)")),
                            React.createElement("input", { maxLength: 120, value: form.name, onChange: event => setForm({ ...form, name: event.target.value }), placeholder: "Aanya and Aarav wedding" })),
                        React.createElement("p", { className: "admin-help admin-field-wide" }, "Complimentary publishing is included. This creates a draft; it does not publish automatically.")),
                    action.kind === 'create' && templatesError && React.createElement("p", { className: "admin-error", role: "alert" },
                        templatesError,
                        " ",
                        React.createElement("button", { type: "button", className: "admin-text-button", onClick: () => loadCreateTemplates(actionVersion.current) }, "Try again")),
                    action.kind === 'create' && !templatesLoading && !templatesError && !createTemplates.length && React.createElement("p", { className: "admin-help" }, "No released builder designs are available in this installation."),
                    action.kind === 'promo' && React.createElement(AdminPromoForm, { value: form, onChange: setForm, templates: promoTemplates, editing: Boolean(action.target?.id) }),
                    React.createElement("label", { className: "admin-field" },
                        React.createElement("span", null, "Reason for this change"),
                        React.createElement("textarea", { required: true, minLength: 4, maxLength: 500, rows: 3, value: form.reason || '', onChange: event => setForm({ ...form, reason: event.target.value }), placeholder: "Record why you are making this change" }),
                        React.createElement("small", null, "Saved in the administrator activity log.")),
                    actionError && React.createElement("p", { className: "admin-error", role: "alert" }, actionError),
                    React.createElement("div", { className: "admin-dialog-actions" },
                        React.createElement("button", { type: "button", className: "admin-button", onClick: closeAction }, "Cancel"),
                        React.createElement("button", { className: 'admin-button ' + (['block', 'remove', 'revoke', 'template-disable'].includes(action.kind) ? 'is-danger' : 'is-primary'), type: "submit", disabled: action.kind === 'create' && (templatesLoading || Boolean(templatesError) || !createTemplates.length) }, saving ? 'Saving…' : action.kind === 'promo' ? 'Save promo code' : action.kind === 'create' ? 'Create & edit' : action.kind === 'moderate' ? 'Update visibility' : { block: 'Block user', unblock: 'Unblock user', remove: 'Remove invitation', restore: 'Restore as draft', grant: 'Grant access', revoke: 'Revoke access', 'template-disable': 'Disable template', 'template-enable': 'Enable template' }[action.kind]))))));
}
Object.assign(window, { Admin });
function AdminBuilder({ projectId, template, user, goTo, openSignIn, t, initialReason = '' }) {
    const [record, setRecord] = React.useState(null), [retry, setRetry] = React.useState(0);
    const [reason, setReason] = React.useState(initialReason || (!projectId ? 'Create my complimentary invitation' : ''));
    const [error, setError] = React.useState(''), [conflict, setConflict] = React.useState(''), [saving, setSaving] = React.useState(false);
    const apiRef = React.useRef(null), generation = React.useRef(0), busyRef = React.useRef(false);
    const scope = JSON.stringify([projectId || '', template?.id || '', user?.id || '', user?.isAdmin === true, retry]);
    const current = record?.scope === scope ? record : null;
    const install = (data, editingReason, version) => {
        if (version !== generation.current)
            return;
        apiRef.current?.dispose();
        const api = window.EA.createAdminEditor({ ...data, reason: editingReason, onConflict: err => { if (version === generation.current)
                setConflict(err.message); }, onAccessError: err => { if (version === generation.current) {
                setRecord({ scope, error: err.message });
                setError('');
            } } });
        apiRef.current = api;
        setRecord({ scope, ...data, api });
        setConflict('');
        setError('');
    };
    React.useEffect(() => {
        const version = ++generation.current;
        let cancelled = false;
        apiRef.current?.dispose();
        apiRef.current = null;
        setError('');
        setConflict('');
        setSaving(false);
        busyRef.current = false;
        (async () => {
            const verified = await window.EA.me();
            if (cancelled || version !== generation.current)
                return;
            if (verified?.user?.isAdmin !== true || verified.user.id !== user?.id)
                throw new Error('Sign in with an authorised administrator account to edit this invitation.');
            if (!projectId) {
                setRecord({ scope, actor: verified.user });
                return;
            }
            const data = await window.EA.adminGetProject(projectId);
            if (cancelled || version !== generation.current)
                return;
            if (data?.project?.id !== projectId || data.project.user_id !== data.owner?.id || !data.project.authoring_revision || !TemplateCatalog.get(data.project.template_id))
                throw new Error('The invitation and its owner could not be confirmed. Return to administration and open it again.');
            if (data.project.deleted_at || data.owner.blocked_at)
                throw new Error('Restore the invitation or unblock its owner in administration before editing.');
            if (data.project.moderation_blocked)
                throw new Error('Release the publishing restriction in administration before editing.');
            setRecord({ scope, ...data });
            if (initialReason.trim().length >= 4 && initialReason.trim().length <= 500)
                install(data, initialReason.trim(), version);
        })().catch(err => { if (!cancelled && version === generation.current)
            setRecord({ scope, error: err.message || 'The invitation could not be opened. Try again.' }); });
        return () => { cancelled = true; generation.current++; apiRef.current?.dispose(); apiRef.current = null; };
    }, [scope]);
    const start = async (event) => {
        event.preventDefault();
        if (busyRef.current)
            return;
        const auditReason = reason.trim();
        if (auditReason.length < 4 || auditReason.length > 500) {
            setError('Add an editing reason between 4 and 500 characters.');
            return;
        }
        const version = generation.current;
        busyRef.current = true;
        setSaving(true);
        setError('');
        try {
            if (current?.project)
                install(current, auditReason, version);
            else if (current?.actor && template) {
                const data = await window.EA.adminCreateProject({ user_id: current.actor.id, template_id: template.id, name: template.name, reason: auditReason });
                if (version !== generation.current)
                    return;
                if (!data?.project?.id || data.project.user_id !== current.actor.id || data.owner?.id !== current.actor.id)
                    throw new Error('The invitation could not be confirmed. Return to administration before trying again.');
                goTo('admin-builder', { projectId: data.project.id, adminReason: auditReason });
            }
        }
        catch (err) {
            if (version === generation.current)
                setError(err.message || 'The editor could not be started.');
        }
        finally {
            if (version === generation.current) {
                busyRef.current = false;
                setSaving(false);
            }
        }
    };
    const back = () => goTo('admin', { projectId: null });
    if (!current)
        return React.createElement("main", { className: "admin-studio admin-access" },
            React.createElement("div", { className: "admin-access-inner" },
                React.createElement("h1", null, "Opening the invitation"),
                React.createElement("p", { role: "status" }, "Verifying administrator access and ownership..."),
                React.createElement("button", { className: "admin-button", onClick: back }, "Back to administration")));
    if (current.error)
        return React.createElement("main", { className: "admin-studio admin-access" },
            React.createElement("div", { className: "admin-access-inner" },
                React.createElement("h1", null, "Invitation editor"),
                React.createElement("p", { className: "admin-error", role: "alert" }, current.error),
                React.createElement("div", { className: "admin-detail-actions" },
                    React.createElement("button", { className: "admin-button is-primary", onClick: () => setRetry(value => value + 1) }, "Try again"),
                    !user && React.createElement("button", { className: "admin-button", onClick: () => openSignIn('admin-builder') }, "Sign in to administration"),
                    React.createElement("button", { className: "admin-button", onClick: back }, "Back to administration"))));
    const ownerEmail = current.owner?.email || current.actor?.email || '';
    if (!current.api)
        return React.createElement("main", { className: "admin-studio admin-access" },
            React.createElement("div", { className: "admin-access-inner admin-authoring-start" },
                React.createElement("h1", null, projectId ? 'Edit this invitation' : 'Create your invitation'),
                React.createElement("p", null,
                    projectId ? 'Personalise the full invitation for ' + ownerEmail + '.' : 'Create ' + (template?.name || 'an invitation') + ' in your administrator account.',
                    " Complimentary publishing is included."),
                React.createElement("form", { onSubmit: start },
                    React.createElement("fieldset", { disabled: saving },
                        React.createElement("label", { className: "admin-field" },
                            React.createElement("span", null, "Reason for editing"),
                            React.createElement("textarea", { required: true, minLength: 4, maxLength: 500, rows: 3, value: reason, onChange: event => setReason(event.target.value), placeholder: "For example: Personalise the invitation requested by this customer" }),
                            React.createElement("small", null, "Recorded with changes made during this editing session.")),
                        error && React.createElement("p", { className: "admin-error", role: "alert" }, error),
                        React.createElement("div", { className: "admin-detail-actions" },
                            React.createElement("button", { type: "submit", className: "admin-button is-primary" }, saving ? 'Opening...' : projectId ? 'Open full builder' : 'Create & edit'),
                            React.createElement("button", { type: "button", className: "admin-button", onClick: back }, "Back to administration"))))));
    const Provider = window.EA_BUILDER_API_CONTEXT.Provider;
    const selected = TemplateCatalog.get(current.project.template_id);
    return React.createElement(React.Fragment, null,
        React.createElement("section", { className: "admin-studio admin-authoring-bar", "aria-label": "Administrator editing session" },
            React.createElement("div", null,
                React.createElement("strong", null,
                    "Editing for ",
                    ownerEmail),
                React.createElement("span", null,
                    selected.name,
                    ". Complimentary publishing")),
            React.createElement("button", { type: "button", className: "admin-button", onClick: back }, "Back to administration"),
            conflict && React.createElement("div", { className: "admin-authoring-conflict", role: "alert" },
                React.createElement("p", null,
                    conflict,
                    " Your unsaved draft remains on this device."),
                React.createElement("button", { type: "button", className: "admin-button", onClick: () => { apiRef.current?.dispose(); setRetry(value => value + 1); } }, "Reload latest invitation"))),
        React.createElement(Provider, { value: current.api },
            React.createElement(Builder, { key: scope, goTo: (view, options) => ['dashboard', 'builder', 'gallery'].includes(view) ? back() : goTo(view, options), t: t, template: selected, user: user, openSignIn: () => openSignIn('admin-builder'), projectId: current.project.id })));
}
window.AdminBuilder = AdminBuilder;
