📊 MELAVAH PRO ADMIN

👥 Total Pros inscrits
0
💰 Revenus confirmés
0 FCFA
📜 Total paiements
0
🪪 Pièces fournies
0
Professionnel
Téléphone
Ville
Total payé
Paiements
Pièce
Actions
Chargement...
En attente
0
Confirmés
0
Refusés
0
💵 Total à valider
0 FCFA
Chargement...

Détails

❌ Refuser ce paiement

Indiquez la raison du refus. Le pro sera informé et le montant sera déduit de son total payé.

voici le code dans l'espace pro, ajoute ceux de l'etape 4 et donne moi le code final. <!-- ========== MELAVAH PRO - TABLEAU DE BORD ADMIN COMPLET ========== -->

<style>

@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@300;400;500;600;700;800;900&family=Montserrat:wght@700;800;900&display=swap');

:root{

--ad-navy:#082B4D; --ad-blue:#0F3E68; --ad-blue2:#175A8A;

--ad-coral:#E89171; --ad-coral-light:#F5B89E;

--ad-bg:#F0F4F8; --ad-cream:#FAF7F4;

--ad-text:#14263A; --ad-muted:#6B7585;

--ad-green:#10B981; --ad-red:#E74C3C;

--ad-orange:#F59E0B; --ad-purple:#8B5CF6;

--ad-info:#3B82F6;

}

.ad-page,.ad-page *{box-sizing:border-box;}

.ad-page{

font-family:'DM Sans',Arial,sans-serif;

background:var(--ad-bg); color:var(--ad-text);

min-height:100vh; padding:30px 3%;

}

/* LOGIN */

.ad-login-wrap{

max-width:420px; margin:80px auto; background:#fff;

border-radius:24px; padding:40px; text-align:center;

box-shadow:0 25px 70px rgba(8,43,77,.15);

}

.ad-login-wrap h1{font-family:'Montserrat',sans-serif;font-size:24px;color:var(--ad-blue);margin:0 0 8px;}

.ad-login-wrap p{color:var(--ad-muted);font-size:14px;margin:0 0 24px;}

.ad-login-wrap input{width:100%;padding:14px 18px;border:1.5px solid rgba(15,62,104,.15);border-radius:12px;font-size:15px;font-family:'DM Sans',sans-serif;margin-bottom:14px;outline:none;}

.ad-login-wrap input:focus{border-color:var(--ad-coral);}

