{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "session-device-manager",
  "title": "Session Device Manager",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/session-device-manager/SessionDeviceManager.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport {\n  CheckCircle2,\n  Clock,\n  Globe,\n  Laptop,\n  LogOut,\n  MapPin,\n  Monitor,\n  Radio,\n  ShieldCheck,\n  Smartphone,\n  Tablet,\n  Terminal,\n  TriangleAlert,\n} from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Separator } from '@/components/ui/separator'\n\nexport interface SessionDevice {\n  id: string\n  name: string\n  deviceType: 'laptop' | 'desktop' | 'mobile' | 'tablet' | 'terminal'\n  os: string\n  browser: string\n  location: string\n  countryFlag: string\n  ip: string\n  signedInAt: string\n  lastActive: string\n  isMfa: boolean\n  isSuspicious?: boolean\n  customBadge?: {\n    label: string\n    variant: 'default' | 'secondary' | 'destructive' | 'outline' | 'success' | 'warning' | 'info'\n  }\n}\n\nexport interface SessionDeviceManagerProps {\n  initialOtherSessions?: SessionDevice[]\n  initialShowSuspiciousAlert?: boolean\n  className?: string\n}\n\nconst currentSession = {\n  id: 'sess-current-01',\n  name: 'MacBook Pro 16\"',\n  deviceType: 'laptop' as const,\n  os: 'macOS Sequoia',\n  browser: 'Chrome 128.0',\n  location: 'San Francisco, CA, United States',\n  countryFlag: '🇺🇸',\n  ip: '76.76.21.21',\n  signedInAt: 'Aug 18, 2026 · 09:42 AM',\n  lastActive: 'Active right now',\n  isMfa: true,\n}\n\nconst stubOtherSessions: SessionDevice[] = [\n  {\n    id: 'sess-02',\n    name: 'iPhone 16 Pro',\n    deviceType: 'mobile',\n    os: 'iOS 18.0',\n    browser: 'Safari Mobile',\n    location: 'Los Angeles, CA, United States',\n    countryFlag: '🇺🇸',\n    ip: '172.56.21.89',\n    signedInAt: 'Aug 19, 2026',\n    lastActive: '12m ago',\n    isMfa: true,\n  },\n  {\n    id: 'sess-03',\n    name: 'Workstation',\n    deviceType: 'desktop',\n    os: 'Ubuntu 24.04 LTS',\n    browser: 'Firefox 130',\n    location: 'London, Greater London, United Kingdom',\n    countryFlag: '🇬🇧',\n    ip: '185.220.101.5',\n    signedInAt: 'Aug 21, 2026',\n    lastActive: '2h ago',\n    isMfa: true,\n    isSuspicious: true,\n    customBadge: {\n      label: 'New Location',\n      variant: 'warning',\n    },\n  },\n  {\n    id: 'sess-04',\n    name: 'CLI Token',\n    deviceType: 'terminal',\n    os: 'Darwin x64',\n    browser: 'Node.js SDK',\n    location: 'AWS us-east-1 (N. Virginia), United States',\n    countryFlag: '🇺🇸',\n    ip: '54.234.19.102',\n    signedInAt: 'Aug 10, 2026',\n    lastActive: '34m ago',\n    isMfa: true,\n    customBadge: {\n      label: 'CLI Token',\n      variant: 'secondary',\n    },\n  },\n  {\n    id: 'sess-05',\n    name: 'iPad Air',\n    deviceType: 'tablet',\n    os: 'iPadOS 17.6',\n    browser: 'Safari',\n    location: 'New York, NY, United States',\n    countryFlag: '🇺🇸',\n    ip: '68.195.44.110',\n    signedInAt: 'Aug 14, 2026',\n    lastActive: '3d ago',\n    isMfa: true,\n  },\n]\n\nexport function SessionDeviceManager({\n  initialOtherSessions,\n  initialShowSuspiciousAlert = true,\n  className,\n}: SessionDeviceManagerProps) {\n  const [otherSessions, setOtherSessions] = React.useState<SessionDevice[]>(\n    initialOtherSessions ? initialOtherSessions.map((s) => ({ ...s })) : stubOtherSessions.map((s) => ({ ...s })),\n  )\n  const [showSuspiciousAlert, setShowSuspiciousAlert] = React.useState(initialShowSuspiciousAlert)\n  const [revokingAll, setRevokingAll] = React.useState(false)\n  const [confirmingRevokeId, setConfirmingRevokeId] = React.useState<string | null>(null)\n  const confirmTimerRef = React.useRef<number | null>(null)\n\n  React.useEffect(() => {\n    return () => {\n      if (confirmTimerRef.current) {\n        window.clearTimeout(confirmTimerRef.current)\n      }\n    }\n  }, [])\n\n  const dismissAlert = () => {\n    setShowSuspiciousAlert(false)\n  }\n\n  const revokeSuspicious = () => {\n    setOtherSessions((prev) => prev.filter((s) => !s.isSuspicious))\n    setShowSuspiciousAlert(false)\n  }\n\n  const revokeSession = (id: string) => {\n    if (confirmTimerRef.current) {\n      window.clearTimeout(confirmTimerRef.current)\n    }\n    setConfirmingRevokeId(null)\n    setOtherSessions((prev) => {\n      const target = prev.find((s) => s.id === id)\n      if (target?.isSuspicious) {\n        setShowSuspiciousAlert(false)\n      }\n      return prev.filter((s) => s.id !== id)\n    })\n  }\n\n  const requestRevoke = (id: string) => {\n    if (confirmingRevokeId === id) {\n      revokeSession(id)\n      return\n    }\n    setConfirmingRevokeId(id)\n    if (confirmTimerRef.current) {\n      window.clearTimeout(confirmTimerRef.current)\n    }\n    confirmTimerRef.current = window.setTimeout(() => {\n      setConfirmingRevokeId(null)\n    }, 3000)\n  }\n\n  const cancelRevoke = (id: string) => {\n    if (confirmingRevokeId === id) {\n      if (confirmTimerRef.current) {\n        window.clearTimeout(confirmTimerRef.current)\n      }\n      setConfirmingRevokeId(null)\n    }\n  }\n\n  const revokeAllOtherSessions = () => {\n    setRevokingAll(true)\n    setOtherSessions([])\n    setShowSuspiciousAlert(false)\n    window.setTimeout(() => {\n      setRevokingAll(false)\n    }, 600)\n  }\n\n  return (\n    <div data-slot=\"session-device-manager\" className={cn('mx-auto w-full max-w-4xl space-y-6', className)}>\n      {/* Header */}\n      <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div className=\"space-y-1\">\n          <h2 className=\"text-foreground text-xl font-semibold tracking-tight sm:text-2xl\">\n            Active Sessions & Connected Devices\n          </h2>\n          <p className=\"text-muted-foreground text-xs sm:text-sm\">\n            Manage and revoke active login sessions across your desktop, mobile, and CLI tokens.\n          </p>\n        </div>\n        <Button\n          variant=\"destructive\"\n          size=\"sm\"\n          disabled={otherSessions.length === 0 || revokingAll}\n          className=\"shrink-0\"\n          onClick={revokeAllOtherSessions}\n        >\n          <LogOut className=\"size-4\" />\n          Revoke All Other Sessions\n        </Button>\n      </div>\n\n      {/* Suspicious Login Alert Banner */}\n      {showSuspiciousAlert && (\n        <div\n          className=\"border-warning/30 bg-warning/10 text-foreground relative flex flex-col gap-3 rounded-lg border p-4 text-sm sm:flex-row sm:items-start sm:justify-between\"\n          role=\"alert\"\n        >\n          <div className=\"flex items-start gap-3\">\n            <div className=\"bg-warning/20 text-warning mt-0.5 grid size-8 shrink-0 place-items-center rounded-md\">\n              <TriangleAlert className=\"size-4\" />\n            </div>\n            <div className=\"space-y-1\">\n              <div className=\"flex flex-wrap items-center gap-2\">\n                <p className=\"text-foreground font-semibold\">Suspicious Login Detected</p>\n                <Badge variant=\"warning\" className=\"text-xs\">\n                  Is this you?\n                </Badge>\n              </div>\n              <p className=\"text-muted-foreground text-xs leading-relaxed\">\n                Recent new login on <span className=\"text-foreground font-medium\">Workstation · Firefox 130</span> from{' '}\n                <span className=\"text-foreground font-medium\">London, UK (IP 185.220.101.5)</span> on Aug 21, 2026. If\n                you do not recognize this activity, revoke the session immediately.\n              </p>\n            </div>\n          </div>\n          <div className=\"flex shrink-0 items-center gap-2 sm:self-center\">\n            <Button\n              variant=\"outline\"\n              size=\"sm\"\n              className=\"text-muted-foreground hover:text-foreground h-8 text-xs\"\n              onClick={dismissAlert}\n            >\n              This was me\n            </Button>\n            <Button variant=\"destructive\" size=\"sm\" className=\"h-8 text-xs\" onClick={revokeSuspicious}>\n              Revoke Session\n            </Button>\n          </div>\n        </div>\n      )}\n\n      {/* Current Session Hero Card */}\n      <Card className=\"border-border bg-card shadow-xs\">\n        <CardHeader className=\"pb-3\">\n          <div className=\"flex flex-wrap items-center justify-between gap-2\">\n            <div className=\"flex items-center gap-2.5\">\n              <span className=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">This Device</span>\n              <Badge variant=\"success\" className=\"gap-1.5 py-0.5 text-xs\">\n                <span className=\"relative flex size-2\">\n                  <span className=\"bg-success absolute inline-flex size-full rounded-full opacity-75\" />\n                  <span className=\"bg-success relative inline-flex size-2 rounded-full\" />\n                </span>\n                Current Active Session\n              </Badge>\n            </div>\n            <Badge variant=\"outline\" className=\"text-muted-foreground gap-1 text-xs\">\n              <ShieldCheck className=\"text-success size-3.5\" />\n              2FA Verified\n            </Badge>\n          </div>\n        </CardHeader>\n\n        <CardContent className=\"space-y-4\">\n          <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n            <div className=\"flex items-start gap-3.5\">\n              <div className=\"border-border bg-muted/80 text-foreground flex size-11 shrink-0 items-center justify-center rounded-lg border shadow-xs\">\n                <Laptop className=\"size-5\" />\n              </div>\n              <div className=\"space-y-1\">\n                <div className=\"flex flex-wrap items-center gap-2\">\n                  <h3 className=\"text-foreground text-base font-semibold sm:text-lg\">\n                    {currentSession.name} · {currentSession.os}\n                  </h3>\n                </div>\n                <p className=\"text-muted-foreground text-xs font-medium sm:text-sm\">{currentSession.browser}</p>\n              </div>\n            </div>\n\n            <div className=\"border-border bg-muted/40 text-muted-foreground flex items-center gap-1.5 self-start rounded-md border px-2.5 py-1 text-xs sm:self-auto\">\n              <Radio className=\"text-success size-3.5\" />\n              <span className=\"text-foreground font-medium\">{currentSession.lastActive}</span>\n            </div>\n          </div>\n\n          <Separator />\n\n          <div className=\"grid grid-cols-1 gap-3 text-xs sm:grid-cols-2 lg:grid-cols-3\">\n            <div className=\"text-muted-foreground flex items-center gap-2\">\n              <MapPin className=\"text-foreground size-3.5 shrink-0\" />\n              <span className=\"truncate\">\n                {currentSession.countryFlag} {currentSession.location}\n              </span>\n            </div>\n\n            <div className=\"text-muted-foreground flex items-center gap-2 font-mono\">\n              <Globe className=\"text-foreground size-3.5 shrink-0\" />\n              <span>IP: {currentSession.ip}</span>\n            </div>\n\n            <div className=\"text-muted-foreground flex items-center gap-2 sm:col-span-2 lg:col-span-1\">\n              <Clock className=\"text-foreground size-3.5 shrink-0\" />\n              <span>Signed in: {currentSession.signedInAt}</span>\n            </div>\n          </div>\n        </CardContent>\n      </Card>\n\n      {/* Other Active Sessions List */}\n      <Card className=\"border-border bg-card shadow-xs\">\n        <CardHeader>\n          <div className=\"flex flex-wrap items-center justify-between gap-2\">\n            <div>\n              <CardTitle className=\"text-foreground text-base font-semibold sm:text-lg\">\n                Other Active Sessions\n              </CardTitle>\n              <CardDescription className=\"mt-1 text-xs sm:text-sm\">\n                {otherSessions.length} active session{otherSessions.length === 1 ? '' : 's'} authenticated across your\n                secondary devices and automation workflows.\n              </CardDescription>\n            </div>\n            <Badge variant=\"secondary\" className=\"font-mono text-xs\">\n              {otherSessions.length} active\n            </Badge>\n          </div>\n        </CardHeader>\n\n        <CardContent>\n          {/* Empty State */}\n          {otherSessions.length === 0 ? (\n            <div className=\"border-border flex flex-col items-center justify-center rounded-lg border border-dashed py-12 text-center\">\n              <div className=\"bg-muted text-muted-foreground grid size-11 place-items-center rounded-full\">\n                <CheckCircle2 className=\"text-success size-5\" />\n              </div>\n              <p className=\"text-foreground mt-3 text-sm font-medium\">No other active sessions</p>\n              <p className=\"text-muted-foreground mt-1 max-w-sm text-xs\">\n                Your account is only signed in on this device. All previous mobile, workstation, and CLI sessions have\n                been revoked.\n              </p>\n            </div>\n          ) : (\n            /* Sessions List */\n            <ul className=\"divide-border -my-2 divide-y\">\n              {otherSessions.map((session) => (\n                <li\n                  key={session.id}\n                  className=\"flex flex-col gap-3 py-4 sm:flex-row sm:items-center sm:justify-between\"\n                >\n                  <div className=\"flex items-start gap-3\">\n                    {/* Device Icon */}\n                    <div className=\"border-border bg-muted/60 text-muted-foreground flex size-10 shrink-0 items-center justify-center rounded-lg border shadow-xs\">\n                      {session.deviceType === 'mobile' ? (\n                        <Smartphone className=\"size-4\" />\n                      ) : session.deviceType === 'desktop' ? (\n                        <Monitor className=\"size-4\" />\n                      ) : session.deviceType === 'terminal' ? (\n                        <Terminal className=\"size-4\" />\n                      ) : session.deviceType === 'tablet' ? (\n                        <Tablet className=\"size-4\" />\n                      ) : (\n                        <Laptop className=\"size-4\" />\n                      )}\n                    </div>\n\n                    {/* Details */}\n                    <div className=\"min-w-0 space-y-1\">\n                      <div className=\"flex flex-wrap items-center gap-2\">\n                        <p className=\"text-foreground truncate text-sm font-medium\">\n                          {session.name} · {session.browser}\n                        </p>\n                        <Badge variant=\"outline\" className=\"gap-1 py-0 text-xs\">\n                          <ShieldCheck className=\"text-success size-3\" />\n                          2FA Verified\n                        </Badge>\n                        {session.customBadge && (\n                          <Badge variant={session.customBadge.variant} className=\"text-xs\">\n                            {session.customBadge.label}\n                          </Badge>\n                        )}\n                      </div>\n\n                      <div className=\"text-muted-foreground flex flex-wrap items-center gap-x-3 gap-y-1 text-xs\">\n                        <span className=\"flex items-center gap-1\">\n                          <MapPin className=\"size-3 shrink-0\" />\n                          {session.countryFlag} {session.location}\n                        </span>\n                        <span>·</span>\n                        <span className=\"font-mono\">IP: {session.ip}</span>\n                      </div>\n\n                      <p className=\"text-muted-foreground text-xs\">\n                        Signed in {session.signedInAt} · Last active{' '}\n                        <span className=\"text-foreground font-medium\">{session.lastActive}</span>\n                      </p>\n                    </div>\n                  </div>\n\n                  {/* Action */}\n                  <div className=\"flex shrink-0 items-center gap-2 self-end sm:self-center\">\n                    <Button\n                      variant=\"outline\"\n                      size=\"sm\"\n                      className={\n                        confirmingRevokeId === session.id\n                          ? 'bg-destructive hover:bg-destructive/90 border-transparent text-white'\n                          : 'border-destructive/30 text-destructive hover:bg-destructive/10 hover:text-destructive'\n                      }\n                      onClick={() => requestRevoke(session.id)}\n                      onBlur={() => cancelRevoke(session.id)}\n                    >\n                      {confirmingRevokeId === session.id ? 'Confirm Revoke?' : 'Revoke Session'}\n                    </Button>\n                  </div>\n                </li>\n              ))}\n            </ul>\n          )}\n        </CardContent>\n      </Card>\n    </div>\n  )\n}\n\nexport default SessionDeviceManager\n",
      "type": "registry:block",
      "target": "~/components/blocks/SessionDeviceManager.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/separator.json"
  ],
  "description": "Active multi-device login sessions manager and security dashboard featuring current session hero card with IP geolocation, suspicious new login alert banner, 2FA verification badges, and instant individual or bulk session revocation for desktop, mobile, and CLI tokens.",
  "categories": [
    "security",
    "app",
    "dashboard"
  ]
}