Files
turf_saas/crm_dashboard_new.html
2026-04-25 17:18:43 +02:00

317 lines
16 KiB
HTML
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>CRM H3R7 - Gestion Prospects</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; background: #1a1a2e; color: #eee; padding: 20px; }
header { background: linear-gradient(90deg, #e94560, #7b2cbf); padding: 20px; text-align: center; margin: -20px -20px 20px; border-radius: 0 0 20px 20px; }
h1 { font-size: 28px; }
.logo { text-align: center; padding: 10px; }
.logo img { width: 100px; border-radius: 10px; }
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin-bottom: 20px; }
.stat-card { background: #16213e; padding: 20px; border-radius: 12px; text-align: center; }
.stat-num { font-size: 32px; font-weight: bold; color: #00d9ff; }
.stat-label { color: #aaa; font-size: 14px; margin-top: 5px; }
.add-form { background: #16213e; padding: 20px; border-radius: 12px; margin-bottom: 20px; }
.add-form h2 { margin-bottom: 15px; color: #fff; }
.form-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
input, select { width: 100%; padding: 12px; margin: 5px 0; background: #0f3460; border: 1px solid #333; border-radius: 8px; color: #fff; }
button { padding: 12px 20px; background: #00d9ff; border: none; border-radius: 8px; color: #000; font-weight: bold; cursor: pointer; }
button:hover { background: #00b8d4; }
.prospects-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 15px; }
.prospect-card { background: #16213e; padding: 15px; border-radius: 12px; border-left: 4px solid #00d9ff; }
.prospect-card.nouveau { border-left-color: #ffd700; }
.prospect-card.qualifie { border-left-color: #00d9ff; }
.prospect-card.proposition { border-left-color: #7b2cbf; }
.prospect-card.gagne { border-left-color: #00ff88; }
.prospect-card.perdu { border-left-color: #e94560; }
.prospect-name { font-size: 18px; font-weight: bold; margin-bottom: 5px; }
.prospect-entreprise { color: #aaa; font-size: 14px; margin-bottom: 10px; }
.prospect-info { font-size: 13px; color: #888; margin: 3px 0; }
.prospect-secteur { background: #7b2cbf; padding: 3px 8px; border-radius: 10px; font-size: 11px; display: inline-block; margin-top: 8px; }
.score { float: right; }
.score-star { color: #ffd700; }
.actions { margin-top: 10px; display: flex; gap: 5px; }
.btn-edit { background: #7b2cbf; color: #fff; padding: 5px 10px; border: none; border-radius: 5px; cursor: pointer; font-size: 12px; }
.btn-delete { background: #e94560; color: #fff; padding: 5px 10px; border: none; border-radius: 5px; cursor: pointer; font-size: 12px; }
.filter-bar { margin-bottom: 15px; display: flex; gap: 10px; }
.filter-btn { padding: 8px 15px; background: #0f3460; border: none; border-radius: 8px; color: #fff; cursor: pointer; }
.filter-btn.active { background: #00d9ff; color: #000; }
.modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); }
.modal.show { display: flex; justify-content: center; align-items: center; }
.modal-content { background: #16213e; padding: 30px; border-radius: 15px; width: 500px; max-width: 90%; }
.modal h2 { margin-bottom: 20px; }
.modal-buttons { display: flex; gap: 10px; margin-top: 20px; }
.btn-cancel { background: #e94560; }
.badge { padding: 3px 8px; border-radius: 5px; font-size: 11px; margin-left: 5px; }
.badge-nouveau { background: #ffd700; color: #000; }
.badge-qualifie { background: #00d9ff; color: #000; }
.badge-proposition { background: #7b2cbf; color: #fff; }
.badge-gagne { background: #00ff88; color: #000; }
.badge-perdu { background: #e94560; color: #fff; }
a { color: #00d9ff; }
.home-btn{position:fixed;top:10px;left:10px;z-index:9999;background:linear-gradient(135deg,#00d9ff,#7b2cbf);color:#fff;border:none;border-radius:8px;padding:10px 15px;font-size:14px;cursor:pointer;text-decoration:none;display:flex;align-items:center;gap:8px;box-shadow:0 2px 10px rgba(0,217,255,0.3);transition:all 0.3s;font-family:-apple-system,BlinkMacSystemFont,sans-serif}.home-btn:hover{transform:translateY(-2px);box-shadow:0 4px 15px rgba(0,217,255,0.5)}
</style>
</head>
<body>
<a href="https://portal-kolifee.duckdns.org/" class="home-btn" title="Retour au portail"><span style="font-size:18px">🏠</span><span>Accueil</span></a>
<div class="logo">
<img src="/turf/H3R7Tech_logo.png" alt="H3R7Tech">
</div>
<header>
<h1>📊 CRM H3R7 - Gestion des Prospects</h1>
</header>
<div class="stats" id="stats">
<div class="stat-card">
<div class="stat-num" id="total-prospects">0</div>
<div class="stat-label">Total Prospects</div>
</div>
<div class="stat-card">
<div class="stat-num" id="nouveaux">0</div>
<div class="stat-label">Nouveaux</div>
</div>
<div class="stat-card">
<div class="stat-num" id="qualifies">0</div>
<div class="stat-label">Qualifiés</div>
</div>
<div class="stat-card">
<div class="stat-num" id="gagnes">0</div>
<div class="stat-label">Gagnés</div>
</div>
</div>
<div class="add-form">
<h2> Nouveau Prospect</h2>
<div class="form-row">
<input type="text" id="nom" placeholder="Nom du contact *">
<input type="text" id="entreprise" placeholder="Entreprise *">
<input type="text" id="secteur" placeholder="Secteur (Artisan, Boulanger, Marketing...)">
</div>
<div class="form-row">
<input type="tel" id="tel" placeholder="Téléphone">
<input type="email" id="email" placeholder="Email">
<select id="source">
<option value="">Source ?</option>
<option value="appeler">Appel téléphonique</option>
<option value="email">Email</option>
<option value="site">Site web</option>
<option value="recommandation">Recommandation</option>
<option value="autre">Autre</option>
</select>
</div>
<button onclick="addProspect()">Ajouter le Prospect</button>
</div>
<div class="filter-bar">
<button class="filter-btn active" onclick="filterProspects('tous')">Tous</button>
<button class="filter-btn" onclick="filterProspects('nouveau')">Nouveau</button>
<button class="filter-btn" onclick="filterProspects('qualifie')">Qualifié</button>
<button class="filter-btn" onclick="filterProspects('proposition')">Proposition</button>
<button class="filter-btn" onclick="filterProspects('gagne')">Gagné</button>
<button class="filter-btn" onclick="filterProspects('perdu')">Perdu</button>
</div>
<div class="prospects-grid" id="prospects-grid">
Chargement...
</div>
<a href="/">← Retour au Portail</a>
<!-- Modal Edit -->
<div class="modal" id="editModal">
<div class="modal-content">
<h2>✏️ Modifier Prospect</h2>
<input type="hidden" id="edit-id">
<div class="form-row">
<input type="text" id="edit-nom" placeholder="Nom">
<input type="text" id="edit-entreprise" placeholder="Entreprise">
<input type="text" id="edit-secteur" placeholder="Secteur">
</div>
<div class="form-row">
<input type="tel" id="edit-tel" placeholder="Téléphone">
<input type="email" id="edit-email" placeholder="Email">
<select id="edit-statut">
<option value="nouveau">Nouveau</option>
<option value="qualifie">Qualifié</option>
<option value="proposition">Proposition</option>
<option value="gagne">Gagné</option>
<option value="perdu">Perdu</option>
</select>
</div>
<textarea id="edit-notes" placeholder="Notes..." rows="3" style="width:100%;padding:12px;margin:5px 0;background:#0f3460;border:1px solid #333;border-radius:8px;color:#fff;"></textarea>
<div class="form-row">
<select id="edit-score">
<option value="0">Score: 0</option>
<option value="1">Score: ⭐</option>
<option value="2">Score: ⭐⭐</option>
<option value="3">Score: ⭐⭐⭐</option>
<option value="4">Score: ⭐⭐⭐⭐</option>
<option value="5">Score: ⭐⭐⭐⭐⭐</option>
</select>
</div>
<div class="modal-buttons">
<button onclick="saveEdit()">💾 Sauvegarder</button>
<button class="btn-cancel" onclick="closeModal()">Annuler</button>
</div>
</div>
</div>
<script>
const API = '/crm/api/prospects';
let allProspects = [];
let currentFilter = 'tous';
function loadProspects() {
fetch(API)
.then(r => r.json())
.then(data => {
allProspects = data.prospects || [];
updateStats();
renderProspects();
});
}
function updateStats() {
document.getElementById('total-prospects').textContent = allProspects.length;
document.getElementById('nouveaux').textContent = allProspects.filter(p => p.status === 'nouveau').length;
document.getElementById('qualifies').textContent = allProspects.filter(p => p.status === 'qualifie' || p.status === 'proposition').length;
document.getElementById('gagnes').textContent = allProspects.filter(p => p.status === 'gagne').length;
}
function renderProspects() {
let prospects = allProspects;
if (currentFilter !== 'tous') {
prospects = allProspects.filter(p => p.status === currentFilter);
}
const grid = document.getElementById('prospects-grid');
if (prospects.length === 0) {
grid.innerHTML = '<div style="grid-column:1/-1;text-align:center;color:#666;padding:40px;">Aucun prospect</div>';
return;
}
grid.innerHTML = prospects.map(p => {
return '<div class="prospect-card ' + p.status + '">' +
'<span class="score">' + '⭐'.repeat(p.score || 0) + '</span>' +
'<div class="prospect-name">' + (p.nom || '') + '</div>' +
'<div class="prospect-entreprise">' + (p.entreprise || '') + '</div>' +
'<div class="prospect-info">📞 ' + (p.tel || '-') + '</div>' +
'<div class="prospect-info">✉️ ' + (p.email || '-') + '</div>' +
'<div class="prospect-info">📅 ' + (p.created ? p.created.substring(0,10) : '-') + '</div>' +
'<span class="prospect-secteur">' + (p.secteur || 'Autre') + '</span>' +
'<span class="badge badge-' + p.status + '">' + p.status + '</span>' +
'<div class="actions">' +
'<button class="btn-edit" onclick="openEdit(' + p.id + ')">✏️</button>' +
'<button class="btn-delete" onclick="deleteProspect(' + p.id + ')">🗑️</button>' +
'</div></div>';
}).join('');
}
function addProspect() {
const nom = document.getElementById('nom').value;
const entreprise = document.getElementById('entreprise').value;
if (!nom || !entreprise) {
alert('Nom et entreprise requis!');
return;
}
fetch(API, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
nom: nom,
entreprise: entreprise,
secteur: document.getElementById('secteur').value,
tel: document.getElementById('tel').value,
email: document.getElementById('email').value,
source: document.getElementById('source').value,
statut: 'nouveau',
score: 0
})
}).then(() => {
document.getElementById('nom').value = '';
document.getElementById('entreprise').value = '';
document.getElementById('secteur').value = '';
document.getElementById('tel').value = '';
document.getElementById('email').value = '';
loadProspects();
});
}
function openEdit(id) {
const p = allProspects.find(x => x.id === id);
if (!p) return;
document.getElementById('edit-id').value = id;
document.getElementById('edit-nom').value = p.nom || '';
document.getElementById('edit-entreprise').value = p.entreprise || '';
document.getElementById('edit-secteur').value = p.secteur || '';
document.getElementById('edit-tel').value = p.tel || '';
document.getElementById('edit-email').value = p.email || '';
document.getElementById('edit-statut').value = p.status || 'nouveau';
document.getElementById('edit-notes').value = p.notes || '';
document.getElementById('edit-score').value = p.score || 0;
document.getElementById('editModal').classList.add('show');
}
function closeModal() {
document.getElementById('editModal').classList.remove('show');
}
function saveEdit() {
const id = parseInt(document.getElementById('edit-id').value);
fetch(API + '/' + id, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
nom: document.getElementById('edit-nom').value,
entreprise: document.getElementById('edit-entreprise').value,
secteur: document.getElementById('edit-secteur').value,
tel: document.getElementById('edit-tel').value,
email: document.getElementById('edit-email').value,
statut: document.getElementById('edit-statut').value,
notes: document.getElementById('edit-notes').value,
score: parseInt(document.getElementById('edit-score').value)
})
}).then(() => {
closeModal();
loadProspects();
});
}
function deleteProspect(id) {
if (!confirm('Supprimer ce prospect?')) return;
fetch(API + '/' + id, { method: 'DELETE' })
.then(() => loadProspects());
}
function filterProspects(filter) {
currentFilter = filter;
document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
event.target.classList.add('active');
renderProspects();
}
loadProspects();
</script>
</body>
</html>