592 lines
36 KiB
PHP
592 lines
36 KiB
PHP
<style>
|
||
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap');
|
||
|
||
.dash-container {
|
||
padding: 28px;
|
||
background: #f4f6fb;
|
||
font-family: 'Plus Jakarta Sans', 'Segoe UI', sans-serif;
|
||
min-height: 100vh;
|
||
}
|
||
|
||
/* ── Stat Cards ── */
|
||
.stat-cards {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 18px;
|
||
margin-bottom: 24px;
|
||
}
|
||
.card-hero {
|
||
background: white;
|
||
padding: 22px 24px;
|
||
border-radius: 14px;
|
||
border: 1px solid #e8edf5;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
|
||
position: relative;
|
||
overflow: hidden;
|
||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||
}
|
||
.card-hero::before {
|
||
content: "";
|
||
position: absolute;
|
||
top: 0; left: 0;
|
||
width: 100%; height: 4px;
|
||
}
|
||
.card-hero:nth-child(1)::before { background: linear-gradient(90deg, #667eea, #764ba2); }
|
||
.card-hero:nth-child(2)::before { background: linear-gradient(90deg, #f093fb, #f5576c); }
|
||
.card-hero:nth-child(3)::before { background: linear-gradient(90deg, #fda085, #f6d365); }
|
||
.card-hero:nth-child(4)::before { background: linear-gradient(90deg, #43e97b, #38f9d7); }
|
||
.card-hero:hover { transform: translateY(-4px); box-shadow: 0 12px 24px rgba(0,0,0,0.09); }
|
||
|
||
.stat-icon {
|
||
width: 42px; height: 42px;
|
||
border-radius: 10px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-size: 18px; margin-bottom: 14px;
|
||
}
|
||
.stat-val { font-size: 30px; font-weight: 800; color: #1a202c; line-height: 1; }
|
||
.stat-label { color: #8896aa; font-size: 13px; margin-top: 6px; font-weight: 600; }
|
||
|
||
/* ── Shared Card ── */
|
||
.card {
|
||
background: white;
|
||
padding: 24px;
|
||
border-radius: 14px;
|
||
border: 1px solid #e8edf5;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
|
||
}
|
||
|
||
/* ── Main Grid ── */
|
||
.main-grid {
|
||
display: grid;
|
||
grid-template-columns: 2fr 1fr;
|
||
gap: 20px;
|
||
margin-bottom: 24px;
|
||
align-items: start;
|
||
}
|
||
.main-grid > .card {
|
||
height: 520px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.table-scroll-area { flex: 1; overflow-y: auto; }
|
||
.table-scroll-area thead th { position: sticky; top: 0; background: white; z-index: 1; }
|
||
|
||
/* ── Right Panel ── */
|
||
.right-panel {
|
||
height: 520px;
|
||
background: white;
|
||
border-radius: 14px;
|
||
border: 1px solid #e8edf5;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.04);
|
||
padding: 22px;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
.team-members-scroll { flex: 1; overflow-y: auto; margin-top: 10px; }
|
||
.team-member {
|
||
display: flex; align-items: center;
|
||
padding: 10px 0;
|
||
border-bottom: 1px solid #f4f6fb;
|
||
}
|
||
.team-member:last-child { border-bottom: none; }
|
||
.member-img {
|
||
width: 38px; height: 38px; border-radius: 50%;
|
||
color: white; margin-right: 12px;
|
||
display: flex; align-items: center; justify-content: center;
|
||
font-weight: 700; font-size: 15px; flex-shrink: 0;
|
||
}
|
||
.act-stats { text-align: right; }
|
||
.act-stats .total { font-weight: 700; font-size: 13px; color: #1a202c; }
|
||
.act-stats .done { font-size: 11px; color: #38a169; font-weight: 600; margin-top: 2px; }
|
||
|
||
/* ── Activity Breakdown ── */
|
||
.breakdown-section {
|
||
flex-shrink: 0;
|
||
margin-top: 12px;
|
||
border: 1px solid #f0f4fa;
|
||
border-radius: 12px;
|
||
padding: 14px;
|
||
background: #fafbfd;
|
||
}
|
||
.breakdown-item {
|
||
display: flex; justify-content: space-between; align-items: center;
|
||
margin-bottom: 9px; font-size: 13px;
|
||
}
|
||
.breakdown-item:last-child { margin-bottom: 0; }
|
||
.breakdown-bar-wrap {
|
||
flex: 1; height: 5px; background: #eef0f5;
|
||
border-radius: 99px; margin: 0 10px; overflow: hidden;
|
||
}
|
||
.breakdown-bar { height: 100%; border-radius: 99px; }
|
||
|
||
/* ── Table ── */
|
||
.table-header {
|
||
display: flex; justify-content: space-between;
|
||
align-items: center; margin-bottom: 16px;
|
||
}
|
||
table { width: 100%; border-collapse: collapse; }
|
||
th {
|
||
text-align: left; padding: 10px 12px;
|
||
color: #8896aa; font-size: 11px;
|
||
text-transform: uppercase; letter-spacing: 0.07em;
|
||
border-bottom: 1px solid #edf2f7; background: white; font-weight: 700;
|
||
}
|
||
td { padding: 13px 12px; border-bottom: 1px solid #f4f6fb; font-size: 14px; vertical-align: middle; }
|
||
tbody tr:hover { background: #fafbfe; }
|
||
|
||
/* ── Status Pills ── */
|
||
.status-pill { padding: 4px 12px; border-radius: 20px; font-size: 11px; font-weight: 700; display: inline-block; }
|
||
.status-completed { background: #f0fff4; color: #38a169; }
|
||
.status-pending { background: #fffaf0; color: #dd6b20; }
|
||
.status-new { background: #e3f2fd; color: #1976d2; }
|
||
.status-potential { background: #fff3e0; color: #f57c00; }
|
||
.status-prospects { background: #e8f5e9; color: #388e3c; }
|
||
.status-not-a-prospects { background: #ffebee; color: #d32f2f; }
|
||
|
||
.leads-table-wrap { max-height: 480px; overflow-y: auto; }
|
||
.leads-table-wrap thead th { position: sticky; top: 0; background: white; z-index: 1; }
|
||
|
||
.empty-state { text-align: center; padding: 50px 20px; color: #aaa; }
|
||
.empty-icon { width: 70px; height: 70px; margin: 0 auto 16px; background: #f5f5f5; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 32px; }
|
||
|
||
/* ── Responsive ── */
|
||
@media (max-width: 1200px) { .stat-cards { grid-template-columns: repeat(2, 1fr); } }
|
||
@media (max-width: 992px) {
|
||
.main-grid { grid-template-columns: 1fr; }
|
||
.main-grid > .card, .right-panel { height: 450px; }
|
||
.stat-cards { grid-template-columns: repeat(2, 1fr); }
|
||
.achievement-cards { grid-template-columns: 1fr 1fr; }
|
||
}
|
||
@media (max-width: 576px) {
|
||
.dash-container { padding: 14px; }
|
||
.stat-cards { grid-template-columns: 1fr 1fr; gap: 10px; }
|
||
.stat-val { font-size: 24px; }
|
||
.main-grid > .card, .right-panel { height: 400px; }
|
||
table th, table td { padding: 10px 8px; font-size: 12px; }
|
||
.achievement-cards { grid-template-columns: 1fr; }
|
||
.achievement-header { flex-direction: column; gap: 14px; }
|
||
}
|
||
|
||
/* ══════════════════════════════════════════
|
||
TEAM ACHIEVEMENT SECTION (NEW)
|
||
══════════════════════════════════════════ */
|
||
|
||
.section-head{display:flex;justify-content:space-between;align-items:flex-end;margin-bottom:16px;}
|
||
.section-title{font-size:16px;font-weight:800;color:#0f172a;}
|
||
.section-sub{font-size:12px;color:#7c8db0;font-weight:600;margin-top:3px;}
|
||
.page-title{font-size:16px;font-weight:800;color:#0f172a;}
|
||
.branch-summary{text-align:right;}
|
||
.branch-amt{font-size:20px;font-weight:800;color:#0f172a;}
|
||
.branch-bar-wrap{width:180px;height:5px;background:#e4eaf5;border-radius:99px;overflow:hidden;margin:6px 0 4px auto;}
|
||
.branch-bar-fill{height:100%;border-radius:99px;background:linear-gradient(90deg,#4f46e5,#818cf8);}
|
||
.branch-pct-lbl{font-size:11px;color:#4f46e5;font-weight:700;}
|
||
.achieve-list{background:#fff;border-radius:14px;border:1px solid #e4eaf5;box-shadow:0 2px 12px rgba(15,23,42,0.06);overflow:hidden;}
|
||
.list-col-head{display:grid;grid-template-columns:260px 1fr 130px 130px 130px 110px 80px;padding:10px 22px;background:#f8fafd;border-bottom:1px solid #e4eaf5;}
|
||
.col-lbl{font-size:10px;font-weight:700;color:#7c8db0;letter-spacing:.07em;text-transform:uppercase;font-family:'DM Mono',monospace;display:flex;align-items:center;}
|
||
.col-lbl.right{justify-content:flex-end;}
|
||
.col-lbl.center{justify-content:center;}
|
||
.achieve-row{display:grid;grid-template-columns:260px 1fr 130px 130px 130px 110px 80px;padding:16px 22px;border-bottom:1px solid #f1f5f9;align-items:center;cursor:pointer;transition:background .15s;position:relative;}
|
||
.achieve-row:last-child{border-bottom:none;}
|
||
.achieve-row:hover{background:#f8fafd;}
|
||
.achieve-row:hover .row-arrow{opacity:1;transform:translateY(-50%) translateX(0);}
|
||
.member-cell{display:flex;align-items:center;gap:12px;}
|
||
.m-avatar{width:42px;height:42px;border-radius:12px;display:flex;align-items:center;justify-content:center;font-weight:800;font-size:16px;color:#fff;flex-shrink:0;}
|
||
.m-name{font-weight:700;font-size:14px;color:#0f172a;}
|
||
.m-role{font-size:11px;color:#7c8db0;font-weight:600;margin-top:2px;}
|
||
.prog-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:5px;}
|
||
.prog-pct{font-size:13px;font-weight:800;}
|
||
.prog-amts{font-size:11px;color:#7c8db0;font-weight:600;}
|
||
.prog-bar-wrap{height:6px;background:#f0f3fa;border-radius:99px;overflow:hidden;}
|
||
.prog-bar{height:100%;border-radius:99px;}
|
||
.num-cell{text-align:right;}
|
||
.num-val{font-size:15px;font-weight:800;}
|
||
.num-lbl{font-size:10px;color:#7c8db0;font-weight:700;margin-top:2px;letter-spacing:.04em;}
|
||
.num-cell.center-col{text-align:center;}
|
||
.badge{display:inline-flex;align-items:center;gap:5px;padding:4px 12px;border-radius:99px;font-size:11px;font-weight:700;white-space:nowrap;}
|
||
.b-achieved{background:#ecfdf5;color:#059669;}
|
||
.b-ontrack{background:#eff6ff;color:#2563eb;}
|
||
.b-behind{background:#fff7ed;color:#c2410c;}
|
||
.b-atrisk{background:#fef2f2;color:#b91c1c;}
|
||
.row-arrow{position:absolute;right:18px;top:50%;transform:translateY(-50%) translateX(4px);color:#cbd5e1;font-size:16px;opacity:0;transition:opacity .15s,transform .15s;}
|
||
.modal-overlay{display:none;position:fixed;inset:0;background:rgba(10,15,30,0.55);backdrop-filter:blur(6px);z-index:1000;align-items:center;justify-content:center;padding:20px;}
|
||
.modal-overlay.open{display:flex;animation:fadeIn .2s ease;}
|
||
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
|
||
.modal-box{background:#fff;border-radius:20px;width:100%;max-width:720px;max-height:90vh;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 32px 80px rgba(15,23,42,0.25);animation:slideUp .25s ease;}
|
||
@keyframes slideUp{from{transform:translateY(30px);opacity:0}to{transform:translateY(0);opacity:1}}
|
||
.modal-header{padding:20px 24px 16px;border-bottom:1px solid #e4eaf5;display:flex;align-items:center;gap:14px;flex-shrink:0;}
|
||
.modal-ava{width:50px;height:50px;border-radius:14px;display:flex;align-items:center;justify-content:center;font-size:21px;font-weight:800;color:#fff;flex-shrink:0;}
|
||
.modal-name{font-size:17px;font-weight:800;}
|
||
.modal-role{font-size:12px;color:#7c8db0;font-weight:600;margin-top:2px;}
|
||
.modal-close{margin-left:auto;background:#f1f5f9;border:none;width:34px;height:34px;border-radius:50%;cursor:pointer;font-size:18px;display:flex;align-items:center;justify-content:center;color:#7c8db0;transition:background .2s;}
|
||
.modal-close:hover{background:#e2e8f0;color:#0f172a;}
|
||
.modal-summary{display:grid;grid-template-columns:repeat(4,1fr);background:#f8fafd;border-bottom:1px solid #e4eaf5;flex-shrink:0;}
|
||
.ms-box{padding:14px 18px;text-align:center;border-right:1px solid #e4eaf5;}
|
||
.ms-box:last-child{border-right:none;}
|
||
.ms-num{font-size:19px;font-weight:800;}
|
||
.ms-lbl{font-size:10px;color:#7c8db0;font-weight:700;letter-spacing:.05em;margin-top:2px;}
|
||
.modal-body{padding:22px 24px;overflow-y:auto;flex:1;}
|
||
.overall-prog{background:linear-gradient(135deg,#0f172a,#1e293b);border-radius:14px;padding:18px 20px;color:#fff;margin-bottom:20px;}
|
||
.op-label{font-size:10px;font-weight:700;letter-spacing:.08em;color:#94a3b8;}
|
||
.op-row{display:flex;justify-content:space-between;align-items:flex-end;margin:6px 0 12px;}
|
||
.op-achieved{font-size:24px;font-weight:800;}
|
||
.op-target{font-size:12px;color:#94a3b8;font-weight:600;}
|
||
.op-pct{font-size:26px;font-weight:800;color:#818cf8;}
|
||
.op-bar-wrap{background:rgba(255,255,255,0.12);height:7px;border-radius:99px;overflow:hidden;}
|
||
.op-bar-fill{height:100%;border-radius:99px;background:linear-gradient(90deg,#818cf8,#67e8f9);}
|
||
.op-foot{display:flex;justify-content:space-between;font-size:11px;color:#94a3b8;font-weight:600;margin-top:7px;}
|
||
.split-section-title{font-size:13px;font-weight:800;margin-bottom:12px;}
|
||
.split-table{width:100%;border-collapse:collapse;font-size:13px;}
|
||
.split-table thead th{background:#f8fafd;padding:9px 12px;text-align:left;font-size:10px;text-transform:uppercase;letter-spacing:.07em;color:#7c8db0;font-family:'DM Mono',monospace;font-weight:500;border-bottom:2px solid #e4eaf5;}
|
||
.split-table thead th:last-child{text-align:right;}
|
||
.split-table tbody tr{border-bottom:1px solid #f1f5f9;}
|
||
.split-table tbody tr:hover{background:#f8fafd;}
|
||
.split-table td{padding:12px;vertical-align:middle;}
|
||
.split-table td:last-child{text-align:right;}
|
||
.split-name{font-weight:700;font-size:13px;}
|
||
.split-dates{font-size:11px;color:#7c8db0;font-weight:600;margin-top:1px;}
|
||
.mini-prog-wrap{width:80px;height:4px;background:#e4eaf5;border-radius:99px;overflow:hidden;margin-top:4px;}
|
||
.mini-prog-bar{height:100%;border-radius:99px;}
|
||
.split-pct-badge{display:inline-block;padding:3px 10px;border-radius:99px;font-size:11px;font-weight:700;}
|
||
.act-chips{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px;}
|
||
.act-chip{display:flex;align-items:center;gap:6px;background:#f1f5f9;border-radius:99px;padding:5px 13px;font-size:12px;font-weight:700;}
|
||
.act-dot{width:7px;height:7px;border-radius:50%;}
|
||
@media(max-width:900px){.list-col-head,.achieve-row{grid-template-columns:220px 1fr 110px 110px 110px;}.col-lbl:nth-child(6),.col-lbl:nth-child(7),.achieve-row>*:nth-child(6),.achieve-row>*:nth-child(7){display:none;}}
|
||
@media(max-width:640px){body{padding:14px;}.list-col-head{display:none;}.achieve-row{grid-template-columns:1fr auto;gap:12px;padding:14px 16px;}.achieve-row>*:not(:nth-child(1)):not(:nth-child(7)){display:none;}.section-head{flex-direction:column;align-items:flex-start;gap:12px;}.modal-summary{grid-template-columns:repeat(2,1fr);}}
|
||
</style>
|
||
|
||
<div class="dash-container">
|
||
|
||
<div>
|
||
<div class="page-title">Branch Dashboard </div>
|
||
<div class="section-sub"><span>FY : {financial_year dropdown selected value here}</span></div>
|
||
<div style="position: relative;">
|
||
<select id="financial_year" name="financial_year" onchange="onFinancialYearChange(this)" style="background:#f5f5f5; padding:10px 20px; border-radius:8px; border:none; width: 250px; font-size: 13px; cursor: pointer;">
|
||
<?php if(!empty($fin_years)): ?>
|
||
<?php foreach($fin_years as $year): ?>
|
||
<option value="<?= $year; ?>"><?= $year; ?></option>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ── Stat Cards ── -->
|
||
<div class="stat-cards">
|
||
<div class="card-hero">
|
||
<div class="stat-icon" style="background:#ede9fe;">👥</div>
|
||
<div class="stat-val"><?php echo $total_leads; ?></div>
|
||
<div class="stat-label">Total Leads</div>
|
||
</div>
|
||
<div class="card-hero">
|
||
<div class="stat-icon" style="background:#fce7f3;">⚡</div>
|
||
<div class="stat-val"><?php echo $total_acts ?></div>
|
||
<div class="stat-label">Total Activities</div>
|
||
</div>
|
||
<div class="card-hero">
|
||
<div class="stat-icon" style="background:#fef3c7;">⏳</div>
|
||
<div class="stat-val"><?php echo $total_pending_acts ?></div>
|
||
<div class="stat-label">Pending Activities</div>
|
||
</div>
|
||
<div class="card-hero">
|
||
<div class="stat-icon" style="background:#d1fae5;">✅</div>
|
||
<div class="stat-val"><?php echo $total_completed_acts ?></div>
|
||
<div class="stat-label">Completed Activities</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ══════════════════════════════════════════
|
||
🏆 TEAM ACHIEVEMENT SECTION (NEW)
|
||
══════════════════════════════════════════ -->
|
||
<div class="section-head">
|
||
<div>
|
||
<div class="section-title">Team Achievement Overview</div>
|
||
<div class="section-sub">Click any row to view split-wise achievement history</div>
|
||
</div>
|
||
<div class="branch-summary">
|
||
<div style="font-size:11px;color:#7c8db0;font-weight:700;">Branch Total</div>
|
||
<div class="branch-amt">₹62.5L <span style="font-size:13px;color:#7c8db0;font-weight:600;">/ ₹100L</span></div>
|
||
<div class="branch-bar-wrap"><div class="branch-bar-fill" style="width:62.5%;"></div></div>
|
||
<div class="branch-pct-lbl">62.5% of branch target</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="achieve-list">
|
||
<div class="list-col-head">
|
||
<div class="col-lbl">Member</div>
|
||
<div class="col-lbl">Progress</div>
|
||
<div class="col-lbl right">Achieved</div>
|
||
<div class="col-lbl right">Target</div>
|
||
<div class="col-lbl right">Remaining</div>
|
||
<div class="col-lbl center">Status</div>
|
||
<div class="col-lbl center">Acts</div>
|
||
</div>
|
||
<div id="achieveList"></div>
|
||
</div>
|
||
<br>
|
||
|
||
<!-- ── Main Grid ── -->
|
||
<div class="main-grid">
|
||
|
||
<!-- LEFT: Pending Activities -->
|
||
<div class="card">
|
||
<div class="table-header">
|
||
<h3 style="font-size:15px; font-weight:700; margin:0;">Pending Activities — All Team</h3>
|
||
<span style="color:#8896aa; font-size:12px; font-weight:600;">
|
||
<?= count($pending_acts) . ' ' . (count($pending_acts) == 1 ? 'activity' : 'activities') ?>
|
||
</span>
|
||
</div>
|
||
<div class="table-scroll-area">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Company</th>
|
||
<th>Activity & Assigned</th>
|
||
<th>Date</th>
|
||
<th>Status</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php if (!empty($pending_acts)): ?>
|
||
<?php foreach ($pending_acts as $a): ?>
|
||
<?php
|
||
$activityIcons = ['Call'=>'📞','Email'=>'✉️','Meeting'=>'📅','Visit'=>'🚗','Demo'=>'🖥️','Share Docs'=>'📄','To Do'=>'✓'];
|
||
$icon = $activityIcons[$a['activity_type']] ?? '📌';
|
||
$statusClass = strtolower(str_replace(' ', '-', $a['status']));
|
||
$formattedscheduledDate = date('M d, Y, h:i A', strtotime($a['scheduled_date']));
|
||
?>
|
||
<tr>
|
||
<td><strong><?= esc($a['company_name']) ?></strong></td>
|
||
<td>
|
||
<div style="color:#ff6b35; font-weight:700; font-size:11px;"><?= $icon ?> <?= strtoupper(esc($a['activity_type'])) ?></div>
|
||
<div style="font-size:12px; color:#8896aa;"><?= esc($a['assigned_to_name'] ?? 'ID: ' . $a['assigned_to']) ?></div>
|
||
</td>
|
||
<td style="color:#4a5568; font-weight:500; font-size:13px;"><?= $formattedscheduledDate ?></td>
|
||
<td><span class="status-pill status-<?= $statusClass ?>"><?= ucfirst(esc($a['status'])) ?></span></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
<?php else: ?>
|
||
<tr><td colspan="4"><div class="empty-state"><div class="empty-icon">✓</div>No pending activities</div></td></tr>
|
||
<?php endif; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- RIGHT: Sales Team Performance + Activity Breakdown -->
|
||
<div class="right-panel">
|
||
<div style="font-size:15px; font-weight:700; padding-bottom:10px; border-bottom:1px solid #f0f4fa; flex-shrink:0;">
|
||
Sales Team Performance
|
||
</div>
|
||
|
||
<div class="team-members-scroll">
|
||
<?php
|
||
if (!empty($team)):
|
||
$colors = ['#ff6b35','#667eea','#48bb78','#ed8936','#9f7aea'];
|
||
foreach ($team as $member):
|
||
$firstLetter = strtoupper(substr($member['first_name'], 0, 1));
|
||
$fullName = $member['first_name'] . ' ' . $member['last_name'];
|
||
$color = $colors[abs(crc32($member['first_name'])) % count($colors)];
|
||
?>
|
||
<div class="team-member">
|
||
<div class="member-img" style="background:<?= $color ?>;"><?= $firstLetter ?></div>
|
||
<div style="flex:1;">
|
||
<div style="font-weight:700; font-size:14px;"><?= esc($fullName) ?></div>
|
||
<div style="font-size:11px; color:#8896aa;"><?= esc($member['role']) ?></div>
|
||
</div>
|
||
<div class="act-stats">
|
||
<div class="total"><?= $member['total_acts'] ?> acts</div>
|
||
<div class="done"><?= $member['done_acts'] ?> done</div>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; else: ?>
|
||
<div class="empty-state">No team data found</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
<div class="breakdown-section">
|
||
<h3 style="font-size:13px; font-weight:700; margin:0 0 12px 0; color:#1a202c;">Activity Breakdown</h3>
|
||
<?php
|
||
$activityConfig = [
|
||
'Call' => ['color'=>'#667eea','icon'=>'📞'],
|
||
'Email' => ['color'=>'#48bb78','icon'=>'✉️'],
|
||
'Meeting' => ['color'=>'#4299e1','icon'=>'📅'],
|
||
'Visit' => ['color'=>'#ecc94b','icon'=>'🚗'],
|
||
'Demo' => ['color'=>'#9f7aea','icon'=>'🖥️'],
|
||
'Share Docs' => ['color'=>'#ed8936','icon'=>'📄'],
|
||
'To Do' => ['color'=>'#718096','icon'=>'✓'],
|
||
];
|
||
?>
|
||
<?php if (!empty($activity_breakdown)): ?>
|
||
<?php foreach ($activity_breakdown as $item): ?>
|
||
<?php $cfg = $activityConfig[$item['activity_type']] ?? ['color'=>'#718096','icon'=>'📌']; ?>
|
||
<div class="breakdown-item">
|
||
<span style="min-width:90px;"><?= $cfg['icon'] ?> <?= esc($item['activity_type']) ?></span>
|
||
<div class="breakdown-bar-wrap">
|
||
<div class="breakdown-bar" style="width:<?= $item['percentage'] ?>%; background:<?= $cfg['color'] ?>;"></div>
|
||
</div>
|
||
<strong style="min-width:34px; text-align:right; color:#1a202c;"><?= $item['percentage'] ?>%</strong>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
<?php else: ?>
|
||
<div style="text-align:center; color:#aaa; font-size:13px;">No activities found</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
|
||
</div><!-- end .main-grid -->
|
||
|
||
<!-- ── All Leads Overview ── -->
|
||
<div class="card" style="width:100%; box-sizing:border-box;">
|
||
<div class="table-header">
|
||
<h3 style="font-size:15px; font-weight:700; margin:0;">All Leads Overview</h3>
|
||
</div>
|
||
<div class="leads-table-wrap">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Company</th>
|
||
<th>Status</th>
|
||
<th>Assigned To</th>
|
||
<th style="text-align:center;">Activities</th>
|
||
<th style="text-align:center;">Opportunities</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php if (!empty($leads_overview)): ?>
|
||
<?php foreach ($leads_overview as $lead): ?>
|
||
<?php $statusClass = strtolower(str_replace(' ', '-', $lead['status'])); ?>
|
||
<tr>
|
||
<td><strong><?= esc($lead['company_name']) ?></strong></td>
|
||
<td><span class="status-pill status-<?= $statusClass ?>"><?= esc($lead['status']) ?></span></td>
|
||
<td><?= esc($lead['assigned_to'] ?? 'Unassigned') ?></td>
|
||
<td><div style="text-align:center; font-weight:700;"><?= $lead['activities'] ?></div></td>
|
||
<td><div style="text-align:center; font-weight:700;"><?= $lead['opportunities'] ?></div></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
<?php else: ?>
|
||
<tr><td colspan="5"><div class="empty-state"><div class="empty-icon">👤</div>No leads found</div></td></tr>
|
||
<?php endif; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="modal-overlay" id="modalOverlay">
|
||
<div class="modal-box">
|
||
<div class="modal-header">
|
||
<div class="modal-ava" id="modalAva"></div>
|
||
<div><div class="modal-name" id="modalName"></div><div class="modal-role" id="modalRole"></div></div>
|
||
<button class="modal-close" onclick="closeModal()">✕</button>
|
||
</div>
|
||
<div class="modal-summary" id="modalSummary"></div>
|
||
<div class="modal-body" id="modalBody"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- end .dash-container -->
|
||
<script>
|
||
const TEAM=[{id:1,first:'Divya',last:'Rao',role:'Senior Sales Executive',total_acts:88,done_acts:82,target_amt:2500000,achieved_amt:2510000,grad:'linear-gradient(135deg,#10b981,#34d399)',color:'#10b981',splits:[{name:'Q1 (Apr-Jun 2024)',start:'Apr 2024',end:'Jun 2024',target:625000,achieved:650000,acts:22,done:21,leads:16},{name:'Q2 (Jul-Sep 2024)',start:'Jul 2024',end:'Sep 2024',target:625000,achieved:610000,acts:22,done:20,leads:15},{name:'Q3 (Oct-Dec 2024)',start:'Oct 2024',end:'Dec 2024',target:625000,achieved:640000,acts:24,done:22,leads:17},{name:'Q4 (Jan-Mar 2025)',start:'Jan 2025',end:'Mar 2025',target:625000,achieved:610000,acts:20,done:19,leads:14}],activities:{Call:35,Email:20,Meeting:19,Visit:9,Demo:5}},{id:2,first:'Priya',last:'Nair',role:'Sales Executive',total_acts:74,done_acts:68,target_amt:2000000,achieved_amt:1940000,grad:'linear-gradient(135deg,#06b6d4,#67e8f9)',color:'#06b6d4',splits:[{name:'Q1 (Apr-Jun 2024)',start:'Apr 2024',end:'Jun 2024',target:500000,achieved:495000,acts:19,done:18,leads:12},{name:'Q2 (Jul-Sep 2024)',start:'Jul 2024',end:'Sep 2024',target:500000,achieved:510000,acts:18,done:17,leads:11},{name:'Q3 (Oct-Dec 2024)',start:'Oct 2024',end:'Dec 2024',target:500000,achieved:487000,acts:20,done:18,leads:13},{name:'Q4 (Jan-Mar 2025)',start:'Jan 2025',end:'Mar 2025',target:500000,achieved:448000,acts:17,done:15,leads:10}],activities:{Call:28,Email:22,Meeting:15,Visit:6,Demo:3}},{id:3,first:'Arjun',last:'Sharma',role:'Senior Sales Executive',total_acts:92,done_acts:78,target_amt:2500000,achieved_amt:1975000,grad:'linear-gradient(135deg,#4f46e5,#818cf8)',color:'#4f46e5',splits:[{name:'Q1 (Apr-Jun 2024)',start:'Apr 2024',end:'Jun 2024',target:625000,achieved:582000,acts:24,done:21,leads:18},{name:'Q2 (Jul-Sep 2024)',start:'Jul 2024',end:'Sep 2024',target:625000,achieved:510000,acts:23,done:20,leads:14},{name:'Q3 (Oct-Dec 2024)',start:'Oct 2024',end:'Dec 2024',target:625000,achieved:498000,acts:22,done:19,leads:16},{name:'Q4 (Jan-Mar 2025)',start:'Jan 2025',end:'Mar 2025',target:625000,achieved:385000,acts:23,done:18,leads:12}],activities:{Call:32,Email:18,Meeting:22,Visit:12,Demo:8}},{id:4,first:'Rahul',last:'Verma',role:'Sales Executive',total_acts:67,done_acts:56,target_amt:1500000,achieved_amt:1005000,grad:'linear-gradient(135deg,#ec4899,#f9a8d4)',color:'#ec4899',splits:[{name:'Q1 (Apr-Jun 2024)',start:'Apr 2024',end:'Jun 2024',target:375000,achieved:285000,acts:17,done:14,leads:10},{name:'Q2 (Jul-Sep 2024)',start:'Jul 2024',end:'Sep 2024',target:375000,achieved:262000,acts:17,done:15,leads:9},{name:'Q3 (Oct-Dec 2024)',start:'Oct 2024',end:'Dec 2024',target:375000,achieved:250000,acts:18,done:15,leads:11},{name:'Q4 (Jan-Mar 2025)',start:'Jan 2025',end:'Mar 2025',target:375000,achieved:208000,acts:15,done:12,leads:8}],activities:{Call:22,Email:16,Meeting:17,Visit:7,Demo:5}},{id:5,first:'Kiran',last:'Menon',role:'Junior Sales Executive',total_acts:65,done_acts:44,target_amt:1500000,achieved_amt:820000,grad:'linear-gradient(135deg,#f97316,#fbbf24)',color:'#f97316',splits:[{name:'Q1 (Apr-Jun 2024)',start:'Apr 2024',end:'Jun 2024',target:375000,achieved:240000,acts:17,done:11,leads:9},{name:'Q2 (Jul-Sep 2024)',start:'Jul 2024',end:'Sep 2024',target:375000,achieved:195000,acts:16,done:10,leads:8},{name:'Q3 (Oct-Dec 2024)',start:'Oct 2024',end:'Dec 2024',target:375000,achieved:210000,acts:18,done:13,leads:10},{name:'Q4 (Jan-Mar 2025)',start:'Jan 2025',end:'Mar 2025',target:375000,achieved:175000,acts:14,done:10,leads:7}],activities:{Call:20,Email:14,Meeting:18,Visit:8,Demo:5}}];
|
||
const ACT_ICONS={Call:'📞',Email:'✉️',Meeting:'📅',Visit:'🚗',Demo:'🖥️','Share Docs':'📄','To Do':'✓'};
|
||
const ACT_COLORS={Call:'#4f46e5',Email:'#10b981',Meeting:'#06b6d4',Visit:'#f59e0b',Demo:'#ec4899','Share Docs':'#f97316','To Do':'#64748b'};
|
||
const fmt=v=>'₹'+(v/100000).toFixed(1)+'L';
|
||
const pct=(a,t)=>t>0?Math.min(100,Math.round(a/t*100)):0;
|
||
const badge=p=>p>=100?['b-achieved','🏆 Achieved']:p>=75?['b-ontrack','🎯 On Track']:p>=50?['b-behind','⚡ Behind']:['b-atrisk','⚠️ At Risk'];
|
||
const progColor=p=>p>=100?'linear-gradient(90deg,#10b981,#34d399)':p>=75?'linear-gradient(90deg,#06b6d4,#67e8f9)':p>=50?'linear-gradient(90deg,#f97316,#fbbf24)':'linear-gradient(90deg,#ef4444,#fca5a5)';
|
||
|
||
function renderList(){
|
||
const sorted=[...TEAM].sort((a,b)=>pct(b.achieved_amt,b.target_amt)-pct(a.achieved_amt,a.target_amt));
|
||
document.getElementById('achieveList').innerHTML=sorted.map((m,i)=>{
|
||
const p=pct(m.achieved_amt,m.target_amt);
|
||
const rem=Math.max(0,m.target_amt-m.achieved_amt);
|
||
const [bc,bt]=badge(p);
|
||
// const rankLabel=i===0?'🥇':i===1?'🥈':i===2?'🥉':'#'+(i+1);
|
||
const rankLabel = '#'+(i+1);
|
||
return `<div class="achieve-row" onclick="openModal(${m.id})">
|
||
<div class="member-cell">
|
||
<div style="font-size:14px;font-weight:800;color:#cbd5e1;min-width:26px;font-family:'DM Mono',monospace;">${rankLabel}</div>
|
||
<div class="m-avatar" style="background:${m.grad};">${m.first[0]}</div>
|
||
<div><div class="m-name">${m.first} ${m.last}</div></div>
|
||
</div>
|
||
<div style="padding-right:20px;">
|
||
<div class="prog-row"><span class="prog-pct" style="color:${m.color};">${p}%</span><span class="prog-amts">${fmt(m.achieved_amt)} / ${fmt(m.target_amt)}</span></div>
|
||
<div class="prog-bar-wrap"><div class="prog-bar" style="width:${p}%;background:${m.grad};"></div></div>
|
||
</div>
|
||
<div class="num-cell"><div class="num-val" style="color:#0f172a;">${fmt(m.achieved_amt)}</div></div>
|
||
<div class="num-cell"><div class="num-val" style="color:#7c8db0;">${fmt(m.target_amt)}</div></div>
|
||
<div class="num-cell"><div class="num-val" style="color:${rem>0?'#f97316':'#10b981'};">${rem>0?fmt(rem):'—'}</div></div>
|
||
<div style="display:flex;justify-content:center;"><span class="badge ${bc}">${bt}</span></div>
|
||
<div class="num-cell center-col"><div class="num-val">${m.done_acts}<span style="color:#cbd5e1;font-size:12px;font-weight:600;">/${m.total_acts}</span></div><div class="num-lbl">DONE/TOTAL</div></div>
|
||
<span class="row-arrow">›</span>
|
||
</div>`;
|
||
}).join('');
|
||
}
|
||
|
||
function openModal(id){
|
||
const m=TEAM.find(x=>x.id===id);if(!m)return;
|
||
const p=pct(m.achieved_amt,m.target_amt);
|
||
const rem=Math.max(0,m.target_amt-m.achieved_amt);
|
||
const [bc,bt]=badge(p);
|
||
document.getElementById('modalAva').style.background=m.grad;
|
||
document.getElementById('modalAva').textContent=m.first[0];
|
||
document.getElementById('modalName').textContent=m.first+' '+m.last
|
||
document.getElementById('modalRole').textContent=m.role;
|
||
document.getElementById('modalSummary').innerHTML=`
|
||
<div class="ms-box"><div class="ms-num" style="color:#4f46e5;">${fmt(m.achieved_amt)}</div><div class="ms-lbl">ACHIEVED</div></div>
|
||
<div class="ms-box"><div class="ms-num">${fmt(m.target_amt)}</div><div class="ms-lbl">TARGET</div></div>
|
||
<div class="ms-box"><div class="ms-num" style="color:#f97316;">${fmt(rem)}</div><div class="ms-lbl">REMAINING</div></div>
|
||
<div class="ms-box"><div class="ms-num" style="color:${p>=75?'#10b981':p>=50?'#f97316':'#ef4444'};">${p}%</div><div class="ms-lbl">ACHIEVED %</div></div>`;
|
||
const splitRows=m.splits.map((s,i)=>{
|
||
const sp=pct(s.achieved,s.target);
|
||
const [sbc,sbt]=badge(sp);
|
||
const srem=Math.max(0,s.target-s.achieved);
|
||
return `<tr>
|
||
<td><div class="split-name">Split ${i+1}: ${s.name}</div><div class="split-dates">📅 ${s.start} → ${s.end}</div></td>
|
||
<td><div style="font-weight:800;">${fmt(s.achieved)}</div><div class="mini-prog-wrap"><div class="mini-prog-bar" style="width:${sp}%;background:${progColor(sp)};"></div></div></td>
|
||
<td style="font-weight:700;color:#7c8db0;">${fmt(s.target)}</td>
|
||
<td style="font-weight:700;color:#f97316;">${srem>0?fmt(srem):'—'}</td>
|
||
<td><span class="split-pct-badge ${sbc}">${sp}% · ${sbt}</span></td>
|
||
<td style="font-weight:700;">${s.done}<span style="color:#cbd5e1;">/${s.acts}</span></td>
|
||
<td style="font-weight:700;">${s.leads}</td>
|
||
</tr>`;
|
||
}).join('');
|
||
const actChips=Object.entries(m.activities).map(([k,v])=>`<div class="act-chip"><div class="act-dot" style="background:${ACT_COLORS[k]||'#64748b'};"></div>${ACT_ICONS[k]||'📌'} ${k}: <strong>${v}</strong></div>`).join('');
|
||
document.getElementById('modalBody').innerHTML=`
|
||
<div class="overall-prog">
|
||
<div class="op-label">OVERALL TARGET ACHIEVEMENT</div>
|
||
<div class="op-row"><div><div class="op-achieved">${fmt(m.achieved_amt)}</div><div class="op-target">of ${fmt(m.target_amt)} target</div></div><div class="op-pct">${p}%</div></div>
|
||
<div class="op-bar-wrap"><div class="op-bar-fill" style="width:${p}%;"></div></div>
|
||
<div class="op-foot"><span>Remaining: <strong style="color:#fbbf24;">${fmt(rem)}</strong></span><span class="badge ${bc}" style="background:rgba(255,255,255,.1);color:#e2e8f0;">${bt}</span></div>
|
||
</div>
|
||
<div class="split-section-title">📊 Split-wise Achievement Breakdown</div>
|
||
<div style="overflow-x:auto;margin-bottom:20px;">
|
||
<table class="split-table">
|
||
<thead><tr><th>Split Period</th><th>Achieved</th><th>Target</th><th>Remaining</th><th>Status</th><th>Activities</th><th>Leads</th></tr></thead>
|
||
<tbody>${splitRows}</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="split-section-title">⚡ Activity Breakdown</div>
|
||
<div class="act-chips">${actChips}</div>`;
|
||
document.getElementById('modalOverlay').classList.add('open');
|
||
document.body.style.overflow='hidden';
|
||
}
|
||
function closeModal(){document.getElementById('modalOverlay').classList.remove('open');document.body.style.overflow='';}
|
||
document.getElementById('modalOverlay').addEventListener('click',e=>{if(e.target===e.currentTarget)closeModal();});
|
||
document.addEventListener('keydown',e=>{if(e.key==='Escape')closeModal();});
|
||
renderList();
|
||
document.addEventListener('DOMContentLoaded', function () {
|
||
const params = new URLSearchParams(window.location.search);
|
||
const fy = params.get('fy');
|
||
if (fy) {
|
||
document.getElementById('financial_year').value = fy;
|
||
}
|
||
});
|
||
|
||
function onFinancialYearChange(select) {
|
||
const url = new URL(window.location.href);
|
||
url.searchParams.set('fy', select.value);
|
||
window.location.href = url.toString();
|
||
}
|
||
</script>
|