mirror of
https://github.com/itflow-org/itflow
synced 2026-11-11 07:01:16 +00:00
188 lines
9.5 KiB
PHP
188 lines
9.5 KiB
PHP
<?php
|
|
|
|
/*
|
|
* All notifications - where "View all notifications" in the bell panel lands.
|
|
*
|
|
* Same rows, same rules and same row behaviour as the panel (functions/
|
|
* notifications.php, js/notifications.js), with paging, search, a type filter
|
|
* and a date range on top. Unread by default; "All" includes the read ones,
|
|
* which nightly_tasks.php clears after 90 days.
|
|
*/
|
|
|
|
// Newest first, always - filter_header.php reads this before the include
|
|
$sort = "notification_id";
|
|
$order = "DESC";
|
|
|
|
require_once "includes/inc_all.php";
|
|
|
|
// ?dismissed is the old "Dismissed notifications" link; those are the read ones now
|
|
$view = (($_GET['view'] ?? '') === 'all' || isset($_GET['dismissed'])) ? 'all' : 'unread';
|
|
|
|
$type_filter = trim((string) ($_GET['type'] ?? ''));
|
|
$type_query = $type_filter !== '' ? "AND notification_type = '" . escapeSql($type_filter) . "'" : '';
|
|
$unread_query = $view === 'unread' ? 'AND notification_dismissed_at IS NULL' : '';
|
|
|
|
$sql = mysqli_query(
|
|
$mysqli,
|
|
"SELECT SQL_CALC_FOUND_ROWS notification_id, notification_type, notification, notification_action,
|
|
notification_timestamp, notification_dismissed_at, notification_client_id, client_name
|
|
FROM notifications
|
|
LEFT JOIN clients ON notification_client_id = client_id
|
|
WHERE " . notificationVisibilitySql() . "
|
|
$unread_query
|
|
$type_query
|
|
AND (notification_type LIKE '%$q%' OR notification LIKE '%$q%' OR client_name LIKE '%$q%')
|
|
AND DATE(notification_timestamp) BETWEEN '$dtf' AND '$dtt'
|
|
ORDER BY notification_id DESC
|
|
LIMIT $record_from, $record_to"
|
|
);
|
|
|
|
$num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|
|
|
$unread_count = notificationUnreadCount();
|
|
|
|
$sql_types = mysqli_query($mysqli, "SELECT DISTINCT notification_type FROM notifications WHERE " . notificationVisibilitySql() . " ORDER BY notification_type");
|
|
|
|
// Links that keep every other filter and change one thing
|
|
function notificationsPageUrl($changes) {
|
|
$params = array_merge($_GET, $changes);
|
|
unset($params['page'], $params['dismissed']);
|
|
$params = array_filter($params, function ($value) {
|
|
return $value !== null && $value !== '';
|
|
});
|
|
return 'notifications.php' . ($params ? '?' . http_build_query($params) : '');
|
|
}
|
|
|
|
function notificationsDayLabel($timestamp) {
|
|
$day = date('Y-m-d', $timestamp);
|
|
if ($day === date('Y-m-d')) {
|
|
return 'Today';
|
|
}
|
|
if ($day === date('Y-m-d', strtotime('-1 day'))) {
|
|
return 'Yesterday';
|
|
}
|
|
return date('l, F j' . (date('Y', $timestamp) === date('Y') ? '' : ', Y'), $timestamp);
|
|
}
|
|
|
|
$notifications_date_filtered = $dtf !== '1970-01-01' || $dtt !== '2099-12-31';
|
|
$notifications_filtered = $q !== '' || $type_filter !== '' || $notifications_date_filtered;
|
|
|
|
// This page draws its own empty state - "all caught up" is not "nothing added yet"
|
|
$empty_state_skip = true;
|
|
|
|
?>
|
|
|
|
<div class="card">
|
|
<div class="card-header bg-dark py-2">
|
|
<h3 class="card-title mt-2"><i class="fas fa-fw fa-bell me-2"></i>Notifications</h3>
|
|
<div class="card-tools">
|
|
<button type="button" class="btn btn-light" data-notify-all data-notify-reload <?= $unread_count ? '' : 'disabled' ?>>
|
|
<i class="fas fa-check-double me-2"></i>Mark all as read
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-header py-3">
|
|
<form autocomplete="off">
|
|
<input type="hidden" name="view" value="<?= $view ?>">
|
|
<div class="row g-2 align-items-center">
|
|
<div class="col-md-5">
|
|
<div class="input-group">
|
|
<input type="search" class="form-control" name="q" value="<?= escapeHtml(stripslashes($q)) ?>" placeholder="Search notifications">
|
|
<button class="btn btn-primary" title="Search"><i class="fa fa-search"></i></button>
|
|
<button class="btn btn-secondary" title="More filters" type="button" data-bs-toggle="collapse" data-bs-target="#advancedFilter"><i class="fas fa-filter"></i></button>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<select class="form-select" name="type" onchange="this.form.submit()" aria-label="Notification type">
|
|
<option value="">All types</option>
|
|
<?php while ($row = mysqli_fetch_assoc($sql_types)) {
|
|
$type_option = escapeHtml($row['notification_type']); ?>
|
|
<option <?php if ($type_filter === $row['notification_type']) { echo "selected"; } ?>><?= $type_option ?></option>
|
|
<?php } ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-4 text-md-end">
|
|
<div class="btn-group d-flex d-md-inline-flex" role="group" aria-label="Show">
|
|
<a href="<?= escapeHtml(notificationsPageUrl(['view' => null])) ?>" class="btn flex-fill <?= $view === 'unread' ? 'btn-primary' : 'btn-outline-primary' ?>">
|
|
Unread <span class="badge rounded-pill text-bg-light ms-1" data-notify-count <?= $unread_count ? '' : 'hidden' ?>><?= $unread_count > 99 ? '99+' : $unread_count ?></span>
|
|
</a>
|
|
<a href="<?= escapeHtml(notificationsPageUrl(['view' => 'all'])) ?>" class="btn flex-fill <?= $view === 'all' ? 'btn-primary' : 'btn-outline-primary' ?>">All</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="collapse mt-3 <?php if ($notifications_date_filtered) { echo "show"; } ?>" id="advancedFilter">
|
|
<div class="row g-3">
|
|
<div class="col-md-3">
|
|
<label class="form-label">Date range</label>
|
|
<input type="text" id="dateFilter" class="form-control" autocomplete="off">
|
|
<input type="hidden" name="canned_date" id="canned_date" value="<?= escapeHtml($_GET['canned_date'] ?? '') ?>">
|
|
<input type="hidden" name="dtf" id="dtf" value="<?= escapeHtml($dtf ?? '') ?>">
|
|
<input type="hidden" name="dtt" id="dtt" value="<?= escapeHtml($dtt ?? '') ?>">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<?php if ($num_rows[0] == 0) { ?>
|
|
|
|
<?= emptyStateHtml([
|
|
'thing' => 'notifications',
|
|
'icon' => 'fa-bell-slash',
|
|
'filtered' => $notifications_filtered,
|
|
'clear_url' => 'notifications.php' . ($view === 'all' ? '?view=all' : ''),
|
|
'view' => $view === 'unread' ? [
|
|
'title' => "You're all caught up",
|
|
'text' => 'Nothing new since you last looked.',
|
|
'icon' => 'fa-check',
|
|
'actions' => [['label' => 'See all notifications', 'href' => 'notifications.php?view=all', 'icon' => 'fa-bell']],
|
|
] : null,
|
|
]) ?>
|
|
|
|
<?php } else { ?>
|
|
|
|
<div class="itflow-notify-page" role="list" aria-label="Notifications">
|
|
<?php
|
|
$notification_day = null;
|
|
while ($row = mysqli_fetch_assoc($sql)) {
|
|
$item = notificationItem($row);
|
|
$item_timestamp = strtotime($row['notification_timestamp']);
|
|
$item_day = notificationsDayLabel($item_timestamp);
|
|
$item_tone = in_array($item['tone'], ['primary', 'secondary', 'success', 'danger', 'warning', 'info'], true) ? $item['tone'] : 'secondary';
|
|
|
|
if ($item_day !== $notification_day) {
|
|
$notification_day = $item_day; ?>
|
|
<div class="itflow-notify-group" role="presentation"><?= escapeHtml($item_day) ?></div>
|
|
<?php } ?>
|
|
|
|
<div class="itflow-notify-item <?= $item['unread'] ? 'is-unread' : '' ?>" role="listitem" data-id="<?= $item['id'] ?>">
|
|
<a class="itflow-notify-link" href="<?= $item['url'] ? escapeHtml($item['url']) : '#' ?>"<?= $item['url'] ? '' : ' data-no-link="1"' ?>>
|
|
<span class="itflow-notify-icon bg-<?= $item_tone ?>-subtle text-<?= $item_tone ?>-emphasis"><i class="fas fa-fw fa-<?= escapeHtml($item['icon']) ?>" aria-hidden="true"></i></span>
|
|
<span class="itflow-notify-body">
|
|
<span class="itflow-notify-top">
|
|
<span class="itflow-notify-type"><?= escapeHtml($item['type']) ?></span>
|
|
<time class="itflow-notify-time" datetime="<?= escapeHtml($item['time']) ?>" title="<?= escapeHtml($item['time_full']) ?>"><?= date('g:i A', $item_timestamp) ?></time>
|
|
</span>
|
|
<span class="itflow-notify-text"><?= escapeHtml($item['text']) ?></span>
|
|
<?php if ($item['client']) { ?>
|
|
<span class="itflow-notify-client"><i class="fas fa-fw fa-building" aria-hidden="true"></i><?= escapeHtml($item['client']) ?></span>
|
|
<?php } ?>
|
|
</span>
|
|
</a>
|
|
<button type="button" class="btn btn-sm itflow-notify-toggle" title="<?= $item['unread'] ? 'Mark as read' : 'Mark as unread' ?>" aria-label="<?= $item['unread'] ? 'Mark as read' : 'Mark as unread' ?>">
|
|
<i class="fas fa-fw fa-<?= $item['unread'] ? 'check' : 'undo' ?>" aria-hidden="true"></i>
|
|
</button>
|
|
</div>
|
|
|
|
<?php } ?>
|
|
</div>
|
|
|
|
<?php } ?>
|
|
|
|
<?php require_once "../includes/filter_footer.php"; ?>
|
|
</div>
|
|
|
|
<?php
|
|
require_once "../includes/footer.php";
|