Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ yarn-error.log*
next-env.d.ts

#cloudflare
.open-next
.open-next
package-lock.json
49 changes: 36 additions & 13 deletions frontend/components/ChatInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChevronDown, Check, ArrowUpIcon } from 'lucide-react';
import { memo, useCallback, useMemo } from 'react';
import { ChevronDown, Check, ArrowUpIcon, Plus, CircleX } from 'lucide-react';
import { memo, useCallback, useMemo, useRef, useState } from 'react';
import { Textarea } from '@/frontend/components/ui/textarea';
import { cn } from '@/lib/utils';
import { Button } from '@/frontend/components/ui/button';
Expand All @@ -18,11 +18,12 @@ import { useAPIKeyStore } from '@/frontend/stores/APIKeyStore';
import { useModelStore } from '@/frontend/stores/ModelStore';
import { AI_MODELS, AIModel, getModelConfig } from '@/lib/models';
import KeyPrompt from '@/frontend/components/KeyPrompt';
import { UIMessage } from 'ai';
import { UIMessage } from 'ai';
import { v4 as uuidv4 } from 'uuid';
import { StopIcon } from './ui/icons';
import { toast } from 'sonner';
import { StopIcon } from './ui/icons';
import { useMessageSummary } from '../hooks/useMessageSummary';
import { useFileHandler } from '../hooks/useFileHandler';
import FilePreview from './filePreview';

interface ChatInputProps {
threadId: string;
Expand Down Expand Up @@ -65,6 +66,9 @@ function PureChatInput({
maxHeight: 200,
});

const { fileList, fileUrls, contentTypes, handlePaste, handleFileChange, clearFiles , handleDragOver , handleDrop} = useFileHandler();


const navigate = useNavigate();
const { id } = useParams();

Expand Down Expand Up @@ -99,10 +103,11 @@ function PureChatInput({

const userMessage = createUserMessage(messageId, currentInput.trim());
await createMessage(threadId, userMessage);

append(userMessage);
append(userMessage, { experimental_attachments: fileList })
setInput('');
clearFiles();
adjustHeight(true);
Comment on lines +106 to 109
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add file validation before appending message.

Consider validating file size and type before sending to prevent issues with large files or unsupported formats.

+// Add validation before append
+if (fileList) {
+  const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
+  const file = fileList[0];
+  if (file.size > MAX_FILE_SIZE) {
+    // Show error to user
+    return;
+  }
+}
 append(userMessage, { experimental_attachments: fileList })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
append(userMessage, { experimental_attachments: fileList })
setInput('');
clearFiles();
adjustHeight(true);
// Add validation before append
if (fileList) {
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
const file = fileList[0];
if (file.size > MAX_FILE_SIZE) {
// Show error to user
return;
}
}
append(userMessage, { experimental_attachments: fileList })
setInput('');
clearFiles();
adjustHeight(true);
🤖 Prompt for AI Agents
In frontend/components/ChatInput.tsx around lines 106 to 109, before calling
append(userMessage, { experimental_attachments: fileList }), add validation
logic to check each file's size and type in fileList. Filter out or reject files
that exceed size limits or are of unsupported formats, and only append messages
with valid files. This prevents issues caused by large or unsupported files
being sent.


}, [
input,
status,
Expand All @@ -113,7 +118,8 @@ function PureChatInput({
textareaRef,
threadId,
complete,
]);
]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add missing dependencies to useCallback.

The handleSubmit callback is missing fileList and clearFiles from its dependency array.

-]); 
+  navigate,
+  fileList,
+  clearFiles,
+]);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
]);
navigate,
fileList,
clearFiles,
]);
🤖 Prompt for AI Agents
In frontend/components/ChatInput.tsx at line 121, the useCallback hook for the
handleSubmit function is missing dependencies. Add both fileList and clearFiles
to the dependency array of the useCallback to ensure the callback updates
correctly when these values change.



