|
|
|
@@ -19,7 +19,6 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
this.innerHTML = `
|
|
|
|
this.innerHTML = `
|
|
|
|
<div class="p-4 md:p-8 bg-gray-50 dark:bg-gray-950 min-h-screen transition-colors duration-300 font-sans">
|
|
|
|
<div class="p-4 md:p-8 bg-gray-50 dark:bg-gray-950 min-h-screen transition-colors duration-300 font-sans">
|
|
|
|
<div class="mx-auto space-y-6">
|
|
|
|
<div class="mx-auto space-y-6">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- En-tête Statistiques -->
|
|
|
|
<!-- En-tête Statistiques -->
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
|
|
<div class="bg-white dark:bg-gray-900 p-5 rounded-2xl shadow-sm border border-gray-100 dark:border-gray-800 flex items-center gap-4">
|
|
|
|
<div class="bg-white dark:bg-gray-900 p-5 rounded-2xl shadow-sm border border-gray-100 dark:border-gray-800 flex items-center gap-4">
|
|
|
|
@@ -27,24 +26,27 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 5l7 7-7 7"></path></svg>
|
|
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 5l7 7-7 7"></path></svg>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
|
<p class="text-[10px] font-bold text-gray-400 uppercase tracking-widest">Départs Jour</p>
|
|
|
|
<p class="text-[10px] font-bold text-gray-400 uppercase tracking-widest">Réservations</p>
|
|
|
|
<p class="text-2xl font-black text-gray-900 dark:text-white" id="stat-departs">0</p>
|
|
|
|
<p class="text-2xl font-black text-gray-900 dark:text-white" id="stat-departs">0</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="bg-white dark:bg-gray-900 p-5 rounded-2xl shadow-sm border border-gray-100 dark:border-gray-800 flex items-center gap-4">
|
|
|
|
<div class="bg-white dark:bg-gray-900 p-5 rounded-2xl shadow-sm border border-gray-100 dark:border-gray-800 flex items-center gap-4">
|
|
|
|
<div class="p-3 bg-emerald-100 dark:bg-emerald-900/30 rounded-xl text-emerald-600">
|
|
|
|
<div class="p-3 bg-emerald-100 dark:bg-emerald-900/30 rounded-xl text-emerald-600">
|
|
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 19l-7-7 7-7M19 19l-7-7 7-7"></path></svg>
|
|
|
|
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
|
<p class="text-[10px] font-bold text-gray-400 uppercase tracking-widest">Retours Jour</p>
|
|
|
|
<p class="text-[10px] font-bold text-gray-400 uppercase tracking-widest">Contrats Signés</p>
|
|
|
|
<p class="text-2xl font-black text-gray-900 dark:text-white" id="stat-retours">0</p>
|
|
|
|
<p class="text-2xl font-black text-gray-900 dark:text-white" id="stat-retours">0</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Calendrier Principal -->
|
|
|
|
<!-- Calendrier Principal -->
|
|
|
|
<div class="bg-white dark:bg-gray-900 p-2 md:p-6 rounded-3xl shadow-sm border border-gray-100 dark:border-gray-800">
|
|
|
|
<div class="bg-white dark:bg-gray-900 p-2 md:p-6 rounded-3xl shadow-sm border border-gray-100 dark:border-gray-800 relative">
|
|
|
|
|
|
|
|
<div id="calendar-loading" class="absolute inset-0 bg-white/50 dark:bg-gray-900/50 backdrop-blur-[2px] z-10 flex items-center justify-center hidden">
|
|
|
|
|
|
|
|
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-600"></div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<div id="calendar-root"></div>
|
|
|
|
<div id="calendar-root"></div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
@@ -53,7 +55,7 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
<!-- Modale de Détails -->
|
|
|
|
<!-- Modale de Détails -->
|
|
|
|
<div id="calendar-modal" class="fixed inset-0 z-[100] hidden items-center justify-center p-4">
|
|
|
|
<div id="calendar-modal" class="fixed inset-0 z-[100] hidden items-center justify-center p-4">
|
|
|
|
<div class="absolute inset-0 bg-gray-900/60 backdrop-blur-sm modal-overlay"></div>
|
|
|
|
<div class="absolute inset-0 bg-gray-900/60 backdrop-blur-sm modal-overlay"></div>
|
|
|
|
<div class="relative bg-white dark:bg-gray-900 rounded-3xl shadow-2xl w-full max-w-lg overflow-hidden border border-gray-100 dark:border-gray-800 animate-in fade-in zoom-in duration-200">
|
|
|
|
<div class="relative bg-white dark:bg-gray-900 rounded-3xl shadow-2xl w-full max-w-lg overflow-hidden border border-gray-100 dark:border-gray-800">
|
|
|
|
<div class="p-6 md:p-8">
|
|
|
|
<div class="p-6 md:p-8">
|
|
|
|
<div class="flex justify-between items-start mb-4">
|
|
|
|
<div class="flex justify-between items-start mb-4">
|
|
|
|
<span id="modal-contract-number" class="px-3 py-1 bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400 rounded-lg text-[10px] font-black uppercase tracking-tighter border border-gray-200 dark:border-gray-700"></span>
|
|
|
|
<span id="modal-contract-number" class="px-3 py-1 bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400 rounded-lg text-[10px] font-black uppercase tracking-tighter border border-gray-200 dark:border-gray-700"></span>
|
|
|
|
@@ -62,15 +64,13 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
</button>
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Badges Statut -->
|
|
|
|
|
|
|
|
<div class="flex flex-wrap gap-2 mb-6" id="modal-status-container"></div>
|
|
|
|
<div class="flex flex-wrap gap-2 mb-6" id="modal-status-container"></div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="mb-6">
|
|
|
|
<div class="mb-6">
|
|
|
|
<h2 id="modal-title" class="text-2xl font-extrabold text-gray-900 dark:text-white leading-tight mb-1"></h2>
|
|
|
|
<h2 id="modal-title" class="text-xl font-extrabold text-gray-900 dark:text-white leading-tight mb-1"></h2>
|
|
|
|
<p id="modal-client" class="text-indigo-600 dark:text-indigo-400 font-bold text-lg"></p>
|
|
|
|
<p id="modal-client" class="text-indigo-600 dark:text-indigo-400 font-bold text-lg"></p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Informations de contact -->
|
|
|
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
|
|
|
|
<a id="link-phone" href="#" class="flex items-center gap-3 p-3 bg-gray-50 dark:bg-gray-800 rounded-xl hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors group">
|
|
|
|
<a id="link-phone" href="#" class="flex items-center gap-3 p-3 bg-gray-50 dark:bg-gray-800 rounded-xl hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors group">
|
|
|
|
<div class="text-indigo-500 group-hover:scale-110 transition-transform"><svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"></path></svg></div>
|
|
|
|
<div class="text-indigo-500 group-hover:scale-110 transition-transform"><svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"></path></svg></div>
|
|
|
|
@@ -82,7 +82,6 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
</a>
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Adresse -->
|
|
|
|
|
|
|
|
<div class="mb-6 p-4 bg-gray-50 dark:bg-gray-800 rounded-2xl border border-gray-100 dark:border-gray-700">
|
|
|
|
<div class="mb-6 p-4 bg-gray-50 dark:bg-gray-800 rounded-2xl border border-gray-100 dark:border-gray-700">
|
|
|
|
<div class="flex items-start gap-3">
|
|
|
|
<div class="flex items-start gap-3">
|
|
|
|
<div class="text-emerald-500 mt-0.5"><svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path></svg></div>
|
|
|
|
<div class="text-emerald-500 mt-0.5"><svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"></path></svg></div>
|
|
|
|
@@ -93,7 +92,6 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Dates -->
|
|
|
|
|
|
|
|
<div class="grid grid-cols-2 gap-6 py-4 border-t border-gray-100 dark:border-gray-800">
|
|
|
|
<div class="grid grid-cols-2 gap-6 py-4 border-t border-gray-100 dark:border-gray-800">
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
|
<span class="block text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Départ / Enlèvement</span>
|
|
|
|
<span class="block text-[10px] font-bold text-gray-400 uppercase tracking-widest mb-1">Départ / Enlèvement</span>
|
|
|
|
@@ -106,16 +104,12 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Actions -->
|
|
|
|
|
|
|
|
<div class="p-6 bg-gray-50 dark:bg-gray-800/50 flex gap-3">
|
|
|
|
<div class="p-6 bg-gray-50 dark:bg-gray-800/50 flex gap-3">
|
|
|
|
<a id="modal-link-contrat" href="#" target="_blank" class="flex-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 text-gray-700 dark:text-gray-200 py-4 rounded-2xl font-bold text-sm hover:bg-gray-50 dark:hover:bg-gray-700 transition-all flex items-center justify-center gap-2 shadow-sm">
|
|
|
|
<a id="modal-link-contrat" href="#" target="_blank" class="flex-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 text-gray-700 dark:text-gray-200 py-4 rounded-2xl font-bold text-sm hover:bg-gray-50 dark:hover:bg-gray-700 transition-all flex items-center justify-center gap-2 shadow-sm">
|
|
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>
|
|
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>
|
|
|
|
Voir Contrat
|
|
|
|
Voir Contrat
|
|
|
|
</a>
|
|
|
|
</a>
|
|
|
|
<button class="flex-1 bg-indigo-600 text-white py-4 rounded-2xl font-bold text-sm hover:bg-indigo-700 shadow-lg shadow-indigo-500/20 transition-all flex items-center justify-center gap-2">
|
|
|
|
|
|
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"></path></svg>
|
|
|
|
|
|
|
|
Éditer
|
|
|
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
@@ -140,7 +134,6 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#calendar-root { min-height: 750px; }
|
|
|
|
#calendar-root { min-height: 750px; }
|
|
|
|
|
|
|
|
|
|
|
|
.fc-toolbar-title { font-weight: 900 !important; color: inherit; font-size: 1.25rem !important; }
|
|
|
|
.fc-toolbar-title { font-weight: 900 !important; color: inherit; font-size: 1.25rem !important; }
|
|
|
|
.fc-col-header-cell { padding: 12px 0 !important; text-transform: uppercase; font-size: 0.7rem; letter-spacing: 0.1em; color: #94a3b8; }
|
|
|
|
.fc-col-header-cell { padding: 12px 0 !important; text-transform: uppercase; font-size: 0.7rem; letter-spacing: 0.1em; color: #94a3b8; }
|
|
|
|
|
|
|
|
|
|
|
|
@@ -170,11 +163,9 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
cursor: pointer;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.fc-event:hover { transform: translateY(-1px); filter: brightness(1.1); box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); }
|
|
|
|
.fc-event:hover { transform: translateY(-1px); filter: brightness(1.1); box-shadow: 0 4px 6px -1px rgba(0,0,0,0.1); }
|
|
|
|
|
|
|
|
|
|
|
|
.fc-event-main-frame { padding: 4px; }
|
|
|
|
.fc-event-main-frame { padding: 4px; }
|
|
|
|
.status-indicators { display: flex; gap: 3px; margin-top: 4px; }
|
|
|
|
.status-indicators { display: flex; gap: 3px; margin-top: 4px; }
|
|
|
|
.status-dot { width: 14px; height: 14px; border-radius: 4px; display: flex; align-items: center; justify-content: center; }
|
|
|
|
.status-dot { width: 14px; height: 14px; border-radius: 4px; display: flex; align-items: center; justify-content: center; }
|
|
|
|
|
|
|
|
|
|
|
|
.dark .fc-theme-standard td, .dark .fc-theme-standard th { border-color: #1f2937 !important; }
|
|
|
|
.dark .fc-theme-standard td, .dark .fc-theme-standard th { border-color: #1f2937 !important; }
|
|
|
|
</style>
|
|
|
|
</style>
|
|
|
|
`;
|
|
|
|
`;
|
|
|
|
@@ -185,45 +176,7 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
|
|
|
|
|
|
|
|
initCalendar() {
|
|
|
|
initCalendar() {
|
|
|
|
const calendarEl = this.querySelector('#calendar-root');
|
|
|
|
const calendarEl = this.querySelector('#calendar-root');
|
|
|
|
|
|
|
|
const loader = this.querySelector('#calendar-loading');
|
|
|
|
// Données exemples intégrant contractNumber
|
|
|
|
|
|
|
|
/*const events = [
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
title: 'Retrait Pack Mariage',
|
|
|
|
|
|
|
|
start: '2026-01-30T14:00:00',
|
|
|
|
|
|
|
|
end: '2026-02-01T12:00:00',
|
|
|
|
|
|
|
|
backgroundColor: '#10b981',
|
|
|
|
|
|
|
|
extendedProps: {
|
|
|
|
|
|
|
|
contractNumber: 'CTR-2026-001',
|
|
|
|
|
|
|
|
client: 'M. et Mme. Lefebvre',
|
|
|
|
|
|
|
|
clientEmail: 'lefebvre.m@gmail.com',
|
|
|
|
|
|
|
|
clientPhone: '06 12 34 56 78',
|
|
|
|
|
|
|
|
eventAdresse: '15 Rue de la Paix, 75002 Paris',
|
|
|
|
|
|
|
|
linkContrat: 'https://admin.votre-erp.com/contrats/12345',
|
|
|
|
|
|
|
|
caution: true,
|
|
|
|
|
|
|
|
acompte: true,
|
|
|
|
|
|
|
|
solde: true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
title: 'Livraison Podium Sonorisé',
|
|
|
|
|
|
|
|
start: '2026-01-29T08:00:00',
|
|
|
|
|
|
|
|
end: '2026-01-29T18:00:00',
|
|
|
|
|
|
|
|
backgroundColor: '#4f46e5',
|
|
|
|
|
|
|
|
extendedProps: {
|
|
|
|
|
|
|
|
contractNumber: 'CTR-2026-042',
|
|
|
|
|
|
|
|
client: 'Mairie de Nanterre',
|
|
|
|
|
|
|
|
clientEmail: 'logistique@nanterre.fr',
|
|
|
|
|
|
|
|
clientPhone: '01 47 29 50 00',
|
|
|
|
|
|
|
|
eventAdresse: 'Place Gabriel Péri, 92000 Nanterre',
|
|
|
|
|
|
|
|
linkContrat: 'https://admin.votre-erp.com/contrats/98765',
|
|
|
|
|
|
|
|
caution: true,
|
|
|
|
|
|
|
|
acompte: true,
|
|
|
|
|
|
|
|
solde: false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
];*/
|
|
|
|
|
|
|
|
const events = {};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.calendar = new Calendar(calendarEl, {
|
|
|
|
this.calendar = new Calendar(calendarEl, {
|
|
|
|
plugins: [ dayGridPlugin, timeGridPlugin, interactionPlugin ],
|
|
|
|
plugins: [ dayGridPlugin, timeGridPlugin, interactionPlugin ],
|
|
|
|
@@ -234,16 +187,49 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
center: 'title',
|
|
|
|
center: 'title',
|
|
|
|
right: 'dayGridMonth,timeGridWeek'
|
|
|
|
right: 'dayGridMonth,timeGridWeek'
|
|
|
|
},
|
|
|
|
},
|
|
|
|
events: events,
|
|
|
|
|
|
|
|
|
|
|
|
events: (fetchInfo, successCallback, failureCallback) => {
|
|
|
|
|
|
|
|
loader.classList.remove('hidden');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const params = new URLSearchParams({
|
|
|
|
|
|
|
|
start: fetchInfo.startStr,
|
|
|
|
|
|
|
|
end: fetchInfo.endStr
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fetch(`/crm/reservation/data?${params.toString()}`)
|
|
|
|
|
|
|
|
.then(response => {
|
|
|
|
|
|
|
|
if (!response.ok) throw new Error('Erreur réseau');
|
|
|
|
|
|
|
|
return response.json();
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.then(data => {
|
|
|
|
|
|
|
|
// On ajoute les propriétés de style si l'API ne les fournit pas
|
|
|
|
|
|
|
|
const formattedData = data.map(item => ({
|
|
|
|
|
|
|
|
...item,
|
|
|
|
|
|
|
|
backgroundColor: item.extendedProps.isSigned ? '#10b981' : '#4f46e5'
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
successCallback(formattedData);
|
|
|
|
|
|
|
|
this.updateStats(formattedData);
|
|
|
|
|
|
|
|
loader.classList.add('hidden');
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
|
|
console.error("Erreur chargement:", error);
|
|
|
|
|
|
|
|
failureCallback(error);
|
|
|
|
|
|
|
|
loader.classList.add('hidden');
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
eventContent: (arg) => {
|
|
|
|
eventContent: (arg) => {
|
|
|
|
const { caution, acompte, solde } = arg.event.extendedProps;
|
|
|
|
const { caution, acompte, solde, isSigned } = arg.event.extendedProps;
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
html: `
|
|
|
|
html: `
|
|
|
|
<div class="fc-event-main-frame">
|
|
|
|
<div class="fc-event-main-frame">
|
|
|
|
<div class="text-[11px] font-bold leading-tight line-clamp-1">${arg.event.title}</div>
|
|
|
|
<div class="text-[11px] font-bold leading-tight line-clamp-1 flex items-center gap-1">
|
|
|
|
|
|
|
|
${isSigned ? '✅' : ''} ${arg.event.title}
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<div class="status-indicators">
|
|
|
|
<div class="status-indicators">
|
|
|
|
<div class="status-dot" style="background:${caution ? '#f59e0b' : '#4b5563'}; opacity:${caution ? 1 : 0.3}"><svg class="w-2.5 h-2.5 text-white" fill="currentColor" viewBox="0 0 20 20"><path d="M4 4a2 2 0 00-2 2v1h16V6a2 2 0 00-2-2H4z"></path><path d="M2 9h16v5a2 2 0 01-2 2H4a2 2 0 01-2-2V9z"></path></svg></div>
|
|
|
|
<div class="status-dot" style="background:${caution ? '#f59e0b' : '#4b5563'}; opacity:${caution ? 1 : 0.3}"><svg class="w-2.5 h-2.5 text-white" fill="currentColor" viewBox="0 0 20 20"><path d="M4 4a2 2 0 00-2 2v1h16V6a2 2 0 00-2-2H4z"></path><path d="M2 9h16v5a2 2 0 01-2 2H4a2 2 0 01-2-2V9z"></path></svg></div>
|
|
|
|
<div class="status-dot" style="background:${acompte ? '#3b82f6' : '#4b5563'}; opacity:${acompte ? 1 : 0.3}"><svg class="w-2.5 h-2.5 text-white" fill="currentColor" viewBox="0 0 20 20"><path d="M4 4a2 2 0 00-2 2v4a2 2 0 002 2V6h10a2 2 0 00-2-2H4z"></path></svg></div>
|
|
|
|
<div class="status-dot" style="background:${acompte ? '#3b82f6' : '#4b5563'}; opacity:${acompte ? 1 : 0.3}"><svg class="w-2.5 h-2.5 text-white" fill="currentColor" viewBox="0 0 20 20"><path d="M4 4a2 2 0 002 2V6h10a2 2 0 00-2-2H4z"></path></svg></div>
|
|
|
|
<div class="status-dot" style="background:${solde ? '#10b981' : '#4b5563'}; opacity:${solde ? 1 : 0.3}"><svg class="w-2.5 h-2.5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path></svg></div>
|
|
|
|
<div class="status-dot" style="background:${solde ? '#10b981' : '#4b5563'}; opacity:${solde ? 1 : 0.3}"><svg class="w-2.5 h-2.5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path></svg></div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
@@ -254,50 +240,53 @@ export default class PlaningLogestics extends HTMLElement {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
this.calendar.render();
|
|
|
|
this.calendar.render();
|
|
|
|
this.updateStats(events);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
updateStats(events) {
|
|
|
|
updateStats(events) {
|
|
|
|
const todayStr = new Date().toISOString().split('T')[0];
|
|
|
|
const total = events.length;
|
|
|
|
const departs = events.filter(e => e.start.split('T')[0] === todayStr).length;
|
|
|
|
const signed = events.filter(e => e.extendedProps && e.extendedProps.isSigned).length;
|
|
|
|
const retours = events.filter(e => e.end && e.end.split('T')[0] === todayStr).length;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.querySelector('#stat-departs').innerText = departs;
|
|
|
|
this.querySelector('#stat-departs').innerText = total;
|
|
|
|
this.querySelector('#stat-retours').innerText = retours;
|
|
|
|
this.querySelector('#stat-retours').innerText = signed;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
formatAddress(addr) {
|
|
|
|
|
|
|
|
if (!addr || typeof addr !== 'object') return 'Adresse non renseignée';
|
|
|
|
|
|
|
|
const parts = [addr.address, addr.address1, addr.address2, addr.zipCode, addr.city];
|
|
|
|
|
|
|
|
return parts.filter(p => p && p !== 'null' && p !== '').join(', ');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
showEventDetails(event) {
|
|
|
|
showEventDetails(event) {
|
|
|
|
const modal = this.querySelector('#calendar-modal');
|
|
|
|
const modal = this.querySelector('#calendar-modal');
|
|
|
|
const props = event.extendedProps;
|
|
|
|
const props = event.extendedProps;
|
|
|
|
|
|
|
|
|
|
|
|
// Mise à jour des informations contractuelles
|
|
|
|
this.querySelector('#modal-contract-number').innerText = `Contrat n°${props.contractNumber || '?'}`;
|
|
|
|
this.querySelector('#modal-contract-number').innerText = props.contractNumber || 'SANS NUMÉRO';
|
|
|
|
|
|
|
|
this.querySelector('#modal-title').innerText = event.title;
|
|
|
|
this.querySelector('#modal-title').innerText = event.title;
|
|
|
|
this.querySelector('#modal-client').innerText = props.client;
|
|
|
|
this.querySelector('#modal-client').innerText = props.client || 'Client inconnu';
|
|
|
|
this.querySelector('#modal-email').innerText = props.clientEmail || 'Non renseigné';
|
|
|
|
this.querySelector('#modal-email').innerText = props.clientEmail || 'Non renseigné';
|
|
|
|
this.querySelector('#modal-phone').innerText = props.clientPhone || 'Non renseigné';
|
|
|
|
this.querySelector('#modal-phone').innerText = props.clientPhone || 'Non renseigné';
|
|
|
|
this.querySelector('#modal-adresse').innerText = props.eventAdresse || 'Adresse non spécifiée';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Formatage des dates
|
|
|
|
// Gestion de l'objet adresse spécifique à votre API
|
|
|
|
|
|
|
|
this.querySelector('#modal-adresse').innerText = this.formatAddress(props.eventAdresse);
|
|
|
|
|
|
|
|
|
|
|
|
const dateOptions = { day: 'numeric', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit' };
|
|
|
|
const dateOptions = { day: 'numeric', month: 'long', year: 'numeric', hour: '2-digit', minute: '2-digit' };
|
|
|
|
this.querySelector('#modal-start').innerText = event.start.toLocaleString('fr-FR', dateOptions);
|
|
|
|
|
|
|
|
this.querySelector('#modal-end').innerText = event.end ? event.end.toLocaleString('fr-FR', dateOptions) : '--';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Mise à jour des liens interactifs
|
|
|
|
this.querySelector('#modal-start').innerText = props.start;
|
|
|
|
|
|
|
|
this.querySelector('#modal-end').innerText = props.end;
|
|
|
|
|
|
|
|
|
|
|
|
this.querySelector('#link-phone').href = `tel:${props.clientPhone}`;
|
|
|
|
this.querySelector('#link-phone').href = `tel:${props.clientPhone}`;
|
|
|
|
this.querySelector('#link-email').href = `mailto:${props.clientEmail}`;
|
|
|
|
this.querySelector('#link-email').href = `mailto:${props.clientEmail}`;
|
|
|
|
this.querySelector('#modal-link-contrat').href = props.linkContrat || '#';
|
|
|
|
this.querySelector('#modal-link-contrat').href = props.linkContrat || '#';
|
|
|
|
|
|
|
|
|
|
|
|
// Couleur thématique
|
|
|
|
|
|
|
|
this.querySelector('#modal-contract-number').style.borderColor = event.backgroundColor;
|
|
|
|
this.querySelector('#modal-contract-number').style.borderColor = event.backgroundColor;
|
|
|
|
this.querySelector('#modal-contract-number').style.color = event.backgroundColor;
|
|
|
|
this.querySelector('#modal-contract-number').style.color = event.backgroundColor;
|
|
|
|
|
|
|
|
|
|
|
|
// Génération dynamique des badges de statut
|
|
|
|
|
|
|
|
const statusContainer = this.querySelector('#modal-status-container');
|
|
|
|
const statusContainer = this.querySelector('#modal-status-container');
|
|
|
|
const statusList = [
|
|
|
|
const statusList = [
|
|
|
|
{ label: 'Caution', val: props.caution, color: 'orange', icon: 'M4 4a2 2 0 00-2 2v1h16V6a2 2 0 00-2-2H4z' },
|
|
|
|
{ label: 'Signé', val: props.isSigned, color: 'emerald' },
|
|
|
|
{ label: 'Acompte', val: props.acompte, color: 'blue', icon: 'M4 4a2 2 0 002 2V6h10a2 2 0 00-2-2H4z' },
|
|
|
|
{ label: 'Caution', val: props.caution, color: 'orange' },
|
|
|
|
{ label: 'Solde', val: props.solde, color: 'emerald', icon: 'M5 13l4 4L19 7' }
|
|
|
|
{ label: 'Acompte', val: props.acompte, color: 'blue' },
|
|
|
|
|
|
|
|
{ label: 'Solde', val: props.solde, color: 'emerald' }
|
|
|
|
];
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
statusContainer.innerHTML = statusList.map(s => `
|
|
|
|
statusContainer.innerHTML = statusList.map(s => `
|
|
|
|
|