Skip to content

Commit 38e3e13

Browse files
committed
invites menus
1 parent 5963d6f commit 38e3e13

File tree

5 files changed

+153
-5
lines changed

5 files changed

+153
-5
lines changed

src/webpage/channel.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import {Message} from "./message.js";
33
import {AVoice} from "./audio/voice.js";
44
import {Contextmenu} from "./contextmenu.js";
5-
import {Guild} from "./guild.js";
5+
import {Guild, makeInviteMenu} from "./guild.js";
66
import {Localuser} from "./localuser.js";
77
import {Permissions} from "./permissions.js";
88
import {Dialog, Float, Settings} from "./settings.js";
@@ -270,6 +270,9 @@ class Channel extends SnowFlake {
270270
),
271271
);
272272

273+
const inviteMenu = settings.addButton(I18n.guild.invites());
274+
makeInviteMenu(inviteMenu, this.owner, this.info.api + `/channels/${this.id}/invites`);
275+
273276
const webhooks = settings.addButton(I18n.webhooks.base());
274277
webhookMenu(this.guild, this.info.api + `/channels/${this.id}/webhooks`, webhooks, this.id);
275278

src/webpage/guild.ts

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,138 @@ import {webhookMenu} from "./webhooks.js";
2424
import {createImg} from "./utils/utils.js";
2525
import {Sticker} from "./sticker.js";
2626
import {ProgessiveDecodeJSON} from "./utils/progessiveLoad.js";
27+
export async function makeInviteMenu(inviteMenu: Options, guild: Guild, url: string) {
28+
const invDiv = document.createElement("div");
29+
const bansp = ProgessiveDecodeJSON<invitejson[]>(url, {
30+
headers: guild.headers,
31+
});
32+
const createInviteHTML = (invite: invitejson) => {
33+
const div = document.createElement("div");
34+
div.classList.add("templateMiniBox");
35+
36+
const edit = document.createElement("button");
37+
edit.textContent = I18n.edit();
38+
39+
const code = document.createElement("span");
40+
code.textContent = invite.code;
41+
42+
const used = document.createElement("span");
43+
used.textContent = I18n.invite.used(invite.uses + "");
44+
45+
edit.onclick = () => {
46+
const opt = inviteMenu.addSubOptions(invite.code);
47+
const inviter = new User(invite.inviter, guild.localuser);
2748

49+
opt.addMDText(
50+
window.location.origin +
51+
"/invite/" +
52+
invite.code +
53+
"?" +
54+
new URLSearchParams([["instance", guild.info.wellknown]]),
55+
);
56+
57+
opt.addText(I18n.invite.used(invite.uses + ""));
58+
if (invite.max_uses !== 0) opt.addText(I18n.invite.maxUses(invite.max_uses + ""));
59+
60+
const channel = guild.channels.find((_) => _.id == invite.channel_id);
61+
if (channel) {
62+
opt.addText(I18n.invite.forChannel(channel.name));
63+
}
64+
65+
opt.addText(I18n.invite.createdAt(new Date(invite.created_at).toLocaleDateString(I18n.lang)));
66+
67+
let expires = I18n.invite.never();
68+
if (invite.expires_at) {
69+
expires = new Date(invite.expires_at).toLocaleDateString(I18n.lang);
70+
}
71+
opt.addText(I18n.invite.expires(expires));
72+
73+
opt.addText(I18n.webhooks.createdBy());
74+
opt.addHTMLArea(inviter.createWidget(guild));
75+
76+
opt.addButtonInput("", I18n.delete(), async () => {
77+
if (
78+
(
79+
await fetch(guild.info.api + "/invites/" + invite.code, {
80+
method: "DELETE",
81+
headers: guild.headers,
82+
})
83+
).ok
84+
) {
85+
invsArr = invsArr.filter((_) => _ !== invite);
86+
inviteMenu.returnFromSub();
87+
loadPage(currentPage);
88+
}
89+
});
90+
};
91+
92+
div.append(used, code, edit);
93+
return div;
94+
};
95+
let invsArr: invitejson[] = [];
96+
let onpage = 0;
97+
async function loadArr() {
98+
let invsArr2: invitejson[] = [];
99+
let waiting = false;
100+
async function addHTML() {
101+
if (waiting) return;
102+
waiting = true;
103+
await new Promise((res) => setTimeout(res, 0));
104+
waiting = false;
105+
invDiv.append(...invsArr2.map((inv) => createInviteHTML(inv)));
106+
invsArr2 = [];
107+
}
108+
while (!(await bansp).done) {
109+
const inv = await (await (await bansp).getNext()).getWhole();
110+
invsArr.push(inv);
111+
if (onpage < 50) {
112+
invsArr2.push(inv);
113+
addHTML();
114+
onpage++;
115+
} else {
116+
next.disabled = false;
117+
}
118+
}
119+
}
120+
let currentPage = 0;
121+
function loadPage(page = 0) {
122+
invDiv.innerHTML = "";
123+
for (onpage = 0; onpage < 50; onpage++) {
124+
const inv = invsArr[onpage + page * 50];
125+
if (!inv) break;
126+
invDiv.append(createInviteHTML(inv));
127+
}
128+
if (onpage === 50 && invsArr[onpage + page * 50]) {
129+
next.disabled = false;
130+
} else {
131+
next.disabled = true;
132+
}
133+
}
134+
135+
const pageNav = document.createElement("div");
136+
const back = document.createElement("button");
137+
back.textContent = I18n.search.back();
138+
back.disabled = !currentPage;
139+
back.onclick = () => {
140+
back.disabled = !(currentPage - 1);
141+
next.disabled = false;
142+
loadPage(--currentPage);
143+
};
144+
145+
const next = document.createElement("button");
146+
next.textContent = I18n.search.next();
147+
next.disabled = true;
148+
pageNav.append(back, next);
149+
inviteMenu.addHTMLArea(pageNav);
150+
next.onclick = () => {
151+
loadPage(++currentPage);
152+
back.disabled = false;
153+
};
154+
155+
loadArr();
156+
loadPage(currentPage);
157+
inviteMenu.addHTMLArea(invDiv);
158+
}
28159
class Guild extends SnowFlake {
29160
owner!: Localuser;
30161
headers!: Localuser["headers"];
@@ -426,6 +557,9 @@ class Guild extends SnowFlake {
426557
genDiv();
427558
emoji.addHTMLArea(containdiv);
428559
}
560+
const inviteMenu = settings.addButton(I18n.guild.invites());
561+
makeInviteMenu(inviteMenu, this, this.info.api + `/guilds/${this.id}/invites`);
562+
429563
const banMenu = settings.addButton(I18n.guild.bans());
430564
const makeBanMenu = () => {
431565
const banDiv = document.createElement("div");

src/webpage/jsontypes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -467,10 +467,10 @@ type invitejson = {
467467
code: string;
468468
temporary: boolean;
469469
uses: number;
470-
max_use: number;
470+
max_uses: number;
471471
max_age: number;
472472
created_at: string;
473-
expires_at: string;
473+
expires_at: string | null;
474474
guild_id: string;
475475
channel_id: string;
476476
inviter_id: string;

src/webpage/style.css

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ body {
6666
border-radius: 4px;
6767
width: fit-content;
6868
background: var(--secondary-bg);
69-
69+
margin-bottom: 8px;
70+
span {
71+
margin-right: 4px;
72+
}
7073
button {
7174
margin-left: 4px;
7275
}

translations/en.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@
179179
"createCatagory": "Create category",
180180
"permissions": "Permissions"
181181
},
182+
"delete": "Delete",
182183
"webhooks": {
183184
"createdAt": "Created at $1",
184185
"name": "Name:",
@@ -259,6 +260,7 @@
259260
"templateName": "Template Name:",
260261
"templateDesc": "Template Description:",
261262
"templcateMetaDesc": "A template allows others to use this guild as a base for their own guilds, it'll copy the channels, roles, and settings of this guild, but not the messages from within the guild, the bots, or the guilds icon.",
263+
"invites": "Invites",
262264
"templateNameShort": "Template name must at least be 2 characters long",
263265
"templateURL": "Template URL: $1",
264266
"bannedBy": "Banned by:",
@@ -474,7 +476,13 @@
474476
"expireAfter": "Expire after:",
475477
"channel:": "Channel:",
476478
"inviteMaker": "Invite Maker",
477-
"createInvite": "Create invite"
479+
"createInvite": "Create invite",
480+
"used": "Used $1 {{PLURAL:$1|time|times}}.",
481+
"forChannel": "For channel: $1",
482+
"createdAt": "Created at $1",
483+
"expires": "Expires: $1",
484+
"never": "Never",
485+
"maxUses": "Max uses: $1"
478486
},
479487
"friends": {
480488
"blocked": "Blocked",

0 commit comments

Comments
 (0)