(function (root, factory) { if (typeof module === 'object' && module.exports) { module.exports = factory(root); return; } root.FamilyInvitePages = factory(root); if (root.document) root.document.addEventListener('DOMContentLoaded', root.FamilyInvitePages.init); })(typeof globalThis !== 'undefined' ? globalThis : window, function (root) { 'use strict'; var STATUS_TEXT = { ACTIVE: '待使用', REDEEMED: '已使用', REVOKED: '已撤销', EXPIRED: '已过期' }; function escapeHtml(value) { return String(value === undefined || value === null ? '' : value) .replace(/&/g, '&').replace(//g, '>') .replace(/"/g, '"').replace(/'/g, '''); } function normalizeId(value) { var text = String(value === undefined || value === null ? '' : value).trim(); return /^[1-9][0-9]*$/.test(text) ? text : ''; } function normalizeInvitation(item) { var source = item || {}; var inviteId = normalizeId(source.inviteId); var genealogyId = normalizeId(source.genealogyId); if (!inviteId || !genealogyId || !String(source.genealogyName || '').trim()) return null; return { inviteId: inviteId, genealogyId: genealogyId, genealogyName: String(source.genealogyName).trim(), lineagePersonName: String(source.lineagePersonName || '').trim(), status: String(source.status || '').toUpperCase(), token: String(source.token || '').trim(), expiresAt: String(source.expiresAt || '').trim(), createTime: String(source.createTime || '').trim() }; } function invitationLink(token) { var base; if (!token) return ''; if (!root.location) return 'profile-invite.html?token=' + encodeURIComponent(token); base = String(root.location.href || '').split('?')[0].split('#')[0]; return base + '?token=' + encodeURIComponent(token); } function renderInvitations(items) { var list = Array.isArray(items) ? items.map(normalizeInvitation).filter(Boolean) : []; if (!list.length) return '
还没有发出的邀请
'; return list.map(function (item) { var canRevoke = item.status === 'ACTIVE'; return '

' + escapeHtml(item.genealogyName) + (item.lineagePersonName ? ' · ' + escapeHtml(item.lineagePersonName) : '') + '

' + escapeHtml([item.createTime, item.expiresAt ? '有效期至 ' + item.expiresAt : ''].filter(Boolean).join(' · ')) + '

' + escapeHtml(STATUS_TEXT[item.status] || item.status || '未知') + '' + (canRevoke ? '' : '') + '
'; }).join(''); } function redirectToLogin(api) { if (api && api.clearToken) api.clearToken(); if (root.location) root.location.href = 'login.html'; } async function init() { var page = root.document && root.document.querySelector('[data-family-invite-page]'); var api = root.GenealogyApi && root.GenealogyApi.defaultClient; var genealogyId = root.ProfileUI && root.ProfileUI.getGenealogyId ? root.ProfileUI.getGenealogyId() : ''; var form = page && page.querySelector('[data-invite-form]'); var personSelect = page && page.querySelector('[data-invite-person]'); var status = page && page.querySelector('[data-invite-status]'); var result = page && page.querySelector('[data-invite-result]'); var list = page && page.querySelector('[data-invite-list]'); var redeem = page && page.querySelector('[data-invite-redeem]'); var token = root.location ? new URLSearchParams(root.location.search).get('token') : ''; var pending = false; if (!page) return; if (!api || !api.getToken || !api.getToken()) return redirectToLogin(api); if (token && redeem) { form.hidden = true; list.hidden = true; redeem.hidden = false; redeem.querySelector('[data-invite-token]').textContent = token; try { var preview = normalizeInvitation(await api.previewGenealogyInvitation(token)); if (!preview) throw new Error('邀请预览响应无效'); redeem.querySelector('h3').textContent = '接受“' + preview.genealogyName + '”邀请'; setStatus('', preview.expiresAt ? '邀请有效期至 ' + preview.expiresAt : '请确认是否加入该家谱'); } catch (error) { setStatus('error', error.message || '邀请预览失败'); redeem.querySelector('[data-invite-redeem-submit]').disabled = true; return; } redeem.querySelector('[data-invite-redeem-submit]').addEventListener('click', async function () { if (pending) return; pending = true; setStatus('loading', '正在接受邀请…'); try { await api.redeemGenealogyInvitation({ token: token }); setStatus('', '邀请已接受,你已加入该家谱。'); } catch (error) { setStatus('error', error.message || '接受邀请失败'); } finally { pending = false; } }); return; } if (!genealogyId) { root.ProfileUI.setApiState(status, 'error', '缺少家谱上下文,请从“我的家谱”重新进入。'); return; } function setStatus(type, message) { if (type) root.ProfileUI.setApiState(status, type, message); else status.textContent = message || ''; } async function loadList() { var invitations = await api.myGenealogyInvitations(); list.innerHTML = renderInvitations(invitations); } try { var initial = await Promise.all([api.lineagePersonOptions(genealogyId), api.myGenealogyInvitations()]); personSelect.innerHTML = '' + (Array.isArray(initial[0]) ? initial[0] : []).map(function (item) { var id = normalizeId(item.personId || item.lineagePersonId); var name = String(item.displayName || item.personName || item.name || '').trim(); return id && name ? '' : ''; }).join(''); list.innerHTML = renderInvitations(initial[1]); setStatus('', '可生成一次性邀请链接'); } catch (error) { setStatus('error', error.message || '邀请服务读取失败'); } form.addEventListener('submit', async function (event) { var body = {}; var created; var link; event.preventDefault(); if (pending) return; if (personSelect.value) body.lineagePersonId = personSelect.value; pending = true; setStatus('loading', '正在生成邀请…'); try { created = normalizeInvitation(await api.issueGenealogyInvitation(genealogyId, body)); if (!created || !created.token) throw new Error('邀请已创建,但响应缺少一次性令牌'); link = invitationLink(created.token); result.hidden = false; result.querySelector('[data-invite-link]').value = link; setStatus('', '邀请已生成,请及时复制给家人。'); await loadList(); } catch (error) { setStatus('error', error.message || '邀请生成失败'); } finally { pending = false; } }); result.querySelector('[data-invite-copy]').addEventListener('click', async function () { var value = result.querySelector('[data-invite-link]').value; try { await root.navigator.clipboard.writeText(value); setStatus('', '邀请链接已复制'); } catch (error) { result.querySelector('[data-invite-link]').select(); setStatus('', '请按 Ctrl+C 复制邀请链接'); } }); list.addEventListener('click', async function (event) { var button = event.target.closest('[data-invite-revoke]'); if (!button || pending) return; pending = true; setStatus('loading', '正在撤销邀请…'); try { await api.revokeGenealogyInvitation(button.getAttribute('data-invite-revoke')); await loadList(); setStatus('', '邀请已撤销'); } catch (error) { setStatus('error', error.message || '撤销邀请失败'); } finally { pending = false; } }); } return { normalizeInvitation: normalizeInvitation, invitationLink: invitationLink, renderInvitations: renderInvitations, init: init }; });