interactive / App.tsx
caustino's picture
Upload 20 files
bb8c446 verified
Raw
History Blame Contribute Delete
5.34 kB
import React, { useState, useCallback } from 'react';
import { CaseIntakeForm } from './components/CaseIntakeForm';
import { ActionPlanComponent } from './components/ActionPlan';
import { generateActionPlan } from './services/geminiService';
import type { ActionPlan, CaseData, ActionItemStatus } from './types';
import { Spinner } from './components/icons/Spinner';
const App: React.FC = () => {
const [view, setView] = useState<'form' | 'plan'>('form');
const [actionPlan, setActionPlan] = useState<ActionPlan | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
const handleFormSubmit = useCallback(async (data: CaseData) => {
setIsLoading(true);
setError(null);
try {
const plan = await generateActionPlan(data);
setActionPlan(plan);
setView('plan');
} catch (err) {
console.error(err);
setError('Failed to generate an action plan. Please check your API key and try again.');
} finally {
setIsLoading(false);
}
}, []);
const handleToggleItem = useCallback((categoryIndex: number, itemIndex: number) => {
setActionPlan(prevPlan => {
if (!prevPlan) return null;
const newPlan = JSON.parse(JSON.stringify(prevPlan));
const currentStatus = newPlan.categories[categoryIndex].items[itemIndex].status;
const newStatus: ActionItemStatus = currentStatus === 'Completed' ? 'Not Started' : 'Completed';
newPlan.categories[categoryIndex].items[itemIndex].status = newStatus;
return newPlan;
});
}, []);
const handleReset = useCallback(() => {
setView('form');
setActionPlan(null);
setError(null);
}, []);
return (
<div className="min-h-screen bg-gray-950">
<div className="relative isolate overflow-hidden">
<svg
className="absolute inset-0 -z-10 h-full w-full stroke-white/10 [mask-image:radial-gradient(100%_100%_at_top_right,white,transparent)]"
aria-hidden="true"
>
<defs>
<pattern
id="983e3e4c-de6d-4c3f-8d64-b9761d1534cc"
width={200}
height={200}
x="50%"
y={-1}
patternUnits="userSpaceOnUse"
>
<path d="M.5 200V.5H200" fill="none" />
</pattern>
</defs>
<svg x="50%" y={-1} className="overflow-visible fill-gray-800/20">
<path
d="M-200 0h201v201h-201Z M600 0h201v201h-201Z M-400 600h201v201h-201Z M200 800h201v201h-201Z"
strokeWidth={0}
/>
</svg>
<rect width="100%" height="100%" strokeWidth={0} fill="url(#983e3e4c-de6d-4c3f-8d64-b9761d1534cc)" />
</svg>
</div>
<main className="container mx-auto px-4 py-8 md:py-16">
<header className="text-center mb-12">
<h1 className="font-display text-4xl md:text-6xl font-bold tracking-tight text-white">
SSDI Case Prep <span className="text-brand-secondary">Assistant</span>
</h1>
<p className="mt-4 text-lg text-gray-400 max-w-2xl mx-auto">
Your AI-powered guide to organizing and strengthening your Social Security Disability claim.
</p>
</header>
{isLoading && (
<div className="fixed inset-0 bg-gray-950 bg-opacity-80 flex flex-col items-center justify-center z-50">
<Spinner />
<p className="mt-4 text-white text-lg font-medium">Generating your personalized action plan...</p>
<p className="mt-2 text-gray-400">This may take a moment. The AI is analyzing your case details.</p>
</div>
)}
{error && (
<div className="bg-red-900/50 border border-red-700 text-red-300 px-4 py-3 rounded-lg relative max-w-2xl mx-auto" role="alert">
<strong className="font-bold">Error: </strong>
<span className="block sm:inline">{error}</span>
</div>
)}
<div className="max-w-4xl mx-auto">
{view === 'form' && !actionPlan ? (
<CaseIntakeForm onSubmit={handleFormSubmit} />
) : (
actionPlan && <ActionPlanComponent plan={actionPlan} onToggleItem={handleToggleItem} onReset={handleReset} />
)}
</div>
</main>
<footer className="text-center py-8 text-gray-500">
<p>&copy; {new Date().getFullYear()} SSDI Case Prep Assistant. All Rights Reserved.</p>
</footer>
</div>
);
};
export default App;