|
@@ -1,14 +1,13 @@
|
|
|
-import { useState, useRef, useEffect, useLayoutEffect } from "react";
|
|
|
import DeleteIcon from "../icons/delete.svg";
|
|
|
import styles from "./home.module.scss";
|
|
|
-
|
|
|
import {
|
|
|
- Message,
|
|
|
- SubmitKey,
|
|
|
- useChatStore,
|
|
|
- ChatSession,
|
|
|
- BOT_HELLO,
|
|
|
-} from "../store";
|
|
|
+ DragDropContext,
|
|
|
+ Droppable,
|
|
|
+ Draggable,
|
|
|
+ OnDragEndResponder,
|
|
|
+} from "@hello-pangea/dnd";
|
|
|
+
|
|
|
+import { useChatStore } from "../store";
|
|
|
|
|
|
import Locale from "../locales";
|
|
|
import { isMobileScreen } from "../utils";
|
|
@@ -20,54 +19,92 @@ export function ChatItem(props: {
|
|
|
count: number;
|
|
|
time: string;
|
|
|
selected: boolean;
|
|
|
+ id: number;
|
|
|
+ index: number;
|
|
|
}) {
|
|
|
return (
|
|
|
- <div
|
|
|
- className={`${styles["chat-item"]} ${
|
|
|
- props.selected && styles["chat-item-selected"]
|
|
|
- }`}
|
|
|
- onClick={props.onClick}
|
|
|
- >
|
|
|
- <div className={styles["chat-item-title"]}>{props.title}</div>
|
|
|
- <div className={styles["chat-item-info"]}>
|
|
|
- <div className={styles["chat-item-count"]}>
|
|
|
- {Locale.ChatItem.ChatItemCount(props.count)}
|
|
|
+ <Draggable draggableId={`${props.id}`} index={props.index}>
|
|
|
+ {(provided) => (
|
|
|
+ <div
|
|
|
+ className={`${styles["chat-item"]} ${
|
|
|
+ props.selected && styles["chat-item-selected"]
|
|
|
+ }`}
|
|
|
+ onClick={props.onClick}
|
|
|
+ ref={provided.innerRef}
|
|
|
+ {...provided.draggableProps}
|
|
|
+ {...provided.dragHandleProps}
|
|
|
+ >
|
|
|
+ <div className={styles["chat-item-title"]}>{props.title}</div>
|
|
|
+ <div className={styles["chat-item-info"]}>
|
|
|
+ <div className={styles["chat-item-count"]}>
|
|
|
+ {Locale.ChatItem.ChatItemCount(props.count)}
|
|
|
+ </div>
|
|
|
+ <div className={styles["chat-item-date"]}>{props.time}</div>
|
|
|
+ </div>
|
|
|
+ <div className={styles["chat-item-delete"]} onClick={props.onDelete}>
|
|
|
+ <DeleteIcon />
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div className={styles["chat-item-date"]}>{props.time}</div>
|
|
|
- </div>
|
|
|
- <div className={styles["chat-item-delete"]} onClick={props.onDelete}>
|
|
|
- <DeleteIcon />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ )}
|
|
|
+ </Draggable>
|
|
|
);
|
|
|
}
|
|
|
|
|
|
export function ChatList() {
|
|
|
- const [sessions, selectedIndex, selectSession, removeSession] = useChatStore(
|
|
|
- (state) => [
|
|
|
+ const [sessions, selectedIndex, selectSession, removeSession, moveSession] =
|
|
|
+ useChatStore((state) => [
|
|
|
state.sessions,
|
|
|
state.currentSessionIndex,
|
|
|
state.selectSession,
|
|
|
state.removeSession,
|
|
|
- ],
|
|
|
- );
|
|
|
+ state.moveSession,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ const onDragEnd: OnDragEndResponder = (result) => {
|
|
|
+ const { destination, source } = result;
|
|
|
+ if (!destination) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (
|
|
|
+ destination.droppableId === source.droppableId &&
|
|
|
+ destination.index === source.index
|
|
|
+ ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ moveSession(source.index, destination.index);
|
|
|
+ };
|
|
|
|
|
|
return (
|
|
|
- <div className={styles["chat-list"]}>
|
|
|
- {sessions.map((item, i) => (
|
|
|
- <ChatItem
|
|
|
- title={item.topic}
|
|
|
- time={item.lastUpdate}
|
|
|
- count={item.messages.length}
|
|
|
- key={i}
|
|
|
- selected={i === selectedIndex}
|
|
|
- onClick={() => selectSession(i)}
|
|
|
- onDelete={() =>
|
|
|
- (!isMobileScreen() || confirm(Locale.Home.DeleteChat)) &&
|
|
|
- removeSession(i)
|
|
|
- }
|
|
|
- />
|
|
|
- ))}
|
|
|
- </div>
|
|
|
+ <DragDropContext onDragEnd={onDragEnd}>
|
|
|
+ <Droppable droppableId="chat-list">
|
|
|
+ {(provided) => (
|
|
|
+ <div
|
|
|
+ className={styles["chat-list"]}
|
|
|
+ ref={provided.innerRef}
|
|
|
+ {...provided.droppableProps}
|
|
|
+ >
|
|
|
+ {sessions.map((item, i) => (
|
|
|
+ <ChatItem
|
|
|
+ title={item.topic}
|
|
|
+ time={item.lastUpdate}
|
|
|
+ count={item.messages.length}
|
|
|
+ key={item.id}
|
|
|
+ id={item.id}
|
|
|
+ index={i}
|
|
|
+ selected={i === selectedIndex}
|
|
|
+ onClick={() => selectSession(i)}
|
|
|
+ onDelete={() =>
|
|
|
+ (!isMobileScreen() || confirm(Locale.Home.DeleteChat)) &&
|
|
|
+ removeSession(i)
|
|
|
+ }
|
|
|
+ />
|
|
|
+ ))}
|
|
|
+ {provided.placeholder}
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </Droppable>
|
|
|
+ </DragDropContext>
|
|
|
);
|
|
|
}
|