/* global React */
const { useState, useEffect, useMemo, useRef } = React;

// Map a server Conversation to the row shape the table expects.
function toRow(c) {
  const iso = c.updatedAt || c.createdAt || '';
  const date = iso.replace('T', ' ').slice(0, 16);
  // currentVersion === 0 means no run has finalised yet — treat as in-flight.
  const currentVersion = c.currentVersion ?? 0;
  const status = currentVersion > 0 ? 'complete' : 'pending';
  const title = (c.title || '').trim();
  return {
    id: c.convoId,
    name: title || c.convoId,
    hasTitle: title.length > 0,
    status,
    score: null,
    cost: null,
    date,
    iso,
    pillars: 6,
    currentVersion,
  };
}

// Fan out to load each completed row's latest version so we can show its
// WAF score and monthly cost in the table. Updates rows individually as
// requests resolve so the UI doesn't block on the slowest one.
function hydrateScoreCost(rows, applyUpdate) {
  for (const row of rows) {
    if (row.status !== 'complete' || row.currentVersion < 1) continue;
    window.API.getConversationVersion(row.id, row.currentVersion)
      .then(snap => applyUpdate(row.id, window.extractScoreCost(snap)))
      .catch(() => { /* leave score/cost as — on failure */ });
  }
}

function bucketAnalyses(rows) {
  const now = new Date();
  const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
  const startOfWeek = startOfToday - 6 * 24 * 60 * 60 * 1000;
  const today = [];
  const week = [];
  const earlier = [];
  for (const r of rows) {
    const t = r.iso ? Date.parse(r.iso) : NaN;
    if (Number.isNaN(t)) { earlier.push(r); continue; }
    if (t >= startOfToday) today.push(r);
    else if (t >= startOfWeek) week.push(r);
    else earlier.push(r);
  }
  return [
    { label: 'Today',     items: today },
    { label: 'This week', items: week },
    { label: 'Earlier',   items: earlier },
  ];
}

/* =========================================================================
   LOGIN
   ========================================================================= */
// Temporary: registrations are closed. Flip to true to re-enable, and
// also clear REGISTRATION_DISABLED in infrastructure/lib/auth-stack.ts.
const REGISTRATION_ENABLED = false;

