Spaces:
Running
Running
| "use client" | |
| import { ComponentPropsWithoutRef, useMemo, useState } from "react" | |
| import { Check, ChevronsUpDown, PlusCircle } from "lucide-react"; | |
| import { cn } from "@/lib/utils" | |
| import { Button } from "@/components/ui/button" | |
| import { | |
| Command, | |
| CommandEmpty, | |
| CommandGroup, | |
| CommandInput, | |
| CommandItem, | |
| CommandList, | |
| CommandSeparator, | |
| } from "@/components/ui/command" | |
| import { | |
| Dialog, | |
| DialogContent, | |
| DialogDescription, | |
| DialogHeader, | |
| DialogTitle, | |
| DialogTrigger, | |
| } from "@/components/ui/dialog" | |
| import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover" | |
| import NewTeamForm from "@/components/basejump/new-team-form"; | |
| import { useAccounts } from "@/hooks/use-accounts"; | |
| type PopoverTriggerProps = ComponentPropsWithoutRef<typeof PopoverTrigger>; | |
| type SelectedAccount = NonNullable<ReturnType<typeof useAccounts>["data"]>[0]; | |
| interface AccountSelectorProps extends PopoverTriggerProps { | |
| accountId: string; | |
| placeholder?: string; | |
| onAccountSelected?: (account: SelectedAccount) => void; | |
| } | |
| export default function AccountSelector({ className, accountId, onAccountSelected, placeholder = "Select an account..." }: AccountSelectorProps) { | |
| const [open, setOpen] = useState(false) | |
| const [showNewTeamDialog, setShowNewTeamDialog] = useState(false) | |
| const { data: accounts } = useAccounts(); | |
| const { teamAccounts, personalAccount, selectedAccount } = useMemo(() => { | |
| const personalAccount = accounts?.find((account) => account.personal_account); | |
| const teamAccounts = accounts?.filter((account) => !account.personal_account); | |
| const selectedAccount = accounts?.find((account) => account.account_id === accountId); | |
| return { | |
| personalAccount, | |
| teamAccounts, | |
| selectedAccount, | |
| } | |
| }, [accounts, accountId]); | |
| return ( | |
| <Dialog open={showNewTeamDialog} onOpenChange={setShowNewTeamDialog}> | |
| <Popover open={open} onOpenChange={setOpen}> | |
| <PopoverTrigger asChild> | |
| <Button | |
| variant="ghost" | |
| role="combobox" | |
| aria-expanded={open} | |
| aria-label="Select a team" | |
| className={cn( | |
| "w-full flex items-center gap-2 h-9 pl-3 pr-2 rounded-md justify-between border border-subtle dark:border-white/10 bg-transparent hover:bg-hover-bg text-foreground/90", | |
| className | |
| )} | |
| > | |
| <span className="truncate max-w-[180px]"> | |
| {selectedAccount?.name || placeholder} | |
| </span> | |
| <ChevronsUpDown className="h-4 w-4 shrink-0 text-foreground/50" /> | |
| </Button> | |
| </PopoverTrigger> | |
| <PopoverContent className="w-[250px] p-0 border-subtle dark:border-white/10 bg-card-bg dark:bg-background-secondary rounded-xl shadow-custom"> | |
| <Command className="rounded-xl overflow-hidden bg-card-bg dark:bg-background-secondary border-0"> | |
| <CommandList className="border-0 bg-card-bg dark:bg-background-secondary"> | |
| <CommandInput placeholder="Search account..." className="h-9 border-0 focus:ring-0 rounded-t-xl bg-card-bg dark:bg-background-secondary text-foreground/90" /> | |
| <CommandEmpty className="text-foreground/70 text-sm py-2">No account found.</CommandEmpty> | |
| <CommandGroup heading="Personal Account" className="text-xs font-medium text-foreground/70 bg-card-bg dark:bg-background-secondary"> | |
| <CommandItem | |
| key={personalAccount?.account_id} | |
| onSelect={() => { | |
| if (onAccountSelected) { | |
| onAccountSelected(personalAccount!) | |
| } | |
| setOpen(false) | |
| }} | |
| className="text-sm rounded-md bg-card-bg dark:bg-background-secondary hover:!bg-[#f1eee7] dark:hover:!bg-[#141413] aria-selected:!bg-[#f1eee7] dark:aria-selected:!bg-[#141413] text-foreground/90" | |
| > | |
| {personalAccount?.name} | |
| <Check | |
| className={cn( | |
| "ml-auto h-4 w-4 text-primary", | |
| selectedAccount?.account_id === personalAccount?.account_id | |
| ? "opacity-100" | |
| : "opacity-0" | |
| )} | |
| /> | |
| </CommandItem> | |
| </CommandGroup> | |
| {Boolean(teamAccounts?.length) && ( | |
| <CommandGroup heading="Teams" className="text-xs font-medium text-foreground/70 bg-card-bg dark:bg-background-secondary"> | |
| {teamAccounts?.map((team) => ( | |
| <CommandItem | |
| key={team.account_id} | |
| onSelect={() => { | |
| if (onAccountSelected) { | |
| onAccountSelected(team) | |
| } | |
| setOpen(false) | |
| }} | |
| className="text-sm rounded-md bg-card-bg dark:bg-background-secondary hover:!bg-[#f1eee7] dark:hover:!bg-[#141413] aria-selected:!bg-[#f1eee7] dark:aria-selected:!bg-[#141413] text-foreground/90" | |
| > | |
| {team.name} | |
| <Check | |
| className={cn( | |
| "ml-auto h-4 w-4 text-primary", | |
| selectedAccount?.account_id === team.account_id | |
| ? "opacity-100" | |
| : "opacity-0" | |
| )} | |
| /> | |
| </CommandItem> | |
| ))} | |
| </CommandGroup> | |
| )} | |
| </CommandList> | |
| <CommandSeparator className="border-subtle dark:border-white/10" /> | |
| <CommandList className="bg-card-bg dark:bg-background-secondary"> | |
| <CommandGroup className="bg-card-bg dark:bg-background-secondary"> | |
| <DialogTrigger asChild> | |
| <CommandItem | |
| value="new-team" | |
| onSelect={() => { | |
| setOpen(false) | |
| setShowNewTeamDialog(true) | |
| }} | |
| className="text-sm rounded-md bg-card-bg dark:bg-background-secondary hover:!bg-[#f1eee7] dark:hover:!bg-[#141413] text-foreground/90" | |
| > | |
| <PlusCircle className="mr-2 h-4 w-4 text-primary" /> | |
| Create Team | |
| </CommandItem> | |
| </DialogTrigger> | |
| </CommandGroup> | |
| </CommandList> | |
| </Command> | |
| </PopoverContent> | |
| </Popover> | |
| <DialogContent className="sm:max-w-[425px] border-subtle dark:border-white/10 bg-card-bg dark:bg-background-secondary rounded-2xl shadow-custom"> | |
| <DialogHeader> | |
| <DialogTitle className="text-foreground">Create a new team</DialogTitle> | |
| <DialogDescription className="text-foreground/70"> | |
| Create a team to collaborate with others. | |
| </DialogDescription> | |
| </DialogHeader> | |
| <NewTeamForm /> | |
| </DialogContent> | |
| </Dialog> | |
| ) | |
| } | |