nhance/app/Views/sales/branch_level_dashboard_view_3mar.php
2026-03-06 22:24:42 +05:30

592 lines
36 KiB
PHP
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.

<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 &amp; 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()">&#x2715;</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>