"use client";
import { useState } from "react";
import {
Download,
Sparkles,
Bug,
Zap,
Shield,
Clock,
ExternalLink,
ChevronRight,
RefreshCw,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
import { cn } from "@/lib/utils";
type ChangeType = "feature" | "fix" | "improvement" | "security";
type ChangelogEntry = {
type: ChangeType;
title: string;
description?: string;
};
const changelog: ChangelogEntry[] = [
{
type: "feature",
title: "Dark mode support",
description: "New dark theme option in preferences with automatic system detection.",
},
{
type: "feature",
title: "Keyboard shortcuts",
description: "Navigate faster with customizable keyboard shortcuts.",
},
{
type: "improvement",
title: "50% faster load times",
description: "Optimized performance for large datasets.",
},
{
type: "improvement",
title: "Updated dashboard layout",
},
{
type: "fix",
title: "Fixed export functionality",
description: "Resolved issue where CSV exports were missing some columns.",
},
{
type: "fix",
title: "Notification delivery improvements",
},
{
type: "security",
title: "Security patches applied",
description: "Important security updates to protect your data.",
},
];
const changeTypeConfig = {
feature: { icon: Sparkles, label: "New", color: "text-primary" },
fix: { icon: Bug, label: "Fix", color: "text-orange-500" },
improvement: { icon: Zap, label: "Improved", color: "text-blue-500" },
security: { icon: Shield, label: "Security", color: "text-red-500" },
};
export const title = "React Dialog Block New Version";
export default function DialogNewVersion() {
const [open, setOpen] = useState(false);
const [isUpdating, setIsUpdating] = useState(false);
const [expandedItems, setExpandedItems] = useState<Set<number>>(new Set());
const currentVersion = "2.3.0";
const newVersion = "2.4.0";
const handleUpdate = async () => {
setIsUpdating(true);
await new Promise((resolve) => setTimeout(resolve, 2000));
setIsUpdating(false);
setOpen(false);
};
const handleRemindLater = () => {
setOpen(false);
// In real app: schedule reminder
};
const toggleExpanded = (index: number) => {
const newExpanded = new Set(expandedItems);
if (newExpanded.has(index)) {
newExpanded.delete(index);
} else {
newExpanded.add(index);
}
setExpandedItems(newExpanded);
};
const groupedChanges = changelog.reduce((acc, change) => {
if (!acc[change.type]) acc[change.type] = [];
acc[change.type].push(change);
return acc;
}, {} as Record<ChangeType, ChangelogEntry[]>);
return (
<Dialog open={open} onOpenChange={setOpen}>
<div className="flex min-h-[350px] items-center justify-center">
<DialogTrigger asChild>
<Button variant="outline">
<RefreshCw className="mr-2 h-4 w-4" />
Check for Updates
</Button>
</DialogTrigger>
</div>
<DialogContent className="sm:max-w-lg">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Download className="h-5 w-5" />
New Version Available
</DialogTitle>
<DialogDescription>
A new version of the app is ready to install.
</DialogDescription>
</DialogHeader>
<div className="space-y-4 py-4">
{/* Version Comparison */}
<div className="flex items-center justify-center gap-4 rounded-lg border p-4">
<div className="text-center">
<p className="text-xs text-muted-foreground">Current</p>
<p className="font-mono font-semibold">{currentVersion}</p>
</div>
<ChevronRight className="h-5 w-5 text-muted-foreground" />
<div className="text-center">
<p className="text-xs text-muted-foreground">New</p>
<p className="font-mono font-semibold text-primary">{newVersion}</p>
</div>
</div>
{/* Changelog */}
<div className="space-y-2">
<div className="flex items-center justify-between">
<h4 className="text-sm font-medium">What's New</h4>
<Button variant="link" size="sm" className="h-auto p-0 text-xs">
Full release notes
<ExternalLink className="ml-1 h-3 w-3" />
</Button>
</div>
<ScrollArea className="h-[240px] rounded-lg border p-3">
<div className="space-y-4">
{(Object.entries(groupedChanges) as [ChangeType, ChangelogEntry[]][]).map(
([type, changes]) => {
const config = changeTypeConfig[type];
const Icon = config.icon;
return (
<div key={type} className="space-y-2">
<div className="flex items-center gap-2">
<Icon className={cn("h-4 w-4", config.color)} />
<span className="text-sm font-medium">{config.label}</span>
<Badge variant="secondary" className="text-xs">
{changes.length}
</Badge>
</div>
<ul className="space-y-1 ml-6">
{changes.map((change, index) => (
<li key={index}>
{change.description ? (
<Collapsible>
<CollapsibleTrigger className="flex items-start gap-1 text-sm hover:underline cursor-pointer text-left">
<span>• {change.title}</span>
</CollapsibleTrigger>
<CollapsibleContent>
<p className="text-xs text-muted-foreground mt-1 ml-3">
{change.description}
</p>
</CollapsibleContent>
</Collapsible>
) : (
<span className="text-sm">• {change.title}</span>
)}
</li>
))}
</ul>
</div>
);
}
)}
</div>
</ScrollArea>
</div>
{/* Security Notice */}
{groupedChanges.security && (
<div className="flex items-start gap-2 rounded-lg border border-red-500/50 p-3">
<Shield className="h-4 w-4 text-red-500 mt-0.5" />
<div>
<p className="text-sm font-medium">Security Update</p>
<p className="text-xs text-muted-foreground">
This update includes important security fixes. We recommend updating soon.
</p>
</div>
</div>
)}
</div>
<DialogFooter className="flex-col sm:flex-row gap-2">
<Button
variant="ghost"
onClick={handleRemindLater}
className="sm:mr-auto"
disabled={isUpdating}
>
<Clock className="mr-2 h-4 w-4" />
Remind Me Later
</Button>
<Button variant="outline" onClick={() => setOpen(false)} disabled={isUpdating}>
Skip This Version
</Button>
<Button onClick={handleUpdate} disabled={isUpdating}>
{isUpdating ? (
<>
<RefreshCw className="mr-2 h-4 w-4 animate-spin" />
Updating...
</>
) : (
<>
<Download className="mr-2 h-4 w-4" />
Update Now
</>
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}