Files
2026-09-21 12:35:52 +01:00

305 lines
8.6 KiB
JavaScript
Executable File

require('flatpickr');
import '@fortawesome/fontawesome-free/css/all.min.css';
import Chart from 'chart.js/auto';
import $ from 'jquery';
window.$ = $;
window.jQuery = $;
import select2Factory from 'select2';
import 'select2/dist/css/select2.min.css';
import '../css/wms-select2.css';
if (typeof select2Factory === 'function') {
select2Factory(window, $);
}
const chartColours = [
'rgb(8, 145, 178)',
'rgb(37, 99, 235)',
'rgb(79, 70, 229)',
'rgb(14, 116, 144)',
];
/**
* Parse JSON attribute safely.
*
* @param {HTMLElement} element
* @param {string} attribute
* @param {Array} fallback
* @returns {*}
*/
function parseJsonAttribute(element, attribute, fallback = []) {
try {
return JSON.parse(
element.getAttribute(attribute) || JSON.stringify(fallback)
);
} catch (error) {
return fallback;
}
}
/**
* Render dashboard charts.
*
* @returns {void}
*/
function renderWmsCharts() {
document.querySelectorAll('[data-wms-chart]').forEach((canvas) => {
if (canvas.dataset.rendered === 'true') {
return;
}
const type = canvas.dataset.wmsChart;
const labels = parseJsonAttribute(canvas, 'data-labels');
const series = parseJsonAttribute(canvas, 'data-series');
const values = parseJsonAttribute(canvas, 'data-values');
const datasets = series.length
? series.map((item, index) => ({
label: item.label,
data: item.data,
backgroundColor:
chartColours[index % chartColours.length],
borderColor:
chartColours[index % chartColours.length],
borderWidth: 2,
borderRadius: 8,
}))
: [
{
label: 'Total',
data: values,
backgroundColor: chartColours,
borderColor: 'rgb(255,255,255)',
borderWidth: 2,
},
];
canvas.wmsChart = new Chart(canvas, {
type,
data: {
labels,
datasets,
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
labels: {
color: document.documentElement.classList.contains(
'dark'
)
? '#e4e4e7'
: '#3f3f46',
boxWidth: 12,
boxHeight: 12,
},
},
},
scales:
type === 'doughnut'
? {}
: {
x: {
ticks: {
color:
document.documentElement.classList.contains(
'dark'
)
? '#d4d4d8'
: '#52525b',
},
grid: {
color:
'rgba(113,113,122,0.18)',
},
},
y: {
beginAtZero: true,
ticks: {
precision: 0,
color:
document.documentElement.classList.contains(
'dark'
)
? '#d4d4d8'
: '#52525b',
},
grid: {
color:
'rgba(113,113,122,0.18)',
},
},
},
},
});
canvas.dataset.rendered = 'true';
});
}
function livewireComponentFor(element) {
let current = element;
while (current && current !== document.documentElement) {
if (current.hasAttribute?.('wire:id')) {
if (!window.Livewire) {
return null;
}
return window.Livewire.find(current.dataset.wireId);
}
current = current.parentElement;
}
return null;
}
function setLivewireProperty(element, model, value) {
const component = livewireComponentFor(element);
if (!component || !model) {
return;
}
component.set(model, value === '' ? null : value);
}
function normaliseSelect2Options($select) {
const isMultiple = $select.prop('multiple');
const $field = $select.closest('.wms-select2-field');
if (!isMultiple && $select.find('option[value=""]').length === 0) {
$select.prepend(new Option('', '', false, false));
}
return {
theme: 'wms',
width: '100%',
allowClear: !isMultiple,
closeOnSelect: !isMultiple,
dropdownAutoWidth: false,
minimumResultsForSearch: 0,
dropdownParent: $field.length ? $field : window.jQuery(document.body),
placeholder:
$select.data('placeholder') ||
$select.attr('placeholder') ||
(isMultiple ? 'Select options' : 'Search and select'),
sorter(data) {
return data.sort((first, second) =>
(first.text || '').localeCompare(second.text || '', undefined, {
sensitivity: 'base',
ignorePunctuation: true,
})
);
},
};
}
function select2Selector() {
return 'select[data-wms-select2], select[data-helpdesk-select2], select[data-company-country-select2], select.wms-select2-control';
}
function initialiseSelect2Element(select) {
if (!window.jQuery?.fn?.select2 || !select) {
return false;
}
const $select = window.jQuery(select);
if ($select.hasClass('select2-hidden-accessible')) {
return true;
}
$select.select2(normaliseSelect2Options($select));
$select.off('change.wms-select2-livewire');
$select.on('change.wms-select2-livewire', function () {
setLivewireProperty(this, this.dataset.wireModel, $select.val());
});
$select.off('select2:open.wms-select2-focus');
$select.on('select2:open.wms-select2-focus', function () {
window.setTimeout(() => {
const search = document.querySelector('.select2-container--open .select2-search__field');
if (search) {
search.focus();
}
}, 0);
});
return true;
}
/**
* Initialise all WMS Select2 controls currently on the page.
*
* @returns {void}
*/
function initialiseSelect2() {
if (!window.jQuery?.fn?.select2) {
window.setTimeout(initialiseSelect2, 100);
return;
}
document.querySelectorAll(select2Selector()).forEach(initialiseSelect2Element);
}
/**
* Selects inside Livewire/Navigate content can appear after DOMContentLoaded.
* Initialise on first interaction as a safety net, then open Select2 immediately.
*/
document.addEventListener('mousedown', (event) => {
const select = event.target.closest?.(select2Selector());
if (!select || select.classList.contains('select2-hidden-accessible')) {
return;
}
if (initialiseSelect2Element(select)) {
event.preventDefault();
window.setTimeout(() => window.jQuery(select).select2('open'), 0);
}
}, true);
document.addEventListener('focusin', (event) => {
const select = event.target.closest?.(select2Selector());
if (select) {
initialiseSelect2Element(select);
}
}, true);
/**
* Boot page UI.
*
* @returns {void}
*/
function bootUi() {
renderWmsCharts();
initialiseSelect2();
window.setTimeout(initialiseSelect2, 50);
window.setTimeout(initialiseSelect2, 250);
window.setTimeout(initialiseSelect2, 750);
}
document.addEventListener('DOMContentLoaded', bootUi);
document.addEventListener('livewire:navigated', bootUi);
document.addEventListener('livewire:init', () => {
if (!window.Livewire?.hook) {
return;
}
window.Livewire.hook('morphed', () => {
window.setTimeout(initialiseSelect2, 0);
});
});