import { useState, useEffect } from 'react'; import { Brain, Sparkles, CheckCircle, XCircle, RotateCcw, Clock, Heart, Lightbulb, ArrowRight, MessageCircle, TrendingUp, Menu, X, Activity, BrainCircuit, Check, BookOpen, Layers, ShieldCheck, Scale } from 'lucide-react'; import frameworkImg from './cbt-macr-framework.png'; // --- Type Definitions --- interface DistortionResult { has_distortion: boolean; distortion_types: string[]; explanation: string; } interface AnalysisResult { emotional_impact: string; underlying_beliefs: string[]; triggers: string[]; recommended_therapies: string[]; therapy_rationales: Record; } interface Candidate { therapy: string; reframe: string; rationale: string; evaluation?: { [key: string]: number; }; } interface FormData { situation: string; thought: string; } interface FeedbackState { belief: number | null; helpfulness: number | null; recall: number | null; learning: number | null; } interface ReframeIteration { reframe: string; iteration: number; } const API_BASE_URL = '/api'; const THERAPY_FULL_NAMES: Record = { "CBT": "Cognitive Behavioral Therapy", "ACT": "Acceptance and Commitment Therapy", "DBT": "Dialectical Behavior Therapy", "REBT": "Rational Emotive Behavior Therapy", "MBCT": "Mindfulness-Based Cognitive Therapy", "CFT": "Compassion-Focused Therapy", "SFBT": "Solution-Focused Brief Therapy", "MI": "Motivational Interviewing", "Schema Therapy": "Schema Therapy", "Narrative Therapy": "Narrative Therapy" }; const LIKERT_OPTIONS = [ { value: 4, label: "Strongly Agree" }, { value: 3, label: "Somewhat Agree" }, { value: 2, label: "Somewhat Disagree" }, { value: 1, label: "Strongly Disagree" } ]; export default function LuminaPlatform() { // --- States --- const [currentPage, setCurrentPage] = useState('app'); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const [step, setStep] = useState(1); const [formData, setFormData] = useState({ situation: '', thought: '' }); const [feedback, setFeedback] = useState({ belief: null, helpfulness: null, recall: null, learning: null }); const [isFeedbackSubmitted, setIsFeedbackSubmitted] = useState(false); const [sessionId, setSessionId] = useState(null); const [distortionResult, setDistortionResult] = useState(null); const [analysis, setAnalysis] = useState(null); const [candidates, setCandidates] = useState([]); const [selectedReframe, setSelectedReframe] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [reframeHistory, setReframeHistory] = useState([]); const [activeHistoryIndex, setActiveHistoryIndex] = useState(0); const [selectedTherapies, setSelectedTherapies] = useState([]); const [aiFeedback, setAiFeedback] = useState(null); const [aiFeedback_summ, setAiFeedback_summ] = useState(null); const [showExample, setShowExample] = useState(false); const [improveCount, setImproveCount] = useState(0); const [isImproving, setIsImproving] = useState(false); // --- Effects --- useEffect(() => { const initSession = async () => { try { const response = await fetch(`${API_BASE_URL}/session/init`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }); const data = await response.json(); setSessionId(data.session_id); } catch (err) { setSessionId('demo-session-' + Date.now()); } }; initSession(); }, []); useEffect(() => { if (analysis && analysis.recommended_therapies) { setSelectedTherapies(analysis.recommended_therapies); } }, [analysis]); useEffect(() => { const initializeStep5 = async () => { if (step === 5 && selectedReframe !== null && candidates[selectedReframe]) { try { const response = await fetch(`${API_BASE_URL}/instruction_feedback`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: sessionId, situation: formData.situation, thought: formData.thought, current_reframe: candidates[selectedReframe].reframe, }) }); if (!response.ok) throw new Error('Network response was not ok'); const apiData = await response.json(); setReframeHistory([{ reframe: candidates[selectedReframe].reframe, iteration: 0 }]); const feedbackObject = JSON.parse(apiData.ai_feedback); setAiFeedback_summ(feedbackObject.summary); setAiFeedback(apiData.ai_feedback); setActiveHistoryIndex(0); setImproveCount(0); } catch (error) { setReframeHistory([{ reframe: candidates[selectedReframe].reframe, iteration: 0 }]); setActiveHistoryIndex(0); setImproveCount(0); } } }; initializeStep5(); }, [step, selectedReframe, candidates, formData.situation, formData.thought, sessionId]); // --- Logic Helpers --- const handleFeedbackChange = (question: keyof FeedbackState, value: number) => setFeedback(prev => ({ ...prev, [question]: value })); const fillExample = () => { setFormData({ situation: "I sent a message to my friend 3 hours ago and saw they were online, but they haven't replied yet.", thought: "They are ignoring me because they find me annoying. I must have said something wrong and now they hate me." }); setShowExample(false); }; const toggleTherapy = (therapyKey: string) => setSelectedTherapies(prev => prev.includes(therapyKey) ? prev.filter(t => t !== therapyKey) : [...prev, therapyKey]); const reset = () => { setStep(1); setFormData({ situation: '', thought: '' }); setDistortionResult(null); setAnalysis(null); setCandidates([]); setSelectedReframe(null); setError(null); setSelectedTherapies([]); setFeedback({ belief: null, helpfulness: null, recall: null, learning: null }); setIsFeedbackSubmitted(false); setImproveCount(0); setIsImproving(false); setReframeHistory([]); setActiveHistoryIndex(0); setAiFeedback(null); }; // --- API Functions --- const detectDistortion = async () => { setLoading(true); setError(null); try { const response = await fetch(`${API_BASE_URL}/detect`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: sessionId, situation: formData.situation, thought: formData.thought }) }); if (!response.ok) throw new Error('Detection failed'); const data = await response.json(); setDistortionResult(data); setStep(2); } catch (err) { setError('Failed to detect distortions. Please try again.'); } finally { setLoading(false); } }; const analyzeThought = async () => { if (!distortionResult) return; setLoading(true); setError(null); try { const response = await fetch(`${API_BASE_URL}/analyze`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: sessionId, situation: formData.situation, thought: formData.thought, distortions: distortionResult.distortion_types }) }); if (!response.ok) throw new Error('Analysis failed'); const data = await response.json(); setAnalysis(data); setStep(3); } catch (err) { setError('Failed to analyze thought. Please try again.'); } finally { setLoading(false); } }; const generateCandidates = async () => { if (!selectedTherapies.length) return; setLoading(true); setError(null); try { const response = await fetch(`${API_BASE_URL}/reframe`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: sessionId, situation: formData.situation, thought: formData.thought, recommended_therapies: selectedTherapies }) }); if (!response.ok) throw new Error('Generation failed'); const data = await response.json(); setCandidates(data.candidates); setStep(4); } catch (err) { setError('Failed to generate reframes. Please try again.'); } finally { setLoading(false); } }; const handleImprove = async () => { if (improveCount >= 5 || selectedReframe === null || reframeHistory.length === 0) return; setIsImproving(true); try { const currentReframeObj = reframeHistory[reframeHistory.length - 1]; const response = await fetch(`${API_BASE_URL}/improve`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: sessionId, situation: formData.situation, thought: formData.thought, current_reframe: currentReframeObj.reframe, history_response: reframeHistory, feedback: aiFeedback }) }); if (!response.ok) throw new Error('Improvement failed'); const data = await response.json(); const feedback_response = await fetch(`${API_BASE_URL}/instruction_feedback`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: sessionId, situation: formData.situation, thought: formData.thought, current_reframe: data.new_reframe }) }); if (!feedback_response.ok) throw new Error('Network response was not ok'); const feedbackData = await feedback_response.json(); const feedbackObject = JSON.parse(feedbackData.ai_feedback); setAiFeedback_summ(feedbackObject.summary); setAiFeedback(feedbackData.ai_feedback); setReframeHistory(prev => [...prev, { reframe: data.new_reframe, iteration: improveCount + 1 }]); setImproveCount(prev => prev + 1); setActiveHistoryIndex(improveCount + 1); setIsFeedbackSubmitted(false); setFeedback({ belief: null, helpfulness: null, recall: null, learning: null }); } catch (err) { console.error('Failed to improve reframe:', err); } finally { setIsImproving(false); } }; const submitFeedback = async () => { try { const response = await fetch(`${API_BASE_URL}/feedback`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: sessionId, timestamp: new Date().toISOString(), input: { situation: formData.situation, thought: formData.thought }, output: { therapy_type: candidates[selectedReframe!]?.therapy, reframe: candidates[selectedReframe!]?.reframe }, ratings: feedback }) }); if (!response.ok) throw new Error('Failed to save feedback'); setIsFeedbackSubmitted(true); } catch (err) { alert("Could not save feedback. Please check your connection."); } }; const saveSelection = async () => { if (selectedReframe === null) return; try { await fetch(`${API_BASE_URL}/save`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ session_id: sessionId, selected_reframe: candidates[selectedReframe], original_thought: formData.thought }) }); } catch (err) { console.error(err); } finally { setStep(5); } }; // --- UI Components --- const renderNavigation = () => ( ); const CustomStepper = () => { const steps = [ { id: 1, name: 'Input', icon: MessageCircle }, { id: 2, name: 'Detect', icon: Activity }, { id: 3, name: 'Analyze', icon: TrendingUp }, { id: 4, name: 'Reframe', icon: Brain }, { id: 5, name: 'Reflect', icon: CheckCircle } ]; return (
{steps.map((s) => { const isActive = step === s.id; const isCompleted = step > s.id; const Icon = s.icon; return (
{isCompleted ? : }
{s.name}
); })}
); }; const renderStep1 = () => (

What's on your mind?

Break down your experience into facts and thoughts. This helps create distance.

{showExample && (

Example Scenario

1. The Situation

"I sent a message to my friend 3 hours ago and haven't received a reply yet."

2. The Thought

"They are ignoring me because they hate me. I always mess up relationships."

)}

Describe the facts as if a camera recorded them (Who, what, when, where).