new: [notification] Added initial version of the notification system
parent
fc2c67ef55
commit
6321725fa9
|
@ -78,6 +78,9 @@ class AppController extends Controller
|
|||
$this->loadComponent('Navigation', [
|
||||
'request' => $this->request,
|
||||
]);
|
||||
$this->loadComponent('Notification', [
|
||||
'request' => $this->request,
|
||||
]);
|
||||
if (Configure::read('debug')) {
|
||||
Configure::write('DebugKit.panels', ['DebugKit.Packages' => true]);
|
||||
Configure::write('DebugKit.forceEnable', true);
|
||||
|
@ -152,6 +155,7 @@ class AppController extends Controller
|
|||
{
|
||||
if (!$this->ParamHandler->isRest()) {
|
||||
$this->set('breadcrumb', $this->Navigation->getBreadcrumb());
|
||||
$this->set('notifications', $this->Notification->getNotifications());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller\Component;
|
||||
|
||||
use Cake\Controller\Component;
|
||||
use Cake\Core\Configure;
|
||||
use Cake\Http\Exception\MethodNotAllowedException;
|
||||
use Cake\ORM\TableRegistry;
|
||||
|
||||
class NotificationComponent extends Component
|
||||
{
|
||||
private $tables = [
|
||||
'Inbox',
|
||||
];
|
||||
|
||||
public function initialize(array $config): void
|
||||
{
|
||||
$this->request = $config['request'];
|
||||
}
|
||||
|
||||
public function getNotifications(): array
|
||||
{
|
||||
$notifications = [];
|
||||
$notifications = $this->collectNotificationsFromTables();
|
||||
return $notifications;
|
||||
}
|
||||
|
||||
private function collectNotificationsFromTables(): array
|
||||
{
|
||||
$notifications = [];
|
||||
foreach ($this->tables as $tableName) {
|
||||
$table = TableRegistry::getTableLocator()->get($tableName);
|
||||
$tableNotifications = $this->collectNotificationFromTable($table);
|
||||
$notifications = array_merge($notifications, $tableNotifications);
|
||||
}
|
||||
return $notifications;
|
||||
}
|
||||
|
||||
private function collectNotificationFromTable($table): array
|
||||
{
|
||||
$notifications = [];
|
||||
if (method_exists($table, 'collectNotifications')) {
|
||||
$notifications = $table->collectNotifications();
|
||||
}
|
||||
return $notifications;
|
||||
}
|
||||
}
|
|
@ -9,6 +9,8 @@ use Cake\ORM\RulesChecker;
|
|||
use Cake\Validation\Validator;
|
||||
use Cake\Http\Exception\NotFoundException;
|
||||
|
||||
use App\Utility\UI\Notification;
|
||||
|
||||
Type::map('json', 'Cake\Database\Type\JsonType');
|
||||
|
||||
class InboxTable extends AppTable
|
||||
|
@ -86,4 +88,27 @@ class InboxTable extends AppTable
|
|||
$savedEntry = $this->save($entryData);
|
||||
return $savedEntry;
|
||||
}
|
||||
|
||||
public function collectNotifications(): array
|
||||
{
|
||||
$allNotifications = [];
|
||||
$query = $this->find();
|
||||
$inboxNotifications = $query->all()->toArray();
|
||||
foreach ($inboxNotifications as $notification) {
|
||||
$title = __('New message');
|
||||
$details = $notification->title;
|
||||
$router = [
|
||||
'controller' => 'inbox',
|
||||
'action' => 'index',
|
||||
'plugin' => null,
|
||||
];
|
||||
$allNotifications[] = (new Notification($title, $router, [
|
||||
'icon' => 'envelope',
|
||||
'details' => $details,
|
||||
'datetime' => $notification->created,
|
||||
'variant' => 'warning',
|
||||
]))->get();
|
||||
}
|
||||
return $allNotifications;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Utility\UI;
|
||||
|
||||
use Cake\Validation\Validator;
|
||||
|
||||
|
||||
class Notification
|
||||
{
|
||||
public $text = '';
|
||||
public $router = null;
|
||||
public $details = null;
|
||||
public $icon = 'exclamation-circle';
|
||||
public $variant = 'primary';
|
||||
public $datetime = null;
|
||||
|
||||
|
||||
public function __construct(string $text, array $router, $options = [])
|
||||
{
|
||||
$this->text = $text;
|
||||
$this->router = $router;
|
||||
foreach ($options as $key => $value) {
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
$this->validate();
|
||||
}
|
||||
|
||||
public function get(): array
|
||||
{
|
||||
if (empty($errors)) {
|
||||
return (array) $this;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function validate()
|
||||
{
|
||||
$validator = new Validator();
|
||||
|
||||
$validator
|
||||
->requirePresence('title', 'create')
|
||||
->notEmptyString('title');
|
||||
|
||||
return $validator->validate((array) $this);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Cake\Routing\Router;
|
||||
|
||||
$seed = 's-' . mt_rand();
|
||||
$datetimeMW = 90;
|
||||
$variant = empty($notification['variant']) ? 'primary' : $notification['variant'];
|
||||
?>
|
||||
<a
|
||||
class="dropdown-item px-2"
|
||||
href="<?= Router::url($notification['router']) ?>"
|
||||
style="max-height: 76px;"
|
||||
title="<?= sprintf('%s:
 %s', $this->ValueGetter->get($notification['text']), $this->ValueGetter->get($notification['details'])) ?>"
|
||||
>
|
||||
<div class="d-flex align-items-center">
|
||||
<?php if (!empty($notification['icon'])) : ?>
|
||||
<span class="rounded-circle <?= "btn-{$variant} me-2" ?> position-relative" style="width: 36px; height: 36px">
|
||||
<?= $this->Bootstrap->icon($notification['icon'], ['class' => ['fa-fw', 'position-absolute top-50 start-50 translate-middle']]) ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
<span class="" style="max-width: calc(100% - 40px - 0.25rem);">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<span class="text-truncate" style=" max-width: calc(100% - <?= $datetimeMW ?>px);"><?= $this->ValueGetter->get($notification['text']) ?></span>
|
||||
<?php if (!empty($notification['datetime'])) : ?>
|
||||
<small id="<?= $seed ?>" class="text-muted fw-light" style="max-width: <?= $datetimeMW ?>px;"><?= h($notification['datetime']->format('Y-m-d\TH:i:s')) ?></small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if (!empty($notification['details'])) : ?>
|
||||
<small class="text-muted text-wrap lh-1 text-truncate" style="-webkit-line-clamp: 2; -webkit-box-orient: vertical; display: -webkit-box;">
|
||||
<?= $this->ValueGetter->get($notification['details']) ?>
|
||||
</small>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
<script>
|
||||
document.getElementById('<?= $seed ?>').innerHTML = moment(document.getElementById('<?= $seed ?>').innerHTML).fromNow();
|
||||
</script>
|
|
@ -1,13 +1,28 @@
|
|||
<?php
|
||||
|
||||
use Cake\Routing\Router;
|
||||
?>
|
||||
<div class="btn-group">
|
||||
<a class="nav-link px-2 text-decoration-none profile-button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="#" data-bs-offset="10,20">
|
||||
<i class="<?= $this->FontAwesome->getClass('bell') ?> fa-lg"></i>
|
||||
<span class="position-relative">
|
||||
<i class="<?= $this->FontAwesome->getClass('bell') ?> fa-lg"></i>
|
||||
<span class="position-absolute top-0 start-100 translate-middle p-1 bg-warning border border-light border-2 rounded-circle">
|
||||
<span class="visually-hidden"><?= __('New notifications') ?></span>
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-end">
|
||||
<?php if (empty($notifications)): ?>
|
||||
<h6 class="dropdown-header"><?= __('- No notification -') ?></h6>
|
||||
<div class="dropdown-menu dropdown-menu-end" style="min-width: 320px; max-width: 25vw">
|
||||
<h6 class="dropdown-header d-flex justify-content-between">
|
||||
<span><?= __n('{0} Notification', '{0} Notifications', count($notifications), count($notifications)) ?></span>
|
||||
</h6>
|
||||
<?php if (empty($notifications)) : ?>
|
||||
<span class="dropdown-item-text text-nowrap user-select-none text-center">
|
||||
<?= __('- No notification -') ?>
|
||||
<span>
|
||||
<?php else : ?>
|
||||
<?php foreach ($notifications as $notification) : ?>
|
||||
<?= $this->element('layouts/header/header-notification-item', ['notification' => $notification]) ?>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
Loading…
Reference in New Issue