telegram-files/web/src/components/chat-select.tsx
2025-01-21 21:10:37 +08:00

163 lines
5.5 KiB
TypeScript

import { Archive, Check, ChevronsUpDown, Ellipsis, List } from "lucide-react";
import { Button } from "./ui/button";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "./ui/command";
import { useEffect, useState } from "react";
import { useTelegramChat } from "@/hooks/use-telegram-chat";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { cn } from "@/lib/utils";
import { CommandLoading } from "cmdk";
import { Toggle } from "./ui/toggle";
import { TooltipWrapper } from "@/components/ui/tooltip";
export default function ChatSelect({ disabled }: { disabled: boolean }) {
const [open, setOpen] = useState(false);
const [search, setSearch] = useState("");
const [archived, setArchived] = useState(false);
const {
isLoading,
handleQueryChange,
chats,
chat: selectedChat,
handleChatChange,
handleArchivedChange,
} = useTelegramChat();
useEffect(() => {
handleQueryChange(search);
}, [search, handleQueryChange]);
useEffect(() => {
handleArchivedChange(archived);
}, [archived, handleArchivedChange]);
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild disabled={disabled}>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="w-full justify-between md:w-[250px]"
>
{selectedChat ? (
<div className="flex items-center gap-2">
<Avatar className="h-6 w-6">
<AvatarImage
src={`data:image/png;base64,${selectedChat.avatar}`}
/>
<AvatarFallback>
{" "}
{selectedChat.name[0] ?? selectedChat.id[0]}
</AvatarFallback>
</Avatar>
<span className="max-w-[170px] overflow-hidden truncate">
{(selectedChat.name ?? "").length > 0
? selectedChat.name
: selectedChat.id}
</span>
</div>
) : (
"Select chat ..."
)}
<ChevronsUpDown className="opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[300px] p-0">
<Command shouldFilter={false}>
<div className="flex w-full border-b">
<TooltipWrapper
content={archived ? "Show main chats" : "Show archived chats"}
>
<Toggle
className="h-9 rounded-none border-r"
pressed={archived}
onPressedChange={setArchived}
>
{archived ? (
<Archive className="h-5 w-5" />
) : (
<List className="h-5 w-5" />
)}
</Toggle>
</TooltipWrapper>
<div className="flex-1">
<CommandInput
placeholder="Search chat..."
className="h-9"
value={search}
onValueChange={setSearch}
/>
</div>
</div>
<CommandList className="relative">
{isLoading && (
<CommandLoading>
<div className="absolute left-1/2 top-1/2 -translate-x-2 -translate-y-2 transform">
<Ellipsis className="h-4 w-4 animate-pulse" />
</div>
</CommandLoading>
)}
<CommandEmpty>
{!isLoading && chats.length === 0 && "No chat found."}
</CommandEmpty>
<CommandGroup>
{chats.map((chat) => (
<CommandItem
key={chat.id}
value={chat.id}
onSelect={(currentValue) => {
handleChatChange(currentValue);
setOpen(false);
}}
>
<div className="flex items-center gap-2">
<div
className={cn(
"h-3 w-1 rounded-md bg-green-500 opacity-0",
{
"opacity-100": chat.autoEnabled,
},
)}
/>
<Avatar className="h-6 w-6">
<AvatarImage
src={`data:image/png;base64,${chat.avatar}`}
/>
<AvatarFallback>
{chat.name[0] ?? chat.id[0]}
</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<span className="font-medium">
{(chat.name ?? "").length > 0 ? chat.name : chat.id}
</span>
<span className="text-xs text-muted-foreground">
{chat.type} {chat.unreadCount ?? 0} unread
</span>
</div>
</div>
<Check
className={cn(
"ml-auto",
selectedChat?.id === chat.id
? "opacity-100"
: "opacity-0",
)}
/>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}