// Providers & sharing — live data from the vault-sharing API. // Source: GET /api/v1/vault/sharing (returns active VaultSharing rows). const Providers = () => { const [tab, setTab] = React.useState('providers'); const [providers, setProviders] = React.useState(null); const [error, setError] = React.useState(null); React.useEffect(() => { let dead = false; (async () => { try { const r = await fetch(window.CHVault.apiRoot + '/api/v1/vault/sharing', { credentials: 'include', headers: { 'Accept': 'application/json' }, }); if (r.status === 404) { if (!dead) setProviders([]); return; } if (!r.ok) throw new Error('sharing-' + r.status); const j = await r.json(); if (!dead) setProviders(Array.isArray(j) ? j : (j.shares || j.providers || [])); } catch (e) { if (!dead) { setError(e.message || String(e)); setProviders([]); } } })(); return () => { dead = true; }; }, []); const renderProviders = () => (
{providers === null && (
Loading vault-sharing records…
)} {providers && providers.length === 0 && (
No active provider grants.
When you authorize a clinic or clinician to read part of your vault, the grant will appear here with full scope detail. Revocation is one click and immediate.
)} {providers && providers.map((p, i) => (
{p.clinic_name || p.provider_name || 'Clinic ' + (p.clinic_id || '').slice(0,8)}
{p.provider_role || 'provider'}
granted {p.consent_date ? new Date(p.consent_date).toLocaleDateString() : '—'} {p.last_accessed && last access {new Date(p.last_accessed).toLocaleString()}}
Vault scope: {(p.shared_categories || []).join(', ') || 'none'}
))}
); async function revokeShare(id) { if (!id || !confirm('Revoke this share? The provider will lose vault access immediately.')) return; try { await fetch(window.CHVault.apiRoot + '/api/v1/vault/sharing/' + id, { method: 'DELETE', credentials: 'include', headers: { 'X-CSRF-Token': document.cookie.match(/csrf_token=([^;]+)/)?.[1] || '' }, }); setProviders((cur) => (cur || []).filter(p => p.id !== id)); } catch (e) { alert('Revoke failed: ' + e.message); } } return (
Providers & Sharing

Who has read access, and why.

Every grant is scoped, revocable, and audited live from your vault. Revocation is one click and immediate.
{[['providers', 'Active grants']].map(([id, label]) => ( ))}
{renderProviders()}
); }; window.Providers = Providers;