src/pages/SharedViewPage.jsx (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
import { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import EditorLayout from '../components/EditorLayout.jsx';
import StatusBadge from '../components/StatusBadge.jsx';
import { ApiError, fetchViewDocument, friendlyErrorMessage } from '../lib/api.js';
import { downloadDocument } from '../lib/download.js';
import { STR } from '../lib/strings.js';
import LinkErrorPage from './LinkErrorPage.jsx';
export default function SharedViewPage() {
const { token } = useParams();
const [doc, setDoc] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
let cancelled = false;
(async () => {
setLoading(true);
setError(null);
try {
const data = await fetchViewDocument(token);
if (!cancelled) setDoc(data);
} catch (err) {
if (!cancelled) setError(err);
} finally {
if (!cancelled) setLoading(false);
}
})();
return () => {
cancelled = true;
};
}, [token]);
if (loading) {
return (
<div className="app">
<p className="page-loading">{STR.LOADING_DOCUMENT}</p>
</div>
);
}
if (error instanceof ApiError) {
if (error.status === 410) {
return (
<LinkErrorPage
title={STR.LINK_EXPIRED_TITLE}
message={STR.LINK_EXPIRED_VIEW}
/>
);
}
if (error.status === 404) {
return (
<LinkErrorPage
title={STR.DOCUMENT_NOT_FOUND_TITLE}
message={friendlyErrorMessage(error)}
/>
);
}
}
if (error || !doc) {
return (
<LinkErrorPage
title={STR.LOAD_ERROR_TITLE}
message={friendlyErrorMessage(error)}
/>
);
}
const saveLabel = doc.mode === 'org' ? STR.DOWNLOAD_ORG : STR.DOWNLOAD_MD;
return (
<div className="app">
<header className="app-header">
<div className="app-header-text">
<div className="app-header-top">
<h1 className="app-title">{doc.title}</h1>
<StatusBadge variant="shared">{STR.BADGE_SHARED}</StatusBadge>
<StatusBadge variant="readonly">{STR.BADGE_READONLY}</StatusBadge>
</div>
<p className="app-subtitle">{STR.SHARED_VIEW}</p>
</div>
<div className="toolbar">
<button
type="button"
className="btn"
onClick={() => downloadDocument(doc.content, doc.mode, doc.title)}
>
{saveLabel}
</button>
</div>
</header>
<EditorLayout mode={doc.mode} content={doc.content} previewOnly showEditor={false} />
<footer className="app-footer">
<p className="app-meta">{STR.FOOTER_SHARED}</p>
</footer>
</div>
);
}
|