'use client'; import { useState, useEffect, startTransition } from 'react'; import { api } from '~/trpc/react'; import { Button } from './ui/button'; import { Badge } from './ui/badge'; import { X, ExternalLink, Calendar, Tag, Loader2 } from 'lucide-react'; import { useRegisterModal } from './modal/ModalStackProvider'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; interface ReleaseNotesModalProps { isOpen: boolean; onClose: () => void; highlightVersion?: string; } interface Release { tagName: string; name: string; publishedAt: string; htmlUrl: string; body: string; } // Helper functions for localStorage const getLastSeenVersion = (): string | null => { if (typeof window === 'undefined') return null; return localStorage.getItem('LAST_SEEN_RELEASE_VERSION'); }; const markVersionAsSeen = (version: string): void => { if (typeof window === 'undefined') return; localStorage.setItem('LAST_SEEN_RELEASE_VERSION', version); }; export function ReleaseNotesModal({ isOpen, onClose, highlightVersion }: ReleaseNotesModalProps) { useRegisterModal(isOpen, { id: 'release-notes-modal', allowEscape: true, onClose }); const [currentVersion, setCurrentVersion] = useState(null); const { data: releasesData, isLoading, error } = api.version.getAllReleases.useQuery(undefined, { enabled: isOpen }); const { data: versionData } = api.version.getCurrentVersion.useQuery(undefined, { enabled: isOpen }); // Get current version when modal opens useEffect(() => { if (isOpen && versionData?.success && versionData.version) { startTransition(() => { setCurrentVersion(versionData.version); }); } }, [isOpen, versionData]); // Mark version as seen when modal closes const handleClose = () => { if (currentVersion) { markVersionAsSeen(currentVersion); } onClose(); }; if (!isOpen) return null; const releases: Release[] = releasesData?.success ? releasesData.releases ?? [] : []; return (
{/* Header */}

Release Notes

{/* Content */}
{isLoading ? (
Loading release notes...
) : error || !releasesData?.success ? (

Failed to load release notes

{releasesData?.error ?? 'Please try again later'}

) : releases.length === 0 ? (

No releases found

) : (
{releases.map((release, index) => { const isHighlighted = highlightVersion && release.tagName.replace('v', '') === highlightVersion; const isLatest = index === 0; return (
{/* Release Header */}

{release.name || release.tagName}

{isLatest && ( Latest )} {isHighlighted && ( New )}
{release.tagName}
{new Date(release.publishedAt).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}
{/* Release Body */} {release.body && (

{children}

, h2: ({children}) =>

{children}

, h3: ({children}) =>

{children}

, p: ({children}) =>

{children}

, ul: ({children}) =>
    {children}
, ol: ({children}) =>
    {children}
, li: ({children}) =>
  • {children}
  • , a: ({href, children}) => {children}, strong: ({children}) => {children}, em: ({children}) => {children}, }} > {release.body}
    )}
    ); })}
    )}
    {/* Footer */}
    {currentVersion && ( Current version: v{currentVersion} )}
    ); } // Export helper functions for use in other components export { getLastSeenVersion, markVersionAsSeen };