Skip to content

Commit

Permalink
add local notifications, work on ui
Browse files Browse the repository at this point in the history
  • Loading branch information
targoninc-alex committed Jun 1, 2024
1 parent 91f9536 commit 58a99e1
Show file tree
Hide file tree
Showing 16 changed files with 408 additions and 64 deletions.
34 changes: 34 additions & 0 deletions ui/actions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,40 @@ export function toast(message, type = "info", timeout = 5) {
}, timeout * 1000);
}

export function notify(image, title, subtitle, message, timeout = 7) {
const notification = create("div")
.classes("card", "flex", "notification")
.styles("animation-duration", `${timeout}s`)
.children(
create("img")
.classes("notification-image")
.src(image)
.build(),
create("div")
.classes("flex-v", "notification-content")
.children(
create("div")
.classes("notification-title")
.text(title)
.build(),
create("div")
.classes("notification-subtitle")
.text(subtitle)
.build(),
create("span")
.classes("notification-message")
.text(message)
.build()
).build()
).build();

Page.notifications.appendChild(notification);

setTimeout(() => {
notification.remove();
}, timeout * 1000);
}

export function popup(popup, classes = []) {
const container = create("div")
.classes("popup-container", ...classes)
Expand Down
6 changes: 6 additions & 0 deletions ui/api/Api.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,10 @@ export class Api extends ApiBase {
static async toggleEnabled(id = null) {
return await this.patch("/api/bridging/toggleEnabled", {id});
}
static async addBridgedUser(userId = null, instanceId = null) {
return await this.post("/api/bridging/addBridgedUser", {userId, instanceId});
}
static async removeBridgedUser(userId = null, instanceId = null) {
return await this.delete("/api/bridging/removeBridgedUser", {userId, instanceId});
}
}
9 changes: 9 additions & 0 deletions ui/api/Hooks.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import {Api} from "./Api.mjs";
import {toast} from "../actions.mjs";
import {signal, store} from "https://fjs.targoninc.com/f.js";
import {Live} from "../live/Live.mjs";
import {Store} from "./Store.mjs";
import {localNotificationsEnabled} from "./LocalSetting.mjs";
import {Notifier} from "../live/Notifier.mjs";

export class Hooks {
static runUser(user) {
Expand Down Expand Up @@ -61,6 +64,12 @@ export function addMessage(channel, message) {
const ex = store().get('messages').value;
setChannel(ex, channel);
store().setSignalValue('messages', {...ex, [channel]: [...ex[channel], message]});

const user = Store.get('user');
// && message.userId !== user.value.id
if (localNotificationsEnabled()) {
Notifier.sendMessage(channel, message);
}
}

export function removeMessage(channel, messageId) {
Expand Down
21 changes: 21 additions & 0 deletions ui/api/LocalSetting.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export class LocalSetting {
static getBoolean(key) {
return sessionStorage.getItem(key) === "true";
}

static getString(key) {
return sessionStorage.getItem(key);
}

static set(key, value) {
sessionStorage.setItem(key, value);
}
}

export function localNotificationsEnabled() {
return LocalSetting.getBoolean("notifications");
}

export function setLocalNotificationsEnabled(enabled) {
LocalSetting.set("notifications", enabled);
}
54 changes: 54 additions & 0 deletions ui/api/Popups.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,58 @@ export class Popups {
});
}, "New DM", "Search for users"));
}

static newBridgedUser(instance, allowList) {
const userSearchResults = signal([]);

popup(PopupComponents.searchPopup(() => {
removePopups();
}, (e) => {
const query = e.target.value;
if (query.length < 3) {
userSearchResults.value = [];
return;
}

Api.search(query).then((res) => {
if (res.status !== 200) {
toast("Failed to search for users", "error");
return;
}
userSearchResults.value = res.data.filter(user => {
return !allowList.value.some(bridgedUser => bridgedUser.id === user.id);
});
})
}, () => {}, userSearchResults, (result) => {
return CommonTemplates.addUserButton(result.username, () => {
Api.addBridgedUser(result.id, instance.id).then((res) => {
if (res.status !== 200) {
toast("Failed to add user", "error");
removePopups();
return;
}
toast("User added", "success");
allowList.value = [...allowList.value, result.data];
removePopups();
});
});
}, "Add bridged user", "Search for users"));
}

static deleteUserPopup(users, user) {
popup(PopupComponents.confirmPopup("Are you sure you want to delete this user?", () => {
Api.deleteUser(user.id).then((res) => {
if (res.status !== 200) {
toast("Failed to delete user", "error");
removePopups();
return;
}
toast("User deleted", "success");
users.value = users.value.filter(u => u.id !== user.id);
removePopups();
});
}, () => {
removePopups();
}, "Delete user", "Yes", "No", "delete", "close"));
}
}
23 changes: 20 additions & 3 deletions ui/base.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
:root {
--black: #040403ff;
/*--black: #040403ff;
--black-2: #10100e;
--black-3: #171712;
--black-4: #23231a;
--black-4: #23231a;*/
--black: #0f0f12;
--black-2: #151519;
--black-3: #1b1b20;
--black-4: #1e1e24;
--white: #efe9e7ff;
--white-2: #e7ddda;
--white-3: #ded2ce;
Expand All @@ -19,7 +23,8 @@
--input-border-radius: 0.25rem;
--input-border-width: 1px;
--avatar-border-width: 2px;
--animation-time: 0.35s;
--animation-time: 0.25s;
--message-padding-left: 3em;
}

