<!-- ===================== Dashboard UI (PerfectPanel Admin API via CF Worker) ===================== -->

<style>

  :root { --bg:#0b1220; --card:#121a2b; --muted:#9aa4b2; --accent:#22c55e; --warn:#f59e0b; --err:#ef4444; --txt:#e5e7eb; --line:#1e293b; }

  .pp-wrap{font-family:Inter,system-ui,Segoe UI,Arial,sans-serif;color:var(--txt)}

  .pp-grid{display:grid;gap:16px}

  .pp-2{grid-template-columns:repeat(2,minmax(0,1fr))}

  .pp-3{grid-template-columns:repeat(3,minmax(0,1fr))}

  .pp-4{grid-template-columns:repeat(4,minmax(0,1fr))}

  .pp-card{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:16px}

  .pp-heading{display:flex;align-items:center;justify-content:space-between;margin:6px 0 12px 0}

  .pp-title{font-weight:700;font-size:16px}

  .pp-sub{font-size:12px;color:var(--muted)}

  .pp-kpi{font-size:28px;font-weight:800}

  .pp-row{display:flex;gap:10px;align-items:center}

  .pp-badge{border:1px solid var(--line);border-radius:20px;padding:4px 8px;font-size:11px;color:var(--muted)}

  .pp-table{width:100%;border-collapse:collapse;font-size:13px}

  .pp-table th,.pp-table td{padding:10px;border-bottom:1px solid var(--line);text-align:left}

  .pp-chip{display:inline-block;padding:4px 8px;border-radius:999px;font-size:11px}

  .pp-chip.ok{background:#052e1a;color:#6ee7b7}

  .pp-chip.warn{background:#2a1f09;color:#f9d76c}

  .pp-chip.err{background:#2a0f12;color:#fca5a5}

  .pp-chip.neutral{background:#111827;color:#9aa4b2}

  .pp-right{margin-left:auto}

  .pp-topbar{display:flex;align-items:center;gap:8px;margin-bottom:12px}

  .pp-select{background:var(--card);color:var(--txt);border:1px solid var(--line);border-radius:8px;padding:8px}

  .pp-btn{background:#1f2937;border:1px solid var(--line);color:var(--txt);padding:8px 10px;border-radius:8px;cursor:pointer}

  .pp-btn:hover{opacity:.9}

  .pp-notice{position:fixed;right:16px;top:16px;display:flex;flex-direction:column;gap:8px;z-index:99999}

  .pp-toast{background:#0b1220;border:1px solid var(--line);border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.35);padding:12px 14px;min-width:280px}

  .pp-toast .hdr{display:flex;align-items:center;justify-content:space-between;font-weight:700;margin-bottom:6px}

  .pp-toast .txt{font-size:13px;color:var(--muted)}

  .pp-nbar{position:fixed;right:16px;top:92px;width:320px;max-height:60vh;overflow:auto;border:1px solid var(--line);background:var(--card);border-radius:12px;padding:10px;display:none;z-index:99990}

  .pp-nbar h4{margin:6px 0 10px 0}

  .pp-nitem{border-bottom:1px solid var(--line);padding:8px 4px}

  .pp-nitem:last-child{border-bottom:none}

  @media (max-width:1024px){.pp-4{grid-template-columns:repeat(2,minmax(0,1fr))}}

  @media (max-width:640px){.pp-2,.pp-3,.pp-4{grid-template-columns:1fr}}

</style>


<div class="pp-wrap">

  <!-- Top controls -->

  <div class="pp-topbar">

    <div class="pp-title">Dashboard</div>

    <div class="pp-right pp-row">

      <!-- Notification center -->

      <button id="pp-open-nbar" class="pp-btn" title="Notifications">Notifications</button>

      <!-- Language switcher -->

      <select id="pp-lang" class="pp-select" title="Language">

        <option value="">Language</option>

        <option value="en">English (Default)</option>

        <option value="ar">Arabic</option>

        <option value="bn">Bengali</option>

        <option value="de">German</option>

        <option value="es">Spanish</option>

        <option value="fr">French</option>

        <option value="hi">Hindi</option>

        <option value="id">Indonesian</option>

        <option value="it">Italian</option>

        <option value="ja">Japanese</option>

        <option value="ko">Korean</option>

        <option value="ms">Malay</option>

        <option value="nl">Dutch</option>

        <option value="pt">Portuguese</option>

        <option value="ru">Russian</option>

        <option value="th">Thai</option>

        <option value="tr">Turkish</option>

        <option value="uk">Ukrainian</option>

        <option value="ur">Urdu</option>

        <option value="vi">Vietnamese</option>

      </select>

      <button id="pp-reset-en" class="pp-btn">Restore English</button>

    </div>

  </div>


  <!-- KPI cards -->

  <div class="pp-grid pp-4">

    <div class="pp-card">

      <div class="pp-heading"><div class="pp-title">Orders Today</div><div class="pp-badge" id="kpi-orders-badge">loading…</div></div>

      <div class="pp-kpi" id="kpi-orders">–</div>

      <div class="pp-sub">New orders created since 00:00 (panel time)</div>

    </div>

    <div class="pp-card">

      <div class="pp-heading"><div class="pp-title">Payments Today</div><div class="pp-badge" id="kpi-payments-badge">loading…</div></div>

      <div class="pp-kpi" id="kpi-payments">–</div>

      <div class="pp-sub">Count of payments created today</div>

    </div>

    <div class="pp-card">

      <div class="pp-heading"><div class="pp-title">New Users Today</div><div class="pp-badge" id="kpi-users-badge">loading…</div></div>

      <div class="pp-kpi" id="kpi-users">–</div>

      <div class="pp-sub">Registered users since midnight</div>

    </div>

    <div class="pp-card">

      <div class="pp-heading"><div class="pp-title">Open Tickets Today</div><div class="pp-badge" id="kpi-tickets-badge">loading…</div></div>

      <div class="pp-kpi" id="kpi-tickets">–</div>

      <div class="pp-sub">Tickets created today (all statuses)</div>

    </div>

  </div>


  <!-- Latest lists -->

  <div class="pp-grid pp-2" style="margin-top:16px">

    <div class="pp-card">

      <div class="pp-heading"><div class="pp-title">Latest Orders</div><button id="reload-orders" class="pp-btn">Reload</button></div>

      <table class="pp-table" id="tbl-orders">

        <thead><tr><th>ID</th><th>User</th><th>Service</th><th>Status</th><th>Created</th></tr></thead>

        <tbody></tbody>

      </table>

    </div>

    <div class="pp-card">

      <div class="pp-heading"><div class="pp-title">Latest Payments</div><button id="reload-payments" class="pp-btn">Reload</button></div>

      <table class="pp-table" id="tbl-payments">

        <thead><tr><th>ID</th><th>User</th><th>Method</th><th>Amount</th><th>Status</th></tr></thead>

        <tbody></tbody>

      </table>

    </div>

  </div>

</div>


<!-- Toast container + Notification bar -->

<div class="pp-notice" id="pp-notice"></div>

<div class="pp-nbar" id="pp-nbar">

  <h4>Notifications</h4>

  <div id="pp-nlist"></div>

  <div style="margin-top:8px;display:flex;gap:8px">

    <button id="pp-clear-nbar" class="pp-btn">Clear</button>

    <button id="pp-close-nbar" class="pp-btn">Close</button>

  </div>

</div>


<!-- Google Translate (hidden) -->

<div id="google_translate_element" style="height:0;overflow:hidden"></div>

<script>

(function addGTranslate(){

  const s=document.createElement('script');

  s.type='text/javascript';

  s.src='//translate.google.com/translate_a/element.js?cb=__gtInit';

  document.head.appendChild(s);

  window.__gtInit=function(){

    new google.translate.TranslateElement({

      pageLanguage:'en',

      includedLanguages:'en,ar,bn,de,es,fr,hi,id,it,ja,ko,ms,nl,pt,ru,th,tr,uk,ur,vi',

      autoDisplay:false

    },'google_translate_element');

  }

})();

</script>


<script>

/* ====================== CONFIG ====================== */

const API_BASE = 'https://panelapi-proxy.panelempire.workers.dev/api'; // your Worker

const PAGE_LIMIT = 50; // list size for latest tables


/* ====================== UTIL ====================== */

const $ = (sel, el=document)=>el.querySelector(sel);

const $$ = (sel, el=document)=>el.querySelectorAll(sel);

const fmt = (d)=>new Date(d.replace(' ', 'T')+'Z').toLocaleString();


/* Toasts + Notification center */

const Notice = (() => {

  const box = $('#pp-notice');

  const bar = $('#pp-nbar');

  const list = $('#pp-nlist');

  const KEY='pp_nbar_items';

  let items = JSON.parse(localStorage.getItem(KEY)||'[]');


  function renderBar(){

    list.innerHTML = items.map(i => `

      <div class="pp-nitem">

        <div style="font-weight:600">${i.title}</div>

        <div class="pp-sub">${i.text}</div>

      </div>`).join('') || '<div class="pp-sub">No notifications</div>';

  }

  function addToBar(title, text){

    items.unshift({title,text,ts:Date.now()});

    items = items.slice(0,50);

    localStorage.setItem(KEY, JSON.stringify(items));

    renderBar();

  }

  function toast(title, text, ttl=3500){

    const t = document.createElement('div');

    t.className='pp-toast';

    t.innerHTML = `<div class="hdr"><div>${title}</div><button class="pp-btn" style="padding:2px 8px">×</button></div>

                   <div class="txt">${text}</div>`;

    box.appendChild(t);

    addToBar(title, text);

    const closer = t.querySelector('button');

    const close = ()=>t.remove();

    closer.onclick = close;

    setTimeout(close, ttl);

  }

  renderBar();

  return { toast, open(){bar.style.display='block'}, close(){bar.style.display='none'}, clear(){items=[];localStorage.setItem(KEY,'[]');renderBar()} };

})();


/* Language switch (Google Translate) */

(function(){

  const sel = $('#pp-lang');

  const reset = $('#pp-reset-en');

  sel.addEventListener('change', ()=>{

    const lang = sel.value;

    // mimic clicks on Google widget

    const combo = document.querySelector('.goog-te-combo');

    if (combo) { combo.value = lang || 'en'; combo.dispatchEvent(new Event('change')); }

    Notice.toast('Language', lang ? 'Language changed.' : 'Language unchanged.');

  });

  reset.addEventListener('click', ()=>{

    const combo = document.querySelector('.goog-te-combo');

    if (combo) { combo.value = 'en'; combo.dispatchEvent(new Event('change')); }

    sel.value = '';

    Notice.toast('Language', 'Restored to English.');

  });

})();


/* ====================== API WRAPPER ====================== */

async function call(endpoint, params={}){

  const url = new URL(API_BASE + endpoint);

  Object.entries(params).forEach(([k,v]) => url.searchParams.set(k, v));

  const res = await fetch(url, { credentials:'omit' });

  if (!res.ok) throw new Error(`HTTP ${res.status}`);

  return res.json();

}


/* ====================== DASHBOARD ====================== */

function statusChip(s){

  s = (s||'').toLowerCase();

  const map = { completed:'ok', processing:'ok', in_progress:'ok', pending:'neutral', canceled:'err', partial:'warn', error:'err', fail:'err' };

  const cls = map[s] || 'neutral';

  const lbl = s.replace('_',' ') || 'unknown';

  return `<span class="pp-chip ${cls}">${lbl}</span>`;

}


async function loadKPIs(){

  const start = new Date(); start.setHours(0,0,0,0);

  const from = Math.floor(start.getTime()/1000);


  // we only need counts; limit high enough for typical daily volume

  const [orders, payments, users, tickets] = await Promise.all([

    call('/orders', { created_from: from, limit: 1000, sort: 'date-desc' }),

    call('/payments', { created_from: from, limit: 1000, sort: 'created-at-desc' }),

    call('/users', { created_from: from, limit: 1000, sort: 'created-at-desc' }),

    call('/tickets', { created_from: from, limit: 1000, sort: 'created-at-desc' }),

  ]);


  const k = (sel, val, badge='Ready') => { $(sel).textContent = val; $(sel+'-badge')?.textContent = badge; };


  k('#kpi-orders', orders?.data?.list?.length ?? 0);

  k('#kpi-payments', payments?.data?.list?.length ?? 0);

  k('#kpi-users', users?.data?.list?.length ?? 0);

  k('#kpi-tickets', tickets?.data?.list?.length ?? 0);


  Notice.toast('Welcome!', 'Your dashboard is ready.');

}


async function loadOrders(){

  const data = await call('/orders', { limit: PAGE_LIMIT, sort: 'date-desc' });

  const rows = (data?.data?.list ?? []).map(o => `

    <tr>

      <td>${o.id}</td>

      <td>${o.user||''}</td>

      <td>${o.service_name||''}</td>

      <td>${statusChip(o.status)}</td>

      <td>${o.created ? fmt(o.created) : ''}</td>

    </tr>

  `).join('');

  $('#tbl-orders tbody').innerHTML = rows || `<tr><td colspan="5" class="pp-sub">No orders found.</td></tr>`;

}


async function loadPayments(){

  const data = await call('/payments', { limit: PAGE_LIMIT, sort: 'created-at-desc' });

  const rows = (data?.data?.list ?? []).map(p => `

    <tr>

      <td>${p.payment_id}</td>

      <td>${p.user?.username || ''}</td>

      <td>${p.method||''}</td>

      <td>${p.amount?.formatted || ''}</td>

      <td>${statusChip(p.status)}</td>

    </tr>

  `).join('');

  $('#tbl-payments tbody').innerHTML = rows || `<tr><td colspan="5" class="pp-sub">No payments found.</td></tr>`;

}


/* ====================== INIT ====================== */

(async () => {

  try{

    // One-time “loading” toast

    Notice.toast('Loading', 'Fetching data…', 1800);


    await Promise.all([loadKPIs(), loadOrders(), loadPayments()]);

  }catch(e){

    console.error(e);

    Notice.toast('Error', 'Failed to load dashboard.');

  }


  // Controls

  $('#reload-orders').onclick = loadOrders;

  $('#reload-payments').onclick = loadPayments;

  $('#pp-open-nbar').onclick = ()=>Notice.open();

  $('#pp-close-nbar').onclick = ()=>Notice.close();

  $('#pp-clear-nbar').onclick = ()=>Notice.clear();

})();

</script>

<!-- ===================== /end Dashboard UI ===================== -->


এই ডিজাইনে কোথায় কোন কালার ইউজ হয়েছে— গ্লোবাল/ব্যাকগ্রাউন্ড: body.dark সক্রিয়। বডি ব্যাকগ্রাউন্ড গ্রেডিয়েন্ট slate-900 → purple-900/20 → slate-900, বেস টেক্সট slate-100। ব্র্যান্ড/অ্যাকসেন্ট প্যালেট: জুড়ে জুড়ে purple ↔ cyan গ্রেডিয়েন্ট (বাটন/হাইলাইটে)। কাস্টম প্যালেটেও primary (উদাহরণ: #18c7e6) ও secondary (উদাহরণ: #a63cff) ডিফাইন করা আছে। সাইডবার: ব্যাকগ্রাউন্ড slate-900/95, বর্ডার slate-700/50। অ্যাক্টিভ আইটেমে purple-600/20 → cyan-600/20 গ্রেডিয়েন্ট + purple-500/30 বর্ডার; হোভার হলে slate-800/50। হেডার/টপবার: slate-900/80 ব্যাকড্রপ + slate-700/50 বর্ডার। টপবারের ছোট বাটনগুলোতে slate-800/50 ব্যাকগ্রাউন্ড + slate-700 বর্ডার; নোটিফিকেশন ব্যাজ purple → pink গ্রেডিয়েন্ট; প্রোফাইল অ্যাভাটার purple → cyan। ইনপুট/সার্চ: slate-800/50 ব্যাকগ্রাউন্ড, slate-700 বর্ডার, টেক্সট slate-200, প্লেসহোল্ডার slate-400; ফোকাসে ring cyan-500/50 + border cyan-500। কার্ডস/বক্স: সব কার্ডে slate-900/50 ব্যাকগ্রাউন্ড + slate-700/50 বর্ডার। মেট্রিক আইকন টাইলসে থিমেটিক গ্রেডিয়েন্ট: অর্ডার: blue → cyan, Completed: green → emerald, Pending/Activity: yellow → orange, Spent/Wallet: purple → pink। প্রাইমারি CTA বাটন: purple-600 → cyan-500 গ্রেডিয়েন্ট, সাদা টেক্সট। সেকেন্ডারি বাটন: slate-800/50 + slate-700 বর্ডার। অর্ডার টোটাল/হাইলাইট প্যানেল: purple-600/20 → cyan-600/20 ব্যাকগ্রাউন্ড, purple-500/30 বর্ডার। স্ট্যাটাস ব্যাজ: Completed = green-600/20 + green-400, Processing = blue-600/20 + blue-400, Pending = yellow-600/20 + yellow-400। ডান পাশের ইনফো/রিওয়ার্ডস: স্ট্যাটাস আইকন yellow → orange, রিওয়ার্ডস আইকন purple → pink, প্রোগ্রেস বার purple → cyan। প্ল্যাটফর্ম সিলেক্টর: সিলেক্টেড বাটন purple-600/20 → cyan-600/20 + purple-500/50 বর্ডার; আনসিলেক্টেড slate-800/30 + slate-700/50। চার্ট (Analytics): Spend = purple → pink ফিল, Orders = blue → cyan ফিল, লাইন সিরিজ সাদা; টিকস slate-300, গ্রিড slate-700 (স্বচ্ছতা সহ)।