feat(helpdesk): redesign handover edit page sidebar

- JOIN users table in findById for created/updated-by display names
- Fix row mapping to handle merged JOIN results
- Use product name instead of debitor name in page title
- Sidebar: collapsible customer/product sections, status dropdown,
  audit partial with user attribution

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-15 21:29:36 +02:00
parent 2600e62a73
commit 9a49e18e27
3 changed files with 73 additions and 33 deletions

View File

@@ -41,7 +41,13 @@ class HandoverRepository
} }
$row = DB::selectOne( $row = DB::selectOne(
'SELECT * FROM helpdesk_handovers WHERE id = ? AND tenant_id = ? LIMIT 1', 'SELECT h.*,'
. ' uc.display_name AS created_by_label, uc.uuid AS created_by_uuid,'
. ' uu.display_name AS updated_by_label, uu.uuid AS updated_by_uuid'
. ' FROM helpdesk_handovers h'
. ' LEFT JOIN users uc ON uc.id = h.created_by'
. ' LEFT JOIN users uu ON uu.id = h.updated_by'
. ' WHERE h.id = ? AND h.tenant_id = ? LIMIT 1',
(string) $id, (string) $id,
(string) $tenantId (string) $tenantId
); );
@@ -140,8 +146,18 @@ class HandoverRepository
if (!is_array($row)) { if (!is_array($row)) {
return null; return null;
} }
$item = $row['helpdesk_handovers'] ?? $row;
if (!is_array($item) || !isset($item['id'])) { // JOIN queries return nested arrays keyed by table name — merge all sub-arrays
$item = [];
foreach ($row as $key => $value) {
if (is_array($value)) {
$item = array_merge($item, $value);
} else {
$item[$key] = $value;
}
}
if (!isset($item['id'])) {
return null; return null;
} }

View File

