diff --git a/client/admin.js b/client/admin.js
index 766057d..b40bbae 100644
--- a/client/admin.js
+++ b/client/admin.js
@@ -454,7 +454,8 @@ async function loadInvites() {
${status} |
${invite.is_active && !isExpired && invite.remaining_uses > 0
- ? ``
+ ? `
+ `
: '-'
}
|
@@ -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) {
if (!confirm(`Are you sure you want to revoke invite code ${code}?`)) return;
diff --git a/client/app.js b/client/app.js
index 94d8e67..4e22926 100644
--- a/client/app.js
+++ b/client/app.js
@@ -4672,8 +4672,9 @@ class AuthManager {
this.forgotForm?.addEventListener('submit', (e) => this.handleForgotPassword(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.checkInviteCode();
}
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) {
e.preventDefault();
this.clearErrors();