import { useState, useRef, useCallback, useEffect } from "react"; import { ChevronDownIcon, RefreshCw } from "lucide-react"; import { useTranslation } from "react-i18next"; import { Popover, PopoverTrigger, PopoverContent, } from "@/components/ui/popover"; import { useDebounce, useKeyPress, usePagination } from "ahooks"; import clsx from "clsx"; import logoImg from "@/assets/icon.svg"; import VisibleKey from "@/components/Common/VisibleKey"; import { useConnectStore } from "@/stores/connectStore"; import FontIcon from "@/components/Common/Icons/FontIcon"; import { useShortcutsStore } from "@/stores/shortcutsStore"; import NoDataImage from "@/components/Common/NoDataImage"; import PopoverInput from "@/components/Common/PopoverInput"; import { AssistantFetcher } from "./AssistantFetcher"; import AssistantItem from "./AssistantItem"; import Pagination from "@/components/Common/Pagination"; import { useSearchStore } from "@/stores/searchStore"; import { Button } from "../ui/button"; interface AssistantListProps { assistantIDs?: string[]; } export function AssistantList({ assistantIDs = [] }: AssistantListProps) { const { t } = useTranslation(); const currentService = useConnectStore((state) => state.currentService); const currentAssistant = useConnectStore((state) => state.currentAssistant); const setCurrentAssistant = useConnectStore((state) => { return state.setCurrentAssistant; }); const assistantList = useConnectStore((state) => state.assistantList); const aiAssistant = useShortcutsStore((state) => state.aiAssistant); const [assistants, setAssistants] = useState([]); const [isRefreshing, setIsRefreshing] = useState(false); const popoverRef = useRef(null); const popoverButtonRef = useRef(null); const searchInputRef = useRef(null); const [keyword, setKeyword] = useState(""); const debounceKeyword = useDebounce(keyword, { wait: 500 }); const askAiAssistantId = useSearchStore((state) => state.askAiAssistantId); const setAskAiAssistantId = useSearchStore((state) => { return state.setAskAiAssistantId; }); const targetAssistantId = useSearchStore((state) => state.targetAssistantId); const setTargetAssistantId = useSearchStore((state) => { return state.setTargetAssistantId; }); const { fetchAssistant } = AssistantFetcher({ debounceKeyword, assistantIDs, }); const getAssistants = (params: { current: number; pageSize: number }) => { return fetchAssistant(params); }; const { pagination, runAsync } = usePagination(getAssistants, { defaultPageSize: 5, refreshDeps: [currentService?.id, debounceKeyword, currentService?.enabled], onSuccess(data) { setAssistants(data.list); if (data.list.length === 0) { setCurrentAssistant(void 0); } }, }); const handleRefresh = async () => { setIsRefreshing(true); await runAsync({ current: 1, pageSize: 5 }); setTimeout(() => setIsRefreshing(false), 1000); }; const [highlightIndex, setHighlightIndex] = useState(-1); const [isKeyboardActive, setIsKeyboardActive] = useState(false); const [open, setOpen] = useState(false); useEffect(() => { const targetId = askAiAssistantId ?? targetAssistantId; if (!targetId || assistantList.length === 0) return; const matched = assistantList.find((item) => item._id === targetId); if (!matched) return; if (currentAssistant?._id !== matched._id) { setCurrentAssistant(matched); } if (askAiAssistantId) { setAskAiAssistantId(void 0); } else if (targetAssistantId) { setTargetAssistantId(void 0); } }, [assistantList, askAiAssistantId, targetAssistantId]); useKeyPress( ["uparrow", "downarrow", "enter"], (event, key) => { const isClose = !open; if (isClose) return; event.stopPropagation(); event.preventDefault(); setIsKeyboardActive(true); const index = assistants.findIndex( (item) => item._id === currentAssistant?._id ); const length = assistants.length; if (length <= 1) return; let nextIndex = highlightIndex === -1 ? index : highlightIndex; if (key === "uparrow") { nextIndex = nextIndex > 0 ? nextIndex - 1 : length - 1; } else if (key === "downarrow") { nextIndex = nextIndex < length - 1 ? nextIndex + 1 : 0; } if (key === "enter") { setCurrentAssistant(assistants[nextIndex]); return popoverButtonRef.current?.click(); } setHighlightIndex(nextIndex); }, { target: popoverRef, } ); const handlePrev = useCallback(() => { if (pagination.current <= 1) return; pagination.changeCurrent(pagination.current - 1); }, [pagination]); const handleNext = useCallback(() => { if (pagination.current >= pagination.totalPage) { return; } pagination.changeCurrent(pagination.current + 1); }, [pagination]); const handleMouseMove = useCallback(() => { setHighlightIndex(-1); setIsKeyboardActive(false); }, []); return (
{ setOpen(v); }} > {currentAssistant?._source?.icon?.startsWith("font_") ? ( ) : ( {t("assistant.message.logo")} )}
{currentAssistant?._source?.name || "Coco AI"}
{ popoverButtonRef.current?.click(); }} >
{t("assistant.popover.title")}({pagination.total})
{ searchInputRef.current?.focus(); }} > ) => { setKeyword(event.target.value); }} /> {assistants.length > 0 ? ( <> {assistants.map((assistant, index) => { return ( { setCurrentAssistant(assistant); popoverButtonRef.current?.click(); }} /> ); })} ) : (
)}
); }