Files
study-bible-project/src/components/ShareOutlineSheet.jsx
T
nmemmertandClaude Sonnet 5.5 d7a1601f80 Outline: share as a read-only link
- Share on the Outline page opens a sheet: create / copy / turn off a
  read-only link, share the link with the system share sheet, or send the
  outline as text
- The link has its own token (separate from the whole-study share link) and
  the public endpoint returns only the outlines, rebuilt field by field:
  no observations, interpretations, applications, scripts or word notes
- Opening the link shows the outline(s) with no sign-in, a switcher between
  the whole-study and per-chunk outlines, and Print / PDF
- New outline_share_token column (added automatically on start)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 16:02:40 -04:00

67 lines
4.2 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Share an outline: a read-only link anyone can open (no account), or the plain text.
import { useState } from 'react';
import Sheet from './reader/Sheet.jsx';
import { useToast } from './Toasts.jsx';
import { useOutlineShareLink } from '../hooks/useOutlineShareLink.js';
import { shareOutline } from '../utils/outlineExport.js';
const btn = 'rounded-xl border border-[var(--r-line)] px-3.5 py-2 text-sm hover:bg-black/5 disabled:opacity-50';
export default function ShareOutlineSheet({ open, onClose, projectId, outline }) {
const { toast } = useToast();
const link = useOutlineShareLink(projectId, open);
const [copied, setCopied] = useState(false);
const copyLink = async () => {
try { await navigator.clipboard.writeText(link.url); setCopied(true); window.setTimeout(() => setCopied(false), 2000); } catch { toast('Couldn’t copy. Select the link and copy it.', { tone: 'error' }); }
};
// The phone/computer share sheet, with the link (falls back to copying it)
const shareLink = async () => {
if (navigator.share) {
try { await navigator.share({ title: `${outline.title} — Outline`, url: link.url }); return; } catch (err) { if (err?.name === 'AbortError') return; }
}
copyLink();
};
const shareText = async () => {
const result = await shareOutline(outline);
if (result === 'copied') toast('Outline copied. Paste it into a message or email.');
else if (result === 'failed') toast('Couldn’t share or copy the outline.', { tone: 'error' });
};
return (
<Sheet open={open} onClose={onClose} title="Share this outline">
<h3 className="text-sm font-medium">Read-only link</h3>
<p className="mb-3 mt-1 text-xs text-[var(--r-sub)]">
Anyone with the link can read this study’s outlines (the whole-study one and each chunk’s), and print them. They can’t edit anything, and they can’t see your notes or scripts. No account needed.
</p>
{link.state === 'loading' && <p className="text-sm text-[var(--r-sub)]">Checking…</p>}
{link.state === 'unavailable' && (
<p className="rounded-xl border border-[var(--r-line)] px-3 py-2 text-sm text-[var(--r-sub)]">Links need your account and a connection to the server. You can still share the text below.</p>
)}
{link.state === 'ready' && (link.token ? (
<div className="space-y-2">
<div className="flex items-center gap-2">
<input readOnly aria-label="Outline link" value={link.url} onFocus={(e) => e.target.select()}
className="min-w-0 flex-1 truncate rounded-lg border border-[var(--r-line)] bg-[var(--r-bg)] px-3 py-2 text-xs text-[var(--r-sub)]" />
<button type="button" onClick={copyLink} className="shrink-0 rounded-lg bg-[var(--r-accent)] px-4 py-2 text-xs font-medium text-[var(--r-on)]">{copied ? 'Copied!' : 'Copy'}</button>
</div>
<div className="flex flex-wrap items-center gap-3">
<button type="button" onClick={shareLink} className={btn}>Share link…</button>
<button type="button" onClick={link.turnOff} disabled={link.busy} className="text-xs text-[var(--r-danger,#b42318)] hover:underline">{link.busy ? 'Turning off…' : 'Turn off link'}</button>
</div>
<p className="text-[11px] text-[var(--r-sub)]">People see the version that last synced to your account, and it updates as you edit. Turning the link off stops it working right away.</p>
</div>
) : (
<button type="button" onClick={link.create} disabled={link.busy} className="rounded-xl bg-[var(--r-accent)] px-4 py-2 text-sm font-medium text-[var(--r-on)] hover:opacity-90 disabled:opacity-50">{link.busy ? 'Creating…' : 'Create read-only link'}</button>
))}
{link.error && <p role="alert" className="mt-2 text-xs text-[var(--r-danger,#b42318)]">{link.error}</p>}
<div className="mt-5 border-t border-[var(--r-line)] pt-4">
<h3 className="text-sm font-medium">Or send the text</h3>
<p className="mb-2 mt-1 text-xs text-[var(--r-sub)]">The outline you’re looking at, as plain text, to paste into a message or email.</p>
<button type="button" onClick={shareText} className={btn}>Share as text</button>
</div>
</Sheet>
);
}