| Server IP : 69.72.244.102 / Your IP : 216.73.216.164 Web Server : LiteSpeed System : Linux s3434.fra1.stableserver.net 4.18.0-513.24.1.lve.2.el8.x86_64 #1 SMP Fri May 24 12:42:50 UTC 2024 x86_64 User : konzalta ( 1271) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/konzalta/constituency.work/ |
Upload File : |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ConstituencyOS โ Social Protection</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
<style>
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0;}
:root{
--green:#1a7a4a;--green-light:#e8f5ee;--green-mid:#2d9e63;
--red:#dc2626;--red-light:#fdecea;
--amber:#f59e0b;--amber-light:#fffbeb;
--blue:#2563eb;--blue-light:#eff6ff;
--purple:#7c3aed;--purple-light:#f5f3ff;
--orange:#ea580c;--orange-light:#fff7ed;
--text:#111827;--muted:#6b7280;--light:#9ca3af;
--border:#e5e7eb;--bg:#f3f4f6;--white:#ffffff;
--sidebar-w:216px;--radius:10px;--radius-sm:6px;
--shadow:0 1px 3px rgba(0,0,0,.08);
}
html,body{height:100%;margin:0;padding:0;}
body{font-family:'Inter',sans-serif;font-size:13px;color:var(--text);background:var(--bg);}
.sidebar{position:fixed;top:0;left:0;bottom:0;width:var(--sidebar-w);background:var(--white);border-right:1px solid var(--border);display:flex;flex-direction:column;overflow-y:auto;overflow-x:hidden;z-index:40;}
.sidebar-logo{display:flex;align-items:center;gap:9px;padding:14px 14px 12px;border-bottom:1px solid var(--border);flex-shrink:0;}
.logo-icon{width:38px;height:38px;background:linear-gradient(135deg,#b91c1c,#1a7a4a);border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:17px;flex-shrink:0;}
.logo-text strong{display:block;font-size:12.5px;font-weight:700;color:var(--green);}
.logo-text small{font-size:10px;color:var(--muted);line-height:1.3;}
.sidebar-profile{display:flex;align-items:center;gap:9px;padding:11px 14px;border-bottom:1px solid var(--border);flex-shrink:0;}
.s-av{width:36px;height:36px;border-radius:50%;background:#374151;color:white;font-weight:600;font-size:13px;display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;}
.s-av .dot{position:absolute;bottom:1px;right:1px;width:8px;height:8px;border-radius:50%;background:var(--green-mid);border:2px solid white;}
.pname{font-size:11.5px;font-weight:600;}.psub{font-size:10.5px;color:var(--muted);}
.sidebar-nav{flex:1;padding:6px 0;}
.nav-item{display:flex;align-items:center;gap:9px;padding:8px 14px;font-size:12px;font-weight:500;color:var(--muted);cursor:pointer;position:relative;transition:background .12s,color .12s;white-space:nowrap;}
.nav-item:hover{background:var(--bg);color:var(--text);}
.nav-item.active{background:var(--green-light);color:var(--green);font-weight:600;}
.nav-item.active::before{content:'';position:absolute;left:0;top:0;bottom:0;width:3px;background:var(--green);border-radius:0 2px 2px 0;}
.nav-icon{font-size:14px;width:16px;text-align:center;flex-shrink:0;}
.nav-badge{margin-left:auto;background:var(--red);color:white;font-size:9.5px;font-weight:700;padding:1px 5px;border-radius:10px;}
.nav-new{margin-left:auto;background:var(--green);color:white;font-size:9px;font-weight:700;padding:2px 5px;border-radius:4px;}
.nav-chev{margin-left:auto;font-size:10px;color:var(--light);}
.sidebar-footer{padding:12px 14px;border-top:1px solid var(--border);flex-shrink:0;}
.right-panel{margin-left:var(--sidebar-w);display:flex;flex-direction:column;min-height:100vh;}
.topbar{position:sticky;top:0;z-index:30;height:52px;background:var(--white);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;padding:0 18px;}
.menu-btn{font-size:17px;cursor:pointer;color:var(--muted);}
.const-sel{display:flex;align-items:center;gap:6px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:5px 10px;cursor:pointer;font-size:12px;font-weight:500;}
.srch{flex:1;max-width:360px;display:flex;align-items:center;gap:7px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:6px 11px;color:var(--muted);font-size:12px;}
.srch input{border:none;background:transparent;outline:none;width:100%;font-size:12px;font-family:inherit;}
.srch kbd{margin-left:auto;font-size:9.5px;background:var(--border);padding:1px 5px;border-radius:3px;font-family:inherit;}
.tbr{margin-left:auto;display:flex;align-items:center;gap:8px;}
.ibt{position:relative;width:32px;height:32px;border-radius:50%;background:var(--bg);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:15px;}
.ibt .bdg{position:absolute;top:-3px;right:-3px;background:var(--red);color:white;font-size:9px;font-weight:700;width:15px;height:15px;border-radius:50%;display:flex;align-items:center;justify-content:center;border:1.5px solid white;}
.ibt .bdg.grn{background:var(--green-mid);}
.upill{display:flex;align-items:center;gap:7px;border:1px solid var(--border);border-radius:var(--radius-sm);padding:3px 8px;cursor:pointer;font-size:12px;font-weight:500;}
.content{padding:18px 18px 40px;display:flex;flex-direction:column;gap:14px;}
.btn{display:inline-flex;align-items:center;gap:6px;padding:7px 14px;border-radius:var(--radius-sm);font-size:12px;font-weight:600;cursor:pointer;border:none;transition:background .15s;}
.btn-primary{background:var(--green);color:white;}.btn-primary:hover{background:var(--green-mid);}
.btn-ghost{background:var(--white);color:var(--text);border:1px solid var(--border);}.btn-ghost:hover{background:var(--bg);}
.page-hdr{display:flex;align-items:flex-start;justify-content:space-between;}
.page-title{font-size:19px;font-weight:700;}
.page-sub{font-size:12px;color:var(--muted);margin-top:2px;}
/* METRIC CARDS */
.metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;}
.mc{background:var(--white);border:1px solid var(--border);border-radius:var(--radius);padding:14px 16px;cursor:pointer;transition:box-shadow .15s;}
.mc:hover,.mc.active{box-shadow:0 0 0 2px var(--green-light);border-color:var(--green);}
.mc-icon{font-size:24px;margin-bottom:6px;}
.mc-val{font-size:26px;font-weight:700;line-height:1;}
.mc-lbl{font-size:11px;color:var(--muted);margin-top:3px;}
.mc-sub{font-size:10.5px;margin-top:5px;}
.mc-bar{height:4px;background:var(--border);border-radius:4px;margin-top:8px;}
.mc-bar-fill{height:100%;border-radius:4px;}
/* LAYOUT */
.main-layout{display:grid;grid-template-columns:1fr 280px;gap:14px;align-items:start;}
/* TOOLBAR */
.toolbar{display:flex;align-items:center;gap:10px;background:var(--white);border:1px solid var(--border);border-radius:var(--radius);padding:10px 14px;flex-wrap:wrap;}
.sb{flex:1;min-width:180px;display:flex;align-items:center;gap:7px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:7px 11px;}
.sb input{border:none;background:transparent;outline:none;width:100%;font-size:12px;font-family:inherit;color:var(--text);}
.fsel{display:flex;align-items:center;gap:5px;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius-sm);padding:6px 10px;font-size:12px;white-space:nowrap;}
.fsel select{border:none;background:transparent;outline:none;font-size:12px;font-family:inherit;color:var(--text);cursor:pointer;}
/* TABLE */
.tcard{background:var(--white);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;}
.twrap{overflow-x:auto;}
table{width:100%;border-collapse:collapse;}
thead tr{background:var(--bg);border-bottom:1px solid var(--border);}
th{padding:9px 14px;font-size:11px;font-weight:600;color:var(--muted);text-align:left;white-space:nowrap;cursor:pointer;user-select:none;}
th:hover{color:var(--text);}
tbody tr{border-bottom:1px solid var(--border);transition:background .1s;cursor:pointer;}
tbody tr:last-child{border-bottom:none;}
tbody tr:hover{background:#f9fafb;}
td{padding:10px 14px;font-size:12px;vertical-align:middle;}
.ctag{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;padding:3px 8px;border-radius:20px;white-space:nowrap;}
.ctag.elderly{background:#fff7ed;color:#c2410c;}
.ctag.pwd{background:var(--blue-light);color:#1d4ed8;}
.ctag.ovc{background:var(--green-light);color:#065f46;}
.stag{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;padding:3px 8px;border-radius:20px;}
.stag.active{background:#ecfdf5;color:#065f46;}
.stag.review{background:var(--amber-light);color:#92400e;}
.stag.suspended{background:var(--red-light);color:#b91c1c;}
.act-btns{display:flex;gap:4px;opacity:0;transition:opacity .15s;}
tbody tr:hover .act-btns{opacity:1;}
.ab{padding:3px 8px;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--white);font-size:10.5px;font-weight:600;cursor:pointer;}
.ab:hover{background:var(--bg);}
/* PAGINATION */
.pgn{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-top:1px solid var(--border);}
.pg-info{font-size:11.5px;color:var(--muted);}
.pg-btns{display:flex;gap:4px;}
.pg-btn{width:28px;height:28px;border-radius:var(--radius-sm);border:1px solid var(--border);background:var(--white);display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:12px;font-weight:500;}
.pg-btn.active{background:var(--green);color:white;border-color:var(--green);}
.pg-btn:hover:not(.active){background:var(--bg);}
/* RIGHT COLUMN */
.rcol{display:flex;flex-direction:column;gap:12px;}
.rcard{background:var(--white);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;}
.rcard-hdr{padding:12px 14px;border-bottom:1px solid var(--border);font-size:12.5px;font-weight:600;display:flex;justify-content:space-between;align-items:center;}
.vlink{font-size:11px;color:var(--green);cursor:pointer;font-weight:500;}
/* WARD BREAKDOWN */
.ward-row{display:flex;align-items:center;gap:8px;padding:8px 14px;border-bottom:1px solid var(--border);font-size:12px;}
.ward-row:last-child{border-bottom:none;}
.ward-name{width:90px;flex-shrink:0;font-weight:500;}
.ward-bar-wrap{flex:1;height:8px;background:var(--border);border-radius:8px;overflow:hidden;}
.ward-bar-fill{height:100%;border-radius:8px;}
.ward-count{width:32px;text-align:right;font-weight:700;font-size:11px;}
/* PAYMENT SCHEDULE */
.pay-item{display:flex;align-items:center;gap:10px;padding:9px 14px;border-bottom:1px solid var(--border);font-size:12px;}
.pay-item:last-child{border-bottom:none;}
.pay-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;}
.pay-month{font-weight:600;flex:1;}
.pay-amt{font-weight:700;color:var(--green);}
.pay-status{font-size:10px;font-weight:600;padding:2px 7px;border-radius:20px;}
.pay-status.done{background:var(--green-light);color:var(--green);}
.pay-status.pending{background:var(--amber-light);color:#92400e;}
/* DETAIL PANEL */
.ov{position:fixed;inset:0;background:rgba(0,0,0,.35);z-index:100;display:none;}
.ov.open{display:flex;align-items:flex-start;justify-content:flex-end;}
.dp{width:430px;height:100%;background:var(--white);box-shadow:-4px 0 24px rgba(0,0,0,.12);display:flex;flex-direction:column;overflow:hidden;}
.dp-hdr{padding:16px 18px;border-bottom:1px solid var(--border);flex-shrink:0;display:flex;align-items:flex-start;gap:12px;}
.dp-av{width:50px;height:50px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:20px;font-weight:700;color:white;flex-shrink:0;}
.dp-close{width:28px;height:28px;border-radius:50%;background:var(--bg);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:14px;margin-left:auto;}
.dp-name{font-size:15px;font-weight:700;}
.dp-body{flex:1;overflow-y:auto;padding:18px;display:flex;flex-direction:column;gap:16px;}
.dp-sect{font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:8px;}
.dp-row{display:flex;justify-content:space-between;padding:5px 0;border-bottom:1px solid var(--border);font-size:12px;}
.dp-row:last-child{border-bottom:none;}
.dp-key{color:var(--muted);}.dp-val{font-weight:500;text-align:right;}
.pmt-list{display:flex;flex-direction:column;gap:5px;}
.pmt-item{display:flex;justify-content:space-between;align-items:center;padding:7px 10px;background:var(--bg);border-radius:var(--radius-sm);font-size:11.5px;}
.dp-footer{padding:14px 18px;border-top:1px solid var(--border);display:flex;gap:8px;flex-shrink:0;}
.dp-footer .btn{flex:1;justify-content:center;}
</style>
</head>
<body>
<aside class="sidebar">
<div class="sidebar-logo"><div class="logo-icon">๐๏ธ</div><div class="logo-text"><strong>ConstituencyOS</strong><small>Everything in your constituency,<br>in one place.</small></div></div>
<div class="sidebar-profile"><div class="s-av">DM<div class="dot"></div></div><div><div class="pname">Hon. David Mwangi, MP</div><div class="psub">Embakasi South</div></div></div>
<nav class="sidebar-nav">
<div class="nav-item" onclick="location.href='index.html'"><span class="nav-icon">๐ </span>Dashboard</div>
<div class="nav-item" onclick="location.href='constituents.html'"><span class="nav-icon">๐ฅ</span>Constituents</div>
<div class="nav-item" onclick="location.href='complaints.html'"><span class="nav-icon">๐</span>Complaints<span class="nav-badge">9</span></div>
<div class="nav-item" onclick="location.href='projects.html'"><span class="nav-icon">๐</span>Projects</div>
<div class="nav-item" onclick="location.href='bursaries.html'"><span class="nav-icon">๐</span>Bursaries</div>
<div class="nav-item" onclick="location.href='events.html'"><span class="nav-icon">๐
</span>Events</div>
<div class="nav-item" onclick="location.href='social_protection.html'"><span class="nav-icon">๐ก๏ธ</span>Social Protection</div>
<div class="nav-item" onclick="location.href='ward_management.html'"><span class="nav-icon">๐๏ธ</span>Ward Management</div>
<div class="nav-item" onclick="location.href='finance.html'"><span class="nav-icon">๐ฐ</span>Finance</div>
<div class="nav-item" onclick="location.href='documents.html'"><span class="nav-icon">๐</span>Documents</div>
<div class="nav-item" onclick="location.href='staff_management.html'"><span class="nav-icon">๐ค</span>Staff Management</div>
<div class="nav-item" onclick="location.href='reports_analytics.html'"><span class="nav-icon">๐</span>Reports & Analytics</div>
<div class="nav-item active"><span class="nav-icon">๐ค</span>AI Assistant<span class="nav-new">New</span></div>
<div class="nav-item" onclick="location.href='settings.html'"><span class="nav-icon">โ๏ธ</span>Settings</div>
<div class="nav-item" onclick="location.href='public_portal.html'"><span class="nav-icon">๐</span>Public Portal</div>
</nav>
<div class="sidebar-footer"><div style="display:flex;align-items:center;gap:9px;cursor:pointer"><span>โ</span><div><div style="font-size:11.5px;font-weight:600">Need Help?</div><div style="font-size:10.5px;color:var(--muted)">Contact Support</div></div></div></div>
</aside>
<div class="right-panel">
<header class="topbar">
<span class="menu-btn">โฐ</span>
<div class="const-sel"><span style="font-size:13px">๐๏ธ</span>Embakasi South Constituency<span style="font-size:10px;color:var(--muted)">โผ</span></div>
<div class="srch"><span>๐</span><input type="text" placeholder="Search for anythingโฆ"><kbd>โK</kbd></div>
<div class="tbr">
<div class="ibt">๐<div class="bdg">8</div></div>
<div class="ibt">โ๏ธ<div class="bdg grn">3</div></div>
<div class="upill"><div class="s-av" style="width:26px;height:26px;font-size:10px">DM</div>Hon. David Mwangi<span style="font-size:10px;color:var(--muted)">โผ</span></div>
</div>
</header>
<main class="content">
<div class="page-hdr">
<div><div class="page-title">Social Protection</div><div class="page-sub">Manage beneficiaries across all social protection programmes in Embakasi South</div></div>
<div style="display:flex;gap:8px;">
<button class="btn btn-ghost">โฌ Export</button>
<button class="btn btn-primary">๏ผ Enrol Beneficiary</button>
</div>
</div>
<!-- Metrics -->
<div class="metrics">
<div class="mc active" onclick="filterCat('all',this)">
<div class="mc-icon">๐ก๏ธ</div>
<div class="mc-val" id="cnt-all">0</div>
<div class="mc-lbl">Total Beneficiaries</div>
<div class="mc-sub" style="color:var(--green)">Active this quarter</div>
<div class="mc-bar"><div class="mc-bar-fill" style="width:100%;background:var(--green)"></div></div>
</div>
<div class="mc" onclick="filterCat('Elderly',this)">
<div class="mc-icon">๐ด</div>
<div class="mc-val" style="color:var(--orange)" id="cnt-elderly">0</div>
<div class="mc-lbl">Elderly Support</div>
<div class="mc-sub" style="color:var(--muted)">Age 60+</div>
<div class="mc-bar"><div class="mc-bar-fill" id="bar-elderly" style="background:var(--orange)"></div></div>
</div>
<div class="mc" onclick="filterCat('PWD',this)">
<div class="mc-icon">โฟ</div>
<div class="mc-val" style="color:var(--blue)" id="cnt-pwd">0</div>
<div class="mc-lbl">Persons with Disabilities</div>
<div class="mc-sub" style="color:var(--muted)">PWD programme</div>
<div class="mc-bar"><div class="mc-bar-fill" id="bar-pwd" style="background:var(--blue)"></div></div>
</div>
<div class="mc" onclick="filterCat('OVC',this)">
<div class="mc-icon">๐ถ</div>
<div class="mc-val" style="color:var(--green)" id="cnt-ovc">0</div>
<div class="mc-lbl">Orphans & Vulnerable</div>
<div class="mc-sub" style="color:var(--muted)">OVC programme</div>
<div class="mc-bar"><div class="mc-bar-fill" id="bar-ovc" style="background:var(--green)"></div></div>
</div>
</div>
<div class="main-layout">
<div style="display:flex;flex-direction:column;gap:12px;">
<!-- Toolbar -->
<div class="toolbar">
<div class="sb"><span>๐</span><input type="text" id="searchInput" placeholder="Search by name, ID, wardโฆ" oninput="applyFilters()"></div>
<div class="fsel">๐๏ธ <select id="wardFilter" onchange="applyFilters()">
<option value="">All Wards</option>
<option>Pipeline Ward</option><option>Imara Daima</option><option>Mabatini Ward</option>
<option>Umoja Ward</option><option>Kwa Njenga Ward</option><option>Mihango Ward</option>
</select></div>
<div class="fsel">๐ <select id="statusFilter" onchange="applyFilters()">
<option value="">All Statuses</option>
<option>Active</option><option>Under Review</option><option>Suspended</option>
</select></div>
<div class="fsel">๐ฐ <select id="pgmFilter" onchange="applyFilters()">
<option value="">All Programmes</option>
<option>Cash Transfer</option><option>Food Basket</option><option>Medical Cover</option>
</select></div>
</div>
<!-- Table -->
<div class="tcard">
<div class="twrap">
<table>
<thead><tr>
<th>ID</th><th onclick="sortBy('name')">Name โ</th><th onclick="sortBy('ward')">Ward โ</th>
<th onclick="sortBy('category')">Category โ</th><th>Programme</th>
<th onclick="sortBy('amount')">Stipend (KSh) โ</th><th>Next Payment</th>
<th onclick="sortBy('status')">Status โ</th><th></th>
</tr></thead>
<tbody id="tableBody"></tbody>
</table>
</div>
<div class="pgn">
<div class="pg-info" id="pgInfo"></div>
<div class="pg-btns" id="pgBtns"></div>
</div>
</div>
</div>
<!-- Right column -->
<div class="rcol">
<!-- Ward breakdown -->
<div class="rcard">
<div class="rcard-hdr">Beneficiaries by Ward <span class="vlink">Map view</span></div>
<div id="wardBreakdown"></div>
</div>
<!-- Payment schedule -->
<div class="rcard">
<div class="rcard-hdr">Payment Schedule 2024</div>
<div id="paySchedule"></div>
</div>
<!-- Budget summary -->
<div class="rcard">
<div class="rcard-hdr">Budget Summary</div>
<div style="padding:12px 14px;display:flex;flex-direction:column;gap:8px;">
<div style="display:flex;justify-content:space-between;font-size:12px;"><span style="color:var(--muted)">Annual Budget</span><strong>KSh 18,400,000</strong></div>
<div style="display:flex;justify-content:space-between;font-size:12px;"><span style="color:var(--muted)">Disbursed (Q1โQ2)</span><strong style="color:var(--green)">KSh 9,200,000</strong></div>
<div style="display:flex;justify-content:space-between;font-size:12px;"><span style="color:var(--muted)">Remaining</span><strong style="color:var(--amber)">KSh 9,200,000</strong></div>
<div style="height:8px;background:var(--border);border-radius:8px;overflow:hidden;margin-top:4px;">
<div style="height:100%;width:50%;background:var(--green);border-radius:8px;"></div>
</div>
<div style="font-size:10.5px;color:var(--muted);text-align:center;">50% utilised ยท Q3 payment due Jun 2024</div>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- DETAIL PANEL -->
<div class="ov" id="ov" onclick="closeOv(event)">
<div class="dp">
<div class="dp-hdr">
<div class="dp-av" id="dp-av"></div>
<div><div class="dp-name" id="dp-name"></div><div style="margin-top:5px" id="dp-tags"></div></div>
<div class="dp-close" onclick="closeDp()">โ</div>
</div>
<div class="dp-body">
<div><div class="dp-sect">Personal Details</div>
<div class="dp-row"><span class="dp-key">Beneficiary ID</span><span class="dp-val" id="dp-id"></span></div>
<div class="dp-row"><span class="dp-key">Gender</span><span class="dp-val" id="dp-gender"></span></div>
<div class="dp-row"><span class="dp-key">Age</span><span class="dp-val" id="dp-age"></span></div>
<div class="dp-row"><span class="dp-key">Ward</span><span class="dp-val" id="dp-ward"></span></div>
<div class="dp-row"><span class="dp-key">Village</span><span class="dp-val" id="dp-village"></span></div>
<div class="dp-row"><span class="dp-key">Phone</span><span class="dp-val" id="dp-phone"></span></div>
<div class="dp-row"><span class="dp-key">Guardian / Contact</span><span class="dp-val" id="dp-guardian"></span></div>
</div>
<div><div class="dp-sect">Programme Details</div>
<div class="dp-row"><span class="dp-key">Category</span><span class="dp-val" id="dp-cat"></span></div>
<div class="dp-row"><span class="dp-key">Programme</span><span class="dp-val" id="dp-pgm"></span></div>
<div class="dp-row"><span class="dp-key">Monthly Stipend</span><span class="dp-val" id="dp-stipend"></span></div>
<div class="dp-row"><span class="dp-key">Enrolled</span><span class="dp-val" id="dp-enrolled"></span></div>
<div class="dp-row"><span class="dp-key">Status</span><span class="dp-val" id="dp-status"></span></div>
<div class="dp-row"><span class="dp-key">Case Worker</span><span class="dp-val" id="dp-worker"></span></div>
</div>
<div><div class="dp-sect">Payment History</div>
<div class="pmt-list" id="dp-payments"></div>
</div>
<div><div class="dp-sect">Notes</div>
<textarea style="width:100%;border:1px solid var(--border);border-radius:var(--radius-sm);padding:8px 10px;font-size:12px;font-family:inherit;resize:none;height:70px;outline:none;" id="dp-notes" placeholder="Add case notesโฆ" onfocus="this.style.borderColor='var(--green)'" onblur="this.style.borderColor='var(--border)'"></textarea>
</div>
</div>
<div class="dp-footer">
<button class="btn btn-ghost" style="flex:1;justify-content:center;color:var(--red);" onclick="suspendBeneficiary()">โ Suspend</button>
<button class="btn btn-ghost" style="flex:1;justify-content:center;" onclick="closeDp()">Close</button>
<button class="btn btn-primary" style="flex:1;justify-content:center;">โ๏ธ Edit</button>
</div>
</div>
</div>
<script>
const CATS = {
Elderly:{color:'#ea580c',bg:'#fff7ed',icon:'๐ด',label:'Elderly'},
PWD:{color:'#2563eb',bg:'#eff6ff',icon:'โฟ',label:'PWD'},
OVC:{color:'#1a7a4a',bg:'#e8f5ee',icon:'๐ถ',label:'OVC'},
};
const BENEFICIARIES = [
{id:'SP-001',name:'David Otieno Omondi',gender:'Male',age:68,ward:'Umoja Ward',village:'Umoja I',phone:'0745 678 901',guardian:'Mary Otieno (Daughter)',category:'Elderly',programme:'Cash Transfer',amount:2000,enrolled:'Jan 2024',status:'Active',worker:'Jane Wambua',payments:[{month:'Jan 2024',amt:2000,done:true},{month:'Feb 2024',amt:2000,done:true},{month:'Mar 2024',amt:2000,done:true},{month:'Apr 2024',amt:2000,done:true},{month:'May 2024',amt:2000,done:false}],notes:''},
{id:'SP-002',name:'Rose Kamau Wanjiru',gender:'Female',age:45,ward:'Mabatini Ward',village:'Mabatini',phone:'0790 123 456',guardian:'Self',category:'PWD',programme:'Medical Cover',amount:3500,enrolled:'Nov 2023',status:'Active',worker:'Peter Njoroge',payments:[{month:'Nov 2023',amt:3500,done:true},{month:'Dec 2023',amt:3500,done:true},{month:'Jan 2024',amt:3500,done:true},{month:'Feb 2024',amt:3500,done:true},{month:'Mar 2024',amt:3500,done:true},{month:'Apr 2024',amt:3500,done:true},{month:'May 2024',amt:3500,done:false}],notes:''},
{id:'SP-003',name:'John Kariuki Njeru',gender:'Male',age:71,ward:'Mabatini Ward',village:'Mabatini South',phone:'',guardian:'Ann Kariuki (Wife)',category:'Elderly',programme:'Cash Transfer',amount:2000,enrolled:'Oct 2023',status:'Active',worker:'Jane Wambua',payments:[{month:'Oct 2023',amt:2000,done:true},{month:'Nov 2023',amt:2000,done:true},{month:'Dec 2023',amt:2000,done:true},{month:'Jan 2024',amt:2000,done:true},{month:'May 2024',amt:2000,done:false}],notes:'Mobility challenges โ home visits required.'},
{id:'SP-004',name:'Hannah Ongeri Odhiambo',gender:'Female',age:54,ward:'Umoja Ward',village:'Umoja I',phone:'0734 890 123',guardian:'Michael Oduya (Son)',category:'OVC',programme:'Food Basket',amount:1500,enrolled:'Dec 2023',status:'Active',worker:'Grace Muthoni',payments:[{month:'Dec 2023',amt:1500,done:true},{month:'Jan 2024',amt:1500,done:true},{month:'Feb 2024',amt:1500,done:true},{month:'Mar 2024',amt:1500,done:true},{month:'May 2024',amt:1500,done:false}],notes:'Raising 3 grandchildren after son\'s death.'},
{id:'SP-005',name:'Elijah Rono Kipchoge',gender:'Male',age:74,ward:'Pipeline Ward',village:'Pipeline South',phone:'',guardian:'Daniel Rono (Son)',category:'Elderly',programme:'Cash Transfer',amount:2000,enrolled:'Sep 2023',status:'Active',worker:'Jane Wambua',payments:[{month:'Sep 2023',amt:2000,done:true},{month:'Oct 2023',amt:2000,done:true},{month:'Nov 2023',amt:2000,done:true},{month:'Dec 2023',amt:2000,done:true},{month:'Jan 2024',amt:2000,done:true},{month:'May 2024',amt:2000,done:false}],notes:''},
{id:'SP-006',name:'Grace Muthoni Njoroge',gender:'Female',age:34,ward:'Kwa Njenga Ward',village:'Kware',phone:'0756 789 012',guardian:'Self',category:'PWD',programme:'Cash Transfer',amount:2500,enrolled:'Feb 2024',status:'Under Review',worker:'Peter Njoroge',payments:[{month:'Feb 2024',amt:2500,done:true},{month:'Mar 2024',amt:2500,done:true}],notes:'Documents under verification โ ID renewal pending.'},
{id:'SP-007',name:'Beatrice Muthoni Waweru',gender:'Female',age:62,ward:'Kwa Njenga Ward',village:'Kware South',phone:'0789 234 567',guardian:'Kevin Waweru (Son)',category:'Elderly',programme:'Food Basket',amount:1500,enrolled:'Aug 2023',status:'Active',worker:'Grace Muthoni',payments:[{month:'Aug 2023',amt:1500,done:true},{month:'Sep 2023',amt:1500,done:true},{month:'Oct 2023',amt:1500,done:true},{month:'Nov 2023',amt:1500,done:true},{month:'Dec 2023',amt:1500,done:true},{month:'Jan 2024',amt:1500,done:true},{month:'May 2024',amt:1500,done:false}],notes:''},
{id:'SP-008',name:'James Mburu Njoroge',gender:'Male',age:28,ward:'Umoja Ward',village:'Umoja II Zone 4',phone:'0723 678 901',guardian:'Self',category:'PWD',programme:'Medical Cover',amount:3500,enrolled:'Mar 2024',status:'Active',worker:'Peter Njoroge',payments:[{month:'Mar 2024',amt:3500,done:true},{month:'Apr 2024',amt:3500,done:true},{month:'May 2024',amt:3500,done:false}],notes:'Hearing impairment. Enrolled after transformer injury.'},
{id:'SP-009',name:'Fatuma Hassan Omar',gender:'Female',age:38,ward:'Kwa Njenga Ward',village:'Kwa Njenga Market',phone:'0712 567 890',guardian:'Self',category:'OVC',programme:'Food Basket',amount:1500,enrolled:'Jan 2024',status:'Active',worker:'Grace Muthoni',payments:[{month:'Jan 2024',amt:1500,done:true},{month:'Feb 2024',amt:1500,done:true},{month:'Mar 2024',amt:1500,done:true},{month:'Apr 2024',amt:1500,done:true},{month:'May 2024',amt:1500,done:false}],notes:'Single mother of 4, husband deceased 2023.'},
{id:'SP-010',name:'Lucy Wambua Mutua',gender:'Female',age:32,ward:'Imara Daima',village:'Imara Daima',phone:'0745 890 123',guardian:'Paul Wambua (Brother)',category:'PWD',programme:'Cash Transfer',amount:2500,enrolled:'Oct 2023',status:'Suspended',worker:'Peter Njoroge',payments:[{month:'Oct 2023',amt:2500,done:true},{month:'Nov 2023',amt:2500,done:true},{month:'Dec 2023',amt:2500,done:false}],notes:'Suspended pending re-assessment. Disability certificate expired.'},
{id:'SP-011',name:'Susan Wanjiku Njeru',gender:'Female',age:44,ward:'Imara Daima',village:'Kwa Reuben',phone:'0756 012 345',guardian:'Self',category:'OVC',programme:'Food Basket',amount:1500,enrolled:'Feb 2024',status:'Active',worker:'Grace Muthoni',payments:[{month:'Feb 2024',amt:1500,done:true},{month:'Mar 2024',amt:1500,done:true},{month:'Apr 2024',amt:1500,done:true},{month:'May 2024',amt:1500,done:false}],notes:'Orphaned children โ 2 in primary school.'},
{id:'SP-012',name:'Peter Ochieng Otieno',gender:'Male',age:65,ward:'Imara Daima',village:'Kwa Reuben',phone:'0723 456 789',guardian:'Rose Otieno (Wife)',category:'Elderly',programme:'Cash Transfer',amount:2000,enrolled:'Jul 2023',status:'Active',worker:'Jane Wambua',payments:[{month:'Jul 2023',amt:2000,done:true},{month:'Aug 2023',amt:2000,done:true},{month:'Sep 2023',amt:2000,done:true},{month:'Oct 2023',amt:2000,done:true},{month:'Nov 2023',amt:2000,done:true},{month:'Dec 2023',amt:2000,done:true},{month:'Jan 2024',amt:2000,done:true},{month:'May 2024',amt:2000,done:false}],notes:''},
{id:'SP-013',name:'Nancy Wangari Kamau',gender:'Female',age:44,ward:'Pipeline Ward',village:'Pipeline Rd',phone:'0734 789 012',guardian:'Self',category:'OVC',programme:'Cash Transfer',amount:2000,enrolled:'Nov 2023',status:'Active',worker:'Grace Muthoni',payments:[{month:'Nov 2023',amt:2000,done:true},{month:'Dec 2023',amt:2000,done:true},{month:'Jan 2024',amt:2000,done:true},{month:'Feb 2024',amt:2000,done:true},{month:'May 2024',amt:2000,done:false}],notes:'Widow with 3 school-going children.'},
{id:'SP-014',name:'Samuel Muthoni Kariuki',gender:'Male',age:52,ward:'Umoja Ward',village:'Umoja II',phone:'0756 789 012',guardian:'Ann Kariuki (Wife)',category:'PWD',programme:'Medical Cover',amount:3500,enrolled:'Dec 2023',status:'Active',worker:'Peter Njoroge',payments:[{month:'Dec 2023',amt:3500,done:true},{month:'Jan 2024',amt:3500,done:true},{month:'Feb 2024',amt:3500,done:true},{month:'Mar 2024',amt:3500,done:true},{month:'May 2024',amt:3500,done:false}],notes:'Bilateral leg amputation โ requiring prosthetics.'},
{id:'SP-015',name:'Amina Wario Hassan',gender:'Female',age:67,ward:'Imara Daima',village:'Imara Daima West',phone:'0712 456 789',guardian:'Fatuma Wario (Daughter)',category:'Elderly',programme:'Food Basket',amount:1500,enrolled:'May 2023',status:'Active',worker:'Jane Wambua',payments:[{month:'May 2023',amt:1500,done:true},{month:'Jun 2023',amt:1500,done:true},{month:'Jul 2023',amt:1500,done:true},{month:'Aug 2023',amt:1500,done:true},{month:'Sep 2023',amt:1500,done:true},{month:'Oct 2023',amt:1500,done:true},{month:'Nov 2023',amt:1500,done:true},{month:'Dec 2023',amt:1500,done:true},{month:'Jan 2024',amt:1500,done:true},{month:'May 2024',amt:1500,done:false}],notes:''},
{id:'SP-016',name:'Ann Chebet Kosgei',gender:'Female',age:36,ward:'Mabatini Ward',village:'Mabatini',phone:'0767 012 345',guardian:'David Kosgei (Husband)',category:'OVC',programme:'Food Basket',amount:1500,enrolled:'Mar 2024',status:'Under Review',worker:'Grace Muthoni',payments:[{month:'Mar 2024',amt:1500,done:true},{month:'Apr 2024',amt:1500,done:true}],notes:''},
{id:'SP-017',name:'Vincent Mwenda Kirimi',gender:'Male',age:26,ward:'Pipeline Ward',village:'Pipeline North',phone:'0790 345 678',guardian:'Mary Kirimi (Mother)',category:'PWD',programme:'Cash Transfer',amount:2500,enrolled:'Jan 2024',status:'Active',worker:'Peter Njoroge',payments:[{month:'Jan 2024',amt:2500,done:true},{month:'Feb 2024',amt:2500,done:true},{month:'Mar 2024',amt:2500,done:true},{month:'Apr 2024',amt:2500,done:true},{month:'May 2024',amt:2500,done:false}],notes:'Visual impairment โ enrolled after community health worker referral.'},
{id:'SP-018',name:'Michael Oduya Ongeri',gender:'Male',age:56,ward:'Mihango Ward',village:'Mihango',phone:'0778 123 456',guardian:'Hannah Ongeri (Wife)',category:'Elderly',programme:'Cash Transfer',amount:2000,enrolled:'Jun 2023',status:'Active',worker:'Jane Wambua',payments:[{month:'Jun 2023',amt:2000,done:true},{month:'Jul 2023',amt:2000,done:true},{month:'Aug 2023',amt:2000,done:true},{month:'Dec 2023',amt:2000,done:true},{month:'Jan 2024',amt:2000,done:true},{month:'May 2024',amt:2000,done:false}],notes:''},
{id:'SP-019',name:'Esther Wanjiru Gitau',gender:'Female',age:60,ward:'Mihango Ward',village:'Mihango Estate',phone:'0767 012 345',guardian:'Peter Gitau (Son)',category:'Elderly',programme:'Food Basket',amount:1500,enrolled:'Feb 2024',status:'Active',worker:'Jane Wambua',payments:[{month:'Feb 2024',amt:1500,done:true},{month:'Mar 2024',amt:1500,done:true},{month:'Apr 2024',amt:1500,done:true},{month:'May 2024',amt:1500,done:false}],notes:''},
{id:'SP-020',name:'Daniel Kipchoge Rono',gender:'Male',age:22,ward:'Kwa Njenga Ward',village:'Kwa Njenga',phone:'0723 789 012',guardian:'Elijah Rono (Father)',category:'OVC',programme:'Cash Transfer',amount:2000,enrolled:'Sep 2023',status:'Active',worker:'Grace Muthoni',payments:[{month:'Sep 2023',amt:2000,done:true},{month:'Oct 2023',amt:2000,done:true},{month:'Nov 2023',amt:2000,done:true},{month:'Dec 2023',amt:2000,done:true},{month:'Jan 2024',amt:2000,done:true},{month:'May 2024',amt:2000,done:false}],notes:'Father lost income โ family of 6.'},
];
let filtered=[...BENEFICIARIES];
let activeCategory='all';
let sortKey='name';
let sortDir=1;
let currentPage=1;
const PAGE_SIZE=10;
let current=null;
const avatarColors={'Elderly':'#ea580c','PWD':'#2563eb','OVC':'#1a7a4a'};
function initials(n){return n.split(' ').slice(0,2).map(x=>x[0]).join('').toUpperCase();}
function statusTag(s){
const cls=s==='Active'?'active':s==='Under Review'?'review':'suspended';
const icon=s==='Active'?'โ':s==='Under Review'?'โณ':'โ';
return `<span class="stag ${cls}">${icon} ${s}</span>`;
}
function catTag(c){
const d=CATS[c];
return `<span class="ctag ${c.toLowerCase()}">${d.icon} ${d.label}</span>`;
}
function updateCounts(){
const all=BENEFICIARIES;
document.getElementById('cnt-all').textContent=all.length;
const e=all.filter(b=>b.category==='Elderly').length;
const p=all.filter(b=>b.category==='PWD').length;
const o=all.filter(b=>b.category==='OVC').length;
document.getElementById('cnt-elderly').textContent=e;
document.getElementById('cnt-pwd').textContent=p;
document.getElementById('cnt-ovc').textContent=o;
document.getElementById('bar-elderly').style.width=(e/all.length*100)+'%';
document.getElementById('bar-pwd').style.width=(p/all.length*100)+'%';
document.getElementById('bar-ovc').style.width=(o/all.length*100)+'%';
}
function filterCat(cat,el){
activeCategory=cat;
document.querySelectorAll('.mc').forEach(m=>m.classList.remove('active'));
el.classList.add('active');
applyFilters();
}
function applyFilters(){
const q=document.getElementById('searchInput').value.toLowerCase();
const ward=document.getElementById('wardFilter').value;
const status=document.getElementById('statusFilter').value;
const pgm=document.getElementById('pgmFilter').value;
filtered=BENEFICIARIES.filter(b=>{
if(activeCategory!=='all'&&b.category!==activeCategory)return false;
if(ward&&b.ward!==ward)return false;
if(status&&b.status!==status)return false;
if(pgm&&b.programme!==pgm)return false;
if(q&&!`${b.id} ${b.name} ${b.ward} ${b.village} ${b.worker}`.toLowerCase().includes(q))return false;
return true;
});
filtered.sort((a,b)=>{let av=a[sortKey],bv=b[sortKey];return av>bv?sortDir:av<bv?-sortDir:0;});
currentPage=1;render();
}
function sortBy(key){
if(sortKey===key)sortDir*=-1;else{sortKey=key;sortDir=1;}
applyFilters();
}
function render(){
const start=(currentPage-1)*PAGE_SIZE,end=start+PAGE_SIZE;
const page=filtered.slice(start,end);
document.getElementById('tableBody').innerHTML=page.map(b=>`
<tr onclick="openDp('${b.id}')">
<td style="font-size:11px;color:var(--muted);font-weight:600">${b.id}</td>
<td>
<div style="display:flex;align-items:center;gap:8px">
<div style="width:30px;height:30px;border-radius:50%;background:${avatarColors[b.category]};color:white;font-size:11px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0">${initials(b.name)}</div>
<div><div style="font-weight:600">${b.name}</div><div style="font-size:10.5px;color:var(--muted)">${b.village} ยท Age ${b.age}</div></div>
</div>
</td>
<td style="font-size:11.5px">${b.ward}</td>
<td>${catTag(b.category)}</td>
<td style="font-size:11.5px">${b.programme}</td>
<td style="font-weight:600">${b.amount.toLocaleString()}/mo</td>
<td style="font-size:11px;color:var(--muted)">Jun 2024</td>
<td>${statusTag(b.status)}</td>
<td><div class="act-btns">
<span class="ab" onclick="event.stopPropagation();openDp('${b.id}')">View</span>
${b.status!=='Active'?`<span class="ab" style="color:var(--green)" onclick="event.stopPropagation();activateBeneficiary('${b.id}')">Activate</span>`:''}
</div></td>
</tr>
`).join('');
const total=filtered.length,pages=Math.ceil(total/PAGE_SIZE);
document.getElementById('pgInfo').textContent=`Showing ${Math.min(start+1,total)}โ${Math.min(end,total)} of ${total}`;
const pb=document.getElementById('pgBtns');pb.innerHTML='';
const add=(l,p,a)=>{const d=document.createElement('div');d.className='pg-btn'+(a?' active':'');d.textContent=l;d.onclick=()=>{currentPage=p;render();};pb.appendChild(d);};
if(currentPage>1)add('โน',currentPage-1,false);
for(let i=1;i<=Math.min(pages,7);i++)add(i,i,i===currentPage);
if(currentPage<pages)add('โบ',currentPage+1,false);
}
function renderWardBreakdown(){
const wards=['Pipeline Ward','Imara Daima','Mabatini Ward','Umoja Ward','Kwa Njenga Ward','Mihango Ward'];
const max=Math.max(...wards.map(w=>BENEFICIARIES.filter(b=>b.ward===w).length));
document.getElementById('wardBreakdown').innerHTML=wards.map(w=>{
const cnt=BENEFICIARIES.filter(b=>b.ward===w).length;
const pct=Math.round(cnt/max*100);
return `<div class="ward-row">
<div class="ward-name">${w.replace(' Ward','')}</div>
<div class="ward-bar-wrap"><div class="ward-bar-fill" style="width:${pct}%;background:var(--green)"></div></div>
<div class="ward-count">${cnt}</div>
</div>`;
}).join('');
}
function renderPaySchedule(){
const schedule=[
{month:'JanโFeb 2024',amt:'3,066,000',done:true},
{month:'MarโApr 2024',amt:'3,066,000',done:true},
{month:'MayโJun 2024',amt:'3,066,000',done:false},
{month:'JulโAug 2024',amt:'3,066,000',done:false},
{month:'SepโOct 2024',amt:'3,066,000',done:false},
{month:'NovโDec 2024',amt:'3,070,000',done:false},
];
document.getElementById('paySchedule').innerHTML=schedule.map(s=>`
<div class="pay-item">
<div class="pay-dot" style="background:${s.done?'var(--green)':'var(--border)'}"></div>
<div class="pay-month">${s.month}</div>
<div class="pay-amt">KSh ${s.amt}</div>
<span class="pay-status ${s.done?'done':'pending'}">${s.done?'Paid':'Due'}</span>
</div>
`).join('');
}
function openDp(id){
current=BENEFICIARIES.find(b=>b.id===id);
const b=current;
const color=avatarColors[b.category];
document.getElementById('dp-av').textContent=initials(b.name);
document.getElementById('dp-av').style.background=color;
document.getElementById('dp-name').textContent=b.name;
document.getElementById('dp-tags').innerHTML=catTag(b.category)+' '+statusTag(b.status);
document.getElementById('dp-id').textContent=b.id;
document.getElementById('dp-gender').textContent=b.gender;
document.getElementById('dp-age').textContent=b.age+' years';
document.getElementById('dp-ward').textContent=b.ward;
document.getElementById('dp-village').textContent=b.village;
document.getElementById('dp-phone').textContent=b.phone||'โ';
document.getElementById('dp-guardian').textContent=b.guardian;
document.getElementById('dp-cat').textContent=b.category;
document.getElementById('dp-pgm').textContent=b.programme;
document.getElementById('dp-stipend').textContent='KSh '+b.amount.toLocaleString()+'/month';
document.getElementById('dp-enrolled').textContent=b.enrolled;
document.getElementById('dp-status').innerHTML=statusTag(b.status);
document.getElementById('dp-worker').textContent=b.worker;
document.getElementById('dp-payments').innerHTML=b.payments.slice(-5).reverse().map(p=>`
<div class="pmt-item">
<span>${p.month}</span>
<span style="font-weight:600;color:${p.done?'var(--green)':'var(--muted)'}">${p.done?'KSh '+p.amt.toLocaleString()+' โ':'Pending'}</span>
</div>
`).join('');
document.getElementById('dp-notes').value=b.notes||'';
document.getElementById('ov').classList.add('open');
}
function closeOv(e){if(e.target===document.getElementById('ov'))closeDp();}
function closeDp(){document.getElementById('ov').classList.remove('open');}
function suspendBeneficiary(){if(current&¤t.status==='Active'){current.status='Suspended';updateCounts();applyFilters();closeDp();}}
function activateBeneficiary(id){const b=BENEFICIARIES.find(x=>x.id===id);if(b){b.status='Active';updateCounts();applyFilters();}}
updateCounts();renderWardBreakdown();renderPaySchedule();applyFilters();
</script>
</body>
</html>