ConversationSidebar.tsx 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  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. }
  24. export function ConversationSidebar({
  25. conversations,
  26. selectedConversationId,
  27. searchQuery,
  28. onSearchChange,
  29. onSelectConversation,
  30. filter,
  31. onFilterChange,
  32. status = "open",
  33. onStatusChange,
  34. mode = "visitor",
  35. onNewClick,
  36. }: ConversationSidebarProps) {
  37. const { t } = useI18n();
  38. return (
  39. <div className="w-80 min-w-0 flex-1 flex flex-col bg-white border-r border-gray-200 min-h-0 overflow-hidden">
  40. {mode === "internal" ? (
  41. <div className="h-14 flex items-center justify-between px-3 border-b border-border bg-background flex-shrink-0">
  42. <span className="text-sm font-medium text-foreground truncate">{t("agent.internalChat.title")}</span>
  43. {onNewClick && (
  44. <Button size="sm" variant="outline" onClick={onNewClick} className="flex-shrink-0 gap-1">
  45. <Plus className="w-4 h-4" />
  46. {t("agent.internalChat.new")}
  47. </Button>
  48. )}
  49. </div>
  50. ) : (
  51. <ConversationHeader
  52. filter={filter}
  53. onFilterChange={onFilterChange}
  54. listStatus={status}
  55. onListStatusChange={onStatusChange}
  56. />
  57. )}
  58. <div className="flex-shrink-0 px-2 min-w-0">
  59. <ConversationSearch value={searchQuery} onChange={onSearchChange} />
  60. </div>
  61. <ConversationList
  62. conversations={conversations}
  63. selectedConversationId={selectedConversationId}
  64. onSelect={onSelectConversation}
  65. searchQuery={searchQuery}
  66. />
  67. </div>
  68. );
  69. }