import { useState } from "react"; import { useNavigate } from "react-router-dom"; import { Check, Plus, Settings, Users } from "lucide-react"; import { toast } from "sonner"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { Small } from "@/components/ui/typography"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Separator } from "@/components/ui/separator"; import { useNetworks } from "@/hooks/use-networks"; import { useMyInvitations, useAcceptInvitation } from "@/hooks/use-invitations"; import { apiClient } from "@/api/client"; import { Progress } from "@/components/ui/progress"; import type { Network, Invitation } from "@/api/types"; function NetworkRow({ network, onClick, onSettingsClick, }: { network: Network; onClick: () => void; onSettingsClick: () => void; }) { const initials = network.name.slice(0, 2).toUpperCase(); const memberCount = network.humans.length; return ( ); } function InvitationRow({ invitation }: { invitation: Invitation }) { const acceptInvitation = useAcceptInvitation(); const initials = invitation.network_name.slice(0, 2).toUpperCase(); const handleAccept = () => { acceptInvitation.mutate(invitation.network_id, { onSuccess: () => { toast.success(`Joined ${invitation.network_name}`); }, onError: (err) => { toast.error(err.message || "Failed to accept invitation"); }, }); }; return (
{initials}

{invitation.network_name}

You've been invited
); } function CreateNetworkDialog({ open, onOpenChange, }: { open: boolean; onOpenChange: (open: boolean) => void; }) { const [name, setName] = useState(""); const navigate = useNavigate(); const queryClient = useQueryClient(); const createNetwork = useMutation({ mutationFn: (networkName: string) => apiClient.createNetwork({ name: networkName }), onSuccess: (network) => { queryClient.invalidateQueries({ queryKey: ["networks"] }); toast.success(`Created ${network.name}`); onOpenChange(false); setName(""); navigate(`/${network.id}/settings`); }, onError: (err) => { toast.error(err.message || "Failed to create network"); }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const trimmed = name.trim(); if (!trimmed) return; createNetwork.mutate(trimmed); }; return ( Create a Network Caution: creating a network will create a new billing account. If your team already has a network, ask them for an invite.
setName(e.target.value)} autoFocus />
); } export default function NetworkSelector() { const navigate = useNavigate(); const [createDialogOpen, setCreateDialogOpen] = useState(false); const { data: networks, isPending, error, refetch } = useNetworks(); const { data: invitations } = useMyInvitations(); if (isPending) { return ; } if (error) { return (

Failed to load networks

{error.message}

); } const hasInvitations = invitations && invitations.length > 0; const hasNetworks = networks && networks.length > 0; if (!hasNetworks && !hasInvitations) { return (

You don't have access to any networks yet. Create one or ask your admin for an invite.

); } return ( <>
{hasInvitations && ( <>

Pending Invitations

{invitations.length}
{invitations.map((inv, index) => (
{index < invitations.length - 1 && ( )}
))} )} {hasNetworks && ( <> {hasInvitations && (

Your Networks

)} {networks.map((network, index) => (
navigate(`/${network.id}`)} onSettingsClick={() => navigate(`/${network.id}/settings`) } /> {index < networks.length - 1 && ( )}
))} )}
); }