mirror of
https://github.com/hrfee/jfa-go.git
synced 2026-01-18 16:47:42 +01:00
invites: add /invites/send, store more details in new SentTo field
deprecated SendTo string field for SentTo, which holds successful send addresses, and failures with a reason that isn't plain text. Will soon add an interface for sending invites after their creation. For #444 (ha).
This commit is contained in:
@@ -2,7 +2,7 @@ import { ThemeManager } from "./modules/theme.js";
|
||||
import { lang, LangFile, loadLangSelector } from "./modules/lang.js";
|
||||
import { Modal } from "./modules/modal.js";
|
||||
import { Tabs, Tab } from "./modules/tabs.js";
|
||||
import { inviteList, createInvite } from "./modules/invites.js";
|
||||
import { DOMInviteList, createInvite } from "./modules/invites.js";
|
||||
import { accountsList } from "./modules/accounts.js";
|
||||
import { settingsList } from "./modules/settings.js";
|
||||
import { activityList } from "./modules/activity.js";
|
||||
@@ -105,7 +105,7 @@ var accounts = new accountsList();
|
||||
|
||||
var activity = new activityList();
|
||||
|
||||
window.invites = new inviteList();
|
||||
window.invites = new DOMInviteList();
|
||||
|
||||
var settings = new settingsList();
|
||||
|
||||
|
||||
@@ -1247,6 +1247,12 @@ export class accountsList extends PaginatedList {
|
||||
this._search.showHideSearchOptionsHeader();
|
||||
|
||||
this.registerURLListener();
|
||||
|
||||
// Get rid of nasty CSS
|
||||
window.modals.announce.onclose = () => {
|
||||
const preview = document.getElementById("announce-preview") as HTMLDivElement;
|
||||
preview.textContent = ``;
|
||||
}
|
||||
}
|
||||
|
||||
reload = (callback?: (resp: paginatedDTO) => void) => {
|
||||
|
||||
@@ -123,20 +123,55 @@ class DOMInvite implements Invite {
|
||||
} else {
|
||||
chip.classList.add("button");
|
||||
chip.parentElement.classList.add("h-full");
|
||||
if (address.includes("Failed")) {
|
||||
if (address.includes(window.lang.strings("failed"))) {
|
||||
icon.classList.remove("ri-mail-line");
|
||||
icon.classList.add("ri-mail-close-line");
|
||||
chip.classList.remove("~neutral");
|
||||
chip.classList.add("~critical");
|
||||
} else {
|
||||
address = "Sent to " + address;
|
||||
icon.classList.remove("ri-mail-close-line");
|
||||
icon.classList.add("ri-mail-line");
|
||||
chip.classList.remove("~critical");
|
||||
chip.classList.add("~neutral");
|
||||
}
|
||||
}
|
||||
tooltip.textContent = address;
|
||||
// innerHTML as the newer sent_to re-uses this with HTML.
|
||||
tooltip.innerHTML = address;
|
||||
}
|
||||
|
||||
private _sent_to: SentToList;
|
||||
get sent_to(): SentToList { return this._sent_to; }
|
||||
set sent_to(v: SentToList) {
|
||||
this._sent_to = v;
|
||||
if (!v || !(v.success || v.failed)) return;
|
||||
let text = "";
|
||||
if (v.success && v.success.length > 0) {
|
||||
text += window.lang.strings("sentTo") + ": " + v.success.join(", ") + " <br>"
|
||||
}
|
||||
if (v.failed && v.failed.length > 0) {
|
||||
text += window.lang.strings("failed") + ": " + v.failed.map((el: SendFailure) => {
|
||||
let err: string;
|
||||
switch (el.reason) {
|
||||
case "CheckLogs":
|
||||
err = window.lang.notif("errorCheckLogs");
|
||||
break;
|
||||
case "NoUser":
|
||||
err = window.lang.notif("errorNoUser");
|
||||
break;
|
||||
case "MultiUser":
|
||||
err = window.lang.notif("errorMultiUser");
|
||||
break;
|
||||
case "InvalidAddress":
|
||||
err = window.lang.notif("errorInvalidAddress");
|
||||
break;
|
||||
default:
|
||||
err = el.reason;
|
||||
break;
|
||||
}
|
||||
return el.address + " (" + err + ")";
|
||||
}).join(", ");
|
||||
}
|
||||
if (text.length != 0) this.send_to = text;
|
||||
}
|
||||
|
||||
private _usedBy: { [name: string]: number };
|
||||
@@ -455,6 +490,7 @@ class DOMInvite implements Invite {
|
||||
this.code = invite.code;
|
||||
this.created = invite.created;
|
||||
this.send_to = invite.send_to;
|
||||
this.sent_to = invite.sent_to;
|
||||
this.expiresIn = invite.expiresIn;
|
||||
if (window.notificationsEnabled) {
|
||||
this.notifyCreation = invite.notifyCreation;
|
||||
@@ -477,7 +513,7 @@ class DOMInvite implements Invite {
|
||||
remove = () => { this._container.remove(); }
|
||||
}
|
||||
|
||||
export class inviteList implements inviteList {
|
||||
export class DOMInviteList implements InviteList {
|
||||
private _list: HTMLDivElement;
|
||||
private _empty: boolean;
|
||||
// since invite reload sends profiles, this event it broadcast so the createInvite object can load them.
|
||||
@@ -493,7 +529,7 @@ export class inviteList implements inviteList {
|
||||
};
|
||||
|
||||
public static readonly _inviteURLEvent = "invite-url";
|
||||
registerURLListener = () => document.addEventListener(inviteList._inviteURLEvent, (event: CustomEvent) => {
|
||||
registerURLListener = () => document.addEventListener(DOMInviteList._inviteURLEvent, (event: CustomEvent) => {
|
||||
this.focusInvite(event.detail);
|
||||
})
|
||||
|
||||
@@ -587,12 +623,14 @@ export class inviteList implements inviteList {
|
||||
}));
|
||||
}
|
||||
|
||||
export const inviteURLEvent = (id: string) => { return new CustomEvent(inviteList._inviteURLEvent, {"detail": id}) };
|
||||
export const inviteURLEvent = (id: string) => { return new CustomEvent(DOMInviteList._inviteURLEvent, {"detail": id}) };
|
||||
|
||||
function parseInvite(invite: { [f: string]: string | number | { [name: string]: number } | boolean }): Invite {
|
||||
// FIXME: Please, i beg you, get rid of this horror!
|
||||
function parseInvite(invite: { [f: string]: string | number | { [name: string]: number } | boolean | SentToList }): Invite {
|
||||
let parsed: Invite = {};
|
||||
parsed.code = invite["code"] as string;
|
||||
parsed.send_to = invite["send_to"] as string || "";
|
||||
parsed.sent_to = invite["sent_to"] as SentToList || null;
|
||||
parsed.label = invite["label"] as string || "";
|
||||
parsed.user_label = invite["user_label"] as string || "";
|
||||
let time = "";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { _get } from "../modules/common.js";
|
||||
import { Template } from "@hrfee/simpletemplate";
|
||||
|
||||
interface Meta {
|
||||
name: string;
|
||||
@@ -39,6 +40,15 @@ export class lang implements Lang {
|
||||
return str;
|
||||
}
|
||||
|
||||
template = (sect: string, key: string, subs: { [key: string]: any }): string => {
|
||||
if (sect == "quantityStrings" || sect == "meta") { return ""; }
|
||||
const map = new Map<string, any>();
|
||||
for (let key of Object.keys(subs)) { map.set(key, subs[key]); }
|
||||
const [out, err] = Template(this._lang[sect][key], map);
|
||||
if (err != null) throw err;
|
||||
return out;
|
||||
}
|
||||
|
||||
quantity = (key: string, number: number): string => {
|
||||
if (number == 1) {
|
||||
return this._lang.quantityStrings[key].singular.replace("{n}", ""+number)
|
||||
|
||||
@@ -1626,7 +1626,8 @@ class MessageEditor {
|
||||
} else {
|
||||
for (let i = this._templ.conditionals.length-1; i >= 0; i--) {
|
||||
let ci = i % colors.length;
|
||||
innerHTML += '<span class="button ~' + colors[ci] +' @low mb-4" style="margin-left: 0.25rem; margin-right: 0.25rem;"></span>'
|
||||
// FIXME: Store full color strings (with ~) so tailwind sees them.
|
||||
innerHTML += '<span class="button ~' + colors[ci] +' @low"></span>'
|
||||
}
|
||||
this._conditionalsLabel.classList.remove("unfocused");
|
||||
this._conditionals.innerHTML = innerHTML
|
||||
@@ -1754,6 +1755,20 @@ class MessageEditor {
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const descriptions = document.getElementsByClassName("editor-syntax-description") as HTMLCollectionOf<HTMLParagraphElement>;
|
||||
for (let el of descriptions) {
|
||||
el.innerHTML = window.lang.template("strings", "syntaxDescription", {
|
||||
"variable": `<span class="font-mono font-bold">{varname}</span>`,
|
||||
"ifTruth": `<span class="font-mono font-bold">{if address}Message sent to {address}{end}</span>`,
|
||||
"ifCompare": `<span class="font-mono font-bold">{if profile == "Friends"}Friend{else if profile != "Admins"}User{end}</span>`
|
||||
});
|
||||
};
|
||||
|
||||
// Get rid of nasty CSS
|
||||
window.modals.editor.onclose = () => {
|
||||
this._preview.textContent = ``;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ declare interface GlobalWindow extends Window {
|
||||
transitionEvent: string;
|
||||
animationEvent: string;
|
||||
tabs: Tabs;
|
||||
invites: inviteList;
|
||||
invites: InviteList;
|
||||
notifications: NotificationBox;
|
||||
language: string;
|
||||
lang: Lang;
|
||||
@@ -61,6 +61,42 @@ declare interface GlobalWindow extends Window {
|
||||
loginAppearance: string;
|
||||
}
|
||||
|
||||
declare interface InviteList {
|
||||
empty: boolean;
|
||||
invites: { [code: string]: Invite }
|
||||
add: (invite: Invite) => void;
|
||||
reload: (callback?: () => void) => void;
|
||||
isInviteURL: () => boolean;
|
||||
loadInviteURL: () => void;
|
||||
}
|
||||
|
||||
declare interface Invite {
|
||||
code?: string;
|
||||
expiresIn?: string;
|
||||
remainingUses?: string;
|
||||
send_to?: string; // DEPRECATED: use sent_to instead.
|
||||
sent_to?: SentToList;
|
||||
usedBy?: { [name: string]: number };
|
||||
created?: number;
|
||||
notifyExpiry?: boolean;
|
||||
notifyCreation?: boolean;
|
||||
profile?: string;
|
||||
label?: string;
|
||||
user_label?: string;
|
||||
userExpiry?: boolean;
|
||||
userExpiryTime?: string;
|
||||
}
|
||||
|
||||
declare interface SendFailure {
|
||||
address: string;
|
||||
reason: "CheckLogs" | "NoUser" | "MultiUser" | "InvalidAddress";
|
||||
}
|
||||
|
||||
declare interface SentToList {
|
||||
success: string[];
|
||||
failed: SendFailure[];
|
||||
}
|
||||
|
||||
declare interface Update {
|
||||
version: string;
|
||||
commit: string;
|
||||
@@ -83,6 +119,7 @@ declare interface Lang {
|
||||
strings: (key: string) => string;
|
||||
notif: (key: string) => string;
|
||||
var: (sect: string, key: string, ...subs: string[]) => string;
|
||||
template: (sect: string, key: string, subs: { [key: string]: string }) => string;
|
||||
quantity: (key: string, number: number) => string;
|
||||
}
|
||||
|
||||
@@ -131,31 +168,6 @@ declare interface Modals {
|
||||
backups?: Modal;
|
||||
}
|
||||
|
||||
interface Invite {
|
||||
code?: string;
|
||||
expiresIn?: string;
|
||||
remainingUses?: string;
|
||||
send_to?: string;
|
||||
usedBy?: { [name: string]: number };
|
||||
created?: number;
|
||||
notifyExpiry?: boolean;
|
||||
notifyCreation?: boolean;
|
||||
profile?: string;
|
||||
label?: string;
|
||||
user_label?: string;
|
||||
userExpiry?: boolean;
|
||||
userExpiryTime?: string;
|
||||
}
|
||||
|
||||
interface inviteList {
|
||||
empty: boolean;
|
||||
invites: { [code: string]: Invite }
|
||||
add: (invite: Invite) => void;
|
||||
reload: (callback?: () => void) => void;
|
||||
isInviteURL: () => boolean;
|
||||
loadInviteURL: () => void;
|
||||
}
|
||||
|
||||
interface paginatedDTO {
|
||||
last_page: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user