// Share.jsx - make a link, optionally with a password. function Share({ file, drive, onClose, toast }) { const [links, setLinks] = React.useState([]); const [busy, setBusy] = React.useState(true); const [password, setPassword] = React.useState(''); const [usePassword, setUsePassword] = React.useState(false); const [expiry, setExpiry] = React.useState(''); const [fresh, setFresh] = React.useState(null); const [copied, setCopied] = React.useState(false); const load = React.useCallback(async () => { setBusy(true); try { const r = await api.drive({ op: 'links', drive, path: file.path }); setLinks(r.links || []); } catch (err) { toast('error', err.message); } finally { setBusy(false); } }, [drive, file, toast]); React.useEffect(() => { load(); }, [load]); async function create() { try { const input = { op: 'link-create', drive, path: file.path }; if (usePassword) { if (password.length < 6) { toast('error', 'A share password needs at least 6 characters'); return; } input.password = password; } if (expiry) input.expires_days = Number(expiry); const r = await api.drive(input); // Shown once, because it was never stored: the record id is a hash of // the token. Losing this means making a new link, not recovering it. setFresh(`${window.location.origin}/s/${r.token}`); setPassword(''); setUsePassword(false); load(); } catch (err) { toast('error', err.message); } } async function revoke(l) { if (!window.confirm('Revoke this link? Anyone holding it loses access.')) return; try { await api.drive({ op: 'link-revoke', drive, id: l.id }); toast('ok', 'Link revoked'); load(); } catch (err) { toast('error', err.message); } } function copy() { navigator.clipboard.writeText(fresh).then( () => { setCopied(true); setTimeout(() => setCopied(false), 1800); }, () => toast('error', 'Could not copy; select the link and copy it by hand') ); } return (
e.stopPropagation()}>
Share {file.name}
{fresh ? (

Your link is ready

e.target.select()} className="flex-1 rounded-lg border border-[var(--line)] px-3 py-2 text-xs font-mono" />

Anyone with this link can download the file. It is shown once — it is not stored, so it cannot be shown again.

) : (
{usePassword && ( setPassword(e.target.value)} placeholder="Password to give the recipient" autoComplete="off" className="mt-2 w-full rounded-lg border border-[var(--line)] px-3 py-2 text-sm" /> )}
)}

Existing links

{busy ? (
Loading…
) : links.length === 0 ? (

No links for this file yet.

) : ( links.map(l => (
{l.password_protected ? 'Password protected' : 'Open link'} {l.expires_at ? ` · expires ${l.expires_at.slice(0, 10)}` : ''} {` · ${l.downloads} download${l.downloads === 1 ? '' : 's'}`}
)) )}
); }