2025-11-02 14:35:35 +03:00

320 lines
13 KiB
HTML

{% extends "base.html" %}
{% load i18n static %}
{% block title %}{% trans "Notifications Dashboard" %} - Tenhal{% endblock %}
{% block css %}
<style>
.stat-card {
border-left: 4px solid;
transition: transform 0.2s;
}
.stat-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.stat-card.primary { border-left-color: #0d6efd; }
.stat-card.success { border-left-color: #198754; }
.stat-card.danger { border-left-color: #dc3545; }
.stat-card.warning { border-left-color: #ffc107; }
.stat-card.info { border-left-color: #0dcaf0; }
.chart-container {
position: relative;
height: 300px;
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Page Header -->
<div class="d-flex justify-content-between align-items-center mb-3">
<div>
<h1 class="page-header mb-0">
<i class="fas fa-bell me-2"></i>{% trans "Notifications Dashboard" %}
</h1>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">{% trans "Dashboard" %}</a></li>
<li class="breadcrumb-item active">{% trans "Notifications" %}</li>
</ol>
</nav>
</div>
<div>
<a href="{% url 'notifications:message_list' %}" class="btn btn-outline-primary">
<i class="fas fa-list me-1"></i>{% trans "All Messages" %}
</a>
<a href="{% url 'notifications:template_list' %}" class="btn btn-outline-secondary">
<i class="fas fa-file-alt me-1"></i>{% trans "Templates" %}
</a>
<a href="{% url 'notifications:bulk_message' %}" class="btn btn-primary">
<i class="fas fa-paper-plane me-1"></i>{% trans "Send Bulk Message" %}
</a>
</div>
</div>
<!-- Time Range Filter -->
<div class="card mb-3">
<div class="card-body">
<form method="get" class="row g-3 align-items-end">
<div class="col-auto">
<label class="form-label">{% trans "Time Range" %}</label>
<select name="days" class="form-select" onchange="this.form.submit()">
<option value="7" {% if days == 7 %}selected{% endif %}>{% trans "Last 7 Days" %}</option>
<option value="30" {% if days == 30 %}selected{% endif %}>{% trans "Last 30 Days" %}</option>
<option value="90" {% if days == 90 %}selected{% endif %}>{% trans "Last 90 Days" %}</option>
</select>
</div>
</form>
</div>
</div>
<!-- Statistics Cards -->
<div class="row g-3 mb-4">
<!-- Total Messages -->
<div class="col-md-3">
<div class="card stat-card primary h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start">
<div>
<h6 class="text-muted mb-2">{% trans "Total Messages" %}</h6>
<h2 class="mb-0">{{ stats.total|default:0 }}</h2>
</div>
<div class="text-primary">
<i class="fas fa-envelope fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Delivered -->
<div class="col-md-3">
<div class="card stat-card success h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start">
<div>
<h6 class="text-muted mb-2">{% trans "Delivered" %}</h6>
<h2 class="mb-0">{{ stats.delivered|default:0 }}</h2>
<small class="text-success">
<i class="fas fa-arrow-up"></i> {{ stats.success_rate }}%
</small>
</div>
<div class="text-success">
<i class="fas fa-check-circle fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Failed -->
<div class="col-md-3">
<div class="card stat-card danger h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start">
<div>
<h6 class="text-muted mb-2">{% trans "Failed" %}</h6>
<h2 class="mb-0">{{ stats.failed|default:0 }}</h2>
{% if failed_messages_count > 0 %}
<small class="text-danger">
{{ failed_messages_count }} {% trans "can retry" %}
</small>
{% endif %}
</div>
<div class="text-danger">
<i class="fas fa-exclamation-circle fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Queued -->
<div class="col-md-3">
<div class="card stat-card warning h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start">
<div>
<h6 class="text-muted mb-2">{% trans "Queued" %}</h6>
<h2 class="mb-0">{{ stats.queued|default:0 }}</h2>
</div>
<div class="text-warning">
<i class="fas fa-clock fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row g-3">
<!-- Channel Breakdown -->
<div class="col-md-4">
<div class="card h-100">
<div class="card-header">
<h5 class="card-title mb-0">{% trans "By Channel" %}</h5>
</div>
<div class="card-body">
<div class="list-group list-group-flush">
{% for channel, count in stats.by_channel.items %}
<div class="list-group-item d-flex justify-content-between align-items-center">
<span>
{% if channel == 'SMS' %}
<i class="fas fa-sms text-primary"></i>
{% elif channel == 'WHATSAPP' %}
<i class="fab fa-whatsapp text-success"></i>
{% elif channel == 'EMAIL' %}
<i class="fas fa-envelope text-info"></i>
{% endif %}
{{ channel }}
</span>
<span class="badge bg-secondary rounded-pill">{{ count }}</span>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<!-- Daily Trend Chart -->
<div class="col-md-8">
<div class="card h-100">
<div class="card-header">
<h5 class="card-title mb-0">{% trans "Daily Trend" %}</h5>
</div>
<div class="card-body">
<div class="chart-container">
<canvas id="dailyTrendChart"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- Recent Messages -->
<div class="card mt-3">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0">{% trans "Recent Messages" %}</h5>
<a href="{% url 'notifications:message_list' %}" class="btn btn-sm btn-outline-primary">
{% trans "View All" %}
</a>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>{% trans "Date" %}</th>
<th>{% trans "Channel" %}</th>
<th>{% trans "Recipient" %}</th>
<th>{% trans "Template" %}</th>
<th>{% trans "Status" %}</th>
<th>{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for message in recent_messages %}
<tr>
<td>{{ message.created_at|date:"Y-m-d H:i" }}</td>
<td>
{% if message.channel == 'SMS' %}
<span class="badge bg-primary">SMS</span>
{% elif message.channel == 'WHATSAPP' %}
<span class="badge bg-success">WhatsApp</span>
{% elif message.channel == 'EMAIL' %}
<span class="badge bg-info">Email</span>
{% endif %}
</td>
<td>{{ message.recipient }}</td>
<td>{{ message.template.name|default:"-" }}</td>
<td>
{% if message.status == 'DELIVERED' or message.status == 'READ' %}
<span class="badge bg-success">{{ message.get_status_display }}</span>
{% elif message.status == 'FAILED' %}
<span class="badge bg-danger">{{ message.get_status_display }}</span>
{% elif message.status == 'QUEUED' %}
<span class="badge bg-warning">{{ message.get_status_display }}</span>
{% else %}
<span class="badge bg-secondary">{{ message.get_status_display }}</span>
{% endif %}
</td>
<td>
<a href="{% url 'notifications:message_detail' message.pk %}"
class="btn btn-sm btn-outline-primary">
<i class="fas fa-eye"></i>
</a>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center text-muted">
{% trans "No messages found" %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<script>
// Daily Trend Chart
const dailyTrendCtx = document.getElementById('dailyTrendChart').getContext('2d');
const dailyTrendData = {{ stats.daily_stats|safe }};
new Chart(dailyTrendCtx, {
type: 'line',
data: {
labels: dailyTrendData.map(d => d.date),
datasets: [
{
label: '{% trans "Total" %}',
data: dailyTrendData.map(d => d.total),
borderColor: '#0d6efd',
backgroundColor: 'rgba(13, 110, 253, 0.1)',
tension: 0.4
},
{
label: '{% trans "Delivered" %}',
data: dailyTrendData.map(d => d.delivered),
borderColor: '#198754',
backgroundColor: 'rgba(25, 135, 84, 0.1)',
tension: 0.4
},
{
label: '{% trans "Failed" %}',
data: dailyTrendData.map(d => d.failed),
borderColor: '#dc3545',
backgroundColor: 'rgba(220, 53, 69, 0.1)',
tension: 0.4
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'top',
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
stepSize: 1
}
}
}
}
});
</script>
{% endblock %}