function LoginScreen() {
  const { signIn, setRoute } = useApp();
  const [mode, setMode] = useState('signin'); // signin | signup | reset
  const [email, setEmail] = useState('');
  const [pw, setPw] = useState('');
  const [givenName, setGivenName] = useState('');
  const [familyName, setFamilyName] = useState('');
  const [show, setShow] = useState(false);
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState(null);
  const [sent, setSent] = useState(false);

  async function submit(e) {
    e.preventDefault();
    if (!window.API?.hasBackend) {
      setError({ code: 'CONFIG', msg: 'Backend is not configured. Set cac-cognito-client-id in index.html.' });
      return;
    }
    setSubmitting(true);
    setError(null);
    try {
      if (mode === 'reset') {
        await window.API.sendPasswordReset(email);
        setSent(true);
      } else if (mode === 'signup') {
        if (!REGISTRATION_ENABLED) {
          setError({ code: 'INVALID', msg: 'Registration is temporarily closed.' });
          setMode('signin');
          return;
        }
        await window.API.signUp(email, pw, {
          givenName: givenName.trim(),
          familyName: familyName.trim(),
        });
        setError({ code: 'UNVERIFIED', msg: 'Account created — check your inbox to verify, then sign in.' });
        setMode('signin');
      } else {
        await window.API.signIn(email, pw);
        signIn();
        setRoute('dashboard');
      }
    } catch (err) {
      const code = err.code === 'UserNotConfirmedException' ? 'UNVERIFIED' : 'INVALID';
      setError({ code, msg: err.message });
    } finally {
      setSubmitting(false);
    }
  }

  const asciiArt =
`  ┌──────────────────────────────────────────┐
  │ cac ▸ converse                           │
  ├──────────────────────────────────────────┤
  │ > parse("ECS Fargate api, RDS postgres") │
  │   ├─ 11 resources                        │
  │   ├─ 14 edges                            │
  │   └─ 0 ambiguous                         │
  │                                          │
  │ > render()                               │
  │   ┌──────────┐     ┌──────────┐          │
  │   │   ALB    │────▶│  ECS×3   │──┐       │
  │   └──────────┘     └──────────┘  │       │
  │                         ┌────────▼──┐    │
  │                         │ RDS (⚠)  │    │
  │                         └───────────┘    │
  │                                          │
  │ > review()                               │
  │   ops  ████████▓░  82 · sec  ███████░░   │
  │   rel  █████▓░░░░  58 · perf ████████▓   │
  │   cost ██████▓░░░  64 · sus  ████████░   │
  │                                          │
  │ > estimate()                             │
  │   €1,284.32 /mo ± 8%                     │
  │   ⚠ 2 hidden line-items detected         │
  └──────────────────────────────────────────┘`;

  return (
    <div className="auth-shell">
      <aside className="auth-art">
        <div>
          <div className="brand" style={{marginBottom: 32}}>
            <span className="brand-mark">{window.Logo ? <window.Logo size={16}/> : 'C'}</span>
            <span>Cloud Architect <span style={{color:'var(--ink-2)'}}>Copilot</span></span>
          </div>
          <pre>{asciiArt}</pre>
        </div>
        <div style={{fontFamily:'var(--font-mono)', fontSize:11, color:'var(--ink-3)', lineHeight:1.8}}>
          <div>v 0.14.2 · eu-west-1</div>
          <div>— describe it. diagram it. defend it. —</div>
        </div>
      </aside>
      <main className="auth-form-wrap">
        <form className="auth-form" onSubmit={submit}>
          <div className="label" style={{marginBottom:8}}>
            {mode === 'signin' && '— sign in —'}
            {mode === 'signup' && '— create account —'}
            {mode === 'reset'  && '— reset password —'}
          </div>
          <h2>
            {mode === 'signin' && 'Welcome back.'}
            {mode === 'signup' && 'Get started.'}
            {mode === 'reset'  && 'Reset your password.'}
          </h2>
          <div className="sub">
            {mode === 'signin' && 'Discuss AWS architectures from plain language or IaC.'}
            {mode === 'signup' && '3 free conversations per month, no credit card required.'}
            {mode === 'reset'  && 'We\'ll send a reset link to your inbox.'}
          </div>

          {sent ? (
            <div className="card" style={{padding:'16px', background:'var(--ok-soft)', borderColor:'color-mix(in srgb, var(--ok) 30%, transparent)'}}>
              <div style={{display:'flex', gap:10, alignItems:'flex-start'}}>
                <Icon name="check" size={16} />
                <div>
                  <div style={{fontWeight:600, fontSize:13}}>Check your inbox</div>
                  <div style={{fontSize:12.5, color:'var(--ink-2)', marginTop:4}}>If an account exists for <b className="mono">{email}</b>, a reset link is on its way.</div>
                </div>
              </div>
              <button type="button" className="btn" style={{marginTop:12}} onClick={() => { setMode('signin'); setSent(false); }}>Back to sign in</button>
            </div>
          ) : (
            <>
              {mode === 'signup' && (
                <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:12}}>
                  <FormRow label="First name">
                    <input className="field" type="text" required autoComplete="given-name" value={givenName} onChange={e => setGivenName(e.target.value)} placeholder="Ada" />
                  </FormRow>
                  <FormRow label="Last name">
                    <input className="field" type="text" required autoComplete="family-name" value={familyName} onChange={e => setFamilyName(e.target.value)} placeholder="Lovelace" />
                  </FormRow>
                </div>
              )}
              <FormRow label="Email">
                <div style={{position:'relative'}}>
                  <input className={`field ${error?.code==='INVALID'?'error':''}`} style={{paddingLeft: 32}} type="email" required value={email} onChange={e => setEmail(e.target.value)} placeholder="you@company.com" />
                  <div style={{position:'absolute', left:10, top:0, bottom:0, display:'grid', alignItems:'center', color:'var(--ink-3)'}}>
                    <Icon name="mail" size={14} />
                  </div>
                </div>
              </FormRow>
              {mode !== 'reset' && (
                <FormRow label="Password" right={mode === 'signin' ? (
                  <button type="button" className="btn ghost sm" onClick={() => setMode('reset')} style={{padding:'0 4px', height:'auto', fontSize:11.5, color:'var(--ink-2)'}}>Forgot?</button>
                ) : null}>
                  <div style={{position:'relative'}}>
                    <input className={`field ${error?.code==='INVALID'?'error':''}`} type={show ? 'text' : 'password'} required value={pw} onChange={e => setPw(e.target.value)} placeholder={mode === 'signup' ? 'min. 12 characters' : '••••••••••••'} />
                    <button type="button" className="btn ghost sm" onClick={() => setShow(s => !s)} style={{position:'absolute', right:4, top:4, color:'var(--ink-3)'}}>
                      <Icon name={show?'eyeoff':'eye'} size={13}/>
                    </button>
                  </div>
                </FormRow>
              )}

              {error?.code === 'INVALID' && (
                <div style={{display:'flex', gap:8, alignItems:'flex-start', padding:'10px 12px', border:'1px solid color-mix(in srgb, var(--err) 30%, transparent)', background:'var(--err-soft)', borderRadius:4, color:'var(--err)', fontSize:12.5, marginBottom: 12}}>
                  <Icon name="warn" size={13}/>
                  <span>{error.msg}</span>
                </div>
              )}
              {error?.code === 'UNVERIFIED' && (
                <div style={{padding:'12px', border:'1px solid color-mix(in srgb, var(--warn) 30%, transparent)', background:'var(--warn-soft)', borderRadius:4, color:'var(--warn)', fontSize:12.5, marginBottom:12}}>
                  <div style={{display:'flex', gap:8, alignItems:'center', fontWeight:600}}><Icon name="warn" size={13}/>Email not verified</div>
                  <div style={{marginTop:4, color:'var(--ink-2)'}}>Check <b className="mono">{email}</b> for the verification link, or <button type="button" style={{textDecoration:'underline'}}>resend</button>.</div>
                </div>
              )}

              <button type="submit" className="btn accent lg" style={{width:'100%', justifyContent:'center'}} disabled={submitting}>
                {submitting ? <span className="spinner" /> : null}
                {mode === 'signin' && 'Sign in'}
                {mode === 'signup' && 'Create account'}
                {mode === 'reset'  && 'Send reset link'}
              </button>

              <div style={{marginTop: 16, display:'flex', justifyContent:'space-between', alignItems:'center', fontSize:12.5, color:'var(--ink-2)'}}>
                {mode === 'signin' && (REGISTRATION_ENABLED
                  ? <>No account? <button type="button" onClick={() => setMode('signup')} style={{fontWeight:500, color:'var(--ink-0)'}}>Create one →</button></>
                  : <span style={{color:'var(--ink-3)'}}>Registrations are temporarily closed.</span>
                )}
                {mode === 'signup' && <>Already have one? <button type="button" onClick={() => setMode('signin')} style={{fontWeight:500, color:'var(--ink-0)'}}>Sign in →</button></>}
                {mode === 'reset'  && <button type="button" onClick={() => setMode('signin')} style={{color:'var(--ink-0)'}}>← Back to sign in</button>}
              </div>

            </>
          )}
        </form>
      </main>
    </div>
  );
}
function FormRow({ label, right, children }) {
  return (
    <div style={{marginBottom: 14}}>
      <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom: 6}}>
        <span className="label">{label}</span>
        {right}
      </div>
      {children}
    </div>
  );
}
window.LoginScreen = LoginScreen;

