Add copy invite link button and auto-populate invite code from URL

Admin panel gets "Copy Link" button on active invites that copies
a signup URL with ?invite= param. Client auto-opens signup form
with invite code pre-filled when visiting that link.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken 2026-02-21 23:54:06 -05:00
parent 538ca51ba5
commit 797d1e0280
2 changed files with 26 additions and 2 deletions

View File

@ -454,7 +454,8 @@ async function loadInvites() {
<td>${status}</td> <td>${status}</td>
<td> <td>
${invite.is_active && !isExpired && invite.remaining_uses > 0 ${invite.is_active && !isExpired && invite.remaining_uses > 0
? `<button class="btn btn-small btn-danger" onclick="promptRevokeInvite('${invite.code}')">Revoke</button>` ? `<button class="btn btn-small" onclick="copyInviteLink('${invite.code}')">Copy Link</button>
<button class="btn btn-small btn-danger" onclick="promptRevokeInvite('${invite.code}')">Revoke</button>`
: '-' : '-'
} }
</td> </td>
@ -619,6 +620,16 @@ async function handleCreateInvite() {
} }
} }
function copyInviteLink(code) {
const link = `${window.location.origin}/?invite=${encodeURIComponent(code)}`;
navigator.clipboard.writeText(link).then(() => {
showToast('Invite link copied!', 'success');
}).catch(() => {
// Fallback: select text for manual copy
prompt('Copy this link:', link);
});
}
async function promptRevokeInvite(code) { async function promptRevokeInvite(code) {
if (!confirm(`Are you sure you want to revoke invite code ${code}?`)) return; if (!confirm(`Are you sure you want to revoke invite code ${code}?`)) return;

View File

@ -4672,8 +4672,9 @@ class AuthManager {
this.forgotForm?.addEventListener('submit', (e) => this.handleForgotPassword(e)); this.forgotForm?.addEventListener('submit', (e) => this.handleForgotPassword(e));
this.resetForm?.addEventListener('submit', (e) => this.handleResetPassword(e)); this.resetForm?.addEventListener('submit', (e) => this.handleResetPassword(e));
// Check URL for reset token on page load // Check URL for reset token or invite code on page load
this.checkResetToken(); this.checkResetToken();
this.checkInviteCode();
} }
showModal(form = 'login') { showModal(form = 'login') {
@ -4826,6 +4827,18 @@ class AuthManager {
} }
} }
checkInviteCode() {
const params = new URLSearchParams(window.location.search);
const invite = params.get('invite');
if (invite) {
this.signupInviteCode.value = invite;
this.showModal('signup');
// Clean URL
window.history.replaceState({}, '', '/');
}
}
async handleForgotPassword(e) { async handleForgotPassword(e) {
e.preventDefault(); e.preventDefault();
this.clearErrors(); this.clearErrors();