1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-09-16 17:30:11 +00:00

add connection error notification, implement notify/delete function

This commit is contained in:
Harvey Tindall 2020-12-30 18:31:38 +00:00
parent 1b41621569
commit 28187d0aa0
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
6 changed files with 80 additions and 26 deletions

View File

@ -274,6 +274,10 @@ sup.\~critical, .text-critical {
resize: vertical;
}
.overflow {
overflow: visible;
}
select {
color: inherit;
border: 0 solid var(--color-neutral-300);
@ -291,4 +295,8 @@ p.top {
margin-top: 0px;
}
#notification-box {
position: fixed;
right: 1rem;
bottom: 1rem;
}

View File

@ -113,6 +113,7 @@
<input type="submit" class="button ~urge !normal full-width center supra submit" value="Submit">
</form>
</div>
<div id="notification-box"></div>
<div class="page-container max-w-screen-lg px-6 py-4 mx-auto lg:mx-auto md:py-8">
<div class="mb-1">
<header class="flex flex-wrap items-center justify-between">

View File

@ -2,6 +2,7 @@ import { toggleTheme, loadTheme } from "./modules/theme.js";
import { Modal } from "./modules/modal.js";
import { Tabs } from "./modules/tabs.js";
import { inviteList } from "./modules/invites.js";
import { notificationBox } from "./modules/common.js";
loadTheme();
(document.getElementById('button-theme') as HTMLSpanElement).onclick = toggleTheme;
@ -14,21 +15,8 @@ const whichAnimationEvent = () => {
return "webkitAnimationEnd";
}
window.animationEvent = whichAnimationEvent();
/*const toggles: HTMLInputElement[] = Array.from(document.getElementsByClassName('toggle-details'));
for (let toggle of toggles) {
toggle.onclick = () => {
const el = toggle.parentElement.parentElement.parentElement.nextElementSibling as HTMLDivElement;
if (el.classList.contains("focused")) {
el.classList.toggle("focused");
el.classList.toggle("unfocused");
} else {
el.classList.toggle("unfocused");
el.classList.toggle("focused");
}
toggle.previousElementSibling.classList.toggle("rotated");
toggle.previousElementSibling.classList.toggle("not-rotated");
};
}*/
window.notifications = new notificationBox(document.getElementById('notification-box') as HTMLDivElement, 5);
const checkInfUses = function (check: HTMLInputElement, mode = 2) {
const uses = document.getElementById('inv-uses') as HTMLInputElement;

View File

@ -56,11 +56,11 @@ export const _get = (url: string, data: Object, onreadystatechange: (req: XMLHtt
req.responseType = 'json';
req.setRequestHeader("Authorization", "Bearer " + window.token);
req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
req.onreadystatechange = () => { onreadystatechange(req); };
req.onreadystatechange = () => { if (req.status == 0) { window.notifications.connectionError(); } else { onreadystatechange(req); } };
req.send(JSON.stringify(data));
};
export const _post = (url: string, data: Object, onreadystatechange: () => void, response?: boolean): void => {
export const _post = (url: string, data: Object, onreadystatechange: (req: XMLHttpRequest) => void, response?: boolean): void => {
let req = new XMLHttpRequest();
req.open("POST", window.URLBase + url, true);
if (response) {
@ -68,16 +68,16 @@ export const _post = (url: string, data: Object, onreadystatechange: () => void,
}
req.setRequestHeader("Authorization", "Bearer " + window.token);
req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
req.onreadystatechange = onreadystatechange;
req.onreadystatechange = () => { if (req.status == 0) { window.notifications.connectionError(); } else { onreadystatechange(req); } };
req.send(JSON.stringify(data));
};
export function _delete(url: string, data: Object, onreadystatechange: () => void): void {
export function _delete(url: string, data: Object, onreadystatechange: (req: XMLHttpRequest) => void): void {
let req = new XMLHttpRequest();
req.open("DELETE", window.URLBase + url, true);
req.setRequestHeader("Authorization", "Bearer " + window.token);
req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
req.onreadystatechange = onreadystatechange;
req.onreadystatechange = () => { if (req.status == 0) { window.notifications.connectionError(); } else { onreadystatechange(req); } };
req.send(JSON.stringify(data));
}
@ -97,3 +97,32 @@ export function toClipboard (str: string) {
document.getSelection().addRange(selected);
}
}
export class notificationBox implements NotificationBox {
private _box: HTMLDivElement;
timeout: number
constructor(box: HTMLDivElement, timeout?: number) { this._box = box; this.timeout = timeout || 5; }
private _error = (message: string): HTMLElement => {
const noti = document.createElement('aside');
noti.classList.add("aside", "~critical", "!normal", "mt-half", "notification-error");
noti.innerHTML = `<strong>Error:</strong> ${message}`;
const closeButton = document.createElement('span') as HTMLSpanElement;
closeButton.classList.add("button", "~critical", "!low", "ml-1");
closeButton.innerHTML = `<i class="icon ri-close-line"></i>`;
closeButton.onclick = () => { this._box.removeChild(noti); };
noti.appendChild(closeButton);
return noti;
}
private _connectionError: boolean = false;
connectionError = () => {
const noti = this._error("Couldn't connect to jfa-go.");
if (this._connectionError) {
this._box.querySelector("aside.notification-error").remove();
}
this._box.appendChild(noti);
this._connectionError = true;
setTimeout(() => { this._box.removeChild(noti); this._connectionError = false; }, this.timeout*1000);
}
}

View File

@ -1,10 +1,28 @@
import { _get, _post, _delete, toClipboard } from "../modules/common.js";
export class DOMInvite implements Invite {
// TODO
updateNotify = () => {}; // SetNotify
delete = () => {}; // deleteInvite
updateNotify = (checkbox: HTMLInputElement) => {
let state: { [code: string]: { [type: string]: boolean } } = {};
let revertChanges: () => void;
if (checkbox.classList.contains("inv-notify-expiry")) {
revertChanges = () => { this.notifyExpiry = !this.notifyExpiry };
state[this.code] = { "notify-expiry": this.notifyExpiry };
} else {
revertChanges = () => { this.notifyCreation = !this.notifyCreation };
state[this.code] = { "notify-creation": this.notifyCreation };
}
_post("/invites/notify", state, (req: XMLHttpRequest) => {
if (req.readyState == 4 && !(req.status == 200 || req.status == 204)) {
revertChanges();
}
});
}
delete = () => { _delete("/invites", { "code": this.code }, (req: XMLHttpRequest) => {
if (req.readyState == 4 && (req.status == 200 || req.status == 204)) {
this.remove();
}
}); }
private _code: string = "None";
get code(): string { return this._code; }
@ -175,7 +193,7 @@ export class DOMInvite implements Invite {
this._header = document.createElement('div') as HTMLDivElement;
this._container.appendChild(this._header);
this._header.classList.add("card", "~neutral", "!normal", "inv-header", "flex-expand", "mt-half");
this._header.classList.add("card", "~neutral", "!normal", "inv-header", "flex-expand", "mt-half", "overflow");
this._codeArea = document.createElement('div') as HTMLDivElement;
this._header.appendChild(this._codeArea);
@ -234,6 +252,11 @@ export class DOMInvite implements Invite {
<span>On user creation</span>
</label>
`;
const notifyExpiry = this._left.querySelector("input.inv-notify-expiry") as HTMLInputElement;
notifyExpiry.onchange = () => { this._notifyExpiry = notifyExpiry.checked; this.updateNotify(notifyExpiry); };
const notifyCreation = this._left.querySelector("input.inv-notify-creation") as HTMLInputElement;
notifyCreation.onchange = () => { this._notifyCreation = notifyCreation.checked; this.updateNotify(notifyCreation); };
this._middle = document.createElement('div') as HTMLDivElement;
detailsInner.appendChild(this._middle);

View File

@ -23,6 +23,11 @@ declare interface Window {
animationEvent: string;
tabs: Tabs;
invites: inviteList;
notifications: NotificationBox;
}
declare interface NotificationBox {
connectionError: (timeout: number) => void;
}
declare interface Tabs {