{
  "name": "social-components-friendsdialog",
  "type": "registry:component",
  "dependencies": [
    "bmap-api-types"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "files": [
    {
      "path": "components/social/components/FriendsDialog.tsx",
      "type": "registry:component",
      "content": "import {\n\tCheckIcon,\n\tCross2Icon,\n\tPersonIcon,\n\tPlusIcon,\n} from \"@radix-ui/react-icons\";\n// FriendsDialog Component - Manage friends and friend requests\nimport type { Friend } from \"bmap-api-types\";\nimport type React from \"react\";\nimport { useBitcoinAuth } from \"../../../hooks/useBitcoinAuth.js\";\nimport { cn } from \"../../../lib/utils.js\";\nimport { BitcoinImage, DecorativeBox } from \"../../ui-components/index.js\";\nimport { Badge } from \"../../ui/badge.js\";\nimport { Button } from \"../../ui/button.js\";\nimport {\n\tDialog,\n\tDialogClose,\n\tDialogContent,\n\tDialogDescription,\n\tDialogTitle,\n\tDialogTrigger,\n} from \"../../ui/dialog.js\";\nimport { ScrollArea } from \"../../ui/scroll-area.js\";\nimport { Skeleton } from \"../../ui/skeleton.js\";\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"../../ui/tabs.js\";\nimport { useFriendActions } from \"../hooks/useFriendActions.js\";\nimport { type FriendRequest, useFriends } from \"../hooks/useFriends.js\";\n\nexport interface FriendsDialogProps {\n\topen?: boolean;\n\tonOpenChange?: (open: boolean) => void;\n\ttrigger?: React.ReactNode;\n}\n\nexport function FriendsDialog({\n\topen,\n\tonOpenChange,\n\ttrigger,\n}: FriendsDialogProps) {\n\tconst { isAuthenticated } = useBitcoinAuth();\n\tconst {\n\t\tfriends,\n\t\tincoming,\n\t\toutgoing,\n\t\tisLoading: friendsLoading,\n\t} = useFriends();\n\tconst {\n\t\tacceptRequest,\n\t\trejectRequest,\n\t\tisLoading: actionLoading,\n\t} = useFriendActions();\n\n\tif (!isAuthenticated) {\n\t\treturn null;\n\t}\n\n\tconst defaultTrigger = (\n\t\t<Button variant=\"outline\" size=\"default\">\n\t\t\t<PersonIcon className=\"mr-2 h-4 w-4\" />\n\t\t\tFriends\n\t\t\t{incoming.length > 0 && (\n\t\t\t\t<Badge variant=\"destructive\" className=\"ml-2\">\n\t\t\t\t\t{incoming.length}\n\t\t\t\t</Badge>\n\t\t\t)}\n\t\t</Button>\n\t);\n\n\treturn (\n\t\t<Dialog open={open} onOpenChange={onOpenChange}>\n\t\t\t<DialogTrigger asChild>{trigger || defaultTrigger}</DialogTrigger>\n\n\t\t\t<DialogContent className=\"max-w-[450px]\">\n\t\t\t\t<DialogTitle>Friends</DialogTitle>\n\t\t\t\t<DialogDescription className=\"mb-4\">\n\t\t\t\t\tManage your friends and friend requests\n\t\t\t\t</DialogDescription>\n\n\t\t\t\t<Tabs defaultValue=\"friends\">\n\t\t\t\t\t<TabsList className=\"grid w-full grid-cols-3\">\n\t\t\t\t\t\t<TabsTrigger value=\"friends\">\n\t\t\t\t\t\t\tFriends ({friends.length})\n\t\t\t\t\t\t</TabsTrigger>\n\t\t\t\t\t\t<TabsTrigger value=\"requests\">\n\t\t\t\t\t\t\tRequests\n\t\t\t\t\t\t\t{incoming.length > 0 && (\n\t\t\t\t\t\t\t\t<Badge variant=\"destructive\" className=\"ml-1\">\n\t\t\t\t\t\t\t\t\t{incoming.length}\n\t\t\t\t\t\t\t\t</Badge>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</TabsTrigger>\n\t\t\t\t\t\t<TabsTrigger value=\"sent\">Sent ({outgoing.length})</TabsTrigger>\n\t\t\t\t\t</TabsList>\n\n\t\t\t\t\t<div className=\"mt-4\">\n\t\t\t\t\t\t<TabsContent value=\"friends\">\n\t\t\t\t\t\t\t<FriendsList friends={friends} isLoading={friendsLoading} />\n\t\t\t\t\t\t</TabsContent>\n\n\t\t\t\t\t\t<TabsContent value=\"requests\">\n\t\t\t\t\t\t\t<FriendRequestsList\n\t\t\t\t\t\t\t\trequests={incoming}\n\t\t\t\t\t\t\t\tonAccept={acceptRequest}\n\t\t\t\t\t\t\t\tonReject={rejectRequest}\n\t\t\t\t\t\t\t\tisLoading={friendsLoading || actionLoading}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</TabsContent>\n\n\t\t\t\t\t\t<TabsContent value=\"sent\">\n\t\t\t\t\t\t\t<SentRequestsList\n\t\t\t\t\t\t\t\trequests={outgoing}\n\t\t\t\t\t\t\t\tisLoading={friendsLoading}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</TabsContent>\n\t\t\t\t\t</div>\n\t\t\t\t</Tabs>\n\n\t\t\t\t<div className=\"flex gap-3 mt-4 justify-between\">\n\t\t\t\t\t<Button variant=\"outline\" size=\"default\">\n\t\t\t\t\t\t<PlusIcon className=\"mr-2 h-4 w-4\" />\n\t\t\t\t\t\tAdd Friend\n\t\t\t\t\t</Button>\n\t\t\t\t\t<DialogClose asChild>\n\t\t\t\t\t\t<Button variant=\"secondary\">Close</Button>\n\t\t\t\t\t</DialogClose>\n\t\t\t\t</div>\n\t\t\t</DialogContent>\n\t\t</Dialog>\n\t);\n}\n\ninterface FriendsListProps {\n\tfriends: Friend[];\n\tisLoading: boolean;\n}\n\nfunction FriendsList({ friends, isLoading }: FriendsListProps) {\n\tif (isLoading) {\n\t\treturn (\n\t\t\t<ScrollArea className=\"h-[300px]\">\n\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t{[...Array(3)].map((_, index) => (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tkey={`friend-list-skeleton-${index + 1}`}\n\t\t\t\t\t\t\tclassName=\"flex items-center gap-3 p-2 rounded-md\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Skeleton className=\"h-10 w-10 rounded-full\" />\n\t\t\t\t\t\t\t<div className=\"flex flex-col gap-1 flex-1\">\n\t\t\t\t\t\t\t\t<Skeleton className=\"h-4 w-[120px]\" />\n\t\t\t\t\t\t\t\t<Skeleton className=\"h-3.5 w-[80px]\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</ScrollArea>\n\t\t);\n\t}\n\n\tif (friends.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col items-center py-6 gap-2\">\n\t\t\t\t<PersonIcon className=\"h-6 w-6 text-muted-foreground\" />\n\t\t\t\t<p className=\"text-sm text-muted-foreground\">No friends yet</p>\n\t\t\t\t<p className=\"text-xs text-muted-foreground\">\n\t\t\t\t\tSend friend requests to start building your network\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<ScrollArea className=\"h-[300px]\">\n\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t{friends.map((friend) => (\n\t\t\t\t\t<FriendItem key={friend.bapId} friend={friend} />\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</ScrollArea>\n\t);\n}\n\ninterface FriendRequestsListProps {\n\trequests: FriendRequest[];\n\tonAccept: (bapId: string) => void;\n\tonReject: (bapId: string) => void;\n\tisLoading: boolean;\n}\n\nfunction FriendRequestsList({\n\trequests,\n\tonAccept,\n\tonReject,\n\tisLoading,\n}: FriendRequestsListProps) {\n\tif (isLoading) {\n\t\treturn (\n\t\t\t<ScrollArea className=\"h-[300px]\">\n\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t{[...Array(2)].map((_, index) => (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tkey={`friend-request-skeleton-${index + 1}`}\n\t\t\t\t\t\t\tclassName=\"flex items-center gap-3 p-2 rounded-md\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Skeleton className=\"h-10 w-10 rounded-full\" />\n\t\t\t\t\t\t\t<div className=\"flex flex-col gap-1 flex-1\">\n\t\t\t\t\t\t\t\t<Skeleton className=\"h-4 w-[120px]\" />\n\t\t\t\t\t\t\t\t<Skeleton className=\"h-3.5 w-[80px]\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div className=\"flex gap-1\">\n\t\t\t\t\t\t\t\t<Skeleton className=\"h-8 w-8\" />\n\t\t\t\t\t\t\t\t<Skeleton className=\"h-8 w-8\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</ScrollArea>\n\t\t);\n\t}\n\n\tif (requests.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col items-center py-6 gap-2\">\n\t\t\t\t<p className=\"text-sm text-muted-foreground\">No pending requests</p>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<ScrollArea className=\"h-[300px]\">\n\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t{requests.map((request) => (\n\t\t\t\t\t<FriendRequestItem\n\t\t\t\t\t\tkey={request.bapId}\n\t\t\t\t\t\trequest={request}\n\t\t\t\t\t\tonAccept={() => onAccept(request.bapId)}\n\t\t\t\t\t\tonReject={() => onReject(request.bapId)}\n\t\t\t\t\t/>\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</ScrollArea>\n\t);\n}\n\ninterface SentRequestsListProps {\n\trequests: FriendRequest[];\n\tisLoading: boolean;\n}\n\nfunction SentRequestsList({ requests, isLoading }: SentRequestsListProps) {\n\tif (isLoading) {\n\t\treturn (\n\t\t\t<ScrollArea className=\"h-[300px]\">\n\t\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t\t{[...Array(2)].map((_, index) => (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tkey={`sent-request-skeleton-${index + 1}`}\n\t\t\t\t\t\t\tclassName=\"flex items-center gap-3 p-2 rounded-md\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Skeleton className=\"h-10 w-10 rounded-full\" />\n\t\t\t\t\t\t\t<div className=\"flex flex-col gap-1 flex-1\">\n\t\t\t\t\t\t\t\t<Skeleton className=\"h-4 w-[120px]\" />\n\t\t\t\t\t\t\t\t<Skeleton className=\"h-3.5 w-[80px]\" />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<Skeleton className=\"h-3.5 w-[60px]\" />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t</ScrollArea>\n\t\t);\n\t}\n\n\tif (requests.length === 0) {\n\t\treturn (\n\t\t\t<div className=\"flex flex-col items-center py-6 gap-2\">\n\t\t\t\t<p className=\"text-sm text-muted-foreground\">No sent requests</p>\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<ScrollArea className=\"h-[300px]\">\n\t\t\t<div className=\"flex flex-col gap-2\">\n\t\t\t\t{requests.map((request) => (\n\t\t\t\t\t<SentRequestItem key={request.bapId} request={request} />\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</ScrollArea>\n\t);\n}\n\ninterface FriendItemProps {\n\tfriend: Friend;\n}\n\nfunction FriendItem({ friend }: FriendItemProps) {\n\treturn (\n\t\t<div className=\"flex items-center gap-3 p-2 rounded-md\">\n\t\t\t<div className=\"w-10 h-10\">\n\t\t\t\t<DecorativeBox borderRadius=\"full\" interactive>\n\t\t\t\t\t{friend.icon ? (\n\t\t\t\t\t\t<BitcoinImage src={friend.icon} alt={friend.name || \"Friend\"} />\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<div className=\"flex items-center justify-center w-full h-full\">\n\t\t\t\t\t\t\t<p className=\"text-sm font-bold\">\n\t\t\t\t\t\t\t\t{friend.name?.charAt(0) || friend.bapId.slice(0, 2)}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t</DecorativeBox>\n\t\t\t</div>\n\t\t\t<div className=\"flex-grow\">\n\t\t\t\t<p className=\"text-sm font-medium\">{friend.name || \"Anonymous\"}</p>\n\t\t\t\t<div>\n\t\t\t\t\t<p className=\"text-xs text-muted-foreground\">\n\t\t\t\t\t\tBAP ID: {friend.bapId.slice(0, 8)}...\n\t\t\t\t\t</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\ninterface FriendRequestItemProps {\n\trequest: FriendRequest;\n\tonAccept: () => void;\n\tonReject: () => void;\n}\n\nfunction FriendRequestItem({\n\trequest,\n\tonAccept,\n\tonReject,\n}: FriendRequestItemProps) {\n\treturn (\n\t\t<div className=\"flex items-center gap-3 p-2 rounded-md\">\n\t\t\t<div className=\"w-10 h-10\">\n\t\t\t\t<DecorativeBox borderRadius=\"full\" interactive>\n\t\t\t\t\t<div className=\"flex items-center justify-center w-full h-full\">\n\t\t\t\t\t\t<p className=\"text-sm font-bold\">{request.bapId.slice(0, 2)}</p>\n\t\t\t\t\t</div>\n\t\t\t\t</DecorativeBox>\n\t\t\t</div>\n\t\t\t<div className=\"flex-grow\">\n\t\t\t\t<p className=\"text-sm font-medium\">{request.bapId.slice(0, 8)}...</p>\n\t\t\t\t<div>\n\t\t\t\t\t<p className=\"text-xs text-muted-foreground\">Wants to be friends</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div className=\"flex gap-1\">\n\t\t\t\t<Button size=\"sm\" onClick={onAccept}>\n\t\t\t\t\t<CheckIcon className=\"h-4 w-4\" />\n\t\t\t\t</Button>\n\t\t\t\t<Button\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\tvariant=\"secondary\"\n\t\t\t\t\tclassName=\"text-destructive hover:bg-destructive hover:text-destructive-foreground\"\n\t\t\t\t\tonClick={onReject}\n\t\t\t\t>\n\t\t\t\t\t<Cross2Icon className=\"h-4 w-4\" />\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n\ninterface SentRequestItemProps {\n\trequest: FriendRequest;\n}\n\nfunction SentRequestItem({ request }: SentRequestItemProps) {\n\treturn (\n\t\t<div className=\"flex items-center gap-3 p-2 rounded-md\">\n\t\t\t<div className=\"w-10 h-10\">\n\t\t\t\t<DecorativeBox borderRadius=\"full\" interactive>\n\t\t\t\t\t<div className=\"flex items-center justify-center w-full h-full\">\n\t\t\t\t\t\t<p className=\"text-sm font-bold\">{request.bapId.slice(0, 2)}</p>\n\t\t\t\t\t</div>\n\t\t\t\t</DecorativeBox>\n\t\t\t</div>\n\t\t\t<div className=\"flex-grow\">\n\t\t\t\t<p className=\"text-sm font-medium\">{request.bapId.slice(0, 8)}...</p>\n\t\t\t\t<div>\n\t\t\t\t\t<p className=\"text-xs text-muted-foreground\">Request pending</p>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<Badge variant=\"secondary\" className=\"bg-purple-100 text-purple-700\">\n\t\t\t\tPending\n\t\t\t</Badge>\n\t\t</div>\n\t);\n}\n",
      "target": "<%- config.aliases.components %>/friendsdialog.tsx"
    }
  ]
}