feature: switch everything to an invite-only model

This commit is contained in:
Andy Burke 2025-10-08 17:38:23 -07:00
parent a3302d2eff
commit 49c7a135d0
10 changed files with 445 additions and 3 deletions

View file

@ -32,6 +32,76 @@
document.addEventListener("topics_updated", update_topic_indicators);
document.addEventListener("topic_changed", update_topic_indicators);
document.addEventListener("user_logged_in", update_topic_indicators);
function generate_invite(click_event) {
const button = click_event.target;
document.body.querySelectorAll(".invitepopover").forEach((element) => element.remove());
const invite_div = document.createElement("div");
invite_div.classList.add("invitepopover");
invite_div.innerHTML = `<form>
<input name="code" type="text" placeholder="Custom code (optional)">
<button onclick="create_invite(event);">Generate</button>
</form>`;
document.body.appendChild(invite_div);
invite_div.style.left = button.getBoundingClientRect().left + "px";
invite_div.style.top = button.getBoundingClientRect().top + "px";
}
async function create_invite(click_event) {
click_event.preventDefault();
const button = click_event.target;
const invite_popover = document.body.querySelector(".invitepopover");
if (!invite_popover) {
alert("Unknown error, try again.");
return;
}
const user = document.body.dataset.user && JSON.parse(document.body.dataset.user);
if (!user) {
alert("You must be logged in.");
return;
}
const form = button.closest("form");
const code_input = form.querySelector('[name="code"]');
const invite_code_response = await api.fetch(`/api/users/${user.id}/invites`, {
method: "POST",
json: {
code: code_input.value,
},
});
if (!invite_code_response.ok) {
const error = await invite_code_response.json();
return alert(error?.error?.message ?? error?.errors?.[0]?.message ?? "Unknown error.");
}
const invite_code = await invite_code_response.json();
console.dir({
invite_code,
});
invite_popover.innerHTML = `
<div>
<div class="share-option">
<span class="name">Code</span>
<input readonly type="text" name="code" value="${invite_code.code}" />
<button onclick="navigator.clipboard.writeText('${invite_code.code}');" />Copy</button>
</div>
<div class="share-option">
<span class="name">Link</span>
<input readonly type="text" name="code" value="${window.location.protocol + "//" + window.location.host + "/?invite_code=" + encodeURIComponent(invite_code.code)}" />
<button onclick="navigator.clipboard.writeText('${window.location.protocol + "//" + window.location.host + "/?invite_code=" + encodeURIComponent(invite_code.code)}');" />Copy</button>
</div>
<button onclick="( () => document.querySelectorAll( '.invitepopover' ).forEach( (element) => element.remove() ) )()">Done</button>
</div>`;
}
</script>
<style type="text/css">
@ -147,6 +217,42 @@
#sidebar .topic-list > li.topic.active a {
color: var(--accent);
}
.invitepopover {
position: fixed;
z-index: 1000;
background: var(--bg);
margin: 1rem;
border: 1px solid var(--border-normal);
border-radius: var(--border-radius);
padding: 1rem;
}
.invitepopover .share-option .name {
text-transform: uppercase;
min-width: 4rem;
display: inline-block;
}
.share-option input {
padding: 0.75rem;
margin: 0 1rem 1rem 0;
background: none;
color: var(--text);
border: 1px solid var(--border-highlight);
border-radius: var(--border-radius);
box-shadow: none;
font-size: large;
width: 15rem;
}
.share-option button {
padding: 1rem;
text-transform: uppercase;
border: 1px solid var(--border-subtle);
border-radius: var(--border-radius);
margin-left: -0.75rem;
}
</style>
<div id="sidebar">
@ -381,6 +487,13 @@
</details>
</form>
<button
style="text-transform: uppercase; width: 100%; padding: 1.1rem 0"
onclick="generate_invite(event)"
>
Invite Another Human
</button>
<form
data-smart="true"
data-method="DELETE"