/* SISTEM KEWANGAN ALFA — Frontend (React UMD + Babel standalone) */
const { useState, useEffect, useMemo } = React;

// ---------- IKON (SVG sebaris, gantian lucide-react) ----------
const mkIcon = (paths) => ({ size = 20, className = '' }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
    strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}
    dangerouslySetInnerHTML={{ __html: paths }} />
);
const Users = mkIcon('<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>');
const Wallet = mkIcon('<path d="M21 12V7H5a2 2 0 0 1 0-4h14v4"/><path d="M3 5v14a2 2 0 0 0 2 2h16v-5"/><path d="M18 12a2 2 0 0 0 0 4h4v-4Z"/>');
const Receipt = mkIcon('<path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1Z"/><path d="M16 8h-6a2 2 0 1 0 0 4h4a2 2 0 1 1 0 4H8"/><path d="M12 17.5v-11"/>');
const FileText = mkIcon('<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/>');
const Bell = mkIcon('<path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/>');
const ClipboardList = mkIcon('<rect width="8" height="4" x="8" y="2" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M12 11h4"/><path d="M12 16h4"/><path d="M8 11h.01"/><path d="M8 16h.01"/>');
const LogOut = mkIcon('<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" x2="9" y1="12" y2="12"/>');
const CheckCircle = mkIcon('<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/>');
const Plus = mkIcon('<path d="M5 12h14"/><path d="M12 5v14"/>');
const Upload = mkIcon('<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" x2="12" y1="3" y2="15"/>');
const XCircle = mkIcon('<circle cx="12" cy="12" r="10"/><path d="m15 9-6 6"/><path d="m9 9 6 6"/>');
const ArrowRight = mkIcon('<path d="M5 12h14"/><path d="m12 5 7 7-7 7"/>');
const Menu = mkIcon('<line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="18" y2="18"/>');
const X = mkIcon('<path d="M18 6 6 18"/><path d="m6 6 12 12"/>');
const LayoutDashboard = mkIcon('<rect width="7" height="9" x="3" y="3" rx="1"/><rect width="7" height="5" x="14" y="3" rx="1"/><rect width="7" height="9" x="14" y="12" rx="1"/><rect width="7" height="5" x="3" y="16" rx="1"/>');
const Edit = mkIcon('<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.375 2.625a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4Z"/>');
const UserPlus = mkIcon('<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><line x1="19" x2="19" y1="8" y2="14"/><line x1="22" x2="16" y1="11" y2="11"/>');
const AlertCircle = mkIcon('<circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12" y1="16" y2="16"/>');
const Printer = mkIcon('<polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><rect width="12" height="8" x="6" y="14"/>');
const Lock = mkIcon('<rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>');
const Download = mkIcon('<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/>');

// ---------- PEMALAR ----------
const ROLES = { ADMIN: 'admin', FINANCE: 'finance', PURCHASING: 'purchasing' };
const LOCATIONS = ['B1', 'B2', 'SRA', 'HQ', 'Lain-lain'];
const BUDGET_STATUS = {
  PENDING_FINANCE: 'Menunggu Kelulusan Kewangan',
  REJECTED_BY_FINANCE: 'Ditolak Kewangan',
  PENDING_ADMIN: 'Menunggu Kelulusan Pengurusan',
  APPROVED_BY_ADMIN: 'Diluluskan Pengurusan',
  REJECTED_BY_ADMIN: 'Ditolak Pengurusan',
  RECEIVED: 'Diterima Kewangan',
  ASSIGNED: 'Diagih kepada Pembelian',
  CLOSED: 'Selesai'
};
const EXPENSE_STATUS = { PENDING: 'Menunggu Kelulusan', APPROVED: 'Diluluskan', REJECTED: 'Ditolak' };
const roleLabel = (r) => r === 'admin' ? 'Pengurusan' : r === 'finance' ? 'Kewangan' : 'Pembelian';
const fmt = (n) => parseFloat(n || 0).toFixed(2);

// ---------- PELAYAN DEMO (fallback bila API tiada — cth. pratonton) ----------
const DemoServer = {
  seq: 100, me: null,
  users: [
    { id: 1, name: 'Pengurus (Pentadbir)', role: 'admin', username: 'pengurus', email: null, active: 1 },
    { id: 2, name: 'Ahmad (Kewangan)', role: 'finance', username: 'ahmad', email: null, active: 1 },
    { id: 3, name: 'Siti (Pembelian)', role: 'purchasing', username: 'siti', email: null, active: 1 },
    { id: 4, name: 'Raju (Pembelian)', role: 'purchasing', username: 'raju', email: null, active: 1 },
  ],
  budgets: [], notifications: [], audit: [],
  notify(target, message) { this.notifications.push({ id: this.seq++, target: String(target), message, date: new Date().toISOString(), read: false }); },
  logAudit(action, entity, entityId, details) { const u = this.me; this.audit.push({ id: this.seq++, user: u ? u.name : null, role: u ? u.role : null, action, entity, entityId, details: details || '', date: new Date().toISOString() }); },
  img(f) { if (!f) return null; const u = URL.createObjectURL(f); return { url: u, view: u, name: f.name }; },
  err(m) { const e = new Error(m); throw e; },
  today() { return new Date().toISOString().split('T')[0]; },
  call(action, p = {}, files = null) {
    const me = this.me;
    const need = () => { if (!me) { const e = new Error('Sesi tamat. Sila log masuk semula.'); e.status = 401; throw e; } };
    const requireRole = (roles) => { need(); if (!roles.includes(me.role)) { const e = new Error('Anda tiada kebenaran untuk tindakan ini.'); e.status = 403; throw e; } };
    switch (action) {
      case 'ping': return { ok: true };
      case 'login': {
        const u = this.users.find(x => x.username === (p.username || '').toLowerCase() && x.active);
        if (!u || !(p.password || '').length) this.err('Nama pengguna atau kata laluan salah. (Demo: pengurus / ahmad / siti / raju — sebarang kata laluan)');
        this.me = u; return { ok: true };
      }
      case 'logout': this.me = null; return { ok: true };
      case 'state': {
        need();
        return JSON.parse(JSON.stringify({
          ok: true, me, users: this.users, budgets: this.budgets,
          audit: (me.role === 'admin' || me.role === 'finance') ? this.audit.slice().reverse() : [],
          notifications: this.notifications.filter(n => n.target === String(me.id) || n.target === me.role).slice().reverse()
        }));
      }
      case 'create_budget': {
        requireRole(['finance','purchasing']);
        const amt = parseFloat(p.amount);
        this.budgets.unshift({
          id: this.seq++, description: p.description, location: p.location, amount: amt, balance: amt,
          status: me.role === 'purchasing' ? BUDGET_STATUS.PENDING_FINANCE : BUDGET_STATUS.PENDING_ADMIN,
          dueDate: p.dueDate, notes: p.notes, requestedBy: me.id, date: this.today(), expenses: [], assignments: []
        });
        this.notify(me.role === 'purchasing' ? 'finance' : 'admin', `Permohonan belanjawan baru: RM ${fmt(amt)}`);
        return { ok: true };
      }
      case 'finance_review': case 'admin_review': {
        requireRole(action === 'finance_review' ? ['finance'] : ['admin']);
        if (!['approve','reject'].includes(p.decision)) this.err('Keputusan tidak sah.');
        if (p.decision === 'reject' && (p.reason || '').trim().length < 5) this.err('Sebab penolakan diwajibkan.');
        const b = this.budgets.find(x => x.id === p.id); if (!b) this.err('Rekod tidak dijumpai.');
        if (p.decision === 'approve') {
          const amt = p.amount !== undefined && p.amount !== '' ? parseFloat(p.amount) : b.amount;
          b.amount = amt; b.balance = amt;
          b.status = action === 'finance_review' ? BUDGET_STATUS.PENDING_ADMIN : BUDGET_STATUS.APPROVED_BY_ADMIN;
          this.logAudit(action === 'finance_review' ? 'finance_review_approve' : 'admin_review_approve', 'budget', b.id, `amount=${fmt(amt)}`);
          this.notify(action === 'finance_review' ? 'admin' : 'finance', `Permohonan belanjawan (Ruj: ${b.id}) diproses. Jumlah: RM ${fmt(amt)}`);
        } else {
          b.status = action === 'finance_review' ? BUDGET_STATUS.REJECTED_BY_FINANCE : BUDGET_STATUS.REJECTED_BY_ADMIN;
          this.logAudit(action === 'finance_review' ? 'finance_review_reject' : 'admin_review_reject', 'budget', b.id, `reason=${(p.reason || '').trim()}`);
          this.notify(action === 'finance_review' ? String(b.requestedBy) : 'finance', `Permohonan belanjawan (Ruj: ${b.id}) telah DITOLAK. Jumlah: RM ${fmt(b.amount)}`);
        }
        return { ok: true };
      }
      case 'receive_budget': {
        requireRole(['finance']);
        const b = this.budgets.find(x => x.id === p.id);
        if (b) { b.status = BUDGET_STATUS.RECEIVED; this.notify('admin', `Kewangan telah menerima dana (Ruj: ${b.id}). Jumlah: RM ${fmt(b.amount)}`); }
        return { ok: true };
      }
      case 'assign_budget': {
        requireRole(['finance']);
        const b = this.budgets.find(x => x.id === parseInt(p.budgetId));
        const amt = parseFloat(p.amount);
        if (!b || amt <= 0 || amt > b.balance) this.err('Jumlah agihan tidak sah atau melebihi baki yang ada!');
        if (!files || !files.transfer) this.err('Sila muat naik resit pindahan bank!');
        b.assignments.push({ id: this.seq++, staffId: parseInt(p.staffId), amount: amt, balance: amt, transferReceipt: this.img(files.transfer), expenses: [] });
        b.balance -= amt; b.status = BUDGET_STATUS.ASSIGNED;
        this.notify(String(p.staffId), `Anda telah menerima agihan bajet baru (RM ${fmt(amt)}) daripada Kewangan (Ruj: ${b.id}).`);
        return { ok: true };
      }
      case 'add_expense': {
        requireRole(['finance','purchasing']);
        const b = this.budgets.find(x => x.id === parseInt(p.budgetId)); if (!b) this.err('Belanjawan tidak dijumpai.');
        const amt = parseFloat(p.amount);
        const images = {};
        ['resit1','resit2','resit3','resit4','barang1','barang2','barang3','barang4'].forEach(k => { if (files && files[k]) images[k] = this.img(files[k]); });
        if (!images.resit1) this.err('Muat Naik Resit 1 adalah diwajibkan!');
        const exp = { id: this.seq++, date: this.today(), amount: amt, description: p.description, images, status: EXPENSE_STATUS.PENDING, created_by: me.id };
        if (p.assignmentId) {
          const a = b.assignments.find(x => x.id === parseInt(p.assignmentId)); if (!a) this.err('Agihan tidak dijumpai.');
          if (amt > a.balance) this.err('Jumlah perbelanjaan melebihi baki dana!');
          a.expenses.unshift(exp);
        } else {
          if (amt > b.balance) this.err('Jumlah perbelanjaan melebihi baki dana!');
          b.expenses.unshift(exp);
        }
        this.notify('finance', `Perbelanjaan baru menunggu kelulusan. Jumlah: RM ${fmt(amt)}`);
        this.notify('admin', `Perbelanjaan baru dikemaskini oleh ${me.name}. Jumlah: RM ${fmt(amt)}`);
        return { ok: true };
      }
      case 'expense_review': {
        requireRole(['finance']);
        if (!['approve','reject'].includes(p.decision)) this.err('Keputusan tidak sah.');
        if (p.decision === 'reject' && (p.reason || '').trim().length < 5) this.err('Sebab penolakan diwajibkan.');
        for (const b of this.budgets) {
          const pools = [{ list: b.expenses, holder: b }, ...b.assignments.map(a => ({ list: a.expenses, holder: a }))];
          for (const { list, holder } of pools) {
            const e = list.find(x => x.id === p.expenseId);
            if (e) {
              if (e.status !== EXPENSE_STATUS.PENDING) this.err('Rekod perbelanjaan tidak sah atau telah diproses.');
              if (p.decision === 'approve') {
                if (holder.balance < e.amount) this.err('Baki dana tidak mencukupi untuk meluluskan perbelanjaan ini.');
                e.status = EXPENSE_STATUS.APPROVED; holder.balance -= e.amount;
                this.logAudit('expense_approve', 'expense', e.id, `amount=${fmt(e.amount)}`);
              } else { e.status = EXPENSE_STATUS.REJECTED; this.logAudit('expense_reject', 'expense', e.id, `reason=${(p.reason || '').trim()}`); }
              this.notify(String(e.created_by), `Perbelanjaan (RM ${fmt(e.amount)}) telah ${p.decision === 'approve' ? 'diluluskan' : 'DITOLAK'}.`);
              return { ok: true };
            }
          }
        }
        this.err('Rekod tidak dijumpai.');
      }
      case 'edit_budget': {
        requireRole(['admin','finance']);
        const b = this.budgets.find(x => x.id === p.id); if (!b) this.err('Rekod tidak dijumpai.');
        const amt = parseFloat(p.amount); const diff = amt - b.amount;
        b.description = p.description; b.location = p.location; b.amount = amt; b.balance += diff;
        this.notify('admin', `Rekod belanjawan (Ruj: ${b.id}) telah dikemaskini. Jumlah: RM ${fmt(amt)}`);
        return { ok: true };
      }
      case 'edit_expense': {
        requireRole(['admin','finance']);
        for (const b of this.budgets) {
          const pools = [{ list: b.expenses, holder: b }, ...b.assignments.map(a => ({ list: a.expenses, holder: a }))];
          for (const { list, holder } of pools) {
            const e = list.find(x => x.id === p.expenseId);
            if (e) {
              const amt = parseFloat(p.amount);
              if (e.status === EXPENSE_STATUS.APPROVED) holder.balance -= (amt - e.amount);
              e.description = p.description; e.amount = amt;
              return { ok: true };
            }
          }
        }
        this.err('Rekod tidak dijumpai.');
      }
      case 'save_user': {
        requireRole(['admin','finance']);
        if (p.id) {
          const u = this.users.find(x => x.id === p.id); if (!u) this.err('Pengguna tidak dijumpai.');
          u.name = p.name; u.role = p.role; u.username = p.username; u.email = p.email || null;
        } else {
          if (!p.password || p.password.length < 8) this.err('Kata laluan mestilah sekurang-kurangnya 8 aksara.');
          this.users.push({ id: this.seq++, name: p.name, role: p.role, username: p.username, email: p.email || null, active: 1 });
        }
        return { ok: true };
      }
      case 'delete_user': {
        requireRole(['admin','finance']);
        const u = this.users.find(x => x.id === p.id); if (u) u.active = 0;
        return { ok: true };
      }
      case 'change_password': {
        need();
        if (!p.new || p.new.length < 8) this.err('Kata laluan baru mestilah sekurang-kurangnya 8 aksara.');
        if (!(p.old || '').length) this.err('Kata laluan semasa salah. (Nota: mod demo tidak menyimpan kata laluan sebenar.)');
        return { ok: true };
      }
      case 'mark_read': {
        need();
        this.notifications.forEach(n => { if (n.target === String(me.id) || n.target === me.role) n.read = true; });
        return { ok: true };
      }
      default: this.err('Tindakan tidak dikenali.');
    }
  }
};

