import React, { useState } from 'react'; import { format } from 'date-fns'; import { motion } from 'framer-motion'; import { FiDownload, FiRefreshCw, FiCheckCircle, FiAlertCircle, FiExternalLink, FiClock, FiTag } from 'react-icons/fi'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from './dialog'; import { Button } from './Button'; import Typography from './Typography'; import { Badge } from './badge'; import { cn } from '../../lib/utils'; export interface UpdateInfo { version: string; releaseDate: string; releaseNotes?: string; } export interface UpdateProgress { percent: number; bytesPerSecond: number; total: number; transferred: number; } interface UpdateDialogProps { open: boolean; onOpenChange: (open: boolean) => void; updateState: 'checking' | 'available' | 'downloading' | 'downloaded' | 'error' | 'not-available' | null; updateInfo?: UpdateInfo; progress?: UpdateProgress; error?: { message: string; stack?: string }; currentVersion?: string; onDownload?: () => void; onInstall?: () => void; onViewReleases?: () => void; onCheckForUpdates?: () => void; } /** * Detailed update dialog component for managing app updates */ export const UpdateDialog: React.FC = ({ open, onOpenChange, updateState, updateInfo, progress, error, currentVersion = '1.0.0', onDownload, onInstall, onViewReleases, onCheckForUpdates }) => { const [showFullNotes, setShowFullNotes] = useState(false); const formatBytes = (bytes: number): string => { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; const formatSpeed = (bytesPerSecond: number): string => { return formatBytes(bytesPerSecond) + '/s'; }; const formatReleaseDate = (dateString: string): string => { try { return format(new Date(dateString), 'PPP'); } catch { return dateString; } }; const getStateIcon = () => { switch (updateState) { case 'checking': return ; case 'available': return ; case 'downloading': return ; case 'downloaded': return ; case 'error': return ; default: return ; } }; const getStateTitle = () => { switch (updateState) { case 'checking': return 'Checking for Updates'; case 'available': return 'Update Available'; case 'downloading': return 'Downloading Update'; case 'downloaded': return 'Ready to Install'; case 'error': return 'Update Error'; case 'not-available': return 'You\'re Up to Date'; default: return 'App Updates'; } }; const getStateDescription = () => { switch (updateState) { case 'checking': return 'Checking for the latest version...'; case 'available': return `Version ${updateInfo?.version} is available for download.`; case 'downloading': return 'Downloading the latest update. This may take a few minutes.'; case 'downloaded': return 'The update has been downloaded and is ready to install.'; case 'error': return error?.message || 'An error occurred while checking for updates.'; case 'not-available': return `You're running the latest version (v${currentVersion}).`; default: return 'Manage application updates and view release information.'; } }; const truncateText = (text: string, maxLength: number = 200): string => { if (text.length <= maxLength) return text; return text.slice(0, maxLength) + '...'; }; return (
{getStateIcon()}
{getStateTitle()} {getStateDescription()}
Current Version v{currentVersion}
{updateInfo ? (
Latest Version
v{updateInfo.version} New
) : null}
{updateInfo && updateState === 'available' ? (
Released on {formatReleaseDate(updateInfo.releaseDate)}
{updateInfo.releaseNotes ? (
Release Notes:
{showFullNotes ? updateInfo.releaseNotes : truncateText(updateInfo.releaseNotes) } {updateInfo.releaseNotes.length > 200 ? ( ) : null}
) : null}
) : null} {updateState === 'downloading' && progress ? (
Progress {progress.percent}%
{formatSpeed(progress.bytesPerSecond)} {formatBytes(progress.transferred)} / {formatBytes(progress.total)}
) : null} {updateState === 'error' && error ? (
Error Details {error.message}
) : null}
{onViewReleases ? ( ) : null} {updateState === 'not-available' && onCheckForUpdates ? ( ) : null} {updateState === 'available' && onDownload ? ( ) : null} {updateState === 'downloaded' && onInstall ? ( ) : null} {updateState === 'error' && onCheckForUpdates ? ( ) : null}
); };