✨ feat(Formules.php): Ajoute relation OneToOne avec FormulesRestriction. ✨ feat(Dashboard/FormulesController.php): Gère restrictions formules et formulaire. 🎨 refactor(template/formules): Améliore interface configuration restriction formule. 🐛 fix(assets/RepeatLine.js): Corrige réinitialisation TomSelect et selects "Type". ✨ feat(assets/initTomSelect.js): Gère cache options et init TomSelect. ```
127 lines
5.7 KiB
JavaScript
127 lines
5.7 KiB
JavaScript
import TomSelect from "tom-select";
|
|
|
|
// Cache séparé pour éviter les conflits entre produits et options
|
|
let productCache = null;
|
|
let optionsCache = null;
|
|
|
|
/**
|
|
* Initialise TomSelect sur un élément ou un groupe d'éléments
|
|
*/
|
|
export function initTomSelect(parent = document) {
|
|
parent.querySelectorAll('select').forEach((el) => {
|
|
// --- CLAUSES DE GARDE ---
|
|
// On ignore si déjà initialisé OU si l'élément possède l'attribut "is"
|
|
if (el.tomselect || el.hasAttribute('ds')) return;
|
|
|
|
// --- CONFIGURATION PRODUITS ---
|
|
if (el.getAttribute('data-load') === "product") {
|
|
const setupSelect = (data) => {
|
|
new TomSelect(el, {
|
|
valueField: 'id',
|
|
labelField: 'name',
|
|
searchField: 'name',
|
|
options: data,
|
|
maxOptions: null,
|
|
onChange: (id) => {
|
|
if (!id) return;
|
|
const product = data.find(p => String(p.id) === String(id));
|
|
if (product) {
|
|
const row = el.closest('.form-repeater__row') || el.closest('fieldset');
|
|
if (!row) return;
|
|
|
|
const priceInput = row.querySelector('input[name*="[price_ht]"]');
|
|
const priceSupInput = row.querySelector('input[name*="[price_sup_ht]"]');
|
|
|
|
if (priceInput) {
|
|
priceInput.value = product.price1day;
|
|
priceInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
}
|
|
if (priceSupInput) {
|
|
priceSupInput.value = product.priceSup;
|
|
priceSupInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
}
|
|
}
|
|
},
|
|
render: {
|
|
option: (data, escape) => `
|
|
<div class="flex items-center gap-3 py-2 px-3 border-b border-slate-800/50">
|
|
<img src="${escape(data.image)}" class="w-8 h-8 object-cover rounded shadow-sm">
|
|
<div class="flex flex-col">
|
|
<div class="text-[13px] font-bold text-white">${escape(data.name)}</div>
|
|
<div class="text-[10px] text-slate-400">J1: ${escape(data.price1day)}€ | Sup: ${escape(data.priceSup)}€</div>
|
|
</div>
|
|
</div>`,
|
|
item: (data, escape) => `<div class="text-blue-400 font-bold flex items-center gap-2"><span class="w-1.5 h-1.5 rounded-full bg-blue-500"></span>${escape(data.name)}</div>`
|
|
}
|
|
});
|
|
};
|
|
|
|
if (productCache) {
|
|
setupSelect(productCache);
|
|
} else {
|
|
fetch("/crm/products/json")
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
productCache = data;
|
|
setupSelect(data);
|
|
});
|
|
}
|
|
}
|
|
// --- CONFIGURATION OPTIONS ---
|
|
else if (el.getAttribute('data-load') === "options") {
|
|
const setupSelect = (data) => {
|
|
new TomSelect(el, {
|
|
valueField: 'id',
|
|
labelField: 'name',
|
|
searchField: 'name',
|
|
options: data,
|
|
maxOptions: null,
|
|
onChange: (id) => {
|
|
if (!id) return;
|
|
const product = data.find(p => String(p.id) === String(id));
|
|
const row = el.closest('.form-repeater__row') || el.closest('fieldset');
|
|
if (!row) return;
|
|
const priceInput = row.querySelector('input[name*="[price_ht]"]');
|
|
|
|
if (priceInput) {
|
|
priceInput.value = product.price;
|
|
priceInput.dispatchEvent(new Event('input', { bubbles: true }));
|
|
}
|
|
},
|
|
render: {
|
|
option: (data, escape) => `
|
|
<div class="flex items-center gap-3 py-2 px-3 border-b border-slate-800/50">
|
|
<img src="${escape(data.image)}" class="w-8 h-8 object-cover rounded shadow-sm">
|
|
<div class="flex flex-col">
|
|
<div class="text-[13px] font-bold text-white">${escape(data.name)}</div>
|
|
<div class="text-[10px] text-slate-400">${escape(data.price)}€</div>
|
|
</div>
|
|
</div>`,
|
|
item: (data, escape) => `<div class="text-blue-400 font-bold flex items-center gap-2"><span class="w-1.5 h-1.5 rounded-full bg-blue-500"></span>${escape(data.name)}</div>`
|
|
}
|
|
});
|
|
};
|
|
|
|
if (optionsCache) {
|
|
setupSelect(optionsCache);
|
|
} else {
|
|
fetch("/crm/options/json")
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
optionsCache = data;
|
|
setupSelect(data);
|
|
});
|
|
}
|
|
}
|
|
// --- AUTRES SELECTS STANDARDS ---
|
|
else {
|
|
new TomSelect(el, {
|
|
controlInput: null,
|
|
allowEmptyOption: true,
|
|
highlight: true,
|
|
plugins: ['dropdown_input'],
|
|
});
|
|
}
|
|
});
|
|
}
|