// ---------- KLIEN API ----------
const Api = {
  base: 'api/api.php', csrf: null, demo: false,
  async request(action, payload, files) {
    if (this.demo) return DemoServer.call(action, payload || {}, files || null);
    const opts = { method: 'POST', headers: {}, credentials: 'same-origin' };
    if (this.csrf) opts.headers['X-CSRF-Token'] = this.csrf;
    if (files) {
      const fd = new FormData();
      Object.entries(payload || {}).forEach(([k, v]) => fd.append(k, v == null ? '' : v));
      Object.entries(files).forEach(([k, f]) => { if (f) fd.append(k, f); });
      opts.body = fd;
    } else if (payload) {
      opts.headers['Content-Type'] = 'application/json';
      opts.body = JSON.stringify(payload);
    }
    const r = await fetch(this.base + '?action=' + action, opts);
    const j = await r.json().catch(() => ({ ok: false, error: 'Ralat pelayan. Cuba sebentar lagi.' }));
    if (!j.ok) { const e = new Error(j.error || 'Ralat tidak diketahui.'); e.status = r.status; throw e; }
    if (j.csrf) this.csrf = j.csrf;
    return j;
  }
};
async function detectServer() {
  try {
    const c = new AbortController(); setTimeout(() => c.abort(), 4000);
    const r = await fetch('api/api.php?action=ping', { signal: c.signal, credentials: 'same-origin' });
    const j = await r.json();
    return j && j.server === true;
  } catch (e) { return false; }
}

// ---------- APLIKASI UTAMA ----------
function App() {
  const [phase, setPhase] = useState('boot');
  const [demo, setDemo] = useState(false);
  const [me, setMe] = useState(null);
  const [users, setUsers] = useState([]);
  const [budgets, setBudgets] = useState([]);
  const [notifications, setNotifications] = useState([]);
  const [audit, setAudit] = useState([]);
  const [activeTab, setActiveTab] = useState('dashboard');
  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
  const [busy, setBusy] = useState(false);
  const [toast, setToast] = useState(null);
  const [showPassModal, setShowPassModal] = useState(false);

  const refresh = async () => {
    const j = await Api.request('state');
    setMe(j.me); setUsers(j.users); setBudgets(j.budgets); setNotifications(j.notifications); setAudit(j.audit || []);
  };

  useEffect(() => { (async () => {
    const server = await detectServer();
    Api.demo = !server; setDemo(!server);
    try { await refresh(); setPhase('app'); } catch (e) { setPhase('login'); }
  })(); }, []);

  useEffect(() => {
    if (phase !== 'app') return;
    const t = setInterval(() => refresh().catch(() => {}), 60000);
    return () => clearInterval(t);
  }, [phase]);

  useEffect(() => { if (!toast) return; const t = setTimeout(() => setToast(null), 6000); return () => clearTimeout(t); }, [toast]);

  const act = async (action, payload, files) => {
    setBusy(true);
    try { await Api.request(action, payload, files); await refresh(); return true; }
    catch (e) { setToast(e.message); if (e.status === 401) { setPhase('login'); setMe(null); } return false; }
    finally { setBusy(false); }
  };

  const handleLogin = async (username, password) => {
    setBusy(true);
    try { await Api.request('login', { username, password }); await refresh(); setActiveTab('dashboard'); setPhase('app'); return null; }
    catch (e) { return e.message; }
    finally { setBusy(false); }
  };
  const handleLogout = async () => {
    try { await Api.request('logout'); } catch (e) {}
    Api.csrf = null; setMe(null); setPhase('login'); setActiveTab('dashboard');
  };

  if (phase === 'boot') return (
    <div className="min-h-screen flex items-center justify-center text-blue-900">
      <div className="text-center"><div className="text-3xl font-extrabold tracking-widest">ALFA</div><p className="text-sm text-gray-500 mt-2">Menyambung ke pelayan…</p></div>
    </div>
  );

  if (phase === 'login' || !me) return (
    <React.Fragment>
      {demo && <DemoBanner />}
      <LoginView onLogin={handleLogin} busy={busy} demo={demo} />
    </React.Fragment>
  );

  const unread = notifications.filter(n => !n.read).length;

  return (
    <div className="min-h-screen bg-gray-50 flex flex-col md:flex-row font-sans">
      {demo && <DemoBanner />}
      {busy && <BusyOverlay />}
      {toast && (
        <div className="fixed bottom-4 left-4 right-4 md:left-auto md:w-96 bg-red-600 text-white px-4 py-3 rounded-xl shadow-lg z-[70] flex items-start gap-2">
          <AlertCircle size={20} className="flex-shrink-0 mt-0.5" />
          <span className="text-sm flex-1">{toast}</span>
          <button onClick={() => setToast(null)}><X size={18} /></button>
        </div>
      )}

      {/* Header Mudah Alih */}
      <div className={`md:hidden bg-blue-700 text-white p-4 flex justify-between items-center shadow-md ${demo ? 'mt-8' : ''}`}>
        <h1 className="text-xl font-bold">ALFA Kewangan</h1>
        <button onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)} className="p-2 -m-2">
          {isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
        </button>
      </div>

      {/* Bar Sisi */}
      <div className={`${isMobileMenuOpen ? 'block' : 'hidden'} md:block w-full md:w-64 bg-blue-900 text-white flex-shrink-0 z-10 md:min-h-screen`}>
        <div className={`p-6 hidden md:block ${demo ? 'pt-12' : ''}`}>
          <h1 className="text-2xl font-bold tracking-wider">ALFA<br /><span className="text-blue-300 text-sm">SISTEM KEWANGAN</span></h1>
        </div>
        <div className="p-4 border-b border-blue-800">
          <p className="text-sm text-blue-300">Log masuk sebagai:</p>
          <p className="font-semibold">{me.name}</p>
          <span className="inline-block px-2 py-1 bg-blue-800 text-xs rounded-full mt-2 uppercase tracking-wide">{roleLabel(me.role)}</span>
        </div>
        <nav className="mt-4 flex flex-col gap-1 px-2 pb-4">
          <NavItem icon={<LayoutDashboard size={20} />} label="Papan Pemuka" isActive={activeTab === 'dashboard'} onClick={() => { setActiveTab('dashboard'); setIsMobileMenuOpen(false); }} />
          {(me.role === ROLES.FINANCE || me.role === ROLES.PURCHASING) && (
            <NavItem icon={<Plus size={20} />} label="Mohon Belanjawan" isActive={activeTab === 'new_budget'} onClick={() => { setActiveTab('new_budget'); setIsMobileMenuOpen(false); }} />
          )}
          <NavItem icon={<FileText size={20} />} label="Laporan & Rekod" isActive={activeTab === 'reports'} onClick={() => { setActiveTab('reports'); setIsMobileMenuOpen(false); }} />
          {(me.role === ROLES.ADMIN || me.role === ROLES.FINANCE) && (
            <NavItem icon={<ClipboardList size={20} />} label="Log Audit" isActive={activeTab === 'audit'} onClick={() => { setActiveTab('audit'); setIsMobileMenuOpen(false); }} />
          )}
          <NavItem icon={<Bell size={20} />} label="Pemberitahuan" isActive={activeTab === 'notifications'} onClick={() => { setActiveTab('notifications'); setIsMobileMenuOpen(false); }} badge={unread} />
          <button onClick={() => { setShowPassModal(true); setIsMobileMenuOpen(false); }}
            className="flex items-center gap-3 px-4 py-3 mt-6 text-blue-300 hover:bg-blue-800 hover:text-white rounded-lg transition-colors text-left">
            <Lock size={20} /><span>Tukar Kata Laluan</span>
          </button>
          <button onClick={handleLogout}
            className="flex items-center gap-3 px-4 py-3 text-blue-300 hover:bg-blue-800 hover:text-white rounded-lg transition-colors text-left">
            <LogOut size={20} /><span>Log Keluar</span>
          </button>
        </nav>
      </div>

      {/* Kandungan Utama */}
      <div className="flex-1 overflow-auto p-4 md:p-8 bg-gray-50">
        <div className="max-w-5xl mx-auto space-y-6">
          {activeTab === 'dashboard' && <Dashboard me={me} users={users} budgets={budgets} act={act} />}
          {activeTab === 'new_budget' && (me.role === ROLES.FINANCE || me.role === ROLES.PURCHASING) && (
            <NewBudgetForm me={me} onSubmit={async (form) => { if (await act('create_budget', form)) setActiveTab('dashboard'); }} />
          )}
          {activeTab === 'reports' && <ReportsView me={me} users={users} budgets={budgets} act={act} />}
          {activeTab === 'audit' && (me.role === ROLES.ADMIN || me.role === ROLES.FINANCE) && <AuditLogView audit={audit} />}
          {activeTab === 'notifications' && (
            <NotificationsView notifications={notifications} onMarkAllRead={() => act('mark_read', {})} />
          )}
        </div>
      </div>

      {showPassModal && <ChangePasswordModal act={act} onClose={() => setShowPassModal(false)} />}
    </div>
  );
}

function DemoBanner() {
  return (
    <div className="fixed top-0 left-0 right-0 bg-yellow-400 text-yellow-900 text-center text-xs font-bold py-1.5 z-[60]">
      MOD DEMO — pelayan tidak dikesan. Data TIDAK disimpan. (Log masuk: pengurus / ahmad / siti / raju)
    </div>
  );
}
function BusyOverlay() {
  return (
    <div className="fixed inset-0 bg-black/30 z-[65] flex items-center justify-center">
      <div className="bg-white rounded-xl shadow-xl px-6 py-4 flex items-center gap-3">
        <svg className="animate-spin h-5 w-5 text-blue-600" viewBox="0 0 24 24" fill="none"><circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" /><path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 0 1 8-8v4a4 4 0 0 0-4 4H4z" /></svg>
        <span className="text-sm font-medium text-gray-700">Sedang diproses… Sila tunggu.</span>
      </div>
    </div>
  );
}

function NavItem({ icon, label, isActive, onClick, badge }) {
  return (
    <button onClick={onClick}
      className={`flex items-center justify-between px-4 py-3 rounded-lg transition-colors text-left w-full ${isActive ? 'bg-blue-800 text-white' : 'text-blue-100 hover:bg-blue-800 hover:text-white'}`}>
      <div className="flex items-center gap-3">{icon}<span className="font-medium">{label}</span></div>
      {badge > 0 && <span className="bg-red-500 text-white text-xs font-bold px-2 py-0.5 rounded-full">{badge}</span>}
    </button>
  );
}

// ---------- LOG MASUK ----------
function LoginView({ onLogin, busy, demo }) {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState(null);
  const submit = async (e) => {
    e.preventDefault();
    setError(null);
    const err = await onLogin(username.trim(), password);
    if (err) setError(err);
  };
  return (
    <div className="min-h-screen flex items-center justify-center bg-gray-100 p-4">
      <div className="bg-white rounded-2xl shadow-xl p-8 w-full max-w-md">
        <div className="text-center mb-8">
          <div className="mx-auto bg-blue-600 w-16 h-16 rounded-full flex items-center justify-center mb-4">
            <Wallet className="text-white" size={32} />
          </div>
          <h1 className="text-2xl font-bold text-gray-800">SISTEM KEWANGAN ALFA</h1>
          <p className="text-gray-500 mt-2">Sila log masuk untuk meneruskan</p>
        </div>
        {error && (
          <div className="bg-red-50 border border-red-200 text-red-700 text-sm rounded-lg p-3 mb-4 flex items-start gap-2">
            <AlertCircle size={18} className="flex-shrink-0 mt-0.5" /><span>{error}</span>
          </div>
        )}
        <form onSubmit={submit} className="space-y-4">
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Nama Pengguna</label>
            <input type="text" required autoCapitalize="none" autoComplete="username" value={username}
              onChange={e => setUsername(e.target.value)}
              className="w-full border border-gray-300 rounded-lg px-4 py-3 focus:ring-2 focus:ring-blue-500 focus:outline-none" />
          </div>
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Kata Laluan</label>
            <input type="password" required autoComplete="current-password" value={password}
              onChange={e => setPassword(e.target.value)}
              className="w-full border border-gray-300 rounded-lg px-4 py-3 focus:ring-2 focus:ring-blue-500 focus:outline-none" />
          </div>
          <button type="submit" disabled={busy}
            className="w-full bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white py-3 rounded-xl font-semibold transition-colors flex items-center justify-center gap-2">
            Log Masuk <ArrowRight size={18} />
          </button>
        </form>
        <p className="text-xs text-gray-400 text-center mt-6">Lupa kata laluan? Sila hubungi Pentadbir sistem.</p>
        {demo && <p className="text-xs text-yellow-600 text-center mt-2 font-medium">Mod demo: pengguna "pengurus", "ahmad", "siti" atau "raju" — sebarang kata laluan.</p>}
      </div>
    </div>
  );
}

// ---------- PAPAN PEMUKA ----------
function Dashboard({ me, users, budgets, act }) {
  if (me.role === ROLES.ADMIN) return <AdminDashboard me={me} users={users} budgets={budgets} act={act} />;
  if (me.role === ROLES.FINANCE) return <FinanceDashboard me={me} users={users} budgets={budgets} act={act} />;
  if (me.role === ROLES.PURCHASING) return <PurchasingDashboard me={me} users={users} budgets={budgets} act={act} />;
  return null;
}

