{% extends "console/layout.html" %}
{% block title %}{{ "notifications_page.title" | t }} ยท {{site_name|default('RustPBX')}}{% endblock %}
{% block content %}
<div class="p-6" x-data="notificationsPage()" x-init="init()">
<div class="mx-auto max-w-4xl space-y-6">
<header class="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
<div class="space-y-1">
<p class="text-xs font-semibold uppercase tracking-wide text-sky-600">{{
"notifications_page.system_notifications" | t }}</p>
<h1 class="text-2xl font-semibold text-slate-900">{{ "notifications_page.title" | t }}</h1>
<p class="text-sm text-slate-500">{{ "notifications_page.system_notifications" | t }}</p>
</div>
<button type="button" @click="markAllRead()"
class="inline-flex items-center gap-2 rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-semibold text-slate-600 shadow-sm hover:bg-slate-50 transition">
<svg class="h-4 w-4 text-slate-400" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1.8">
<path stroke-linecap="round" stroke-linejoin="round"
d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
{{ "notifications_page.mark_all_read" | t }}
</button>
</header>
{% if notifications %}
<div class="space-y-3">
{% for n in notifications %}
<div id="notification-{{ n.id }}"
class="flex items-start gap-4 rounded-xl bg-white p-5 shadow-sm ring-1 transition {{ 'ring-sky-200 bg-sky-50/40' if not n.read else 'ring-black/5' }}">
<div
class="mt-0.5 flex h-10 w-10 shrink-0 items-center justify-center rounded-full
{{ 'bg-sky-100 text-sky-600' if n.kind == 'update' else ('bg-amber-100 text-amber-600' if n.kind == 'warning' else 'bg-slate-100 text-slate-500') }}">
{% if n.kind == 'update' %}
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<path stroke-linecap="round" stroke-linejoin="round"
d="M9 12.75L11.25 15 15 9.75m-3-7.036A11.959 11.959 0 013.598 6 11.99 11.99 0 003 9.749c0 5.592 3.824 10.29 9 11.623 5.176-1.332 9-6.03 9-11.622 0-1.31-.21-2.571-.598-3.751h-.152c-3.196 0-6.1-1.248-8.25-3.285z" />
</svg>
{% elif n.kind == 'warning' %}
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<path stroke-linecap="round" stroke-linejoin="round"
d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z" />
</svg>
{% else %}
<svg class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
<path stroke-linecap="round" stroke-linejoin="round"
d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" />
</svg>
{% endif %}
</div>
<div class="min-w-0 flex-1">
<div class="flex items-start justify-between gap-2">
<div class="flex items-center gap-2">
<p class="text-sm font-semibold text-slate-900">{{ n.title }}</p>
{% if not n.read %}
<span class="inline-block h-2 w-2 rounded-full bg-sky-500" title="{{ "
notifications_page.unread" | t }}"></span>
{% endif %}
</div>
<time class="shrink-0 text-xs text-slate-400">{{ n.created_at }}</time>
</div>
{% if n.body %}
<p class="mt-1 text-sm text-slate-600">{{ n.body }}</p>
{% endif %}
{% if not n.read %}
<button type="button" @click="markRead({{ n.id }})" data-mark-read
class="mt-2 text-xs font-semibold text-sky-600 hover:text-sky-500 transition">
{{ "notifications_page.mark_as_read" | t }}
</button>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% else %}
<div
class="flex flex-col items-center justify-center rounded-xl bg-white py-20 text-center shadow-sm ring-1 ring-black/5">
<svg class="h-12 w-12 text-slate-300" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="1">
<path stroke-linecap="round" stroke-linejoin="round"
d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" />
</svg>
<p class="mt-4 text-sm font-semibold text-slate-700">{{ "notifications_page.no_notifications" | t }}</p>
<p class="mt-1 text-xs text-slate-400">{{ "notifications_page.all_caught_up" | t }}</p>
</div>
{% endif %}
</div>
</div>
{% block scripts %}
<script>
function notificationsPage() {
return {
init() { },
async markRead(id) {
const res = await fetch(`{{ api_prefix | safe }}/notifications/${id}/read`, { method: 'POST' });
if (res.ok) {
const el = document.getElementById(`notification-${id}`);
if (el) {
el.classList.remove('ring-sky-200', 'bg-sky-50/40');
el.classList.add('ring-black/5');
el.querySelectorAll('[title="Unread"]').forEach(e => e.remove());
el.querySelectorAll('[data-mark-read]').forEach(b => b.remove());
}
window.dispatchEvent(new CustomEvent('notifications:refresh'));
}
},
async markAllRead() {
const res = await fetch(`{{ api_prefix | safe }}/notifications/read-all`, { method: 'POST' });
if (res.ok) {
window.location.reload();
}
}
};
}
</script>
{% endblock %}
{% endblock %}