refactor: move conversation list into component

This commit is contained in:
steven
2023-04-28 17:14:47 +08:00
parent 435e0bffeb
commit d8f1e99192
2 changed files with 127 additions and 99 deletions

View File

@ -2,17 +2,16 @@ import { Drawer } from "@mui/material";
import { head } from "lodash-es"; import { head } from "lodash-es";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useConversationStore, useConnectionStore, useLayoutStore, ResponsiveWidth } from "@/store"; import { useConnectionStore, useLayoutStore, ResponsiveWidth } from "@/store";
import { Conversation, Connection } from "@/types"; import { Connection } from "@/types";
import Select from "./kit/Select"; import Select from "./kit/Select";
import Tooltip from "./kit/Tooltip"; import Tooltip from "./kit/Tooltip";
import Dropdown, { DropdownItem } from "./kit/Dropdown";
import Icon from "./Icon"; import Icon from "./Icon";
import EngineIcon from "./EngineIcon"; import EngineIcon from "./EngineIcon";
import DarkModeSwitch from "./DarkModeSwitch"; import DarkModeSwitch from "./DarkModeSwitch";
import CreateConnectionModal from "./CreateConnectionModal"; import CreateConnectionModal from "./CreateConnectionModal";
import SettingModal from "./SettingModal"; import SettingModal from "./SettingModal";
import UpdateConversationModal from "./UpdateConversationModal"; import ConversationList from "./Sidebar/ConversationList";
interface State { interface State {
showCreateConnectionModal: boolean; showCreateConnectionModal: boolean;
@ -24,23 +23,16 @@ const ConnectionSidebar = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const layoutStore = useLayoutStore(); const layoutStore = useLayoutStore();
const connectionStore = useConnectionStore(); const connectionStore = useConnectionStore();
const conversationStore = useConversationStore();
const [state, setState] = useState<State>({ const [state, setState] = useState<State>({
showCreateConnectionModal: false, showCreateConnectionModal: false,
showSettingModal: false, showSettingModal: false,
showUpdateConversationModal: false, showUpdateConversationModal: false,
}); });
const [editConnectionModalContext, setEditConnectionModalContext] = useState<Connection>(); const [editConnectionModalContext, setEditConnectionModalContext] = useState<Connection>();
const [updateConversationModalContext, setUpdateConversationModalContext] = useState<Conversation>();
const [isRequestingDatabase, setIsRequestingDatabase] = useState<boolean>(false); const [isRequestingDatabase, setIsRequestingDatabase] = useState<boolean>(false);
const connectionList = connectionStore.connectionList; const connectionList = connectionStore.connectionList;
const currentConnectionCtx = connectionStore.currentConnectionCtx; const currentConnectionCtx = connectionStore.currentConnectionCtx;
const databaseList = connectionStore.databaseList.filter((database) => database.connectionId === currentConnectionCtx?.connection.id); const databaseList = connectionStore.databaseList.filter((database) => database.connectionId === currentConnectionCtx?.connection.id);
const conversationList = conversationStore.conversationList.filter(
(conversation) =>
conversation.connectionId === currentConnectionCtx?.connection.id &&
conversation.databaseName === currentConnectionCtx?.database?.name
);
useEffect(() => { useEffect(() => {
const handleWindowResize = () => { const handleWindowResize = () => {
@ -87,13 +79,6 @@ const ConnectionSidebar = () => {
}); });
}; };
const toggleUpdateConversationModal = (show = true) => {
setState({
...state,
showUpdateConversationModal: show,
});
};
const handleConnectionSelect = async (connection: Connection) => { const handleConnectionSelect = async (connection: Connection) => {
const databaseList = await connectionStore.getOrFetchDatabaseList(connection); const databaseList = await connectionStore.getOrFetchDatabaseList(connection);
connectionStore.setCurrentConnectionCtx({ connectionStore.setCurrentConnectionCtx({
@ -123,36 +108,6 @@ const ConnectionSidebar = () => {
}); });
}; };
const handleCreateConversation = () => {
if (!currentConnectionCtx) {
conversationStore.createConversation();
} else {
conversationStore.createConversation(currentConnectionCtx.connection.id, currentConnectionCtx.database?.name);
}
};
const handleConversationSelect = (conversation: Conversation) => {
conversationStore.setCurrentConversationId(conversation.id);
if (layoutStore.isMobileView) {
layoutStore.toggleSidebar(false);
}
};
const handleEditConversation = (conversation: Conversation) => {
setUpdateConversationModalContext(conversation);
setState({
...state,
showUpdateConversationModal: true,
});
};
const handleDeleteConversation = (conversation: Conversation) => {
conversationStore.clearConversation((item) => item.id !== conversation.id);
if (conversationStore.currentConversationId === conversation.id) {
conversationStore.setCurrentConversationId(undefined);
}
};
return ( return (
<> <>
<Drawer <Drawer
@ -240,53 +195,7 @@ const ConnectionSidebar = () => {
/> />
</div> </div>
)} )}
{conversationList.map((conversation) => ( <ConversationList />
<div
key={conversation.id}
className={`w-full mt-2 first:mt-4 py-3 pl-4 pr-2 rounded-lg flex flex-row justify-start items-center cursor-pointer dark:text-gray-300 border border-transparent group hover:bg-white dark:hover:bg-zinc-800 ${
conversation.id === conversationStore.currentConversationId && "bg-white dark:bg-zinc-800 border-gray-200 font-medium"
}`}
onClick={() => handleConversationSelect(conversation)}
>
{conversation.id === conversationStore.currentConversationId ? (
<Icon.IoChatbubble className="w-5 h-auto mr-1.5 shrink-0" />
) : (
<Icon.IoChatbubbleOutline className="w-5 h-auto mr-1.5 opacity-80 shrink-0" />
)}
<span className="truncate grow">{conversation.title || "SQL Chat"}</span>
<Dropdown
tigger={
<button className="w-4 h-4 shrink-0 group-hover:visible invisible flex justify-center items-center text-gray-400 hover:text-gray-500">
<Icon.FiMoreHorizontal className="w-full h-auto" />
</button>
}
>
<div className="p-1 flex flex-col justify-start items-start bg-white dark:bg-zinc-900 shadow-lg rounded-lg">
<DropdownItem
className="w-full p-1 px-2 flex flex-row justify-start items-center rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-zinc-800"
onClick={() => handleEditConversation(conversation)}
>
<Icon.FiEdit3 className="w-4 h-auto mr-2 opacity-70" />
{t("common.edit")}
</DropdownItem>
<DropdownItem
className="w-full p-1 px-2 flex flex-row justify-start items-center rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-zinc-800"
onClick={() => handleDeleteConversation(conversation)}
>
<Icon.IoTrash className="w-4 h-auto mr-2 opacity-70" />
{t("common.delete")}
</DropdownItem>
</div>
</Dropdown>
</div>
))}
<button
className="w-full my-4 py-3 px-4 border dark:border-zinc-800 rounded-lg flex flex-row justify-center items-center text-gray-500 dark:text-gray-400 hover:text-gray-700 hover:bg-gray-50 dark:hover:bg-zinc-800"
onClick={handleCreateConversation}
>
<Icon.AiOutlinePlus className="w-5 h-auto mr-1" />
{t("conversation.new-chat")}
</button>
</div> </div>
<div className="sticky bottom-0 w-full flex flex-col justify-center bg-gray-100 dark:bg-zinc-700 backdrop-blur bg-opacity-60 pb-4 py-2"> <div className="sticky bottom-0 w-full flex flex-col justify-center bg-gray-100 dark:bg-zinc-700 backdrop-blur bg-opacity-60 pb-4 py-2">
<a <a
@ -333,10 +242,6 @@ const ConnectionSidebar = () => {
)} )}
{state.showSettingModal && <SettingModal close={() => toggleSettingModal(false)} />} {state.showSettingModal && <SettingModal close={() => toggleSettingModal(false)} />}
{updateConversationModalContext && state.showUpdateConversationModal && (
<UpdateConversationModal close={() => toggleUpdateConversationModal(false)} conversation={updateConversationModalContext} />
)}
</> </>
); );
}; };

