ConversationSidebar.tsx 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. "use client";
  2. import { ConversationSummary } from "@/features/agent/types";
  3. import { ConversationHeader, type ConversationFilter } from "./ConversationHeader";
  4. import { ConversationSearch } from "./ConversationSearch";
  5. import { ConversationList } from "./ConversationList";
  6. import { Button } from "@/components/ui/button";
  7. import { Plus } from "lucide-react";
  8. import { useI18n } from "@/lib/i18n/provider";
  9. type ConversationStatus = "open" | "closed";
  10. interface ConversationSidebarProps {
  11. conversations: ConversationSummary[];
  12. selectedConversationId: number | null;
  13. searchQuery: string;
  14. onSearchChange: (value: string) => void;
  15. onSelectConversation: (id: number) => void;
  16. filter: ConversationFilter;
  17. onFilterChange: (filter: ConversationFilter) => void;
  18. status?: ConversationStatus;
  19. onStatusChange?: (status: ConversationStatus) => void;
  20. /** 内部对话(知识库测试)模式:显示「新建内部对话」按钮,隐藏筛选 */
  21. mode?: "visitor" | "internal";
  22. onNewClick?: () => void;
  23. hasMore?: boolean;
  24. loadingMore?: boolean;
  25. onLoadMore?: () => void;
  26. }
  27. export function ConversationSidebar({
  28. conversations,
  29. selectedConversationId,
  30. searchQuery,
  31. onSearchChange,
  32. onSelectConversation,
  33. filter,
  34. onFilterChange,
  35. status = "open",
  36. onStatusChange,
  37. mode = "visitor",
  38. onNewClick,
  39. hasMore,
  40. loadingMore,
  41. onLoadMore,
  42. }: ConversationSidebarProps) {
  43. const { t } = useI18n();
  44. return (
  45. <div className="w-80 min-w-0 flex-1 flex flex-col bg-white border-r border-gray-200 min-h-0 overflow-hidden">
  46. {mode === "internal" ? (
  47. <div className="h-14 flex items-center justify-between px-3 border-b border-border bg-background flex-shrink-0">
  48. <span className="text-sm font-medium text-foreground truncate">{t("agent.internalChat.title")}</span>
  49. {onNewClick && (
  50. <Button size="sm" variant="outline" onClick={onNewClick} className="flex-shrink-0 gap-1">
  51. <Plus className="w-4 h-4" />
  52. {t("agent.internalChat.new")}
  53. </Button>
  54. )}
  55. </div>
  56. ) : (
  57. <ConversationHeader
  58. filter={filter}
  59. onFilterChange={onFilterChange}
  60. listStatus={status}
  61. onListStatusChange={onStatusChange}
  62. />
  63. )}
  64. <div className="flex-shrink-0 px-2 min-w-0">
  65. <ConversationSearch value={searchQuery} onChange={onSearchChange} />
  66. </div>
  67. <ConversationList
  68. conversations={conversations}
  69. selectedConversationId={selectedConversationId}
  70. onSelect={onSelectConversation}
  71. searchQuery={searchQuery}
  72. hasMore={hasMore}
  73. loadingMore={loadingMore}
  74. onLoadMore={onLoadMore}
  75. />
  76. </div>
  77. );
  78. }