// Approved — review queue for Submitted records from General Information only.
// Approving/Rejecting writes the status back into finx_expense_requests_v1 plus
// an audit stamp: approvedBy / approvedAt / approveNote.
(function(){

const SOURCES = {
  general: { key:'finx_expense_requests_v1', label:'General Information',  icon:'GrossLayers', hue:'#0f766e' },
};

const readDB  = (k) => { try { return JSON.parse(localStorage.getItem(k)||'{}'); } catch(_){ return {}; } };
const writeDB = (k,db) => { try { localStorage.setItem(k, JSON.stringify(db)); return true; }
  catch(_){ window.toast('บันทึกไม่สำเร็จ — พื้นที่จัดเก็บเต็มหรือถูกบล็อก', {tone:'warn', title:'Storage error'}); return false; } };

const money = n => (Number(n)||0).toLocaleString('en-US',{minimumFractionDigits:2,maximumFractionDigits:2});
const stampDT = iso => { const d = new Date(iso); if (isNaN(d)) return '';
  const p = n => String(n).padStart(2,'0');
  return `${p(d.getDate())}/${p(d.getMonth()+1)}/${d.getFullYear()} ${p(d.getHours())}:${p(d.getMinutes())} น.`; };
const dmy   = v => (window.fmtDMY ? window.fmtDMY(v) : String(v||''));

// One flat queue item per saved record.
function collect(){
  const out = [];
  Object.entries(SOURCES).forEach(([src, meta]) => {
    Object.entries(readDB(meta.key)).forEach(([id, r]) => {
      const status = r.status || 'Draft';
      if (status==='Draft' || status==='Canceled') return;   // drafts are not reviewable
      const rows = r.rows || [];
      const actual   = rows.reduce((s,x)=>s+(Number(x.amount)||0),0);
      const estimate = rows.reduce((s,x)=>s+(Number(x.estimate)||0),0);
      out.push({
        src, id, status,
        owner: r.company || r.companyName || r.channel || '—',
        period: [r.fm, r.fy].filter(Boolean).join(' '),
        date: (r.reqDate||'').slice(0,10),
        items: rows.length,
        actual, estimate,
        note: (r.approveNote==='Bulk approved' ? '' : (r.approveNote||'')),   // legacy bulk stamp is never shown
        by: r.approvedBy || '',
        at: r.approvedAt || '',
        stamp: r.approvedAt || r.submittedAt || r.savedAt || '',
      });
    });
  });
  return out.sort((a,b)=> (a.stamp<b.stamp?1:a.stamp>b.stamp?-1:0));
}

function setStatus(item, status, note){
  const meta = SOURCES[item.src];
  const db = readDB(meta.key);
  const rec = db[item.id];
  if (!rec){ window.toast('ไม่พบรายการในฐานข้อมูล', {tone:'warn', title:'Not found'}); return false; }
  if ((rec.status||'') !== item.status){   // changed elsewhere since this row was rendered
    window.dispatchEvent(new CustomEvent('finx:status-changed'));
    window.toast('รายการนี้ถูกเปลี่ยนสถานะไปแล้ว — ระบบรีเฟรชข้อมูลใหม่', {tone:'warn', title:'Out of date'});
    return false;
  }
  db[item.id] = { ...rec, status,
    approvedBy: window.CURRENT_USER || 'Admin',
    approvedAt: new Date().toISOString(),
    approveNote: note || '' };
  if (!writeDB(meta.key, db)) return false;
  window.logActivity(status+' · '+meta.label+' · '+item.owner, '');
  // Result goes ONLY to the user who submitted the request (fallback: the actor).
  if (window.finxNotify){
    const ok = status==='Approved';
    window.finxNotify({ t: ok?'success':'warn', view:'approved',
      audience: rec.submittedBy || window.CURRENT_USER,
      title:(ok?'อนุมัติแล้ว · ':'ไม่อนุมัติ · ')+item.id,
      msg:[meta.label, item.owner, note?('หมายเหตุ: '+note):''].filter(Boolean).join(' · ') });
  }
  window.dispatchEvent(new CustomEvent('finx:status-changed'));   // refresh sidebar badge
  return true;
}

const STATUS_STYLE = {
  Submitted: { label:'Pending', ink:'#d97706',  bg:'#fef3c7', fg:'#a16207', bd:'#fde68a', icon:'Clock',       tile:'linear-gradient(135deg,#fbbf24,#d97706)', ring:'rgba(245,158,11,.16)' },
  Approved:  { label:'Approved', ink:'#059669', bg:'#dcfce7', fg:'#15803d', bd:'#bbf7d0', icon:'CheckCircle', tile:'linear-gradient(135deg,#34d399,#059669)', ring:'rgba(16,185,129,.14)' },
  Rejected:  { label:'Rejected', ink:'#e11d48', bg:'#fee2e2', fg:'#b91c1c', bd:'#fecaca', icon:'BanCircle',   tile:'linear-gradient(135deg,#fb7185,#e11d48)', ring:'rgba(244,63,94,.14)' },
};

function StatusTag({ status }){
  const s = STATUS_STYLE[status] || STATUS_STYLE.Submitted;
  return (
    <span style={{display:'inline-flex',alignItems:'center',gap:5,padding:'3px 10px',borderRadius:99,background:s.bg,color:s.fg,border:'1px solid '+s.bd,
      fontSize:10,fontWeight:800,textTransform:'uppercase',letterSpacing:'.05em'}}>
      <span style={{width:5,height:5,borderRadius:99,background:'currentColor'}}></span>{s.label}
    </span>
  );
}

// Note-capture dialog used by both Approve and Reject.
function DecisionForm({ item, decision, onDone }){
  const [note, setNote] = useState('');
  const busyRef = React.useRef(false);   // guard against double-click Confirm
  const reject = decision==='Rejected';
  return (
    <div style={{display:'grid',gap:14}}>
      <div style={{padding:'12px 14px',borderRadius:12,border:'1px solid var(--line)',background:'linear-gradient(180deg,#f7f8fc,#fff)',display:'flex',alignItems:'center',gap:12}}>
        <span style={{width:38,height:38,borderRadius:99,flexShrink:0,display:'grid',placeItems:'center',background: reject?'rgba(239,68,68,.12)':'rgba(34,197,94,.14)'}}>
          <span style={{width:26,height:26,borderRadius:99,display:'grid',placeItems:'center',color:'#fff',
            background: reject?'linear-gradient(135deg,#f4526e,#dc2640)':'linear-gradient(135deg,#34d399,#15803d)',
            boxShadow: reject?'0 2px 6px -2px rgba(220,38,64,.5)':'0 2px 6px -2px rgba(21,128,61,.5)'}}>
            {reject ? <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3 4 6v6c0 5 3.4 7.7 8 9 4.6-1.3 8-4 8-9V6z"/><path d="M13.8 9.7l-3.6 3.6"/><path d="M10.2 9.7l3.6 3.6"/></svg> : <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M8.5 12.5l2.5 2.5 4.5-5"/></svg>}
          </span>
        </span>
        <span style={{display:'grid',gap:3,minWidth:0}}>
          <span style={{fontSize:11,letterSpacing:'.07em',textTransform:'uppercase',color:'var(--muted)'}}>{SOURCES[item.src].label}</span>
          <span className="thai" style={{fontWeight:700,fontSize:14}}>{item.owner}</span>
          <span className="mono" style={{fontSize:11.5,color:'var(--muted)'}}>{dmy(item.date)} · {item.items} items · Act. {money(item.actual)} THB</span>
        </span>
      </div>
      <div className="field">
        <label>{reject ? 'เหตุผลที่ไม่อนุมัติ' : 'บันทึกเพิ่มเติม'} {reject && <span className="req">*</span>}</label>
        <textarea className="input" rows={3} value={note} onChange={e=>setNote(e.target.value)}
          placeholder={reject ? 'ระบุเหตุผลเพื่อให้ผู้บันทึกแก้ไข' : 'ไม่จำเป็นต้องระบุ'}
          style={{resize:'vertical',height:'auto',minHeight:76,padding:'10px 12px',font:'inherit',fontSize:13,lineHeight:1.5}}/>
      </div>
      <div className="row" style={{gap:8,justifyContent:'flex-end'}}>
        <button className="btn" onClick={()=>window.closeModal()}>Cancel</button>
        <button className={reject ? 'btn primary' : 'btn success'}
          style={reject?{background:'linear-gradient(135deg,#b91c1c,#ef4444)',borderColor:'#b91c1c'}:undefined}
          onClick={()=>{
            if (reject && !note.trim()){ window.toast('กรุณาระบุเหตุผลที่ไม่อนุมัติ', {tone:'warn', title:'ข้อมูลไม่ครบ'}); return; }
            if (busyRef.current) return;   // guard against double-click
            busyRef.current = true;
            window.closeModal();
            window.showLoading('กำลังบันทึกผลอนุมัติ…');
            setTimeout(()=>{ try {
              if (setStatus(item, decision, note.trim())){
                window.toast((reject?'ไม่อนุมัติรายการแล้ว · ':'อนุมัติรายการแล้ว · ')+item.owner,
                  {tone: reject?'warn':'success', title: reject?'Rejected':'Approved', ttl:3600});
                onDone();
              }
            } finally { window.hideLoading(); busyRef.current = false; } }, 450);
          }}>
          {reject ? <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M15 9l-6 6"/><path d="M9 9l6 6"/></svg> : <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M8.5 12.5l2.5 2.5 4.5-5"/></svg>} {reject ? 'Confirm Reject' : 'Confirm Approve'}
        </button>
      </div>
    </div>
  );
}

function ApprovedView(){
  const clock = useSystemClock();
  const [tick, setTick] = useState(0);
  const [refreshing, setRefreshing] = useState(false);
  const refresh = () => setTick(t=>t+1);
  const all = React.useMemo(()=> collect(), [tick]);

  const [tab, setTab] = useState('Submitted');
  const [srcFilter, setSrcFilter] = useState('');
  const [q, setQ] = useState('');
  const [sel, setSel] = useState([]);
  const bulkRef = React.useRef(false);     // guard against double-fire Bulk approve
  const reopenRef = React.useRef(false);   // guard against double-fire Reopen
  const [page, setPage] = useState(0);
  const PAGE = 8;

  const counts = {
    Submitted: all.filter(r=>r.status==='Submitted').length,
    Approved:  all.filter(r=>r.status==='Approved').length,
    Rejected:  all.filter(r=>r.status==='Rejected').length,
  };
  const pendingValue = all.filter(r=>r.status==='Submitted').reduce((s,r)=>s+r.actual,0);

  const list = all.filter(r =>
    r.status===tab &&
    (!srcFilter || r.src===srcFilter) &&
    (!q.trim() || (r.owner+' '+r.date+' '+dmy(r.date)).toLowerCase().includes(q.trim().toLowerCase())));   // dd/mm/yyyy searchable too
  const pageCount = Math.max(1, Math.ceil(list.length/PAGE));
  const curPage = Math.min(page, pageCount-1);
  const paged = list.slice(curPage*PAGE, curPage*PAGE+PAGE);
  useEffect(()=>{ setPage(0); setSel([]); }, [tab, srcFilter, q, tick]);

  // Stay in sync with decisions written elsewhere (other tab / General Information)
  useEffect(()=>{
    const re = ()=> setTick(t=>t+1);
    window.addEventListener('finx:status-changed', re);
    window.addEventListener('storage', re);
    return ()=>{ window.removeEventListener('finx:status-changed', re); window.removeEventListener('storage', re); };
  }, []);

  const key = r => r.src+'::'+r.id;
  const toggle = r => setSel(s => s.includes(key(r)) ? s.filter(x=>x!==key(r)) : [...s, key(r)]);
  const selItems = list.filter(r => sel.includes(key(r)));

  const decide = (item, decision) => window.openModal({
    title: decision==='Approved'
      ? <span style={{color:'var(--ink)'}}>Approve <span style={{color:'#047857'}}>อนุมัติรายการ ?</span></span>
      : <span style={{color:'var(--ink)'}}>Reject <span style={{color:'#b91c1c'}}>ไม่อนุมัติรายการ ?</span></span>,
    size:'sm',
    message: <DecisionForm item={item} decision={decision} onDone={refresh}/>,
  });

  const bulkApprove = () => {
    if (!selItems.length) return;
    window.confirmDialog({
      title:<span style={{color:'var(--ink)'}}>Approve <span style={{color:'#047857'}}>{selItems.length} รายการ ?</span></span>,
      message:<span style={{fontSize:13,display:'flex',alignItems:'center',gap:12}}>
        <span style={{width:38,height:38,borderRadius:99,flexShrink:0,display:'grid',placeItems:'center',background:'rgba(16,185,129,.16)'}}>
          <span style={{width:26,height:26,borderRadius:99,display:'grid',placeItems:'center',color:'#fff',background:'linear-gradient(135deg,#10b981,#047857)',boxShadow:'0 2px 6px -2px rgba(4,120,87,.5)'}}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M2 13l4 4 8-9"/><path d="M11 15l2 2 9-10"/></svg>
          </span>
        </span>
        <span>ยืนยันการอนุมัติรายการที่เลือกทั้งหมด</span></span>,
      okLabel:'Approve all', cancelLabel:'Cancel', tone:'success',
      okStyle:{background:'linear-gradient(135deg,#10b981,#047857)',color:'#fff',border:'none',boxShadow:'0 6px 16px -8px rgba(4,120,87,.65)'},
      onOk: ()=>{
        if (bulkRef.current) return;   // guard against double-fire
        bulkRef.current = true;
        window.showLoading('กำลังอนุมัติรายการ…', selItems.length+' รายการ');
        setTimeout(()=>{ try {
          let n = 0;
          selItems.forEach(it => { if (setStatus(it,'Approved','')) n++; });
          setSel([]); refresh();
          window.toast(n+' รายการถูกอนุมัติแล้ว', {tone:'success', title:'Bulk approve', ttl:3600});
        } finally { window.hideLoading(); bulkRef.current = false; } }, 450);
      }
    });
  };

  const TABS = [
    ['Submitted','Pending',  counts.Submitted, '#a16207'],
    ['Approved','Approved',  counts.Approved,  '#15803d'],
    ['Rejected','Rejected',  counts.Rejected,  '#b91c1c'],
  ];

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <div className="page-title">Approved</div>
          <div className="page-sub">ตรวจสอบและอนุมัติรายการค่าใช้จ่าย</div>
        </div>
        <div className="row" style={{gap:8}}>
          <button className="btn" disabled={refreshing} onClick={()=>{
            setRefreshing(true);
            window.showLoading('กำลังโหลดข้อมูลล่าสุด…');
            setTimeout(()=>{ try {
              refresh();
            } finally { window.hideLoading(); setRefreshing(false); } }, 700);
          }}><I.Refresh size={14}/> Refresh</button>
          <button className="btn success" disabled={!selItems.length} onClick={bulkApprove} style={!selItems.length?{opacity:.5,cursor:'not-allowed'}:{}}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="M2 13l4 4 8-9"/><path d="M11 15l2 2 9-10"/></svg> Approve selected{selItems.length ? ' ('+selItems.length+')' : ''}
          </button>
        </div>
      </div>

      <div className="kpis" style={{display:'grid',gridTemplateColumns:'repeat(auto-fit,minmax(200px,1fr))',gap:14,marginBottom:18}}>
        {[
          ['Pending review', counts.Submitted+'', 'amber',  'AlertCircle', 'รอการอนุมัติ'],
          ['Approved',       counts.Approved+'',  'green',  'CheckCircle', 'อนุมัติแล้ว'],
          ['Rejected',       counts.Rejected+'',  'red',    'BanCircle',   'ไม่อนุมัติ'],
          ['Pending value',  money(pendingValue), 'blue',   'Coin',        'ยอดเงินรอการอนุมัติ (THB)'],
        ].map(([label,val,tone,ic,sub])=>{
          const Icon = I[ic] || I.Doc;
          return (
            <div key={label} className={'card kpi '+tone} style={{padding:'16px 18px'}}>
              <div className="label"><span>{label}</span><span className="badge"><Icon size={16}/></span></div>
              <div className="value">{val}</div>
              <div style={{marginTop:8,fontSize:11.5,color:'var(--muted)'}}>{sub}</div>
            </div>
          );
        })}
      </div>

      <div className="card elev">
        <div className="card-head" style={{flexWrap:'wrap',gap:12}}>
          <div className="seg">
            {TABS.map(([k,label,n,c])=>(
              <button key={k} className={tab===k?'on':''} onClick={()=>setTab(k)} style={tab===k?{color:c}:undefined}>
                {label} <span style={{opacity:.6}}>({n})</span>
              </button>
            ))}
          </div>
          <div className="row" style={{gap:8,marginLeft:'auto'}}>
            <div className="search" style={{minWidth:190}}>
              <I.Search size={14} stroke="#9aa3c2"/>
              <input placeholder="ค้นหา Company / Request Date" value={q} onChange={e=>setQ(e.target.value)}/>
            </div>
          </div>
        </div>

        <div style={{padding:'14px 18px 18px',display:'grid',gap:10}}>
          {tab==='Submitted' && list.length>0 && (()=>{
            const keys = list.map(key);
            const allSel = keys.every(k=>sel.includes(k));
            const someSel = !allSel && keys.some(k=>sel.includes(k));
            return (
              <div style={{display:'flex',alignItems:'center',gap:10,padding:'2px 4px 4px'}}>
                <button onClick={()=>setSel(allSel ? [] : keys)} aria-label="select all"
                  style={{width:20,height:20,flexShrink:0,borderRadius:6,cursor:'pointer',display:'flex',alignItems:'center',justifyContent:'center',padding:0,lineHeight:0,
                    border: (allSel||someSel) ? 'none' : '1.5px solid #d4dbe8', background: (allSel||someSel) ? '#d97706' : '#fff'}}>
                  {allSel && <svg style={{display:'block'}} width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="3.4" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>}
                  {someSel && <svg style={{display:'block'}} width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="3.4" strokeLinecap="round"><path d="M6 12h12"/></svg>}
                </button>
                <span style={{fontSize:12.5,color:'var(--ink-2)',fontWeight:600,cursor:'pointer'}} onClick={()=>setSel(allSel ? [] : keys)}>
                  {allSel ? 'Deselect all' : 'Select all'} <span style={{color:'var(--muted)',fontWeight:500}}>({list.length} items)</span>
                </span>
                {sel.length>0 && <span style={{fontSize:12,color:'#a16207',fontWeight:600,marginLeft:'auto'}}>{sel.length} selected</span>}
              </div>
            );
          })()}
          {paged.length===0 && (
            <div style={{padding:40,textAlign:'center',color:'var(--muted)',fontSize:13,border:'1px dashed var(--line)',borderRadius:14}}>
              ไม่มีรายการในสถานะนี้
            </div>
          )}
          {paged.map(r => {
            const meta = SOURCES[r.src];
            const ss = STATUS_STYLE[r.status] || STATUS_STYLE.Submitted;
            const StIcon = I[ss.icon] || I.Doc;
            const on = sel.includes(key(r));
            const pending = r.status==='Submitted';
            return (
              <div key={key(r)} style={{display:'flex',alignItems:'center',gap:14,padding:'13px 16px',borderRadius:14,
                border: on ? '1.5px solid #f5d98e' : '1px solid #e5e9f2',
                background: on ? 'linear-gradient(135deg,#fffaf0 0%,#fff 62%)' : '#fff',
                boxShadow: on ? '0 3px 10px -10px rgba(180,120,20,.35)' : '0 1px 2px rgba(15,23,42,.05)'}}>
                {pending && (
                  <button onClick={()=>toggle(r)} aria-label="select"
                    style={{width:20,height:20,flexShrink:0,borderRadius:6,cursor:'pointer',display:'flex',alignItems:'center',justifyContent:'center',padding:0,lineHeight:0,
                      border: on ? 'none' : '1.5px solid #d4dbe8', background: on ? ss.ink : '#fff'}}>
                    {on && <svg style={{display:'block'}} width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="3.4" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>}
                  </button>
                )}
                <div title={ss.label} style={{width:32,height:32,margin:'0 4px',borderRadius:'50%',flexShrink:0,display:'grid',placeItems:'center',color:'#fff',
                  background:ss.tile,boxShadow:'0 0 0 4px '+ss.ring}}>
                  <StIcon size={16} strokeWidth={2.6}/>
                </div>
                <div style={{minWidth:0,flex:1}}>
                  <div className="row" style={{gap:8,alignItems:'center',flexWrap:'wrap'}}>
                    <span className="thai" style={{fontWeight:700,fontSize:13.5}}>{r.owner}</span>
                    <StatusTag status={r.status}/>
                    <span className="chip" style={{fontSize:10.5}}>{meta.label}</span>
                  </div>
                  <div style={{fontSize:11.5,color:'var(--muted)',marginTop:4,display:'flex',gap:6,flexWrap:'wrap'}}>
                    <span className="mono">{dmy(r.date)}</span><span style={{opacity:.4}}>·</span>
                    <span>{r.items} items</span>
                    {r.status!=='Submitted' && r.by && (<><span style={{opacity:.4}}>·</span><span style={{color:ss.fg,fontWeight:600}}>{ss.label} by {r.by}</span>{r.at && <><span style={{opacity:.4}}>·</span><span className="mono">Date {stampDT(r.at)}</span></>}</>)}
                    {r.status==='Submitted' && <><span style={{opacity:.4}}>·</span><span style={{color:ss.fg,fontWeight:600}}>รออนุมัติ</span></>}
                  </div>
                  {r.note && <div style={{fontSize:11.5,color:'var(--ink-2)',marginTop:5,fontStyle:'italic'}}>“{r.note}”</div>}
                </div>
                <div style={{textAlign:'right',flexShrink:0}}>
                  <div className="mono" style={{fontWeight:800,fontSize:13.5,color:'#1f2a8e'}}>{money(r.actual)} <span style={{fontSize:10,opacity:.6}}>THB</span></div>
                  <div className="mono" style={{fontSize:10.5,color:'var(--muted)',marginTop:2}}>Est. {money(r.estimate)} <span style={{fontSize:9.5,opacity:.7}}>THB</span></div>
                </div>
                <div className="row" style={{gap:7,flexShrink:0}}>
                  {pending ? (
                    <>
                      <button className="btn" onClick={()=>decide(r,'Rejected')}
                        style={{padding:'7px 13px',height:30,fontSize:12,color:'#b91c1c',borderColor:'#fecaca',background:'#fff5f5'}}>
                        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M15 9l-6 6"/><path d="M9 9l6 6"/></svg> Reject
                      </button>
                      <button className="btn success" onClick={()=>decide(r,'Approved')}
                        style={{padding:'7px 12px',height:30,fontSize:12}}>
                        <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M8.5 12.5l2.5 2.5 4.5-5"/></svg> Approve
                      </button>
                    </>
                  ) : (
                    <button className="btn" onClick={()=>{
                      window.confirmDialog({
                        title:<span style={{color:'var(--ink)'}}>Reopen <span style={{color:'#2e3bbf'}}>ส่งกลับเพื่อทบทวนอีกครั้ง ?</span></span>,
                        message:<span style={{fontSize:13,display:'flex',alignItems:'center',gap:12}}>
                          <span style={{width:38,height:38,borderRadius:99,flexShrink:0,display:'grid',placeItems:'center',background:'rgba(31,42,142,.12)'}}>
                            <span style={{width:26,height:26,borderRadius:99,display:'grid',placeItems:'center',color:'#fff',background:'linear-gradient(135deg,#5b6bff,#1f2a8e)',boxShadow:'0 2px 6px -2px rgba(31,42,142,.5)'}}>
                              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/><path d="M13.5 10.5l-3 3M10.5 10.5l3 3"/></svg>
                            </span>
                          </span>
                          <span>สถานะจะเปลี่ยนกลับเป็น รออนุมัติ (Pending) เพื่อพิจารณาใหม่</span></span>,
                        okLabel:'Reopen', cancelLabel:'Cancel',
                        onOk: ()=>{
                          if (reopenRef.current) return;   // guard against double-fire
                          reopenRef.current = true;
                          window.showLoading('กำลังส่งกลับสถานะ…');
                          setTimeout(()=>{ try {
                            if (setStatus(r,'Submitted','')) { refresh(); window.toast('ส่งกลับสถานะรออนุมัติแล้ว', {tone:'info', title:'Reopened', ttl:3200}); }
                          } finally { window.hideLoading(); reopenRef.current = false; } }, 450);
                        }
                      });
                    }} style={{padding:'7px 13px',height:30,fontSize:12}}>
                      <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/></svg> Reopen
                    </button>
                  )}
                </div>
              </div>
            );
          })}

          <div className="row" style={{justifyContent:'space-between',alignItems:'center',marginTop:4}}>
            <span style={{fontSize:12.5,color:'var(--muted)'}}>ทั้งหมด {list.length} รายการ</span>
            {pageCount>1 && (
              <div className="row" style={{gap:8,alignItems:'center'}}>
                <button className="btn" disabled={curPage===0} onClick={()=>setPage(curPage-1)} style={{padding:'5px 12px',fontSize:12}}>‹ Previous</button>
                <span style={{fontSize:12.5,color:'var(--muted)'}}>หน้า {curPage+1} / {pageCount}</span>
                <button className="btn" disabled={curPage>=pageCount-1} onClick={()=>setPage(curPage+1)} style={{padding:'5px 12px',fontSize:12}}>Next ›</button>
              </div>
            )}
          </div>
        </div>
      </div>

      <div style={{marginTop:18,color:'var(--muted)',fontSize:12,fontStyle:'italic'}}>{clock}</div>
    </div>
  );
}

window.ApprovedView = ApprovedView;
})();
