SarahXia0405 commited on
Commit
28f05af
·
verified ·
1 Parent(s): c829a69

Update web/src/components/ChatArea.tsx

Browse files
Files changed (1) hide show
  1. web/src/components/ChatArea.tsx +24 -14
web/src/components/ChatArea.tsx CHANGED
@@ -1,5 +1,5 @@
1
  // web/src/components/ChatArea.tsx
2
- import React, { useState, useRef, useEffect } from 'react';
3
  import { Button } from './ui/button';
4
  import { Textarea } from './ui/textarea';
5
  import { Send, ArrowDown, Trash2, Share2 } from 'lucide-react';
@@ -13,14 +13,18 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
13
  interface ChatAreaProps {
14
  messages: MessageType[];
15
  onSendMessage: (content: string) => void;
 
16
  uploadedFiles: UploadedFile[];
17
  onFileUpload: (files: File[]) => void;
18
  onRemoveFile: (index: number) => void;
19
  onFileTypeChange: (index: number, type: FileType) => void;
20
 
21
- // ✅ 新增:feedback 需要 userId
22
  userId?: string;
23
 
 
 
 
24
  memoryProgress: number;
25
  isLoggedIn: boolean;
26
  learningMode: LearningMode;
@@ -37,6 +41,7 @@ export function ChatArea({
37
  onRemoveFile,
38
  onFileTypeChange,
39
  userId,
 
40
  memoryProgress,
41
  isLoggedIn,
42
  learningMode,
@@ -50,6 +55,13 @@ export function ChatArea({
50
  const messagesEndRef = useRef<HTMLDivElement>(null);
51
  const scrollContainerRef = useRef<HTMLDivElement>(null);
52
 
 
 
 
 
 
 
 
53
  const scrollToBottom = () => {
54
  messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
55
  };
@@ -60,10 +72,9 @@ export function ChatArea({
60
 
61
  useEffect(() => {
62
  const handleScroll = () => {
63
- if (scrollContainerRef.current) {
64
- const { scrollTop, scrollHeight, clientHeight } = scrollContainerRef.current;
65
- setShowScrollButton(scrollHeight - scrollTop - clientHeight > 100);
66
- }
67
  };
68
 
69
  const container = scrollContainerRef.current;
@@ -152,7 +163,7 @@ export function ChatArea({
152
 
153
  <div ref={scrollContainerRef} className="h-full max-h-[600px] overflow-y-auto px-4 py-6 pb-36">
154
  <div className="max-w-4xl mx-auto space-y-6">
155
- {messages.map((message) => (
156
  <Message
157
  key={m.id}
158
  message={m}
@@ -160,10 +171,9 @@ export function ChatArea({
160
  userId={userId}
161
  isLoggedIn={isLoggedIn}
162
  learningMode={learningMode}
163
- docType={currentDocTypeForChat}
164
  lastUserText={lastUserMessageContent}
165
  />
166
-
167
  ))}
168
 
169
  {isTyping && (
@@ -218,13 +228,13 @@ export function ChatArea({
218
  </Button>
219
  </DropdownMenuTrigger>
220
  <DropdownMenuContent align="start" className="w-56">
221
- {(['concept', 'socratic', 'exam', 'assignment', 'summary'] as LearningMode[]).map((m) => (
222
  <DropdownMenuItem
223
- key={m}
224
- onClick={() => onLearningModeChange(m)}
225
- className={learningMode === m ? 'bg-accent' : ''}
226
  >
227
- <span className="font-medium">{modeLabels[m]}</span>
228
  </DropdownMenuItem>
229
  ))}
230
  </DropdownMenuContent>
 
1
  // web/src/components/ChatArea.tsx
2
+ import React, { useState, useRef, useEffect, useMemo } from 'react';
3
  import { Button } from './ui/button';
4
  import { Textarea } from './ui/textarea';
5
  import { Send, ArrowDown, Trash2, Share2 } from 'lucide-react';
 
13
  interface ChatAreaProps {
14
  messages: MessageType[];
15
  onSendMessage: (content: string) => void;
16
+
17
  uploadedFiles: UploadedFile[];
18
  onFileUpload: (files: File[]) => void;
19
  onRemoveFile: (index: number) => void;
20
  onFileTypeChange: (index: number, type: FileType) => void;
21
 
22
+ // ✅ feedback 需要 userId
23
  userId?: string;
24
 
25
+ // ✅ 由 App.tsx 传入 currentDocTypeForChat
26
+ docType?: string;
27
+
28
  memoryProgress: number;
29
  isLoggedIn: boolean;
30
  learningMode: LearningMode;
 
41
  onRemoveFile,
42
  onFileTypeChange,
43
  userId,
44
+ docType = 'Other',
45
  memoryProgress,
46
  isLoggedIn,
47
  learningMode,
 
55
  const messagesEndRef = useRef<HTMLDivElement>(null);
56
  const scrollContainerRef = useRef<HTMLDivElement>(null);
57
 
58
+ const lastUserMessageContent = useMemo(() => {
59
+ for (let i = messages.length - 1; i >= 0; i--) {
60
+ if (messages[i].role === 'user' && messages[i].content?.trim()) return messages[i].content;
61
+ }
62
+ return '';
63
+ }, [messages]);
64
+
65
  const scrollToBottom = () => {
66
  messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
67
  };
 
72
 
73
  useEffect(() => {
74
  const handleScroll = () => {
75
+ if (!scrollContainerRef.current) return;
76
+ const { scrollTop, scrollHeight, clientHeight } = scrollContainerRef.current;
77
+ setShowScrollButton(scrollHeight - scrollTop - clientHeight > 100);
 
78
  };
79
 
80
  const container = scrollContainerRef.current;
 
163
 
164
  <div ref={scrollContainerRef} className="h-full max-h-[600px] overflow-y-auto px-4 py-6 pb-36">
165
  <div className="max-w-4xl mx-auto space-y-6">
166
+ {messages.map((m) => (
167
  <Message
168
  key={m.id}
169
  message={m}
 
171
  userId={userId}
172
  isLoggedIn={isLoggedIn}
173
  learningMode={learningMode}
174
+ docType={docType}
175
  lastUserText={lastUserMessageContent}
176
  />
 
177
  ))}
178
 
179
  {isTyping && (
 
228
  </Button>
229
  </DropdownMenuTrigger>
230
  <DropdownMenuContent align="start" className="w-56">
231
+ {(['concept', 'socratic', 'exam', 'assignment', 'summary'] as LearningMode[]).map((mode) => (
232
  <DropdownMenuItem
233
+ key={mode}
234
+ onClick={() => onLearningModeChange(mode)}
235
+ className={learningMode === mode ? 'bg-accent' : ''}
236
  >
237
+ <span className="font-medium">{modeLabels[mode]}</span>
238
  </DropdownMenuItem>
239
  ))}
240
  </DropdownMenuContent>