ai-helpdesk-api / Frontend /src /user /pages /AutoResolve.jsx
ritesh19180's picture
Upload folder using huggingface_hub
d96d2a2 verified
Raw
History Blame Contribute Delete
9.02 kB
import React, { useState, useEffect, useRef } from 'react';
import { useNavigate } from 'react-router-dom';
import { Bot, User, CheckCircle2, XCircle, Send, RefreshCcw, ShieldCheck } from 'lucide-react';
import useTicketStore from '../../store/ticketStore';
function AutoResolve() {
const { aiTicket } = useTicketStore();
const navigate = useNavigate();
const [messages, setMessages] = useState([]);
const [isThinking, setIsThinking] = useState(false);
const [currentOptions, setCurrentOptions] = useState([]);
const [isFinal, setIsFinal] = useState(false);
const scrollRef = useRef(null);
const fetchNextStep = async (history = []) => {
setIsThinking(true);
try {
const response = await fetch('http://127.0.0.1:8000/ai/troubleshoot', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: aiTicket.summary,
category: aiTicket.category,
history: history
})
});
const data = await response.json();
// Add bot message
setMessages(prev => [...prev, { role: 'bot', text: data.step_text }]);
setCurrentOptions(data.options || []);
setIsFinal(data.is_final);
} catch (error) {
console.error("Troubleshooting Error:", error);
setMessages(prev => [...prev, {
role: 'bot',
text: "I encountered an error connecting to the AI. Let's try basic troubleshooting first."
}]);
setCurrentOptions(["My internet is working", "I'm not sure"]);
} finally {
setIsThinking(false);
}
};
useEffect(() => {
if (!aiTicket) {
navigate('/create-ticket');
return;
}
// Initial fetch
if (messages.length === 0) {
fetchNextStep([]);
}
}, [aiTicket, navigate]);
useEffect(() => {
if (scrollRef.current) {
scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
}
}, [messages, isThinking]);
const handleUserChoice = (choice) => {
const newUserMsg = { role: 'user', text: choice };
const updatedHistory = [...messages, newUserMsg];
setMessages(prev => [...prev, newUserMsg]);
setCurrentOptions([]); // Clear options while thinking
fetchNextStep(updatedHistory);
};
if (!aiTicket) return null;
return (
<main className="flex-1 flex flex-col h-[calc(100vh-64px)] overflow-hidden">
{/* Header */}
<div className="bg-white border-b border-gray-200 px-8 py-4 flex items-center justify-between shadow-sm shrink-0">
<div className="flex items-center gap-3">
<div className="bg-emerald-100 p-2 rounded-lg">
<Bot className="w-5 h-5 text-emerald-700" />
</div>
<div>
<h1 className="text-lg font-bold text-gray-900 uppercase tracking-tight">Troubleshooting Assistant</h1>
<p className="text-xs text-gray-500 font-medium">Auto-Resolution for {aiTicket.summary}</p>
</div>
</div>
<div className="flex items-center gap-2 px-3 py-1 bg-emerald-50 text-emerald-700 rounded-full border border-emerald-100">
<ShieldCheck className="w-4 h-4" />
<span className="text-xs font-bold uppercase tracking-wider">AI Guided Mode</span>
</div>
</div>
{/* Chat Area */}
<div
ref={scrollRef}
className="flex-1 overflow-y-auto p-4 md:p-8 space-y-6 scroll-smooth"
>
{messages.map((msg, idx) => (
<div key={idx} className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}>
<div className={`flex gap-3 max-w-[80%] ${msg.role === 'user' ? 'flex-row-reverse' : 'flex-row'}`}>
<div className={`w-10 h-10 rounded-xl flex items-center justify-center shrink-0 shadow-sm ${msg.role === 'bot' ? 'bg-emerald-600 text-white' : 'bg-white text-gray-400 border border-gray-100'
}`}>
{msg.role === 'bot' ? <Bot size={20} /> : <User size={20} />}
</div>
<div className={`p-4 rounded-2xl text-sm font-medium leading-relaxed shadow-sm ${msg.role === 'bot'
? 'bg-white text-gray-700 rounded-tl-none border border-emerald-50'
: 'bg-emerald-900 text-white rounded-tr-none'
}`}>
{msg.text}
</div>
</div>
</div>
))}
{isThinking && (
<div className="flex justify-start">
<div className="flex gap-3">
<div className="w-10 h-10 rounded-xl bg-emerald-600 text-white flex items-center justify-center shadow-sm">
<Bot size={20} />
</div>
<div className="bg-white border border-emerald-50 p-4 rounded-2xl rounded-tl-none flex gap-1 items-center shadow-sm">
<div className="w-1.5 h-1.5 bg-emerald-400 rounded-full animate-bounce [animation-delay:-0.3s]"></div>
<div className="w-1.5 h-1.5 bg-emerald-400 rounded-full animate-bounce [animation-delay:-0.15s]"></div>
<div className="w-1.5 h-1.5 bg-emerald-400 rounded-full animate-bounce"></div>
</div>
</div>
</div>
)}
</div>
{/* Footer / Input */}
<div className="bg-white border-t border-gray-100 p-6 shadow-[0_-4px_20px_rgba(0,0,0,0.03)] shrink-0">
<div className="max-w-4xl mx-auto">
{!isFinal ? (
<div className="flex flex-wrap gap-3 justify-center">
{currentOptions.map((option, idx) => (
<button
key={idx}
disabled={isThinking}
onClick={() => handleUserChoice(option)}
className="px-6 py-3 bg-white border border-gray-200 text-gray-700 font-bold rounded-xl hover:border-emerald-500 hover:text-emerald-700 hover:bg-emerald-50/50 active:scale-[0.98] transition-all disabled:opacity-50 disabled:cursor-not-allowed shadow-sm flex items-center gap-2 group"
>
{option}
<Send size={14} className="opacity-0 group-hover:opacity-100 -translate-x-2 group-hover:translate-x-0 transition-all" />
</button>
))}
</div>
) : (
<div className="flex flex-col sm:flex-row gap-4 items-center justify-center">
<button
onClick={() => navigate('/resolved')}
className="w-full sm:w-auto px-8 py-4 bg-emerald-600 text-white font-black rounded-xl hover:bg-emerald-700 shadow-lg shadow-emerald-600/20 active:scale-[0.98] transition-all flex items-center justify-center gap-2"
>
<CheckCircle2 size={20} />
Yes, It Works
</button>
<button
onClick={() => navigate('/ticket-tracking')}
className="w-full sm:w-auto px-8 py-4 bg-gray-900 text-white font-black rounded-xl hover:bg-black shadow-lg shadow-gray-900/10 active:scale-[0.98] transition-all flex items-center justify-center gap-2"
>
<XCircle size={20} />
Still Not Working
</button>
<button
onClick={() => window.location.reload()}
className="w-full sm:w-auto px-4 py-4 text-gray-400 hover:text-emerald-600 transition-colors"
>
<RefreshCcw size={20} />
</button>
</div>
)}
</div>
</div>
</main>
);
}
export default AutoResolve;