| <!DOCTYPE html> |
| <html lang="fr"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>CRM - ComSync Pro</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <script src="https://unpkg.com/feather-icons"></script> |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> |
| <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.net.min.js"></script> |
| <link rel="stylesheet" href="style.css"> |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> |
| <style> |
| body { font-family: 'Inter', sans-serif; } |
| .crm-card { |
| background: rgba(31, 41, 55, 0.7); |
| backdrop-filter: blur(20px); |
| border: 1px solid rgba(75, 85, 99, 0.4); |
| transition: all 0.3s ease; |
| } |
| .crm-card:hover { |
| background: rgba(31, 41, 55, 0.85); |
| border-color: rgba(75, 85, 99, 0.6); |
| transform: translateY(-2px); |
| box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); |
| } |
| .status-dot { |
| width: 10px; |
| height: 10px; |
| border-radius: 50%; |
| border: 2px solid #1f2937; |
| } |
| .status-online { background: #10b981; } |
| .status-offline { background: #ef4444; } |
| .status-busy { background: #f59e0b; } |
| .contact-row { |
| transition: all 0.2s ease; |
| } |
| .contact-row:hover { |
| background: rgba(55, 65, 81, 0.5); |
| } |
| .action-btn { |
| transition: all 0.2s; |
| } |
| .action-btn:hover { |
| transform: scale(1.1); |
| } |
| .pipeline-bar { |
| height: 8px; |
| border-radius: 4px; |
| background: #374151; |
| overflow: hidden; |
| } |
| .pipeline-fill { |
| height: 100%; |
| border-radius: 4px; |
| transition: width 0.5s ease; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-900 text-gray-100 overflow-x-hidden"> |
| <div id="vanta-bg" class="fixed inset-0 z-0"></div> |
| <script src="components/navbar.js"></script> |
| <custom-navbar></custom-navbar> |
|
|
| <main class="relative z-10 max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8"> |
| |
| <div class="mb-8 slide-in-bottom"> |
| <div class="flex flex-col md:flex-row md:items-center justify-between gap-4"> |
| <div> |
| <h2 class="text-3xl font-bold text-white mb-2">CRM - Relations & Équipes</h2> |
| <p class="text-gray-400">Gérez vos contacts, équipes et missions clients</p> |
| </div> |
| <div class="flex items-center gap-3"> |
| <div class="bg-gray-700/50 rounded-xl p-2 flex items-center space-x-3"> |
| <i data-feather="search" class="w-5 h-5 text-gray-400 ml-2"></i> |
| <input type="text" id="crmSearch" class="bg-transparent border-none text-white text-sm focus:outline-none w-48" placeholder="Rechercher contact..."> |
| </div> |
| <button onclick="openAddContactModal()" class="btn-primary flex items-center"> |
| <i data-feather="plus" class="w-4 h-4 mr-2"></i> |
| Ajouter Contact |
| </button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8"> |
| <div class="metric-card glass-card rounded-xl p-6"> |
| <div class="flex items-center justify-between mb-4"> |
| <div class="p-3 bg-blue-900/30 rounded-xl"> |
| <i data-feather="users" class="w-6 h-6 text-blue-400"></i> |
| </div> |
| <span class="text-green-400 text-sm">+5 cette semaine</span> |
| </div> |
| <p class="text-3xl font-bold text-white" id="stat-contacts">42</p> |
| <p class="text-gray-400">Contacts</p> |
| </div> |
| <div class="metric-card glass-card rounded-xl p-6"> |
| <div class="flex items-center justify-between mb-4"> |
| <div class="p-3 bg-purple-900/30 rounded-xl"> |
| <i data-feather="briefcase" class="w-6 h-6 text-purple-400"></i> |
| </div> |
| <span class="text-yellow-400 text-sm">3 en négociation</span> |
| </div> |
| <p class="text-3xl font-bold text-white" id="stat-deals">12</p> |
| <p class="text-gray-400">Contrats Actifs</p> |
| </div> |
| <div class="metric-card glass-card rounded-xl p-6"> |
| <div class="flex items-center justify-between mb-4"> |
| <div class="p-3 bg-green-900/30 rounded-xl"> |
| <i data-feather="target" class="w-6 h-6 text-green-400"></i> |
| </div> |
| <span class="text-green-400 text-sm">87% taux</span> |
| </div> |
| <p class="text-3xl font-bold text-white" id="stat-missions">8</p> |
| <p class="text-gray-400">Missions en Cours</p> |
| </div> |
| <div class="metric-card glass-card rounded-xl p-6"> |
| <div class="flex items-center justify-between mb-4"> |
| <div class="p-3 bg-orange-900/30 rounded-xl"> |
| <i data-feather="clock" class="w-6 h-6 text-orange-400"></i> |
| </div> |
| <span class="text-gray-400 text-sm">Ce mois</span> |
| </div> |
| <p class="text-3xl font-bold text-white">156h</p> |
| <p class="text-gray-400">Heures Facturées</p> |
| </div> |
| </div> |
|
|
| |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> |
| |
| <div class="lg:col-span-2 space-y-6"> |
| |
| <div class="glass-card rounded-xl p-4 flex flex-wrap gap-3"> |
| <button onclick="filterContacts('all')" class="px-4 py-2 bg-blue-600 rounded-lg text-sm font-medium text-white">Tous</button> |
| <button onclick="filterContacts('client')" class="px-4 py-2 bg-gray-700/50 rounded-lg text-sm font-medium text-gray-300 hover:bg-gray-700">Clients</button> |
| <button onclick="filterContacts('team')" class="px-4 py-2 bg-gray-700/50 rounded-lg text-sm font-medium text-gray-300 hover:bg-gray-700">Équipe</button> |
| <button onclick="filterContacts('provider')" class="px-4 py-2 bg-gray-700/50 rounded-lg text-sm font-medium text-gray-300 hover:bg-gray-700">Fournisseurs</button> |
| <button onclick="filterContacts('online')" class="px-4 py-2 bg-gray-700/50 rounded-lg text-sm font-medium text-gray-300 hover:bg-gray-700 flex items-center gap-2"> |
| <span class="w-2 h-2 bg-green-500 rounded-full"></span> En ligne |
| </button> |
| </div> |
|
|
| |
| <div class="glass-card rounded-xl overflow-hidden" id="contacts-container"> |
| <div class="p-6 border-b border-gray-700/50 flex items-center justify-between"> |
| <h3 class="text-xl font-semibold text-white flex items-center"> |
| <i data-feather="users" class="w-5 h-5 mr-3 text-blue-400"></i> |
| Annuaire |
| </h3> |
| <span class="text-sm text-gray-400" id="contacts-count">42 contacts</span> |
| </div> |
| <div id="contacts-list" class="divide-y divide-gray-700/50"> |
| |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="space-y-6"> |
| |
| <div class="glass-card rounded-xl p-6"> |
| <h3 class="text-xl font-semibold text-white mb-4 flex items-center"> |
| <i data-feather="zap" class="w-5 h-5 mr-3 text-yellow-400"></i> |
| Actions Rapides |
| </h3> |
| <div class="grid grid-cols-2 gap-3"> |
| <button onclick="quickAction('mission')" class="p-4 bg-blue-600/20 hover:bg-blue-600/30 rounded-xl border border-blue-500/30 transition-all group text-center"> |
| <i data-feather="target" class="w-6 h-6 text-blue-400 mb-2 mx-auto"></i> |
| <p class="text-sm font-medium text-blue-400">Nouvelle Mission</p> |
| </button> |
| <button onclick="quickAction('deal')" class="p-4 bg-purple-600/20 hover:bg-purple-600/30 rounded-xl border border-purple-500/30 transition-all group text-center"> |
| <i data-feather="file-text" class="w-6 h-6 text-purple-400 mb-2 mx-auto"></i> |
| <p class="text-sm font-medium text-purple-400">Nouveau Contrat</p> |
| </button> |
| <button onclick="quickAction('quote')" class="p-4 bg-green-600/20 hover:bg-green-600/30 rounded-xl border border-green-500/30 transition-all group text-center"> |
| <i data-feather="dollar-sign" class="w-6 h-6 text-green-400 mb-2 mx-auto"></i> |
| <p class="text-sm font-medium text-green-400">Devis</p> |
| </button> |
| <button onclick="quickAction('invoice')" class="p-4 bg-orange-600/20 hover:bg-orange-600/30 rounded-xl border border-orange-500/30 transition-all group text-center"> |
| <i data-feather="credit-card" class="w-6 h-6 text-orange-400 mb-2 mx-auto"></i> |
| <p class="text-sm font-medium text-orange-400">Facture</p> |
| </button> |
| </div> |
| </div> |
|
|
| |
| <div class="glass-card rounded-xl p-6"> |
| <h3 class="text-xl font-semibold text-white mb-4 flex items-center"> |
| <i data-feather="trending-up" class="w-5 h-5 mr-3 text-green-400"></i> |
| Pipeline Missions |
| </h3> |
| <div class="space-y-4"> |
| <div> |
| <div class="flex justify-between text-sm mb-1"> |
| <span class="text-gray-300">Prospection</span> |
| <span class="text-blue-400">4</span> |
| </div> |
| <div class="pipeline-bar"> |
| <div class="pipeline-fill bg-blue-500" style="width: 20%"></div> |
| </div> |
| </div> |
| <div> |
| <div class="flex justify-between text-sm mb-1"> |
| <span class="text-gray-300">Proposition</span> |
| <span class="text-yellow-400">3</span> |
| </div> |
| <div class="pipeline-bar"> |
| <div class="pipeline-fill bg-yellow-500" style="width: 35%"></div> |
| </div> |
| </div> |
| <div> |
| <div class="flex justify-between text-sm mb-1"> |
| <span class="text-gray-300">Négociation</span> |
| <span class="text-orange-400">2</span> |
| </div> |
| <div class="pipeline-bar"> |
| <div class="pipeline-fill bg-orange-500" style="width: 50%"></div> |
| </div> |
| </div> |
| <div> |
| <div class="flex justify-between text-sm mb-1"> |
| <span class="text-gray-300">Mission Active</span> |
| <span class="text-green-400">8</span> |
| </div> |
| <div class="pipeline-bar"> |
| <div class="pipeline-fill bg-green-500" style="width: 80%"></div> |
| </div> |
| </div> |
| <div> |
| <div class="flex justify-between text-sm mb-1"> |
| <span class="text-gray-300">Terminée</span> |
| <span class="text-purple-400">24</span> |
| </div> |
| <div class="pipeline-bar"> |
| <div class="pipeline-fill bg-purple-500" style="width: 95%"></div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="glass-card rounded-xl p-6"> |
| <h3 class="text-xl font-semibold text-white mb-4 flex items-center"> |
| <i data-feather="activity" class="w-5 h-5 mr-3 text-purple-400"></i> |
| Activité CRM |
| </h3> |
| <div class="space-y-3" id="crm-activity"> |
| <div class="flex items-start gap-3 p-3 bg-gray-700/30 rounded-lg"> |
| <div class="w-2 h-2 bg-blue-500 rounded-full mt-2 shrink-0"></div> |
| <div> |
| <p class="text-sm text-white">Nouveau contrat signé — <span class="text-gray-400">SecurEvent SAS</span></p> |
| <p class="text-xs text-gray-500">il y a 12 min</p> |
| </div> |
| </div> |
| <div class="flex items-start gap-3 p-3 bg-gray-700/30 rounded-lg"> |
| <div class="w-2 h-2 bg-green-500 rounded-full mt-2 shrink-0"></div> |
| <div> |
| <p class="text-sm text-white">Mission "Surveillance Secteur 7" démarrée</p> |
| <p class="text-xs text-gray-500">il y a 45 min</p> |
| </div> |
| </div> |
| <div class="flex items-start gap-3 p-3 bg-gray-700/30 rounded-lg"> |
| <div class="w-2 h-2 bg-yellow-500 rounded-full mt-2 shrink-0"></div> |
| <div> |
| <p class="text-sm text-white">Devis envoyé — <span class="text-gray-400">Logistique Nord</span></p> |
| <p class="text-xs text-gray-500">il y a 2h</p> |
| </div> |
| </div> |
| <div class="flex items-start gap-3 p-3 bg-gray-700/30 rounded-lg"> |
| <div class="w-2 h-2 bg-purple-500 rounded-full mt-2 shrink-0"></div> |
| <div> |
| <p class="text-sm text-white">Nouveau contact ajouté — <span class="text-gray-400">Ahmed B.</span></p> |
| <p class="text-xs text-gray-500">il y a 3h</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </main> |
|
|
| |
| <div id="add-contact-modal" class="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 hidden flex items-center justify-center p-4"> |
| <div class="bg-gray-800 rounded-xl max-w-lg w-full border border-gray-700 shadow-2xl"> |
| <div class="p-6 border-b border-gray-700 flex justify-between items-center"> |
| <h2 class="text-xl font-semibold">Ajouter un Contact</h2> |
| <button onclick="closeAddContactModal()" class="text-gray-400 hover:text-white"> |
| <i data-feather="x" class="w-6 h-6"></i> |
| </button> |
| </div> |
| <div class="p-6 space-y-4"> |
| <div class="grid grid-cols-2 gap-4"> |
| <div> |
| <label class="block text-sm font-medium mb-2">Type *</label> |
| <select id="contact-type" class="w-full bg-gray-700 rounded-lg px-3 py-2 border border-gray-600 text-white"> |
| <option value="client">Client</option> |
| <option value="team">Équipe</option> |
| <option value="provider">Fournisseur</option> |
| </select> |
| </div> |
| <div> |
| <label class="block text-sm font-medium mb-2">Statut</label> |
| <select id="contact-status" class="w-full bg-gray-700 rounded-lg px-3 py-2 border border-gray-600 text-white"> |
| <option value="online">En ligne</option> |
| <option value="offline">Hors ligne</option> |
| <option value="busy">Occupé</option> |
| </select> |
| </div> |
| </div> |
| <div class="grid grid-cols-2 gap-4"> |
| <div> |
| <label class="block text-sm font-medium mb-2">Prénom *</label> |
| <input type="text" id="contact-firstname" class="w-full bg-gray-700 rounded-lg px-3 py-2 border border-gray-600 text-white" placeholder="Prénom"> |
| </div> |
| <div> |
| <label class="block text-sm font-medium mb-2">Nom *</label> |
| <input type="text" id="contact-lastname" class="w-full bg-gray-700 rounded-lg px-3 py-2 border border-gray-600 text-white" placeholder="Nom"> |
| </div> |
| </div> |
| <div> |
| <label class="block text-sm font-medium mb-2">Email</label> |
| <input type="email" id="contact-email" class="w-full bg-gray-700 rounded-lg px-3 py-2 border border-gray-600 text-white" placeholder="email@entreprise.com"> |
| </div> |
| <div> |
| <label class="block text-sm font-medium mb-2">Téléphone</label> |
| <input type="tel" id="contact-phone" class="w-full bg-gray-700 rounded-lg px-3 py-2 border border-gray-600 text-white" placeholder="+33 6 12 34 56 78"> |
| </div> |
| <div> |
| <label class="block text-sm font-medium mb-2">Entreprise / Rôle</label> |
| <input type="text" id="contact-role" class="w-full bg-gray-700 rounded-lg px-3 py-2 border border-gray-600 text-white" placeholder="Ex: Sécurité Plus SA — Chef d'équipe"> |
| </div> |
| </div> |
| <div class="p-6 border-t border-gray-700 flex justify-end space-x-3"> |
| <button onclick="closeAddContactModal()" class="btn-secondary">Annuler</button> |
| <button onclick="saveContact()" class="btn-primary">Enregistrer</button> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| |
| let contacts = [ |
| { id: 'C001', type: 'team', firstname: 'John', lastname: 'Smith', email: 'j.smith@comsync.pro', phone: '+33 6 12 34 56 78', role: 'Opérations — Secteur 7', status: 'online', lastSeen: 'Actif' }, |
| { id: 'C002', type: 'team', firstname: 'Maria', lastname: 'Garcia', email: 'm.garcia@comsync.pro', phone: '+33 6 23 45 67 89', role: 'Logistique — Base', status: 'online', lastSeen: 'Actif' }, |
| { id: 'C003', type: 'client', firstname: 'Pierre', lastname: 'Dubois', email: 'p.dubois@secur-event.fr', phone: '+33 1 42 56 78 90', role: 'SecurEvent SAS — Directeur', status: 'offline', lastSeen: 'il y a 2h' }, |
| { id: 'C004', type: 'team', firstname: 'Ahmed', lastname: 'Benjelloun', email: 'a.benjelloun@comsync.pro', phone: '+33 6 34 56 78 90', role: 'Sécurité — Périmètre', status: 'busy', lastSeen: 'En mission' }, |
| { id: 'C005', type: 'client', firstname: 'Sophie', lastname: 'Laurent', email: 's.laurent@log-nord.fr', phone: '+33 3 20 45 67 89', role: 'Logistique Nord — Responsable', status: 'offline', lastSeen: 'il y a 5h' }, |
| { id: 'C006', type: 'provider', firstname: 'Thomas', lastname: 'Bernard', email: 't.bernard@radiopro.fr', phone: '+33 4 91 23 45 67', role: 'RadioPro — Technicien', status: 'online', lastSeen: 'Actif' }, |
| { id: 'C007', type: 'team', firstname: 'Robert', lastname: 'Johnson', email: 'r.johnson@comsync.pro', phone: '+33 6 45 67 89 01', role: 'Support — Secteur 3', status: 'offline', lastSeen: 'il y a 1h' }, |
| { id: 'C008', type: 'client', firstname: 'Claire', lastname: 'Moreau', email: 'c.moreau@industech.fr', phone: '+33 2 40 12 34 56', role: 'Industech — Sécurité', status: 'online', lastSeen: 'Actif' } |
| ]; |
| |
| let currentFilter = 'all'; |
| |
| function renderContacts() { |
| const list = document.getElementById('contacts-list'); |
| const searchVal = document.getElementById('crmSearch').value.toLowerCase(); |
| let filtered = contacts; |
| |
| if (currentFilter !== 'all') { |
| if (currentFilter === 'online') { |
| filtered = contacts.filter(c => c.status === 'online'); |
| } else { |
| filtered = contacts.filter(c => c.type === currentFilter); |
| } |
| } |
| |
| if (searchVal) { |
| filtered = filtered.filter(c => |
| (c.firstname + ' ' + c.lastname).toLowerCase().includes(searchVal) || |
| c.role.toLowerCase().includes(searchVal) || |
| c.email.toLowerCase().includes(searchVal) |
| ); |
| } |
| |
| document.getElementById('contacts-count').textContent = filtered.length + ' contact(s)'; |
| |
| if (filtered.length === 0) { |
| list.innerHTML = '<div class="p-8 text-center text-gray-500">Aucun contact trouvé</div>'; |
| feather.replace(); |
| return; |
| } |
| |
| list.innerHTML = filtered.map(c => ` |
| <div class="contact-row flex items-center gap-4 p-4 cursor-pointer group"> |
| <div class="relative shrink-0"> |
| <div class="w-12 h-12 bg-gradient-to-r from-blue-500 to-purple-600 rounded-full flex items-center justify-center text-white font-bold text-sm"> |
| ${c.firstname[0]}${c.lastname[0]} |
| </div> |
| <div class="absolute -bottom-1 -right-1 w-3.5 h-3.5 rounded-full border-2 border-gray-800 ${c.status === 'online' ? 'bg-green-500' : c.status === 'busy' ? 'bg-yellow-500' : 'bg-red-500'}"></div> |
| </div> |
| <div class="flex-1 min-w-0"> |
| <div class="flex items-center gap-2 mb-0.5"> |
| <h4 class="text-white font-medium truncate">${c.firstname} ${c.lastname}</h4> |
| <span class="text-xs px-2 py-0.5 rounded-full ${c.type === 'client' ? 'bg-blue-900/30 text-blue-400' : c.type === 'team' ? 'bg-green-900/30 text-green-400' : 'bg-purple-900/30 text-purple-400'}">${c.type}</span> |
| </div> |
| <p class="text-sm text-gray-400 truncate">${c.role}</p> |
| <div class="flex items-center gap-3 mt-1 text-xs text-gray-500"> |
| <span class="flex items-center gap-1"><i data-feather="mail" class="w-3 h-3"></i> ${c.email}</span> |
| <span class="flex items-center gap-1"><i data-feather="phone" class="w-3 h-3"></i> ${c.phone}</span> |
| </div> |
| </div> |
| <div class="flex items-center gap-2 opacity-0 group-hover:opacity-100 transition-opacity shrink-0"> |
| <button onclick="event.stopPropagation(); callContact('${c.id}')" class="action-btn p-2 bg-blue-600 rounded-lg hover:bg-blue-700" title="Appeler"> |
| <i data-feather="phone" class="w-4 h-4"></i> |
| </button> |
| <button onclick="event.stopPropagation(); messageContact('${c.id}')" class="action-btn p-2 bg-green-600 rounded-lg hover:bg-green-700" title="Message"> |
| <i data-feather="message-square" class="w-4 h-4"></i> |
| </button> |
| <button onclick="event.stopPropagation(); locateContact('${c.id}')" class="action-btn p-2 bg-purple-600 rounded-lg hover:bg-purple-700" title="Localiser"> |
| <i data-feather="map-pin" class="w-4 h-4"></i> |
| </button> |
| </div> |
| <div class="text-right shrink-0 min-w-[80px]"> |
| <p class="text-xs ${c.status === 'online' ? 'text-green-400' : c.status === 'busy' ? 'text-yellow-400' : 'text-gray-500'} capitalize">${c.status}</p> |
| <p class="text-xs text-gray-500">${c.lastSeen}</p> |
| </div> |
| </div> |
| `).join(''); |
| |
| feather.replace(); |
| } |
| |
| function filterContacts(type) { |
| currentFilter = type; |
| |
| document.querySelectorAll('#contacts-container button').forEach(btn => { |
| btn.classList.remove('bg-blue-600', 'text-white'); |
| btn.classList.add('bg-gray-700/50', 'text-gray-300'); |
| }); |
| event.target.classList.remove('bg-gray-700/50', 'text-gray-300'); |
| event.target.classList.add('bg-blue-600', 'text-white'); |
| renderContacts(); |
| } |
| |
| function callContact(id) { |
| const c = contacts.find(x => x.id === id); |
| alert(`📞 Appel vers ${c.firstname} ${c.lastname}\n${c.phone}`); |
| } |
| function messageContact(id) { |
| const c = contacts.find(x => x.id === id); |
| alert(`💬 Message rapide à ${c.firstname} ${c.lastname}\nEmail: ${c.email}`); |
| } |
| function locateContact(id) { |
| const c = contacts.find(x => x.id === id); |
| alert(`📍 Localisation de ${c.firstname} ${c.lastname}\nDernière position: Base Camp`); |
| } |
| function quickAction(type) { |
| const labels = { mission: 'Nouvelle Mission', deal: 'Nouveau Contrat', quote: 'Nouveau Devis', invoice: 'Nouvelle Facture' }; |
| alert(`${labels[type]}\n\nCette action ouvrirait le formulaire complet dans une implementation complète.`); |
| } |
| |
| function openAddContactModal() { |
| document.getElementById('add-contact-modal').classList.remove('hidden'); |
| } |
| function closeAddContactModal() { |
| document.getElementById('add-contact-modal').classList.add('hidden'); |
| } |
| function saveContact() { |
| const type = document.getElementById('contact-type').value; |
| const status = document.getElementById('contact-status').value; |
| const firstname = document.getElementById('contact-firstname').value.trim(); |
| const lastname = document.getElementById('contact-lastname').value.trim(); |
| if (!firstname || !lastname) { alert('Veuillez remplir le prénom et le nom'); return; } |
| contacts.unshift({ |
| id: 'C' + Date.now().toString().slice(-3), |
| type, |
| status, |
| firstname, |
| lastname, |
| email: document.getElementById('contact-email').value || '-', |
| phone: document.getElementById('contact-phone').value || '-', |
| role: document.getElementById('contact-role').value || '-', |
| lastSeen: 'À l\'instant' |
| }); |
| closeAddContactModal(); |
| renderContacts(); |
| alert('Contact ajouté avec succès !'); |
| } |
| |
| |
| document.getElementById('crmSearch').addEventListener('input', renderContacts); |
| |
| |
| if (typeof VANTA !== 'undefined') { |
| VANTA.NET({ |
| el: "#vanta-bg", |
| mouseControls: true, touchControls: true, gyroControls: false, |
| minHeight: 200, minWidth: 200, scale: 1, scaleMobile: 1, |
| color: 0x3b82f6, backgroundColor: 0x111827, |
| points: 10, maxDistance: 22, spacing: 18 |
| }); |
| } |
| |
| feather.replace(); |
| renderContacts(); |
| </script> |
| </body> |
| </html> |