/* =========================================================================
   ONE-TIME PROFILE SETUP
   Shown automatically the first time a user signs in without given_name /
   family_name claims (e.g. accounts created before the signup form
   collected them). Skipping persists for the session only.
   ========================================================================= */
const PROFILE_SKIP_KEY = 'cac.profile-setup-skipped';

function profileSetupNeeded(user) {
  if (!user) return false;
  if (sessionStorage.getItem(PROFILE_SKIP_KEY) === '1') return false;
  return !user.firstName || !user.name || user.name === user.email;
}
window.profileSetupNeeded = profileSetupNeeded;

function ProfileSetup() {
  const { user, refreshUser, setRoute } = useApp();
  const [given, setGiven] = useState('');
  const [family, setFamily] = useState('');
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState(null);

  async function submit(e) {
    e.preventDefault();
    setSubmitting(true);
    setError(null);
    try {
      await window.API.updateProfile({ givenName: given.trim(), familyName: family.trim() });
      refreshUser();
      sessionStorage.removeItem(PROFILE_SKIP_KEY);
      setRoute('dashboard');
    } catch (err) {
      setError(err.message || 'Could not save your name.');
    } finally {
      setSubmitting(false);
    }
  }

  function skip() {
    sessionStorage.setItem(PROFILE_SKIP_KEY, '1');
    setRoute('dashboard');
  }

  return (
    <div className="page" style={{maxWidth: 560}}>
      <div className="page-head">
        <div>
          <div className="eyebrow">welcome</div>
          <h1 className="display">What should we call you?</h1>
          <div className="meta">Signed in as <b className="mono">{user?.email}</b>. We'll use your name in greetings and exports.</div>
        </div>
      </div>
      <form onSubmit={submit} className="card" style={{padding:20}}>
        <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:12}}>
          <FormRow label="First name">
            <input className="field" type="text" required autoFocus autoComplete="given-name" value={given} onChange={e => setGiven(e.target.value)} placeholder="Ada"/>
          </FormRow>
          <FormRow label="Last name">
            <input className="field" type="text" required autoComplete="family-name" value={family} onChange={e => setFamily(e.target.value)} placeholder="Lovelace"/>
          </FormRow>
        </div>
        {error && (
          <div style={{display:'flex', gap:8, alignItems:'flex-start', padding:'10px 12px', border:'1px solid color-mix(in srgb, var(--err) 30%, transparent)', background:'var(--err-soft)', borderRadius:4, color:'var(--err)', fontSize:12.5, marginBottom: 12}}>
            <Icon name="warn" size={13}/><span>{error}</span>
          </div>
        )}
        <div style={{display:'flex', gap:8, marginTop:8}}>
          <button type="submit" className="btn accent" disabled={submitting}>
            {submitting ? <span className="spinner"/> : null}
            Save
          </button>
          <button type="button" className="btn" onClick={skip} disabled={submitting}>Skip for now</button>
        </div>
      </form>
    </div>
  );
}
window.ProfileSetup = ProfileSetup;

