import { useTranslation } from "react-i18next"; import { useDispatch, useSelector } from "react-redux"; import { selectAuthenticated, selectUsername } from "@/store/auth.ts"; import { closeMarket, selectCurrent, selectHistory, selectMaskItem, useConversationActions, } from "@/store/chat.ts"; import React, { useRef, useState } from "react"; import { ConversationInstance } from "@/api/types.tsx"; import { useToast } from "@/components/ui/use-toast.ts"; import { extractMessage, filterMessage } from "@/utils/processor.ts"; import { copyClipboard } from "@/utils/dom.ts"; import { useEffectAsync, useAnimation } from "@/utils/hook.ts"; import { mobile, openWindow } from "@/utils/device.ts"; import { Button } from "@/components/ui/button.tsx"; import { selectMenu, setMenu } from "@/store/menu.ts"; import { Copy, Eraser, LogIn, MoreHorizontal, Paintbrush, Plus, RotateCw, } from "lucide-react"; import ConversationSegment from "./ConversationSegment.tsx"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog.tsx"; import { getSharedLink, shareConversation } from "@/api/sharing.ts"; import { Input } from "@/components/ui/input.tsx"; import MenuBar from "@/components/app/MenuBar.tsx"; import { Separator } from "@/components/ui/separator.tsx"; import { goAuth } from "@/utils/app.ts"; import Avatar from "@/components/Avatar.tsx"; import { cn } from "@/components/ui/lib/utils.ts"; import { getNumberMemory } from "@/utils/memory.ts"; type Operation = { target: ConversationInstance | null; type: string; }; type SidebarActionProps = { setOperateConversation: (operation: Operation) => void; }; type ConversationListProps = { operateConversation: Operation; setOperateConversation: (operation: Operation) => void; }; function SidebarAction({ setOperateConversation }: SidebarActionProps) { const { t } = useTranslation(); const dispatch = useDispatch(); const { toast } = useToast(); const { toggle, refresh: refreshAction, removeAll: removeAllAction, } = useConversationActions(); const refreshRef = useRef(null); const [removeAll, setRemoveAll] = useState(false); const current = useSelector(selectCurrent); const mask = useSelector(selectMaskItem); async function handleDeleteAll(e: React.MouseEvent) { e.preventDefault(); e.stopPropagation(); (await removeAllAction()) ? toast({ title: t("conversation.delete-success"), description: t("conversation.delete-success-prompt"), }) : toast({ title: t("conversation.delete-failed"), description: t("conversation.delete-failed-prompt"), }); await refreshAction(); setOperateConversation({ target: null, type: "" }); setRemoveAll(false); } return (
{t("conversation.remove-all-title")} {t("conversation.remove-all-description")} {t("conversation.cancel")}
); } function SidebarConversationList({ operateConversation, setOperateConversation, }: ConversationListProps) { const { t } = useTranslation(); const { toast } = useToast(); const { remove } = useConversationActions(); const history: ConversationInstance[] = useSelector(selectHistory); const [shared, setShared] = useState(""); const current = useSelector(selectCurrent); async function handleDelete(e: React.MouseEvent) { e.preventDefault(); e.stopPropagation(); if (await remove(operateConversation?.target?.id || -1)) toast({ title: t("conversation.delete-success"), description: t("conversation.delete-success-prompt"), }); else toast({ title: t("conversation.delete-failed"), description: t("conversation.delete-failed-prompt"), }); setOperateConversation({ target: null, type: "" }); } async function handleShare(e: React.MouseEvent) { e.preventDefault(); e.stopPropagation(); const resp = await shareConversation(operateConversation?.target?.id || -1); if (resp.status) setShared(getSharedLink(resp.data)); else toast({ title: t("share.failed"), description: resp.message, }); setOperateConversation({ target: null, type: "" }); } return ( <>
{history.length ? ( history.map((conversation, i) => ( )) ) : (
{t("conversation.empty")}
)}
{ if (!open) setOperateConversation({ target: null, type: "" }); }} > {t("conversation.remove-title")} {t("conversation.remove-description")} {extractMessage( filterMessage(operateConversation?.target?.name || ""), )} {t("end")} {t("conversation.cancel")} {t("conversation.delete")} { if (!open) setOperateConversation({ target: null, type: "" }); }} > {t("share.title")} {t("share.description")} {extractMessage( filterMessage(operateConversation?.target?.name || ""), )} {t("end")} {t("conversation.cancel")} {t("share.title")} 0} onOpenChange={(open) => { if (!open) { setShared(""); setOperateConversation({ target: null, type: "" }); } }} > {t("share.success")}
{t("close")} { e.preventDefault(); e.stopPropagation(); openWindow(shared, "_blank"); }} > {t("share.view")}
); } function SidebarMenu() { const username = useSelector(selectUsername); return (
); } function SideBar() { const { t } = useTranslation(); const { refresh, toggle } = useConversationActions(); const current = useSelector(selectCurrent); const open = useSelector(selectMenu); const auth = useSelector(selectAuthenticated); const [operateConversation, setOperateConversation] = useState({ target: null, type: "", }); useEffectAsync(async () => { const resp = await refresh(); const store = getNumberMemory("history_conversation", -1); if (current === store) return; // no need to dispatch current if (store === -1) return; // -1 is default, no need to dispatch if (!resp.map((item) => item.id).includes(store)) return; // not in the list, no need to dispatch await toggle(store); }, []); return (
{auth ? (
) : ( )}
); } export default SideBar;