import { useCallback, useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { ArrowLeft, RefreshCw } from 'lucide-react'; import { toast } from 'sonner'; import { api } from '@/api'; import { cn, errMessage } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { MarkdownText } from '@/components/MarkdownText'; interface ReleaseHistoryData { history?: string; version?: string; updated_at?: string; } function formatDateTime(value: string | null | undefined): string | null { if (!value) return null; const date = new Date(value); if (Number.isNaN(date.getTime())) return value; return date.toLocaleString(); } function parseImageLine(line: string): { alt: string; src: string } | null { const match = line.match(/^!\[([^\]\n]*)\]\(([^)\s]+)\)$/); if (!match) return null; return { alt: match[1] ?? '', src: match[2] ?? '' }; } function HistoryLine({ line, index }: { line: string; index: number }) { const trimmed = line.trim(); const image = parseImageLine(trimmed); if (!trimmed) return
; if (trimmed === '---') return
; if (image) { return (
{image.alt}
); } if (trimmed.startsWith('# ')) { return (

); } if (trimmed.startsWith('## ')) { return (

); } if (trimmed.startsWith('### ')) { return (

); } if (trimmed.startsWith('- ')) { return (

); } return (

); } export default function ReleaseNotesPage() { const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const load = useCallback(async () => { setLoading(true); setError(null); try { setData(await api.releaseHistory() as ReleaseHistoryData); } catch (err) { setError(errMessage(err, 'Failed to load release notes.')); toast.error(errMessage(err, 'Failed to load release notes.')); } finally { setLoading(false); } }, []); useEffect(() => { load(); }, [load]); const history = data?.history || ''; return (

Release Notes

{data?.version ? `Current version v${data.version}` : 'Full project changelog'} {data?.updated_at ? ` ยท Updated ${formatDateTime(data.updated_at)}` : ''}

{loading ? (
) : error ? (

Unable to load release notes.

{error}

) : !history.trim() ? (

No release notes are available.

) : (
{history.split('\n').map((line, index) => ( ))}
)}
); }