View File

@ -0,0 +1,123 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { useConversationStore, useConnectionStore, useLayoutStore } from "@/store";
import { Conversation } from "@/types";
import Dropdown, { DropdownItem } from "../kit/Dropdown";
import Icon from "../Icon";
import UpdateConversationModal from "../UpdateConversationModal";
interface State {
showUpdateConversationModal: boolean;
}
const ConversationList = () => {
const { t } = useTranslation();
const layoutStore = useLayoutStore();
const connectionStore = useConnectionStore();
const conversationStore = useConversationStore();
const [state, setState] = useState<State>({
showUpdateConversationModal: false,
});
const [updateConversationModalContext, setUpdateConversationModalContext] = useState<Conversation>();
const currentConnectionCtx = connectionStore.currentConnectionCtx;
const conversationList = conversationStore.conversationList.filter(
(conversation) =>
conversation.connectionId === currentConnectionCtx?.connection.id &&
conversation.databaseName === currentConnectionCtx?.database?.name
);
const toggleUpdateConversationModal = (show = true) => {
setState({
...state,
showUpdateConversationModal: show,
});
};
const handleCreateConversation = () => {
if (!currentConnectionCtx) {
conversationStore.createConversation();
} else {
conversationStore.createConversation(currentConnectionCtx.connection.id, currentConnectionCtx.database?.name);
}
};
const handleConversationSelect = (conversation: Conversation) => {
conversationStore.setCurrentConversationId(conversation.id);
if (layoutStore.isMobileView) {
layoutStore.toggleSidebar(false);
}
};
const handleEditConversation = (conversation: Conversation) => {
setUpdateConversationModalContext(conversation);
setState({
...state,
showUpdateConversationModal: true,
});
};
const handleDeleteConversation = (conversation: Conversation) => {
conversationStore.clearConversation((item) => item.id !== conversation.id);
if (conversationStore.currentConversationId === conversation.id) {
conversationStore.setCurrentConversationId(undefined);
}
};
return (
<>
{conversationList.map((conversation) => (
<div
key={conversation.id}
className={`w-full mt-2 first:mt-4 py-3 pl-4 pr-2 rounded-lg flex flex-row justify-start items-center cursor-pointer dark:text-gray-300 border border-transparent group hover:bg-white dark:hover:bg-zinc-800 ${
conversation.id === conversationStore.currentConversationId && "bg-white dark:bg-zinc-800 border-gray-200 font-medium"
}`}
onClick={() => handleConversationSelect(conversation)}
>
{conversation.id === conversationStore.currentConversationId ? (
<Icon.IoChatbubble className="w-5 h-auto mr-1.5 shrink-0" />
) : (
<Icon.IoChatbubbleOutline className="w-5 h-auto mr-1.5 opacity-80 shrink-0" />
)}
<span className="truncate grow">{conversation.title || "SQL Chat"}</span>
<Dropdown
tigger={
<button className="w-4 h-4 shrink-0 group-hover:visible invisible flex justify-center items-center text-gray-400 hover:text-gray-500">
<Icon.FiMoreHorizontal className="w-full h-auto" />
</button>
}
>
<div className="p-1 flex flex-col justify-start items-start bg-white dark:bg-zinc-900 shadow-lg rounded-lg">
<DropdownItem
className="w-full p-1 px-2 flex flex-row justify-start items-center rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-zinc-800"
onClick={() => handleEditConversation(conversation)}
>
<Icon.FiEdit3 className="w-4 h-auto mr-2 opacity-70" />
{t("common.edit")}
</DropdownItem>
<DropdownItem
className="w-full p-1 px-2 flex flex-row justify-start items-center rounded-lg cursor-pointer hover:bg-gray-100 dark:hover:bg-zinc-800"
onClick={() => handleDeleteConversation(conversation)}
>
<Icon.IoTrash className="w-4 h-auto mr-2 opacity-70" />
{t("common.delete")}
</DropdownItem>
</div>
</Dropdown>
</div>
))}
<button
className="w-full my-4 py-3 px-4 border dark:border-zinc-800 rounded-lg flex flex-row justify-center items-center text-gray-500 dark:text-gray-400 hover:text-gray-700 hover:bg-gray-50 dark:hover:bg-zinc-800"
onClick={handleCreateConversation}
>
<Icon.AiOutlinePlus className="w-5 h-auto mr-1" />
{t("conversation.new-chat")}
</button>
{updateConversationModalContext && state.showUpdateConversationModal && (
<UpdateConversationModal close={() => toggleUpdateConversationModal(false)} conversation={updateConversationModalContext} />
)}
</>
);
};
export default ConversationList;