✨ feat(reservation/flow): Améliore le flux de réservation et ajoute des options.
Cette commit améliore le flux de réservation, ajoute une estimation des
frais de livraison et gère les options de produit et les paiements.
```
160 lines
6.0 KiB
JavaScript
160 lines
6.0 KiB
JavaScript
import './admin.scss';
|
|
import * as Sentry from "@sentry/browser";
|
|
import * as Turbo from "@hotwired/turbo";
|
|
|
|
import { RepeatLine } from "./libs/RepeatLine.js";
|
|
import { DevisManager } from "./libs/DevisManager.js";
|
|
import { CrmEditor } from "./libs/CrmEditor.js";
|
|
import { initTomSelect } from "./libs/initTomSelect.js";
|
|
import { SearchProduct, SearchOptions } from "./libs/SearchProduct.js";
|
|
import { SearchProductDevis, SearchOptionsDevis } from "./libs/SearchProductDevis.js";
|
|
import { SearchOptionsProduct } from "./libs/SearchProductProduct.js";
|
|
import { SearchProductFormule, SearchOptionsFormule } from "./libs/SearchProductFormule.js";
|
|
import PlaningLogestics from "./libs/PlaningLogestics.js";
|
|
import {SortableReorder} from "./libs/SortableReorder.js";
|
|
import { StripeCommissionCalculator } from "./libs/StripeCommissionCalculator.js";
|
|
import { ProductAddOption } from "./libs/ProductAddOption.js";
|
|
import { LeafletMap } from "./tools/LeafletMap.js";
|
|
|
|
// --- CONFIGURATION SENTRY ---
|
|
Sentry.init({
|
|
dsn: "https://803814be6540031b1c37bf92ba9c0f79@sentry.esy-web.dev/24",
|
|
tunnel: "/sentry-tunnel",
|
|
integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()],
|
|
tracesSampleRate: 1.0,
|
|
replaysSessionSampleRate: 0.1,
|
|
replaysOnErrorSampleRate: 1.0
|
|
});
|
|
|
|
/**
|
|
* Enregistre les Custom Elements de manière groupée
|
|
*/
|
|
const registerCustomElements = () => {
|
|
const elements = [
|
|
{ name: 'repeat-line', class: RepeatLine, extends: 'div' },
|
|
{ name: 'sortable-reorder', class: SortableReorder, extends: 'table' },
|
|
{ name: 'devis-manager', class: DevisManager, extends: 'div' },
|
|
{ name: 'search-product', class: SearchProduct, extends: 'button' },
|
|
{ name: 'search-productformule', class: SearchProductFormule, extends: 'button' },
|
|
{ name: 'search-optionsformule', class: SearchOptionsFormule, extends: 'button' },
|
|
{ name: 'search-optionsproduct', class: SearchOptionsProduct, extends: 'button' },
|
|
{ name: 'planing-logestics', class: PlaningLogestics },
|
|
{ name: 'search-options', class: SearchOptions, extends: 'button' },
|
|
{ name: 'search-productdevis', class: SearchProductDevis, extends: 'button' },
|
|
{ name: 'search-optionsdevis', class: SearchOptionsDevis, extends: 'button' },
|
|
{ name: 'crm-editor', class: CrmEditor, extends: 'textarea' },
|
|
{ name: 'stripe-commission-calculator', class: StripeCommissionCalculator, extends: 'div' },
|
|
{ name: 'product-add-option', class: ProductAddOption, extends: 'button' },
|
|
{ name: 'leaflet-map', class: LeafletMap }
|
|
];
|
|
|
|
elements.forEach(el => {
|
|
if (!customElements.get(el.name)) {
|
|
if(el.extends != undefined) {
|
|
customElements.define(el.name, el.class, { extends: el.extends });
|
|
} else {
|
|
customElements.define(el.name, el.class);
|
|
}
|
|
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Preview d'image optimisée
|
|
*/
|
|
function initImagePreview() {
|
|
const input = document.getElementById('product_image_input');
|
|
const preview = document.getElementById('product-image-preview');
|
|
const placeholder = document.getElementById('product-image-placeholder');
|
|
|
|
input?.addEventListener('change', ({ target }) => {
|
|
const file = target.files[0];
|
|
if (!file) return;
|
|
|
|
const reader = new FileReader();
|
|
reader.onload = (e) => {
|
|
if (preview) {
|
|
preview.src = e.target.result;
|
|
preview.classList.remove('hidden');
|
|
}
|
|
placeholder?.classList.add('hidden');
|
|
};
|
|
reader.readAsDataURL(file);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Filtrage dynamique (Contrats, Devis, etc.)
|
|
*/
|
|
function initDynamicSearch() {
|
|
const searchInput = document.getElementById('searchContrat');
|
|
const listContainer = document.getElementById('contratsList');
|
|
|
|
searchInput?.addEventListener('input', (e) => {
|
|
const filter = e.target.value.toLowerCase();
|
|
const cards = listContainer?.querySelectorAll('.contrat-card');
|
|
|
|
cards?.forEach(card => {
|
|
const isVisible = card.textContent.toLowerCase().includes(filter);
|
|
card.classList.toggle('hidden', !isVisible);
|
|
card.style.opacity = isVisible ? "1" : "0";
|
|
card.style.transform = isVisible ? "scale(1)" : "scale(0.95)";
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Gestion UI : Sidebar, Submenus et Flash messages
|
|
*/
|
|
function initUI() {
|
|
// Sidebar
|
|
const elements = {
|
|
sidebar: document.getElementById('sidebar'),
|
|
overlay: document.getElementById('sidebar-overlay'),
|
|
toggleBtn: document.getElementById('sidebar-toggle'),
|
|
settingsToggle: document.getElementById('settings-toggle'),
|
|
settingsSubmenu: document.getElementById('settings-submenu')
|
|
};
|
|
|
|
const toggleSidebar = () => {
|
|
elements.sidebar?.classList.toggle('-translate-x-full');
|
|
elements.overlay?.classList.toggle('hidden');
|
|
};
|
|
|
|
elements.toggleBtn?.addEventListener('click', toggleSidebar);
|
|
elements.overlay?.addEventListener('click', toggleSidebar);
|
|
|
|
// Settings Submenu
|
|
elements.settingsToggle?.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
const isHidden = elements.settingsSubmenu?.classList.toggle('hidden');
|
|
localStorage.setItem('admin_settings_open', !isHidden);
|
|
});
|
|
|
|
// Flash Messages (Délégation pour performance)
|
|
document.querySelectorAll('.flash-message').forEach(flash => {
|
|
setTimeout(() => {
|
|
flash.classList.add('opacity-0', 'translate-x-10');
|
|
setTimeout(() => flash.remove(), 500);
|
|
}, 5000);
|
|
});
|
|
}
|
|
|
|
// --- INITIALISATION ---
|
|
document.addEventListener('turbo:load', () => {
|
|
registerCustomElements();
|
|
initDynamicSearch();
|
|
initImagePreview();
|
|
initUI();
|
|
initTomSelect();
|
|
});
|
|
|
|
// Confirmation de suppression Turbo
|
|
document.addEventListener("turbo:click", (event) => {
|
|
const attr = event.target.closest("[data-turbo-confirm]")?.getAttribute("data-turbo-confirm");
|
|
if (attr && !confirm(attr)) {
|
|
event.preventDefault();
|
|
}
|
|
});
|