Replace bare <input type="file"> across all upload locations with a card-based dropzone component via shared partial. Three visual states: current server file (thumbnail + Replace/Delete), empty dropzone, and pending file preview (local FileReader thumbnail + metadata). Delete actions use data-confirm-message for confirmation dialog. Centralized as templates/partials/app-file-upload.phtml to prevent markup drift — documented as deliberate exception to plain-HTML inputs convention in CLAUDE.md and developer checklist. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
323 lines
12 KiB
PHTML
323 lines
12 KiB
PHTML
<?php
|
|
|
|
/**
|
|
* @var array<int, string> $errors
|
|
* @var array $form
|
|
* @var array $tenant
|
|
*/
|
|
|
|
use MintyPHP\Session;
|
|
|
|
$values = $form ?? $tenant ?? [];
|
|
$pageAuth = is_array($viewAuth['page'] ?? null) ? $viewAuth['page'] : [];
|
|
$canUpdateTenant = (bool) ($pageAuth['can_update_tenant'] ?? false);
|
|
$canDeleteTenant = (bool) ($pageAuth['can_delete_tenant'] ?? false);
|
|
$canManageCustomFields = (bool) ($pageAuth['can_manage_custom_fields'] ?? false);
|
|
$canManageSso = (bool) ($pageAuth['can_manage_sso'] ?? false);
|
|
$isReadOnly = !$canUpdateTenant;
|
|
$titleText = $isReadOnly ? t('View tenant') : t('Edit tenant');
|
|
$avatarUuid = (string) ($values['uuid'] ?? '');
|
|
$tenantAvatarService = app(\MintyPHP\Service\Tenant\TenantAvatarService::class);
|
|
$tenantFaviconService = app(\MintyPHP\Service\Tenant\TenantFaviconService::class);
|
|
$hasAvatar = $avatarUuid !== '' && $tenantAvatarService->hasAvatar($avatarUuid);
|
|
$hasFavicon = $avatarUuid !== '' && $tenantFaviconService->hasFavicon($avatarUuid);
|
|
|
|
?>
|
|
|
|
<div class="app-details-container">
|
|
<section>
|
|
<?php
|
|
$titlebar = [
|
|
'title' => $titleText,
|
|
'backHref' => 'admin/tenants',
|
|
'backTitle' => t('Cancel'),
|
|
'actions' => $canUpdateTenant ? [
|
|
[
|
|
'form' => 'tenant-form',
|
|
'name' => 'action',
|
|
'value' => 'save',
|
|
'class' => 'secondary outline',
|
|
'label' => t('Save'),
|
|
],
|
|
[
|
|
'form' => 'tenant-form',
|
|
'name' => 'action',
|
|
'value' => 'save_close',
|
|
'class' => 'primary',
|
|
'label' => t('Save & close'),
|
|
],
|
|
] : [],
|
|
];
|
|
require templatePath('partials/app-details-titlebar.phtml');
|
|
?>
|
|
<?php
|
|
$validationSummaryErrors = $validationSummaryErrors ?? ($errors ?? []);
|
|
require templatePath('partials/app-details-validation-summary.phtml');
|
|
?>
|
|
|
|
<?php
|
|
$detailsOpenAll = false;
|
|
$isReadOnly = $isReadOnly ?? false;
|
|
$showDangerZone = $canDeleteTenant;
|
|
$dangerZoneDeleteFormId = $showDangerZone ? 'tenant-delete-form' : '';
|
|
$dangerZoneWarning = t('This will permanently delete this tenant.');
|
|
$dangerZoneActionLabel = t('Delete tenant');
|
|
$showCustomFieldsTab = $canManageCustomFields;
|
|
$showSsoTab = $canManageSso;
|
|
$customFieldTenantUuid = (string) ($values['uuid'] ?? '');
|
|
$customFieldDefinitions = $customFieldDefinitions ?? [];
|
|
require __DIR__ . '/_form.phtml';
|
|
?>
|
|
<?php if ($showDangerZone): ?>
|
|
<form
|
|
id="tenant-delete-form"
|
|
method="post"
|
|
action="admin/tenants/delete/<?php e($values['uuid'] ?? ''); ?>"
|
|
hidden
|
|
data-detail-confirm-message="<?php e(t('Delete this tenant?')); ?>"
|
|
data-detail-action-kind="delete"
|
|
>
|
|
<?php Session::getCsrfInput(); ?>
|
|
</form>
|
|
<?php endif; ?>
|
|
</section>
|
|
<aside id="app-details-aside-section">
|
|
<div class="app-details-aside-section">
|
|
<div class="entity-avatar-block avatar-size-auto avatar-borderless">
|
|
<?php if ($hasAvatar): ?>
|
|
<a data-fslightbox="tenant-avatar" href="admin/tenants/avatar-file?uuid=<?php e($avatarUuid); ?>&size=256">
|
|
<img class="entity-avatar-image" src="admin/tenants/avatar-file?uuid=<?php e($avatarUuid); ?>&size=128"
|
|
alt="<?php e(t('Tenant image')); ?>">
|
|
</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
<hgroup>
|
|
<h2><?php e($values['description'] ?? ''); ?></h2>
|
|
<p><?php e(t('Tenant')); ?></p>
|
|
</hgroup>
|
|
<hr>
|
|
<?php if ($canUpdateTenant): ?>
|
|
<details name="tenant-avatar">
|
|
<summary>
|
|
<?php e(t('Upload image')); ?>
|
|
</summary>
|
|
<hr>
|
|
<form class="user-avatar-form" method="post" action="admin/tenants/avatar/<?php e($avatarUuid); ?>"
|
|
enctype="multipart/form-data">
|
|
<?php
|
|
$fileUpload = [
|
|
'name' => 'avatar',
|
|
'accept' => 'image/*',
|
|
'hint' => t('Allowed file types: SVG, PNG, JPG, WEBP'),
|
|
'currentSrc' => $hasAvatar ? 'admin/tenants/avatar-file?uuid=' . $avatarUuid . '&size=128' : '',
|
|
'deleteAction' => $hasAvatar ? 'admin/tenants/avatar-delete/' . $avatarUuid : '',
|
|
];
|
|
require templatePath('partials/app-file-upload.phtml');
|
|
?>
|
|
<button type="submit" class="app-action-success">
|
|
<?php e(t('Save')); ?>
|
|
</button>
|
|
<?php Session::getCsrfInput(); ?>
|
|
</form>
|
|
</details>
|
|
<?php endif; ?>
|
|
<hr>
|
|
<?php if ($canUpdateTenant): ?>
|
|
<details name="tenant-favicon">
|
|
<summary>
|
|
<?php e(t('Upload favicon')); ?>
|
|
</summary>
|
|
<hr>
|
|
<small><?php e(t('Square images are recommended (icons are center-cropped).')); ?></small>
|
|
<hr>
|
|
<form class="user-avatar-form" method="post" action="admin/tenants/favicon/<?php e($avatarUuid); ?>"
|
|
enctype="multipart/form-data">
|
|
<?php
|
|
$fileUpload = [
|
|
'name' => 'favicon',
|
|
'accept' => 'image/png',
|
|
'hint' => t('Allowed file types: PNG'),
|
|
'currentSrc' => $hasFavicon ? asset('favicon/tenants/' . $avatarUuid . '/favicon/favicon-32x32.png') : '',
|
|
'currentLabel' => t('Favicon'),
|
|
'deleteAction' => $hasFavicon ? 'admin/tenants/favicon-delete/' . $avatarUuid : '',
|
|
];
|
|
require templatePath('partials/app-file-upload.phtml');
|
|
?>
|
|
<button type="submit" class="app-action-success">
|
|
<?php e(t('Save')); ?>
|
|
</button>
|
|
<?php Session::getCsrfInput(); ?>
|
|
</form>
|
|
</details>
|
|
<?php endif; ?>
|
|
<hr>
|
|
<?php
|
|
$phone = trim((string) ($values['phone'] ?? ''));
|
|
$fax = trim((string) ($values['fax'] ?? ''));
|
|
$email = trim((string) ($values['email'] ?? ''));
|
|
$supportEmail = trim((string) ($values['support_email'] ?? ''));
|
|
$supportPhone = trim((string) ($values['support_phone'] ?? ''));
|
|
$billingEmail = trim((string) ($values['billing_email'] ?? ''));
|
|
$website = trim((string) ($values['website'] ?? ''));
|
|
$privacyUrl = trim((string) ($values['privacy_url'] ?? ''));
|
|
$imprintUrl = trim((string) ($values['imprint_url'] ?? ''));
|
|
$statusValue = (string) ($values['status'] ?? 'active');
|
|
?>
|
|
<details name="tenant-contact">
|
|
<summary><?php e(t('Contact')); ?></summary>
|
|
<hr>
|
|
<?php if ($supportEmail !== '' || $supportPhone !== '' || $billingEmail !== '' || $email !== '' || $phone !== '' || $fax !== '' || $website !== ''): ?>
|
|
<?php if ($supportEmail !== ''): ?>
|
|
<div>
|
|
<small><?php e(t('Support email')); ?></small>
|
|
<p><a href="mailto:<?php e($supportEmail); ?>"><?php e($supportEmail); ?></a></p>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($supportPhone !== ''): ?>
|
|
<div>
|
|
<small><?php e(t('Support phone')); ?></small>
|
|
<p><a href="tel:<?php e($supportPhone); ?>"><?php e($supportPhone); ?></a></p>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($billingEmail !== ''): ?>
|
|
<div>
|
|
<small><?php e(t('Billing email')); ?></small>
|
|
<p><a href="mailto:<?php e($billingEmail); ?>"><?php e($billingEmail); ?></a></p>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($email !== ''): ?>
|
|
<div>
|
|
<small><?php e(t('Email')); ?></small>
|
|
<p><a href="mailto:<?php e($email); ?>"><?php e($email); ?></a></p>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($phone !== ''): ?>
|
|
<div>
|
|
<small><?php e(t('Phone')); ?></small>
|
|
<p><a href="tel:<?php e($phone); ?>"><?php e($phone); ?></a></p>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($fax !== ''): ?>
|
|
<div>
|
|
<small><?php e(t('Fax')); ?></small>
|
|
<div><?php e($fax); ?></div>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($website !== ''): ?>
|
|
<div>
|
|
<small><?php e(t('Website')); ?></small>
|
|
<div>
|
|
<a href="<?php e($website); ?>" target="_blank" rel="noopener noreferrer">
|
|
<?php e($website); ?>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php else: ?>
|
|
<?php
|
|
$emptyState = [
|
|
'message' => t('No contact details available'),
|
|
'size' => 'small',
|
|
'align' => 'left',
|
|
'icon' => false,
|
|
];
|
|
require templatePath('partials/app-empty-state.phtml');
|
|
?>
|
|
<?php endif; ?>
|
|
</details>
|
|
<hr>
|
|
<details name="tenant-legal">
|
|
<summary><?php e(t('Legal')); ?></summary>
|
|
<hr>
|
|
<?php if ($privacyUrl !== '' || $imprintUrl !== ''): ?>
|
|
<?php if ($privacyUrl !== ''): ?>
|
|
<div>
|
|
<small><?php e(t('Privacy URL')); ?></small>
|
|
<p>
|
|
<a href="<?php e($privacyUrl); ?>" target="_blank" rel="noopener noreferrer">
|
|
<?php e($privacyUrl); ?>
|
|
</a>
|
|
</p>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($imprintUrl !== ''): ?>
|
|
<div>
|
|
<small><?php e(t('Imprint URL')); ?></small>
|
|
<p>
|
|
<a href="<?php e($imprintUrl); ?>" target="_blank" rel="noopener noreferrer">
|
|
<?php e($imprintUrl); ?>
|
|
</a>
|
|
</p>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php else: ?>
|
|
<?php
|
|
$emptyState = [
|
|
'message' => t('No legal links configured'),
|
|
'size' => 'small',
|
|
'align' => 'left',
|
|
'icon' => false,
|
|
];
|
|
require templatePath('partials/app-empty-state.phtml');
|
|
?>
|
|
<?php endif; ?>
|
|
</details>
|
|
<hr>
|
|
<?php
|
|
$statusChangedByLabel = $values['status_changed_by_label'] ?? '';
|
|
$statusChangedById = $values['status_changed_by'] ?? null;
|
|
$statusChangedByUuid = $values['status_changed_by_uuid'] ?? null;
|
|
?>
|
|
<details name="tenant-status">
|
|
<summary><?php e(t('Status')); ?></summary>
|
|
<hr>
|
|
<div>
|
|
<small><?php e(t('Status')); ?></small>
|
|
<p><?php e($statusValue !== '' ? t(ucfirst($statusValue)) : '-'); ?></p>
|
|
</div>
|
|
<div>
|
|
<small><?php e(t('Status changed')); ?></small>
|
|
<p><?php e(dt($values['status_changed_at'] ?? '') ?: '-'); ?></p>
|
|
</div>
|
|
<div>
|
|
<small><?php e(t('Status changed by')); ?></small>
|
|
<p>
|
|
<?php if ($statusChangedByLabel !== ''): ?>
|
|
<?php if ($statusChangedByUuid): ?>
|
|
<a href="admin/users/edit/<?php e($statusChangedByUuid); ?>"><?php e($statusChangedByLabel); ?></a>
|
|
<?php else: ?>
|
|
<?php e($statusChangedByLabel); ?>
|
|
<?php endif; ?>
|
|
<?php elseif ($statusChangedById): ?>
|
|
<?php e('#' . $statusChangedById); ?>
|
|
<?php else: ?>
|
|
-
|
|
<?php endif; ?>
|
|
</p>
|
|
</div>
|
|
</details>
|
|
<hr>
|
|
<?php
|
|
$asideAuditDetailsName = 'tenant-audit';
|
|
$asideAuditCreated = (string) ($values['created'] ?? '');
|
|
$asideAuditCreatedByLabel = (string) ($values['created_by_label'] ?? '');
|
|
$asideAuditCreatedById = $values['created_by'] ?? null;
|
|
$asideAuditCreatedByUuid = (string) ($values['created_by_uuid'] ?? '');
|
|
$asideAuditModified = (string) ($values['modified'] ?? '');
|
|
$asideAuditModifiedByLabel = (string) ($values['modified_by_label'] ?? '');
|
|
$asideAuditModifiedById = $values['modified_by'] ?? null;
|
|
$asideAuditModifiedByUuid = (string) ($values['modified_by_uuid'] ?? '');
|
|
require templatePath('partials/app-details-aside-audit.phtml');
|
|
?>
|
|
<hr>
|
|
<?php
|
|
$asideIdsDetailsName = 'tenant-ids';
|
|
$asideIdsUuidFirst = true;
|
|
$asideIdValue = $values['id'] ?? '';
|
|
$asideUuidValue = (string) ($values['uuid'] ?? '');
|
|
require templatePath('partials/app-details-aside-ids.phtml');
|
|
?>
|
|
</div>
|
|
</aside>
|
|
</div>
|