// PAPAN PEMUKA PENGURUSAN
function AdminDashboard({ me, users, budgets, act }) {
  const pendingBudgets = budgets.filter(b => b.status === BUDGET_STATUS.PENDING_ADMIN);
  const [editingBudget, setEditingBudget] = useState(null);
  const [editAmount, setEditAmount] = useState('');
  const [editingRecord, setEditingRecord] = useState(null);
  const [isUserModalOpen, setIsUserModalOpen] = useState(false);

  const handleApprove = async (id, newAmount = null) => {
    await act('admin_review', { id, decision: 'approve', amount: newAmount !== null ? parseFloat(newAmount) : undefined });
    setEditingBudget(null);
  };
  const handleReject = (id) => {
    const reason = window.prompt('Sila nyatakan sebab penolakan (min 5 aksara):');
    if (reason === null) return;
    if (reason.trim().length < 5) { alert('Sebab penolakan diwajibkan (min 5 aksara).'); return; }
    return act('admin_review', { id, decision: 'reject', reason: reason.trim() });
  };
  const handleSaveRecord = async (d) => {
    await act('edit_budget', { id: d.id, description: d.description, location: d.location, amount: parseFloat(d.amount) });
    setEditingRecord(null);
  };

  return (
    <div className="space-y-6 relative">
      <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
        <h2 className="text-2xl font-bold text-gray-800">Ringkasan Pengurusan</h2>
        <button onClick={() => setIsUserModalOpen(true)}
          className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2.5 rounded-xl font-semibold transition-all flex items-center gap-2 shadow-sm">
          <Users size={18} /> Urus Pengguna (Kewangan / Pembelian)
        </button>
      </div>

      <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
        <StatCard title="Jumlah Belanjawan" value={budgets.length} icon={<Wallet />} color="bg-blue-500" />
        <StatCard title="Menunggu Kelulusan Anda" value={pendingBudgets.length} icon={<Bell />} color="bg-yellow-500" />
      </div>

      <FinancialOverview users={users} budgets={budgets} />

      {pendingBudgets.length > 0 && (
        <div className="bg-white rounded-xl shadow-sm border border-yellow-200 overflow-hidden mt-6">
          <div className="px-6 py-4 border-b border-yellow-200 bg-yellow-50/50">
            <h3 className="text-lg font-semibold text-yellow-800">Permohonan Belanjawan Perlu Kelulusan</h3>
          </div>
          <div className="p-6 space-y-4">
            {pendingBudgets.map(b => (
              <div key={b.id} className="border border-gray-200 rounded-lg p-4 flex flex-col md:flex-row gap-4 items-center justify-between hover:bg-gray-50">
                <div>
                  <h4 className="font-bold text-gray-800">{b.description} <span className="text-gray-500 font-normal">({b.location})</span></h4>
                  <p className="text-sm text-gray-600 mt-1">Dipohon oleh: {users.find(u => u.id === b.requestedBy)?.name || 'Kewangan'} | Tarikh Akhir: {b.dueDate}</p>
                  <p className="font-semibold text-lg text-blue-600 mt-2">RM {fmt(b.amount)}</p>
                </div>
                <div className="flex flex-wrap gap-2 w-full md:w-auto justify-end">
                  <button onClick={() => handleApprove(b.id)} className="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg font-medium transition-colors flex items-center gap-2">
                    <CheckCircle size={18} /> Lulus Penuh
                  </button>
                  <button onClick={() => { setEditingBudget(b); setEditAmount(b.amount); }} className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium transition-colors flex items-center gap-2">
                    <Edit size={18} /> Ubah & Lulus
                  </button>
                  <button onClick={() => handleReject(b.id)} className="bg-red-100 text-red-700 hover:bg-red-200 px-4 py-2 rounded-lg font-medium transition-colors flex items-center gap-2">
                    <XCircle size={18} /> Tolak
                  </button>
                </div>
              </div>
            ))}
          </div>
        </div>
      )}

      {editingBudget && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
          <div className="bg-white rounded-xl shadow-xl w-full max-w-md overflow-hidden">
            <div className="px-6 py-4 bg-blue-50 border-b border-blue-100 flex justify-between items-center">
              <h3 className="font-bold text-blue-900">Ubah Kelulusan Belanjawan</h3>
              <button onClick={() => setEditingBudget(null)} className="text-blue-500 hover:text-blue-700"><X size={20} /></button>
            </div>
            <div className="p-6 space-y-4">
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Keterangan</label>
                <input type="text" readOnly value={editingBudget.description} className="w-full border border-gray-300 rounded-lg px-4 py-2 bg-gray-100 text-gray-500" />
              </div>
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Jumlah Diluluskan (RM)</label>
                <input type="number" step="0.01" value={editAmount} onChange={(e) => setEditAmount(e.target.value)}
                  className="w-full border border-blue-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 outline-none text-lg font-bold" />
              </div>
              <div className="pt-4 flex justify-end gap-3">
                <button onClick={() => setEditingBudget(null)} className="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-lg font-medium">Batal</button>
                <button onClick={() => handleApprove(editingBudget.id, editAmount)} className="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium">Sahkan & Lulus</button>
              </div>
            </div>
          </div>
        </div>
      )}

      <section className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden mt-6">
        <div className="px-6 py-4 border-b border-gray-100 bg-gray-50">
          <h3 className="text-lg font-semibold text-gray-800">Sejarah Rekod Belanjawan</h3>
        </div>
        <div className="overflow-x-auto">
          <table className="w-full text-left">
            <thead className="bg-gray-50 text-gray-600 text-sm">
              <tr><th className="px-6 py-3">Tarikh</th><th className="px-6 py-3">Keterangan</th><th className="px-6 py-3">Lokasi</th><th className="px-6 py-3">Jumlah (RM)</th><th className="px-6 py-3">Status</th><th className="px-6 py-3 text-center">Tindakan</th></tr>
            </thead>
            <tbody className="divide-y divide-gray-100">
              {budgets.length === 0 ? (
                <tr><td colSpan="6" className="px-6 py-8 text-center text-gray-400">Tiada rekod belanjawan dijumpai.</td></tr>
              ) : budgets.map(b => (
                <tr key={b.id} className="hover:bg-gray-50">
                  <td className="px-6 py-4 text-sm">{b.date}</td>
                  <td className="px-6 py-4 text-sm font-medium">{b.description}</td>
                  <td className="px-6 py-4 text-sm">{b.location}</td>
                  <td className="px-6 py-4 text-sm font-bold text-blue-600">{fmt(b.amount)}</td>
                  <td className="px-6 py-4 text-sm"><StatusBadge status={b.status} /></td>
                  <td className="px-6 py-4 text-sm text-center">
                    <button onClick={() => setEditingRecord(b)} className="text-blue-600 hover:bg-blue-50 p-2 rounded-lg transition-colors inline-flex items-center gap-1" title="Ubah Maklumat">
                      <Edit size={16} /> Ubah
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </section>

      {editingRecord && <EditBudgetRecordModal budget={editingRecord} onClose={() => setEditingRecord(null)} onSave={handleSaveRecord} />}
      {isUserModalOpen && <UserManagementModal me={me} users={users} act={act} allowedRoles={[ROLES.FINANCE, ROLES.PURCHASING]} onClose={() => setIsUserModalOpen(false)} />}
    </div>
  );
}

// PAPAN PEMUKA KEWANGAN
function FinanceDashboard({ me, users, budgets, act }) {
  const [selectedBudgetId, setSelectedBudgetId] = useState(null);
  const emptyExpenseForm = { amount: '', description: '', resit1: null, resit2: null, resit3: null, resit4: null, barang1: null, barang2: null, barang3: null, barang4: null };
  const [expenseForm, setExpenseForm] = useState(emptyExpenseForm);
  const [editingStaffBudget, setEditingStaffBudget] = useState(null);
  const [editStaffAmount, setEditStaffAmount] = useState('');
  const [transferModal, setTransferModal] = useState({ isOpen: false, budgetId: null, staffId: null, assignAmount: '', receiptFile: null, maxAmount: 0 });
  const [selectedExpenseImages, setSelectedExpenseImages] = useState(null);
  const [editingRecord, setEditingRecord] = useState(null);
  const [errorFeedback, setErrorFeedback] = useState(null);
  const [isUserModalOpen, setIsUserModalOpen] = useState(false);

  const selectedBudget = budgets.find(b => b.id === selectedBudgetId) || null;
  const closeTransfer = () => setTransferModal({ isOpen: false, budgetId: null, staffId: null, assignAmount: '', receiptFile: null, maxAmount: 0 });

  const handleReceiveBudget = (id) => act('receive_budget', { id });

  const confirmTransfer = async () => {
    if (!transferModal.receiptFile || !transferModal.assignAmount) { setErrorFeedback('Sila masukkan jumlah agihan dan muat naik resit pindahan bank!'); return; }
    const amt = parseFloat(transferModal.assignAmount);
    if (!(amt > 0) || amt > transferModal.maxAmount) { setErrorFeedback('Jumlah agihan tidak sah atau melebihi baki yang ada!'); return; }
    const ok = await act('assign_budget', { budgetId: transferModal.budgetId, staffId: transferModal.staffId, amount: amt }, { transfer: transferModal.receiptFile });
    if (ok) { closeTransfer(); setErrorFeedback(null); }
  };

  const handleApproveExpense = (expenseId) => act('expense_review', { expenseId, decision: 'approve' });
  const handleRejectExpense = (expenseId) => {
    const reason = window.prompt('Sila nyatakan sebab penolakan (min 5 aksara):');
    if (reason === null) return;
    if (reason.trim().length < 5) { alert('Sebab penolakan diwajibkan (min 5 aksara).'); return; }
    return act('expense_review', { expenseId, decision: 'reject', reason: reason.trim() });
  };

  const handleSubmitExpense = async (e) => {
    e.preventDefault();
    if (!expenseForm.amount || !expenseForm.description || !expenseForm.resit1) { setErrorFeedback('Keterangan, Jumlah dan Muat Naik Resit 1 adalah diwajibkan!'); return; }
    if (parseFloat(expenseForm.amount) > selectedBudget.balance) { setErrorFeedback('Jumlah perbelanjaan melebihi baki dana!'); return; }
    const ok = await act('add_expense', { budgetId: selectedBudget.id, amount: parseFloat(expenseForm.amount), description: expenseForm.description },
      { resit1: expenseForm.resit1, resit2: expenseForm.resit2, resit3: expenseForm.resit3, resit4: expenseForm.resit4,
        barang1: expenseForm.barang1, barang2: expenseForm.barang2, barang3: expenseForm.barang3, barang4: expenseForm.barang4 });
    if (ok) { setExpenseForm(emptyExpenseForm); setSelectedBudgetId(null); setErrorFeedback(null); }
  };

  const pendingStaffRequests = budgets.filter(b => b.status === BUDGET_STATUS.PENDING_FINANCE);
  const handleApproveStaffRequest = async (id, newAmount = null) => {
    await act('finance_review', { id, decision: 'approve', amount: newAmount !== null ? parseFloat(newAmount) : undefined });
    setEditingStaffBudget(null);
  };
  const handleRejectStaffRequest = (id) => {
    const reason = window.prompt('Sila nyatakan sebab penolakan (min 5 aksara):');
    if (reason === null) return;
    if (reason.trim().length < 5) { alert('Sebab penolakan diwajibkan (min 5 aksara).'); return; }
    return act('finance_review', { id, decision: 'reject', reason: reason.trim() });
  };
  const handleSaveRecord = async (d) => {
    await act('edit_budget', { id: d.id, description: d.description, location: d.location, amount: parseFloat(d.amount) });
    setEditingRecord(null);
  };

  const purchasers = users.filter(u => u.role === ROLES.PURCHASING && u.active);
  const pendingExpenses = budgets.flatMap(b => [
    ...(b.expenses || []).filter(e => e.status === EXPENSE_STATUS.PENDING).map(e => ({ ...e, budgetId: b.id, budgetDesc: b.description, assignedToName: 'Kewangan' })),
    ...(b.assignments || []).flatMap(a =>
      (a.expenses || []).filter(e => e.status === EXPENSE_STATUS.PENDING).map(e => ({ ...e, budgetId: b.id, budgetDesc: b.description, assignedToName: users.find(u => u.id === a.staffId)?.name || 'Tidak diketahui' })))
  ]);

  return (
    <div className="space-y-8">
      <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
        <h2 className="text-2xl font-bold text-gray-800">Papan Pemuka Kewangan</h2>
        <button onClick={() => setIsUserModalOpen(true)}
          className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2.5 rounded-xl font-semibold transition-all flex items-center gap-2 shadow-sm">
          <Users size={18} /> Urus Staf Pembelian
        </button>
      </div>

      {errorFeedback && (
        <div className="bg-red-50 border-l-4 border-red-500 p-4 rounded-lg flex items-start gap-3">
          <AlertCircle className="text-red-500 flex-shrink-0 mt-0.5" size={20} />
          <div><p className="font-semibold text-red-800">Sila ambil perhatian</p><p className="text-sm text-red-700 mt-0.5">{errorFeedback}</p></div>
          <button onClick={() => setErrorFeedback(null)} className="ml-auto text-red-500 hover:text-red-700"><X size={18} /></button>
        </div>
      )}

      <FinancialOverview users={users} budgets={budgets} />

      {pendingStaffRequests.length > 0 && (
        <section className="bg-white rounded-xl shadow-sm border border-orange-200 overflow-hidden mb-8">
          <div className="px-6 py-4 border-b border-orange-200 bg-orange-50/50">
            <h3 className="text-lg font-semibold text-orange-800">Permohonan Belanjawan dari Staf (Menunggu Kelulusan Anda)</h3>
          </div>
          <div className="p-6 space-y-4">
            {pendingStaffRequests.map(b => (
              <div key={b.id} className="border border-gray-200 rounded-lg p-4 flex flex-col md:flex-row gap-4 items-center justify-between hover:bg-gray-50">
                <div>
                  <h4 className="font-bold text-gray-800">{b.description} <span className="text-gray-500 font-normal">({b.location})</span></h4>
                  <p className="text-sm text-gray-600 mt-1">Dipohon oleh: {users.find(u => u.id === b.requestedBy)?.name} | Tarikh Akhir: {b.dueDate}</p>
                  <p className="font-semibold text-lg text-blue-600 mt-2">RM {fmt(b.amount)}</p>
                </div>
                <div className="flex flex-wrap gap-2 w-full md:w-auto justify-end">
                  <button onClick={() => handleApproveStaffRequest(b.id)} className="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg font-medium transition-colors flex items-center gap-2">
                    <CheckCircle size={18} /> Lulus & Ke Pengurusan
                  </button>
                  <button onClick={() => { setEditingStaffBudget(b); setEditStaffAmount(b.amount); }} className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium transition-colors flex items-center gap-2">
                    <Edit size={18} /> Ubah & Lulus
                  </button>
                  <button onClick={() => handleRejectStaffRequest(b.id)} className="bg-red-100 text-red-700 hover:bg-red-200 px-4 py-2 rounded-lg font-medium transition-colors flex items-center gap-2">
                    <XCircle size={18} /> Tolak
                  </button>
                </div>
              </div>
            ))}
          </div>
        </section>
      )}

      {editingStaffBudget && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
          <div className="bg-white rounded-xl shadow-xl w-full max-w-md overflow-hidden">
            <div className="px-6 py-4 bg-blue-50 border-b border-blue-100 flex justify-between items-center">
              <h3 className="font-bold text-blue-900">Ubah Permohonan Belanjawan (Staf)</h3>
              <button onClick={() => setEditingStaffBudget(null)} className="text-blue-500 hover:text-blue-700"><X size={20} /></button>
            </div>
            <div className="p-6 space-y-4">
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Keterangan</label>
                <input type="text" readOnly value={editingStaffBudget.description} className="w-full border border-gray-300 rounded-lg px-4 py-2 bg-gray-100 text-gray-500" />
              </div>
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Jumlah Diluluskan (RM)</label>
                <input type="number" step="0.01" value={editStaffAmount} onChange={(e) => setEditStaffAmount(e.target.value)}
                  className="w-full border border-blue-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 outline-none text-lg font-bold" />
              </div>
              <div className="pt-4 flex justify-end gap-3">
                <button onClick={() => setEditingStaffBudget(null)} className="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-lg font-medium">Batal</button>
                <button onClick={() => handleApproveStaffRequest(editingStaffBudget.id, editStaffAmount)} className="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium">Lulus & Hantar</button>
              </div>
            </div>
          </div>
        </div>
      )}

      {selectedBudget && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-start md:items-center justify-center z-50 p-3 md:p-4 overflow-y-auto">
          <div className="bg-white rounded-xl shadow-xl w-full max-w-3xl overflow-hidden my-4 md:my-0 max-h-[92vh] flex flex-col">
            <div className="px-6 py-4 border-b border-gray-100 bg-gray-50 flex justify-between items-center flex-shrink-0">
              <h3 className="text-lg font-semibold text-gray-800">Masukkan Perbelanjaan (Kewangan)</h3>
              <button onClick={() => setSelectedBudgetId(null)} className="text-gray-500 hover:text-gray-700"><X size={24} /></button>
            </div>
            <div className="p-6 grid grid-cols-1 md:grid-cols-3 gap-6 overflow-y-auto">
              <div className="col-span-1 bg-blue-50 rounded-xl p-5 border border-blue-100">
                <h4 className="font-bold text-blue-900 mb-4">{selectedBudget.description}</h4>
                <div className="space-y-4">
                  <div><p className="text-sm text-blue-700">Jumlah Asal (Belanjawan)</p><p className="text-2xl font-bold text-blue-900">RM {fmt(selectedBudget.amount)}</p></div>
                  <div className="pt-4 border-t border-blue-200">
                    <p className="text-sm text-blue-700">Baki Di Tangan Kewangan</p>
                    <p className={`text-3xl font-bold ${selectedBudget.balance <= 0 ? 'text-red-600' : 'text-green-600'}`}>RM {fmt(selectedBudget.balance)}</p>
                  </div>
                </div>
              </div>
              <div className="col-span-1 md:col-span-2">
                <ExpenseForm form={expenseForm} setForm={setExpenseForm} onSubmit={handleSubmitExpense} disabled={selectedBudget.balance <= 0} idPrefix="f" />
              </div>
            </div>
          </div>
        </div>
      )}

      <section className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
        <div className="px-6 py-4 border-b border-gray-100 bg-gray-50 flex justify-between items-center">
          <h3 className="text-lg font-semibold text-gray-800">Status Permohonan Anda</h3>
        </div>
        <div className="p-6">
          {budgets.filter(b => b.status === BUDGET_STATUS.PENDING_ADMIN || b.status === BUDGET_STATUS.REJECTED_BY_ADMIN).length === 0 ? (
            <p className="text-gray-500 text-center py-2">Tiada permohonan sedang menunggu kelulusan Pengurusan.</p>
          ) : (
            <div className="space-y-3">
              {budgets.filter(b => b.status === BUDGET_STATUS.PENDING_ADMIN || b.status === BUDGET_STATUS.REJECTED_BY_ADMIN).map(b => (
                <div key={b.id} className="flex items-center justify-between border-b pb-3 last:border-0 last:pb-0">
                  <div><p className="font-semibold text-gray-800">{b.description}</p><p className="text-sm text-gray-500">Diminta: RM {fmt(b.amount)}</p></div>
                  <StatusBadge status={b.status} />
                </div>
              ))}
            </div>
          )}
        </div>
      </section>

      <section className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
        <div className="px-6 py-4 border-b border-gray-100 bg-blue-50/50">
          <h3 className="text-lg font-semibold text-blue-800">Penerimaan Dana & Agihan Bajet kepada Pembelian</h3>
        </div>
        <div className="p-6">
          {budgets.filter(b => [BUDGET_STATUS.APPROVED_BY_ADMIN, BUDGET_STATUS.RECEIVED, BUDGET_STATUS.ASSIGNED].includes(b.status)).length === 0 ? (
            <p className="text-gray-500 text-center py-4">Tiada dana baru sedia untuk diproses.</p>
          ) : (
            <div className="space-y-4">
              {budgets.filter(b => [BUDGET_STATUS.APPROVED_BY_ADMIN, BUDGET_STATUS.RECEIVED, BUDGET_STATUS.ASSIGNED].includes(b.status)).map(b => {
                const isPurchaser = purchasers.some(p => p.id === b.requestedBy);
                const reqUser = users.find(u => u.id === b.requestedBy);
                return (
                  <div key={b.id} className="border border-gray-200 rounded-lg p-5 flex flex-col md:flex-row gap-4 items-start md:items-center justify-between hover:bg-gray-50 transition-colors">
                    <div className="flex-1 w-full">
                      <div className="flex justify-between items-start mb-2">
                        <h4 className="font-bold text-gray-800 text-lg">{b.description} <span className="text-gray-500 font-normal text-base">({b.location})</span></h4>
                        <StatusBadge status={b.status} />
                      </div>
                      <div className="flex flex-col sm:flex-row sm:gap-6 mt-2">
                        <div><p className="text-xs text-gray-500 uppercase tracking-wide">Jumlah Asal</p><p className="font-semibold text-gray-800">RM {fmt(b.amount)}</p></div>
                        <div className="mt-2 sm:mt-0"><p className="text-xs text-green-700 uppercase tracking-wide font-bold">Baki Belum Diagih</p><p className="font-bold text-green-600 text-lg">RM {fmt(b.balance)}</p></div>
                      </div>
                      {b.assignments && b.assignments.length > 0 && (
                        <div className="mt-3 bg-white p-3 rounded-lg border border-gray-200 shadow-sm">
                          <p className="text-xs font-bold text-gray-500 mb-2 uppercase">Rekod Agihan Bajet:</p>
                          {b.assignments.map(a => (
                            <div key={a.id} className="flex justify-between items-center text-sm border-b last:border-0 border-gray-100 py-1">
                              <span className="text-gray-700">{users.find(u => u.id === a.staffId)?.name}</span>
                              <span className="font-semibold text-blue-600">RM {fmt(a.amount)} <span className="text-gray-400 font-normal text-xs ml-1">(Baki Semasa: RM {fmt(a.balance)})</span></span>
                            </div>
                          ))}
                        </div>
                      )}
                    </div>
                    <div className="flex flex-col gap-2 w-full md:w-auto">
                      {b.status === BUDGET_STATUS.APPROVED_BY_ADMIN && (
                        <button onClick={() => handleReceiveBudget(b.id)} className="bg-green-600 hover:bg-green-700 text-white px-5 py-2.5 rounded-lg font-medium transition-colors flex items-center justify-center gap-2 shadow-sm">
                          <CheckCircle size={18} /> Terima (Masuk Dana)
                        </button>
                      )}
                      {(b.status === BUDGET_STATUS.RECEIVED || b.status === BUDGET_STATUS.ASSIGNED) && b.balance > 0 && (
                        <div className="flex gap-2 items-center flex-wrap mt-3 md:mt-0 pt-3 md:pt-0 border-t md:border-0 border-gray-200">
                          {isPurchaser ? (
                            <span className="text-sm font-medium bg-blue-50 text-blue-800 px-3 py-2 rounded-lg border border-blue-200 shadow-sm flex items-center gap-2">
                              <Users size={16} /> {reqUser?.name}
                            </span>
                          ) : (
                            <select className="border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:border-blue-500 shadow-sm" id={`assign-${b.id}`} defaultValue="">
                              <option value="" disabled>Pilih Staf Pembelian...</option>
                              {purchasers.map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
                            </select>
                          )}
                          <button onClick={() => {
                            const selId = isPurchaser ? b.requestedBy : parseInt(document.getElementById(`assign-${b.id}`)?.value || 0);
                            if (selId) setTransferModal({ isOpen: true, budgetId: b.id, staffId: selId, assignAmount: b.balance, receiptFile: null, maxAmount: b.balance });
                            else setErrorFeedback('Sila pilih staf terlebih dahulu sebelum membuat agihan bajet!');
                          }} className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg font-medium transition-colors shadow-sm">
                            Agihan Bajet
                          </button>
                        </div>
                      )}
                      {(b.status === BUDGET_STATUS.RECEIVED || b.status === BUDGET_STATUS.ASSIGNED) && (
                        <button onClick={() => setSelectedBudgetId(b.id)} className="bg-purple-50 text-purple-700 border border-purple-200 hover:bg-purple-100 hover:border-purple-300 px-4 py-2 rounded-lg font-medium transition-colors shadow-sm mt-1">
                          Urus Perbelanjaan (Kewangan)
                        </button>
                      )}
                    </div>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </section>

      <section className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden mt-8">
        <div className="px-6 py-4 border-b border-gray-100 bg-orange-50/50">
          <h3 className="text-lg font-semibold text-orange-800">Kelulusan Perbelanjaan (Staf & Kewangan)</h3>
        </div>
        <div className="p-6">
          {pendingExpenses.length === 0 ? (
            <p className="text-gray-500 text-center py-4">Tiada perbelanjaan menunggu kelulusan.</p>
          ) : (
            <div className="space-y-4">
              {pendingExpenses.map((e, index) => (
                <div key={`${e.budgetId}-${e.id}-${index}`} className="border border-orange-200 bg-orange-50/30 rounded-lg p-4 flex flex-col md:flex-row gap-4 items-center justify-between">
                  <div className="flex-1">
                    <div className="flex items-center gap-2 mb-1">
                      <span className="text-xs font-bold px-2 py-1 bg-orange-100 text-orange-800 rounded">Menunggu</span>
                      <span className="text-sm text-gray-500">Dana: {e.budgetDesc}</span>
                    </div>
                    <h4 className="font-bold text-gray-800">{e.description}</h4>
                    <p className="text-sm text-gray-600 mt-1">Staf: {e.assignedToName} | Tarikh: {e.date}</p>
                    <div className="flex gap-4 mt-2">
                      <button onClick={() => setSelectedExpenseImages(e.images)} className="text-xs bg-blue-50 text-blue-700 hover:bg-blue-100 px-3 py-1.5 rounded-lg flex items-center gap-1 font-medium transition-colors">
                        <Receipt size={14} /> Lihat Resit & Barang
                      </button>
                    </div>
                  </div>
                  <div className="text-right flex flex-col items-end gap-3">
                    <p className="font-bold text-xl text-red-600">RM {fmt(e.amount)}</p>
                    <div className="flex gap-2">
                      <button onClick={() => handleApproveExpense(e.id)} className="bg-green-600 hover:bg-green-700 text-white px-3 py-1.5 rounded text-sm font-medium flex items-center gap-1">
                        <CheckCircle size={16} /> Lulus & Tolak Dana
                      </button>
                      <button onClick={() => handleRejectExpense(e.id)} className="bg-red-100 text-red-700 hover:bg-red-200 px-3 py-1.5 rounded text-sm font-medium flex items-center gap-1">
                        <XCircle size={16} /> Tolak
                      </button>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          )}
        </div>
      </section>

      <section className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden mt-6">
        <div className="px-6 py-4 border-b border-gray-100">
          <h3 className="text-lg font-semibold text-gray-800">Semua Rekod Belanjawan Saya</h3>
        </div>
        <div className="overflow-x-auto">
          <table className="w-full text-left">
            <thead className="bg-gray-50 text-gray-600 text-sm">
              <tr><th className="px-6 py-3">Tarikh</th><th className="px-6 py-3">Keterangan</th><th className="px-6 py-3">Lokasi</th><th className="px-6 py-3">Jumlah (RM)</th><th className="px-6 py-3">Status</th><th className="px-6 py-3 text-center">Tindakan</th></tr>
            </thead>
            <tbody className="divide-y divide-gray-100">
              {budgets.filter(b => b.requestedBy === me.id || (b.assignments || []).some(a => a.staffId === me.id)).length === 0 ? (
                <tr><td colSpan="6" className="px-6 py-8 text-center text-gray-400">Tiada rekod belanjawan dijumpai.</td></tr>
              ) : budgets.filter(b => b.requestedBy === me.id || (b.assignments || []).some(a => a.staffId === me.id)).map(b => (
                <tr key={b.id} className="hover:bg-gray-50">
                  <td className="px-6 py-4 text-sm">{b.date}</td>
                  <td className="px-6 py-4 text-sm font-medium">{b.description}</td>
                  <td className="px-6 py-4 text-sm">{b.location}</td>
                  <td className="px-6 py-4 text-sm font-bold text-blue-600">{fmt(b.amount)}</td>
                  <td className="px-6 py-4 text-sm"><StatusBadge status={b.status} /></td>
                  <td className="px-6 py-4 text-sm text-center">
                    <button onClick={() => setEditingRecord(b)} className="text-blue-600 hover:bg-blue-50 p-2 rounded-lg transition-colors inline-flex items-center gap-1" title="Ubah Maklumat">
                      <Edit size={16} /> Ubah
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </section>

      {editingRecord && <EditBudgetRecordModal budget={editingRecord} onClose={() => setEditingRecord(null)} onSave={handleSaveRecord} />}

      {transferModal.isOpen && (
        <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
          <div className="bg-white rounded-xl shadow-xl w-full max-w-md overflow-hidden">
            <div className="px-6 py-4 bg-blue-50 border-b border-blue-100 flex justify-between items-center">
              <h3 className="font-bold text-blue-900">Butiran Agihan Bajet</h3>
              <button onClick={closeTransfer} className="text-blue-500 hover:text-blue-700"><X size={20} /></button>
            </div>
            <div className="p-6 space-y-4">
              <div className="bg-yellow-50 p-3 rounded-lg border border-yellow-100">
                <p className="text-sm text-yellow-800">Anda sedang membuat agihan bajet kepada: <strong>{users.find(u => u.id === transferModal.staffId)?.name}</strong></p>
                <p className="text-xs text-yellow-600 mt-1">Baki maksimum yang boleh diagih: RM {fmt(transferModal.maxAmount)}</p>
              </div>
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Jumlah Agihan (RM) *</label>
                <input type="number" step="0.01" max={transferModal.maxAmount} required
                  className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none font-bold text-lg"
                  value={transferModal.assignAmount} onChange={e => setTransferModal({ ...transferModal, assignAmount: e.target.value })} />
              </div>
              <div className="pt-2">
                <label className="block text-sm font-medium text-gray-700 mb-2">Resit Pindahan Bank *</label>
                <div className="h-28">
                  <ImageUploadBox id="transfer_receipt_img" label="Resit Pindahan Bank" isRequired={true} file={transferModal.receiptFile}
                    onChange={e => setTransferModal({ ...transferModal, receiptFile: e.target.files[0] })} icon={Receipt} />
                </div>
              </div>
              <div className="pt-4 flex justify-end gap-3 border-t border-gray-100 mt-4">
                <button onClick={closeTransfer} className="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-lg font-medium">Batal</button>
                <button onClick={confirmTransfer} className="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium">Sahkan & Agih</button>
              </div>
            </div>
          </div>
        </div>
      )}

      <ExpenseImageModal images={selectedExpenseImages} onClose={() => setSelectedExpenseImages(null)} />
      {isUserModalOpen && <UserManagementModal me={me} users={users} act={act} allowedRoles={[ROLES.PURCHASING]} onClose={() => setIsUserModalOpen(false)} />}
    </div>
  );
}

// BORANG PERBELANJAAN (dikongsi Kewangan & Pembelian)
function ExpenseForm({ form, setForm, onSubmit, disabled, idPrefix }) {
  return (
    <form onSubmit={onSubmit} className="space-y-4">
      <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1">Tarikh</label>
          <input type="date" className="w-full border border-gray-300 rounded-lg px-4 py-2 bg-gray-100" value={new Date().toISOString().split('T')[0]} readOnly />
        </div>
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1">Jumlah Perbelanjaan (RM) *</label>
          <input type="number" step="0.01" required className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
            value={form.amount} onChange={e => setForm({ ...form, amount: e.target.value })} />
        </div>
      </div>
      <div>
        <label className="block text-sm font-medium text-gray-700 mb-1">Keterangan Barang/Perkhidmatan *</label>
        <textarea required rows="2" className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
          value={form.description} onChange={e => setForm({ ...form, description: e.target.value })}></textarea>
      </div>
      <div className="space-y-3">
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-2">Gambar Resit (Resit 1 Wajib)</label>
          <div className="grid grid-cols-2 sm:grid-cols-4 gap-3 h-24">
            {[1, 2, 3, 4].map(n => (
              <ImageUploadBox key={n} id={`${idPrefix}_r${n}`} label={`Resit ${n}`} isRequired={n === 1} file={form[`resit${n}`]}
                onChange={e => setForm({ ...form, [`resit${n}`]: e.target.files[0] })} icon={Receipt} />
            ))}
          </div>
        </div>
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-2">Gambar Barang (Pilihan)</label>
          <div className="grid grid-cols-2 sm:grid-cols-4 gap-3 h-24">
            {[1, 2, 3, 4].map(n => (
              <ImageUploadBox key={n} id={`${idPrefix}_b${n}`} label={`Barang ${n}`} isRequired={false} file={form[`barang${n}`]}
                onChange={e => setForm({ ...form, [`barang${n}`]: e.target.files[0] })} icon={Upload} />
            ))}
          </div>
        </div>
      </div>
      <div className="pt-4 flex justify-end">
        <button type="submit" disabled={disabled} className="bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white px-6 py-2 rounded-lg font-medium transition-colors">
          Hantar Perbelanjaan
        </button>
      </div>
      <p className="text-xs text-gray-500 text-right mt-2">* Perbelanjaan akan ditolak dari dana selepas diluluskan oleh Kewangan.</p>
    </form>
  );
}

// PAPAN PEMUKA PEMBELIAN
function PurchasingDashboard({ me, users, budgets, act }) {
  const [selectedKey, setSelectedKey] = useState(null); // {budgetId, assignmentId}
  const emptyExpenseForm = { amount: '', description: '', resit1: null, resit2: null, resit3: null, resit4: null, barang1: null, barang2: null, barang3: null, barang4: null };
  const [expenseForm, setExpenseForm] = useState(emptyExpenseForm);
  const [errorFeedback, setErrorFeedback] = useState(null);

  const myAssignments = budgets.flatMap(b =>
    (b.assignments || []).filter(a => a.staffId === me.id).map(a => ({
      ...a, budgetId: b.id, budgetDesc: b.description, location: b.location, budgetStatus: b.status
    }))
  );
  // Baki sifar → keluar dari "Agihan Bajet Saya" (aktif), pindah ke "Transaksi Sebelumnya".
  const activeAssignments = myAssignments.filter(a => a.balance > 0);
  const pastAssignments = myAssignments.filter(a => a.balance <= 0);
  const selectedAssignment = selectedKey ? myAssignments.find(a => a.id === selectedKey.assignmentId && a.budgetId === selectedKey.budgetId) : null;

  const handleSubmitExpense = async (e) => {
    e.preventDefault();
    if (!expenseForm.amount || !expenseForm.description || !expenseForm.resit1) { setErrorFeedback('Keterangan, Jumlah dan Muat Naik Resit 1 adalah diwajibkan!'); return; }
    if (parseFloat(expenseForm.amount) > selectedAssignment.balance) { setErrorFeedback('Jumlah perbelanjaan melebihi baki dana!'); return; }
    const ok = await act('add_expense',
      { budgetId: selectedAssignment.budgetId, assignmentId: selectedAssignment.id, amount: parseFloat(expenseForm.amount), description: expenseForm.description },
      { resit1: expenseForm.resit1, resit2: expenseForm.resit2, resit3: expenseForm.resit3, resit4: expenseForm.resit4,
        barang1: expenseForm.barang1, barang2: expenseForm.barang2, barang3: expenseForm.barang3, barang4: expenseForm.barang4 });
    if (ok) { setExpenseForm(emptyExpenseForm); setSelectedKey(null); setErrorFeedback(null); }
  };

  return (
    <div className="space-y-6">
      <h2 className="text-2xl font-bold text-gray-800">Agihan Bajet Saya</h2>

      {errorFeedback && (
        <div className="bg-red-50 border-l-4 border-red-500 p-4 rounded-lg flex items-start gap-3">
          <AlertCircle className="text-red-500 flex-shrink-0 mt-0.5" size={20} />
          <div><p className="font-semibold text-red-800">Perhatian</p><p className="text-sm text-red-700 mt-0.5">{errorFeedback}</p></div>
          <button onClick={() => setErrorFeedback(null)} className="ml-auto text-red-500 hover:text-red-700"><X size={18} /></button>
        </div>
      )}

      {selectedAssignment ? (
        <div className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
          <div className="px-6 py-4 border-b border-gray-100 bg-gray-50 flex justify-between items-center">
            <h3 className="text-lg font-semibold text-gray-800">Masukkan Perbelanjaan</h3>
            <button onClick={() => setSelectedKey(null)} className="text-gray-500 hover:text-gray-700"><X size={24} /></button>
          </div>
          <div className="p-6 grid grid-cols-1 md:grid-cols-3 gap-6">
            <div className="col-span-1 bg-blue-50 rounded-xl p-5 border border-blue-100">
              <h4 className="font-bold text-blue-900 mb-4">{selectedAssignment.budgetDesc} <span className="text-sm font-normal text-blue-700">({selectedAssignment.location})</span></h4>
              <div className="space-y-4">
                <div><p className="text-sm text-blue-700">Jumlah Asal (Agihan Bajet Ini)</p><p className="text-2xl font-bold text-blue-900">RM {fmt(selectedAssignment.amount)}</p></div>
                <div className="pt-4 border-t border-blue-200">
                  <p className="text-sm text-blue-700">Baki Terkini</p>
                  <p className={`text-3xl font-bold ${selectedAssignment.balance <= 0 ? 'text-red-600' : 'text-green-600'}`}>RM {fmt(selectedAssignment.balance)}</p>
                </div>
                {selectedAssignment.balance <= 0 && (
                  <p className="text-xs text-red-500 bg-red-50 p-2 rounded">Dana telah habis. Lebihan akan diserahkan kembali kepada Kewangan.</p>
                )}
              </div>
            </div>
            <div className="col-span-1 md:col-span-2">
              <ExpenseForm form={expenseForm} setForm={setExpenseForm} onSubmit={handleSubmitExpense} disabled={selectedAssignment.balance <= 0} idPrefix="p" />
            </div>
          </div>
        </div>
      ) : (
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
          {activeAssignments.length === 0 ? (
            <div className="col-span-full py-12 text-center text-gray-500 bg-white rounded-xl shadow-sm border border-gray-100">
              Tiada agihan bajet aktif ditugaskan kepada anda setakat ini.
            </div>
          ) : activeAssignments.map(a => (
            <div key={a.id} className="bg-white rounded-xl shadow-sm border border-gray-200 overflow-hidden hover:shadow-md transition-shadow flex flex-col">
              <div className="px-5 py-4 border-b border-gray-100 flex justify-between items-center bg-gray-50">
                <span className="text-sm font-bold text-gray-500 uppercase tracking-wider">{a.location}</span>
                <StatusBadge status={a.budgetStatus} />
              </div>
              <div className="p-5 flex-1 flex flex-col justify-between">
                <div>
                  <h4 className="font-semibold text-gray-800 text-lg mb-4">{a.budgetDesc}</h4>
                  <div className="flex justify-between items-end mb-4">
                    <div><p className="text-xs text-gray-500 mb-1">Baki Dana</p><p className="text-2xl font-bold text-green-600">RM {fmt(a.balance)}</p></div>
                    <div className="text-right"><p className="text-xs text-gray-500 mb-1">Jumlah Diagih</p><p className="text-sm font-medium text-gray-700">RM {fmt(a.amount)}</p></div>
                  </div>
                </div>
                <button onClick={() => setSelectedKey({ budgetId: a.budgetId, assignmentId: a.id })}
                  disabled={a.budgetStatus === BUDGET_STATUS.CLOSED}
                  className="w-full bg-blue-50 text-blue-700 hover:bg-blue-100 disabled:opacity-50 disabled:cursor-not-allowed py-2 rounded-lg font-medium transition-colors mt-2">
                  {a.budgetStatus === BUDGET_STATUS.CLOSED ? 'Dana Selesai' : 'Urus Perbelanjaan'}
                </button>
              </div>
            </div>
          ))}
        </div>
      )}

      {!selectedAssignment && pastAssignments.length > 0 && (
        <section className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden mt-8">
          <div className="px-6 py-4 border-b border-gray-100 bg-gray-50">
            <h3 className="text-lg font-semibold text-gray-800">Transaksi Sebelumnya</h3>
            <p className="text-sm text-gray-500 mt-0.5">Agihan bajet yang dananya telah habis (baki RM 0.00).</p>
          </div>
          <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-6">
            {pastAssignments.map(a => (
              <div key={a.id} className="bg-gray-50 rounded-xl border border-gray-200 overflow-hidden flex flex-col opacity-90">
                <div className="px-5 py-4 border-b border-gray-100 flex justify-between items-center">
                  <span className="text-sm font-bold text-gray-500 uppercase tracking-wider">{a.location}</span>
                  <StatusBadge status={a.budgetStatus} />
                </div>
                <div className="p-5 flex-1 flex flex-col justify-between">
                  <h4 className="font-semibold text-gray-700 text-lg mb-4">{a.budgetDesc}</h4>
                  <div className="flex justify-between items-end">
                    <div><p className="text-xs text-gray-500 mb-1">Baki Dana</p><p className="text-2xl font-bold text-gray-400">RM {fmt(a.balance)}</p></div>
                    <div className="text-right"><p className="text-xs text-gray-500 mb-1">Jumlah Diagih</p><p className="text-sm font-medium text-gray-700">RM {fmt(a.amount)}</p></div>
                  </div>
                </div>
              </div>
            ))}
          </div>
        </section>
      )}

      {!selectedAssignment && (
        <section className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden mt-8">
          <div className="px-6 py-4 border-b border-gray-100">
            <h3 className="text-lg font-semibold text-gray-800">Semua Rekod Permohonan & Agihan Saya</h3>
          </div>
          <div className="overflow-x-auto">
            <table className="w-full text-left">
              <thead className="bg-gray-50 text-gray-600 text-sm">
                <tr><th className="px-6 py-3">Tarikh</th><th className="px-6 py-3">Keterangan (Belanjawan)</th><th className="px-6 py-3">Lokasi</th><th className="px-6 py-3">Status</th></tr>
              </thead>
              <tbody className="divide-y divide-gray-100">
                {budgets.filter(b => b.requestedBy === me.id || (b.assignments || []).some(a => a.staffId === me.id)).length === 0 ? (
                  <tr><td colSpan="4" className="px-6 py-8 text-center text-gray-400">Tiada rekod dijumpai.</td></tr>
                ) : budgets.filter(b => b.requestedBy === me.id || (b.assignments || []).some(a => a.staffId === me.id)).map(b => (
                  <tr key={b.id} className="hover:bg-gray-50">
                    <td className="px-6 py-4 text-sm">{b.date}</td>
                    <td className="px-6 py-4 text-sm font-medium">{b.description}</td>
                    <td className="px-6 py-4 text-sm">{b.location}</td>
                    <td className="px-6 py-4 text-sm"><StatusBadge status={b.status} /></td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </section>
      )}
    </div>
  );
}

// PENGURUSAN PENGGUNA (dengan username & kata laluan)
function UserManagementModal({ me, users, act, allowedRoles, onClose }) {
  const empty = { id: 0, name: '', role: allowedRoles[0], username: '', email: '', password: '' };
  const [form, setForm] = useState(empty);
  const [isEditing, setIsEditing] = useState(false);
  const [error, setError] = useState(null);
  const filteredUsers = users.filter(u => allowedRoles.includes(u.role) && u.active);

  const handleSave = async (e) => {
    e.preventDefault();
    if (!form.name.trim()) { setError('Nama tidak boleh dibiarkan kosong.'); return; }
    if (!/^[a-z0-9_.]{3,30}$/.test(form.username)) { setError('Nama pengguna: 3-30 aksara (huruf kecil, nombor, _ .).'); return; }
    if (!isEditing && form.password.length < 8) { setError('Kata laluan mestilah sekurang-kurangnya 8 aksara.'); return; }
    const ok = await act('save_user', { id: form.id || undefined, name: form.name, role: form.role, username: form.username, email: form.email, password: form.password });
    if (ok) { setForm(empty); setIsEditing(false); setError(null); }
  };
  const startEdit = (u) => { setForm({ id: u.id, name: u.name, role: u.role, username: u.username || '', email: u.email || '', password: '' }); setIsEditing(true); setError(null); };
  const handleDelete = async (id) => {
    if (!window.confirm('Nyahaktifkan pengguna ini? Rekod lama akan kekal.')) return;
    await act('delete_user', { id });
    if (form.id === id) { setForm(empty); setIsEditing(false); }
  };

  return (
    <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
      <div className="bg-white rounded-xl shadow-xl w-full max-w-2xl overflow-hidden max-h-[90vh] flex flex-col">
        <div className="px-6 py-4 bg-blue-900 border-b border-blue-800 flex justify-between items-center text-white">
          <h3 className="font-bold text-lg flex items-center gap-2">
            <Users size={20} /> Pengurusan Pengguna ({allowedRoles.map(r => r === 'finance' ? 'Kewangan' : 'Pembelian').join(' / ')})
          </h3>
          <button onClick={onClose} className="text-blue-200 hover:text-white"><X size={24} /></button>
        </div>
        <div className="p-6 overflow-y-auto space-y-6 flex-1">
          {error && (
            <div className="bg-red-50 text-red-700 p-3 rounded-lg flex items-center gap-2 border border-red-100">
              <AlertCircle size={18} /><span className="text-sm font-medium">{error}</span>
            </div>
          )}
          <form onSubmit={handleSave} className="bg-gray-50 p-4 rounded-xl border border-gray-200 space-y-4">
            <h4 className="font-bold text-gray-800 text-sm">{isEditing ? 'Ubah Pengguna Sedia Ada' : 'Daftar Pengguna Baru'}</h4>
            <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
              <div>
                <label className="block text-xs font-medium text-gray-700 mb-1">Nama Penuh *</label>
                <input type="text" required placeholder="Masukkan nama penuh" value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })}
                  className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" />
              </div>
              <div>
                <label className="block text-xs font-medium text-gray-700 mb-1">Peranan (Role) *</label>
                <select value={form.role} onChange={(e) => setForm({ ...form, role: e.target.value })}
                  className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
                  {allowedRoles.map(role => (
                    <option key={role} value={role}>{role === ROLES.FINANCE ? 'Kewangan (Finance)' : 'Pembelian (Purchasing)'}</option>
                  ))}
                </select>
              </div>
              <div>
                <label className="block text-xs font-medium text-gray-700 mb-1">Nama Pengguna (log masuk) *</label>
                <input type="text" required autoCapitalize="none" placeholder="cth: siti" value={form.username}
                  onChange={(e) => setForm({ ...form, username: e.target.value.toLowerCase() })}
                  className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" />
              </div>
              <div>
                <label className="block text-xs font-medium text-gray-700 mb-1">E-mel (untuk notifikasi)</label>
                <input type="email" placeholder="pilihan" value={form.email} onChange={(e) => setForm({ ...form, email: e.target.value })}
                  className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" />
              </div>
              <div className="md:col-span-2">
                <label className="block text-xs font-medium text-gray-700 mb-1">Kata Laluan {isEditing ? '(biar kosong jika tiada perubahan)' : '* (min. 8 aksara)'}</label>
                <input type="password" value={form.password} minLength={form.password ? 8 : undefined}
                  onChange={(e) => setForm({ ...form, password: e.target.value })}
                  className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" />
              </div>
            </div>
            <div className="flex justify-end gap-2 pt-2">
              {isEditing && (
                <button type="button" onClick={() => { setForm(empty); setIsEditing(false); setError(null); }}
                  className="px-4 py-2 text-sm bg-gray-200 text-gray-700 hover:bg-gray-300 rounded-lg font-medium transition-colors">
                  Batal Ubah
                </button>
              )}
              <button type="submit" className="px-4 py-2 text-sm bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium transition-colors flex items-center gap-1.5">
                {isEditing ? <Edit size={16} /> : <UserPlus size={16} />}
                {isEditing ? 'Simpan Perubahan' : 'Daftar Pengguna'}
              </button>
            </div>
          </form>
          <div>
            <h4 className="font-bold text-gray-800 text-sm mb-3">Senarai Pengguna Aktif ({filteredUsers.length})</h4>
            <div className="border border-gray-200 rounded-xl overflow-hidden bg-white overflow-x-auto">
              <table className="w-full text-left text-sm">
                <thead className="bg-gray-50 text-gray-600 font-medium">
                  <tr><th className="px-4 py-3">Nama</th><th className="px-4 py-3">Peranan</th><th className="px-4 py-3 text-right">Tindakan</th></tr>
                </thead>
                <tbody className="divide-y divide-gray-200">
                  {filteredUsers.length === 0 ? (
                    <tr><td colSpan="3" className="px-4 py-6 text-center text-gray-400">Tiada pengguna berdaftar dalam kategori ini.</td></tr>
                  ) : filteredUsers.map(u => (
                    <tr key={u.id} className="hover:bg-gray-50">
                      <td className="px-4 py-3 font-semibold text-gray-800">{u.name}</td>
                      <td className="px-4 py-3">
                        <span className={`inline-block px-2 py-0.5 rounded-full text-xs font-semibold uppercase ${u.role === ROLES.FINANCE ? 'bg-purple-100 text-purple-800' : 'bg-blue-100 text-blue-800'}`}>
                          {u.role === ROLES.FINANCE ? 'Kewangan' : 'Pembelian'}
                        </span>
                      </td>
                      <td className="px-4 py-3 text-right space-x-2 whitespace-nowrap">
                        <button onClick={() => startEdit(u)} className="text-blue-600 hover:text-blue-800 font-medium inline-flex items-center gap-1 text-xs">
                          <Edit size={14} /> Ubah
                        </button>
                        <button onClick={() => handleDelete(u.id)} className="text-red-600 hover:text-red-800 font-medium inline-flex items-center gap-1 text-xs ml-3">
                          <XCircle size={14} /> Padam
                        </button>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
        <div className="px-6 py-4 bg-gray-50 border-t border-gray-100 flex justify-end">
          <button onClick={onClose} className="px-4 py-2 bg-gray-200 hover:bg-gray-300 text-gray-700 rounded-lg font-medium text-sm transition-colors">Tutup</button>
        </div>
      </div>
    </div>
  );
}

// BORANG PERMOHONAN BELANJAWAN
function NewBudgetForm({ onSubmit, me }) {
  const [form, setForm] = useState({ amount: '', description: '', location: LOCATIONS[0], dueDate: '', notes: '' });
  const handleSubmit = (e) => { e.preventDefault(); onSubmit(form); };
  return (
    <div className="max-w-2xl mx-auto bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
      <div className="px-6 py-4 border-b border-gray-100 bg-blue-50">
        <h2 className="text-lg font-semibold text-blue-900">Borang Permohonan Belanjawan Baru</h2>
      </div>
      <form onSubmit={handleSubmit} className="p-6 space-y-5">
        <div className="grid grid-cols-1 md:grid-cols-2 gap-5">
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Tarikh Permohonan</label>
            <input type="text" className="w-full border border-gray-300 rounded-lg px-4 py-2 bg-gray-100" value={new Date().toISOString().split('T')[0]} readOnly />
            <p className="text-xs text-gray-500 mt-1">Dijana secara automatik</p>
          </div>
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Tarikh Akhir (Keperluan)</label>
            <input type="date" required className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
              value={form.dueDate} onChange={e => setForm({ ...form, dueDate: e.target.value })} />
          </div>
        </div>
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1">Jumlah Diminta (RM) *</label>
          <input type="number" step="0.01" required className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none font-bold text-lg"
            value={form.amount} onChange={e => setForm({ ...form, amount: e.target.value })} />
        </div>
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1">Lokasi Projek/Cawangan *</label>
          <select className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
            value={form.location} onChange={e => setForm({ ...form, location: e.target.value })}>
            {LOCATIONS.map(l => <option key={l} value={l}>{l}</option>)}
          </select>
        </div>
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1">Keterangan / Deskripsi *</label>
          <textarea required rows="2" className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
            value={form.description} onChange={e => setForm({ ...form, description: e.target.value })}></textarea>
        </div>
        <div>
          <label className="block text-sm font-medium text-gray-700 mb-1">Nota Tambahan</label>
          <textarea rows="2" className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
            value={form.notes} onChange={e => setForm({ ...form, notes: e.target.value })}></textarea>
        </div>
        <div className="pt-4 border-t border-gray-100 flex flex-col md:flex-row items-center justify-between gap-4">
          <p className="text-sm text-gray-500 text-center md:text-left">
            {me?.role === ROLES.PURCHASING ? 'Permohonan akan dihantar ke Kewangan untuk disemak sebelum ke Pengurusan.' : 'Permohonan akan dihantar ke Pengurusan untuk disemak dan diluluskan.'}
          </p>
          <button type="submit" className="w-full md:w-auto bg-blue-600 hover:bg-blue-700 text-white px-8 py-3 rounded-lg font-medium transition-colors flex justify-center items-center gap-2">
            Hantar Permohonan
          </button>
        </div>
      </form>
    </div>
  );
}

// LOG AUDIT — jejak kelulusan & penolakan (admin & kewangan)
function AuditLogView({ audit }) {
  const [q, setQ] = useState('');
  const ACTIONS = {
    finance_review_approve: { label: 'Lulus (Kewangan)', cls: 'bg-green-100 text-green-700' },
    finance_review_reject: { label: 'Tolak (Kewangan)', cls: 'bg-red-100 text-red-700' },
    admin_review_approve: { label: 'Lulus (Pengurusan)', cls: 'bg-green-100 text-green-700' },
    admin_review_reject: { label: 'Tolak (Pengurusan)', cls: 'bg-red-100 text-red-700' },
    expense_approve: { label: 'Lulus Perbelanjaan', cls: 'bg-green-100 text-green-700' },
    expense_reject: { label: 'Tolak Perbelanjaan', cls: 'bg-red-100 text-red-700' },
  };
  const rows = (audit || []).filter(r => ACTIONS[r.action]);
  const filtered = rows.filter(r => {
    const s = q.trim().toLowerCase(); if (!s) return true;
    return [r.user, ACTIONS[r.action]?.label, r.entity, String(r.entityId), r.details].join(' ').toLowerCase().includes(s);
  });
  const fmtDate = (d) => { try { return new Date(d).toLocaleString('ms-MY', { dateStyle: 'medium', timeStyle: 'short' }); } catch (e) { return d; } };

  return (
    <div className="space-y-6">
      <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
        <div>
          <h2 className="text-2xl font-bold text-gray-800">Log Audit Kelulusan</h2>
          <p className="text-sm text-gray-500 mt-1">Rekod semua kelulusan dan penolakan belanjawan &amp; perbelanjaan.</p>
        </div>
        <input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Cari (nama, rujukan, tindakan)…"
          className="w-full sm:w-72 border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 outline-none text-sm" />
      </div>
      <section className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
        <div className="overflow-x-auto">
          <table className="w-full text-left">
            <thead className="bg-gray-50 text-gray-600 text-sm">
              <tr>
                <th className="px-6 py-3">Tarikh &amp; Masa</th>
                <th className="px-6 py-3">Pengguna</th>
                <th className="px-6 py-3">Tindakan</th>
                <th className="px-6 py-3">Rujukan</th>
                <th className="px-6 py-3">Butiran</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-gray-100">
              {filtered.length === 0 ? (
                <tr><td colSpan="5" className="px-6 py-10 text-center text-gray-400">Tiada rekod kelulusan setakat ini.</td></tr>
              ) : filtered.map(r => (
                <tr key={r.id} className="hover:bg-gray-50 align-top">
                  <td className="px-6 py-4 text-sm text-gray-600 whitespace-nowrap">{fmtDate(r.date)}</td>
                  <td className="px-6 py-4 text-sm font-medium text-gray-800">{r.user || '—'}</td>
                  <td className="px-6 py-4 text-sm">
                    <span className={`inline-block px-2.5 py-1 rounded-full text-xs font-semibold ${ACTIONS[r.action].cls}`}>{ACTIONS[r.action].label}</span>
                  </td>
                  <td className="px-6 py-4 text-sm text-gray-600 whitespace-nowrap">{r.entity === 'budget' ? 'Belanjawan' : 'Perbelanjaan'} #{r.entityId}</td>
                  <td className="px-6 py-4 text-sm text-gray-600">{r.details || '—'}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </section>
    </div>
  );
}

// LAPORAN & REKOD (+ Cetak & CSV)
function ReportsView({ me, users, budgets, act }) {
  const [filterLoc, setFilterLoc] = useState('All');
  const [filterStaff, setFilterStaff] = useState('All');
  const [selectedExpenseImages, setSelectedExpenseImages] = useState(null);
  const [editingExpense, setEditingExpense] = useState(null);

  const allExpenses = useMemo(() => {
    let exps = budgets.flatMap(b => [
      ...(b.expenses || []).map(e => ({ ...e, budgetId: b.id, budgetDesc: b.description, location: b.location, purchaserId: e.created_by, purchaserName: 'Kewangan' })),
      ...(b.assignments || []).flatMap(a =>
        (a.expenses || []).map(e => ({ ...e, budgetId: b.id, budgetDesc: b.description, location: b.location, purchaserId: a.staffId, purchaserName: users.find(u => u.id === a.staffId)?.name || 'Tidak diketahui' })))
    ]);
    if (me?.role === ROLES.PURCHASING) exps = exps.filter(e => e.purchaserId === me.id);
    return exps.filter(e => (filterLoc === 'All' || e.location === filterLoc) && (filterStaff === 'All' || e.purchaserName === filterStaff));
  }, [budgets, filterLoc, filterStaff, me, users]);

  const handleSaveExpense = async (d) => {
    await act('edit_expense', { expenseId: d.id, description: d.description, amount: parseFloat(d.amount) });
    setEditingExpense(null);
  };

  const staffList = ['Kewangan', ...users.filter(u => u.role === ROLES.PURCHASING && u.active).map(u => u.name)];
  const isPrivileged = me?.role === ROLES.ADMIN || me?.role === ROLES.FINANCE;

  const downloadCsv = () => {
    const safeCell = (v) => { const t = String(v ?? ''); const safe = /^[=+\-@]/.test(t) ? "'" + t : t; return '"' + safe.replace(/"/g, '""') + '"'; };
    const head = ['ID Ruj', 'Tarikh', 'Lokasi', 'Staf', 'Keterangan', 'Jumlah (RM)', 'Status'];
    const rows = allExpenses.map(e => [e.id, e.date, e.location, e.purchaserName, e.description, fmt(e.amount), e.status].map(safeCell));
    const csv = '\uFEFF' + [head.map(safeCell).join(','), ...rows.map(r => r.join(','))].join('\r\n');
    const a = document.createElement('a');
    a.href = URL.createObjectURL(new Blob([csv], { type: 'text/csv;charset=utf-8' }));
    a.download = `laporan-perbelanjaan-${new Date().toISOString().split('T')[0]}.csv`;
    a.click();
  };

  return (
    <div className="space-y-6">
      <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
        <h2 className="text-2xl font-bold text-gray-800">Laporan & Rekod</h2>
        <div className="flex flex-wrap items-center gap-3">
          <div className="flex items-center gap-2">
            <label className="text-sm text-gray-600 font-medium">Tapis Lokasi:</label>
            <select className="border border-gray-300 rounded-lg px-3 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm"
              value={filterLoc} onChange={(e) => setFilterLoc(e.target.value)}>
              <option value="All">Semua Lokasi</option>
              {LOCATIONS.map(l => <option key={l} value={l}>{l}</option>)}
            </select>
          </div>
          {me?.role !== ROLES.PURCHASING && (
            <div className="flex items-center gap-2">
              <label className="text-sm text-gray-600 font-medium">Tapis Staf:</label>
              <select className="border border-gray-300 rounded-lg px-3 py-1.5 focus:outline-none focus:ring-2 focus:ring-blue-500 text-sm"
                value={filterStaff} onChange={(e) => setFilterStaff(e.target.value)}>
                <option value="All">Semua Staf</option>
                {staffList.map(s => <option key={s} value={s}>{s}</option>)}
              </select>
            </div>
          )}
          <button onClick={() => window.print()} className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center gap-2">
            <Printer size={16} /> Cetak / PDF
          </button>
          <button onClick={downloadCsv} className="bg-gray-700 hover:bg-gray-800 text-white px-4 py-2 rounded-lg text-sm font-medium flex items-center gap-2">
            <Download size={16} /> CSV
          </button>
        </div>
      </div>

      <div className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
        <div className="overflow-x-auto">
          <table className="w-full text-left">
            <thead className="bg-gray-50 text-gray-600 text-sm">
              <tr><th className="px-6 py-3">ID Ruj</th><th className="px-6 py-3">Tarikh</th><th className="px-6 py-3">Lokasi</th><th className="px-6 py-3">Staf</th><th className="px-6 py-3">Keterangan</th><th className="px-6 py-3">Jumlah (RM)</th><th className="px-6 py-3">Status</th><th className="px-6 py-3">Tindakan</th></tr>
            </thead>
            <tbody className="divide-y divide-gray-100 text-sm">
              {allExpenses.length === 0 ? (
                <tr><td colSpan="8" className="px-6 py-12 text-center text-gray-400">Tiada rekod perbelanjaan ditemui untuk tapisan ini.</td></tr>
              ) : allExpenses.map((exp, idx) => (
                <tr key={idx} className="hover:bg-gray-50">
                  <td className="px-6 py-3 text-gray-500 font-mono text-xs">{String(exp.id).slice(-6)}</td>
                  <td className="px-6 py-3 whitespace-nowrap">{exp.date}</td>
                  <td className="px-6 py-3"><span className="bg-gray-100 px-2 py-1 rounded text-xs">{exp.location}</span></td>
                  <td className="px-6 py-3">{exp.purchaserName}</td>
                  <td className="px-6 py-3">{exp.description}</td>
                  <td className="px-6 py-3 font-semibold text-gray-700">{fmt(exp.amount)}</td>
                  <td className="px-6 py-3">
                    <span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium
                      ${exp.status === EXPENSE_STATUS.APPROVED ? 'bg-green-100 text-green-800' : exp.status === EXPENSE_STATUS.REJECTED ? 'bg-red-100 text-red-800' : 'bg-orange-100 text-orange-800'}`}>
                      {exp.status}
                    </span>
                  </td>
                  <td className="px-6 py-3 flex items-center gap-2">
                    <button onClick={() => setSelectedExpenseImages(exp.images)} className="text-xs bg-blue-50 text-blue-700 hover:bg-blue-100 px-3 py-1.5 rounded-lg flex items-center gap-1 font-medium transition-colors whitespace-nowrap">
                      <Receipt size={14} /> Resit & Barang
                    </button>
                    {isPrivileged && (
                      <button onClick={() => setEditingExpense(exp)} className="text-xs bg-yellow-50 text-yellow-700 hover:bg-yellow-100 px-3 py-1.5 rounded-lg flex items-center gap-1 font-medium transition-colors whitespace-nowrap">
                        <Edit size={14} /> Ubah
                      </button>
                    )}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      <ExpenseImageModal images={selectedExpenseImages} onClose={() => setSelectedExpenseImages(null)} />
      {editingExpense && <EditExpenseRecordModal expense={editingExpense} onClose={() => setEditingExpense(null)} onSave={handleSaveExpense} />}
      <PrintReport expenses={allExpenses} filterLoc={filterLoc} filterStaff={filterStaff} me={me} />
    </div>
  );
}

// LAPORAN BERCETAK (dipaparkan hanya semasa cetak)
function PrintReport({ expenses, filterLoc, filterStaff, me }) {
  const root = document.getElementById('print-root');
  if (!root) return null;
  const total = expenses.reduce((s, e) => s + parseFloat(e.amount || 0), 0);
  const approved = expenses.filter(e => e.status === EXPENSE_STATUS.APPROVED).reduce((s, e) => s + parseFloat(e.amount || 0), 0);
  const pending = expenses.filter(e => e.status === EXPENSE_STATUS.PENDING).reduce((s, e) => s + parseFloat(e.amount || 0), 0);
  const now = new Date();
  const th = { border: '1px solid #cbd5e1', padding: '7px 9px', background: '#1e3a8a', color: '#fff', fontSize: '11px', textAlign: 'left' };
  const td = { border: '1px solid #cbd5e1', padding: '6px 9px', fontSize: '11px' };
  return ReactDOM.createPortal(
    <div style={{ fontFamily: 'Arial, sans-serif', color: '#0f172a' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', borderBottom: '3px solid #1e3a8a', paddingBottom: '12px', marginBottom: '16px' }}>
        <div>
          <div style={{ fontSize: '26px', fontWeight: 800, letterSpacing: '3px', color: '#1e3a8a' }}>ALFA</div>
          <div style={{ fontSize: '12px', color: '#475569', letterSpacing: '1px' }}>SISTEM KEWANGAN — LAPORAN PERBELANJAAN</div>
        </div>
        <div style={{ textAlign: 'right', fontSize: '11px', color: '#475569' }}>
          <div>Tarikh cetakan: {now.toLocaleDateString('ms-MY')} {now.toLocaleTimeString('ms-MY')}</div>
          <div>Dicetak oleh: {me?.name}</div>
          <div>Tapisan: Lokasi — {filterLoc === 'All' ? 'Semua' : filterLoc} · Staf — {filterStaff === 'All' ? 'Semua' : filterStaff}</div>
        </div>
      </div>
      <div style={{ display: 'flex', gap: '12px', marginBottom: '16px' }}>
        {[['Jumlah Rekod', expenses.length], ['Jumlah Keseluruhan', 'RM ' + fmt(total)], ['Diluluskan', 'RM ' + fmt(approved)], ['Menunggu', 'RM ' + fmt(pending)]].map(([label, val], i) => (
          <div key={i} style={{ flex: 1, border: '1px solid #cbd5e1', borderRadius: '8px', padding: '10px 12px' }}>
            <div style={{ fontSize: '10px', color: '#64748b', textTransform: 'uppercase', letterSpacing: '0.5px' }}>{label}</div>
            <div style={{ fontSize: '16px', fontWeight: 700, color: '#1e3a8a', marginTop: '2px' }}>{val}</div>
          </div>
        ))}
      </div>
      <table style={{ width: '100%', borderCollapse: 'collapse' }}>
        <thead><tr>
          <th style={th}>#</th><th style={th}>Tarikh</th><th style={th}>Lokasi</th><th style={th}>Staf</th><th style={th}>Keterangan</th><th style={{ ...th, textAlign: 'right' }}>Jumlah (RM)</th><th style={th}>Status</th>
        </tr></thead>
        <tbody>
          {expenses.map((e, i) => (
            <tr key={i} style={{ background: i % 2 ? '#f8fafc' : '#fff' }}>
              <td style={td}>{i + 1}</td><td style={td}>{e.date}</td><td style={td}>{e.location}</td><td style={td}>{e.purchaserName}</td>
              <td style={td}>{e.description}</td><td style={{ ...td, textAlign: 'right', fontWeight: 600 }}>{fmt(e.amount)}</td><td style={td}>{e.status}</td>
            </tr>
          ))}
          <tr>
            <td colSpan="5" style={{ ...td, fontWeight: 700, textAlign: 'right', background: '#eff6ff' }}>JUMLAH KESELURUHAN</td>
            <td style={{ ...td, textAlign: 'right', fontWeight: 800, background: '#eff6ff' }}>{fmt(total)}</td>
            <td style={{ ...td, background: '#eff6ff' }}></td>
          </tr>
        </tbody>
      </table>
      <div style={{ display: 'flex', gap: '40px', marginTop: '56px' }}>
        {['Disediakan oleh (Kewangan)', 'Disahkan oleh (Pengurusan)'].map((label, i) => (
          <div key={i} style={{ flex: 1, textAlign: 'center' }}>
            <div style={{ borderTop: '1px solid #0f172a', paddingTop: '8px', fontSize: '11px', color: '#475569' }}>{label}</div>
            <div style={{ fontSize: '10px', color: '#94a3b8', marginTop: '18px' }}>Nama: ____________________ &nbsp; Tarikh: ____________</div>
          </div>
        ))}
      </div>
    </div>, root);
}

// PEMBERITAHUAN
function NotificationsView({ notifications, onMarkAllRead }) {
  return (
    <div className="max-w-3xl mx-auto space-y-6">
      <div className="flex justify-between items-center">
        <h2 className="text-2xl font-bold text-gray-800">Pemberitahuan / Notifikasi</h2>
        <button onClick={onMarkAllRead} className="text-sm text-blue-600 hover:underline font-medium">Tanda Semua Dibaca</button>
      </div>
      <div className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
        {notifications.length === 0 ? (
          <div className="p-8 text-center text-gray-500">Tiada pemberitahuan baru.</div>
        ) : (
          <ul className="divide-y divide-gray-100">
            {notifications.map(n => (
              <li key={n.id} className={`p-4 hover:bg-gray-50 transition-colors ${!n.read ? 'bg-blue-50/30' : ''}`}>
                <div className="flex gap-4 items-start">
                  <div className={`mt-1 p-2 rounded-full ${!n.read ? 'bg-blue-100 text-blue-600' : 'bg-gray-100 text-gray-500'}`}><Bell size={16} /></div>
                  <div>
                    <p className={`text-sm ${!n.read ? 'font-semibold text-gray-900' : 'text-gray-600'}`}>{n.message}</p>
                    <p className="text-xs text-gray-400 mt-1">{new Date((n.date || '').replace(' ', 'T')).toLocaleString('ms-MY')}</p>
                  </div>
                </div>
              </li>
            ))}
          </ul>
        )}
      </div>
    </div>
  );
}

// PEMBANTU UI & MODAL
// LOAN/PENGGUNAAN DANA — lawan pemuka data (Pengurusan & Kewangan sahaja)
function FinancialOverview({ users, budgets }) {
  const [openCard, setOpenCard] = useState(null); // 'spent' | 'pending' | 'remaining'
  const userName = (id) => users.find(u => u.id === id)?.name || 'Tidak diketahui';
  const FINANCE_HOLDER = 'Kewangan (Pusat)';

  const data = useMemo(() => {
    const rows = [];
    let spent = 0, pending = 0, remaining = 0;
    const perPerson = {};
    const ensure = (name) => (perPerson[name] || (perPerson[name] = { name, took: 0, spent: 0, pending: 0, remaining: 0 }));
    const RECEIVED = [BUDGET_STATUS.RECEIVED, BUDGET_STATUS.ASSIGNED, BUDGET_STATUS.CLOSED];

    budgets.forEach(b => {
      if (RECEIVED.includes(b.status)) {
        ensure(FINANCE_HOLDER).took += b.amount;
        ensure(FINANCE_HOLDER).remaining += b.balance;
        remaining += b.balance;
      }
      const addExp = (holderName, e) => {
        const row = { holderName, budgetDesc: b.description, location: b.location, description: e.description, amount: e.amount, status: e.status, date: e.date, spender: userName(e.created_by) };
        if (e.status === EXPENSE_STATUS.APPROVED) { spent += e.amount; ensure(holderName).spent += e.amount; rows.push(row); }
        else if (e.status === EXPENSE_STATUS.PENDING) { pending += e.amount; ensure(holderName).pending += e.amount; rows.push(row); }
      };
      (b.expenses || []).forEach(e => addExp(FINANCE_HOLDER, e));
      (b.assignments || []).forEach(a => {
        const holderName = userName(a.staffId);
        ensure(holderName).took += a.amount;
        ensure(holderName).remaining += a.balance;
        remaining += a.balance;
        (a.expenses || []).forEach(e => addExp(holderName, e));
      });
    });
    return { spent, pending, remaining, rows, perPerson: Object.values(perPerson).filter(p => p.took || p.spent || p.pending || p.remaining) };
  }, [budgets, users]);

  const cards = [
    { key: 'spent', title: 'Jumlah Perbelanjaan', value: data.spent, sub: 'Perbelanjaan yang telah diluluskan', color: 'rose', icon: <Receipt size={26} /> },
    { key: 'pending', title: 'Menunggu Kelulusan', value: data.pending, sub: 'Amaun perbelanjaan belum diluluskan', color: 'amber', icon: <Bell size={26} /> },
    { key: 'remaining', title: 'Baki Belum Dibelanja', value: data.remaining, sub: 'Dana dipegang tetapi belum dibelanja', color: 'emerald', icon: <Wallet size={26} /> },
  ];
  const C = {
    rose: { ring: 'ring-rose-500', bar: 'bg-rose-500', text: 'text-rose-600', soft: 'bg-rose-50' },
    amber: { ring: 'ring-amber-500', bar: 'bg-amber-500', text: 'text-amber-600', soft: 'bg-amber-50' },
    emerald: { ring: 'ring-emerald-500', bar: 'bg-emerald-500', text: 'text-emerald-600', soft: 'bg-emerald-50' },
  };
  const approvedRows = data.rows.filter(r => r.status === EXPENSE_STATUS.APPROVED);
  const pendingRows = data.rows.filter(r => r.status === EXPENSE_STATUS.PENDING);

  const ExpTable = ({ list, accent }) => (
    <div className="overflow-x-auto">
      <table className="w-full text-left text-sm">
        <thead className="bg-gray-50 text-gray-600">
          <tr><th className="px-4 py-3">Individu / Pemegang</th><th className="px-4 py-3">Belanjawan</th><th className="px-4 py-3">Keterangan</th><th className="px-4 py-3">Dimasukkan oleh</th><th className="px-4 py-3">Tarikh</th><th className="px-4 py-3 text-right">Jumlah (RM)</th></tr>
        </thead>
        <tbody className="divide-y divide-gray-100">
          {list.length === 0 ? (
            <tr><td colSpan="6" className="px-4 py-8 text-center text-gray-400">Tiada rekod.</td></tr>
          ) : list.map((r, i) => (
            <tr key={i} className="hover:bg-gray-50">
              <td className="px-4 py-3 font-medium text-gray-800">{r.holderName}</td>
              <td className="px-4 py-3 text-gray-600">{r.budgetDesc} <span className="text-gray-400">({r.location})</span></td>
              <td className="px-4 py-3 text-gray-600">{r.description}</td>
              <td className="px-4 py-3 text-gray-600">{r.spender}</td>
              <td className="px-4 py-3 text-gray-500 whitespace-nowrap">{r.date}</td>
              <td className={`px-4 py-3 text-right font-bold ${accent}`}>{fmt(r.amount)}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );

  return (
    <section className="space-y-4">
      <div className="flex items-center justify-between">
        <h3 className="text-lg font-semibold text-gray-800">Papan Data Kewangan</h3>
        <p className="text-xs text-gray-500">Klik mana-mana kad untuk melihat butiran</p>
      </div>
      <div className="grid grid-cols-1 md:grid-cols-3 gap-4">
        {cards.map(c => {
          const active = openCard === c.key;
          return (
            <button key={c.key} onClick={() => setOpenCard(active ? null : c.key)}
              className={`text-left bg-white p-5 rounded-xl shadow-sm border border-gray-100 transition-all hover:shadow-md ${active ? `ring-2 ${C[c.color].ring}` : ''}`}>
              <div className="flex items-start justify-between">
                <div className={`${C[c.color].soft} ${C[c.color].text} p-3 rounded-xl`}>{c.icon}</div>
                <span className={`text-xs font-semibold ${C[c.color].text} ${active ? '' : 'opacity-0'}`}>Dipaparkan ▾</span>
              </div>
              <p className="text-sm text-gray-500 font-medium mt-4">{c.title}</p>
              <p className="text-3xl font-bold text-gray-800 mt-1">RM {fmt(c.value)}</p>
              <p className="text-xs text-gray-400 mt-1">{c.sub}</p>
            </button>
          );
        })}
      </div>

      {openCard && (
        <div className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
          <div className={`px-6 py-4 border-b border-gray-100 ${C[cards.find(c => c.key === openCard).color].soft}`}>
            <h4 className="font-semibold text-gray-800">
              {openCard === 'spent' && 'Butiran Perbelanjaan Diluluskan'}
              {openCard === 'pending' && 'Butiran Perbelanjaan Menunggu Kelulusan'}
              {openCard === 'remaining' && 'Baki Dana Mengikut Individu (Diambil / Dibelanja / Baki)'}
            </h4>
          </div>
          {openCard === 'spent' && <ExpTable list={approvedRows} accent="text-rose-600" />}
          {openCard === 'pending' && <ExpTable list={pendingRows} accent="text-amber-600" />}
          {openCard === 'remaining' && (
            <div className="overflow-x-auto">
              <table className="w-full text-left text-sm">
                <thead className="bg-gray-50 text-gray-600">
                  <tr><th className="px-4 py-3">Individu / Pemegang</th><th className="px-4 py-3 text-right">Diambil (RM)</th><th className="px-4 py-3 text-right">Dibelanja (RM)</th><th className="px-4 py-3 text-right">Menunggu (RM)</th><th className="px-4 py-3 text-right">Baki (RM)</th></tr>
                </thead>
                <tbody className="divide-y divide-gray-100">
                  {data.perPerson.length === 0 ? (
                    <tr><td colSpan="5" className="px-4 py-8 text-center text-gray-400">Tiada rekod.</td></tr>
                  ) : data.perPerson.map((p, i) => (
                    <tr key={i} className="hover:bg-gray-50">
                      <td className="px-4 py-3 font-medium text-gray-800">{p.name}</td>
                      <td className="px-4 py-3 text-right text-gray-700">{fmt(p.took)}</td>
                      <td className="px-4 py-3 text-right text-rose-600 font-medium">{fmt(p.spent)}</td>
                      <td className="px-4 py-3 text-right text-amber-600 font-medium">{fmt(p.pending)}</td>
                      <td className="px-4 py-3 text-right text-emerald-600 font-bold">{fmt(p.remaining)}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          )}
        </div>
      )}
    </section>
  );
}

function StatCard({ title, value, icon, color }) {
  return (
    <div className="bg-white p-6 rounded-xl shadow-sm border border-gray-100 flex items-center gap-4">
      <div className={`${color} text-white p-4 rounded-xl`}>{icon}</div>
      <div><p className="text-sm text-gray-500 font-medium mb-1">{title}</p><p className="text-3xl font-bold text-gray-800">{value}</p></div>
    </div>
  );
}

function StatusBadge({ status }) {
  let color = 'bg-gray-100 text-gray-800';
  if (status === BUDGET_STATUS.PENDING_FINANCE) color = 'bg-orange-100 text-orange-800';
  if (status === BUDGET_STATUS.REJECTED_BY_FINANCE) color = 'bg-red-100 text-red-800';
  if (status === BUDGET_STATUS.PENDING_ADMIN) color = 'bg-yellow-100 text-yellow-800';
  if (status === BUDGET_STATUS.APPROVED_BY_ADMIN) color = 'bg-green-100 text-green-800';
  if (status === BUDGET_STATUS.REJECTED_BY_ADMIN) color = 'bg-red-100 text-red-800';
  if (status === BUDGET_STATUS.RECEIVED) color = 'bg-blue-100 text-blue-800';
  if (status === BUDGET_STATUS.ASSIGNED) color = 'bg-purple-100 text-purple-800';
  if (status === BUDGET_STATUS.CLOSED) color = 'bg-gray-200 text-gray-600';
  return <span className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${color}`}>{status}</span>;
}

function ImageUploadBox({ id, label, isRequired, file, onChange, icon: Icon }) {
  return (
    <div className={`border border-dashed ${file ? 'border-green-400 bg-green-50' : 'border-gray-300 hover:bg-gray-50'} rounded-lg p-2 text-center cursor-pointer h-full flex flex-col items-center justify-center transition-colors`}>
      <input type="file" id={id} className="hidden" onChange={onChange} accept="image/*" />
      <label htmlFor={id} className="cursor-pointer flex flex-col items-center justify-center w-full h-full">
        <Icon className={file ? 'text-green-500' : 'text-gray-400 mb-1'} size={20} />
        <span className="text-[10px] text-gray-600 font-medium leading-tight px-1">
          {file ? 'Telah Dimuatnaik' : label}
          {isRequired && !file && <span className="text-red-500 ml-0.5">*</span>}
        </span>
      </label>
    </div>
  );
}

function ExpenseImageModal({ images, onClose }) {
  if (!images) return null;
  const cell = (img, emptyLabel) => (
    <div className="border rounded-lg p-1.5 flex flex-col items-center justify-center h-32 bg-gray-50 text-center overflow-hidden">
      {img ? (
        <a href={img.view || img.url} target="_blank" rel="noreferrer" className="w-full h-full flex flex-col">
          <img src={img.url} alt={img.name} className="w-full flex-1 object-cover rounded" referrerPolicy="no-referrer" />
          <span className="text-[10px] text-blue-600 truncate w-full mt-1 underline">Lihat penuh</span>
        </a>
      ) : (
        <span className="text-xs text-gray-400">{emptyLabel}</span>
      )}
    </div>
  );
  return (
    <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
      <div className="bg-white rounded-xl shadow-xl w-full max-w-2xl overflow-hidden max-h-[90vh] flex flex-col">
        <div className="px-6 py-4 border-b border-gray-100 flex justify-between items-center bg-gray-50">
          <h3 className="font-bold text-gray-800">Lampiran Resit & Barang</h3>
          <button onClick={onClose} className="text-gray-500 hover:text-gray-700"><X size={20} /></button>
        </div>
        <div className="p-6 overflow-y-auto space-y-6">
          <div>
            <h4 className="font-semibold text-gray-700 mb-3 border-b pb-2">Gambar Resit</h4>
            <div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
              {[1, 2, 3, 4].map(n => <React.Fragment key={`r${n}`}>{cell(images[`resit${n}`], `Tiada Resit ${n}`)}</React.Fragment>)}
            </div>
          </div>
          <div>
            <h4 className="font-semibold text-gray-700 mb-3 border-b pb-2">Gambar Barang</h4>
            <div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
              {[1, 2, 3, 4].map(n => <React.Fragment key={`b${n}`}>{cell(images[`barang${n}`], `Tiada Barang ${n}`)}</React.Fragment>)}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function EditBudgetRecordModal({ budget, onClose, onSave }) {
  const [form, setForm] = useState({ description: budget.description, location: budget.location, amount: budget.amount });
  return (
    <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
      <div className="bg-white rounded-xl shadow-xl w-full max-w-md overflow-hidden">
        <div className="px-6 py-4 bg-yellow-50 border-b border-yellow-100 flex justify-between items-center">
          <h3 className="font-bold text-yellow-900 flex items-center gap-2"><Edit size={18} /> Ubah Rekod Belanjawan</h3>
          <button onClick={onClose} className="text-gray-500 hover:text-gray-700"><X size={20} /></button>
        </div>
        <div className="p-6 space-y-4">
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Keterangan</label>
            <input type="text" value={form.description} onChange={e => setForm({ ...form, description: e.target.value })}
              className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 outline-none" />
          </div>
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Lokasi</label>
            <select className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none"
              value={form.location} onChange={e => setForm({ ...form, location: e.target.value })}>
              {LOCATIONS.map(l => <option key={l} value={l}>{l}</option>)}
            </select>
          </div>
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Jumlah (RM)</label>
            <input type="number" step="0.01" value={form.amount} onChange={e => setForm({ ...form, amount: e.target.value })}
              className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 outline-none font-bold text-lg" />
            <p className="text-xs text-gray-500 mt-1">Mengubah jumlah ini akan mengemaskini baki keseluruhan secara automatik.</p>
          </div>
          <div className="pt-4 flex justify-end gap-3">
            <button onClick={onClose} className="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-lg font-medium">Batal</button>
            <button onClick={() => onSave({ ...budget, ...form })} className="px-4 py-2 bg-yellow-600 hover:bg-yellow-700 text-white rounded-lg font-medium">Simpan Perubahan</button>
          </div>
        </div>
      </div>
    </div>
  );
}

function EditExpenseRecordModal({ expense, onClose, onSave }) {
  const [form, setForm] = useState({ description: expense.description, amount: expense.amount });
  return (
    <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
      <div className="bg-white rounded-xl shadow-xl w-full max-w-md overflow-hidden">
        <div className="px-6 py-4 bg-yellow-50 border-b border-yellow-100 flex justify-between items-center">
          <h3 className="font-bold text-yellow-900 flex items-center gap-2"><Edit size={18} /> Ubah Rekod Perbelanjaan</h3>
          <button onClick={onClose} className="text-gray-500 hover:text-gray-700"><X size={20} /></button>
        </div>
        <div className="p-6 space-y-4">
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Keterangan Barang/Perkhidmatan</label>
            <textarea rows="2" value={form.description} onChange={e => setForm({ ...form, description: e.target.value })}
              className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 outline-none" />
          </div>
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Jumlah Perbelanjaan (RM)</label>
            <input type="number" step="0.01" value={form.amount} onChange={e => setForm({ ...form, amount: e.target.value })}
              className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 outline-none font-bold text-lg" />
            {expense.status === EXPENSE_STATUS.APPROVED && (
              <p className="text-xs text-orange-500 mt-1">Status rekod ini adalah "Diluluskan". Mengubah jumlah akan menjejaskan baki dana yang berkaitan.</p>
            )}
          </div>
          <div className="pt-4 flex justify-end gap-3">
            <button onClick={onClose} className="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-lg font-medium">Batal</button>
            <button onClick={() => onSave({ ...expense, ...form })} className="px-4 py-2 bg-yellow-600 hover:bg-yellow-700 text-white rounded-lg font-medium">Simpan Perubahan</button>
          </div>
        </div>
      </div>
    </div>
  );
}

function ChangePasswordModal({ act, onClose }) {
  const [form, setForm] = useState({ old: '', neu: '', confirm: '' });
  const [error, setError] = useState(null);
  const submit = async (e) => {
    e.preventDefault();
    if (form.neu.length < 8) { setError('Kata laluan baru mestilah sekurang-kurangnya 8 aksara.'); return; }
    if (form.neu !== form.confirm) { setError('Pengesahan kata laluan tidak sepadan.'); return; }
    const ok = await act('change_password', { old: form.old, new: form.neu });
    if (ok) onClose();
  };
  return (
    <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
      <div className="bg-white rounded-xl shadow-xl w-full max-w-md overflow-hidden">
        <div className="px-6 py-4 bg-blue-50 border-b border-blue-100 flex justify-between items-center">
          <h3 className="font-bold text-blue-900 flex items-center gap-2"><Lock size={18} /> Tukar Kata Laluan</h3>
          <button onClick={onClose} className="text-blue-500 hover:text-blue-700"><X size={20} /></button>
        </div>
        <form onSubmit={submit} className="p-6 space-y-4">
          {error && <p className="text-sm text-red-600 bg-red-50 border border-red-100 rounded-lg p-3">{error}</p>}
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Kata Laluan Semasa</label>
            <input type="password" required autoComplete="current-password" value={form.old} onChange={e => setForm({ ...form, old: e.target.value })}
              className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none" />
          </div>
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Kata Laluan Baru (min. 8 aksara)</label>
            <input type="password" required minLength="8" autoComplete="new-password" value={form.neu} onChange={e => setForm({ ...form, neu: e.target.value })}
              className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none" />
          </div>
          <div>
            <label className="block text-sm font-medium text-gray-700 mb-1">Sahkan Kata Laluan Baru</label>
            <input type="password" required minLength="8" autoComplete="new-password" value={form.confirm} onChange={e => setForm({ ...form, confirm: e.target.value })}
              className="w-full border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none" />
          </div>
          <div className="pt-2 flex justify-end gap-3">
            <button type="button" onClick={onClose} className="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-lg font-medium">Batal</button>
            <button type="submit" className="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg font-medium">Simpan</button>
          </div>
        </form>
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
