Welcome to WordPress. This is your first post. Edit or delete it, then start writing!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bappi Ads Analytics</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<style>
* { font-family: 'Inter', sans-serif; }
::-webkit-scrollbar { width: 4px; height: 4px; }
::-webkit-scrollbar-track { background: #0a0e17; }
::-webkit-scrollbar-thumb { background: #1e293b; border-radius: 2px; }
.fade-in { animation: fadeIn 0.4s ease-out; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes pulse-dot { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
.pulse-dot { animation: pulse-dot 2s infinite; }
.glass { background: rgba(30, 41, 59, 0.6); backdrop-filter: blur(12px); border: 1px solid rgba(51, 65, 85, 0.5); }
.glass-hover:hover { background: rgba(51, 65, 85, 0.6); border-color: rgba(71, 85, 105, 0.7); }
.sidebar-link { transition: all 0.2s; border-radius: 8px; }
.sidebar-link:hover { background: rgba(59, 130, 246, 0.1); color: #60a5fa; }
.sidebar-link.active { background: rgba(59, 130, 246, 0.15); color: #60a5fa; border-left: 3px solid #3b82f6; }
.metric-card { transition: all 0.2s; }
.metric-card:hover { transform: translateY(-2px); box-shadow: 0 8px 25px rgba(0,0,0,0.3); }
.nav-item { transition: all 0.2s; }
.nav-item:hover { background: rgba(255,255,255,0.05); }
.tab-btn { transition: all 0.2s; }
.tab-btn.active { background: #3b82f6; color: white; }
input[type="text"], input[type="email"], input[type="password"], input[type="number"], select {
background: rgba(15, 23, 42, 0.8);
border: 1px solid rgba(51, 65, 85, 0.5);
color: #e2e8f0;
}
input:focus, select:focus { border-color: #3b82f6; outline: none; box-shadow: 0 0 0 2px rgba(59,130,246,0.2); }
.modal-overlay { backdrop-filter: blur(8px); }
.status-dot { width: 6px; height: 6px; border-radius: 50%; display: inline-block; }
.status-active { background: #22c55e; box-shadow: 0 0 6px rgba(34,197,94,0.5); }
.status-paused { background: #f59e0b; box-shadow: 0 0 6px rgba(245,158,11,0.5); }
.campaign-card { transition: all 0.2s; }
.campaign-card:hover { background: rgba(59, 130, 246, 0.05); }
.campaign-card.selected { border-color: #3b82f6; background: rgba(59, 130, 246, 0.08); }
.campaign-card .checkbox { transition: all 0.2s; }
.campaign-card.selected .checkbox { background: #3b82f6; border-color: #3b82f6; }
.campaign-card.selected .checkbox::after { content: '✓'; color: white; font-size: 10px; }
.client-stat-card { background: #1e293b; border: 1px solid rgba(51, 65, 85, 0.8); border-radius: 12px; padding: 20px; transition: all 0.2s; }
.client-stat-card:hover { background: #253347; }
.client-table-row { transition: background 0.15s; }
.client-table-row:hover { background: rgba(51, 65, 85, 0.3); }
.filter-btn { background: linear-gradient(135deg, #3b82f6, #6366f1); transition: all 0.2s; }
.filter-btn:hover { opacity: 0.9; transform: translateY(-1px); }
.preview-btn { background: rgba(99, 102, 241, 0.2); color: #818cf8; padding: 2px 8px; border-radius: 4px; font-size: 10px; cursor: pointer; }
.preview-btn:hover { background: rgba(99, 102, 241, 0.3); }
.loading-spinner {
width: 20px;
height: 20px;
border: 2px solid #1e293b;
border-top-color: #3b82f6;
border-radius: 50%;
animation: spin 0.8s linear infinite;
display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }
</style>
</head>
<body class="bg-[#0a0e17] text-slate-200 min-h-screen">
<!-- Auth Screen -->
<div id="authScreen" class="fixed inset-0 z-50 bg-[#0a0e17] flex items-center justify-center p-4">
<div class="w-full max-w-md fade-in">
<div class="text-center mb-8">
<div class="w-16 h-16 bg-gradient-to-br from-blue-500 to-blue-700 rounded-2xl flex items-center justify-center mx-auto mb-4 shadow-lg shadow-blue-500/20">
<span class="text-3xl text-white font-bold">AB</span>
</div>
<h1 class="text-2xl font-bold text-white">Bappi Ads Analytics</h1>
<p class="text-slate-400 mt-2">Sign in to manage your ad campaigns</p>
</div>
<div class="glass rounded-2xl p-6 space-y-4">
<div id="loginForm" class="space-y-4">
<div>
<label class="block text-sm font-medium text-slate-400 mb-1.5">Email</label>
<input type="email" id="loginEmail" class="w-full px-4 py-2.5 rounded-xl text-sm outline-none" placeholder="arbappi82@gmail.com">
</div>
<div>
<label class="block text-sm font-medium text-slate-400 mb-1.5">Password</label>
<input type="password" id="loginPassword" class="w-full px-4 py-2.5 rounded-xl text-sm outline-none" placeholder="admin123">
</div>
<div id="loginError" class="hidden p-3 bg-red-500/10 border border-red-500/20 text-red-400 rounded-xl text-sm flex items-center gap-2">
<span class="text-red-400"></span> Invalid email or password.
</div>
<button onclick="handleLogin()" class="w-full bg-blue-600 hover:bg-blue-500 text-white font-medium py-2.5 rounded-xl transition shadow-lg shadow-blue-600/20">Sign In as Agency</button>
<div class="relative flex items-center justify-center my-2">
<div class="border-t border-slate-700 w-full"></div>
<span class="px-3 text-xs text-slate-500 absolute">or</span>
</div>
<button onclick="showClientLogin()" class="w-full bg-slate-800 hover:bg-slate-700 text-slate-300 font-medium py-2.5 rounded-xl border border-slate-700 transition flex items-center justify-center gap-2">
<span class="text-slate-400"></span> View as Client
</button>
</div>
<div id="clientLoginForm" class="hidden space-y-4">
<div>
<label class="block text-sm font-medium text-slate-400 mb-1.5">Client ID</label>
<input type="text" id="clientIdInput" class="w-full px-4 py-2.5 rounded-xl text-sm outline-none" placeholder="e.g. CLI-8821">
</div>
<button onclick="handleClientLogin()" class="w-full bg-blue-600 hover:bg-blue-500 text-white font-medium py-2.5 rounded-xl transition shadow-lg shadow-blue-600/20">Access Client Dashboard</button>
<button onclick="showAgencyLogin()" class="w-full text-sm text-slate-500 hover:text-slate-300 py-2">← Back to Agency Login</button>
</div>
</div>
<p class="text-center text-xs text-slate-600 mt-6"> Authorized access only. Contact arbappi82@gmail.com for support.</p>
</div>
</div>
<!-- Client Portal - Public Login Page -->
<div id="clientPortalLogin" class="hidden min-h-screen bg-[#0a0e17] flex items-center justify-center p-4">
<div class="w-full max-w-lg fade-in">
<div class="text-center mb-8">
<h1 class="text-3xl font-bold text-white mb-2">Campaign Analytics</h1>
<p class="text-slate-400 text-sm">Enter your credentials to view campaign performance</p>
</div>
<div class="bg-[#1e293b] rounded-2xl p-8 border border-slate-700">
<div class="mb-6">
<label class="block text-sm font-medium text-slate-300 mb-2">Client ID</label>
<input type="text" id="portalClientIdInput" class="w-full px-4 py-3 rounded-xl text-sm outline-none bg-[#2d3748] border border-slate-600 text-white placeholder-slate-500 text-center tracking-wider" placeholder="E.G. ABC12345">
<p id="clientPortalError" class="hidden text-red-400 text-sm mt-2 flex items-center gap-1.5">
<span>⚠</span> Client not found.
</p>
</div>
<button onclick="handlePortalLogin()" class="w-full bg-blue-600 hover:bg-blue-500 text-white font-semibold py-3 rounded-xl transition shadow-lg shadow-blue-600/30 text-base">
View Campaigns
</button>
<div class="mt-6 pt-6 border-t border-slate-700">
<div class="bg-slate-800/50 rounded-xl p-4 border border-slate-700">
<div class="flex items-start gap-3">
<span class="text-slate-500 mt-0.5">️</span>
<p class="text-xs text-slate-400 leading-relaxed">Your Client ID and Campaign IDs were provided by your agency. Contact them if you don't have these credentials.</p>
</div>
</div>
</div>
</div>
<div class="text-center mt-6">
<button onclick="logout()" class="text-sm text-slate-500 hover:text-slate-300 transition">Return to Home</button>
</div>
</div>
</div>
<!-- Client Portal - Campaign Analysis Dashboard -->
<div id="clientPortalDashboard" class="hidden min-h-screen bg-[#0a0e17]">
<header class="sticky top-0 z-30 bg-[#0a0e17]/80 backdrop-blur-xl border-b border-slate-800 px-4 md:px-6 py-3">
<div class="flex items-center justify-between max-w-6xl mx-auto">
<div class="flex items-center gap-3">
<button onclick="clientLogout()" class="w-8 h-8 rounded-lg bg-slate-800 border border-slate-700 flex items-center justify-center text-slate-400 hover:text-white hover:bg-slate-700 transition">
<span class="text-sm">←</span>
</button>
<div class="w-10 h-10 bg-blue-600 rounded-xl flex items-center justify-center text-white font-bold text-sm">AB</div>
</div>
<div class="flex items-center gap-2">
<div class="flex items-center bg-slate-800 rounded-xl px-3 py-1.5 border border-slate-700">
<div class="w-6 h-6 rounded-full bg-blue-600 flex items-center justify-center text-white text-[10px] font-bold">C</div>
<span class="text-xs text-slate-300 ml-2 hidden md:inline">Client View</span>
</div>
<button onclick="clientLogout()" class="text-xs text-slate-400 hover:text-white transition">Logout</button>
</div>
</div>
</header>
<div class="p-4 md:p-6 max-w-6xl mx-auto space-y-6">
<div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
<div>
<h1 class="text-xl font-bold text-white" id="clientDashboardName">Client Name</h1>
<p class="text-xs text-slate-500 mt-1" id="clientDashboardDate">Date range</p>
</div>
<div class="flex items-center gap-2 bg-[#1e293b] rounded-xl p-1.5 border border-slate-700">
<div class="flex items-center">
<span class="text-[10px] text-slate-500 uppercase mr-2 px-2">Range</span>
<select id="clientDateRange" class="bg-slate-800 border border-slate-700 rounded-lg px-3 py-1.5 text-xs outline-none text-slate-300">
<option value="all">All Time</option>
<option value="today">Today</option>
<option value="7d">Last 7 Days</option>
<option value="30d">Last 30 Days</option>
</select>
</div>
<button onclick="filterClientData()" class="filter-btn text-white px-4 py-1.5 rounded-lg text-xs font-medium">Filter</button>
</div>
</div>
<div id="dataSuccessMsg" class="hidden bg-emerald-500/10 border border-emerald-500/20 rounded-xl p-4 fade-in">
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-full bg-emerald-500/20 flex items-center justify-center">
<span class="text-emerald-400 text-sm">✓</span>
</div>
<div>
<p class="text-sm font-medium text-emerald-400">Data loaded successfully</p>
<p class="text-xs text-emerald-400/60" id="dataLoadedInfo">1 ads with live performance data</p>
</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="client-stat-card">
<div class="flex items-center justify-between mb-4">
<span class="text-[10px] text-slate-500 uppercase tracking-wider">Total Deposit (USD)</span>
<span class="w-4 h-4 rounded-full bg-blue-500/20 flex items-center justify-center">
<span class="text-blue-400 text-[8px]">💰</span>
</span>
</div>
<p class="text-2xl font-bold text-white" id="cTotalDeposit">$0</p>
<p class="text-xs text-slate-500 mt-1" id="cTotalDepositBDT"></p>
</div>
<div class="client-stat-card">
<div class="flex items-center justify-between mb-4">
<span class="text-[10px] text-slate-500 uppercase tracking-wider">Total Spend</span>
<span class="w-4 h-4 rounded-full bg-purple-500/20 flex items-center justify-center">
<span class="text-purple-400 text-[8px]">💸</span>
</span>
</div>
<p class="text-2xl font-bold text-white" id="cTotalSpend">$0</p>
<p class="text-xs text-slate-500 mt-1" id="cTotalSpendBDT"></p>
</div>
<div class="client-stat-card">
<div class="flex items-center justify-between mb-4">
<span class="text-[10px] text-slate-500 uppercase tracking-wider">Remaining Balance</span>
<span class="w-4 h-4 rounded-full bg-emerald-500/20 flex items-center justify-center">
<span class="text-emerald-400 text-[8px]">✓</span>
</span>
</div>
<p class="text-2xl font-bold text-white" id="cRemaining">$0</p>
<p class="text-xs text-slate-500 mt-1" id="cRemainingBDT"></p>
<p class="text-[10px] text-emerald-400 mt-1 font-medium">REMAINING</p>
</div>
</div>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="client-stat-card">
<div class="flex items-center justify-between mb-2">
<span class="text-[10px] text-slate-500 uppercase">Impressions</span>
<span class="w-4 h-4 rounded-full bg-orange-500/20 flex items-center justify-center">
<span class="text-orange-400 text-[8px]">👁</span>
</span>
</div>
<p class="text-xl font-bold text-white" id="cImpressions">0</p>
</div>
<div class="client-stat-card">
<div class="flex items-center justify-between mb-2">
<span class="text-[10px] text-slate-500 uppercase">Reach</span>
<span class="w-4 h-4 rounded-full bg-emerald-500/20 flex items-center justify-center">
<span class="text-emerald-400 text-[8px]">👥</span>
</span>
</div>
<p class="text-xl font-bold text-white" id="cReach">0</p>
</div>
<div class="client-stat-card">
<div class="flex items-center justify-between mb-2">
<span class="text-[10px] text-slate-500 uppercase">Results</span>
<span class="w-4 h-4 rounded-full bg-red-500/20 flex items-center justify-center">
<span class="text-red-400 text-[8px]">🎯</span>
</span>
</div>
<p class="text-xl font-bold text-white" id="cResults">0</p>
</div>
<div class="client-stat-card">
<div class="flex items-center justify-between mb-2">
<span class="text-[10px] text-slate-500 uppercase">Cost / Result</span>
<span class="w-4 h-4 rounded-full bg-blue-500/20 flex items-center justify-center">
<span class="text-blue-400 text-[8px]">📈</span>
</span>
</div>
<p class="text-xl font-bold text-white" id="cCPR">$0</p>
</div>
</div>
<div class="bg-[#1e293b] rounded-xl border border-slate-700 overflow-hidden">
<div class="p-4 border-b border-slate-700 flex justify-between items-center">
<div>
<h3 class="font-semibold text-white text-sm">Ad Performance</h3>
<p class="text-[10px] text-slate-500 mt-0.5" id="adsAssignedInfo">0 ads assigned to your account</p>
</div>
<button class="text-slate-500 hover:text-white transition text-sm"></button>
</div>
<div class="overflow-x-auto">
<table class="w-full text-xs text-left">
<thead class="text-slate-500 uppercase text-[10px] border-b border-slate-700 bg-[#162032]">
<tr>
<th class="px-4 py-3 font-medium">Ad Name</th>
<th class="px-4 py-3 font-medium">Status</th>
<th class="px-4 py-3 font-medium">Daily Budget</th>
<th class="px-4 py-3 font-medium">End Date</th>
<th class="px-4 py-3 font-medium">Spend</th>
<th class="px-4 py-3 font-medium">Impressions</th>
<th class="px-4 py-3 font-medium">Reach</th>
<th class="px-4 py-3 font-medium">CTR</th>
<th class="px-4 py-3 font-medium">Result Rate</th>
<th class="px-4 py-3 font-medium">Results</th>
<th class="px-4 py-3 font-medium">Cost / Result</th>
</tr>
</thead>
<tbody id="clientAdsTable" class="divide-y divide-slate-800 text-slate-300">
<tr><td class="px-4 py-8 text-center text-slate-600" colspan="11">No ad data available.</td></tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Admin App -->
<div id="adminApp" class="hidden min-h-screen flex">
<aside id="sidebar" class="w-64 bg-[#0d1117] border-r border-slate-800 flex flex-col fixed h-screen z-40 transition-transform duration-300 -translate-x-full md:translate-x-0">
<div class="p-4 border-b border-slate-800 flex items-center gap-3">
<div class="w-10 h-10 bg-blue-600 rounded-xl flex items-center justify-center text-white font-bold text-sm">AB</div>
<div>
<h1 class="text-sm font-bold text-white leading-tight">Bappi Ads Analytics</h1>
<p class="text-[10px] text-slate-500">Atikur Rahman Bappi</p>
</div>
<button onclick="toggleSidebar()" class="md:hidden ml-auto text-slate-400">✕</button>
</div>
<div class="flex-1 overflow-y-auto p-3 space-y-1">
<div class="p-3 glass rounded-xl mb-3">
<div class="flex items-center gap-2">
<div class="w-8 h-8 rounded-full bg-blue-600/20 text-blue-400 flex items-center justify-center text-xs font-bold">A</div>
<div>
<p class="text-sm font-medium text-white">Atikur R. Bappi</p>
<p class="text-[10px] text-blue-400">Super Admin</p>
</div>
</div>
</div>
<p class="px-3 text-[10px] font-semibold text-slate-600 uppercase tracking-wider mt-4 mb-2">MAIN</p>
<a onclick="showSection('dashboard')" id="nav-dashboard" class="sidebar-link active flex items-center gap-3 px-3 py-2 cursor-pointer text-slate-400 text-sm font-medium">
<span class="w-5 text-center"></span> Dashboard
</a>
<a onclick="showSection('campaigns')" id="nav-campaigns" class="sidebar-link flex items-center gap-3 px-3 py-2 cursor-pointer text-slate-400 text-sm font-medium">
<span class="w-5 text-center"></span> Campaigns
</a>
<a onclick="showSection('adsets')" id="nav-adsets" class="sidebar-link flex items-center gap-3 px-3 py-2 cursor-pointer text-slate-400 text-sm font-medium">
<span class="w-5 text-center">🎯</span> Ad Sets
</a>
<a onclick="showSection('ads')" id="nav-ads" class="sidebar-link flex items-center gap-3 px-3 py-2 cursor-pointer text-slate-400 text-sm font-medium">
<span class="w-5 text-center">🖼</span> Ads
</a>
<a onclick="showSection('insights')" id="nav-insights" class="sidebar-link flex items-center gap-3 px-3 py-2 cursor-pointer text-slate-400 text-sm font-medium">
<span class="w-5 text-center">📊</span> Insights
</a>
<p class="px-3 text-[10px] font-semibold text-slate-600 uppercase tracking-wider mt-4 mb-2">MANAGEMENT</p>
<a onclick="showSection('clients')" id="nav-clients" class="sidebar-link flex items-center gap-3 px-3 py-2 cursor-pointer text-slate-400 text-sm font-medium">
<span class="w-5 text-center">👥</span> Clients
</a>
<a onclick="showSection('reports')" id="nav-reports" class="sidebar-link flex items-center gap-3 px-3 py-2 cursor-pointer text-slate-400 text-sm font-medium">
<span class="w-5 text-center">📄</span> Reports
</a>
<a onclick="showSection('budget')" id="nav-budget" class="sidebar-link flex items-center gap-3 px-3 py-2 cursor-pointer text-slate-400 text-sm font-medium">
<span class="w-5 text-center">💰</span> Budget Tracker
</a>
<a onclick="showSection('alerts')" id="nav-alerts" class="sidebar-link flex items-center gap-3 px-3 py-2 cursor-pointer text-slate-400 text-sm font-medium">
<span class="w-5 text-center">🔔</span> Alerts <span id="alertBadge" class="ml-auto bg-red-500 text-white text-[10px] rounded-full px-1.5 py-0.5 hidden">0</span>
</a>
<p class="px-3 text-[10px] font-semibold text-slate-600 uppercase tracking-wider mt-4 mb-2">SYSTEM</p>
<a onclick="showSection('metaConnect')" id="nav-metaConnect" class="sidebar-link flex items-center gap-3 px-3 py-2 cursor-pointer text-slate-400 text-sm font-medium">
<span class="w-5 text-center"></span> Meta Connect
</a>
<a onclick="showSection('settings')" id="nav-settings" class="sidebar-link flex items-center gap-3 px-3 py-2 cursor-pointer text-slate-400 text-sm font-medium">
<span class="w-5 text-center">⚙️</span> Settings
</a>
</div>
<div class="p-3 border-t border-slate-800">
<button onclick="logout()" class="w-full bg-slate-800 hover:bg-slate-700 text-red-400 border border-slate-700 rounded-xl py-2 text-sm transition flex items-center justify-center gap-2">
<span>🚪</span> Logout
</button>
</div>
</aside>
<main class="flex-1 overflow-y-auto ml-0 md:ml-64 min-h-screen">
<header class="sticky top-0 z-30 bg-[#0a0e17]/80 backdrop-blur-xl border-b border-slate-800 px-4 md:px-6 py-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-4">
<button onclick="toggleSidebar()" class="md:hidden text-slate-400 text-lg">☰</button>
<div class="hidden md:block">
<p class="text-sm text-slate-400" id="greeting">Good Evening,</p>
<p class="text-sm font-semibold text-white">Bappi Ads Analytics</p>
</div>
</div>
<div class="flex items-center gap-2">
<div class="hidden md:flex items-center bg-slate-800 rounded-xl px-3 py-1.5 border border-slate-700">
<span class="text-slate-500 text-sm mr-2"></span>
<input type="text" placeholder="Search campaigns, clients..." class="bg-transparent border-none outline-none text-sm text-slate-300 w-40 md:w-56">
</div>
<button class="w-8 h-8 rounded-xl bg-slate-800 border border-slate-700 flex items-center justify-center text-slate-400 hover:text-white hover:bg-slate-700 transition">
<span class="text-sm"></span>
</button>
<button class="w-8 h-8 rounded-xl bg-slate-800 border border-slate-700 flex items-center justify-center text-slate-400 hover:text-white hover:bg-slate-700 transition relative">
<span class="text-sm">🔔</span>
<span class="absolute top-0 right-0 w-2 h-2 bg-red-500 rounded-full pulse-dot"></span>
</button>
<div class="flex items-center gap-2 bg-slate-800 rounded-xl px-3 py-1.5 border border-slate-700">
<div class="w-6 h-6 rounded-full bg-blue-600 flex items-center justify-center text-white text-[10px] font-bold">A</div>
<span class="text-xs text-slate-300 hidden md:inline">Bappi Agency</span>
<span class="text-slate-500 text-xs">▼</span>
</div>
<button onclick="showSection('reports')" class="hidden md:flex items-center gap-1.5 bg-slate-800 hover:bg-slate-700 border border-slate-700 rounded-xl px-3 py-1.5 text-xs text-slate-300 transition">
<span></span> Export
</button>
<button onclick="openModal('addClientModal')" class="hidden md:flex items-center gap-1.5 bg-blue-600 hover:bg-blue-500 rounded-xl px-3 py-1.5 text-xs text-white font-medium transition">
<span>+</span> Add New Entry
</button>
</div>
</div>
</header>
<div class="p-4 md:p-6 space-y-6">
<!-- Dashboard -->
<div id="dashboard" class="section-content fade-in space-y-6">
<div class="glass rounded-2xl p-6">
<div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
<div>
<h1 class="text-xl font-bold text-white">🌅 Good Morning, Atikur Rahman Bappi 👋</h1>
<p class="text-slate-400 mt-1 text-sm">Welcome to your Command Center. Track every campaign, every client, and every dollar — all in real time.</p>
</div>
<div class="flex gap-2">
<button onclick="startFacebookLogin()" class="bg-[#1877F2] hover:bg-[#166FE5] text-white px-4 py-2 rounded-xl text-sm transition flex items-center gap-2 shadow-lg shadow-blue-600/20">
<span class="loading-spinner" id="fbLoadingSpinner" style="display:none;"></span>
<span id="fbConnectText">Connect Facebook</span>
</button>
<button onclick="openModal('addClientModal')" class="bg-slate-800 hover:bg-slate-700 text-slate-300 border border-slate-700 px-4 py-2 rounded-xl text-sm transition flex items-center gap-2">
<span></span> Add Client
</button>
</div>
</div>
</div>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="glass rounded-2xl p-4 metric-card">
<div class="flex items-center gap-2 mb-2">
<span class="w-2 h-2 rounded-full bg-blue-500"></span>
<p class="text-xs text-slate-500 uppercase font-medium"> Total Spend</p>
<span class="ml-auto text-green-400 text-xs font-medium" id="spendGrowth">+0%</span>
</div>
<p class="text-2xl font-bold text-white" id="dashTotalSpend">$0</p>
<p class="text-[10px] text-slate-600 mt-1">Across all accounts</p>
</div>
<div class="glass rounded-2xl p-4 metric-card">
<div class="flex items-center gap-2 mb-2">
<span class="w-2 h-2 rounded-full bg-purple-500"></span>
<p class="text-xs text-slate-500 uppercase font-medium"> Total Reach</p>
<span class="ml-auto text-green-400 text-xs font-medium" id="reachGrowth">+0%</span>
</div>
<p class="text-2xl font-bold text-white" id="dashTotalReach">0</p>
<p class="text-[10px] text-slate-600 mt-1">Unique people reached</p>
</div>
<div class="glass rounded-2xl p-4 metric-card">
<div class="flex items-center gap-2 mb-2">
<span class="w-2 h-2 rounded-full bg-green-500"></span>
<p class="text-xs text-slate-500 uppercase font-medium">✅ Total Results</p>
<span class="ml-auto text-green-400 text-xs font-medium" id="resultsGrowth">+0%</span>
</div>
<p class="text-2xl font-bold text-white" id="dashTotalResults">0</p>
<p class="text-[10px] text-slate-600 mt-1">Campaign objectives met</p>
</div>
<div class="glass rounded-2xl p-4 metric-card">
<div class="flex items-center gap-2 mb-2">
<span class="w-2 h-2 rounded-full bg-orange-500"></span>
<p class="text-xs text-slate-500 uppercase font-medium">📢 Active Campaigns</p>
</div>
<p class="text-2xl font-bold text-white" id="dashActiveCampaigns">0</p>
<p class="text-[10px] text-slate-600 mt-1">Currently running</p>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div class="lg:col-span-2 glass rounded-2xl p-5">
<div class="flex justify-between items-center mb-4">
<div>
<h3 class="font-bold text-white text-sm">Ad Spend Trend</h3>
<p class="text-[10px] text-slate-500">Daily spend across all accounts</p>
</div>
<div class="flex items-center gap-1">
<span class="text-xs text-slate-400 mr-2">TOTAL SPEND:</span>
<span class="text-lg font-bold text-white" id="chartTotalSpend">$0</span>
</div>
<div class="flex gap-1">
<button class="tab-btn active text-[10px] px-2 py-1 rounded-lg">Today</button>
<button class="tab-btn text-[10px] px-2 py-1 rounded-lg text-slate-400 hover:text-white">7D</button>
<button class="tab-btn text-[10px] px-2 py-1 rounded-lg text-slate-400 hover:text-white">30D</button>
</div>
</div>
<div class="h-52">
<canvas id="spendChart"></canvas>
</div>
<div class="flex justify-center gap-4 mt-3">
<span class="flex items-center gap-1.5 text-[10px] text-slate-400"><span class="w-3 h-3 bg-blue-500 rounded-sm"></span> Spend</span>
<span class="flex items-center gap-1.5 text-[10px] text-slate-400"><span class="w-3 h-3 bg-green-400 rounded-sm"></span> Results</span>
</div>
</div>
<div class="glass rounded-2xl p-5">
<div class="flex justify-between items-center mb-4">
<div>
<h3 class="font-bold text-white text-sm">Top Campaigns</h3>
<p class="text-[10px] text-slate-500">By spend (last 7 days)</p>
</div>
</div>
<div class="flex justify-between mb-3 text-[10px] text-slate-600">
<span>Mon</span><span>Tue</span><span>Wed</span><span>Thu</span><span>Fri</span><span>Sat</span><span>Sun</span>
</div>
<div class="space-y-3" id="topCampaignsGauges">
<div class="flex gap-2 items-center">
<div class="flex-1 bg-slate-800 rounded-full h-1.5 overflow-hidden">
<div class="bg-blue-500 h-full rounded-full" style="width:85%"></div>
</div>
<span class="text-[10px] text-slate-500 w-8 text-right">$120</span>
</div>
<div class="flex gap-2 items-center">
<div class="flex-1 bg-slate-800 rounded-full h-1.5 overflow-hidden">
<div class="bg-purple-500 h-full rounded-full" style="width:65%"></div>
</div>
<span class="text-[10px] text-slate-500 w-8 text-right">$85</span>
</div>
<div class="flex gap-2 items-center">
<div class="flex-1 bg-slate-800 rounded-full h-1.5 overflow-hidden">
<div class="bg-green-500 h-full rounded-full" style="width:45%"></div>
</div>
<span class="text-[10px] text-slate-500 w-8 text-right">$60</span>
</div>
<div class="flex gap-2 items-center">
<div class="flex-1 bg-slate-800 rounded-full h-1.5 overflow-hidden">
<div class="bg-orange-500 h-full rounded-full" style="width:30%"></div>
</div>
<span class="text-[10px] text-slate-500 w-8 text-right">$40</span>
</div>
</div>
<div class="mt-4 pt-3 border-t border-slate-800">
<p class="text-[10px] text-slate-600">Total: 4 campaigns</p>
</div>
</div>
</div>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="glass rounded-2xl p-4 metric-card flex items-center gap-3">
<div class="w-8 h-8 rounded-lg bg-purple-500/20 flex items-center justify-center"><span class="text-purple-400 text-sm"></span></div>
<div><p class="text-[10px] text-slate-500 uppercase">Reach</p><p class="text-lg font-bold text-white" id="metricReach">0</p></div>
</div>
<div class="glass rounded-2xl p-4 metric-card flex items-center gap-3">
<div class="w-8 h-8 rounded-lg bg-green-500/20 flex items-center justify-center"><span class="text-green-400 text-sm">✅</span></div>
<div><p class="text-[10px] text-slate-500 uppercase">Results</p><p class="text-lg font-bold text-white" id="metricResults">0</p></div>
</div>
<div class="glass rounded-2xl p-4 metric-card flex items-center gap-3">
<div class="w-8 h-8 rounded-lg bg-blue-500/20 flex items-center justify-center"><span class="text-blue-400 text-sm">💰</span></div>
<div><p class="text-[10px] text-slate-500 uppercase">Revenue</p><p class="text-lg font-bold text-white">$0</p></div>
</div>
<div class="glass rounded-2xl p-4 metric-card flex items-center gap-3">
<div class="w-8 h-8 rounded-lg bg-orange-500/20 flex items-center justify-center"><span class="text-orange-400 text-sm">📈</span></div>
<div><p class="text-[10px] text-slate-500 uppercase">ROAS</p><p class="text-lg font-bold text-white">0.00x</p></div>
</div>
</div>
<div class="glass rounded-2xl p-5">
<div class="flex justify-between items-center mb-4">
<h3 class="font-bold text-white text-sm">Today's Campaigns</h3>
<button onclick="showSection('campaigns')" class="text-xs text-blue-400 hover:text-blue-300">View All →</button>
</div>
<div class="overflow-x-auto">
<table class="w-full text-xs text-left">
<thead class="text-slate-500 uppercase text-[10px] border-b border-slate-800">
<tr>
<th class="pb-3 pl-2">No</th><th class="pb-3">Campaign Name</th><th class="pb-3">Objective</th><th class="pb-3">Date Created</th><th class="pb-3">Status</th>
</tr>
</thead>
<tbody id="dashCampaignsTable" class="text-slate-300">
<tr><td class="py-4 pl-2 text-slate-600" colspan="5">No campaigns yet. Add manually.</td></tr>
</tbody>
</table>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<div class="md:col-span-2 glass rounded-2xl p-5">
<h3 class="font-bold text-white text-sm mb-4"> Quick Actions</h3>
<div class="grid grid-cols-2 md:grid-cols-4 gap-3">
<button onclick="startFacebookLogin()" class="bg-slate-800 hover:bg-slate-700 border border-slate-700 rounded-xl p-3 text-center transition"><span class="text-lg block mb-1"></span><span class="text-[10px] text-slate-400">Connect Meta</span></button>
<button onclick="openModal('addClientModal')" class="bg-slate-800 hover:bg-slate-700 border border-slate-700 rounded-xl p-3 text-center transition"><span class="text-lg block mb-1"></span><span class="text-[10px] text-slate-400">Add Client</span></button>
<button onclick="showSection('budget')" class="bg-slate-800 hover:bg-slate-700 border border-slate-700 rounded-xl p-3 text-center transition"><span class="text-lg block mb-1"></span><span class="text-[10px] text-slate-400">Budget</span></button>
<button onclick="showSection('clients')" class="bg-slate-800 hover:bg-slate-700 border border-slate-700 rounded-xl p-3 text-center transition"><span class="text-lg block mb-1"></span><span class="text-[10px] text-slate-400">Client Portal</span></button>
</div>
</div>
<div class="glass rounded-2xl p-5">
<h3 class="font-bold text-white text-sm mb-4"> System Status</h3>
<div class="space-y-3">
<div class="flex items-center gap-2"><span class="status-dot status-active"></span><span class="text-xs text-slate-400">Meta API</span><span class="text-[10px] text-slate-600 ml-auto" id="metaApiStatus">Not Connected</span></div>
<div class="flex items-center gap-2"><span class="status-dot status-active"></span><span class="text-xs text-slate-400">Database</span><span class="text-[10px] text-slate-600 ml-auto">Synced</span></div>
<div class="flex items-center gap-2"><span class="status-dot status-paused"></span><span class="text-xs text-slate-400">Auto-Sync</span><span class="text-[10px] text-slate-600 ml-auto">Manual</span></div>
</div>
<div class="mt-4 pt-3 border-t border-slate-800">
<div class="flex items-center justify-between">
<div><p class="text-lg font-bold text-white" id="activeAccountCount">0</p><p class="text-[10px] text-slate-500">Active Campaigns</p></div>
</div>
</div>
</div>
</div>
</div>
<!-- Campaigns -->
<div id="campaigns" class="section-content hidden fade-in space-y-6">
<div class="flex justify-between items-center">
<h2 class="text-lg font-bold text-white">📢 Campaigns <span class="text-slate-600 text-sm font-normal">All campaigns</span></h2>
<button onclick="openModal('addCampaignModal')" class="bg-blue-600 hover:bg-blue-500 text-white px-4 py-2 rounded-xl text-sm transition flex items-center gap-2 shadow-lg shadow-blue-600/20">+ Add Campaign</button>
</div>
<div class="glass rounded-2xl overflow-hidden">
<div class="p-4 border-b border-slate-800 flex gap-4">
<input type="text" placeholder="🔍 Search campaigns..." class="px-4 py-2 rounded-xl text-sm outline-none w-full md:w-64">
<select class="bg-slate-800 border border-slate-700 rounded-xl px-3 py-2 text-sm outline-none"><option>All Statuses</option><option>Active</option><option>Paused</option></select>
</div>
<div class="overflow-x-auto">
<table class="w-full text-sm text-left">
<thead class="bg-slate-800/50 text-slate-500 uppercase text-[10px] border-b border-slate-800">
<tr><th class="px-4 py-3">Campaign</th><th class="px-4 py-3">Status</th><th class="px-4 py-3">Objective</th><th class="px-4 py-3">Spend</th><th class="px-4 py-3">Reach</th><th class="px-4 py-3">Results</th><th class="px-4 py-3">Client</th><th class="px-4 py-3">Action</th></tr>
</thead>
<tbody id="campaignsTable" class="divide-y divide-slate-800">
<tr><td class="px-4 py-8 text-center text-slate-600" colspan="8">No campaigns. Add one.</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Ad Sets -->
<div id="adsets" class="section-content hidden fade-in space-y-6">
<div class="flex justify-between items-center">
<h2 class="text-lg font-bold text-white">🎯 Ad Sets</h2>
<button onclick="openModal('addAdSetModal')" class="bg-blue-600 hover:bg-blue-500 text-white px-4 py-2 rounded-xl text-sm transition flex items-center gap-2 shadow-lg shadow-blue-600/20">+ Add Ad Set</button>
</div>
<div class="glass rounded-2xl overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-sm text-left">
<thead class="bg-slate-800/50 text-slate-500 uppercase text-[10px] border-b border-slate-800">
<tr><th class="px-4 py-3">Ad Set</th><th class="px-4 py-3">Campaign</th><th class="px-4 py-3">Status</th><th class="px-4 py-3">Budget</th><th class="px-4 py-3">Spend</th><th class="px-4 py-3">Reach</th><th class="px-4 py-3">CTR</th><th class="px-4 py-3">Results</th></tr>
</thead>
<tbody id="adSetsTable" class="divide-y divide-slate-800">
<tr><td class="px-4 py-8 text-center text-slate-600" colspan="8">No ad sets yet.</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Ads -->
<div id="ads" class="section-content hidden fade-in space-y-6">
<div class="flex justify-between items-center">
<h2 class="text-lg font-bold text-white">🖼 Ads <span class="text-slate-600 text-sm font-normal">All creatives</span></h2>
<button onclick="openModal('addAdModal')" class="bg-blue-600 hover:bg-blue-500 text-white px-4 py-2 rounded-xl text-sm transition flex items-center gap-2 shadow-lg shadow-blue-600/20">+ Add Ad</button>
</div>
<div class="glass rounded-2xl overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-sm text-left">
<thead class="bg-slate-800/50 text-slate-500 uppercase text-[10px] border-b border-slate-800">
<tr><th class="px-4 py-3">Ad Name</th><th class="px-4 py-3">Campaign</th><th class="px-4 py-3">Status</th><th class="px-4 py-3">Spend</th><th class="px-4 py-3">Reach</th><th class="px-4 py-3">Impressions</th><th class="px-4 py-3">CTR</th><th class="px-4 py-3">Results</th><th class="px-4 py-3">Client</th></tr>
</thead>
<tbody id="adsTable" class="divide-y divide-slate-800">
<tr><td class="px-4 py-8 text-center text-slate-600" colspan="9">No ads. Add one manually.</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Insights -->
<div id="insights" class="section-content hidden fade-in space-y-6">
<h2 class="text-lg font-bold text-white"> Insights</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="glass rounded-2xl p-4"><p class="text-xs text-slate-500"> Avg CTR</p><p class="text-xl font-bold text-white">—</p></div>
<div class="glass rounded-2xl p-4"><p class="text-xs text-slate-500">💸 Avg CPM</p><p class="text-xl font-bold text-white">—</p></div>
<div class="glass rounded-2xl p-4"><p class="text-xs text-slate-500">⚡ Avg CPC</p><p class="text-xl font-bold text-white">—</p></div>
<div class="glass rounded-2xl p-4"><p class="text-xs text-slate-500">🔄 Frequency</p><p class="text-xl font-bold text-white">—</p></div>
</div>
<div class="glass rounded-2xl p-8 text-center">
<p class="text-slate-500">📊 Add campaign data to see insights.</p>
</div>
</div>
<!-- Clients -->
<div id="clients" class="section-content hidden fade-in space-y-6">
<div class="flex justify-between items-center">
<h2 class="text-lg font-bold text-white">👥 Clients <span class="text-slate-600 text-sm font-normal">Manage profiles</span></h2>
<button onclick="openModal('addClientModal')" class="bg-blue-600 hover:bg-blue-500 text-white px-4 py-2 rounded-xl text-sm transition flex items-center gap-2 shadow-lg shadow-blue-600/20">+ Add Client</button>
</div>
<div class="glass rounded-2xl overflow-hidden">
<div class="p-4 border-b border-slate-800 flex gap-4">
<input type="text" placeholder=" Search clients..." class="px-4 py-2 rounded-xl text-sm outline-none w-full md:w-64">
</div>
<div class="overflow-x-auto">
<table class="w-full text-sm text-left">
<thead class="bg-slate-800/50 text-slate-500 uppercase text-[10px] border-b border-slate-800">
<tr><th class="px-4 py-3">Client</th><th class="px-4 py-3">Company</th><th class="px-4 py-3">Contact</th><th class="px-4 py-3">Status</th><th class="px-4 py-3">Balance</th><th class="px-4 py-3">Client ID</th><th class="px-4 py-3">Action</th></tr>
</thead>
<tbody id="clientsTable" class="divide-y divide-slate-800">
<tr><td class="px-4 py-8 text-center text-slate-600" colspan="7">No clients added yet.</td></tr>
</tbody>
</table>
</div>
<div class="p-3 border-t border-slate-800 text-[10px] text-slate-600" id="clientsCount">0 clients</div>
</div>
</div>
<!-- Reports -->
<div id="reports" class="section-content hidden fade-in space-y-6">
<h2 class="text-lg font-bold text-white">📄 Reports</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="glass rounded-2xl p-6">
<h3 class="font-bold text-white mb-2">📄 Generate Report</h3>
<p class="text-xs text-slate-500 mb-4">PDF or CSV for a client</p>
<div class="space-y-3">
<select class="w-full px-3 py-2 rounded-xl text-sm outline-none"><option>Select client</option></select>
<div class="grid grid-cols-2 gap-2">
<input type="date" class="px-3 py-2 rounded-xl text-sm">
<input type="date" class="px-3 py-2 rounded-xl text-sm">
</div>
<div class="flex gap-2 pt-2">
<button class="flex-1 bg-slate-800 hover:bg-slate-700 text-slate-300 py-2 rounded-xl text-sm border border-slate-700">⬇ PDF</button>
<button class="flex-1 bg-slate-800 hover:bg-slate-700 text-slate-300 py-2 rounded-xl text-sm border border-slate-700"> CSV</button>
</div>
</div>
</div>
<div class="glass rounded-2xl p-6">
<h3 class="font-bold text-white mb-2">🔗 Client Report Link</h3>
<p class="text-xs text-slate-500 mb-4">Share access link with client</p>
<div class="space-y-3">
<select class="w-full px-3 py-2 rounded-xl text-sm outline-none"><option>Select client</option></select>
<button onclick="generateClientLink()" class="w-full bg-blue-600 hover:bg-blue-500 text-white py-2 rounded-xl text-sm transition"> Generate Link</button>
<div id="generatedLinkBox" class="hidden p-3 bg-green-500/10 border border-green-500/20 rounded-xl">
<p class="text-[10px] text-green-400 font-medium mb-1">✅ Share link ready!</p>
<div class="flex gap-2">
<input type="text" readonly value="https://bappi-ads.com/portal?c=CLI-8821" class="flex-1 px-2 py-1 text-[10px] border border-green-500/20 rounded-lg bg-slate-800 text-slate-400">
<button class="bg-green-600 text-white px-3 py-1 rounded-lg text-[10px]"> Copy</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Budget -->
<div id="budget" class="section-content hidden fade-in space-y-6">
<div class="flex justify-between items-center">
<h2 class="text-lg font-bold text-white">💰 Budget Tracker</h2>
<button onclick="openModal('addDepositModal')" class="bg-blue-600 hover:bg-blue-500 text-white px-4 py-2 rounded-xl text-sm transition flex items-center gap-2 shadow-lg shadow-blue-600/20">+ Add Deposit</button>
</div>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="glass rounded-2xl p-4"><p class="text-[10px] text-slate-500 uppercase mb-1">💳 Total Deposits</p><p class="text-lg font-bold text-white" id="budgetTotalDeposits">৳0</p></div>
<div class="glass rounded-2xl p-4"><p class="text-[10px] text-slate-500 uppercase mb-1">💸 Total Spent</p><p class="text-lg font-bold text-red-400" id="budgetTotalSpent">$0</p></div>
<div class="glass rounded-2xl p-4"><p class="text-[10px] text-slate-500 uppercase mb-1">🏦 Remaining</p><p class="text-lg font-bold text-green-400" id="budgetRemaining">৳0</p></div>
<div class="glass rounded-2xl p-4"><p class="text-[10px] text-slate-500 uppercase mb-1">⚠️ Low Balance</p><p class="text-lg font-bold text-orange-400" id="budgetLowCount">0</p></div>
</div>
<div class="glass rounded-2xl overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-sm text-left">
<thead class="bg-slate-800/50 text-slate-500 uppercase text-[10px] border-b border-slate-800">
<tr><th class="px-4 py-3">Client</th><th class="px-4 py-3">Deposit (BDT)</th><th class="px-4 py-3">Rate</th><th class="px-4 py-3">USD Budget</th><th class="px-4 py-3">Spent</th><th class="px-4 py-3">Remaining</th><th class="px-4 py-3">Usage</th><th class="px-4 py-3">Status</th></tr>
</thead>
<tbody id="budgetTable" class="divide-y divide-slate-800">
<tr><td class="px-4 py-8 text-center text-slate-600" colspan="8">No clients added yet.</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Alerts -->
<div id="alerts" class="section-content hidden fade-in space-y-6">
<div class="flex justify-between items-center">
<h2 class="text-lg font-bold text-white"> Alerts</h2>
<button onclick="markAlertsRead()" class="text-xs text-blue-400 hover:text-blue-300">✓ Mark All Read</button>
</div>
<div class="glass rounded-2xl p-8 text-center">
<p class="text-slate-500">🔔 No alerts yet</p>
</div>
</div>
<!-- Meta Connect - Facebook Login & Real-time Data -->
<div id="metaConnect" class="section-content hidden fade-in space-y-6">
<h2 class="text-lg font-bold text-white"> Meta Connection</h2>
<!-- Facebook Login Status -->
<div class="glass rounded-2xl p-6">
<div class="flex items-center gap-4 mb-6">
<div class="w-12 h-12 bg-[#1877F2] rounded-xl flex items-center justify-center text-white text-xl"></div>
<div>
<h3 class="font-bold text-white">Connect Facebook</h3>
<p class="text-xs text-slate-500">Connect Business Managers & Ad Accounts via Facebook Login</p>
</div>
<div class="ml-auto">
<span id="fbConnectionStatus" class="px-3 py-1 rounded-full text-xs font-medium bg-slate-800 text-slate-400">Not Connected</span>
</div>
</div>
<!-- Connected Info -->
<div id="connectedUserInfo" class="hidden bg-slate-800/50 rounded-xl p-4 mb-6 border border-slate-700">
<div class="flex items-center gap-3 mb-3">
<img id="fbUserAvatar" src="" alt="" class="w-10 h-10 rounded-full">
<div>
<p class="text-sm font-medium text-white" id="fbUserName"></p>
<p class="text-xs text-slate-400" id="fbUserEmail"></p>
</div>
</div>
<div class="grid grid-cols-2 md:grid-cols-4 gap-3 text-xs">
<div class="bg-slate-800 p-2 rounded-lg">
<p class="text-slate-500">Access Token</p>
<p class="text-blue-400 font-mono truncate" id="fbTokenDisplay">EAA...</p>
</div>
<div class="bg-slate-800 p-2 rounded-lg">
<p class="text-slate-500">Expires In</p>
<p class="text-green-400" id="fbTokenExpiry">—</p>
</div>
<div class="bg-slate-800 p-2 rounded-lg">
<p class="text-slate-500">Permissions</p>
<p class="text-emerald-400" id="fbPermissions">ads_read, pages_read_engagement</p>
</div>
<div class="bg-slate-800 p-2 rounded-lg">
<p class="text-slate-500">Last Sync</p>
<p class="text-slate-300" id="fbLastSync">—</p>
</div>
</div>
<div class="flex gap-2 mt-4">
<button onclick="syncAllAccounts()" class="bg-blue-600 hover:bg-blue-500 text-white px-4 py-2 rounded-lg text-xs transition flex items-center gap-2">
<span class="loading-spinner" id="syncSpinner" style="display:none; width:14px; height:14px; border-width:2px;"></span>
🔄 Sync All Accounts
</button>
<button onclick="fetchCampaigns()" class="bg-slate-700 hover:bg-slate-600 text-slate-300 px-4 py-2 rounded-lg text-xs transition">
📊 Fetch Campaigns
</button>
<button onclick="disconnectFacebook()" class="bg-red-500/20 hover:bg-red-500/30 text-red-400 px-4 py-2 rounded-lg text-xs transition">
🔌 Disconnect
</button>
</div>
</div>
<!-- Login Button -->
<div id="fbLoginSection">
<p class="text-xs text-slate-400 mb-3">Login with Facebook to connect your Meta Ad Accounts and pull real-time campaign data.</p>
<button onclick="startFacebookLogin()" class="w-full bg-[#1877F2] hover:bg-[#166FE5] text-white py-3 rounded-xl text-sm font-medium transition shadow-lg shadow-blue-600/20 flex items-center justify-center gap-2">
<span class="text-lg"></span>
Continue with Facebook
</button>
<p class="text-[10px] text-slate-500 mt-3 text-center">
You'll be redirected to Facebook's official login page. Required: ads_read, pages_read_engagement, business_management
</p>
</div>
</div>
<!-- Ad Accounts -->
<div class="glass rounded-2xl overflow-hidden">
<div class="p-4 border-b border-slate-800 flex justify-between items-center">
<h3 class="text-sm font-medium text-slate-300"> Ad Accounts</h3>
<button onclick="refreshAdAccounts()" class="text-xs text-blue-400 hover:text-blue-300">🔄 Refresh</button>
</div>
<div class="overflow-x-auto">
<table class="w-full text-sm text-left">
<thead class="bg-slate-800/50 text-slate-500 uppercase text-[10px] border-b border-slate-800">
<tr><th class="px-4 py-3">Name</th><th class="px-4 py-3">Account ID</th><th class="px-4 py-3">Currency</th><th class="px-4 py-3">Status</th><th class="px-4 py-3">Spend Today</th><th class="px-4 py-3">Actions</th></tr>
</thead>
<tbody id="adAccountsTable" class="divide-y divide-slate-800">
<tr><td class="px-4 py-8 text-center text-slate-600" colspan="6">Connect Facebook to view your ad accounts.</td></tr>
</tbody>
</table>
</div>
</div>
<!-- Real-time Campaigns -->
<div class="glass rounded-2xl overflow-hidden">
<div class="p-4 border-b border-slate-800 flex justify-between items-center">
<h3 class="text-sm font-medium text-slate-300">📈 Live Campaigns</h3>
<button onclick="fetchCampaigns()" class="text-xs text-blue-400 hover:text-blue-300">🔄 Fetch from Meta</button>
</div>
<div class="overflow-x-auto">
<table class="w-full text-sm text-left">
<thead class="bg-slate-800/50 text-slate-500 uppercase text-[10px] border-b border-slate-800">
<tr><th class="px-4 py-3">Campaign</th><th class="px-4 py-3">Status</th><th class="px-4 py-3">Spend</th><th class="px-4 py-3">Reach</th><th class="px-4 py-3">Results</th><th class="px-4 py-3">CTR</th><th class="px-4 py-3">CPR</th></tr>
</thead>
<tbody id="liveCampaignsTable" class="divide-y divide-slate-800">
<tr><td class="px-4 py-8 text-center text-slate-600" colspan="7">No campaigns loaded. Connect Facebook and sync.</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Settings -->
<div id="settings" class="section-content hidden fade-in space-y-6">
<h2 class="text-lg font-bold text-white">⚙️ Settings</h2>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="glass rounded-2xl p-6">
<h3 class="font-bold text-white mb-4 text-sm border-b border-slate-800 pb-2">General</h3>
<div class="space-y-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Organization Name</label>
<input type="text" id="orgName" value="Bappi Ads Analytics" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Owner Name</label>
<input type="text" id="orgOwner" value="Atikur Rahman Bappi" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Email</label>
<input type="email" id="orgEmail" value="arbappi82@gmail.com" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<button onclick="saveSettings()" class="bg-blue-600 hover:bg-blue-500 text-white px-4 py-2 rounded-xl text-sm transition">💾 Save</button>
</div>
</div>
<div class="glass rounded-2xl p-6">
<h3 class="font-bold text-white mb-4 text-sm border-b border-slate-800 pb-2">Preferences</h3>
<div class="space-y-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Default BDT/USD Rate</label>
<div class="flex items-center gap-2">
<span class="text-slate-500 text-sm"></span>
<input type="number" id="exchangeRate" value="115" class="w-24 px-3 py-2 rounded-xl text-sm outline-none">
<span class="text-xs text-slate-600">per $1</span>
</div>
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Timezone</label>
<select class="w-full px-3 py-2 rounded-xl text-sm outline-none"><option>Asia/Dhaka</option><option>UTC</option></select>
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Auto-refresh Interval</label>
<select id="autoRefreshInterval" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option value="30000">30 seconds</option>
<option value="60000">1 minute</option>
<option value="300000">5 minutes</option>
<option value="0">Manual</option>
</select>
</div>
<button onclick="saveSettings()" class="bg-blue-600 hover:bg-blue-500 text-white px-4 py-2 rounded-xl text-sm transition">💾 Save</button>
</div>
</div>
<div class="glass rounded-2xl p-6">
<h3 class="font-bold text-white mb-4 text-sm border-b border-slate-800 pb-2">Branding</h3>
<div class="flex items-center gap-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Primary Color</label>
<input type="color" id="brandColor" value="#2563eb" class="w-12 h-10 p-1 rounded cursor-pointer bg-slate-800 border border-slate-700">
</div>
<div class="flex-1">
<p class="text-[10px] text-slate-600 mb-1">Preview</p>
<div id="brandPreview" class="h-10 rounded-xl flex items-center justify-center text-white font-bold text-sm" style="background-color:#2563eb">AB Analytics</div>
</div>
</div>
<button onclick="saveBranding()" class="mt-4 bg-slate-800 hover:bg-slate-700 text-slate-300 px-4 py-2 rounded-xl text-sm transition w-full border border-slate-700">Apply</button>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- Add Client Modal -->
<div id="addClientModal" class="hidden fixed inset-0 z-50 modal-overlay bg-black/70 flex items-center justify-center p-4">
<div class="bg-[#0d1117] rounded-2xl w-full max-w-2xl max-h-[90vh] overflow-y-auto fade-in border border-slate-800">
<div class="p-5 border-b border-slate-800 flex justify-between items-center">
<h3 class="text-lg font-bold text-white"> Add New Client</h3>
<button onclick="closeModal('addClientModal')" class="text-slate-400 hover:text-white text-xl">✕</button>
</div>
<div class="p-5 space-y-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Client Name *</label>
<input type="text" id="newClientName" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Company</label>
<input type="text" id="newClientCompany" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Email</label>
<input type="email" id="newClientEmail" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Phone</label>
<input type="text" id="newClientPhone" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Deposit (BDT)</label>
<input type="number" id="newClientDeposit" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">BDT/USD Rate</label>
<input type="number" id="newClientRate" value="115" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
</div>
</div>
<div class="p-5 border-t border-slate-800 flex justify-end gap-3">
<button onclick="closeModal('addClientModal')" class="px-4 py-2 text-slate-400 bg-slate-800 hover:bg-slate-700 rounded-xl text-sm border border-slate-700 transition">Cancel</button>
<button onclick="saveNewClient()" class="px-6 py-2 bg-blue-600 hover:bg-blue-500 text-white rounded-xl text-sm transition shadow-lg shadow-blue-600/20">💾 Save</button>
</div>
</div>
</div>
<!-- Add Campaign Modal -->
<div id="addCampaignModal" class="hidden fixed inset-0 z-50 modal-overlay bg-black/60 flex items-center justify-center p-4">
<div class="glass rounded-2xl w-full max-w-lg fade-in">
<div class="p-5 border-b border-slate-800 flex justify-between items-center">
<h3 class="text-lg font-bold text-white"> Add Campaign</h3>
<button onclick="closeModal('addCampaignModal')" class="text-slate-400 hover:text-white text-xl"></button>
</div>
<div class="p-5 space-y-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Campaign Name *</label>
<input type="text" id="newCampName" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Objective</label>
<select id="newCampObjective" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option>Sales</option><option>Leads</option><option>Engagement</option><option>Traffic</option><option>Awareness</option>
</select>
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Status</label>
<select id="newCampStatus" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option>Active</option><option>Paused</option>
</select>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Budget ($)</label>
<input type="number" id="newCampBudget" step="0.01" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Start Date</label>
<input type="date" id="newCampStart" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Assign Client</label>
<select id="newCampClient" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option value="">None</option>
</select>
</div>
</div>
<div class="p-5 border-t border-slate-800 flex justify-end gap-3">
<button onclick="closeModal('addCampaignModal')" class="px-4 py-2 text-slate-400 bg-slate-800 hover:bg-slate-700 rounded-xl text-sm border border-slate-700 transition">Cancel</button>
<button onclick="saveNewCampaign()" class="px-6 py-2 bg-blue-600 hover:bg-blue-500 text-white rounded-xl text-sm transition shadow-lg shadow-blue-600/20">💾 Save</button>
</div>
</div>
</div>
<!-- Add Ad Set Modal -->
<div id="addAdSetModal" class="hidden fixed inset-0 z-50 modal-overlay bg-black/60 flex items-center justify-center p-4">
<div class="glass rounded-2xl w-full max-w-lg fade-in">
<div class="p-5 border-b border-slate-800 flex justify-between items-center">
<h3 class="text-lg font-bold text-white">🎯 Add Ad Set</h3>
<button onclick="closeModal('addAdSetModal')" class="text-slate-400 hover:text-white text-xl">✕</button>
</div>
<div class="p-5 space-y-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Ad Set Name *</label>
<input type="text" id="newAdSetName" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Campaign *</label>
<select id="newAdSetCampaign" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option value="">Select campaign</option>
</select>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Budget ($)</label>
<input type="number" id="newAdSetBudget" step="0.01" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">End Date</label>
<input type="date" id="newAdSetEnd" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Targeting</label>
<select id="newAdSetTargeting" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option>Broad</option><option>Interest</option><option>Lookalike</option><option>Retargeting</option>
</select>
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Assign Client</label>
<select id="newAdSetClient" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option value="">None</option>
</select>
</div>
</div>
<div class="p-5 border-t border-slate-800 flex justify-end gap-3">
<button onclick="closeModal('addAdSetModal')" class="px-4 py-2 text-slate-400 bg-slate-800 hover:bg-slate-700 rounded-xl text-sm border border-slate-700 transition">Cancel</button>
<button onclick="saveNewAdSet()" class="px-6 py-2 bg-blue-600 hover:bg-blue-500 text-white rounded-xl text-sm transition shadow-lg shadow-blue-600/20">💾 Save</button>
</div>
</div>
</div>
<!-- Add Ad Modal -->
<div id="addAdModal" class="hidden fixed inset-0 z-50 modal-overlay bg-black/60 flex items-center justify-center p-4">
<div class="glass rounded-2xl w-full max-w-lg fade-in">
<div class="p-5 border-b border-slate-800 flex justify-between items-center">
<h3 class="text-lg font-bold text-white">🖼 Add Ad</h3>
<button onclick="closeModal('addAdModal')" class="text-slate-400 hover:text-white text-xl">✕</button>
</div>
<div class="p-5 space-y-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Ad Name *</label>
<input type="text" id="newAdName" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Campaign</label>
<select id="newAdCampaign" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option value="">Select Campaign</option>
</select>
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Status</label>
<select id="newAdStatus" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option>Active</option><option>Paused</option>
</select>
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Assign Client</label>
<select id="newAdClient" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option value="">None</option>
</select>
</div>
</div>
<div class="p-5 border-t border-slate-800 flex justify-end gap-3">
<button onclick="closeModal('addAdModal')" class="px-4 py-2 text-slate-400 bg-slate-800 hover:bg-slate-700 rounded-xl text-sm border border-slate-700 transition">Cancel</button>
<button onclick="saveNewAd()" class="px-6 py-2 bg-blue-600 hover:bg-blue-500 text-white rounded-xl text-sm transition shadow-lg shadow-blue-600/20">💾 Save</button>
</div>
</div>
</div>
<!-- Add Deposit Modal -->
<div id="addDepositModal" class="hidden fixed inset-0 z-50 modal-overlay bg-black/60 flex items-center justify-center p-4">
<div class="glass rounded-2xl w-full max-w-md fade-in">
<div class="p-5 border-b border-slate-800 flex justify-between items-center">
<h3 class="text-lg font-bold text-white">💰 Add Deposit</h3>
<button onclick="closeModal('addDepositModal')" class="text-slate-400 hover:text-white text-xl">✕</button>
</div>
<div class="p-5 space-y-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Client *</label>
<select id="depositClient" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option value="">Select client</option>
</select>
</div>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-[10px] text-slate-500 mb-1">Amount (BDT)</label>
<input type="number" id="depositAmount" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Rate</label>
<input type="number" id="depositRate" value="115" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
</div>
</div>
<div>
<label class="block text-[10px] text-slate-500 mb-1">Method</label>
<select id="depositMethod" class="w-full px-3 py-2 rounded-xl text-sm outline-none">
<option>Bank Transfer</option><option>bKash</option><option>Nagad</option><option>Cash</option>
</select>
</div>
</div>
<div class="p-5 border-t border-slate-800 flex justify-end gap-3">
<button onclick="closeModal('addDepositModal')" class="px-4 py-2 text-slate-400 bg-slate-800 hover:bg-slate-700 rounded-xl text-sm border border-slate-700 transition">Cancel</button>
<button onclick="saveDeposit()" class="px-6 py-2 bg-green-600 hover:bg-green-500 text-white rounded-xl text-sm transition">💰 Add</button>
</div>
</div>
</div>
<!-- Client Created Success Modal -->
<div id="clientSuccessModal" class="hidden fixed inset-0 z-50 modal-overlay bg-black/60 flex items-center justify-center p-4">
<div class="glass rounded-2xl w-full max-w-md p-6 text-center fade-in">
<div class="w-16 h-16 bg-green-500/20 text-green-400 rounded-full flex items-center justify-center text-3xl mx-auto mb-4">✅</div>
<h3 class="text-lg font-bold text-white mb-2">Client Created</h3>
<p class="text-slate-400 mb-4 text-sm">Share this Client ID for portal access:</p>
<div class="bg-slate-800 p-4 rounded-xl mb-6 border border-slate-700">
<p class="text-[10px] text-slate-600 uppercase tracking-wider mb-1">Client ID</p>
<p class="text-2xl font-mono font-bold text-blue-400" id="newClientIdDisplay">—</p>
</div>
<div class="flex gap-3">
<button onclick="copyClientId()" class="flex-1 bg-slate-800 hover:bg-slate-700 text-slate-300 py-3 rounded-xl font-medium border border-slate-700 transition"> Copy ID</button>
<button onclick="closeModal('clientSuccessModal')" class="flex-1 bg-blue-600 hover:bg-blue-500 text-white py-3 rounded-xl font-medium transition">Close</button>
</div>
</div>
</div>
<script>
const state = {
clients: [], campaigns: [], adSets: [], ads: [], deposits: [],
budgetRate: 115,
selectedCampaigns: [],
// Facebook Meta API State
fbAppId: '1234567890123456', // Replace with your Facebook App ID
fbRedirectUri: window.location.origin + window.location.pathname,
fbAccessToken: null,
fbTokenExpiry: null,
fbUser: null,
fbPermissions: ['ads_read', 'pages_read_engagement', 'business_management', 'read_insights'],
fbAutoRefresh: null
};
function updateGreeting() {
const h = new Date().getHours();
let g = h < 12 ? 'Good Morning' : h < 18 ? 'Good Afternoon' : 'Good Evening';
document.getElementById('greeting').textContent = g + ',';
}
function showClientLogin() {
document.getElementById('loginForm').classList.add('hidden');
document.getElementById('clientLoginForm').classList.remove('hidden');
}
function showAgencyLogin() {
document.getElementById('loginForm').classList.remove('hidden');
document.getElementById('clientLoginForm').classList.add('hidden');
}
function handleLogin() {
const email = document.getElementById('loginEmail').value;
const pass = document.getElementById('loginPassword').value;
if (email && pass === 'admin123') {
document.getElementById('authScreen').classList.add('hidden');
document.getElementById('adminApp').classList.remove('hidden');
updateGreeting();
initCharts();
loadDashboard();
checkFacebookAuth();
} else {
document.getElementById('loginError').classList.remove('hidden');
}
}
function handleClientLogin() {
const cid = document.getElementById('clientIdInput').value;
checkPortalClient(cid, true);
}
// Facebook OAuth Login - Redirect to Official Facebook Login
function startFacebookLogin() {
// Show loading
const spinner = document.getElementById('fbLoadingSpinner');
const btnText = document.getElementById('fbConnectText');
if(spinner) spinner.style.display = 'inline-block';
if(btnText) btnText.textContent = 'Connecting...';
// Facebook OAuth 2.0 Authorization URL
const scope = state.fbPermissions.join(',');
const authUrl = `https://www.facebook.com/v20.0/dialog/oauth?` +
`client_id=${state.fbAppId}` +
`&redirect_uri=${encodeURIComponent(state.fbRedirectUri)}` +
`&scope=${scope}` +
`&response_type=token` +
`&auth_type=rerequest`;
// Redirect to Facebook Login
window.location.href = authUrl;
}
// Handle Facebook OAuth Response
function handleFacebookResponse() {
const hash = window.location.hash;
if (hash && hash.includes('access_token')) {
const params = new URLSearchParams(hash.substring(1));
const accessToken = params.get('access_token');
const expiresIn = params.get('expires_in');
if (accessToken) {
state.fbAccessToken = accessToken;
state.fbTokenExpiry = expiresIn ? parseInt(expiresIn) : 0;
// Store in localStorage
localStorage.setItem('fb_access_token', accessToken);
localStorage.setItem('fb_token_expiry', Date.now() + (state.fbTokenExpiry * 1000));
// Clean URL
window.history.replaceState({}, document.title, window.location.pathname);
// Fetch user info
fetchFacebookUser();
}
}
}
// Fetch Facebook User Info
async function fetchFacebookUser() {
try {
const response = await fetch(`https://graph.facebook.com/me?fields=id,name,email,picture&access_token=${state.fbAccessToken}`);
const data = await response.json();
if (data.id) {
state.fbUser = data;
updateFacebookUI();
fetchAdAccounts();
}
} catch (error) {
console.error('Error fetching user:', error);
}
}
// Update Facebook UI
function updateFacebookUI() {
const statusEl = document.getElementById('fbConnectionStatus');
const userInfoEl = document.getElementById('connectedUserInfo');
const loginSection = document.getElementById('fbLoginSection');
const metaApiStatus = document.getElementById('metaApiStatus');
if (state.fbAccessToken) {
if(statusEl) {
statusEl.textContent = 'Connected';
statusEl.className = 'px-3 py-1 rounded-full text-xs font-medium bg-green-500/20 text-green-400';
}
if(userInfoEl) userInfoEl.classList.remove('hidden');
if(loginSection) loginSection.classList.add('hidden');
if(metaApiStatus) {
metaApiStatus.textContent = 'Connected';
metaApiStatus.className = 'text-[10px] text-green-400 ml-auto';
}
// Update user info
if (state.fbUser) {
document.getElementById('fbUserName').textContent = state.fbUser.name || '';
document.getElementById('fbUserEmail').textContent = state.fbUser.email || '';
document.getElementById('fbUserAvatar').src = state.fbUser.picture?.data?.url || '';
}
document.getElementById('fbTokenDisplay').textContent = state.fbAccessToken.substring(0, 20) + '...';
document.getElementById('fbLastSync').textContent = new Date().toLocaleString();
}
}
// Fetch Ad Accounts from Meta
async function fetchAdAccounts() {
try {
const response = await fetch(`https://graph.facebook.com/v20.0/me/adaccounts?fields=id,name,currency,amount_spent,spend_cap,account_status&access_token=${state.fbAccessToken}`);
const data = await response.json();
if (data.data && data.data.length > 0) {
updateAdAccountsTable(data.data);
document.getElementById('activeAccountCount').textContent = data.data.length;
}
} catch (error) {
console.error('Error fetching ad accounts:', error);
}
}
// Update Ad Accounts Table
function updateAdAccountsTable(accounts) {
const tbody = document.getElementById('adAccountsTable');
if (accounts.length === 0) {
tbody.innerHTML = '<tr><td class="px-4 py-8 text-center text-slate-600" colspan="6">No ad accounts found.</td></tr>';
return;
}
tbody.innerHTML = accounts.map(account => {
const statusMap = {
1: 'Active', 2: 'Disabled', 3: 'Unsettled', 7: 'In Grace Period', 100: 'Closed'
};
const status = statusMap[account.account_status] || 'Unknown';
const statusClass = account.account_status === 1 ? 'bg-green-500/10 text-green-400' : 'bg-orange-500/10 text-orange-400';
return `
<tr class="hover:bg-slate-800/30">
<td class="px-4 py-3 font-medium text-white">${account.name}</td>
<td class="px-4 py-3 font-mono text-[10px] text-slate-400">${account.id}</td>
<td class="px-4 py-3 text-slate-400">${account.currency}</td>
<td class="px-4 py-3"><span class="px-2 py-1 rounded-full text-[10px] ${statusClass}">${status}</span></td>
<td class="px-4 py-3">$${account.amount_spent || '0.00'}</td>
<td class="px-4 py-3">
<button onclick="fetchAccountInsights('${account.id}')" class="text-slate-500 hover:text-blue-400 text-xs"> Insights</button>
</td>
</tr>`;
}).join('');
}
// Fetch Campaigns from Meta
async function fetchCampaigns() {
try {
const response = await fetch(`https://graph.facebook.com/v20.0/me/campaigns?fields=id,name,status,objective,daily_budget,spend_cap,insights{spend,reach,impressions,results,ctr,cpc,cpm}&access_token=${state.fbAccessToken}`);
const data = await response.json();
if (data.data && data.data.length > 0) {
updateLiveCampaignsTable(data.data);
updateCampaignsFromMeta(data.data);
}
} catch (error) {
console.error('Error fetching campaigns:', error);
alert('Error fetching campaigns. Make sure you have ads_read permission.');
}
}
// Update Live Campaigns Table
function updateLiveCampaignsTable(campaigns) {
const tbody = document.getElementById('liveCampaignsTable');
if (campaigns.length === 0) {
tbody.innerHTML = '<tr><td class="px-4 py-8 text-center text-slate-600" colspan="7">No campaigns found.</td></tr>';
return;
}
tbody.innerHTML = campaigns.map(camp => {
const insights = camp.insights?.data?.[0] || {};
const spend = insights.spend || 0;
const reach = insights.reach || 0;
const results = insights.results || 0;
const ctr = insights.ctr?.[0] || 0;
const cpr = results > 0 ? (spend / results).toFixed(2) : '0.00';
const status = camp.status === 'ACTIVE' ? 'Active' : 'Paused';
const statusClass = camp.status === 'ACTIVE' ? 'bg-green-500/10 text-green-400' : 'bg-orange-500/10 text-orange-400';
return `
<tr class="hover:bg-slate-800/30">
<td class="px-4 py-3 font-medium text-white">${camp.name}</td>
<td class="px-4 py-3"><span class="px-2 py-1 rounded-full text-[10px] ${statusClass}">${status}</span></td>
<td class="px-4 py-3">$${spend}</td>
<td class="px-4 py-3">${reach.toLocaleString()}</td>
<td class="px-4 py-3">${results}</td>
<td class="px-4 py-3">${(ctr * 100).toFixed(2)}%</td>
<td class="px-4 py-3">$${cpr}</td>
</tr>`;
}).join('');
}
// Update Internal Campaigns from Meta
function updateCampaignsFromMeta(campaigns) {
campaigns.forEach(camp => {
const insights = camp.insights?.data?.[0] || {};
const existing = state.campaigns.find(c => c.id === camp.id);
if (!existing) {
state.campaigns.push({
id: camp.id,
name: camp.name,
objective: camp.objective || 'Unknown',
status: camp.status === 'ACTIVE' ? 'Active' : 'Paused',
budget: camp.daily_budget || 0,
start: new Date().toISOString().split('T')[0],
client: '',
spend: parseFloat(insights.spend) || 0,
reach: parseInt(insights.reach) || 0,
results: parseInt(insights.results) || 0
});
} else {
existing.spend = parseFloat(insights.spend) || 0;
existing.reach = parseInt(insights.reach) || 0;
existing.results = parseInt(insights.results) || 0;
}
});
renderAll();
}
// Fetch Account Insights
async function fetchAccountInsights(accountId) {
try {
const response = await fetch(`https://graph.facebook.com/v20.0/${accountId}/insights?fields=spend,reach,impressions,results,ctr,cpc,cpm&access_token=${state.fbAccessToken}`);
const data = await response.json();
console.log('Account Insights:', data);
alert('Insights fetched! Check console for details.');
} catch (error) {
console.error('Error fetching insights:', error);
}
}
// Disconnect Facebook
function disconnectFacebook() {
state.fbAccessToken = null;
state.fbUser = null;
localStorage.removeItem('fb_access_token');
localStorage.removeItem('fb_token_expiry');
document.getElementById('fbConnectionStatus').textContent = 'Not Connected';
document.getElementById('fbConnectionStatus').className = 'px-3 py-1 rounded-full text-xs font-medium bg-slate-800 text-slate-400';
document.getElementById('connectedUserInfo').classList.add('hidden');
document.getElementById('fbLoginSection').classList.remove('hidden');
document.getElementById('metaApiStatus').textContent = 'Not Connected';
document.getElementById('metaApiStatus').className = 'text-[10px] text-slate-600 ml-auto';
}
// Check Facebook Auth on Load
function checkFacebookAuth() {
const storedToken = localStorage.getItem('fb_access_token');
const storedExpiry = localStorage.getItem('fb_token_expiry');
if (storedToken) {
if (!storedExpiry || Date.now() < parseInt(storedExpiry)) {
state.fbAccessToken = storedToken;
fetchFacebookUser();
} else {
localStorage.removeItem('fb_access_token');
localStorage.removeItem('fb_token_expiry');
}
}
}
// Sync All Accounts
async function syncAllAccounts() {
const spinner = document.getElementById('syncSpinner');
spinner.style.display = 'inline-block';
await fetchAdAccounts();
await fetchCampaigns();
spinner.style.display = 'none';
alert('Sync complete! Data has been updated.');
}
// Refresh Ad Accounts
function refreshAdAccounts() {
if (state.fbAccessToken) {
fetchAdAccounts();
}
}
// Auto-refresh setup
function setupAutoRefresh() {
const interval = parseInt(document.getElementById('autoRefreshInterval')?.value || '0');
if (state.fbAutoRefresh) {
clearInterval(state.fbAutoRefresh);
}
if (interval > 0 && state.fbAccessToken) {
state.fbAutoRefresh = setInterval(() => {
fetchAdAccounts();
fetchCampaigns();
}, interval);
}
}
function handlePortalLogin() {
const cid = document.getElementById('portalClientIdInput').value.trim();
const client = state.clients.find(c => c.id === cid);
if (client) {
document.getElementById('clientPortalLogin').classList.add('hidden');
document.getElementById('clientPortalDashboard').classList.remove('hidden');
loadClientDashboard(client);
} else {
document.getElementById('clientPortalError').classList.remove('hidden');
}
}
function clientLogout() {
document.getElementById('clientPortalDashboard').classList.add('hidden');
document.getElementById('clientPortalLogin').classList.remove('hidden');
document.getElementById('portalClientIdInput').value = '';
document.getElementById('clientPortalError').classList.add('hidden');
}
function logout() {
document.getElementById('authScreen').classList.remove('hidden');
document.getElementById('adminApp').classList.add('hidden');
document.getElementById('clientPortalLogin').classList.add('hidden');
document.getElementById('clientPortalDashboard').classList.add('hidden');
}
function toggleSidebar() { document.getElementById('sidebar').classList.toggle('-translate-x-full'); }
function showSection(sectionId) {
document.querySelectorAll('.section-content').forEach(el => el.classList.add('hidden'));
document.getElementById(sectionId).classList.remove('hidden');
document.querySelectorAll('.sidebar-link').forEach(el => el.classList.remove('active'));
const navItem = document.getElementById('nav-' + sectionId);
if (navItem) navItem.classList.add('active');
if (window.innerWidth < 768) document.getElementById('sidebar').classList.add('-translate-x-full');
}
function openModal(id) {
document.getElementById(id).classList.remove('hidden');
populateDropdowns();
}
function closeModal(id) { document.getElementById(id).classList.add('hidden'); }
function populateDropdowns() {
const cOpts = state.clients.map(c => `<option value="${c.id}">${c.name}</option>`).join('');
const cmOpts = state.campaigns.map(c => `<option value="${c.id}">${c.name}</option>`).join('');
['newCampClient','newAdSetClient','newAdClient','depositClient'].forEach(id => {
const el = document.getElementById(id);
if(el) el.innerHTML = '<option value="">None</option>' + cOpts;
});
['newAdSetCampaign','newAdCampaign'].forEach(id => {
const el = document.getElementById(id);
if(el) el.innerHTML = '<option value="">Select</option>' + cmOpts;
});
}
function saveNewClient() {
const name = document.getElementById('newClientName').value;
const deposit = parseFloat(document.getElementById('newClientDeposit').value) || 0;
const rate = parseFloat(document.getElementById('newClientRate').value) || state.budgetRate;
if (!name) return alert('Client Name is required');
const clientId = 'CLI-' + Math.floor(1000 + Math.random() * 9000);
state.clients.push({
id: clientId, name,
company: document.getElementById('newClientCompany').value,
email: document.getElementById('newClientEmail').value,
phone: document.getElementById('newClientPhone').value,
deposit, rate, usdBudget: (deposit / rate), status: 'Active',
campaigns: [...state.selectedCampaigns]
});
if (deposit > 0) state.deposits.push({ clientId, amount: deposit, rate, method: 'Initial', date: new Date().toISOString().split('T')[0] });
closeModal('addClientModal');
document.getElementById('newClientIdDisplay').textContent = clientId;
openModal('clientSuccessModal');
state.selectedCampaigns = [];
renderAll();
}
function copyClientId() { navigator.clipboard.writeText(document.getElementById('newClientIdDisplay').textContent); alert('Copied!'); }
function saveNewCampaign() {
const name = document.getElementById('newCampName').value;
if (!name) return;
state.campaigns.push({ id: 'CMP-' + Date.now(), name, objective: document.getElementById('newCampObjective').value, status: document.getElementById('newCampStatus').value, budget: document.getElementById('newCampBudget').value, start: document.getElementById('newCampStart').value, client: document.getElementById('newCampClient').value, spend: 0, reach: 0, results: 0 });
closeModal('addCampaignModal'); renderAll();
}
function saveNewAdSet() {
const name = document.getElementById('newAdSetName').value;
if (!name) return;
state.adSets.push({ id: 'ADT-' + Date.now(), name, campaign: document.getElementById('newAdSetCampaign').value, status: 'Active', budget: document.getElementById('newAdSetBudget').value, spend: 0, reach: 0, ctr: '0%', results: 0, client: document.getElementById('newAdSetClient').value });
closeModal('addAdSetModal'); renderAll();
}
function saveNewAd() {
const name = document.getElementById('newAdName').value;
if (!name) return;
state.ads.push({ id: 'ADV-' + Date.now(), name, campaign: document.getElementById('newAdCampaign').value, status: document.getElementById('newAdStatus').value, client: document.getElementById('newAdClient').value, spend: 0, reach: 0, impressions: 0, ctr: '0%', results: 0, costPerResult: 0 });
closeModal('addAdModal'); renderAll();
}
function saveDeposit() {
const clientId = document.getElementById('depositClient').value;
const amount = parseFloat(document.getElementById('depositAmount').value);
const rate = parseFloat(document.getElementById('depositRate').value);
if (!clientId || !amount) return;
const client = state.clients.find(c => c.id === clientId);
if (client) { client.deposit += amount; client.usdBudget += (amount / rate); }
state.deposits.push({ clientId, amount, rate, method: document.getElementById('depositMethod').value, ref: document.getElementById('depositRef').value, date: new Date().toISOString().split('T')[0] });
closeModal('addDepositModal'); renderAll();
}
function renderAll() {
renderClientsTable(); renderCampaignsTable(); renderAdSetsTable(); renderAdsTable(); renderBudgetTable(); renderDashCampaigns(); updateDashboard();
}
function updateDashboard() {
const totalSpend = state.campaigns.reduce((a, c) => a + (parseFloat(c.spend) || 0), 0);
const totalReach = state.campaigns.reduce((a, c) => a + (parseInt(c.reach) || 0), 0);
const totalResults = state.campaigns.reduce((a, c) => a + (parseInt(c.results) || 0), 0);
document.getElementById('dashTotalSpend').textContent = '$' + totalSpend.toFixed(2);
document.getElementById('dashTotalReach').textContent = totalReach.toLocaleString();
document.getElementById('dashTotalResults').textContent = totalResults;
document.getElementById('dashActiveCampaigns').textContent = state.campaigns.filter(c => c.status === 'Active').length;
document.getElementById('chartTotalSpend').textContent = '$' + totalSpend.toFixed(2);
document.getElementById('metricReach').textContent = totalReach.toLocaleString();
document.getElementById('metricResults').textContent = totalResults;
}
function renderClientsTable() {
const tbody = document.getElementById('clientsTable');
document.getElementById('clientsCount').textContent = state.clients.length + ' clients';
if (state.clients.length === 0) { tbody.innerHTML = '<tr><td class="px-4 py-8 text-center text-slate-600" colspan="7">No clients yet.</td></tr>'; return; }
tbody.innerHTML = state.clients.map(c => `<tr class="hover:bg-slate-800/30"><td class="px-4 py-3 font-medium text-white">${c.name}</td><td class="px-4 py-3 text-slate-400">${c.company||'—'}</td><td class="px-4 py-3 text-slate-500 text-xs">${c.email||'—'}</td><td class="px-4 py-3"><span class="bg-green-500/10 text-green-400 px-2 py-1 rounded-full text-[10px]">${c.status}</span></td><td class="px-4 py-3 font-medium text-white">$${(c.usdBudget||0).toFixed(2)}</td><td class="px-4 py-3 font-mono text-[10px] text-blue-400">${c.id}</td><td class="px-4 py-3"><button onclick="deleteClient('${c.id}')" class="text-slate-500 hover:text-red-400">🗑</button></td></tr>`).join('');
}
function renderCampaignsTable() {
const tbody = document.getElementById('campaignsTable');
if (state.campaigns.length === 0) { tbody.innerHTML = '<tr><td class="px-4 py-8 text-center text-slate-600" colspan="8">No campaigns.</td></tr>'; return; }
tbody.innerHTML = state.campaigns.map(c => `<tr class="hover:bg-slate-800/30"><td class="px-4 py-3 font-medium text-white">${c.name}</td><td class="px-4 py-3"><span class="px-2 py-1 rounded-full text-[10px] ${c.status==='Active'?'bg-green-500/10 text-green-400':'bg-orange-500/10 text-orange-400'}">${c.status}</span></td><td class="px-4 py-3 text-slate-400">${c.objective}</td><td class="px-4 py-3">$${c.spend.toFixed(2)}</td><td class="px-4 py-3">${c.reach.toLocaleString()}</td><td class="px-4 py-3">${c.results}</td><td class="px-4 py-3 text-[10px] text-blue-400">${c.client||'—'}</td><td class="px-4 py-3"><button class="text-slate-500 hover:text-red-400">🗑</button></td></tr>`).join('');
}
function renderAdSetsTable() {
const tbody = document.getElementById('adSetsTable');
if (state.adSets.length === 0) { tbody.innerHTML = '<tr><td class="px-4 py-8 text-center text-slate-600" colspan="8">No ad sets.</td></tr>'; return; }
tbody.innerHTML = state.adSets.map(a => `<tr class="hover:bg-slate-800/30"><td class="px-4 py-3 font-medium text-white">${a.name}</td><td class="px-4 py-3 text-slate-400">${state.campaigns.find(c=>c.id===a.campaign)?.name||'—'}</td><td class="px-4 py-3"><span class="px-2 py-1 rounded-full text-[10px] ${a.status==='Active'?'bg-green-500/10 text-green-400':'bg-orange-500/10 text-orange-400'}">${a.status}</span></td><td class="px-4 py-3">$${a.budget}</td><td class="px-4 py-3">$${a.spend.toFixed(2)}</td><td class="px-4 py-3">${a.reach.toLocaleString()}</td><td class="px-4 py-3">${a.ctr}%</td><td class="px-4 py-3">${a.results}</td></tr>`).join('');
}
function renderAdsTable() {
const tbody = document.getElementById('adsTable');
if (state.ads.length === 0) { tbody.innerHTML = '<tr><td class="px-4 py-8 text-center text-slate-600" colspan="9">No ads.</td></tr>'; return; }
tbody.innerHTML = state.ads.map(a => `<tr class="hover:bg-slate-800/30"><td class="px-4 py-3 font-medium text-white">${a.name}</td><td class="px-4 py-3 text-slate-500 text-xs">${a.campaign||'—'}</td><td class="px-4 py-3"><span class="px-2 py-1 rounded-full text-[10px] ${a.status==='Active'?'bg-green-500/10 text-green-400':'bg-orange-500/10 text-orange-400'}">${a.status}</span></td><td class="px-4 py-3">$${a.spend.toFixed(2)}</td><td class="px-4 py-3">${a.reach.toLocaleString()}</td><td class="px-4 py-3">${a.impressions.toLocaleString()}</td><td class="px-4 py-3">${a.ctr}%</td><td class="px-4 py-3">${a.results}</td><td class="px-4 py-3 text-[10px] text-blue-400">${a.client||'—'}</td></tr>`).join('');
}
function renderDashCampaigns() {
const tbody = document.getElementById('dashCampaignsTable');
if (state.campaigns.length === 0) { tbody.innerHTML = '<tr><td class="py-4 pl-2 text-slate-600" colspan="5">No campaigns yet. Add manually.</td></tr>'; return; }
tbody.innerHTML = state.campaigns.slice(0,5).map((c,i) => `<tr class="hover:bg-slate-800/30"><td class="py-3 pl-2 text-slate-500">${i+1}</td><td class="py-3 font-medium text-white">${c.name}</td><td class="py-3 text-slate-400">${c.objective}</td><td class="py-3 text-slate-500">${c.start||'—'}</td><td class="py-3"><span class="px-2 py-1 rounded-full text-[10px] ${c.status==='Active'?'bg-green-500/10 text-green-400':'bg-orange-500/10 text-orange-400'}">${c.status}</span></td></tr>`).join('');
}
function renderBudgetTable() {
const tbody = document.getElementById('budgetTable');
let totalDep = 0, totalSpent = 0, lowCount = 0;
if (state.clients.length === 0) { tbody.innerHTML = '<tr><td class="px-4 py-8 text-center text-slate-600" colspan="8">No clients.</td></tr>'; } else {
tbody.innerHTML = state.clients.map(c => {
totalDep += c.deposit||0;
const spentUSD = state.campaigns.filter(cmp => cmp.client === c.id).reduce((a, cmp) => a + (parseFloat(cmp.spend)||0), 0);
totalSpent += spentUSD;
const spentBDT = spentUSD * c.rate;
const remaining = c.deposit - spentBDT;
const usage = c.deposit > 0 ? (spentBDT/c.deposit)*100 : 0;
const status = remaining < 1000 ? 'Low' : 'OK';
if (status === 'Low') lowCount++;
return `<tr class="hover:bg-slate-800/30"><td class="px-4 py-3 font-medium text-white">${c.name}</td><td class="px-4 py-3">${c.deposit}</td><td class="px-4 py-3 text-slate-500">${c.rate}</td><td class="px-4 py-3">$${(c.deposit/c.rate).toFixed(2)}</td><td class="px-4 py-3 text-red-400">$${spentUSD.toFixed(2)}</td><td class="px-4 py-3 font-medium ${status==='Low'?'text-red-400':'text-green-400'}">${remaining.toFixed(0)}</td><td class="px-4 py-3"><div class="w-full bg-slate-800 rounded-full h-1.5"><div class="bg-blue-500 h-1.5 rounded-full" style="width:${usage}%"></div></div><span class="text-[10px] text-slate-600">${usage.toFixed(0)}%</span></td><td class="px-4 py-3"><span class="px-2 py-1 rounded text-[10px] ${status==='Low'?'bg-red-500/10 text-red-400':'bg-green-500/10 text-green-400'}">${status}</span></td></tr>`;
}).join('');
}
document.getElementById('budgetTotalDeposits').textContent = '৳' + totalDep;
document.getElementById('budgetTotalSpent').textContent = '$' + totalSpent.toFixed(2);
document.getElementById('budgetRemaining').textContent = '' + (totalDep - (totalSpent * state.budgetRate));
document.getElementById('budgetLowCount').textContent = lowCount;
}
function checkPortalClient(cid, fromLogin = false) {
const input = fromLogin ? cid : document.getElementById('portalClientIdInput').value;
const client = state.clients.find(c => c.id === input);
if (client) {
document.getElementById('clientNoData').classList.add('hidden');
document.getElementById('clientDashboard').classList.remove('hidden');
document.getElementById('clientPortalName').textContent = client.name;
loadClientData(client);
if (fromLogin) { document.getElementById('authScreen').classList.add('hidden'); document.getElementById('clientPortal').classList.remove('hidden'); }
} else { document.getElementById('clientPortalError').classList.remove('hidden'); }
}
function loadClientDashboard(client) {
document.getElementById('clientDashboardName').textContent = client.name;
const today = new Date();
const dateStr = today.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
document.getElementById('clientDashboardDate').textContent = `${dateStr} - ${dateStr}`;
const spent = state.campaigns.filter(c => c.client === client.id).reduce((a,c) => a+(parseFloat(c.spend)||0), 0);
const depositUSD = (client.deposit || 0) / client.rate;
const remaining = depositUSD - spent;
document.getElementById('cTotalDeposit').textContent = '$' + depositUSD.toFixed(2);
document.getElementById('cTotalDepositBDT').textContent = '' + client.deposit.toFixed(0);
document.getElementById('cTotalSpend').textContent = '$' + spent.toFixed(2);
document.getElementById('cTotalSpendBDT').textContent = '৳' + (spent * client.rate).toFixed(0);
document.getElementById('cRemaining').textContent = '$' + remaining.toFixed(2);
document.getElementById('cRemainingBDT').textContent = '৳' + (remaining * client.rate).toFixed(0);
const clientAds = state.ads.filter(a => a.client === client.id);
const totalImpressions = clientAds.reduce((a, ad) => a + (parseInt(ad.impressions) || 0), 0);
const totalReach = clientAds.reduce((a, ad) => a + (parseInt(ad.reach) || 0), 0);
const totalResults = clientAds.reduce((a, ad) => a + (parseInt(ad.results) || 0), 0);
const cpr = totalResults > 0 ? (spent / totalResults).toFixed(2) : '0.00';
document.getElementById('cImpressions').textContent = totalImpressions.toLocaleString();
document.getElementById('cReach').textContent = totalReach.toLocaleString();
document.getElementById('cResults').textContent = totalResults;
document.getElementById('cCPR').textContent = '$' + cpr;
document.getElementById('dataSuccessMsg').classList.remove('hidden');
document.getElementById('dataLoadedInfo').textContent = clientAds.length + ' ads with live performance data';
document.getElementById('adsAssignedInfo').textContent = clientAds.length + ' ads assigned to your account';
const tbody = document.getElementById('clientAdsTable');
if (clientAds.length === 0) {
tbody.innerHTML = '<tr><td class="px-4 py-8 text-center text-slate-600" colspan="11">No ad data available.</td></tr>';
} else {
tbody.innerHTML = clientAds.map(ad => {
const resultRate = ad.impressions > 0 ? ((ad.results / ad.impressions) * 100).toFixed(2) : '0.00';
const ctr = ad.impressions > 0 ? ((ad.reach / ad.impressions) * 100).toFixed(2) : '0.00';
return `
<tr class="client-table-row">
<td class="px-4 py-3">
<div class="flex items-center gap-3">
<div class="w-8 h-8 rounded-lg bg-slate-700 flex items-center justify-center text-xs flex-shrink-0">🖼</div>
<div>
<p class="font-medium text-white text-xs">${ad.name}</p>
<p class="text-[10px] text-slate-500">${ad.id}</p>
<span class="preview-btn mt-1 inline-block">Preview</span>
</div>
</div>
</td>
<td class="px-4 py-3"><span class="px-2 py-1 rounded-full text-[10px] ${ad.status==='Active'?'bg-emerald-500/20 text-emerald-400':'bg-orange-500/20 text-orange-400'}">${ad.status}</span></td>
<td class="px-4 py-3">$${ad.budget || '0'}</td>
<td class="px-4 py-3 text-slate-400">${ad.endDate || '—'}</td>
<td class="px-4 py-3 font-medium">$${ad.spend.toFixed(2)}</td>
<td class="px-4 py-3">${ad.impressions.toLocaleString()}</td>
<td class="px-4 py-3">${ad.reach.toLocaleString()}</td>
<td class="px-4 py-3">${ctr}%</td>
<td class="px-4 py-3">${resultRate}%</td>
<td class="px-4 py-3 font-medium text-center">${ad.results}</td>
<td class="px-4 py-3">$${ad.costPerResult || '0.00'}</td>
</tr>`;
}).join('');
}
}
function filterClientData() {
const clientId = document.getElementById('portalClientIdInput').value.trim();
const client = state.clients.find(c => c.id === clientId);
if (client) loadClientDashboard(client);
}
function generateClientLink() { document.getElementById('generatedLinkBox').classList.remove('hidden'); }
function saveSettings() {
state.budgetRate = parseFloat(document.getElementById('exchangeRate').value)||115;
setupAutoRefresh();
alert('Settings saved!');
}
function saveBranding() { const color = document.getElementById('brandColor').value; document.getElementById('brandPreview').style.backgroundColor = color; }
function deleteClient(id) { if(confirm('Delete client?')) { state.clients = state.clients.filter(c=>c.id!==id); renderAll(); } }
let spendChart;
function initCharts() {
const ctx = document.getElementById('spendChart');
if (!ctx) return;
if (spendChart) spendChart.destroy();
spendChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'],
datasets: [
{ label: 'Spend', data: [15, 25, 20, 35, 28, 45, 30], backgroundColor: '#3b82f6', borderRadius: 4, barPercentage: 0.6 },
{ label: 'Results', data: [5, 10, 8, 15, 12, 20, 14], backgroundColor: '#4ade80', borderRadius: 4, barPercentage: 0.6 }
]
},
options: {
responsive: true, maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
x: { grid: { color: 'rgba(51,65,85,0.3)' }, ticks: { color: '#64748b', font: { size: 10 } } },
y: { grid: { color: 'rgba(51,65,85,0.3)' }, ticks: { color: '#64748b', font: { size: 10 } } }
}
}
});
}
function loadDashboard() { renderAll(); }
// Initialize on load
window.addEventListener('load', () => {
handleFacebookResponse();
});
</script>
</body>
</html>