Files
ludikevent_crm/assets/libs/initTomSelect.js
Serreau Jovann 0afc9e3396 feat(ansible): Ajoute le dossier PDF aux droits d'écriture et modifie l'URL API
 feat(.env): Met à jour les URLs de signature et Stripe pour Ngrok

 feat(SignatureController): Ajoute le contrôleur de signature

 feat(DevisController): Intègre DocuSeal et la gestion des adresses client

🐛 fix(DevisManager.js): Corrige la sélection et la synchronisation des adresses

 feat(vich_uploader.yaml): Configure le stockage des fichiers PDF

 feat(initTomSelect.js): Améliore la gestion des prix des produits

 feat(DevisPdfService): Intègre la signature DocuSeal et améliore le pied de page

 feat(Client.php): Crée une soumission Docuseal pour les devis
2026-01-19 18:22:53 +01:00

94 lines
4.1 KiB
JavaScript

// Cache pour éviter les requêtes HTTP répétitives
import TomSelect from "tom-select";
let productCache = null;
/**
* Initialise TomSelect sur un élément ou un groupe d'éléments
*/
export function initTomSelect(parent = document) {
parent.querySelectorAll('select').forEach((el) => {
if (el.tomselect) 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,
// LORSQU'ON SÉLECTIONNE UN PRODUIT
// Dans admin.js, section onChange de TomSelect :
onChange: (id) => {
if (!id) return;
// On s'assure de trouver le produit (id peut être string ou int)
const product = data.find(p => String(p.id) === String(id));
if (product) {
// On remonte au parent le plus proche (le bloc de ligne du devis)
const row = el.closest('.form-repeater__row') || el.closest('fieldset');
if (!row) return;
// Ciblage précis des inputs
const priceInput = row.querySelector('input[name*="[price_ht]"]');
const priceSupInput = row.querySelector('input[name*="[price_sup_ht]"]');
if (priceInput) {
priceInput.value = product.price1day;
// Indispensable pour que d'autres scripts (calcul totaux) voient le changement
priceInput.dispatchEvent(new Event('input', { bubbles: true }));
priceInput.dispatchEvent(new Event('change', { bubbles: true }));
}
if (priceSupInput) {
priceSupInput.value = product.priceSup;
priceSupInput.dispatchEvent(new Event('input', { bubbles: true }));
priceSupInput.dispatchEvent(new Event('change', { 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>`
}
});
};
// Utilisation du cache ou fetch
if (productCache) {
setupSelect(productCache);
} else {
fetch("/crm/products/json")
.then(r => r.json())
.then(data => {
productCache = data;
setupSelect(data);
});
}
}
// --- AUTRES SELECTS ---
else {
new TomSelect(el, {
controlInput: null,
allowEmptyOption: true,
highlight: true,
plugins: ['dropdown_input'],
});
}
});
}