new: [notification] Added initial version of the notification system

pull/93/head
Sami Mokaddem 2022-01-24 15:13:28 +01:00
parent fc2c67ef55
commit 6321725fa9
No known key found for this signature in database
GPG Key ID: 164C473F627A06FA
6 changed files with 181 additions and 5 deletions

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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:&#010; %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>

View File

@ -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>