if (!canChat) {
return <KeyPrompt />;
Expand All @@ -137,6 +143,14 @@ function PureChatInput({
<div className="relative">
<div className="flex flex-col">
<div className="bg-secondary overflow-y-auto max-h-[300px]">

<FilePreview
clearFiles={clearFiles}
contentTypes={contentTypes}
fileList={fileList}
fileUrls={fileUrls}
/>

<Textarea
id="chat-input"
value={input}
Expand All @@ -152,6 +166,9 @@ function PureChatInput({
ref={textareaRef}
onKeyDown={handleKeyDown}
onChange={handleInputChange}
onPaste={handlePaste}
onDrop={handleDrop}
onDragOver={handleDragOver}
aria-label="Chat message input"
aria-describedby="chat-input-description"
/>
Expand All @@ -163,12 +180,18 @@ function PureChatInput({
<div className="h-14 flex items-center px-2">
<div className="flex items-center justify-between w-full">
<ChatModelDropdown />
<div className="flex gap-2 items-center">
<input onChange={handleFileChange} className='hidden' type="file" name="" id="fileChange" />
<label htmlFor="fileChange">
<Plus />
</label>
Comment on lines +183 to +187
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve file input UI accessibility and styling.

The Plus icon button lacks proper styling and accessibility attributes.

-<label htmlFor="fileChange">
-  <Plus />
-</label>
+<label 
+  htmlFor="fileChange" 
+  className="cursor-pointer p-2 hover:bg-muted rounded-md transition-colors"
+  aria-label="Attach file"
+>
+  <Plus className="w-5 h-5" />
+</label>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="flex gap-2 items-center">
<input onChange={handleFileChange} className='hidden' type="file" name="" id="fileChange" />
<label htmlFor="fileChange">
<Plus />
</label>
<div className="flex gap-2 items-center">
<input onChange={handleFileChange} className='hidden' type="file" name="" id="fileChange" />
<label
htmlFor="fileChange"
className="cursor-pointer p-2 hover:bg-muted rounded-md transition-colors"
aria-label="Attach file"
>
<Plus className="w-5 h-5" />
</label>
🤖 Prompt for AI Agents
In frontend/components/ChatInput.tsx around lines 183 to 187, the file input UI
lacks proper accessibility and styling. Add appropriate ARIA attributes to the
label or input for better accessibility, such as aria-label or role. Also,
enhance the styling of the Plus icon button to make it visually clear and
interactive, for example by adding cursor pointer and focus styles to the label
element.


{status === 'submitted' || status === 'streaming' ? (
<StopButton stop={stop} />
) : (
<SendButton onSubmit={handleSubmit} disabled={isDisabled} />
)}
{status === 'submitted' || status === 'streaming' ? (
<StopButton stop={stop} />
) : (
<SendButton onSubmit={handleSubmit} disabled={isDisabled} />
)}
</div>
</div>
</div>
</div>
Expand Down
25 changes: 23 additions & 2 deletions frontend/components/Message.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { memo, useState } from 'react';
import MarkdownRenderer from '@/frontend/components/MemoizedMarkdown';
import { cn } from '@/lib/utils';
import { UIMessage } from 'ai';
import { Attachment, UIMessage } from 'ai';
import equal from 'fast-deep-equal';
import MessageControls from './MessageControls';
import { UseChatHelpers } from '@ai-sdk/react';
import MessageEditor from './MessageEditor';
import MessageReasoning from './MessageReasoning';
import { TextFilePreview } from './filePreview';

function PureMessage({
threadId,
Expand Down Expand Up @@ -67,7 +68,27 @@ function PureMessage({
stop={stop}
/>
)}
{mode === 'view' && <p>{part.text}</p>}
{mode === 'view' && (
<div className='flex flex-col gap-2'>
{message.experimental_attachments
?.map((attachment, index) => (
<section key={attachment.name}>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use a unique key for attachment rendering.

Using attachment.name as the React key could cause rendering issues if multiple files have the same name.

-<section key={attachment.name}>
+<section key={`${message.id}-attachment-${index}`}>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<section key={attachment.name}>
<section key={`${message.id}-attachment-${index}`}>
🤖 Prompt for AI Agents
In frontend/components/Message.tsx at line 75, the React key for the attachment
section is set to attachment.name, which may not be unique if multiple
attachments share the same name. Update the key to use a unique identifier for
each attachment, such as a combination of attachment name and a unique property
like an ID or index, to ensure stable and correct rendering by React.

{attachment.contentType?.startsWith("image/") ?
<img className='w-12 h-12 rounded-md'
key={`${message.id}-${index}`}
src={attachment.url}
alt={attachment.name}
/>
: attachment.contentType?.startsWith("text/") ?
<TextFilePreview fileList={undefined} /> :
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix TextFilePreview receiving undefined fileList.

The TextFilePreview component is being passed undefined as the fileList prop, which will always render empty content. You need to pass the actual file data from the attachment.

The attachment object likely contains the file data or URL that should be used here. Consider either:

  1. Modifying TextFilePreview to accept a URL and fetch the content
  2. Storing the actual File object in the attachment data structure
🤖 Prompt for AI Agents
In frontend/components/Message.tsx at line 83, the TextFilePreview component is
incorrectly receiving undefined for its fileList prop, causing it to render
empty content. To fix this, pass the actual file data from the attachment object
to the fileList prop. This may involve accessing the file or URL stored in the
attachment and providing it directly to TextFilePreview, or updating the
attachment structure to include the necessary file information.

<iframe src={attachment.url} className="w-20 h-20 overflow-hidden" scrolling="no"></iframe>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Security concern: Validate iframe source URLs.

Rendering arbitrary URLs in an iframe without validation could pose security risks. Consider implementing a whitelist of allowed domains or file types.

Add proper sandboxing attributes to the iframe and validate the URL source:

-<iframe src={attachment.url} className="w-20 h-20 overflow-hidden" scrolling="no"></iframe>
+<iframe 
+  src={attachment.url} 
+  className="w-20 h-20 overflow-hidden" 
+  scrolling="no"
+  sandbox="allow-scripts allow-same-origin"
+  title={attachment.name}
+></iframe>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<iframe src={attachment.url} className="w-20 h-20 overflow-hidden" scrolling="no"></iframe>
<iframe
src={attachment.url}
className="w-20 h-20 overflow-hidden"
scrolling="no"
sandbox="allow-scripts allow-same-origin"
title={attachment.name}
></iframe>
🤖 Prompt for AI Agents
In frontend/components/Message.tsx at line 84, the iframe src attribute is set
directly from attachment.url without validation, posing a security risk. Fix
this by implementing a whitelist check to ensure the URL domain or file type is
allowed before rendering. Additionally, add sandbox attributes to the iframe
element to restrict its capabilities and enhance security.


}
</section>
))}
<p>{part.text}</p>
</div>
)}

{mode === 'view' && (
<MessageControls
Expand Down
72 changes: 72 additions & 0 deletions frontend/components/filePreview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { CircleX } from "lucide-react";
import { memo, useEffect, useState } from "react";


interface FileInputProps {
fileUrls: string[],
fileList: FileList | undefined,
contentTypes: string[],
clearFiles: () => void
}

export function TextFilePreview({ fileList }: { fileList: FileList | undefined }) {
const [content, setContent] = useState<string>("");

useEffect(() => {
if (!fileList || fileList.length === 0) {
setContent("");
return;
}
const file = fileList[0];
const reader = new FileReader();
reader.onload = (e) => {
const text = e.target?.result;
setContent(typeof text === "string" ? text.slice(0, 100) : "");
};
reader.readAsText(file);
Comment on lines +22 to +26
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling for FileReader operations.

The FileReader operations could fail and should include error handling.

 reader.onload = (e) => {
   const text = e.target?.result;
   setContent(typeof text === "string" ? text.slice(0, 100) : "");
 };
+reader.onerror = () => {
+  setContent("Error reading file");
+};
 reader.readAsText(file);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
reader.onload = (e) => {
const text = e.target?.result;
setContent(typeof text === "string" ? text.slice(0, 100) : "");
};
reader.readAsText(file);
reader.onload = (e) => {
const text = e.target?.result;
setContent(typeof text === "string" ? text.slice(0, 100) : "");
};
reader.onerror = () => {
setContent("Error reading file");
};
reader.readAsText(file);
🤖 Prompt for AI Agents
In frontend/components/filePreview.tsx around lines 22 to 26, the FileReader
usage lacks error handling which can cause silent failures. Add an onerror event
handler to the FileReader instance to catch and handle errors during the read
operation. In the onerror handler, implement appropriate error handling logic
such as logging the error or updating the UI to inform the user.

}, [fileList]);

return (
<div className="text-[5px] leading-1 w-15 h-14 overflow-hidden text-zinc-500 border p-2 rounded-lg bg-white dark:bg-zinc-800 dark:border-zinc-700 dark:text-zinc-400">
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Text preview font size is too small.

The font size of 5px is likely unreadable. Consider using a larger, more accessible size.

-<div className="text-[5px] leading-1 w-15 h-14 overflow-hidden text-zinc-500 border p-2 rounded-lg bg-white dark:bg-zinc-800 dark:border-zinc-700 dark:text-zinc-400">
+<div className="text-[10px] leading-tight w-20 h-20 overflow-hidden text-zinc-500 border p-2 rounded-lg bg-white dark:bg-zinc-800 dark:border-zinc-700 dark:text-zinc-400">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="text-[5px] leading-1 w-15 h-14 overflow-hidden text-zinc-500 border p-2 rounded-lg bg-white dark:bg-zinc-800 dark:border-zinc-700 dark:text-zinc-400">
<div className="text-[10px] leading-tight w-20 h-20 overflow-hidden text-zinc-500 border p-2 rounded-lg bg-white dark:bg-zinc-800 dark:border-zinc-700 dark:text-zinc-400">
🤖 Prompt for AI Agents
In frontend/components/filePreview.tsx at line 30, the font size is set to 5px,
which is too small and unreadable. Increase the font size to a more accessible
value, such as 12px or 14px, by updating the className to use a larger text size
utility or a custom size that improves readability.

<p className="">
{content}
{content.length >= 100 && "..."}
</p>
</div>
);
}


function PreviewFile({ fileUrls, clearFiles, fileList, contentTypes }: FileInputProps) {
return (
<>
{fileUrls?.length > 0 &&
<div className="relative overflow-hidden rounded-md mb-2">
<CircleX
onClick={() => clearFiles()}
className={`absolute top-2 ${contentTypes[0] === "image/jpeg" ? 'w-5 h-5 left-14' : 'w-4 h-4 left-10'} hover:stroke-red-400`}
/>
{contentTypes[0] === "image/jpeg" ?
<img src={fileUrls[0]} className='w-20 h-20 rounded-md' alt="attached_image" />
Comment on lines +47 to +50
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Support all image types, not just JPEG.

The code only checks for "image/jpeg" but should support all common image formats.

-${contentTypes[0] === "image/jpeg" ? 'w-5 h-5 left-14' : 'w-4 h-4 left-10'}
+${contentTypes[0]?.startsWith("image/") ? 'w-5 h-5 left-14' : 'w-4 h-4 left-10'}
-{contentTypes[0] === "image/jpeg" ?
+{contentTypes[0]?.startsWith("image/") ?
🤖 Prompt for AI Agents
In frontend/components/filePreview.tsx around lines 47 to 50, the code only
checks if the first content type is "image/jpeg" to determine image handling,
which limits support to JPEG images. Update the condition to check for all
common image MIME types such as "image/png", "image/gif", "image/webp", and
others by using a more inclusive check (e.g., checking if the content type
starts with "image/"). Modify both the className conditional and the rendering
logic to support any image type accordingly.

:
contentTypes[0] === "text/plain" ?
<TextFilePreview fileList={fileList} />
:
<iframe src={fileUrls[0]} className="w-20 h-20 overflow-hidden" scrolling="no"></iframe>
}

</div>
}
</>
);
}



const FilePreview = memo(PreviewFile, (prevProps, nextProps) => {
if (prevProps.fileUrls !== nextProps.fileUrls) return false;
return true;
});
Comment on lines +66 to +69
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix memoization to check all relevant props.

The memo comparison only checks fileUrls but should check all props that affect rendering.

-const FilePreview = memo(PreviewFile, (prevProps, nextProps) => {
-  if (prevProps.fileUrls !== nextProps.fileUrls) return false;
-  return true;
-});
+const FilePreview = memo(PreviewFile, (prevProps, nextProps) => {
+  return prevProps.fileUrls === nextProps.fileUrls &&
+    prevProps.fileList === nextProps.fileList &&
+    prevProps.contentTypes === nextProps.contentTypes;
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const FilePreview = memo(PreviewFile, (prevProps, nextProps) => {
if (prevProps.fileUrls !== nextProps.fileUrls) return false;
return true;
});
const FilePreview = memo(PreviewFile, (prevProps, nextProps) => {
return prevProps.fileUrls === nextProps.fileUrls &&
prevProps.fileList === nextProps.fileList &&
prevProps.contentTypes === nextProps.contentTypes;
});
🤖 Prompt for AI Agents
In frontend/components/filePreview.tsx around lines 66 to 69, the memoization
comparison function only checks the fileUrls prop, which is insufficient. Update
the comparison function to check all props that influence rendering by comparing
each relevant prop between prevProps and nextProps, returning false if any
differ, and true only if all are equal.



export default FilePreview;
84 changes: 84 additions & 0 deletions frontend/hooks/useFileHandler.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { useState, useCallback } from 'react';

export function useFileHandler() {
const [fileUrls, setFileUrls] = useState<string[]>([]);
const [fileList, setFileList] = useState<FileList | undefined>(undefined);
const [contentTypes, setContentTypes] = useState<string[]>([]);

const processFiles = useCallback((files: FileList) => {
const urls = Array.from(files).map((file) => URL.createObjectURL(file));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Prevent memory leaks by revoking object URLs.

Object URLs created with URL.createObjectURL must be revoked to prevent memory leaks.

Store the URLs and revoke them when clearing or before creating new ones:

 const processFiles = useCallback((files: FileList) => {
+  // Revoke previous URLs
+  fileUrls.forEach(url => URL.revokeObjectURL(url));
+  
   const urls = Array.from(files).map((file) => URL.createObjectURL(file));

Also update clearFiles:

 const clearFiles = useCallback(() =>{
+  fileUrls.forEach(url => URL.revokeObjectURL(url));
   setFileList(undefined);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In frontend/hooks/useFileHandler.tsx at line 9, the code creates object URLs
with URL.createObjectURL but does not revoke them, causing potential memory
leaks. Modify the code to store the generated URLs in a variable or state, and
ensure that before creating new URLs or when clearing files, you call
URL.revokeObjectURL on each stored URL to release the memory. Also update the
clearFiles function to revoke all stored URLs before clearing them.

const types = Array.from(files).map((file) => file.type);

setFileUrls(urls);
setFileList(files);
setContentTypes(types);
console.log("type" , types , fileUrls , fileList);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove console.log statement.

Debug logging should not be included in production code.

-console.log("type" , types , fileUrls , fileList);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
console.log("type" , types , fileUrls , fileList);
// (Remove the debug log; no replacement needed)
🤖 Prompt for AI Agents
In frontend/hooks/useFileHandler.tsx at line 15, remove the console.log
statement that outputs "type", types, fileUrls, and fileList to eliminate debug
logging from production code.


}, []);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix useCallback dependency array.

The empty dependency array is incorrect since the callback uses fileUrls and fileList in the console.log.

-}, []);
+}, [fileUrls]);

Note: After removing the console.log, the empty array would be correct.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In frontend/hooks/useFileHandler.tsx at line 17, the useCallback hook has an
empty dependency array but uses fileUrls and fileList inside its callback, which
is incorrect. To fix this, either add fileUrls and fileList to the dependency
array to ensure the callback updates when these values change, or remove the
console.log statement that references them, allowing the empty array to be
correct.

Comment on lines +8 to +17
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add file validation for size and quantity.

The file processing should validate file size and limit the number of files to prevent performance issues.

 const processFiles = useCallback((files: FileList) => {
+  const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
+  const MAX_FILES = 5;
+  
+  if (files.length > MAX_FILES) {
+    console.error(`Maximum ${MAX_FILES} files allowed`);
+    return;
+  }
+  
+  for (const file of Array.from(files)) {
+    if (file.size > MAX_FILE_SIZE) {
+      console.error(`File ${file.name} exceeds maximum size of 10MB`);
+      return;
+    }
+  }
+  
   const urls = Array.from(files).map((file) => URL.createObjectURL(file));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const processFiles = useCallback((files: FileList) => {
const urls = Array.from(files).map((file) => URL.createObjectURL(file));
const types = Array.from(files).map((file) => file.type);
setFileUrls(urls);
setFileList(files);
setContentTypes(types);
console.log("type" , types , fileUrls , fileList);
}, []);
const processFiles = useCallback((files: FileList) => {
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
const MAX_FILES = 5;
if (files.length > MAX_FILES) {
console.error(`Maximum ${MAX_FILES} files allowed`);
return;
}
for (const file of Array.from(files)) {
if (file.size > MAX_FILE_SIZE) {
console.error(`File ${file.name} exceeds maximum size of 10MB`);
return;
}
}
const urls = Array.from(files).map((file) => URL.createObjectURL(file));
const types = Array.from(files).map((file) => file.type);
setFileUrls(urls);
setFileList(files);
setContentTypes(types);
console.log("type", types, fileUrls, fileList);
}, []);
🤖 Prompt for AI Agents
In frontend/hooks/useFileHandler.tsx around lines 8 to 17, add validation to the
processFiles function to check each file's size against a defined maximum limit
and ensure the total number of files does not exceed a set quantity limit. If
any file is too large or the number of files is too many, prevent further
processing and optionally provide feedback. Implement these checks before
creating object URLs and updating state to avoid performance issues.


const handlePaste = useCallback((event: React.ClipboardEvent) => {
event.preventDefault();

const items = event.clipboardData?.items;
if (!items) return;

for (let i = 0; i < items.length; i++) {
if (
items[i].type.startsWith('image') ||
items[i].type === 'application/pdf' ||
items[i].type === 'text/plain'
) {
const file = items[i].getAsFile();
if (file) {
const dt = new DataTransfer();
dt.items.add(file);
processFiles(dt.files);
break;
}
}
}

// Optional: handle pasted text if needed
const text = event.clipboardData.getData('text/plain');
if (text) {
document.execCommand('insertText', false, text);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Replace deprecated document.execCommand.

document.execCommand is deprecated and should not be used. Consider using the modern Clipboard API or letting the browser handle text paste naturally.

-document.execCommand('insertText', false, text);
+// Let the default paste behavior handle text insertion
+// or use: navigator.clipboard.writeText(text);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
document.execCommand('insertText', false, text);
// Let the default paste behavior handle text insertion
// or use: navigator.clipboard.writeText(text);
🤖 Prompt for AI Agents
In frontend/hooks/useFileHandler.tsx at line 44, replace the deprecated
document.execCommand('insertText', false, text) with a modern approach. Use the
Clipboard API's navigator.clipboard.writeText(text) if you want to
programmatically copy text, or alternatively, allow the browser to handle text
insertion naturally without forcing it via execCommand. Adjust the code to avoid
using execCommand and adopt the Clipboard API or native input handling.

}
}, [processFiles]);

const handleFileChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const files = event.target.files;
if (files && files.length > 0) {
processFiles(files);
}
}, [processFiles]);


const handleDrop = useCallback((event: React.DragEvent) => {
event.preventDefault();
const files = event.dataTransfer.files;
if (files && files.length > 0) {
processFiles(files);
}
}, [processFiles]);

const handleDragOver = useCallback((event: React.DragEvent) => {
event.preventDefault();
}, []);

const clearFiles = useCallback(() =>{
setFileList(undefined);
setFileUrls([]);
setContentTypes([])
} , [])

return {
fileUrls,
fileList,
contentTypes,
handlePaste,
handleFileChange,
handleDragOver,
handleDrop,
clearFiles
};
}