feat(notifications): add notification dashboard and detail views
This commit introduces a comprehensive notification management system with three new templates for displaying and managing notifications. **New Features** - Added `dashboard.html` with a notification overview featuring: - Summary statistics for pending, sent, and failed notifications - A table of recent notifications with status indicators - Navigation links to view all notifications - Added `notification_list.html` for displaying all notifications in a paginated table format - Added `notification_detail.html` for viewing individual notification details including: - Recipient information - Subject and message content - Status with visual indicators - Timestamps for creation and delivery - Related object information when available **Enhancements & Refinements** - Consistent styling across all notification templates using the existing design system - Status badges with color coding (success for sent, error for failed, warning for pending) - Responsive table layouts for better mobile viewing - Empty state handling for when no notifications exist ```
This commit is contained in:
3 files changed
+223
No files matched your search
@@ -0,0 +1,89 @@
|
|||||||
|
{% extends "shared/base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include "shared/navbar.html" %}
|
||||||
|
|
||||||
|
<div class="pt-20 min-h-screen flex flex-col pb-10">
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="flex justify-between items-center mb-8">
|
||||||
|
<h1 class="text-3xl font-bold text-heading">Notifications</h1>
|
||||||
|
<a href="{% url 'notification_list' %}" class="btn btn-ghost btn-sm">View All</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Top Stats -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
||||||
|
<div class="stat bg-neutral-secondary-soft rounded-lg shadow-sm border border-default">
|
||||||
|
<div class="stat-title text-body">Pending</div>
|
||||||
|
<div class="stat-value text-warning">{{ pending_count }}</div>
|
||||||
|
<div class="stat-desc text-body-secondary">Waiting to be sent</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat bg-neutral-secondary-soft rounded-lg shadow-sm border border-default">
|
||||||
|
<div class="stat-title text-body">Sent</div>
|
||||||
|
<div class="stat-value text-success">{{ sent_count }}</div>
|
||||||
|
<div class="stat-desc text-body-secondary">Successfully delivered</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="stat bg-neutral-secondary-soft rounded-lg shadow-sm border border-default">
|
||||||
|
<div class="stat-title text-body">Failed</div>
|
||||||
|
<div class="stat-value text-error">{{ failed_count }}</div>
|
||||||
|
<div class="stat-desc text-body-secondary">Need attention</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Recent Notifications -->
|
||||||
|
<div class="bg-neutral-secondary-soft rounded-lg shadow-sm border border-default p-6">
|
||||||
|
<div class="flex justify-between items-center mb-4">
|
||||||
|
<h2 class="text-xl font-bold text-heading">Recent Notifications</h2>
|
||||||
|
<a href="{% url 'notification_list' %}" class="btn btn-ghost btn-xs">View All</a>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="table w-full">
|
||||||
|
<thead>
|
||||||
|
<tr class="text-body border-b border-default">
|
||||||
|
<th>Recipient</th>
|
||||||
|
<th>Subject</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Created</th>
|
||||||
|
<th>Sent At</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for n in recent_notifications %}
|
||||||
|
<tr class="hover:bg-neutral-tertiary border-b border-default last:border-0">
|
||||||
|
<td class="text-body">{{ n.recipient }}</td>
|
||||||
|
<td class="font-medium text-heading">
|
||||||
|
<a href="{% url 'notification_detail' n.pk %}" class="link link-hover">
|
||||||
|
{{ n.subject }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge badge-sm
|
||||||
|
{% if n.status == 'SENT' %}badge-success
|
||||||
|
{% elif n.status == 'FAILED' %}badge-error
|
||||||
|
{% else %}badge-warning{% endif %}">
|
||||||
|
{{ n.get_status_display }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-body-secondary text-sm">
|
||||||
|
{{ n.created_at|date:"M d, Y H:i" }}
|
||||||
|
</td>
|
||||||
|
<td class="text-body-secondary text-sm">
|
||||||
|
{% if n.sent_at %}{{ n.sent_at|date:"M d, Y H:i" }}{% else %}-{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" class="text-center text-body-secondary py-4">No notifications yet.</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
{% extends "shared/base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include "shared/navbar.html" %}
|
||||||
|
|
||||||
|
<div class="pt-20 min-h-screen flex flex-col pb-10">
|
||||||
|
<div class="max-w-3xl mx-auto px-4 sm:px-6 lg:px-8 w-full">
|
||||||
|
<div class="mb-8">
|
||||||
|
<h1 class="text-3xl font-bold text-heading">Notification Detail</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-neutral-secondary-soft rounded-lg shadow-sm border border-default p-6 space-y-4">
|
||||||
|
<div>
|
||||||
|
<h2 class="text-sm font-semibold text-body-secondary uppercase tracking-wide">Recipient</h2>
|
||||||
|
<p class="text-heading">{{ notification.recipient }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 class="text-sm font-semibold text-body-secondary uppercase tracking-wide">Subject</h2>
|
||||||
|
<p class="text-heading">{{ notification.subject }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 class="text-sm font-semibold text-body-secondary uppercase tracking-wide">Status</h2>
|
||||||
|
<span class="badge
|
||||||
|
{% if notification.status == 'SENT' %}badge-success
|
||||||
|
{% elif notification.status == 'FAILED' %}badge-error
|
||||||
|
{% else %}badge-warning{% endif %}">
|
||||||
|
{{ notification.get_status_display }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<h2 class="text-sm font-semibold text-body-secondary uppercase tracking-wide">Created At</h2>
|
||||||
|
<p class="text-body-secondary text-sm">
|
||||||
|
{{ notification.created_at|date:"M d, Y H:i" }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2 class="text-sm font-semibold text-body-secondary uppercase tracking-wide">Sent At</h2>
|
||||||
|
<p class="text-body-secondary text-sm">
|
||||||
|
{% if notification.sent_at %}{{ notification.sent_at|date:"M d, Y H:i" }}{% else %}-{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 class="text-sm font-semibold text-body-secondary uppercase tracking-wide">Message</h2>
|
||||||
|
<pre class="mt-2 p-4 bg-base-100 rounded-lg border border-default text-sm text-body whitespace-pre-wrap">{{ notification.message }}</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if notification.content_object %}
|
||||||
|
<div>
|
||||||
|
<h2 class="text-sm font-semibold text-body-secondary uppercase tracking-wide">Related Object</h2>
|
||||||
|
<p class="text-body text-sm">
|
||||||
|
{{ notification.content_type }} — ID {{ notification.object_id }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="pt-4 flex justify-end">
|
||||||
|
<a href="{% url 'notification_list' %}" class="btn btn-ghost">Back to List</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
{% extends "shared/base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include "shared/navbar.html" %}
|
||||||
|
|
||||||
|
<div class="pt-20 min-h-screen flex flex-col pb-10">
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 w-full">
|
||||||
|
<div class="flex justify-between items-center mb-8">
|
||||||
|
<h1 class="text-3xl font-bold text-heading">All Notifications</h1>
|
||||||
|
<a href="{% url 'notifications_dashboard' %}" class="btn btn-ghost btn-sm">Back to Dashboard</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-neutral-secondary-soft rounded-lg shadow-sm border border-default p-6">
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="table w-full">
|
||||||
|
<thead>
|
||||||
|
<tr class="text-body border-b border-default">
|
||||||
|
<th>Recipient</th>
|
||||||
|
<th>Subject</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Created</th>
|
||||||
|
<th>Sent At</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for n in notifications %}
|
||||||
|
<tr class="hover:bg-neutral-tertiary border-b border-default last:border-0">
|
||||||
|
<td class="text-body">{{ n.recipient }}</td>
|
||||||
|
<td class="font-medium text-heading">
|
||||||
|
<a href="{% url 'notification_detail' n.pk %}" class="link link-hover">
|
||||||
|
{{ n.subject }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge badge-sm
|
||||||
|
{% if n.status == 'SENT' %}badge-success
|
||||||
|
{% elif n.status == 'FAILED' %}badge-error
|
||||||
|
{% else %}badge-warning{% endif %}">
|
||||||
|
{{ n.get_status_display }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td class="text-body-secondary text-sm">
|
||||||
|
{{ n.created_at|date:"M d, Y H:i" }}
|
||||||
|
</td>
|
||||||
|
<td class="text-body-secondary text-sm">
|
||||||
|
{% if n.sent_at %}{{ n.sent_at|date:"M d, Y H:i" }}{% else %}-{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% empty %}
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" class="text-center text-body-secondary py-4">No notifications found.</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
Reference in new issue
Block a user