// Chart Growth Hub — "My Documents", shown under Account. // // A member's own record of what they have signed: status per document, the // version and date, a downloadable signed copy, and a way to sign anything // outstanding. Read-only over an append-only table — there is no edit path // here by design. // // Depends on portal/agreements.js and portal/agreement-gate.jsx. // Exposes window.MyDocuments({client, session, member, status, onSigned}). (function(){ const { useState, useEffect } = React; const fmtWhen = d => { if(!d) return '—'; try { return new Date(d).toLocaleString(undefined, {year:'numeric', month:'short', day:'numeric', hour:'2-digit', minute:'2-digit'}); } catch(e){ return String(d).slice(0,16).replace('T',' '); } }; (function injectCSS(){ if(document.getElementById('cg-mydocs-css')) return; const s = document.createElement('style'); s.id = 'cg-mydocs-css'; s.textContent = ` .md-row{display:flex;gap:14px;align-items:flex-start;padding:15px 17px;border:1px solid var(--border); border-radius:var(--radius-sm);background:linear-gradient(165deg,var(--surface-2),var(--surface)); flex-wrap:wrap} .md-row.pending{border-color:var(--border-gold); background:linear-gradient(165deg,rgba(212,175,55,.07),transparent 60%),var(--navy-950)} .md-ico{width:36px;height:36px;flex-shrink:0;border-radius:9px;display:grid;place-items:center; border:1px solid var(--border-gold);background:rgba(212,175,55,.08)} .md-ico svg{width:17px;height:17px;fill:none;stroke:var(--gold-2);stroke-width:1.7; stroke-linecap:round;stroke-linejoin:round} .md-title{font-weight:600;font-size:.92rem} .md-sub{font-size:.74rem;color:var(--ink-faint);font-family:var(--font-mono);margin-top:3px} .md-pill{font-size:.66rem;font-family:var(--font-mono);letter-spacing:.05em;text-transform:uppercase; padding:3px 9px;border-radius:999px;border:1px solid var(--border);white-space:nowrap} .md-pill.ok{color:var(--green);border-color:rgba(74,222,128,.35);background:rgba(74,222,128,.07)} .md-pill.no{color:var(--gold-2);border-color:var(--border-gold);background:rgba(212,175,55,.08)} .md-pill.old{color:#f0a35e;border-color:rgba(240,163,94,.4);background:rgba(240,163,94,.08)} .md-act{display:flex;gap:8px;align-items:center;margin-left:auto;flex-wrap:wrap} .md-btn{cursor:pointer;padding:7px 12px;border-radius:8px;border:1px solid var(--border); background:var(--surface);color:var(--ink-dim);font-size:.75rem;font-weight:600;font-family:inherit; display:inline-flex;align-items:center;gap:6px} .md-btn:hover{border-color:var(--border-gold);color:var(--gold-2)} .md-btn svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:1.8; stroke-linecap:round;stroke-linejoin:round} @media(max-width:560px){ .md-act{margin-left:0;width:100%} }`; document.head.appendChild(s); })(); const ICON = ; const DOWN = ; function MyDocuments({client, session, member, status, onSigned}){ const A = window.CG_AGREEMENTS; const [rows,setRows] = useState(null); // latest acceptance per form const [signing,setSigning] = useState(null); const [err,setErr] = useState(''); async function load(){ const { data, error } = await client.from('agreement_acceptances') .select('*').eq('student_id', session.user.id) .order('accepted_at', {ascending:false}); if(error){ setErr(error.message); setRows([]); return; } // Keep only the most recent acceptance per document. Superseded versions // stay in the database as the record of what was agreed at the time, but // showing five rows of the same terms would just be noise here. const latest = {}; (data||[]).forEach(r => { if(!latest[r.form_key]) latest[r.form_key] = r; }); setRows(latest); setErr(''); } useEffect(()=>{ load(); /* eslint-disable-next-line */ },[]); if(!A) return
Documents are loading…
; if(rows === null) return
; function signed(key){ return rows[key] || null; } function state(key){ const r = signed(key); if(!r) return 'none'; return r.version === A.docs[key].version ? 'ok' : 'old'; } const outstanding = A.order.filter(k => state(k) !== 'ok'); return
My documents

The agreements you have signed with Chart Growth Hub. Download a copy for your records at any time. Signed copies cannot be edited or deleted — by you or by us.

{err &&
{err}
} {outstanding.length > 0 &&
You have {outstanding.length}{' '} {outstanding.length===1?'document':'documents'} still to sign.
}
{A.order.map(key => { const doc = A.docs[key]; const r = signed(key); const st = state(key); return
{ICON}
{doc.title}
{st==='ok' && <>SIGNED {fmtWhen(r.accepted_at)} · v{r.version}} {st==='old' && <>SIGNED v{r.version} · UPDATED TO v{doc.version}} {st==='none' && <>NOT YET SIGNED · v{doc.version}}
{st==='ok' ? 'Signed' : st==='old' ? 'Update needed' : 'Not signed'} {r && } {st!=='ok' && }
; })}

“Signed copy” opens a print view — choose Save as PDF in the print dialog to keep it. A copy of every signature is also filed with {A.company.email}.

{signing && window.AgreementGate && setSigning(null)} onDone={(k,v)=>{ setSigning(null); load(); if(onSigned) onSigned(k,v); }}/>}
; } window.MyDocuments = MyDocuments; })();