import { ChatbotUIContext } from "@/context/context" import { updateAssistant } from "@/db/assistants" import { updateChat } from "@/db/chats" import { updateCollection } from "@/db/collections" import { updateFile } from "@/db/files" import { updateModel } from "@/db/models" import { updatePreset } from "@/db/presets" import { updatePrompt } from "@/db/prompts" import { updateTool } from "@/db/tools" import { cn } from "@/lib/utils" import { Tables } from "@/supabase/types" import { ContentType, DataItemType, DataListType } from "@/types" import { FC, useContext, useEffect, useRef, useState } from "react" import { Separator } from "../ui/separator" import { AssistantItem } from "./items/assistants/assistant-item" import { ChatItem } from "./items/chat/chat-item" import { CollectionItem } from "./items/collections/collection-item" import { FileItem } from "./items/files/file-item" import { Folder } from "./items/folders/folder-item" import { ModelItem } from "./items/models/model-item" import { PresetItem } from "./items/presets/preset-item" import { PromptItem } from "./items/prompts/prompt-item" import { ToolItem } from "./items/tools/tool-item" import { useTranslation } from "react-i18next"; interface SidebarDataListProps { contentType: ContentType data: DataListType folders: Tables<"folders">[] } export const SidebarDataList: FC = ({ contentType, data, folders }) => { const { t } = useTranslation(); const dateCategories = [ { key: "Today", label: t("side.chatTime.Today") }, { key: "Yesterday", label: t("side.chatTime.Yesterday") }, { key: "PreviousWeek", label: t("side.chatTime.PreviousWeek") }, { key: "Older", label: t("side.chatTime.Older") } ] const { setChats, setPresets, setPrompts, setFiles, setCollections, setAssistants, setTools, setModels } = useContext(ChatbotUIContext) const divRef = useRef(null) const [isOverflowing, setIsOverflowing] = useState(false) const [isDragOver, setIsDragOver] = useState(false) const getDataListComponent = ( contentType: ContentType, item: DataItemType ) => { switch (contentType) { case "chats": return } /> case "presets": return } /> case "prompts": return } /> case "files": return } /> case "collections": return ( } /> ) case "assistants": return ( } /> ) case "tools": return } /> case "models": return } /> default: return null } } const getSortedData = ( data: any, dateCategory: "Today" | "Yesterday" | "PreviousWeek" | "Older" ) => { const now = new Date() const todayStart = new Date(now.setHours(0, 0, 0, 0)) const yesterdayStart = new Date( new Date().setDate(todayStart.getDate() - 1) ) const oneWeekAgoStart = new Date( new Date().setDate(todayStart.getDate() - 7) ) return data .filter((item: any) => { const itemDate = new Date(item.updated_at || item.created_at) switch (dateCategory) { case "Today": return itemDate >= todayStart case "Yesterday": return itemDate >= yesterdayStart && itemDate < todayStart case "PreviousWeek": return itemDate >= oneWeekAgoStart && itemDate < yesterdayStart case "Older": return itemDate < oneWeekAgoStart default: return true } }) .sort( ( a: { updated_at: string; created_at: string }, b: { updated_at: string; created_at: string } ) => new Date(b.updated_at || b.created_at).getTime() - new Date(a.updated_at || a.created_at).getTime() ) } const updateFunctions = { chats: updateChat, presets: updatePreset, prompts: updatePrompt, files: updateFile, collections: updateCollection, assistants: updateAssistant, tools: updateTool, models: updateModel } const stateUpdateFunctions = { chats: setChats, presets: setPresets, prompts: setPrompts, files: setFiles, collections: setCollections, assistants: setAssistants, tools: setTools, models: setModels } const updateFolder = async (itemId: string, folderId: string | null) => { const item: any = data.find(item => item.id === itemId) if (!item) return null const updateFunction = updateFunctions[contentType] const setStateFunction = stateUpdateFunctions[contentType] if (!updateFunction || !setStateFunction) return const updatedItem = await updateFunction(item.id, { folder_id: folderId }) setStateFunction((items: any) => items.map((item: any) => item.id === updatedItem.id ? updatedItem : item ) ) } const handleDragEnter = (e: React.DragEvent) => { e.preventDefault() setIsDragOver(true) } const handleDragLeave = (e: React.DragEvent) => { e.preventDefault() setIsDragOver(false) } const handleDragStart = (e: React.DragEvent, id: string) => { e.dataTransfer.setData("text/plain", id) } const handleDragOver = (e: React.DragEvent) => { e.preventDefault() } const handleDrop = (e: React.DragEvent) => { e.preventDefault() const target = e.target as Element if (!target.closest("#folder")) { const itemId = e.dataTransfer.getData("text/plain") updateFolder(itemId, null) } setIsDragOver(false) } useEffect(() => { if (divRef.current) { setIsOverflowing( divRef.current.scrollHeight > divRef.current.clientHeight ) } }, [data]) const dataWithFolders = data.filter(item => item.folder_id) const dataWithoutFolders = data.filter(item => item.folder_id === null) // 获取 "No {contentType}" 的国际化文本 const getNoContentTypeText = (contentType: string) => { const translatedContentType = t(`contentType.${contentType}`); return t('side.sidebarNoContentType', { contentType: translatedContentType }) + "."; }; return ( <>
{data.length === 0 && (
{getNoContentTypeText(contentType)}
)} {(dataWithFolders.length > 0 || dataWithoutFolders.length > 0) && (
{folders.map(folder => ( {dataWithFolders .filter(item => item.folder_id === folder.id) .map(item => (
handleDragStart(e, item.id)} > {getDataListComponent(contentType, item)}
))}
))} {folders.length > 0 && } {contentType === "chats" ? ( <> {/* {["Today", "Yesterday", "Previous Week", "Older"].map( dateCategory => { const sortedData = getSortedData( dataWithoutFolders, dateCategory as | "Today" | "Yesterday" | "Previous Week" | "Older" ) */} {dateCategories.map(({ key, label }) => { const sortedData = getSortedData( dataWithoutFolders, key as "Today" | "Yesterday" | "PreviousWeek" | "Older" ) return ( // sortedData.length > 0 && ( //
//
// {dateCategory} //
sortedData.length > 0 && (
{/* ✅ 用 key 替代已删的变量 */}
{label} {/* ✅ 用 label 显示翻译文本 */}
{sortedData.map((item: any) => (
handleDragStart(e, item.id)} > {getDataListComponent(contentType, item)}
))}
) ) } )} ) : (
{dataWithoutFolders.map(item => { return (
handleDragStart(e, item.id)} > {getDataListComponent(contentType, item)}
) })}
)}
)}
) }