Files
breadcrumb-the-shire/pages/admin/users/_form.phtml
2026-02-11 19:28:12 +01:00

481 lines
20 KiB
PHTML

<?php
/**
* @var array $values
* @var bool $passwordRequired
* @var string|null $passwordLabel
* @var string|null $passwordLegend
* @var string|null $passwordConfirmLabel
* @var string|null $formId
* @var bool $detailsOpenAll
* @var bool $showTenants
* @var array $tenants
* @var array $selectedTenantIds
* @var bool $showRoles
* @var array $roles
* @var array $selectedRoleIds
* @var bool $showDepartments
* @var array $departments
* @var array $selectedDepartmentIds
* @var bool $isReadOnly
* @var bool $showPermissions
* @var array $permissionRows
* @var bool $showPasswordResets
* @var array $passwordResets
* @var bool $showRememberTokens
* @var array $rememberTokens
*/
use MintyPHP\Session;
use MintyPHP\Service\User\UserService;
use MintyPHP\I18n;
$values = $values ?? [];
$isOwnAccount = (int) ($_SESSION['user']['id'] ?? 0) === (int) ($values['id'] ?? 0);
$passwordRequired = $passwordRequired ?? false;
$passwordLabel = $passwordLabel ?? t('Password');
$passwordLegend = $passwordLegend ?? t('Password');
$passwordConfirmLabel = $passwordConfirmLabel ?? t('Password (again)');
$formId = $formId ?? 'user-form';
$detailsOpenAll = $detailsOpenAll ?? false;
$showTenants = $showTenants ?? false;
$tenants = $tenants ?? [];
$selectedTenantIds = $selectedTenantIds ?? [];
$showRoles = $showRoles ?? false;
$roles = $roles ?? [];
$selectedRoleIds = $selectedRoleIds ?? [];
$showDepartments = $showDepartments ?? false;
$departments = $departments ?? [];
$selectedDepartmentIds = $selectedDepartmentIds ?? [];
$primaryTenantId = (int) ($values['primary_tenant_id'] ?? 0);
if (!$primaryTenantId && count($selectedTenantIds) === 1) {
$primaryTenantId = (int) $selectedTenantIds[0];
}
$isReadOnly = $isReadOnly ?? false;
$permissionRows = $permissionRows ?? [];
$showPermissions = $showPermissions ?? false;
$passwordResets = $passwordResets ?? [];
$showPasswordResets = $showPasswordResets ?? false;
$rememberTokens = $rememberTokens ?? [];
$showRememberTokens = $showRememberTokens ?? false;
$minLength = UserService::passwordMinLength();
$requiredAttr = $passwordRequired ? 'required' : '';
$readonlyAttr = $isReadOnly ? 'readonly' : '';
$disabledAttr = $isReadOnly ? 'disabled' : '';
$dataDisabledAttr = $isReadOnly ? 'data-disabled="true"' : '';
$locales = defined('APP_LOCALES') ? APP_LOCALES : [I18n::$defaultLocale];
$primaryTenantDisabled = $isReadOnly || count($selectedTenantIds) === 1;
$primaryTenantDisabledAttr = $primaryTenantDisabled ? 'disabled' : '';
$showOrganization = $showTenants || $showDepartments || $showRoles;
?>
<form id="<?php e($formId); ?>" method="post">
<div class="app-tabs" data-tabs data-tabs-param="tab" data-tabs-storage-key="admin-user-form">
<div class="app-tabs-nav">
<button type="button" data-tab="profile" data-tab-default><?php e(t('Profile')); ?></button>
<button type="button" data-tab="access"><?php e(t('Access & password')); ?></button>
<?php if ($showOrganization): ?>
<button type="button" data-tab="organization"><?php e(t('Organization')); ?></button>
<?php endif; ?>
<button type="button" data-tab="masterdata"><?php e(t('Master data')); ?></button>
<?php if ($showPermissions): ?>
<button type="button" data-tab="permissions"><?php e(t('Permissions')); ?></button>
<?php endif; ?>
<?php if ($showPasswordResets): ?>
<button type="button" data-tab="password-resets"><?php e(t('Password resets')); ?></button>
<?php endif; ?>
<?php if ($showRememberTokens): ?>
<button type="button" data-tab="login-tokens"><?php e(t('Login tokens')); ?></button>
<?php endif; ?>
</div>
<div data-tab-panel="profile">
<div class="grid">
<label for="first_name">
<span><?php e(t('First name')); ?></span>
<input required type="text" name="first_name" id="first_name" value="<?php e($values['first_name'] ?? ''); ?>"
<?php e($readonlyAttr); ?> />
</label>
<label for="last_name">
<span><?php e(t('Last name')); ?></span>
<input required type="text" name="last_name" id="last_name" value="<?php e($values['last_name'] ?? ''); ?>"
<?php e($readonlyAttr); ?> />
</label>
</div>
<label for="email">
<span><?php e(t('Email')); ?></span>
<input required type="email" name="email" id="email" value="<?php e($values['email'] ?? ''); ?>" <?php e($readonlyAttr); ?> />
</label>
<hr>
<details name="profile-data" open>
<summary><?php e(t('Profile')); ?></summary>
<hr>
<label for="job_title">
<span><?php e(t('Job title')); ?></span>
<input type="text" name="job_title" id="job_title" value="<?php e($values['job_title'] ?? ''); ?>"
<?php e($readonlyAttr); ?> />
</label>
<label for="profile_description">
<span><?php e(t('Profile description')); ?></span>
<textarea name="profile_description" id="profile_description" rows="4"
<?php e($readonlyAttr); ?>><?php e($values['profile_description'] ?? ''); ?></textarea>
</label>
</details>
<hr>
<details name="preferences" open>
<summary><?php e(t('Preferences')); ?></summary>
<hr>
<div class="grid">
<?php if (allowUserTheme()): ?>
<label for="theme">
<span><?php e(t('Theme')); ?></span>
<?php
$themes = appThemes();
$selectedTheme = (string) ($values['theme'] ?? '');
if ($selectedTheme === '' || !isset($themes[$selectedTheme])) {
$selectedTheme = appDefaultTheme();
}
?>
<select name="theme" id="theme" <?php e($disabledAttr); ?>>
<?php foreach ($themes as $key => $label): ?>
<option value="<?php e($key); ?>" <?php if ($selectedTheme === $key) { ?>selected<?php } ?>>
<?php e(t($label)); ?>
</option>
<?php endforeach; ?>
</select>
</label>
<?php endif; ?>
<label for="locale">
<span><?php e(t('Language')); ?></span>
<?php $selectedLocale = $values['locale'] ?? (I18n::$locale ?? I18n::$defaultLocale); ?>
<select name="locale" id="locale" <?php e($disabledAttr); ?>>
<?php foreach ($locales as $locale): ?>
<?php
$label = strtoupper($locale);
if ($locale === 'de') {
$label = t('German');
} elseif ($locale === 'en') {
$label = t('English');
}
?>
<option value="<?php e($locale); ?>" <?php if ($selectedLocale === $locale) { ?>selected<?php } ?>>
<?php e($label); ?>
</option>
<?php endforeach; ?>
</select>
</label>
</div>
</details>
</div>
<div data-tab-panel="access">
<div class="grid">
<div>
<label for="password">
<span><?php e($passwordLabel); ?></span>
<input <?php e($requiredAttr); ?> type="password" name="password" id="password"
minlength="<?php e($minLength); ?>" autocomplete="new-password" <?php e($disabledAttr); ?> />
</label>
<label for="password2">
<span><?php e($passwordConfirmLabel); ?></span>
<input <?php e($requiredAttr); ?> type="password" name="password2" id="password2"
minlength="<?php e($minLength); ?>" autocomplete="new-password" <?php e($disabledAttr); ?> />
</label>
</div>
<div class="form-hint" data-password-hints data-password-input="#password" data-confirm-input="#password2"
data-email-input="#email" data-min-length="<?php e($minLength); ?>">
<strong><?php e(t('Password requirements')); ?></strong>
<ul class="form-hint-list">
<?php foreach (UserService::passwordHints() as $hint): ?>
<li data-rule="<?php e($hint['rule']); ?>"><?php e($hint['text']); ?></li>
<?php endforeach; ?>
<li data-rule="match"><?php e(t('Passwords must match')); ?></li>
</ul>
</div>
</div>
<?php if (!$isOwnAccount): ?>
<label for="active">
<input type="checkbox" name="active" id="active" value="1" <?php e(($values['active'] ?? 0) ? 'checked' : ''); ?>
<?php e($disabledAttr); ?> />
<span><?php e(t('Active')); ?></span>
</label>
<?php endif; ?>
</div>
<?php if ($showOrganization): ?>
<div data-tab-panel="organization">
<?php if ($showTenants): ?>
<details name="assignments-tenants" open>
<summary><?php e(t('Tenants')); ?></summary>
<hr>
<label>
<span>
<?php e(t('Primary tenant')); ?>
</span>
</label>
<?php if ($primaryTenantDisabled && $primaryTenantId > 0): ?>
<input type="hidden" name="primary_tenant_id" value="<?php e((string) $primaryTenantId); ?>">
<?php endif; ?>
<select id="user-primary-tenant" name="primary_tenant_id" <?php e($primaryTenantDisabledAttr); ?>
<?php e($disabledAttr); ?>>
<?php if (count($selectedTenantIds) !== 1): ?>
<option value="">
<?php e(t('Select primary tenant')); ?>
</option>
<?php endif; ?>
<?php foreach ($tenants as $tenant): ?>
<?php
$tenantId = (int) ($tenant['id'] ?? 0);
if (!in_array($tenantId, $selectedTenantIds ?? [], true)) {
continue;
}
$selected = $tenantId === $primaryTenantId ? 'selected' : '';
?>
<option value="<?php e((string) $tenantId); ?>" <?php e($selected); ?>>
<?php e($tenant['description'] ?? ''); ?>
</option>
<?php endforeach; ?>
</select>
<?php multiSelectForm('user-tenants', 'tenant_ids', 'Assigned tenants', 'Select tenants', $tenants, $selectedTenantIds, $isReadOnly); ?>
</details>
<hr>
<?php endif; ?>
<?php if ($showDepartments || $showRoles): ?>
<details name="assignments-structure" open>
<summary><?php e(t('Departments & roles')); ?></summary>
<hr>
<div class="grid">
<?php if ($showDepartments): ?>
<div>
<?php multiSelectForm('user-departments', 'department_ids', 'Assigned departments', 'Select departments', $departments, $selectedDepartmentIds, $isReadOnly); ?>
</div>
<?php endif; ?>
<?php if ($showRoles): ?>
<div>
<?php multiSelectForm('user-roles', 'role_ids', 'Assigned roles', 'Select roles', $roles, $selectedRoleIds, $isReadOnly); ?>
</div>
<?php endif; ?>
</div>
</details>
<?php endif; ?>
</div>
<?php endif; ?>
<div data-tab-panel="masterdata">
<details name="contact-data" open>
<summary><?php e(t('Contact')); ?></summary>
<hr>
<div class="grid">
<label for="phone">
<span><?php e(t('Phone')); ?></span>
<input type="tel" name="phone" id="phone" autocomplete="tel" value="<?php e($values['phone'] ?? ''); ?>"
<?php e($readonlyAttr); ?> />
</label>
<label for="mobile">
<span><?php e(t('Mobile')); ?></span>
<input type="tel" name="mobile" id="mobile" autocomplete="tel" value="<?php e($values['mobile'] ?? ''); ?>"
<?php e($readonlyAttr); ?> />
</label>
<label for="short_dial">
<span><?php e(t('Short dial')); ?></span>
<input type="text" name="short_dial" id="short_dial" inputmode="numeric"
value="<?php e($values['short_dial'] ?? ''); ?>" <?php e($readonlyAttr); ?> />
</label>
</div>
</details>
<hr>
<details name="address-data" open>
<summary><?php e(t('Address')); ?></summary>
<hr>
<label for="address">
<span><?php e(t('Address')); ?></span>
<input type="text" name="address" id="address" value="<?php e($values['address'] ?? ''); ?>" <?php e($readonlyAttr); ?> />
</label>
<div class="grid">
<label for="postal_code">
<span><?php e(t('Postal code')); ?></span>
<input type="text" name="postal_code" id="postal_code" value="<?php e($values['postal_code'] ?? ''); ?>" <?php e($readonlyAttr); ?> />
</label>
<label for="city">
<span><?php e(t('City')); ?></span>
<input type="text" name="city" id="city" value="<?php e($values['city'] ?? ''); ?>" <?php e($readonlyAttr); ?> />
</label>
</div>
<div class="grid">
<label for="region">
<span><?php e(t('Region')); ?></span>
<input type="text" name="region" id="region" value="<?php e($values['region'] ?? ''); ?>" <?php e($readonlyAttr); ?> />
</label>
<label for="country">
<span><?php e(t('Country')); ?></span>
<input type="text" name="country" id="country" value="<?php e($values['country'] ?? ''); ?>" <?php e($readonlyAttr); ?> />
</label>
</div>
</details>
<hr>
<details name="employment-data" open>
<summary><?php e(t('Employment')); ?></summary>
<hr>
<label for="hire_date">
<span><?php e(t('Hire date')); ?></span>
<input type="date" name="hire_date" id="hire_date" value="<?php e($values['hire_date'] ?? ''); ?>" <?php e($readonlyAttr); ?> />
</label>
</details>
</div>
<?php if ($showPermissions): ?>
<div data-tab-panel="permissions">
<div class="overflow-auto white-space-nowrap">
<table>
<thead>
<tr>
<th><?php e(t('Description')); ?></th>
<th><?php e(t('Permission key')); ?></th>
<th><?php e(t('Permission origin')); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($permissionRows as $permissionRow): ?>
<?php
$permissionKey = (string) ($permissionRow['key'] ?? '');
$labelKey = 'perm.' . $permissionKey;
$label = t($labelKey);
if ($label === $labelKey) {
$label = (string) ($permissionRow['description'] ?? '');
if ($label === '') {
$label = $permissionKey;
}
}
$rolesList = [];
if (!empty($permissionRow['roles']) && is_array($permissionRow['roles'])) {
$rolesList = $permissionRow['roles'];
}
?>
<tr>
<td><?php e($label); ?></td>
<td><code><?php e($permissionKey); ?></code></td>
<td>
<?php if ($rolesList): ?>
<?php foreach ($rolesList as $roleLabel): ?>
<span class="badge" data-variant="neutral"><?php e($roleLabel); ?></span>
<?php endforeach; ?>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
<?php if ($showPasswordResets): ?>
<div data-tab-panel="password-resets">
<div class="overflow-auto white-space-nowrap">
<table>
<thead>
<tr>
<th><?php e(t('Requested at')); ?></th>
<th><?php e(t('Expires at')); ?></th>
<th><?php e(t('Used at')); ?></th>
<th><?php e(t('Attempts')); ?></th>
<th><?php e(t('Status')); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($passwordResets as $reset): ?>
<?php
$expiresAt = (string) ($reset['expires_at'] ?? '');
$usedAt = (string) ($reset['used_at'] ?? '');
$status = t('Active');
$statusVariant = 'success';
if ($usedAt !== '') {
$status = t('Used');
$statusVariant = 'neutral';
} elseif ($expiresAt !== '') {
try {
$expired = (new \DateTimeImmutable($expiresAt)) <= new \DateTimeImmutable('now');
if ($expired) {
$status = t('Expired');
$statusVariant = 'warning';
}
} catch (\Exception $e) {
// fallback: keep Active
}
}
?>
<tr>
<td><?php e(dt($reset['created'] ?? '')); ?></td>
<td><?php e($expiresAt !== '' ? dt($expiresAt) : '-'); ?></td>
<td><?php e($usedAt !== '' ? dt($usedAt) : '-'); ?></td>
<td><?php e((string) ($reset['attempts'] ?? 0)); ?></td>
<td>
<span class="badge" data-variant="<?php e($statusVariant); ?>">
<?php e($status); ?>
</span>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
<?php if ($showRememberTokens): ?>
<div data-tab-panel="login-tokens">
<div class="overflow-auto white-space-nowrap">
<table>
<thead>
<tr>
<th><?php e(t('Created at')); ?></th>
<th><?php e(t('Expires at')); ?></th>
<th><?php e(t('Last used')); ?></th>
<th><?php e(t('Status')); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($rememberTokens as $token): ?>
<?php
$expiresAt = (string) ($token['expires_at'] ?? '');
$expiredByAdminAt = (string) ($token['expired_by_admin_at'] ?? '');
$lastUsed = (string) ($token['last_used'] ?? '');
$status = t('Active');
$statusVariant = 'success';
if ($expiresAt !== '') {
try {
$expired = (new \DateTimeImmutable($expiresAt)) <= new \DateTimeImmutable('now');
if ($expired) {
if ($expiredByAdminAt !== '') {
$status = t('Expired by admin');
$statusVariant = 'warning';
} else {
$status = t('Expired');
$statusVariant = 'warning';
}
}
} catch (\Exception $e) {
// fallback: keep Active
}
}
?>
<tr>
<td><?php e(dt($token['created'] ?? '')); ?></td>
<td><?php e($expiresAt !== '' ? dt($expiresAt) : '-'); ?></td>
<td><?php e($lastUsed !== '' ? dt($lastUsed) : '-'); ?></td>
<td>
<span class="badge" data-variant="<?php e($statusVariant); ?>">
<?php e($status); ?>
</span>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
</div>
<?php Session::getCsrfInput(); ?>
</form>