@@ -111,8 +111,12 @@ if ($request->isMethod('POST') && $canEdit) {
$validationSummaryErrors = $errorBag->toArray(); $validationSummaryErrors = $errorBag->toArray();
$errors = $errorBag->toFlatList(); $errors = $errorBag->toFlatList();
$displayName = trim((string) ($handover['debitor_name'] ?? '')); $productCode = (string) ($handover['product_code'] ?? '');
$titleText = $displayName !== '' ? $displayName : (t('Handover') . ' #' . $handoverId); $product = app(\MintyPHP\Module\Helpdesk\Service\SoftwareProductService::class)->findByCode($productCode);
$productName = trim((string) ($product['name'] ?? '')) !== ''
? $product['name']
: (trim((string) ($product['bc_description'] ?? '')) !== '' ? $product['bc_description'] : $productCode);
$titleText = t('Handover') . ' ' . $productName;
Buffer::set('title', $titleText); Buffer::set('title', $titleText);
Buffer::set('style_groups', json_encode(['helpdesk'])); Buffer::set('style_groups', json_encode(['helpdesk']));
$breadcrumbs = [ $breadcrumbs = [

View File

@@ -58,10 +58,6 @@ $readonly = !$canEdit;
</div> </div>
</div> </div>
<?php if ($allowedStatuses && count($allowedStatuses) > 1): ?>
<input type="hidden" name="status" value="<?php e($currentStatus); ?>">
<?php endif; ?>
<?php \MintyPHP\Session::getCsrfInput(); ?> <?php \MintyPHP\Session::getCsrfInput(); ?>
</form> </form>
<?php else: ?> <?php else: ?>
@@ -80,8 +76,8 @@ $readonly = !$canEdit;
<aside id="app-details-aside-section"> <aside id="app-details-aside-section">
<div class="app-details-aside-section"> <div class="app-details-aside-section">
<hgroup> <hgroup>
<h2><?php e(t('Handover')); ?> #<?php e($handover['id'] ?? ''); ?></h2> <h2>#<?php e($handover['id'] ?? ''); ?></h2>
<p><?php e($handover['product_code'] ?? ''); ?></p> <p><?php e(t('Handover')); ?></p>
</hgroup> </hgroup>
<div class="badge-list"> <div class="badge-list">
@@ -92,35 +88,59 @@ $readonly = !$canEdit;
<?php if ($canEdit && $allowedStatuses && count($allowedStatuses) > 1): ?> <?php if ($canEdit && $allowedStatuses && count($allowedStatuses) > 1): ?>
<hr> <hr>
<p><small><?php e(t('Change status')); ?></small></p> <label for="handover-status"><small><?php e(t('Status')); ?></small></label>
<div class="helpdesk-handover-status-actions"> <select id="handover-status" name="status" form="<?php e($formId); ?>">
<?php foreach ($allowedStatuses as $status): <?php foreach ($allowedStatuses as $status): ?>
if ($status === $currentStatus) { <option value="<?php e($status); ?>"<?php if ($status === $currentStatus): ?> selected<?php endif; ?>>
continue;
}
?>
<button
type="button"
class="secondary outline small"
onclick="document.querySelector('input[name=status]').value='<?php e($status); ?>';document.getElementById('<?php e($formId); ?>').requestSubmit();"
>
<?php e(HandoverService::statusLabel($status)); ?> <?php e(HandoverService::statusLabel($status)); ?>
</button> </option>
<?php endforeach; ?> <?php endforeach; ?>
</div> </select>
<?php endif; ?> <?php endif; ?>
<?php
$debitorNo = trim((string) ($handover['debitor_no'] ?? ''));
$debitorName = trim((string) ($handover['debitor_name'] ?? ''));
?>
<details name="handover-aside" open>
<summary><?php e(t('Customer')); ?></summary>
<hr>
<p>
<?php if ($debitorNo !== ''): ?>
<a href="<?php e(lurl('helpdesk/debitor/' . rawurlencode($debitorNo))); ?>"><?php e($debitorName !== '' ? $debitorName : $debitorNo); ?></a>
<?php else: ?>
<?php e($debitorName); ?>
<?php endif; ?>
</p>
<?php if ($debitorNo !== '' && $debitorName !== ''): ?>
<p><small><?php e(t('Debitor No.')); ?></small><br><?php e($debitorNo); ?></p>
<?php endif; ?>
</details>
<hr> <hr>
<p><small><?php e(t('Customer')); ?></small><br><?php e($handover['debitor_name'] ?? ''); ?></p>
<p><small><?php e(t('Debitor No.')); ?></small><br><?php e($handover['debitor_no'] ?? ''); ?></p>
<details name="handover-aside" open>
<summary><?php e(t('Software product')); ?></summary>
<hr>
<p><?php e($productName ?? ($handover['product_code'] ?? '')); ?></p>
<?php if (($productName ?? '') !== ($handover['product_code'] ?? '')): ?>
<p><small><?php e(t('Code')); ?></small><br><span class="badge" data-variant="neutral"><?php e($handover['product_code'] ?? ''); ?></span></p>
<?php endif; ?>
</details>
<hr> <hr>
<?php if (!empty($handover['created_at'])): ?>
<p><small><?php e(t('Created')); ?></small><br><?php e(dt($handover['created_at'])); ?></p> <?php
<?php endif; ?> $asideAuditDetailsName = 'handover-aside';
<?php if (!empty($handover['updated_at'])): ?> $asideAuditOpen = false;
<p><small><?php e(t('Modified')); ?></small><br><?php e(dt($handover['updated_at'])); ?></p> $asideAuditCreated = (string) ($handover['created_at'] ?? '');
<?php endif; ?> $asideAuditCreatedByLabel = (string) ($handover['created_by_label'] ?? '');
$asideAuditCreatedById = $handover['created_by'] ?? null;
$asideAuditCreatedByUuid = (string) ($handover['created_by_uuid'] ?? '');
$asideAuditModified = (string) ($handover['updated_at'] ?? '');
$asideAuditModifiedByLabel = (string) ($handover['updated_by_label'] ?? '');
$asideAuditModifiedById = $handover['updated_by'] ?? null;
$asideAuditModifiedByUuid = (string) ($handover['updated_by_uuid'] ?? '');
require templatePath('partials/app-details-aside-audit.phtml');
?>
<hr> <hr>
</div> </div>
</aside> </aside>