.ad-login-wrap button{width:100%;padding:14px;border:0;border-radius:50px;background:linear-gradient(135deg,var(--ad-blue),var(--ad-coral));color:#fff;font-weight:900;font-size:15px;cursor:pointer;font-family:'DM Sans',sans-serif;}

/* HEADER */

.ad-header{

max-width:1400px; margin:0 auto 24px; background:#fff;

border-radius:18px; padding:20px 28px; display:flex;

justify-content:space-between; align-items:center;

box-shadow:0 8px 25px rgba(8,43,77,.07); flex-wrap:wrap; gap:14px;

}

.ad-header h1{font-family:'Montserrat',sans-serif;font-size:22px;color:var(--ad-blue);margin:0;font-weight:900;}

.ad-header .badge-admin{display:inline-block;margin-left:10px;padding:4px 12px;background:var(--ad-coral);color:#fff;border-radius:50px;font-size:11px;font-weight:900;letter-spacing:1px;}

.ad-header-actions{display:flex;gap:10px;}

.ad-btn-reload{padding:10px 18px;border:0;border-radius:50px;background:var(--ad-blue);color:#fff;font-weight:800;font-size:13px;cursor:pointer;font-family:'DM Sans',sans-serif;}

.ad-btn-logout{padding:10px 18px;border:1.5px solid var(--ad-red);background:transparent;color:var(--ad-red);border-radius:50px;font-weight:800;font-size:13px;cursor:pointer;font-family:'DM Sans',sans-serif;}

/* TABS PRINCIPAUX */

.ad-main-tabs{

max-width:1400px; margin:0 auto 20px;

display:flex; gap:8px; background:#fff;

padding:8px; border-radius:14px;

box-shadow:0 6px 20px rgba(8,43,77,.05);

}

.ad-main-tab{

flex:1; padding:14px 18px; border:0; background:transparent;

border-radius:10px; font-family:'DM Sans',sans-serif;

font-weight:900; font-size:13px; cursor:pointer;

color:var(--ad-muted); transition:.3s;

display:flex; align-items:center; justify-content:center; gap:8px;

}

.ad-main-tab.active{

background:linear-gradient(135deg,var(--ad-blue),var(--ad-coral));

color:#fff; box-shadow:0 6px 18px rgba(15,62,104,.2);

}

.ad-tab-badge{

background:var(--ad-red); color:#fff;

padding:2px 8px; border-radius:50px;

font-size:11px; font-weight:900;

min-width:22px; text-align:center;

}

/* STATS */

.ad-stats{

max-width:1400px; margin:0 auto 24px; display:grid;

grid-template-columns:repeat(auto-fit,minmax(200px,1fr)); gap:16px;

}

.ad-stat{

background:#fff; border-radius:16px; padding:22px;

box-shadow:0 8px 25px rgba(8,43,77,.07);

border-left:4px solid var(--ad-blue);

}

.ad-stat.green{border-color:var(--ad-green);}

.ad-stat.orange{border-color:var(--ad-orange);}

.ad-stat.purple{border-color:var(--ad-purple);}

.ad-stat.info{border-color:var(--ad-info);}

.ad-stat.red{border-color:var(--ad-red);}

.ad-stat small{display:block;font-size:11px;font-weight:900;color:var(--ad-muted);text-transform:uppercase;letter-spacing:1px;margin-bottom:8px;}

.ad-stat .value{font-family:'Montserrat',sans-serif;font-size:28px;font-weight:900;color:var(--ad-blue);line-height:1;}

.ad-stat .icon{font-size:24px;margin-bottom:8px;display:block;}

/* FILTRES */

.ad-filters{

max-width:1400px; margin:0 auto 20px; background:#fff;

border-radius:14px; padding:16px; display:flex; gap:10px;

flex-wrap:wrap; align-items:center;

box-shadow:0 6px 20px rgba(8,43,77,.05);

}

.ad-filters input,.ad-filters select{

padding:10px 14px; border:1.5px solid rgba(15,62,104,.12);

border-radius:10px; font-family:'DM Sans',sans-serif;

font-size:13px; outline:none;

}

.ad-filters input{flex:1;min-width:200px;}

/* TABLE PROS */

.ad-pros-wrap{

max-width:1400px; margin:0 auto; background:#fff;

border-radius:16px; overflow:hidden;

box-shadow:0 8px 25px rgba(8,43,77,.07);

}

.ad-pros-list{overflow-x:auto;}

.ad-pro-row{

display:grid; grid-template-columns:60px 1fr 140px 130px 90px 90px 130px 90px;

gap:14px; padding:14px 20px; align-items:center;

border-bottom:1px solid rgba(15,62,104,.06); font-size:13px;

}

.ad-pro-row:nth-child(odd){background:#FAFAFB;}

.ad-pro-row.header{background:var(--ad-blue) !important;color:#fff;font-weight:900;font-size:12px;text-transform:uppercase;letter-spacing:.8px;border-bottom:0;}

.ad-pro-avatar{

width:46px; height:46px; border-radius:50%; overflow:hidden;

background:linear-gradient(135deg,var(--ad-blue),var(--ad-coral));

display:flex; align-items:center; justify-content:center;

color:#fff; font-size:18px;

}

.ad-pro-avatar img{width:100%;height:100%;object-fit:cover;}

.ad-pro-info strong{display:block;font-size:14px;color:var(--ad-text);margin-bottom:3px;font-weight:800;}

.ad-pro-info small{display:block;font-size:11.5px;color:var(--ad-muted);}

.ad-pro-skills{display:flex;flex-wrap:wrap;gap:4px;}

.ad-skill-tag{font-size:10.5px;padding:2px 8px;border-radius:50px;background:rgba(15,62,104,.10);color:var(--ad-blue);font-weight:700;}

.ad-pro-amount{font-family:'Montserrat',sans-serif;font-weight:900;color:var(--ad-green);font-size:14px;}

.ad-pro-actions{display:flex;gap:6px;flex-wrap:wrap;}

.ad-action-btn{padding:6px 10px;border:0;border-radius:8px;font-size:11.5px;font-weight:800;cursor:pointer;font-family:'DM Sans',sans-serif;}

.ad-action-btn.view{background:var(--ad-blue);color:#fff;}

.ad-action-btn.del{background:var(--ad-red);color:#fff;}

.ad-badge-piece{display:inline-block;padding:3px 8px;border-radius:50px;font-size:10px;font-weight:800;}

.ad-badge-piece.yes{background:rgba(16,185,129,.15);color:#0F7B3E;}

.ad-badge-piece.no{background:rgba(231,76,60,.15);color:#C0392B;}

/* ===== SECTION PAIEMENTS - NOUVELLE ===== */

.ad-payments-wrap{

max-width:1400px; margin:0 auto;

}

.ad-payment-card{

background:#fff; border-radius:14px; padding:18px 22px;

margin-bottom:12px; box-shadow:0 6px 18px rgba(8,43,77,.06);

border-left:5px solid var(--ad-info);

display:grid; grid-template-columns:auto 1fr auto; gap:16px;

align-items:center;

}

/* COULEURS SELON STATUT */

.ad-payment-card.declare{

border-left-color:var(--ad-info);

background:linear-gradient(to right, rgba(59,130,246,.08), #fff 30%);

}

.ad-payment-card.confirme{

border-left-color:var(--ad-green);

background:linear-gradient(to right, rgba(16,185,129,.08), #fff 30%);

}

.ad-payment-card.refuse{

border-left-color:var(--ad-red);

background:linear-gradient(to right, rgba(231,76,60,.08), #fff 30%);

opacity:.85;

}

.ad-payment-pro-photo{

width:56px; height:56px; border-radius:50%; overflow:hidden;

background:linear-gradient(135deg,var(--ad-blue),var(--ad-coral));

display:flex; align-items:center; justify-content:center;

color:#fff; font-size:22px;

}

.ad-payment-pro-photo img{width:100%;height:100%;object-fit:cover;}

.ad-payment-info strong{

display:block; font-size:15px; color:var(--ad-text);

margin-bottom:4px; font-weight:800;

}

.ad-payment-info .meta{

display:flex; gap:14px; flex-wrap:wrap; font-size:12.5px;

color:var(--ad-muted); margin-bottom:6px;

}

.ad-payment-info .meta span{display:inline-flex;align-items:center;gap:4px;}

.ad-payment-info .meta strong{display:inline;color:var(--ad-text);font-weight:800;}

.ad-payment-wave{

display:inline-flex; align-items:center; gap:6px;

background:rgba(26,177,229,.12); padding:5px 12px;

border-radius:50px; font-size:12px; font-weight:800;

color:#0E7CA6;

}

.ad-payment-side{

display:flex; flex-direction:column; align-items:flex-end;

gap:10px;

}

.ad-payment-amount-big{

font-family:'Montserrat',sans-serif; font-size:22px;

font-weight:900; color:var(--ad-blue);

}

.ad-payment-status-pill{

display:inline-flex; align-items:center; gap:6px;

padding:6px 14px; border-radius:50px;

font-size:12px; font-weight:900;

}

.ad-payment-status-pill.declare{

background:var(--ad-info); color:#fff;

}

.ad-payment-status-pill.confirme{

background:var(--ad-green); color:#fff;

}

.ad-payment-status-pill.refuse{

background:var(--ad-red); color:#fff;

}

.ad-payment-actions{

display:flex; gap:8px; flex-wrap:wrap; justify-content:flex-end;

}

.ad-btn-approve{

padding:8px 16px; border:0; border-radius:50px;

background:var(--ad-green); color:#fff;

font-weight:900; font-size:12.5px; cursor:pointer;

font-family:'DM Sans',sans-serif;

display:inline-flex; align-items:center; gap:5px;

}

.ad-btn-reject{

padding:8px 16px; border:0; border-radius:50px;

background:var(--ad-red); color:#fff;

font-weight:900; font-size:12.5px; cursor:pointer;

font-family:'DM Sans',sans-serif;

display:inline-flex; align-items:center; gap:5px;

}

.ad-btn-contact{

padding:7px 14px; background:#25D366; color:#fff;

border-radius:50px; font-size:11.5px; font-weight:800;

text-decoration:none; display:inline-flex; align-items:center; gap:5px;

}

.ad-payment-extra-info{

width:100%; margin-top:10px; padding-top:10px;

border-top:1px dashed rgba(15,62,104,.10);

font-size:12.5px; color:var(--ad-muted);

}

.ad-motif-refus{

background:rgba(231,76,60,.08); padding:10px 14px;

border-radius:8px; margin-top:8px; font-size:12.5px;

color:#C0392B; border-left:3px solid var(--ad-red);

}

/* SOUS-FILTRES PAIEMENTS */

.ad-pay-subfilters{

display:flex; gap:8px; margin-bottom:16px; flex-wrap:wrap;

}

.ad-pay-subfilter{

padding:8px 16px; border:1.5px solid rgba(15,62,104,.15);

border-radius:50px; background:#fff; cursor:pointer;

font-family:'DM Sans',sans-serif; font-size:12.5px;

font-weight:800; color:var(--ad-muted); transition:.3s;

display:inline-flex; align-items:center; gap:6px;

}

.ad-pay-subfilter.active{

border-color:transparent; color:#fff;

}

.ad-pay-subfilter[data-filter="all"].active{background:var(--ad-blue);}

.ad-pay-subfilter[data-filter="declare"].active{background:var(--ad-info);}

.ad-pay-subfilter[data-filter="confirme"].active{background:var(--ad-green);}

.ad-pay-subfilter[data-filter="refuse"].active{background:var(--ad-red);}

.ad-pay-subfilter .count{

background:rgba(0,0,0,.15); padding:2px 8px;

border-radius:50px; font-size:11px;

}

.ad-pay-subfilter.active .count{background:rgba(255,255,255,.25);}

/* MODAL */

.ad-modal{

position:fixed; inset:0; background:rgba(8,43,77,.65);

z-index:9999; display:none; align-items:center; justify-content:center;

padding:20px; overflow-y:auto;

}

.ad-modal.show{display:flex;}

.ad-modal-content{

background:#fff; border-radius:20px; max-width:550px; width:100%;

max-height:90vh; overflow-y:auto;

}

.ad-modal-content.large{max-width:850px;}

.ad-modal-head{

position:sticky; top:0; background:linear-gradient(135deg,var(--ad-blue),var(--ad-coral));

color:#fff; padding:20px 28px; display:flex;

justify-content:space-between; align-items:center;

border-radius:20px 20px 0 0;

}

.ad-modal-head h2{font-family:'Montserrat',sans-serif;margin:0;font-size:20px;}

.ad-modal-close{background:rgba(255,255,255,.2);border:0;color:#fff;width:36px;height:36px;border-radius:50%;cursor:pointer;font-size:20px;font-weight:900;}

.ad-modal-body{padding:28px;}

.ad-reject-form label{

display:block; font-size:13px; font-weight:800;

color:var(--ad-blue); margin-bottom:8px;

}

.ad-reject-form textarea{

width:100%; padding:14px; border:1.5px solid rgba(15,62,104,.15);

border-radius:12px; font-family:'DM Sans',sans-serif;

font-size:14px; min-height:100px; resize:vertical;

outline:none; margin-bottom:14px;

}

.ad-reject-form .preset-motifs{

display:flex; gap:8px; flex-wrap:wrap; margin-bottom:14px;

}

.ad-reject-form .preset{

padding:7px 14px; border:1.5px solid var(--ad-red);

background:transparent; color:var(--ad-red);

border-radius:50px; cursor:pointer; font-size:12px;

font-weight:800; font-family:'DM Sans',sans-serif;

}

.ad-reject-form .preset:hover{background:var(--ad-red);color:#fff;}

.ad-modal-actions{

display:flex; gap:10px; justify-content:flex-end; margin-top:18px;

}

.ad-modal-actions button{

padding:12px 22px; border:0; border-radius:50px;

font-weight:900; cursor:pointer; font-family:'DM Sans',sans-serif;

font-size:13.5px;

}

.ad-modal-actions .cancel{

background:#E5E7EB; color:var(--ad-text);

}

.ad-modal-actions .confirm-reject{

background:var(--ad-red); color:#fff;

}

/* MODAL DÉTAILS */

.ad-detail-section{margin-bottom:24px;padding-bottom:20px;border-bottom:1px solid rgba(15,62,104,.08);}

.ad-detail-section:last-child{border-bottom:0;}

.ad-detail-section h3{font-family:'Montserrat',sans-serif;color:var(--ad-blue);font-size:15px;margin:0 0 14px;padding:8px 14px;background:rgba(15,62,104,.08);border-radius:8px;font-weight:900;text-transform:uppercase;letter-spacing:.8px;}

.ad-detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:14px;}

.ad-detail-item{background:#FAFAFB;padding:12px 16px;border-radius:10px;border-left:3px solid var(--ad-coral);}

.ad-detail-item small{display:block;font-size:11px;font-weight:900;color:var(--ad-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:4px;}

.ad-detail-item strong{font-size:14px;color:var(--ad-text);font-weight:700;}

.ad-photo-zone{text-align:center;margin-bottom:14px;}

.ad-photo-zone img{max-width:160px;max-height:160px;border-radius:50%;border:4px solid var(--ad-coral);object-fit:cover;box-shadow:0 10px 30px rgba(8,43,77,.20);}

.ad-piece-images{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-top:10px;}

.ad-piece-img{border:2px solid rgba(15,62,104,.10);border-radius:10px;overflow:hidden;cursor:pointer;transition:.3s;}

.ad-piece-img:hover{border-color:var(--ad-coral);transform:translateY(-3px);}

.ad-piece-img img{width:100%;height:140px;object-fit:cover;display:block;}

.ad-piece-img small{display:block;text-align:center;padding:8px;font-size:12px;font-weight:800;color:var(--ad-muted);background:#FAFAFB;}

.ad-piece-empty{padding:20px;text-align:center;background:#FAFAFB;border-radius:10px;color:var(--ad-muted);font-size:13px;}

.ad-empty{padding:50px 20px;text-align:center;color:var(--ad-muted);font-size:14px;}

.ad-hidden{display:none !important;}

@media(max-width:900px){

.ad-payment-card{grid-template-columns:1fr;}

.ad-payment-side{align-items:flex-start;}

.ad-pro-row{grid-template-columns:50px 1fr;gap:10px;}

.ad-pro-row > div:not(:nth-child(-n+2)){display:none;}

.ad-pro-row.header{display:none;}

.ad-pro-row{background:#fff !important;border-radius:12px;margin:8px 12px;border:1px solid rgba(15,62,104,.10);}

}

</style>

<div class="ad-page">

<!-- LOGIN -->

<div id="adLogin" class="ad-login-wrap">

<h1>🔐 Tableau de bord</h1>

<p>Espace réservé à l'administration MELAVAH PRO</p>

<input type="password" id="adminPassword" placeholder="Mot de passe administrateur" autocomplete="off">

<button onclick="window.adLoginAdmin()">Accéder au tableau de bord</button>

<div id="adLoginMsg" style="margin-top:14px;color:var(--ad-red);font-size:13px;font-weight:700;"></div>

</div>

<!-- DASHBOARD -->

<div id="adDashboard" class="ad-hidden">

<div class="ad-header">

<div>

<h1>📊 MELAVAH PRO <span class="badge-admin">ADMIN</span></h1>

</div>

<div class="ad-header-actions">

<button class="ad-btn-reload" onclick="window.adReload()">🔄 Actualiser</button>

<button class="ad-btn-logout" onclick="window.adLogout()">🚪 Déconnexion</button>

</div>

</div>

<!-- ONGLETS PRINCIPAUX -->

<div class="ad-main-tabs">

<button class="ad-main-tab active" data-tab="pros" onclick="window.adSwitchTab('pros')">

👥 Professionnels

</button>

<button class="ad-main-tab" data-tab="payments" onclick="window.adSwitchTab('payments')">

💳 Paiements <span class="ad-tab-badge" id="pendingBadge" style="display:none;">0</span>

</button>

</div>

<!-- ===== ONGLET PROS ===== -->

<div id="tabPros">

<div class="ad-stats">

<div class="ad-stat">

<span class="icon">👥</span>

<small>Total Pros inscrits</small>

<div class="value" id="statPros">0</div>

</div>

<div class="ad-stat green">

<span class="icon">💰</span>

<small>Revenus confirmés</small>

<div class="value" id="statRevenus">0 FCFA</div>

</div>

<div class="ad-stat orange">

<span class="icon">📜</span>

<small>Total paiements</small>

<div class="value" id="statPaiements">0</div>

</div>

<div class="ad-stat purple">

<span class="icon">🪪</span>

<small>Pièces fournies</small>

<div class="value" id="statPieces">0</div>

</div>

</div>

<div class="ad-filters">

<input type="text" id="adSearch" placeholder="🔍 Rechercher (nom, email, ville, métier...)">

<select id="adFilterPiece">

<option value="all">Tous les pros</option>

<option value="with">Avec pièce d'identité</option>

<option value="without">Sans pièce d'identité</option>

</select>

<select id="adFilterPay">

<option value="all">Tous</option>

<option value="paid">Ont payé</option>

<option value="unpaid">N'ont pas payé</option>

</select>

<select id="adSort">

<option value="recent">📅 Plus récents</option>

<option value="amount">💰 Plus gros payeurs</option>

<option value="name">🔤 Ordre alphabétique</option>

</select>

</div>

<div class="ad-pros-wrap">

<div class="ad-pros-list">

<div class="ad-pro-row header">

<div></div>

<div>Professionnel</div>

<div>Téléphone</div>

<div>Ville</div>

<div>Total payé</div>

<div>Paiements</div>

<div>Pièce</div>

<div>Actions</div>

</div>

<div id="adProsList">

<div class="ad-empty">Chargement...</div>

</div>

</div>

</div>

</div>

<!-- ===== ONGLET PAIEMENTS ===== -->

<div id="tabPayments" class="ad-hidden">

<div class="ad-stats">

<div class="ad-stat info">

<span class="icon">⏳</span>

<small>En attente</small>

<div class="value" id="statPayDeclare" style="color:var(--ad-info);">0</div>

</div>

<div class="ad-stat green">

<span class="icon">✅</span>

<small>Confirmés</small>

<div class="value" id="statPayConfirme" style="color:var(--ad-green);">0</div>

</div>

<div class="ad-stat red">

<span class="icon">❌</span>

<small>Refusés</small>

<div class="value" id="statPayRefuse" style="color:var(--ad-red);">0</div>

</div>

<div class="ad-stat orange">

<span class="icon">💵</span>

<small>Total à valider</small>

<div class="value" id="statPayMontant" style="color:var(--ad-orange);">0 FCFA</div>

</div>

</div>

<!-- SOUS-FILTRES -->

<div class="ad-pay-subfilters">

<button class="ad-pay-subfilter active" data-filter="all" onclick="window.adFilterPayments('all')">

🔍 Tous <span class="count" id="cntAll">0</span>

</button>

<button class="ad-pay-subfilter" data-filter="declare" onclick="window.adFilterPayments('declare')">

⏳ En attente <span class="count" id="cntDeclare">0</span>

</button>

<button class="ad-pay-subfilter" data-filter="confirme" onclick="window.adFilterPayments('confirme')">

✅ Confirmés <span class="count" id="cntConfirme">0</span>

</button>

<button class="ad-pay-subfilter" data-filter="refuse" onclick="window.adFilterPayments('refuse')">

❌ Refusés <span class="count" id="cntRefuse">0</span>

</button>

</div>

<div class="ad-filters">

<input type="text" id="adSearchPay" placeholder="🔍 Rechercher (nom du pro, numéro Wave...)">

</div>

<div class="ad-payments-wrap" id="adPaymentsList">

<div class="ad-empty">Chargement...</div>

</div>

</div>

</div>

<!-- MODAL DÉTAILS PRO -->

<div class="ad-modal" id="adModal">

<div class="ad-modal-content large">

<div class="ad-modal-head">

<h2 id="modalTitle">Détails</h2>

<button class="ad-modal-close" onclick="window.adCloseModal()">×</button>

</div>

<div class="ad-modal-body" id="modalBody"></div>

</div>

</div>

<!-- MODAL REFUS PAIEMENT -->

<div class="ad-modal" id="adRejectModal">

<div class="ad-modal-content">

<div class="ad-modal-head" style="background:linear-gradient(135deg,var(--ad-red),#FF6B6B);">

<h2>❌ Refuser ce paiement</h2>

<button class="ad-modal-close" onclick="window.adCloseRejectModal()">×</button>

</div>

<div class="ad-modal-body">

<div class="ad-reject-form">

<p style="color:var(--ad-muted);font-size:14px;line-height:1.6;margin-bottom:18px;">

Indiquez la raison du refus. Le pro sera informé et le montant sera déduit de son total payé.

</p>

<label>Motifs courants (cliquez pour utiliser)</label>

<div class="preset-motifs">

<button type="button" class="preset" onclick="window.adSetMotif('Paiement non reçu sur Wave')">Paiement non reçu</button>

<button type="button" class="preset" onclick="window.adSetMotif('Montant insuffisant')">Montant insuffisant</button>

<button type="button" class="preset" onclick="window.adSetMotif('Numéro Wave incorrect')">N° Wave incorrect</button>

<button type="button" class="preset" onclick="window.adSetMotif('Doublon de paiement')">Doublon</button>

</div>

<label>Motif détaillé <span style="color:var(--ad-red);">*</span></label>

<textarea id="rejectMotif" placeholder="Expliquez la raison du refus..."></textarea>

<div class="ad-modal-actions">

<button type="button" class="cancel" onclick="window.adCloseRejectModal()">Annuler</button>

<button type="button" class="confirm-reject" onclick="window.adConfirmReject()">❌ Confirmer le refus</button>

</div>

</div>

</div>

</div>

</div>

</div>

<script>

(function(){

const API_URL = 'https://script.google.com/macros/s/AKfycbweg2H5GzLWwYwKh3d7lp8qMFPmb2jeZ1O4rpNMs9rKNm8_zo7vIITUYQ7-qElNJkk/exec';

const ADMIN_STORAGE = 'mpro_admin_session';

let allPros = [];

let allPayments = [];

let adminKey = '';

let currentTab = 'pros';

let currentPayFilter = 'all';

let pendingReject = null;

// ===== LOGIN =====

window.adLoginAdmin = async function(){

const pwd = document.getElementById('adminPassword').value.trim();

if(!pwd){ document.getElementById('adLoginMsg').textContent = 'Mot de passe requis'; return; }

document.getElementById('adLoginMsg').textContent = '⏳ Vérification...';

try{

const formData = new FormData();

formData.append('action', 'adminGetAll');

formData.append('adminKey', pwd);

const response = await fetch(API_URL, {method:'POST', body:formData});

const result = await response.json();

if(result.success){

adminKey = pwd;

sessionStorage.setItem(ADMIN_STORAGE, pwd);

document.getElementById('adLogin').classList.add('ad-hidden');

document.getElementById('adDashboard').classList.remove('ad-hidden');

renderDashboard(result);

loadPayments();

} else {

document.getElementById('adLoginMsg').textContent = '❌ Mot de passe incorrect';

}

} catch(err){

document.getElementById('adLoginMsg').textContent = '❌ Erreur de connexion';

}

};

window.adLogout = function(){

sessionStorage.removeItem(ADMIN_STORAGE);

location.reload();

};

window.adReload = async function(){

if(!adminKey) return;

await loadPros();

await loadPayments();

};

async function loadPros(){

document.getElementById('adProsList').innerHTML = '<div class="ad-empty">⏳ Chargement...</div>';

try{

const formData = new FormData();

formData.append('action', 'adminGetAll');

formData.append('adminKey', adminKey);

const response = await fetch(API_URL, {method:'POST', body:formData});

const result = await response.json();

if(result.success) renderDashboard(result);

} catch(err){

document.getElementById('adProsList').innerHTML = '<div class="ad-empty">❌ Erreur</div>';

}

}

async function loadPayments(){

try{

const formData = new FormData();

formData.append('action', 'adminGetAllPayments');

formData.append('adminKey', adminKey);

const response = await fetch(API_URL, {method:'POST', body:formData});

const result = await response.json();

if(result.success){

allPayments = result.payments || [];

renderPayments();

updatePendingBadge();

}

} catch(err){

document.getElementById('adPaymentsList').innerHTML = '<div class="ad-empty">❌ Erreur</div>';

}

}

function renderDashboard(data){

allPros = data.pros || [];

const stats = data.stats || {};

document.getElementById('statPros').textContent = stats.totalPros || 0;

document.getElementById('statRevenus').textContent = (stats.totalRevenus || 0).toLocaleString('fr-FR') + ' FCFA';

document.getElementById('statPaiements').textContent = stats.totalPaiements || 0;

document.getElementById('statPieces').textContent = stats.prosAvecPiece || 0;

applyFilters();

}

function updatePendingBadge(){

const pending = allPayments.filter(p => (p.statut || 'Déclaré') === 'Déclaré').length;

const badge = document.getElementById('pendingBadge');

if(pending > 0){

badge.textContent = pending;

badge.style.display = 'inline-block';

} else {

badge.style.display = 'none';

}

}

// ===== ONGLETS PRINCIPAUX =====

window.adSwitchTab = function(tab){

currentTab = tab;

document.querySelectorAll('.ad-main-tab').forEach(t =>

t.classList.toggle('active', t.getAttribute('data-tab') === tab));

document.getElementById('tabPros').classList.toggle('ad-hidden', tab !== 'pros');

document.getElementById('tabPayments').classList.toggle('ad-hidden', tab !== 'payments');

};

// ===== FILTRES PROS =====

function applyFilters(){

const search = document.getElementById('adSearch').value.toLowerCase().trim();

const filterPiece = document.getElementById('adFilterPiece').value;

const filterPay = document.getElementById('adFilterPay').value;

const sortBy = document.getElementById('adSort').value;

let filtered = [...allPros];

if(search){

filtered = filtered.filter(p => {

const txt = (p.nom + ' ' + p.email + ' ' + p.ville + ' ' + p.competences + ' ' + p.zones).toLowerCase();

return txt.includes(search);

});

}

if(filterPiece === 'with') filtered = filtered.filter(p => p.pieceRecto || p.pieceVerso);

if(filterPiece === 'without') filtered = filtered.filter(p => !p.pieceRecto && !p.pieceVerso);

if(filterPay === 'paid') filtered = filtered.filter(p => p.totalPaye > 0);

if(filterPay === 'unpaid') filtered = filtered.filter(p => p.totalPaye === 0);

if(sortBy === 'amount') filtered.sort((a,b) => b.totalPaye - a.totalPaye);

else if(sortBy === 'name') filtered.sort((a,b) => a.nom.localeCompare(b.nom));

else filtered.sort((a,b) => parseInt(b.id.replace('MP','')) - parseInt(a.id.replace('MP','')));

renderProsList(filtered);

}

function renderProsList(pros){

const list = document.getElementById('adProsList');

if(pros.length === 0){

list.innerHTML = '<div class="ad-empty">Aucun pro trouvé.</div>';

return;

}

list.innerHTML = pros.map((p, idx) => {

const skills = (p.competences || '').split(',').slice(0, 3).map(s =>

`<span class="ad-skill-tag">${escapeHtml(s.trim())}</span>`).join('');

const photoHTML = p.photo ? `<img src="${p.photo}" alt="">` : '👤';

const hasPiece = (p.pieceRecto || p.pieceVerso);

const piecesCount = (p.pieceRecto ? 1 : 0) + (p.pieceVerso ? 1 : 0) + (p.piecePagesSup ? p.piecePagesSup.length : 0);

const paysFlag = getFlag(p.pays);

return `

<div class="ad-pro-row">

<div class="ad-pro-avatar">${photoHTML}</div>

<div class="ad-pro-info">

<strong>${escapeHtml(p.nom)}</strong>

<small>${escapeHtml(p.email)}</small>

<div class="ad-pro-skills" style="margin-top:6px;">${skills}</div>

</div>

<div><strong>${paysFlag} ${p.indicatif || ''} ${escapeHtml(p.numero)}</strong></div>

<div>${escapeHtml(p.ville || '—')}</div>

<div class="ad-pro-amount">${p.totalPaye.toLocaleString('fr-FR')} FCFA</div>

<div>${p.historique ? p.historique.length : 0} pmt(s)</div>

<div>

${hasPiece ? `<span class="ad-badge-piece yes">✓ ${piecesCount} doc</span>` : `<span class="ad-badge-piece no">✗ Aucune</span>`}

</div>

<div class="ad-pro-actions">

<button class="ad-action-btn view" onclick="window.adShowDetails(${idx})">👁️ Voir</button>

<button class="ad-action-btn del" onclick="window.adDelete(${p.rowNum}, '${escapeJs(p.nom)}')">🗑️</button>

</div>

</div>

`;

}).join('');

window._adFiltered = pros;

}

// ===== RENDER PAIEMENTS =====

function renderPayments(){

// Stats par statut

const declare = allPayments.filter(p => (p.statut || 'Déclaré') === 'Déclaré');

const confirme = allPayments.filter(p => p.statut === 'Confirmé');

const refuse = allPayments.filter(p => p.statut === 'Refusé');

document.getElementById('statPayDeclare').textContent = declare.length;

document.getElementById('statPayConfirme').textContent = confirme.length;

document.getElementById('statPayRefuse').textContent = refuse.length;

document.getElementById('statPayMontant').textContent =

declare.reduce((s,p) => s + p.montant, 0).toLocaleString('fr-FR') + ' FCFA';

document.getElementById('cntAll').textContent = allPayments.length;

document.getElementById('cntDeclare').textContent = declare.length;

document.getElementById('cntConfirme').textContent = confirme.length;

document.getElementById('cntRefuse').textContent = refuse.length;

applyPaymentFilters();

}

window.adFilterPayments = function(filter){

currentPayFilter = filter;

document.querySelectorAll('.ad-pay-subfilter').forEach(b =>

b.classList.toggle('active', b.getAttribute('data-filter') === filter));

applyPaymentFilters();

};

function applyPaymentFilters(){

const search = document.getElementById('adSearchPay').value.toLowerCase().trim();

let filtered = [...allPayments];

if(currentPayFilter === 'declare') filtered = filtered.filter(p => (p.statut || 'Déclaré') === 'Déclaré');

else if(currentPayFilter === 'confirme') filtered = filtered.filter(p => p.statut === 'Confirmé');

else if(currentPayFilter === 'refuse') filtered = filtered.filter(p => p.statut === 'Refusé');

if(search){

filtered = filtered.filter(p => {

const txt = (p.proNom + ' ' + p.proEmail + ' ' + p.numeroWave).toLowerCase();

return txt.includes(search);

});

}

renderPaymentsList(filtered);

}

function renderPaymentsList(payments){

const list = document.getElementById('adPaymentsList');

if(payments.length === 0){

list.innerHTML = '<div class="ad-empty">Aucun paiement trouvé.</div>';

return;

}

list.innerHTML = payments.map(p => {

const statut = (p.statut || 'Déclaré').toLowerCase();

const cardClass = statut === 'confirmé' ? 'confirme' : statut === 'refusé' ? 'refuse' : 'declare';

const pillClass = cardClass;

const photoHTML = p.proPhoto ? `<img src="${p.proPhoto}" alt="">` : '👤';

const paysFlag = getFlag(p.proPays);

const waPhone = (p.proIndicatif + p.proNumero).replace(/\D/g, '').replace(/^00/, '');

let statutLabel = '⏳ Déclaré (en attente)';

let statutIcon = '⏳';

if(statut === 'confirmé'){ statutLabel = '✅ Confirmé'; statutIcon = '✅'; }

else if(statut === 'refusé'){ statutLabel = '❌ Refusé'; statutIcon = '❌'; }

let actionsHTML = '';

if(statut === 'déclaré'){

actionsHTML = `

<button class="ad-btn-approve" onclick="window.adApprovePayment(${p.rowNum}, ${p.paymentIndex})">

✅ Approuver

</button>

<button class="ad-btn-reject" onclick="window.adOpenRejectModal(${p.rowNum}, ${p.paymentIndex}, '${escapeJs(p.proNom)}', ${p.montant})">

❌ Refuser

</button>

`;

}

let extraInfo = '';

if(statut === 'confirmé' && p.dateValidation){

extraInfo = `<div class="ad-payment-extra-info">✅ Validé le ${escapeHtml(p.dateValidation)}</div>`;

} else if(statut === 'refusé'){

extraInfo = `<div class="ad-payment-extra-info">❌ Refusé le ${escapeHtml(p.dateRefus || '—')}</div>`;

if(p.motifRefus){

extraInfo += `<div class="ad-motif-refus"><strong>Motif :</strong> ${escapeHtml(p.motifRefus)}</div>`;

}

}

return `

<div class="ad-payment-card ${cardClass}">

<div class="ad-payment-pro-photo">${photoHTML}</div>

<div class="ad-payment-info">

<strong>${escapeHtml(p.proNom)}</strong>

<div class="meta">

<span>📧 ${escapeHtml(p.proEmail)}</span>

<span>${paysFlag} ${p.proIndicatif} ${escapeHtml(p.proNumero)}</span>

<span>📅 ${escapeHtml(p.date)}</span>

</div>

<span class="ad-payment-wave">🌊 N° Wave : <strong>${escapeHtml(p.numeroWave || 'Non renseigné')}</strong></span>

${extraInfo}

</div>

<div class="ad-payment-side">

<div class="ad-payment-amount-big">${p.montant.toLocaleString('fr-FR')} FCFA</div>

<span class="ad-payment-status-pill ${pillClass}">${statutLabel}</span>

<div class="ad-payment-actions">

${actionsHTML}

<a href="https://wa.me/${waPhone}?text=Bonjour%20${encodeURIComponent(p.proNom)},%20concernant%20votre%20paiement%20du%20${encodeURIComponent(p.date)}" target="_blank" class="ad-btn-contact">💬 WhatsApp</a>

</div>

</div>

</div>

`;

}).join('');

}

// ===== ACTIONS PAIEMENTS =====

window.adApprovePayment = async function(rowNum, paymentIndex){

if(!confirm('✅ Confirmer ce paiement comme reçu ?')) return;

try{

const formData = new FormData();

formData.append('action', 'adminValidatePayment');

formData.append('adminKey', adminKey);

formData.append('rowNum', rowNum);

formData.append('paymentIndex', paymentIndex);

const response = await fetch(API_URL, {method:'POST', body:formData});

const result = await response.json();

if(result.success){

await loadPayments();

await loadPros();

} else {

alert('❌ ' + result.message);

}

} catch(err){

alert('❌ Erreur');

}

};

window.adOpenRejectModal = function(rowNum, paymentIndex, proNom, montant){

pendingReject = {rowNum, paymentIndex, proNom, montant};

document.getElementById('rejectMotif').value = '';

document.getElementById('adRejectModal').classList.add('show');

};

window.adCloseRejectModal = function(){

document.getElementById('adRejectModal').classList.remove('show');

pendingReject = null;

};

window.adSetMotif = function(motif){

document.getElementById('rejectMotif').value = motif;

};

window.adConfirmReject = async function(){

if(!pendingReject) return;

const motif = document.getElementById('rejectMotif').value.trim();

if(!motif){

alert('⚠️ Veuillez saisir un motif');

return;

}

if(!confirm(`Refuser le paiement de ${pendingReject.montant.toLocaleString('fr-FR')} FCFA de ${pendingReject.proNom} ?`)) return;

try{

const formData = new FormData();

formData.append('action', 'adminRejectPayment');

formData.append('adminKey', adminKey);

formData.append('rowNum', pendingReject.rowNum);

formData.append('paymentIndex', pendingReject.paymentIndex);

formData.append('motif', motif);

const response = await fetch(API_URL, {method:'POST', body:formData});

const result = await response.json();

if(result.success){

window.adCloseRejectModal();

await loadPayments();

await loadPros();

} else {

alert('❌ ' + result.message);

}

} catch(err){

alert('❌ Erreur');

}

};

// ===== DÉTAILS PRO =====

window.adShowDetails = function(idx){

const p = window._adFiltered[idx];

if(!p) return;

const skills = (p.competences || '').split(',').map(s =>

`<span class="ad-skill-tag">${escapeHtml(s.trim())}</span>`).join(' ');

const photoHTML = p.photo

? `<img src="${p.photo}" alt="profil">`

: '<div style="width:160px;height:160px;border-radius:50%;background:linear-gradient(135deg,var(--ad-blue),var(--ad-coral));margin:0 auto;display:flex;align-items:center;justify-content:center;color:#fff;font-size:60px;">👤</div>';

let piecesHTML = '';

const hasPiece = p.pieceRecto || p.pieceVerso || (p.piecePagesSup && p.piecePagesSup.length);

if(hasPiece){

piecesHTML = '<div class="ad-piece-images">';

if(p.pieceRecto) piecesHTML += `<div class="ad-piece-img" onclick="window.open('${p.pieceRecto}','_blank')"><img src="${p.pieceRecto}"><small>📄 Recto</small></div>`;

if(p.pieceVerso) piecesHTML += `<div class="ad-piece-img" onclick="window.open('${p.pieceVerso}','_blank')"><img src="${p.pieceVerso}"><small>📄 Verso</small></div>`;

if(p.piecePagesSup) p.piecePagesSup.forEach((url, i) => {

piecesHTML += `<div class="ad-piece-img" onclick="window.open('${url}','_blank')"><img src="${url}"><small>📑 Page ${i+1}</small></div>`;

});

piecesHTML += '</div>';

} else {

piecesHTML = '<div class="ad-piece-empty">Aucune pièce d\'identité fournie</div>';

}

document.getElementById('modalTitle').textContent = '👤 ' + p.nom;

document.getElementById('modalBody').innerHTML = `

<div class="ad-detail-section">

<div class="ad-photo-zone">${photoHTML}</div>

<h3>📋 Informations</h3>

<div class="ad-detail-grid">

<div class="ad-detail-item"><small>Email</small><strong>${escapeHtml(p.email)}</strong></div>

<div class="ad-detail-item"><small>Téléphone</small><strong>${getFlag(p.pays)} ${escapeHtml(p.indicatif || '')} ${escapeHtml(p.numero)}</strong></div>

<div class="ad-detail-item"><small>Pays</small><strong>${escapeHtml(p.pays || '—')}</strong></div>

<div class="ad-detail-item"><small>Ville</small><strong>${escapeHtml(p.ville)}</strong></div>

<div class="ad-detail-item"><small>Zones</small><strong>${escapeHtml(p.zones)}</strong></div>

<div class="ad-detail-item"><small>Code</small><strong style="color:var(--ad-coral);letter-spacing:3px;">${escapeHtml(p.code)}</strong></div>

</div>

</div>

<div class="ad-detail-section">

<h3>🛠️ Compétences</h3>

<div style="line-height:2;">${skills}</div>

</div>

<div class="ad-detail-section">

<h3>🪪 Pièces d'identité</h3>

${piecesHTML}

</div>

`;

document.getElementById('adModal').classList.add('show');

};

window.adCloseModal = function(){

document.getElementById('adModal').classList.remove('show');

};

window.adDelete = async function(rowNum, nom){

if(!confirm(`⚠️ Supprimer "${nom}" ?\n\nCette action est irréversible.`)) return;

try{

const formData = new FormData();

formData.append('action', 'adminDelete');

formData.append('adminKey', adminKey);

formData.append('rowNum', rowNum);

const response = await fetch(API_URL, {method:'POST', body:formData});

const result = await response.json();

if(result.success){

await loadPros();

await loadPayments();

} else {

alert('❌ ' + result.message);

}

} catch(err){

alert('❌ Erreur');

}

};

// ===== UTILS =====

function escapeHtml(s){

return String(s || '').replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[m]);

}

function escapeJs(s){

return String(s || '').replace(/'/g, "\\'");

}

function getFlag(country){

const flags = {

'Côte d\'Ivoire':'🇨🇮','Sénégal':'🇸🇳','Mali':'🇲🇱','Burkina Faso':'🇧🇫',

'Bénin':'🇧🇯','Togo':'🇹🇬','Niger':'🇳🇪','Guinée':'🇬🇳','Mauritanie':'🇲🇷',

'Ghana':'🇬🇭','Nigeria':'🇳🇬','Cameroun':'🇨🇲','Gabon':'🇬🇦','Congo':'🇨🇬',

'RD Congo':'🇨🇩','Tchad':'🇹🇩','Maroc':'🇲🇦','Algérie':'🇩🇿','Tunisie':'🇹🇳',

'Kenya':'🇰🇪','Rwanda':'🇷🇼','Afrique du Sud':'🇿🇦','Angola':'🇦🇴',

'Madagascar':'🇲🇬','France':'🇫🇷','Belgique':'🇧🇪','Canada':'🇨🇦','États-Unis':'🇺🇸'

};

return flags[country] || '🌍';

}

// ===== EVENTS =====

['adSearch','adFilterPiece','adFilterPay','adSort'].forEach(id => {

document.getElementById(id).addEventListener(id === 'adSearch' ? 'input' : 'change', applyFilters);

});

document.getElementById('adSearchPay').addEventListener('input', applyPaymentFilters);

document.getElementById('adminPassword').addEventListener('keypress', e => {

if(e.key === 'Enter') window.adLoginAdmin();

});

document.getElementById('adModal').addEventListener('click', e => {

if(e.target.id === 'adModal') window.adCloseModal();

});

document.getElementById('adRejectModal').addEventListener('click', e => {

if(e.target.id === 'adRejectModal') window.adCloseRejectModal();

});

// Auto-login

(async function(){

const savedPwd = sessionStorage.getItem(ADMIN_STORAGE);

if(savedPwd){

document.getElementById('adminPassword').value = savedPwd;

window.adLoginAdmin();

}

})();

})();

</script>