Files
devplacepy/devplacepy/static/js/NotificationPrefs.js
T
retoor e0e64c8d9e feat: add telegram notification channel with outbox service and per-user preferences
Extend the notification system with a third channel (telegram) alongside existing in_app and push channels. Add `telegram_enabled` column to `notification_preferences` table, update `NOTIFICATION_CHANNELS` and `_NOTIFICATION_CHANNEL_COLUMNS` mappings, and set telegram default to off (`_NOTIFICATION_CHANNEL_DEFAULTS`). Create `telegram_outbox` table with columns for uid, user_uid, chat_id, text, status, attempts, created_at, and sent_at, plus an index on status/id for efficient polling. Register `TelegramOutboxService` in the service manager lifecycle. Update API documentation strings to describe the new channel and its pairing requirement. Extend admin notification defaults view to include telegram column. Pass `notif_telegram_paired` flag to profile template based on `telegram_store.is_paired()` check. Update `NotificationPrefForm` and `NotificationDefaultForm` model literals to accept "telegram" as a valid channel value.
2026-06-22 20:52:02 +00:00

79 lines
2.6 KiB
JavaScript

// retoor <retoor@molodetz.nl>
import { Http } from "./Http.js";
class NotificationPrefs {
constructor(pubsub) {
this.root = document.querySelector("[data-notif-prefs]");
if (!this.root) return;
this.pubsub = pubsub;
this.username = this.root.dataset.username;
this.root
.querySelectorAll("[data-notif-toggle]")
.forEach((input) => this.bind(input));
const reset = this.root.querySelector("[data-notif-reset]");
if (reset) reset.addEventListener("click", () => this.reset(reset));
this.subscribe();
}
subscribe() {
const uid = document.body.dataset.userUid || "";
if (!uid || !this.pubsub) return;
this.pubsub.subscribe(`user.${uid}.telegram`, (data) => {
if (data && data.paired) this.enableTelegram();
});
}
enableTelegram() {
this.root
.querySelectorAll('[data-notif-toggle][data-channel="telegram"]')
.forEach((input) => {
input.disabled = false;
const label = input.closest(".notif-switch");
if (label) label.classList.remove("notif-switch-disabled");
});
const hint = this.root.querySelector(".notif-prefs-hint");
if (hint) hint.hidden = true;
}
bind(input) {
input.addEventListener("change", async () => {
const desired = input.checked;
input.disabled = true;
try {
await Http.send(`/profile/${this.username}/notifications`, {
notification_type: input.dataset.type,
channel: input.dataset.channel,
value: desired ? "true" : "false",
});
this.flash(desired ? "Saved" : "Disabled", "success");
} catch (error) {
input.checked = !desired;
this.flash("Could not save notification setting", "error");
} finally {
input.disabled = false;
}
});
}
async reset(button) {
button.disabled = true;
try {
await Http.send(`/profile/${this.username}/notifications/reset`, {});
window.location.reload();
} catch (error) {
button.disabled = false;
this.flash("Could not reset notifications", "error");
}
}
flash(message, type) {
if (window.app && window.app.toast) {
window.app.toast.show(message, { type });
}
}
}
window.NotificationPrefs = NotificationPrefs;
export { NotificationPrefs };