forked from fa/breadcrumb-the-shire
- New statuses: under_review - New DB fields: assigned_to, assigned_by, assigned_at, due_date (migration 012) - HandoverNotificationService: emails on assign and review-request - HandoverService: assign(), submitForReview(), resendNotification() - Assign page: manager selects employee + due date, resend notification - Create wizard: manager can assign during creation (step 1) - Edit page: "Submit for review" button for assignee, assign link for manager - List page: open/closed tabs, non-managers see only their assigned handovers - Email templates: handover_assigned + handover_review_requested (de/en) - i18n keys added for de and en Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
172 lines
8.2 KiB
PHTML
172 lines
8.2 KiB
PHTML
<?php
|
|
$step = $step ?? 1;
|
|
$closeTarget = $closeTarget ?? 'helpdesk/handovers';
|
|
$createTarget = $createTarget ?? 'helpdesk/handovers/create';
|
|
$form = is_array($form ?? null) ? $form : [];
|
|
$errors = is_array($errors ?? null) ? $errors : [];
|
|
$validationSummaryErrors = is_array($validationSummaryErrors ?? null) ? $validationSummaryErrors : [];
|
|
$productsWithSchema = is_array($productsWithSchema ?? null) ? $productsWithSchema : [];
|
|
$schemaFields = is_array($schemaFields ?? null) ? $schemaFields : [];
|
|
$fieldValues = is_array($fieldValues ?? null) ? $fieldValues : [];
|
|
$wizardData = is_array($wizardData ?? null) ? $wizardData : [];
|
|
$productDisplayName = $productDisplayName ?? '';
|
|
|
|
$steps = [
|
|
['label' => t('Customer & product'), 'number' => 1],
|
|
['label' => t('Protocol'), 'number' => 2],
|
|
];
|
|
$canManage = $canManage ?? false;
|
|
$tenantUsers = is_array($tenantUsers ?? null) ? $tenantUsers : [];
|
|
?>
|
|
<div class="app-wizard-content">
|
|
<div class="app-wizard-header">
|
|
<a href="<?php e(lurl($closeTarget)); ?>" class="app-wizard-back" data-tooltip="<?php e(t('Back to list')); ?>">
|
|
<i class="bi bi-arrow-left"></i>
|
|
</a>
|
|
<h1 class="app-wizard-title"><?php e(t('New handover')); ?></h1>
|
|
</div>
|
|
|
|
<!-- Step indicator -->
|
|
<nav class="app-wizard-steps" aria-label="<?php e(t('Progress')); ?>">
|
|
<?php foreach ($steps as $s): ?>
|
|
<div class="app-wizard-step<?php if ($s['number'] === $step): ?> is-active<?php elseif ($s['number'] < $step): ?> is-completed<?php endif; ?>"
|
|
<?php if ($s['number'] === $step): ?>aria-current="step"<?php endif; ?>>
|
|
<span class="app-wizard-step-number"><?php e($s['number']); ?></span>
|
|
<span class="app-wizard-step-label"><?php e($s['label']); ?></span>
|
|
</div>
|
|
<?php if ($s['number'] < count($steps)): ?>
|
|
<div class="app-wizard-step-connector<?php if ($s['number'] < $step): ?> is-completed<?php endif; ?>" aria-hidden="true"></div>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
</nav>
|
|
|
|
<?php if ($validationSummaryErrors): ?>
|
|
<?php require templatePath('partials/app-details-validation-summary.phtml'); ?>
|
|
<?php endif; ?>
|
|
|
|
<!-- Step 1: Customer & Product -->
|
|
<?php if ($step === 1): ?>
|
|
<div class="app-wizard-card">
|
|
<form method="post" id="wizard-step-1">
|
|
<h2 class="app-wizard-card-heading"><?php e(t('Select customer and product')); ?></h2>
|
|
<p class="app-wizard-card-description"><?php e(t('Choose the customer and software product for this handover protocol.')); ?></p>
|
|
|
|
<div class="app-wizard-field-group">
|
|
<label><?php e(t('Customer')); ?> <span class="handover-form-required">*</span></label>
|
|
<div
|
|
data-app-lookup
|
|
data-lookup-url="<?php e(lurl('helpdesk/debitor-lookup-data')); ?>"
|
|
data-lookup-min-chars="2"
|
|
data-lookup-debounce="300"
|
|
data-lookup-value-key="value"
|
|
data-lookup-display-key="label"
|
|
data-lookup-placeholder="<?php e(t('Search by name or number...')); ?>"
|
|
data-lookup-empty-text="<?php e(t('No customers found')); ?>"
|
|
data-lookup-error-text="<?php e(t('Search failed')); ?>"
|
|
data-lookup-initial-value="<?php e($form['debitor_no'] ?? ''); ?>"
|
|
data-lookup-initial-display="<?php e($form['debitor_name'] ?? ''); ?>"
|
|
>
|
|
<input type="hidden" name="debitor_no" data-lookup-value value="<?php e($form['debitor_no'] ?? ''); ?>">
|
|
<input type="hidden" name="debitor_name" data-lookup-display-value value="<?php e($form['debitor_name'] ?? ''); ?>">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="app-wizard-field-group" id="wizard-domain-group" data-app-component="helpdesk-handover-domain-select"
|
|
data-domains-url="<?php e(lurl('helpdesk/handover-domains-data')); ?>"
|
|
data-text-initial="<?php e(t('Select a customer first...')); ?>"
|
|
data-text-loading="<?php e(t('Loading domains...')); ?>"
|
|
data-text-select="<?php e(t('Please select...')); ?>"
|
|
data-text-empty="<?php e(t('No domains found for this customer')); ?>"
|
|
data-text-error="<?php e(t('Failed to load domains')); ?>"
|
|
data-initial-debitor="<?php e($form['debitor_no'] ?? ''); ?>"
|
|
data-initial-domain="<?php e($form['domain_no'] ?? ''); ?>"
|
|
>
|
|
<label for="wizard-domain"><?php e(t('Domain')); ?> <span class="handover-form-required">*</span></label>
|
|
<select id="wizard-domain" name="domain_no" disabled>
|
|
<option value=""><?php e(t('Select a customer first...')); ?></option>
|
|
</select>
|
|
<input type="hidden" name="domain_url" id="wizard-domain-url" value="<?php e($form['domain_url'] ?? ''); ?>">
|
|
<div id="wizard-domain-feedback" class="app-wizard-field-feedback" role="alert" hidden></div>
|
|
</div>
|
|
|
|
<div class="app-wizard-field-group">
|
|
<label for="wizard-product-code"><?php e(t('Software product')); ?> <span class="handover-form-required">*</span></label>
|
|
<?php if ($productsWithSchema === []): ?>
|
|
<div class="notice" data-variant="info" role="alert">
|
|
<p><?php e(t('No software products with handover protocol schemas found.')); ?></p>
|
|
</div>
|
|
<?php else: ?>
|
|
<select id="wizard-product-code" name="product_code">
|
|
<option value=""><?php e(t('Please select...')); ?></option>
|
|
<?php foreach ($productsWithSchema as $p):
|
|
$code = (string) ($p['code'] ?? '');
|
|
$name = trim((string) ($p['name'] ?? ''));
|
|
$desc = (string) ($p['bc_description'] ?? '');
|
|
$displayLabel = $name !== '' ? $name : ($desc !== '' ? $desc : $code);
|
|
?>
|
|
<option value="<?php e($code); ?>"<?php if (($form['product_code'] ?? '') === $code): ?> selected<?php endif; ?>>
|
|
<?php e($displayLabel); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<?php if ($canManage && $tenantUsers !== []): ?>
|
|
<div class="app-wizard-field-group">
|
|
<label for="wizard-assigned-to"><?php e(t('Assign to (optional)')); ?></label>
|
|
<select id="wizard-assigned-to" name="assigned_to">
|
|
<option value="0"><?php e(t('— Not assigned yet —')); ?></option>
|
|
<?php foreach ($tenantUsers as $u): ?>
|
|
<option value="<?php e($u['id']); ?>"<?php if ((int) ($form['assigned_to'] ?? 0) === (int) $u['id']): ?> selected<?php endif; ?>>
|
|
<?php e($u['display_name'] ?: $u['email']); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="app-wizard-field-group" id="wizard-due-date-group">
|
|
<label for="wizard-due-date"><?php e(t('Due date (optional)')); ?></label>
|
|
<input
|
|
type="date"
|
|
id="wizard-due-date"
|
|
name="due_date"
|
|
value="<?php e($form['due_date'] ?? ''); ?>"
|
|
>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php \MintyPHP\Session::getCsrfInput(); ?>
|
|
|
|
<div class="app-wizard-actions">
|
|
<a href="<?php e(lurl($closeTarget)); ?>" role="button" class="outline secondary"><?php e(t('Cancel')); ?></a>
|
|
<button type="submit" class="primary"><?php e(t('Continue')); ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Step 2: Fill protocol -->
|
|
<?php elseif ($step === 2): ?>
|
|
<div class="app-wizard-card">
|
|
<form method="post" id="wizard-step-2">
|
|
<h2 class="app-wizard-card-heading"><?php e(t('Fill handover protocol')); ?></h2>
|
|
<p class="app-wizard-card-description">
|
|
<?php e($wizardData['debitor_name'] ?? ''); ?> — <?php e($productDisplayName); ?>
|
|
</p>
|
|
|
|
<?php
|
|
$readonly = false;
|
|
require __DIR__ . '/_form.phtml';
|
|
?>
|
|
|
|
<?php \MintyPHP\Session::getCsrfInput(); ?>
|
|
|
|
<div class="app-wizard-actions">
|
|
<a href="<?php e(lurl($createTarget)); ?>" role="button" class="outline secondary"><?php e(t('Back')); ?></a>
|
|
<button type="submit" class="primary"><?php e(t('Create handover')); ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|