"use client";
import { useState } from "react";
import {
Monitor,
Smartphone,
Tablet,
Laptop,
MapPin,
LogOut,
Shield,
AlertTriangle,
} 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 { cn } from "@/lib/utils";
type DeviceType = "desktop" | "laptop" | "tablet" | "mobile";
type Device = {
id: string;
type: DeviceType;
name: string;
browser: string;
location: string;
lastActive: string;
isCurrent: boolean;
isSuspicious?: boolean;
};
const devices: Device[] = [
{
id: "1",
type: "laptop",
name: "MacBook Pro",
browser: "Chrome on macOS",
location: "San Francisco, CA",
lastActive: "Active now",
isCurrent: true,
},
{
id: "2",
type: "mobile",
name: "iPhone 15",
browser: "Safari on iOS",
location: "San Francisco, CA",
lastActive: "2 hours ago",
isCurrent: false,
},
{
id: "3",
type: "desktop",
name: "Windows PC",
browser: "Edge on Windows",
location: "New York, NY",
lastActive: "Yesterday",
isCurrent: false,
isSuspicious: true,
},
{
id: "4",
type: "tablet",
name: "iPad Air",
browser: "Safari on iPadOS",
location: "San Francisco, CA",
lastActive: "3 days ago",
isCurrent: false,
},
];
const deviceIcons: Record<DeviceType, React.ElementType> = {
desktop: Monitor,
laptop: Laptop,
tablet: Tablet,
mobile: Smartphone,
};
export const title = "React Dialog Block Device Management";
export default function DialogDeviceManagement() {
const [open, setOpen] = useState(false);
const [activeDevices, setActiveDevices] = useState<Device[]>(devices);
const [revokedId, setRevokedId] = useState<string | null>(null);
const [showConfirmAll, setShowConfirmAll] = useState(false);
const handleRevokeDevice = (deviceId: string) => {
setRevokedId(deviceId);
setTimeout(() => {
setActiveDevices((prev) => prev.filter((d) => d.id !== deviceId));
setRevokedId(null);
}, 500);
};
const handleRevokeAll = () => {
const otherDevices = activeDevices.filter((d) => !d.isCurrent);
otherDevices.forEach((device, index) => {
setTimeout(() => {
setActiveDevices((prev) => prev.filter((d) => d.isCurrent || d.id !== device.id));
}, index * 200);
});
setShowConfirmAll(false);
};
const handleClose = () => {
setOpen(false);
setTimeout(() => {
setActiveDevices(devices);
setRevokedId(null);
setShowConfirmAll(false);
}, 200);
};
const otherDevicesCount = activeDevices.filter((d) => !d.isCurrent).length;
const suspiciousCount = activeDevices.filter((d) => d.isSuspicious).length;
return (
<Dialog open={open} onOpenChange={setOpen}>
<div className="flex min-h-[350px] items-center justify-center">
<DialogTrigger asChild>
<Button variant="outline">
<Shield className="mr-2 h-4 w-4" />
Manage Devices
</Button>
</DialogTrigger>
</div>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<Shield className="h-5 w-5" />
Active Sessions
</DialogTitle>
<DialogDescription>
Manage devices that are signed in to your account.
</DialogDescription>
</DialogHeader>
{suspiciousCount > 0 && (
<p className="text-sm text-destructive flex items-center gap-2">
<AlertTriangle className="h-4 w-4" />
{suspiciousCount} suspicious session{suspiciousCount > 1 ? "s" : ""} detected
</p>
)}
<div className="space-y-2 py-2">
{activeDevices.map((device) => {
const DeviceIcon = deviceIcons[device.type];
const isRevoking = revokedId === device.id;
return (
<div
key={device.id}
className={cn(
"flex items-center gap-3 p-3 rounded-lg transition-all",
device.isCurrent && "bg-muted",
isRevoking && "opacity-50"
)}
>
<DeviceIcon className="h-5 w-5 text-muted-foreground shrink-0" />
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<span className="text-sm font-medium truncate">
{device.name}
</span>
{device.isCurrent && (
<Badge variant="secondary" className="text-xs">
Current
</Badge>
)}
{device.isSuspicious && (
<Badge variant="destructive" className="text-xs">
Suspicious
</Badge>
)}
</div>
<p className="text-xs text-muted-foreground">
{device.browser} · {device.location} · {device.lastActive}
</p>
</div>
{!device.isCurrent && (
<Button
variant="ghost"
size="sm"
className="text-muted-foreground hover:text-destructive shrink-0"
onClick={() => handleRevokeDevice(device.id)}
disabled={isRevoking}
>
<LogOut className="h-4 w-4" />
</Button>
)}
</div>
);
})}
</div>
<DialogFooter>
{showConfirmAll ? (
<>
<Button variant="outline" onClick={() => setShowConfirmAll(false)}>
Cancel
</Button>
<Button variant="destructive" onClick={handleRevokeAll}>
Sign out {otherDevicesCount} devices
</Button>
</>
) : (
<>
{otherDevicesCount > 0 && (
<Button
variant="outline"
onClick={() => setShowConfirmAll(true)}
className="text-destructive hover:text-destructive"
>
Sign out all others
</Button>
)}
<Button onClick={handleClose}>Done</Button>
</>
)}
</DialogFooter>
</DialogContent>
</Dialog>
);
}