/* =========================================================================
   DASHBOARD
   ========================================================================= */
function Dashboard() {
  const { tier, setRoute, user, usageCount, analysesLimit, quotaExceeded: ctxQuotaExceeded } = useApp();

  const quotaByTier = { free: 3, pro: 25, team: 100, enterprise: Infinity, admin: Infinity };
  const quota = Number.isFinite(analysesLimit) ? analysesLimit : (quotaByTier[tier] ?? quotaByTier.free);
  const unlimited = !Number.isFinite(quota);

  const now = new Date();
  const hour = now.getHours();
  const greeting = hour < 12 ? 'Good morning' : hour < 18 ? 'Good afternoon' : 'Good evening';
  const greetName = user?.firstName || user?.name || '';
  const monthYear = now.toLocaleString(undefined, { month: 'long', year: 'numeric' });

  const [analyses, setAnalyses] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [page, setPage] = useState(1);
  const [pageSize, setPageSize] = window.usePersistedPageSize('dashboard');
  useEffect(() => {
    let cancelled = false;
    window.API.listConversations(200)
      .then(r => {
        if (cancelled) return;
        const rows = (r.items || []).map(toRow);
        setAnalyses(rows);
        hydrateScoreCost(rows, (id, patch) => {
          if (cancelled) return;
          setAnalyses(prev => prev.map(row => row.id === id ? { ...row, ...patch } : row));
        });
      })
      .catch(e => { if (!cancelled) setError(e.message); })
      .finally(() => { if (!cancelled) setLoading(false); });
    return () => { cancelled = true; };
  }, []);

  const totalPages = Math.max(1, Math.ceil(analyses.length / pageSize));
  const safePage = Math.min(page, totalPages);
  const pageItems = analyses.slice((safePage - 1) * pageSize, safePage * pageSize);

  // `used` is the authoritative this-month count from /user (server-tracked
  // in the usage table). Fall back to the conversation list length only when
  // the /user response hasn't loaded yet — never use it as the truth source,
  // since lifetime conversations ≠ monthly analyses.
  const used = typeof usageCount === 'number' ? usageCount : analyses.length;
  const pct = unlimited ? 0 : Math.min(100, (used / quota) * 100);
  const quotaExceeded = ctxQuotaExceeded || (used >= quota && tier === 'free');

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <div className="eyebrow">dashboard · {monthYear.toLowerCase()}</div>
          <h1 className="marketing-display" style={{fontSize:44, fontWeight:400, margin:0}}>{greeting}{greetName ? `, ${greetName}` : ''}.</h1>
          <div className="meta">{unlimited ? <>You have <b className="mono">unlimited</b> conversations.</> : <>You have <b className="mono">{quota - used}</b> conversations remaining this billing month.</>}</div>
        </div>
        <div style={{display:'flex', gap:8}}>
          <button className="btn accent lg" onClick={() => setRoute('new')} disabled={quotaExceeded}>
            <Icon name="plus" size={13}/>New chat
          </button>
        </div>
      </div>

      {/* Quota exceeded banner */}
      {quotaExceeded && (
        <div className="card" style={{padding:16, marginBottom: 24, background:'var(--err-soft)', borderColor:'color-mix(in srgb, var(--err) 30%, transparent)'}}>
          <div style={{display:'flex', alignItems:'flex-start', gap:14}}>
            <Icon name="warn" size={16} className="diag-err" />
            <div style={{flex:1}}>
              <div style={{fontWeight:600, fontSize:13.5, color:'var(--err)'}}>Free-tier quota reached</div>
              <div style={{color:'var(--ink-2)', fontSize:12.5, marginTop:4}}>You've used all 3 conversations for this month. Upgrade to Pro for 25/mo, full pipeline, and PDF export.</div>
            </div>
            <UpgradeCta className="btn accent" label="Upgrade"/>
          </div>
        </div>
      )}

      {/* Stats row */}
      <div className="bento cols-4" style={{marginBottom: 24}}>
        <div className="stat">
          <div className="label">Conversations used</div>
          <div className="val">{used}<span className="unit">/ {unlimited ? <span className="infinity">∞</span> : quota}</span></div>
          {!unlimited && <div className="bar"><span style={{width: `${pct}%`, background: pct > 90 ? 'var(--err)' : pct > 70 ? 'var(--warn)' : 'var(--accent)'}} /></div>}
          <div className="sub">{unlimited ? 'no monthly cap' : <>resets on <b className="mono">2026-05-01</b></>}</div>
        </div>
        <div className="stat">
          <div className="label">Current plan</div>
          <div className="val" style={{textTransform:'capitalize', fontSize: 20, letterSpacing:'-0.01em'}}>{TIER_LABEL[tier]}</div>
          <div className="sub">
            {tier === 'free' ? '€0/mo — 3 conversations' : tier === 'pro' ? '€29/mo — 25 conversations' : tier === 'team' ? '€79/mo — 100 conversations' : tier === 'admin' ? 'Unlimited · all features' : 'Custom SLAs'}
          </div>
          <button className="btn sm" style={{marginTop:12}} onClick={() => setRoute('pricing')}>
            {tier === 'free' ? 'Upgrade' : 'Manage plan'}
          </button>
        </div>
        <div className="stat">
          <div className="label">Conversations (total)</div>
          <div className="val">{loading ? '—' : analyses.length}</div>
          <div className="sub">{loading ? 'Loading…' : (error || 'across all time')}</div>
        </div>
        <div className="stat">
          <div className="label">Last activity</div>
          <div className="val" style={{fontSize:18, letterSpacing:'-0.01em'}}>
            {loading ? '—' : (analyses[0]?.date || 'No runs yet')}
          </div>
          <div className="sub">{loading ? '' : (analyses[0]?.name || 'Start a new chat to begin')}</div>
        </div>
      </div>

      {/* Recent conversations */}
      <div className="card">
        <div className="card-header">
          <div style={{display:'flex', alignItems:'center', gap:10}}>
            <div className="label">Conversations</div>
            {analyses.length > 0 && <span className="pill ghost">{analyses.length}</span>}
          </div>
          <div style={{display:'flex', gap:6, alignItems:'center'}}>
            <div style={{position:'relative'}}>
              <input className="field" placeholder="Search by name, tag, or ID…" style={{height:26, fontSize:12, width:240, paddingLeft:28}}/>
              <div style={{position:'absolute', left:8, top:0, bottom:0, display:'grid', alignItems:'center', color:'var(--ink-3)'}}><Icon name="list" size={11}/></div>
            </div>
            <button className="btn sm"><Icon name="tag" size={11}/>Tags</button>
            <button className="btn sm ghost" style={{color:'var(--ink-2)'}}>Status</button>
            <button className="btn sm ghost" style={{color:'var(--ink-2)'}}>Archive</button>
          </div>
        </div>
        {analyses.length === 0 ? (
          <div style={{padding:'48px 24px'}}>
            <div className="empty" style={{border:0, background:'transparent', padding:0}}>
              <pre className="glyph">{`    ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
    │                           │
    │    no conversations yet   │
    │                           │
    └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘`}</pre>
              <div style={{fontSize:14, color:'var(--ink-1)', fontWeight:500, marginBottom:4}}>Start with a description</div>
              <div style={{fontSize:12.5, color:'var(--ink-2)', maxWidth: 420, margin:'0 auto 16px'}}>Paste a paragraph describing your AWS setup, or drop in Terraform. We'll diagram it, review it against Well-Architected, and quote it.</div>
              <button className="btn accent" onClick={() => setRoute('new')}><Icon name="plus" size={13}/>Create your first conversation</button>
              <div style={{marginTop:24, display:'flex', gap:8, justifyContent:'center', flexWrap:'wrap'}}>
                {['3-tier web app', 'Event-driven API', 'Data lake', 'Multi-region DR'].map(ex => (
                  <button key={ex} className="btn sm" onClick={() => setRoute('new')} style={{color:'var(--ink-2)'}}>
                    <span style={{fontFamily:'var(--font-mono)', color:'var(--ink-3)', marginRight:4}}>▸</span>{ex}
                  </button>
                ))}
              </div>
            </div>
          </div>
        ) : (
          <div>
            {bucketAnalyses(pageItems).map((g, gi) => g.items.length === 0 ? null : (
              <div key={gi}>
                <div style={{padding:'10px 16px', background:'var(--bg-1)', borderBottom:'1px solid var(--line)', display:'flex', alignItems:'center', gap:8}}>
                  <div className="label" style={{margin:0}}>— {g.label} —</div>
                  <span className="pill ghost">{g.items.length}</span>
                </div>
                <table className="tbl">
                  <tbody>
                    {g.items.map(a => (
                      <tr key={a.id} style={{cursor:'pointer'}} onClick={() => setRoute('detail', { id: a.id })}>
                        <td style={{width:'42%'}}>
                          <div style={{display:'flex', alignItems:'center', gap:10}}>
                            {a.hasTitle && <span style={{fontFamily:'var(--font-mono)', color:'var(--ink-3)', fontSize:11}}>{a.id}</span>}
                            <span style={{fontWeight:500}}>{a.name}</span>
                          </div>
                        </td>
                        <td>
                          {a.status === 'complete' && <span className="pill ok"><span className="dot" style={{background:'var(--ok)'}}/>complete</span>}
                          {a.status === 'failed'   && <span className="pill err"><span className="dot" style={{background:'var(--err)'}}/>failed</span>}
                        </td>
                        <td className="mono">{a.score ?? '—'}</td>
                        <td className="mono">{a.cost ? `€${a.cost.toFixed(2)}` : '—'}</td>
                        <td className="mono" style={{color:'var(--ink-2)', fontSize:11.5}}>{a.date}</td>
                        <td style={{textAlign:'right'}}><Icon name="chev" size={14} className="diag-edge" /></td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            ))}
            <window.Pagination
              total={analyses.length}
              page={safePage}
              pageSize={pageSize}
              onPage={setPage}
              onPageSize={n => { setPageSize(n); setPage(1); }}
            />
          </div>
        )}
      </div>
    </div>
  );
}
window.Dashboard = Dashboard;
