chore: fixed now updates
58b705b0
1 file(s) · +63 −53
| 10 | 10 | const DID = "did:plc:ia2zdnhjaokf5lazhxrmj6eu"; |
|
| 11 | 11 | const PDS_URL = "https://polybius.social"; |
|
| 12 | 12 | ||
| 13 | - | interface Record { |
|
| 13 | + | interface Document { |
|
| 14 | 14 | uri: string; |
|
| 15 | - | value: any; |
|
| 15 | + | value: { |
|
| 16 | + | title: string; |
|
| 17 | + | publishedAt: string; |
|
| 18 | + | path: string; |
|
| 19 | + | content?: { |
|
| 20 | + | markdown?: string; |
|
| 21 | + | }; |
|
| 22 | + | textContent?: string; |
|
| 23 | + | }; |
|
| 16 | 24 | } |
|
| 17 | 25 | ||
| 18 | 26 | export default function NowUpdates() { |
|
| 19 | - | const [content, setContent] = useState<string>("<p>Loading...</p>"); |
|
| 27 | + | const [documents, setDocuments] = useState<Document[]>([]); |
|
| 28 | + | const [loading, setLoading] = useState(true); |
|
| 29 | + | const [error, setError] = useState(false); |
|
| 20 | 30 | ||
| 21 | 31 | useEffect(() => { |
|
| 22 | 32 | async function fetchPosts() { |
|
| 23 | 33 | try { |
|
| 24 | - | // Fetch site.standard.document records only |
|
| 25 | 34 | const documentsData = await fetch( |
|
| 26 | 35 | `${PDS_URL}/xrpc/com.atproto.repo.listRecords?` + |
|
| 27 | 36 | new URLSearchParams({ |
|
| 33 | 42 | .then((res) => (res.ok ? res.json() : { records: [] })) |
|
| 34 | 43 | .catch(() => ({ records: [] })); |
|
| 35 | 44 | ||
| 36 | - | const documents: Record[] = (documentsData.records || []).sort( |
|
| 37 | - | (a: Record, b: Record) => { |
|
| 45 | + | const sortedDocuments: Document[] = (documentsData.records || []).sort( |
|
| 46 | + | (a: Document, b: Document) => { |
|
| 38 | 47 | const dateA = new Date(a.value.publishedAt); |
|
| 39 | 48 | const dateB = new Date(b.value.publishedAt); |
|
| 40 | - | return dateB.getTime() - dateA.getTime(); // Most recent first |
|
| 49 | + | return dateB.getTime() - dateA.getTime(); |
|
| 41 | 50 | }, |
|
| 42 | 51 | ); |
|
| 43 | 52 | ||
| 44 | - | if (documents.length === 0) { |
|
| 45 | - | setContent("<p>No recent updates found.</p>"); |
|
| 46 | - | return; |
|
| 47 | - | } |
|
| 48 | - | ||
| 49 | - | const postsHTML = documents |
|
| 50 | - | .map((record) => { |
|
| 51 | - | const value = record.value; |
|
| 52 | - | const path = record.value.path.slice(1) |
|
| 53 | - | const publishedAt = new Date( |
|
| 54 | - | value.publishedAt, |
|
| 55 | - | ).toLocaleDateString(); |
|
| 56 | - | ||
| 57 | - | // Extract markdown content |
|
| 58 | - | let contentHTML = ""; |
|
| 59 | - | if (value.content && value.content.markdown) { |
|
| 60 | - | contentHTML = md.render(value.content.markdown); |
|
| 61 | - | } else if (value.textContent) { |
|
| 62 | - | contentHTML = `<p>${value.textContent}</p>`; |
|
| 63 | - | } |
|
| 64 | - | ||
| 65 | - | return ` |
|
| 66 | - | <a href="/now/${path}" class="block border-b pb-6 mb-6 last:border-b-0"> |
|
| 67 | - | <article> |
|
| 68 | - | <h3 class="text-lg font-semibold mb-3">${value.title}</h3> |
|
| 69 | - | <div class="prose prose-invert max-w-none mb-3"> |
|
| 70 | - | ${contentHTML} |
|
| 71 | - | </div> |
|
| 72 | - | <div class="flex items-center gap-2 text-sm text-gray-500"> |
|
| 73 | - | <time>${publishedAt}</time> |
|
| 74 | - | </div> |
|
| 75 | - | </article> |
|
| 76 | - | </a> |
|
| 77 | - | `; |
|
| 78 | - | }) |
|
| 79 | - | .join(""); |
|
| 80 | - | ||
| 81 | - | setContent(` |
|
| 82 | - | <div class="space-y-4"> |
|
| 83 | - | <div>${postsHTML}</div> |
|
| 84 | - | </div> |
|
| 85 | - | `); |
|
| 53 | + | setDocuments(sortedDocuments); |
|
| 54 | + | setLoading(false); |
|
| 86 | 55 | } catch (err) { |
|
| 87 | 56 | console.error("Error fetching updates:", err); |
|
| 88 | - | setContent( |
|
| 89 | - | "<p>Error loading recent updates. Make sure your PDS is accessible.</p>", |
|
| 90 | - | ); |
|
| 57 | + | setError(true); |
|
| 58 | + | setLoading(false); |
|
| 91 | 59 | } |
|
| 92 | 60 | } |
|
| 93 | 61 | ||
| 94 | 62 | fetchPosts(); |
|
| 95 | 63 | }, []); |
|
| 96 | 64 | ||
| 97 | - | return <div dangerouslySetInnerHTML={{ __html: content }} />; |
|
| 65 | + | if (loading) { |
|
| 66 | + | return <p>Loading...</p>; |
|
| 67 | + | } |
|
| 68 | + | ||
| 69 | + | if (error) { |
|
| 70 | + | return <p>Error loading recent updates. Make sure your PDS is accessible.</p>; |
|
| 71 | + | } |
|
| 72 | + | ||
| 73 | + | if (documents.length === 0) { |
|
| 74 | + | return <p>No recent updates found.</p>; |
|
| 75 | + | } |
|
| 76 | + | ||
| 77 | + | return ( |
|
| 78 | + | <div className="space-y-4"> |
|
| 79 | + | {documents.map((record) => { |
|
| 80 | + | const value = record.value; |
|
| 81 | + | const path = value.path.slice(1); |
|
| 82 | + | const publishedAt = new Date(value.publishedAt).toLocaleDateString(); |
|
| 83 | + | ||
| 84 | + | let contentHTML = ""; |
|
| 85 | + | if (value.content && value.content.markdown) { |
|
| 86 | + | contentHTML = md.render(value.content.markdown).trim(); |
|
| 87 | + | } else if (value.textContent) { |
|
| 88 | + | contentHTML = `<p>${value.textContent}</p>`; |
|
| 89 | + | } |
|
| 90 | + | ||
| 91 | + | return ( |
|
| 92 | + | <article key={record.uri} className="border-b pb-6 mb-6 last:border-b-0"> |
|
| 93 | + | <a href={`/now/${path}`} className="block hover:opacity-80 transition-opacity"> |
|
| 94 | + | <h3 className="text-lg font-semibold mb-3">{value.title}</h3> |
|
| 95 | + | </a> |
|
| 96 | + | <div |
|
| 97 | + | className="prose prose-invert max-w-none mb-3" |
|
| 98 | + | dangerouslySetInnerHTML={{ __html: contentHTML }} |
|
| 99 | + | /> |
|
| 100 | + | <div className="flex items-center gap-2 text-sm text-gray-500"> |
|
| 101 | + | <time>{publishedAt}</time> |
|
| 102 | + | </div> |
|
| 103 | + | </article> |
|
| 104 | + | ); |
|
| 105 | + | })} |
|
| 106 | + | </div> |
|
| 107 | + | ); |
|
| 98 | 108 | } |
|