feat(helpdesk): add ticket/debtor communication feed and chat timeline UI
This commit is contained in:
@@ -38,6 +38,7 @@ $locationDisplay = $postCode !== '' && $city !== '' ? $postCode . ' ' . $city :
|
||||
data-tickets-url="<?php e(lurl('helpdesk/debitor-tickets-data')); ?>"
|
||||
data-ticket-base-url="<?php e(lurl('helpdesk/ticket/')); ?>"
|
||||
data-summary-url="<?php e(lurl('helpdesk/debitor-summary-data')); ?>"
|
||||
data-communication-url="<?php e(lurl('helpdesk/debitor-communication-data')); ?>"
|
||||
>
|
||||
<section>
|
||||
<?php
|
||||
@@ -222,6 +223,22 @@ $locationDisplay = $postCode !== '' && $city !== '' ? $postCode . ' ' . $city :
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<?php if (!$hasError && $customer !== []): ?>
|
||||
<aside id="app-details-aside-section">
|
||||
<div class="app-details-aside-section helpdesk-comm-aside">
|
||||
<hgroup>
|
||||
<h2><?php e(t('Ticket communication')); ?></h2>
|
||||
<p><?php e(t('Last 5 tickets')); ?></p>
|
||||
</hgroup>
|
||||
<hr>
|
||||
<div id="debitor-communication-loading" aria-busy="true"><?php e(t('Loading...')); ?></div>
|
||||
<div id="debitor-communication-content" hidden>
|
||||
<div id="debitor-communication-feed"></div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Grid.js tickets config -->
|
||||
@@ -272,6 +289,23 @@ $locationDisplay = $postCode !== '' && $city !== '' ? $postCode . ' ' . $city :
|
||||
'No recent activity found.' => t('No recent activity found.'),
|
||||
'Could not load contacts.' => t('Could not load contacts.'),
|
||||
'Could not load tickets.' => t('Could not load tickets.'),
|
||||
'Ticket communication' => t('Ticket communication'),
|
||||
'Last 5 tickets' => t('Last 5 tickets'),
|
||||
'No communication found.' => t('No communication found.'),
|
||||
'Could not load communication history.' => t('Could not load communication history.'),
|
||||
'Some ticket communications could not be loaded completely.' => t('Some ticket communications could not be loaded completely.'),
|
||||
'Unknown user' => t('Unknown user'),
|
||||
'Unknown time' => t('Unknown time'),
|
||||
'Ticket' => t('Ticket'),
|
||||
'Activity' => t('Activity'),
|
||||
'Message' => t('Message'),
|
||||
'Status change' => t('Status change'),
|
||||
'Forwarded' => t('Forwarded'),
|
||||
'attached a file' => t('attached a file'),
|
||||
'logged an activity' => t('logged an activity'),
|
||||
'on' => t('on'),
|
||||
'SOAP' => t('SOAP'),
|
||||
'Activity fallback' => t('Activity fallback'),
|
||||
'Loading...' => t('Loading...'),
|
||||
]); ?></script>
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Http\SessionStoreInterface;
|
||||
use MintyPHP\Module\Helpdesk\HelpdeskAuthorizationPolicy;
|
||||
use MintyPHP\Module\Helpdesk\Service\TicketCommunicationService;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
Guard::requireAbilityOrForbidden(HelpdeskAuthorizationPolicy::ABILITY_ACCESS);
|
||||
|
||||
$request = requestInput();
|
||||
if ($request->method() !== 'GET') {
|
||||
http_response_code(405);
|
||||
Router::json(['ok' => false, 'error' => 'method_not_allowed']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$customerNo = trim((string) $request->query('customerNo', ''));
|
||||
$customerName = trim((string) $request->query('customerName', ''));
|
||||
|
||||
if ($customerNo === '' || $customerName === '') {
|
||||
http_response_code(400);
|
||||
Router::json(['ok' => false, 'error' => 'missing_parameters']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$sessionStore = app(SessionStoreInterface::class);
|
||||
$session = $sessionStore->all();
|
||||
$tenantId = (int) (($session['current_tenant']['id'] ?? 0));
|
||||
$tenantScope = $tenantId > 0 ? (string) $tenantId : 'global';
|
||||
$cacheKey = 'module.helpdesk.debitor_comm_cache.v3.' . $tenantScope . '.' . $customerNo;
|
||||
$cacheTtl = 120;
|
||||
$cached = $sessionStore->get($cacheKey);
|
||||
|
||||
if (is_array($cached) && isset($cached['fetched_at']) && (time() - (int) $cached['fetched_at']) < $cacheTtl) {
|
||||
Router::json((array) ($cached['payload'] ?? ['ok' => false]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$service = app(TicketCommunicationService::class);
|
||||
$result = $service->loadDebitorCommunicationFeed($customerNo, $customerName, 5, 40, 250);
|
||||
if (($result['ok'] ?? false) === true) {
|
||||
$sessionStore->set($cacheKey, [
|
||||
'payload' => $result,
|
||||
'fetched_at' => time(),
|
||||
]);
|
||||
}
|
||||
|
||||
Router::json($result);
|
||||
@@ -3,6 +3,7 @@
|
||||
use MintyPHP\Module\Helpdesk\HelpdeskAuthorizationPolicy;
|
||||
use MintyPHP\Module\Helpdesk\Service\DebitorDetailService;
|
||||
use MintyPHP\Http\SessionStoreInterface;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
@@ -15,8 +16,8 @@ $customerNo = trim((string) $request->query('customerNo', ''));
|
||||
$customerName = trim((string) $request->query('customerName', ''));
|
||||
|
||||
if ($customerNo === '' || $customerName === '') {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['ok' => false, 'error' => 'Missing parameters']);
|
||||
http_response_code(400);
|
||||
Router::json(['ok' => false, 'error' => 'Missing parameters']);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -31,9 +32,12 @@ $cacheTtl = 120;
|
||||
$cached = $sessionStore->get($cacheKey);
|
||||
|
||||
if (is_array($cached) && isset($cached['fetched_at']) && (time() - (int) $cached['fetched_at']) < $cacheTtl) {
|
||||
$summary = DebitorDetailService::summarizeTickets($cached['tickets'] ?? []);
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($summary);
|
||||
$cachedTickets = $cached['tickets'] ?? [];
|
||||
if (!is_array($cachedTickets)) {
|
||||
$cachedTickets = [];
|
||||
}
|
||||
$summary = DebitorDetailService::summarizeTickets($cachedTickets);
|
||||
Router::json($summary);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -43,13 +47,15 @@ $service = app(DebitorDetailService::class);
|
||||
$ticketsResult = $service->loadTickets($customerNo, $customerName);
|
||||
|
||||
if (!($ticketsResult['ok'] ?? false)) {
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode(['ok' => false, 'error' => $ticketsResult['error'] ?? 'Failed to load tickets']);
|
||||
Router::json(['ok' => false, 'error' => $ticketsResult['error'] ?? 'Failed to load tickets']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$tickets = $ticketsResult['tickets'] ?? [];
|
||||
if (!is_array($tickets)) {
|
||||
$tickets = [];
|
||||
}
|
||||
|
||||
$sessionStore->set($cacheKey, [
|
||||
'tickets' => $tickets,
|
||||
@@ -58,5 +64,4 @@ $sessionStore->set($cacheKey, [
|
||||
|
||||
$summary = DebitorDetailService::summarizeTickets($tickets);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($summary);
|
||||
Router::json($summary);
|
||||
|
||||
@@ -41,6 +41,7 @@ if ($ticket === null && !$connectionError) {
|
||||
$ticketCustomerNo = $fromCustomerNo;
|
||||
$ticketDescription = (string) ($ticket['Description'] ?? $ticketNo);
|
||||
$ticketLogUrl = lurl('helpdesk/ticket-log-data');
|
||||
$ticketCommunicationUrl = lurl('helpdesk/ticket-communication-data');
|
||||
|
||||
Buffer::set('title', $ticketDescription . ' — ' . t('Helpdesk'));
|
||||
Buffer::set('style_groups', json_encode(['helpdesk']));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* @var string $ticketCustomerNo
|
||||
* @var string $ticketDescription
|
||||
* @var string $ticketLogUrl
|
||||
* @var string $ticketCommunicationUrl
|
||||
*/
|
||||
|
||||
$ticketNo = $ticketNo ?? '';
|
||||
@@ -17,6 +18,7 @@ $connectionError = $connectionError ?? false;
|
||||
$ticketCustomerNo = $ticketCustomerNo ?? '';
|
||||
$ticketDescription = $ticketDescription ?? '';
|
||||
$ticketLogUrl = $ticketLogUrl ?? '';
|
||||
$ticketCommunicationUrl = $ticketCommunicationUrl ?? '';
|
||||
|
||||
$backUrl = $ticketCustomerNo !== '' ? lurl('helpdesk/debitor/' . rawurlencode($ticketCustomerNo)) : lurl('helpdesk/debitor');
|
||||
|
||||
@@ -24,6 +26,7 @@ $backUrl = $ticketCustomerNo !== '' ? lurl('helpdesk/debitor/' . rawurlencode($t
|
||||
<div class="app-details-container"
|
||||
data-ticket-no="<?php e($ticketNo); ?>"
|
||||
data-ticket-log-url="<?php e($ticketLogUrl); ?>"
|
||||
data-ticket-communication-url="<?php e($ticketCommunicationUrl); ?>"
|
||||
>
|
||||
<section>
|
||||
<?php
|
||||
@@ -127,14 +130,20 @@ $backUrl = $ticketCustomerNo !== '' ? lurl('helpdesk/debitor/' . rawurlencode($t
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activity timeline — loaded async -->
|
||||
<div class="grid">
|
||||
<!-- Activity timeline + communication feed — loaded async -->
|
||||
<div class="grid grid-2">
|
||||
<div class="app-stats-table">
|
||||
<div class="app-stats-table-header"><?php e(t('Activity timeline')); ?></div>
|
||||
<div id="ticket-timeline">
|
||||
<div id="timeline-loading" aria-busy="true"><?php e(t('Loading...')); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-stats-table">
|
||||
<div class="app-stats-table-header"><?php e(t('Communication history')); ?></div>
|
||||
<div id="ticket-communication">
|
||||
<div id="ticket-communication-loading" aria-busy="true"><?php e(t('Loading...')); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
@@ -147,10 +156,22 @@ $backUrl = $ticketCustomerNo !== '' ? lurl('helpdesk/debitor/' . rawurlencode($t
|
||||
'Activity' => t('Activity'),
|
||||
'No activity found.' => t('No activity found.'),
|
||||
'Could not load activity log.' => t('Could not load activity log.'),
|
||||
'Communication history' => t('Communication history'),
|
||||
'No communication found.' => t('No communication found.'),
|
||||
'Could not load communication history.' => t('Could not load communication history.'),
|
||||
'Live communication unavailable, showing activity fallback.' => t('Live communication unavailable, showing activity fallback.'),
|
||||
'Ticket' => t('Ticket'),
|
||||
'Unknown user' => t('Unknown user'),
|
||||
'Unknown time' => t('Unknown time'),
|
||||
'Source' => t('Source'),
|
||||
'SOAP' => t('SOAP'),
|
||||
'Activity fallback' => t('Activity fallback'),
|
||||
'sent a message' => t('sent a message'),
|
||||
'changed status' => t('changed status'),
|
||||
'Forwarded' => t('Forwarded'),
|
||||
'attached a file' => t('attached a file'),
|
||||
'logged an activity' => t('logged an activity'),
|
||||
'on' => t('on'),
|
||||
'Process' => t('Process'),
|
||||
'Loading...' => t('Loading...'),
|
||||
]); ?></script>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
use MintyPHP\Http\SessionStoreInterface;
|
||||
use MintyPHP\Module\Helpdesk\HelpdeskAuthorizationPolicy;
|
||||
use MintyPHP\Module\Helpdesk\Service\TicketCommunicationService;
|
||||
use MintyPHP\Router;
|
||||
use MintyPHP\Support\Guard;
|
||||
|
||||
Guard::requireLogin();
|
||||
Guard::requireAbilityOrForbidden(HelpdeskAuthorizationPolicy::ABILITY_ACCESS);
|
||||
|
||||
$request = requestInput();
|
||||
if ($request->method() !== 'GET') {
|
||||
http_response_code(405);
|
||||
Router::json(['ok' => false, 'error' => 'method_not_allowed']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$ticketNo = trim((string) $request->query('ticketNo', ''));
|
||||
if ($ticketNo === '') {
|
||||
http_response_code(400);
|
||||
Router::json(['ok' => false, 'error' => 'missing_parameters']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$sessionStore = app(SessionStoreInterface::class);
|
||||
$session = $sessionStore->all();
|
||||
$tenantId = (int) (($session['current_tenant']['id'] ?? 0));
|
||||
$tenantScope = $tenantId > 0 ? (string) $tenantId : 'global';
|
||||
$cacheKey = 'module.helpdesk.ticket_comm_cache.v2.' . $tenantScope . '.' . $ticketNo;
|
||||
$cacheTtl = 120;
|
||||
$cached = $sessionStore->get($cacheKey);
|
||||
|
||||
if (is_array($cached) && isset($cached['fetched_at']) && (time() - (int) $cached['fetched_at']) < $cacheTtl) {
|
||||
Router::json((array) ($cached['payload'] ?? ['ok' => false]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$service = app(TicketCommunicationService::class);
|
||||
$result = $service->loadTicketCommunicationFeed($ticketNo, 40);
|
||||
if (($result['ok'] ?? false) === true) {
|
||||
$sessionStore->set($cacheKey, [
|
||||
'payload' => $result,
|
||||
'fetched_at' => time(),
|
||||
]);
|
||||
}
|
||||
|
||||
Router::json($result);
|
||||
Reference in New Issue
Block a user