197 lines
8.3 KiB
JavaScript
197 lines
8.3 KiB
JavaScript
const PID_NEW_TOOLS_NOTIFICATIONS = [
|
|
{ id: "tool-calendario-individual", date: "01/08", title: "CALENDÁRIO INDIVIDUAL", breadcrumb: "Menu > Calendário Individual" },
|
|
{ id: "tool-perfis-acesso", date: "03/08", title: "PERFIS DE ACESSO", breadcrumb: "Menu > Administração > Perfis de Acesso" },
|
|
{ id: "tool-usuarios", date: "03/08", title: "USUÁRIOS", breadcrumb: "Menu > Administração > Usuários" },
|
|
{ id: "tool-widgets", date: "10/08", title: "WIDGETS NA TELA INICIAL", breadcrumb: "Menu > Principal > Widgets" },
|
|
];
|
|
|
|
const PID_NOTIF_ICON_TOOL =
|
|
'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2 3 14h7l-1 8 10-12h-7l1-8z" stroke-linejoin="round"/></svg>';
|
|
|
|
const PID_NOTIF_ICON_EVENT =
|
|
'<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M3 9h18M8 3v4M16 3v4" stroke-linecap="round"/><path d="M9 15l2 2 4-4" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
|
|
const PID_NOTIF_ICON_RESTORE =
|
|
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 12a9 9 0 1 0 3-6.7L3 8" stroke-linecap="round" stroke-linejoin="round"/><path d="M3 3v5h5" stroke-linecap="round" stroke-linejoin="round"/></svg>';
|
|
|
|
function pidFormatNotifDate(iso) {
|
|
const [, month, day] = iso.split("-");
|
|
return `${day}/${month}`;
|
|
}
|
|
|
|
async function pidFetchDismissedNotifIds() {
|
|
const list = await pidApiRequest("/notificacoes-dispensadas/");
|
|
return (list || []).map((n) => n.notif_id);
|
|
}
|
|
|
|
async function pidDismissNotification(id) {
|
|
await pidApiRequest("/notificacoes-dispensadas/", { method: "POST", body: { notif_id: id } });
|
|
}
|
|
|
|
async function pidRestoreNotification(id) {
|
|
await pidApiRequest(`/notificacoes-dispensadas/${id}/`, { method: "DELETE" });
|
|
}
|
|
|
|
function pidSortEventsByDate(a, b) {
|
|
const dateCompare = a.data.localeCompare(b.data);
|
|
return dateCompare !== 0 ? dateCompare : (a.horario || "").localeCompare(b.horario || "");
|
|
}
|
|
|
|
function pidMapEventToNotification(ev) {
|
|
return {
|
|
id: `event-${ev.id}`,
|
|
type: "event",
|
|
date: pidFormatNotifDate(ev.data),
|
|
title: ev.titulo.toUpperCase(),
|
|
breadcrumb: ev.sou_dono
|
|
? "Menu > Calendário Individual"
|
|
: `Menu > Calendário Individual > Compartilhado por ${ev.dono_nome}`,
|
|
};
|
|
}
|
|
|
|
/** Só os compromissos "elegíveis" a notificação agora (lembrete configurado, já
|
|
* atingido e não no passado) — a mesma regra do sino. O histórico (ver
|
|
* `renderHistory` abaixo) reconstrói a partir de todos os eventos, sem essas
|
|
* duas restrições, já que um item dispensado pode ter saído desse recorte. */
|
|
function pidEventosElegiveisAgora(events) {
|
|
const now = new Date();
|
|
const todayIso = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
|
return events
|
|
.filter((ev) => ev.data >= todayIso && ev.notificar_em && new Date(ev.notificar_em) <= now)
|
|
.sort(pidSortEventsByDate)
|
|
.slice(0, 5)
|
|
.map(pidMapEventToNotification);
|
|
}
|
|
|
|
document.addEventListener("DOMContentLoaded", async () => {
|
|
const bell = document.getElementById("notif-bell");
|
|
const dropdown = document.getElementById("notif-dropdown");
|
|
const list = document.getElementById("notif-list");
|
|
const badge = document.getElementById("notif-badge");
|
|
const clearAllBtn = document.getElementById("notif-clear-all");
|
|
const historyBtn = document.getElementById("notif-history-btn");
|
|
const historyModal = document.getElementById("notif-history-modal");
|
|
const historyList = document.getElementById("notif-history-list");
|
|
const historyCloseBtn = document.getElementById("notif-history-close-btn");
|
|
if (!bell || !dropdown || !list) return;
|
|
|
|
const me = await pidGetMe();
|
|
const events = me ? await pidFetchEvents() : [];
|
|
const eventNotifications = pidEventosElegiveisAgora(events);
|
|
const allEventNotifications = events.slice().sort(pidSortEventsByDate).map(pidMapEventToNotification);
|
|
const toolNotifications = PID_NEW_TOOLS_NOTIFICATIONS.map((n) => ({ ...n, type: "tool" }));
|
|
let dismissedIds = me ? await pidFetchDismissedNotifIds() : [];
|
|
let notifications = [...eventNotifications, ...toolNotifications].filter((n) => !dismissedIds.includes(n.id));
|
|
|
|
function render() {
|
|
list.innerHTML = notifications.length
|
|
? notifications
|
|
.map(
|
|
(n) => `
|
|
<li class="notif-item notif-item--${n.type}" data-notif-id="${n.id}">
|
|
<span class="notif-item__icon">${n.type === "event" ? PID_NOTIF_ICON_EVENT : PID_NOTIF_ICON_TOOL}</span>
|
|
<div class="notif-item__body">
|
|
<p class="notif-item__title">${n.date} - ${n.title}</p>
|
|
<p class="notif-item__breadcrumb">${n.breadcrumb}</p>
|
|
</div>
|
|
<button type="button" class="notif-item__dismiss" data-notif-dismiss="${n.id}" aria-label="Remover notificação">
|
|
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12" stroke-linecap="round"/></svg>
|
|
</button>
|
|
</li>`
|
|
)
|
|
.join("")
|
|
: `<li class="notif-empty">Nenhuma notificação no momento.</li>`;
|
|
|
|
if (badge) {
|
|
badge.hidden = notifications.length === 0;
|
|
badge.textContent = notifications.length;
|
|
}
|
|
}
|
|
|
|
bell.addEventListener("click", (event) => {
|
|
event.stopPropagation();
|
|
dropdown.hidden = !dropdown.hidden;
|
|
});
|
|
|
|
list.addEventListener("click", async (event) => {
|
|
const dismissBtn = event.target.closest("[data-notif-dismiss]");
|
|
if (!dismissBtn) return;
|
|
event.stopPropagation();
|
|
const id = dismissBtn.getAttribute("data-notif-dismiss");
|
|
await pidDismissNotification(id);
|
|
dismissedIds.push(id);
|
|
notifications = notifications.filter((n) => n.id !== id);
|
|
render();
|
|
});
|
|
|
|
if (clearAllBtn) {
|
|
clearAllBtn.addEventListener("click", async () => {
|
|
await Promise.all(notifications.map((n) => pidDismissNotification(n.id)));
|
|
dismissedIds.push(...notifications.map((n) => n.id));
|
|
notifications = [];
|
|
render();
|
|
});
|
|
}
|
|
|
|
document.addEventListener("click", (event) => {
|
|
if (!dropdown.hidden && !dropdown.contains(event.target) && event.target !== bell) {
|
|
dropdown.hidden = true;
|
|
}
|
|
if (historyModal && !historyModal.hidden && event.target === historyModal) {
|
|
historyModal.hidden = true;
|
|
}
|
|
});
|
|
|
|
function renderHistory() {
|
|
if (!historyList) return;
|
|
const historyItems = [...allEventNotifications, ...toolNotifications].filter((n) => dismissedIds.includes(n.id));
|
|
historyList.innerHTML = historyItems.length
|
|
? historyItems
|
|
.map(
|
|
(n) => `
|
|
<li class="notif-item notif-item--${n.type}" data-notif-id="${n.id}">
|
|
<span class="notif-item__icon">${n.type === "event" ? PID_NOTIF_ICON_EVENT : PID_NOTIF_ICON_TOOL}</span>
|
|
<div class="notif-item__body">
|
|
<p class="notif-item__title">${n.date} - ${n.title}</p>
|
|
<p class="notif-item__breadcrumb">${n.breadcrumb}</p>
|
|
</div>
|
|
<button type="button" class="notif-item__restore" data-notif-restore="${n.id}" aria-label="Restaurar notificação" title="Restaurar">
|
|
${PID_NOTIF_ICON_RESTORE}
|
|
</button>
|
|
</li>`
|
|
)
|
|
.join("")
|
|
: `<li class="notif-empty">Nenhuma notificação no histórico.</li>`;
|
|
}
|
|
|
|
if (historyBtn && historyModal) {
|
|
historyBtn.addEventListener("click", (event) => {
|
|
event.stopPropagation();
|
|
dropdown.hidden = true;
|
|
renderHistory();
|
|
historyModal.hidden = false;
|
|
});
|
|
}
|
|
|
|
if (historyCloseBtn) {
|
|
historyCloseBtn.addEventListener("click", () => {
|
|
historyModal.hidden = true;
|
|
});
|
|
}
|
|
|
|
if (historyList) {
|
|
historyList.addEventListener("click", async (event) => {
|
|
const restoreBtn = event.target.closest("[data-notif-restore]");
|
|
if (!restoreBtn) return;
|
|
const id = restoreBtn.getAttribute("data-notif-restore");
|
|
await pidRestoreNotification(id);
|
|
dismissedIds = dismissedIds.filter((dismissedId) => dismissedId !== id);
|
|
notifications = [...eventNotifications, ...toolNotifications].filter((n) => !dismissedIds.includes(n.id));
|
|
renderHistory();
|
|
render();
|
|
});
|
|
}
|
|
|
|
render();
|
|
});
|