forked from fa/breadcrumb-the-shire
157 lines
5.7 KiB
PHTML
157 lines
5.7 KiB
PHTML
<?php
|
|
use MintyPHP\Buffer;
|
|
?>
|
|
<div class="app-breadcrumb">
|
|
<a href="/admin">Startseite</a><i class="bi bi-chevron-right"></i><?php e(t('Address book')); ?>
|
|
</div>
|
|
<div class="app-list-titlebar">
|
|
<h1><?php e(t('Address book')); ?></h1>
|
|
<div class="app-list-titlebar-actions">
|
|
<button
|
|
class="outline secondary"
|
|
type="button"
|
|
data-toolbar-toggle
|
|
data-toolbar-target="#address-book-toolbar"
|
|
data-toolbar-text-show="<?php e(t('Show filters')); ?>"
|
|
data-toolbar-text-hide="<?php e(t('Hide filters')); ?>"
|
|
>
|
|
<i class="bi bi-funnel-fill"></i> <span data-toolbar-label><?php e(t('Hide filters')); ?></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="app-list-toolbar" id="address-book-toolbar">
|
|
<label class="app-field">
|
|
<span><?php e(t('Search')); ?></span>
|
|
<input type="search" id="address-book-search" placeholder="<?php e(t('Search...')); ?>">
|
|
</label>
|
|
<?php multiSelectFilter('address-book-tenant-filter', 'Tenants', 'Select tenants', $tenantItems ?? [], $activeTenants ?? []); ?>
|
|
<?php multiSelectFilter('address-book-department-filter', 'Departments', 'Select departments', $departments ?? [], $activeDepartments ?? []); ?>
|
|
<?php multiSelectFilter('address-book-role-filter', 'Roles', 'Select roles', $roles ?? [], $activeRoles ?? []); ?>
|
|
</div>
|
|
<div class="app-list-table">
|
|
<div id="address-book-grid"></div>
|
|
</div>
|
|
|
|
<?php $gridFactoryVersion = @filemtime('web/js/core/app-grid-factory.js') ?: time(); ?>
|
|
<script src="<?php e(asset('vendor/gridjs/gridjs.umd.js')); ?>"></script>
|
|
<script type="module">
|
|
import { initToolbarToggles } from "<?php e(asset('js/components/app-toggle-toolbar.js')); ?>";
|
|
import { createServerGrid } from "<?php e(asset('js/core/app-grid-factory.js?v=' . $gridFactoryVersion)); ?>";
|
|
initToolbarToggles();
|
|
|
|
const appBase = "<?php e(localeBase()); ?>";
|
|
|
|
const escapeHtml = (value) => String(value ?? '').replace(/[&<>"']/g, (char) => ({
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": '''
|
|
}[char]));
|
|
const buildBadgeList = (items) => {
|
|
if (!Array.isArray(items) || items.length === 0) return '';
|
|
const badges = items.map((label) => `<span class="badge" data-variant="neutral">${escapeHtml(label)}</span>`).join(' ');
|
|
return `<div class="badge-list">${badges}</div>`;
|
|
};
|
|
const uuidIndex = 1;
|
|
const normalizeCommaSeparated = (value) => {
|
|
if (Array.isArray(value)) return value.filter(Boolean);
|
|
return String(value || '')
|
|
.split(',')
|
|
.map((item) => item.trim())
|
|
.filter(Boolean);
|
|
};
|
|
const initialsForRow = (row) => {
|
|
const first = row?.cells?.[2]?.data ?? '';
|
|
const last = row?.cells?.[3]?.data ?? '';
|
|
const parts = [first, last]
|
|
.map((value) => String(value || '').trim())
|
|
.filter(Boolean);
|
|
const chars = parts.map((value) => value[0] || '').join('').toUpperCase();
|
|
return chars || '?';
|
|
};
|
|
|
|
createServerGrid({
|
|
gridjs: window.gridjs,
|
|
container: '#address-book-grid',
|
|
dataUrl: 'address-book/data',
|
|
appBase,
|
|
columns: [
|
|
{
|
|
name: "<?php e(t('Avatar')); ?>",
|
|
sort: false,
|
|
formatter: (cell, row) => {
|
|
if (!cell) {
|
|
const initials = escapeHtml(initialsForRow(row));
|
|
return gridjs.html(`<span class="grid-avatar grid-avatar-placeholder">${initials}</span>`);
|
|
}
|
|
const src = new URL(`admin/users/avatar-file?uuid=${cell}&size=64`, appBase).toString();
|
|
const full = new URL(`admin/users/avatar-file?uuid=${cell}&size=256`, appBase).toString();
|
|
return gridjs.html(`<a data-fslightbox="address-book-avatars" href="${full}"><img class="grid-avatar" src="${src}" alt="" loading="lazy"></a>`);
|
|
}
|
|
},
|
|
{ name: 'UUID', hidden: true },
|
|
{ name: "<?php e(t('First name')); ?>", sort: true },
|
|
{ name: "<?php e(t('Last name')); ?>", sort: true },
|
|
{ name: "<?php e(t('Email')); ?>", sort: true },
|
|
{ name: "<?php e(t('Phone')); ?>", sort: false },
|
|
{ name: "<?php e(t('Mobile')); ?>", sort: false },
|
|
{ name: "<?php e(t('Short dial')); ?>", sort: false },
|
|
{ name: "<?php e(t('Departments')); ?>", sort: false, formatter: (cell) => gridjs.html(buildBadgeList(cell)) },
|
|
{ name: "<?php e(t('Roles')); ?>", sort: false, formatter: (cell) => gridjs.html(buildBadgeList(cell)) },
|
|
{ name: "<?php e(t('Tenants')); ?>", sort: false, formatter: (cell) => gridjs.html(buildBadgeList(cell)) }
|
|
],
|
|
sortColumns: [null, null, 'first_name', 'last_name', 'email', null, null, null, null, null, null],
|
|
paginationLimit: 10,
|
|
language: <?php MintyPHP\Buffer::get('grid_lang'); ?>,
|
|
mapData: (data) => data.data.map((row) => [
|
|
row.has_avatar ? row.uuid : '',
|
|
row.uuid,
|
|
row.first_name,
|
|
row.last_name,
|
|
row.email,
|
|
row.phone,
|
|
row.mobile,
|
|
row.short_dial,
|
|
row.departments,
|
|
row.roles,
|
|
row.tenants
|
|
]),
|
|
search: {
|
|
input: '#address-book-search',
|
|
param: 'search',
|
|
debounce: 250
|
|
},
|
|
filters: [
|
|
{
|
|
input: '#address-book-tenant-filter',
|
|
param: 'tenants',
|
|
default: [],
|
|
normalize: normalizeCommaSeparated
|
|
},
|
|
{
|
|
input: '#address-book-department-filter',
|
|
param: 'departments',
|
|
default: [],
|
|
normalize: normalizeCommaSeparated
|
|
},
|
|
{
|
|
input: '#address-book-role-filter',
|
|
param: 'roles',
|
|
default: [],
|
|
normalize: normalizeCommaSeparated
|
|
}
|
|
],
|
|
urlSync: true,
|
|
rowDataset: (row) => ({
|
|
uuid: row?.cells?.[uuidIndex]?.data
|
|
}),
|
|
rowDblClick: {
|
|
getUrl: (rowData) => {
|
|
const uuid = rowData?.cells?.[uuidIndex]?.data;
|
|
return uuid ? new URL(`address-book/view/${uuid}`, appBase).toString() : '';
|
|
}
|
|
}
|
|
});
|
|
</script>
|