Skip to content

Commit 14e32d1

Browse files
committed
improved UI for for auto selecting newly uploaded image, message input auto focused after sending, and stricter image upload file type guardrails
1 parent 6c6ea2c commit 14e32d1

File tree

2 files changed

+45
-11
lines changed

2 files changed

+45
-11
lines changed

src/app/page.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ export default function Home() {
169169
// Add to images list immediately for UI responsiveness
170170
setImages((prev) => [...prev, uploadedImage]);
171171

172+
// Auto-select the uploaded image
173+
setSelectedImages((prev) => new Set([imageId]));
174+
172175
// Scroll to show the new image
173176
setTimeout(scrollToRight, 100);
174177

src/ui/chat-interface.tsx

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,22 @@ export default function ChatInterface({
2020
}: ChatInterfaceProps) {
2121
const [inputMessage, setInputMessage] = useState("");
2222
const [isClient, setIsClient] = useState(false);
23+
const [shouldFocus, setShouldFocus] = useState(false);
2324
const messagesEndRef = useRef<HTMLDivElement>(null);
25+
const inputRef = useRef<HTMLInputElement>(null);
2426

2527
useEffect(() => {
2628
setIsClient(true);
2729
}, []);
2830

31+
// Focus input when shouldFocus is true
32+
useEffect(() => {
33+
if (shouldFocus && inputRef.current && !isLoading) {
34+
inputRef.current.focus();
35+
setShouldFocus(false);
36+
}
37+
}, [shouldFocus, isLoading]);
38+
2939
const scrollToBottom = () => {
3040
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
3141
};
@@ -39,22 +49,42 @@ export default function ChatInterface({
3949
if (inputMessage.trim() && !isLoading) {
4050
onSendMessage(inputMessage.trim());
4151
setInputMessage("");
52+
// Set flag to focus input after component updates
53+
setShouldFocus(true);
4254
}
4355
};
4456

57+
const validateImageFile = (file: File): boolean => {
58+
// Check file type
59+
const allowedTypes = [
60+
"image/jpeg",
61+
"image/jpg",
62+
"image/png",
63+
"image/gif",
64+
"image/webp",
65+
];
66+
if (!allowedTypes.includes(file.type)) {
67+
alert("Please select a valid image file (JPEG, PNG, GIF, or WebP).");
68+
return false;
69+
}
70+
71+
// Check file size (10MB = 10 * 1024 * 1024 bytes)
72+
const maxSize = 10 * 1024 * 1024; // 10MB in bytes
73+
if (file.size > maxSize) {
74+
alert("Image size cannot exceed 10MB. Please choose a smaller image.");
75+
return false;
76+
}
77+
78+
return true;
79+
};
80+
4581
const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
4682
const file = e.target.files?.[0];
4783
if (file) {
48-
// Check file size (10MB = 10 * 1024 * 1024 bytes)
49-
const maxSize = 10 * 1024 * 1024; // 10MB in bytes
50-
if (file.size > maxSize) {
51-
alert("Image size cannot exceed 10MB. Please choose a smaller image.");
52-
e.target.value = "";
53-
return;
54-
}
55-
56-
if (onImageUpload) {
57-
onImageUpload(file);
84+
if (validateImageFile(file)) {
85+
if (onImageUpload) {
86+
onImageUpload(file);
87+
}
5888
}
5989
}
6090
// Reset the input value so the same file can be selected again
@@ -177,7 +207,7 @@ export default function ChatInterface({
177207
<label className="flex items-center justify-center w-12 h-12 bg-white/10 hover:bg-white/20 border border-white/20 rounded-xl cursor-pointer transition-all duration-200 hover:scale-105">
178208
<input
179209
type="file"
180-
accept="image/*"
210+
accept="image/jpeg,image/jpg,image/png,image/gif,image/webp"
181211
onChange={handleImageUpload}
182212
className="hidden"
183213
disabled={isLoading}
@@ -199,6 +229,7 @@ export default function ChatInterface({
199229
</label>
200230

201231
<input
232+
ref={inputRef}
202233
type="text"
203234
value={inputMessage}
204235
onChange={(e) => setInputMessage(e.target.value)}

0 commit comments

Comments
 (0)