Initial commit
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
@{
|
||||
ViewData["Title"] = "Notification History";
|
||||
ViewData["PageIcon"] = "bi-bell";
|
||||
var items = Model as IEnumerable<dynamic> ?? Enumerable.Empty<dynamic>();
|
||||
var pageNumber = (int)(ViewBag.PageNumber ?? 1);
|
||||
var pageSize = (int)(ViewBag.PageSize ?? 25);
|
||||
var totalCount = (int)(ViewBag.TotalCount ?? 0);
|
||||
var totalPages = (int)(ViewBag.TotalPages ?? 1);
|
||||
}
|
||||
|
||||
@section Styles {
|
||||
<style>
|
||||
tr.notif-unread { background: rgba(99, 102, 241, 0.08) !important; }
|
||||
tr.notif-unread:hover { background: rgba(99, 102, 241, 0.14) !important; }
|
||||
</style>
|
||||
}
|
||||
|
||||
<div class="mb-4"></div>
|
||||
|
||||
@if (!items.Any())
|
||||
{
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body text-center py-5 text-muted">
|
||||
<i class="bi bi-bell-slash fs-1 d-block mb-3 opacity-25"></i>
|
||||
<p class="mb-0">No notifications yet.</p>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover align-middle mb-0">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th style="width:20px;"></th>
|
||||
<th>Title</th>
|
||||
<th>Message</th>
|
||||
<th>Type</th>
|
||||
<th>Received</th>
|
||||
<th>Read</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var n in items)
|
||||
{
|
||||
bool isRead = (bool)n.IsRead;
|
||||
string title = (string)n.Title;
|
||||
string message = (string)n.Message;
|
||||
string? link = (string?)n.Link;
|
||||
string notifType = (string)n.NotificationType;
|
||||
DateTime createdAt = ((DateTime)n.CreatedAt).Tz(ViewBag.CompanyTimeZone as string);
|
||||
DateTime? readAt = n.ReadAt == null ? (DateTime?)null : ((DateTime)n.ReadAt).Tz(ViewBag.CompanyTimeZone as string);
|
||||
<tr class="@(!isRead ? "notif-unread" : "") notif-history-row" style="cursor:pointer;"
|
||||
data-id="@n.Id"
|
||||
data-title="@title"
|
||||
data-message="@message"
|
||||
data-link="@(link ?? "")"
|
||||
data-type="@notifType"
|
||||
data-is-read="@(isRead ? "1" : "0")"
|
||||
data-created-at="@createdAt.ToString("MMM d, yyyy h:mm tt")">
|
||||
<td>
|
||||
@if (!isRead)
|
||||
{
|
||||
<span title="Unread" style="display:inline-block;width:10px;height:10px;background:#6366f1;border-radius:50%;"></span>
|
||||
}
|
||||
</td>
|
||||
<td class="@(!isRead ? "fw-semibold" : "text-muted")">
|
||||
@if (!string.IsNullOrEmpty(link))
|
||||
{
|
||||
<a href="@link" class="text-decoration-none">@title</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
@title
|
||||
}
|
||||
</td>
|
||||
<td class="text-muted small" style="max-width:320px;">@message</td>
|
||||
<td><span class="badge bg-secondary bg-opacity-25 text-body small">@notifType</span></td>
|
||||
<td class="text-nowrap small text-muted">@createdAt.ToString("MMM d, yyyy h:mm tt")</td>
|
||||
<td class="text-nowrap small text-muted">
|
||||
@if (readAt.HasValue)
|
||||
{
|
||||
@readAt.Value.ToString("MMM d, h:mm tt")
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="badge bg-primary bg-opacity-10 text-primary">Unread</span>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if (totalPages > 1)
|
||||
{
|
||||
<div class="card-footer d-flex justify-content-between align-items-center">
|
||||
<small class="text-muted">
|
||||
Showing @((pageNumber - 1) * pageSize + 1)–@(Math.Min(pageNumber * pageSize, totalCount)) of @totalCount
|
||||
</small>
|
||||
<nav>
|
||||
<ul class="pagination pagination-sm mb-0">
|
||||
<li class="page-item @(pageNumber <= 1 ? "disabled" : "")">
|
||||
<a class="page-link" href="?pageNumber=@(pageNumber - 1)&pageSize=@pageSize">‹</a>
|
||||
</li>
|
||||
@for (var p = Math.Max(1, pageNumber - 2); p <= Math.Min(totalPages, pageNumber + 2); p++)
|
||||
{
|
||||
<li class="page-item @(p == pageNumber ? "active" : "")">
|
||||
<a class="page-link" href="?pageNumber=@p&pageSize=@pageSize">@p</a>
|
||||
</li>
|
||||
}
|
||||
<li class="page-item @(pageNumber >= totalPages ? "disabled" : "")">
|
||||
<a class="page-link" href="?pageNumber=@(pageNumber + 1)&pageSize=@pageSize">›</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
document.querySelectorAll('.notif-history-row').forEach(row => {
|
||||
row.addEventListener('click', () => {
|
||||
const n = {
|
||||
id: parseInt(row.dataset.id),
|
||||
title: row.dataset.title,
|
||||
message: row.dataset.message,
|
||||
link: row.dataset.link || null,
|
||||
notificationType: row.dataset.type,
|
||||
isRead: row.dataset.isRead === '1',
|
||||
createdAt: row.dataset.createdAt
|
||||
};
|
||||
|
||||
// Open the shared detail modal
|
||||
notifBell.openDetail(n, null);
|
||||
|
||||
// Update this row's visual state if it was unread
|
||||
if (!n.isRead) {
|
||||
row.classList.remove('notif-unread');
|
||||
row.dataset.isRead = '1';
|
||||
const dot = row.querySelector('[title="Unread"]');
|
||||
if (dot) dot.remove();
|
||||
const badge = row.querySelector('.badge.text-primary');
|
||||
if (badge) badge.remove();
|
||||
const titleCell = row.querySelector('td:nth-child(2)');
|
||||
if (titleCell) {
|
||||
titleCell.classList.remove('fw-semibold');
|
||||
titleCell.classList.add('text-muted');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
Reference in New Issue
Block a user