@media (prefers-color-scheme: light) {
Expand Down Expand Up @@ -187,6 +192,18 @@ button:hover {
z-index: 999;
}

#notifications {
position: fixed;
top: 50%;
right: 0;
transform: translateY(-50%);
display: flex;
flex-direction: column;
gap: var(--gap-v);
padding: var(--gap-v);
z-index: 999;
}

#popups {
position: fixed;
top: 0;
Expand Down
52 changes: 49 additions & 3 deletions ui/classes.css
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
background: var(--blue);
color: var(--bg);
font-size: 0.8em;
font-weight: bold;
}

.pill {
Expand Down Expand Up @@ -232,12 +233,22 @@
overflow-y: auto;
}

.chat-user {
margin-top: var(--gap-v);
position: relative;
}

.rounded-max {
border-radius: 9999px;
}

.message-username {
padding-left: var(--message-padding-left);
}

.message-text {
padding-left: 1em;
padding-left: calc(var(--message-padding-left) - 0.25em);
max-width: calc(100% - 200px);
}

.message-timestamp {
Expand All @@ -258,14 +269,15 @@
.message-content {
padding: 0.25em;
border-radius: var(--input-border-radius);
word-wrap: anywhere;
}

.message-menu {
position: absolute;
right: 0;
top: 0;
padding: 0.5em;
background: var(--bg-2);
background: var(--bg-3);
border-radius: var(--input-border-radius);
border: var(--input-border-width) solid var(--bg-4);
z-index: 999;
Expand Down Expand Up @@ -323,9 +335,12 @@
}

.message-avatar {
--size: 1em;
--size: 2em;
width: var(--size);
height: var(--size);
position: absolute;
top: 0;
left: .5em;
}

.max800 {
Expand Down Expand Up @@ -380,4 +395,35 @@

.nav-margin {
margin-top: 43px;
}

.notification {
animation: fade-out var(--animation-time) forwards;
}

@keyframes fade-out {
0% {
opacity: 1;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}

.notification-image {
width: 2em;
height: 2em;
border-radius: 50%;
border: var(--input-border-width) solid var(--bg-4);
}

.notification-content {
max-width: 200px;
}

.notification-title, .notification-subtitle, .notification-message {
word-wrap: anywhere;
}
39 changes: 36 additions & 3 deletions ui/components/common.mjs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import {computedSignal, create, FjsObservable, ifjs} from "https://fjs.targoninc.com/f.js";
import {Popups} from "../api/Popups.mjs";
import {Store} from "../api/Store.mjs";
import {testImage} from "../actions.mjs";

export class CommonTemplates {
static icon(icon, classes = [], tag = "span") {
if ((icon.constructor === String && (icon.includes(".") || icon.startsWith("data:image"))) || (icon.constructor === FjsObservable && icon.value.includes("."))) {
if (!icon) {
icon = testImage;
}

if ((icon.constructor === String && (icon.includes(".") || icon.startsWith("data:image"))) || (icon.constructor === FjsObservable && icon.value &&
(icon.value.includes(".") || icon.value.startsWith("data:image")))) {
return create("img")
.classes("icon", ...classes)
.src(icon)
Expand Down Expand Up @@ -81,6 +87,7 @@ export class CommonTemplates {
return (currentRoute && currentRoute.path === page) ? "active" : "_";
};
const user = Store.get('user');
const avatar = computedSignal(user, user => user && user.avatar ? user.avatar : testImage);
const hasAnyRole = computedSignal(user, user => user && user.roles && user.roles.length > 0);

return create("nav")
Expand All @@ -95,12 +102,12 @@ export class CommonTemplates {
ifjs(hasAnyRole, create("div")
.classes("flex", "align-center")
.children(
CommonTemplates.buttonWithIcon("admin_panel_settings", "Administration", () => window.router.navigate('admin'), [activeIfActive("admin")]),
CommonTemplates.buttonWithIcon("settings", "Settings", () => window.router.navigate('settings'), [activeIfActive("settings")]),
).build()),
create("div")
.classes("flex", "align-center")
.children(
CommonTemplates.buttonWithIcon("face_5", "Profile", () => window.router.navigate('profile'), [activeIfActive("profile")]),
CommonTemplates.buttonWithIcon(avatar, "Profile", () => window.router.navigate('profile'), [activeIfActive("profile")]),
CommonTemplates.pageLink("Logout", "logout")
).build(),
).build();
Expand Down Expand Up @@ -154,6 +161,19 @@ export class CommonTemplates {
).build();
}

static addUserButton(username, onclick) {
return create("button")
.classes("flex", "align-center", "small-gap", "full-width", "space-between")
.onclick(onclick)
.children(
CommonTemplates.icon("person_add"),
create("span")
.classes("bold")
.text(username)
.build(),
).build();
}

static input(type, id, label, placeholder, value, onchange, required = true, autocomplete = "off", onkeydown = () => {}) {
return create("div")
.classes("flex-v", "small-gap")
Expand Down Expand Up @@ -316,4 +336,17 @@ export class CommonTemplates {
.build()
).build();
}

static chatUser(avatar, name, onclick) {
return create("div")
.classes("flex", "align-center", "chat-user")
.onclick(onclick)
.children(
CommonTemplates.icon(avatar, ["round", "message-avatar"]),
create("span")
.classes("bold", "message-username")
.text(name)
.build()
).build();
}
}
Loading

0 comments on commit 58a99e1

Please sign in to comment.