Socratic-Lens / src /components /AskQuestionModal.tsx
Jainish1808
Initial commit - Socratic Lens
4000a4c
'use client';
import { useState } from 'react';
import { X, Send, Loader2, MessageCircle } from 'lucide-react';
import clsx from 'clsx';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
interface AskQuestionModalProps {
isOpen: boolean;
onClose: () => void;
context: string; // The original analyzed content
}
interface Message {
role: 'user' | 'assistant';
content: string;
}
export default function AskQuestionModal({ isOpen, onClose, context }: AskQuestionModalProps) {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!input.trim() || loading) return;
const userMessage = input.trim();
setInput('');
setMessages(prev => [...prev, { role: 'user', content: userMessage }]);
setLoading(true);
try {
const formData = new FormData();
formData.append('text', `
Based on this content I just learned:
---
${context.substring(0, 2000)}
---
My question: ${userMessage}
Please answer my question in a helpful, educational way. Use simple language and examples if needed.
`);
const res = await fetch('/api/analyze', {
method: 'POST',
body: formData,
});
if (!res.ok) throw new Error('Failed to get response');
const data = await res.json();
const cleanResponse = data.result?.replace(/\[\[TOPICS?:.*?\]\]/gi, '').trim() || 'Sorry, I could not generate a response.';
setMessages(prev => [...prev, { role: 'assistant', content: cleanResponse }]);
} catch (error) {
setMessages(prev => [...prev, { role: 'assistant', content: 'Sorry, something went wrong. Please try again.' }]);
} finally {
setLoading(false);
}
};
if (!isOpen) return null;
return (
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm animate-fade-in-up">
<div className="w-full max-w-2xl bg-white dark:bg-neutral-900 rounded-2xl shadow-2xl border border-gray-200 dark:border-neutral-800 flex flex-col max-h-[80vh]">
{/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-neutral-800">
<div className="flex items-center gap-2">
<MessageCircle size={20} className="text-sky-500" />
<h2 className="text-lg font-semibold text-gray-900 dark:text-white">Ask a Question</h2>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-gray-100 dark:hover:bg-neutral-800 rounded-full transition-colors"
>
<X size={20} className="text-gray-500" />
</button>
</div>
{/* Messages */}
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.length === 0 && (
<div className="text-center py-12 text-gray-400">
<MessageCircle size={48} className="mx-auto mb-4 opacity-50" />
<p>Ask any question about the content you just analyzed.</p>
</div>
)}
{messages.map((msg, idx) => (
<div
key={idx}
className={clsx(
"flex",
msg.role === 'user' ? "justify-end" : "justify-start"
)}
>
<div
className={clsx(
"max-w-[80%] rounded-2xl px-4 py-3",
msg.role === 'user'
? "bg-sky-500 text-white rounded-br-md"
: "bg-gray-100 dark:bg-neutral-800 text-gray-800 dark:text-gray-200 rounded-bl-md"
)}
>
{msg.role === 'assistant' ? (
<div className="prose prose-sm dark:prose-invert max-w-none">
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{msg.content}
</ReactMarkdown>
</div>
) : (
<p>{msg.content}</p>
)}
</div>
</div>
))}
{loading && (
<div className="flex justify-start">
<div className="bg-gray-100 dark:bg-neutral-800 rounded-2xl rounded-bl-md px-4 py-3">
<Loader2 size={20} className="animate-spin text-gray-400" />
</div>
</div>
)}
</div>
{/* Input */}
<form onSubmit={handleSubmit} className="p-4 border-t border-gray-200 dark:border-neutral-800">
<div className="flex gap-3">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
placeholder="Type your question..."
className="flex-1 px-4 py-3 bg-gray-100 dark:bg-neutral-800 border border-gray-200 dark:border-neutral-700 rounded-xl focus:outline-none focus:ring-2 focus:ring-sky-500 focus:border-transparent text-gray-900 dark:text-white placeholder-gray-400"
disabled={loading}
/>
<button
type="submit"
disabled={loading || !input.trim()}
className={clsx(
"px-4 py-3 rounded-xl font-medium transition-all flex items-center gap-2",
loading || !input.trim()
? "bg-gray-200 dark:bg-neutral-700 text-gray-400 cursor-not-allowed"
: "bg-sky-500 text-white hover:bg-sky-600"
)}
>
{loading ? <Loader2 size={18} className="animate-spin" /> : <Send size={18} />}
</button>
</div>
</form>
</div>
</div>
);
}