forked from fa/breadcrumb-the-shire
Move breadcrumb rendering from individual page templates into the core topbar. Each page now sets $breadcrumbs in its action .php file; the topbar renders it automatically via the shared partial. - Remove global back/forward buttons and app-nav-history.js component - Remove Alt+Arrow keyboard shortcuts for history navigation - Render breadcrumb in topbar-left section (replaces button area) - Clean up breadcrumb CSS: context-neutral base (flex, no margin) - Recalculate sticky titlebar offset in details container - Migrate all 41 pages (core + helpdesk, audit, addressbook, api-docs) - Add missing breadcrumbs to addressbook detail view - Update architecture contract tests (nav-history references removed) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
160 lines
6.8 KiB
PHTML
160 lines
6.8 KiB
PHTML
<?php
|
|
|
|
/**
|
|
* @var string $ticketNo
|
|
* @var string $fromCustomerNo
|
|
* @var array|null $ticket
|
|
* @var bool $connectionError
|
|
* @var string $ticketCustomerNo
|
|
* @var string $ticketDescription
|
|
* @var string $ticketCommunicationUrl
|
|
*/
|
|
|
|
$ticketNo = $ticketNo ?? '';
|
|
$fromCustomerNo = $fromCustomerNo ?? '';
|
|
$ticket = is_array($ticket ?? null) ? $ticket : null;
|
|
$connectionError = $connectionError ?? false;
|
|
$ticketCustomerNo = $ticketCustomerNo ?? '';
|
|
$ticketDescription = $ticketDescription ?? '';
|
|
$ticketCommunicationUrl = $ticketCommunicationUrl ?? '';
|
|
|
|
$backUrl = $ticketCustomerNo !== '' ? lurl('helpdesk/debitor/' . rawurlencode($ticketCustomerNo)) : lurl('helpdesk');
|
|
|
|
?>
|
|
<div class="app-details-container"
|
|
data-ticket-no="<?php e($ticketNo); ?>"
|
|
data-ticket-communication-url="<?php e($ticketCommunicationUrl); ?>"
|
|
>
|
|
<section>
|
|
<?php
|
|
$titlebar = [
|
|
'title' => t('Ticket') . ' ' . $ticketNo,
|
|
'backHref' => $backUrl,
|
|
'backTitle' => t('Back'),
|
|
'actions' => [],
|
|
];
|
|
require templatePath('partials/app-details-titlebar.phtml');
|
|
?>
|
|
|
|
<?php require templatePath('partials/app-flash.phtml'); ?>
|
|
|
|
<?php if ($connectionError): ?>
|
|
<div class="notice" data-variant="error" role="alert">
|
|
<?php e(t('Could not connect to Business Central.')); ?>
|
|
</div>
|
|
<?php elseif ($ticket !== null): ?>
|
|
<!-- Communication feed — main content, loaded async -->
|
|
<div class="helpdesk-ticket-detail-content">
|
|
<section>
|
|
<h3 class="helpdesk-support-section-title"><?php e(t('Ticket communication')); ?></h3>
|
|
<div id="ticket-communication-loading">
|
|
<?php for ($i = 0; $i < 6; $i++): ?>
|
|
<div class="helpdesk-skeleton helpdesk-skeleton-aside-bubble <?php e($i % 2 === 1 ? 'helpdesk-skeleton-aside-bubble-alt' : ($i % 3 === 0 ? 'helpdesk-skeleton-aside-bubble-short' : '')); ?>"></div>
|
|
<?php endfor; ?>
|
|
</div>
|
|
<div id="ticket-communication-content" hidden>
|
|
<div id="ticket-communication-feed"></div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
<?php endif; ?>
|
|
</section>
|
|
|
|
<?php if (!$connectionError && $ticket !== null): ?>
|
|
<?php
|
|
$createdRaw = (string) ($ticket['Created_On'] ?? '');
|
|
$createdFormatted = $createdRaw !== '' && $createdRaw !== '0001-01-01T00:00:00Z'
|
|
? (new DateTimeImmutable($createdRaw))->format('d.m.Y H:i')
|
|
: '—';
|
|
$lastActivityRaw = (string) ($ticket['Last_Activity_Date'] ?? '');
|
|
$lastActivityFormatted = $lastActivityRaw !== '' && $lastActivityRaw !== '0001-01-01T00:00:00Z'
|
|
? (new DateTimeImmutable($lastActivityRaw))->format('d.m.Y H:i')
|
|
: '—';
|
|
$ticketState = (string) ($ticket['Ticket_State'] ?? '');
|
|
|
|
// Compute ticket age
|
|
$ageLabel = '—';
|
|
if ($createdRaw !== '' && $createdRaw !== '0001-01-01T00:00:00Z') {
|
|
$createdDt = new DateTimeImmutable($createdRaw);
|
|
$diff = $createdDt->diff(new DateTimeImmutable('now'));
|
|
if ($diff->days >= 1) {
|
|
$ageLabel = $diff->days . ' ' . ($diff->days === 1 ? t('day') : t('days'));
|
|
} else {
|
|
$hours = $diff->h + ($diff->days * 24);
|
|
$ageLabel = max(1, $hours) . ' ' . t('hours');
|
|
}
|
|
}
|
|
?>
|
|
<aside id="app-details-aside-section">
|
|
<div class="app-details-aside-section helpdesk-ticket-aside">
|
|
<!-- KPI tiles: Status + Age — stacked vertically -->
|
|
<h3 class="helpdesk-support-section-title"><?php e(t('Ticket details')); ?></h3>
|
|
<div class="helpdesk-support-metrics helpdesk-support-metrics-aside">
|
|
<article class="helpdesk-support-metric">
|
|
<p class="helpdesk-support-metric-label"><?php e(t('Status')); ?></p>
|
|
<p class="helpdesk-support-metric-value"><?php e($ticketState); ?></p>
|
|
<p class="helpdesk-support-metric-trend"><?php e(t('Last activity')); ?>: <?php e($lastActivityFormatted); ?></p>
|
|
</article>
|
|
<article class="helpdesk-support-metric">
|
|
<p class="helpdesk-support-metric-label"><?php e(t('Age')); ?></p>
|
|
<p class="helpdesk-support-metric-value"><?php e($ageLabel); ?></p>
|
|
<p class="helpdesk-support-metric-trend"><?php e(t('Created')); ?>: <?php e($createdFormatted); ?></p>
|
|
</article>
|
|
</div>
|
|
|
|
<!-- Compact key-value details -->
|
|
<h3 class="helpdesk-support-section-title"><?php e(t('Details')); ?></h3>
|
|
<dl class="helpdesk-ticket-meta">
|
|
<div class="helpdesk-ticket-meta-item">
|
|
<dt><?php e(t('Description')); ?></dt>
|
|
<dd><?php e((string) ($ticket['Description'] ?? '—')); ?></dd>
|
|
</div>
|
|
<div class="helpdesk-ticket-meta-item">
|
|
<dt><?php e(t('Company')); ?></dt>
|
|
<dd>
|
|
<?php if ($ticketCustomerNo !== ''): ?>
|
|
<a href="<?php e(lurl('helpdesk/debitor/' . rawurlencode($ticketCustomerNo))); ?>"><?php e((string) ($ticket['Company_Contact_Name'] ?? $ticketCustomerNo)); ?></a>
|
|
<?php else: ?>
|
|
<?php e((string) ($ticket['Company_Contact_Name'] ?? '—')); ?>
|
|
<?php endif; ?>
|
|
</dd>
|
|
</div>
|
|
<div class="helpdesk-ticket-meta-item">
|
|
<dt><?php e(t('Contact')); ?></dt>
|
|
<dd><?php e((string) ($ticket['Current_Contact_Name'] ?? '—')); ?></dd>
|
|
</div>
|
|
<div class="helpdesk-ticket-meta-item">
|
|
<dt><?php e(t('Category')); ?></dt>
|
|
<dd><?php e((string) ($ticket['Category_1_Description'] ?? '—')); ?></dd>
|
|
</div>
|
|
<div class="helpdesk-ticket-meta-item">
|
|
<dt><?php e(t('Support')); ?></dt>
|
|
<dd><?php e((string) ($ticket['Support_User_Name'] ?? '—')); ?></dd>
|
|
</div>
|
|
<div class="helpdesk-ticket-meta-item">
|
|
<dt><?php e(t('Debtor No.')); ?></dt>
|
|
<dd><?php e($ticketCustomerNo !== '' ? $ticketCustomerNo : '—'); ?></dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
</aside>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- i18n strings for JS rendering -->
|
|
<script type="application/json" id="helpdesk-ticket-i18n"><?php gridJsonForJs([
|
|
'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'),
|
|
'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'),
|
|
]); ?></script>
|
|
|
|
<script type="module" src="<?php e(assetVersion('modules/helpdesk/js/helpdesk-ticket.js')); ?>"></script>
|