chat-list.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import DeleteIcon from "../icons/delete.svg";
  2. import styles from "./home.module.scss";
  3. import {
  4. DragDropContext,
  5. Droppable,
  6. Draggable,
  7. OnDragEndResponder,
  8. } from "@hello-pangea/dnd";
  9. import { useChatStore } from "../store";
  10. import Locale from "../locales";
  11. import { Link, useNavigate } from "react-router-dom";
  12. import { Path } from "../constant";
  13. export function ChatItem(props: {
  14. onClick?: () => void;
  15. onDelete?: () => void;
  16. title: string;
  17. count: number;
  18. time: string;
  19. selected: boolean;
  20. id: number;
  21. index: number;
  22. narrow?: boolean;
  23. }) {
  24. return (
  25. <Draggable draggableId={`${props.id}`} index={props.index}>
  26. {(provided) => (
  27. <div
  28. className={`${styles["chat-item"]} ${
  29. props.selected && styles["chat-item-selected"]
  30. }`}
  31. onClick={props.onClick}
  32. ref={provided.innerRef}
  33. {...provided.draggableProps}
  34. {...provided.dragHandleProps}
  35. >
  36. {props.narrow ? (
  37. <div className={styles["chat-item-narrow"]}>{props.count}</div>
  38. ) : (
  39. <>
  40. <div className={styles["chat-item-title"]}>{props.title}</div>
  41. <div className={styles["chat-item-info"]}>
  42. <div className={styles["chat-item-count"]}>
  43. {Locale.ChatItem.ChatItemCount(props.count)}
  44. </div>
  45. <div className={styles["chat-item-date"]}>{props.time}</div>
  46. </div>
  47. </>
  48. )}
  49. <div className={styles["chat-item-delete"]} onClick={props.onDelete}>
  50. <DeleteIcon />
  51. </div>
  52. </div>
  53. )}
  54. </Draggable>
  55. );
  56. }
  57. export function ChatList(props: { narrow?: boolean }) {
  58. const [sessions, selectedIndex, selectSession, removeSession, moveSession] =
  59. useChatStore((state) => [
  60. state.sessions,
  61. state.currentSessionIndex,
  62. state.selectSession,
  63. state.removeSession,
  64. state.moveSession,
  65. ]);
  66. const chatStore = useChatStore();
  67. const navigate = useNavigate();
  68. const onDragEnd: OnDragEndResponder = (result) => {
  69. const { destination, source } = result;
  70. if (!destination) {
  71. return;
  72. }
  73. if (
  74. destination.droppableId === source.droppableId &&
  75. destination.index === source.index
  76. ) {
  77. return;
  78. }
  79. moveSession(source.index, destination.index);
  80. };
  81. return (
  82. <DragDropContext onDragEnd={onDragEnd}>
  83. <Droppable droppableId="chat-list">
  84. {(provided) => (
  85. <div
  86. className={styles["chat-list"]}
  87. ref={provided.innerRef}
  88. {...provided.droppableProps}
  89. >
  90. {sessions.map((item, i) => (
  91. <ChatItem
  92. title={item.topic}
  93. time={item.lastUpdate}
  94. count={item.messages.length}
  95. key={item.id}
  96. id={item.id}
  97. index={i}
  98. selected={i === selectedIndex}
  99. onClick={() => {
  100. navigate(Path.Chat);
  101. selectSession(i);
  102. }}
  103. onDelete={() => {
  104. if (!props.narrow || confirm(Locale.Home.DeleteChat)) {
  105. chatStore.deleteSession(i);
  106. }
  107. }}
  108. narrow={props.narrow}
  109. />
  110. ))}
  111. {provided.placeholder}
  112. </div>
  113. )}
  114. </Droppable>
  115. </DragDropContext>
  116. );
  117. }