Skip to content

Commit

Permalink
checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
birdup000 committed Dec 22, 2024
1 parent 8cb7c78 commit e2e5d7e
Show file tree
Hide file tree
Showing 27 changed files with 4,756 additions and 1,106 deletions.
235 changes: 235 additions & 0 deletions app/components/AIAssistantPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
"use client";

import React, { useState } from 'react';
import { useAIAssistant } from '../hooks/useAIAssistant';
import { Task } from '../types/task';

interface AIAssistantPanelProps {
backendUrl: string;
authToken: string;
onTaskSuggestion: (task: Partial<Task>) => void;
onTaskOptimization: (taskIds: string[]) => void;
tasks: Task[];
selectedTask: Task | null;
className?: string;
}

const AIAssistantPanel: React.FC<AIAssistantPanelProps> = ({
backendUrl,
authToken,
onTaskSuggestion,
onTaskOptimization,
tasks,
selectedTask,
className = '',
}) => {
const [context, setContext] = useState('');
const [suggestions, setSuggestions] = useState<any[]>([]);
const [analysis, setAnalysis] = useState<any>(null);
const [isExpanded, setIsExpanded] = useState(true);

const {
isProcessing,
error,
selectedAgent,
setSelectedAgent,
generateTaskSuggestions,
optimizeTaskOrder,
analyzeTaskProgress,
generateSubtasks,
} = useAIAssistant({ backendUrl, authToken });

const handleGenerateSuggestions = async () => {
const result = await generateTaskSuggestions(context);
setSuggestions(result);
};

const handleOptimizeOrder = async () => {
const result = await optimizeTaskOrder(tasks);
if (result) {
onTaskOptimization(result);
}
};

const handleAnalyzeTask = async () => {
if (!selectedTask) return;
const result = await analyzeTaskProgress(selectedTask);
setAnalysis(result);
};

const handleGenerateSubtasks = async () => {
if (!selectedTask) return;
const result = await generateSubtasks(selectedTask);
if (result) {
onTaskSuggestion({ ...selectedTask, subtasks: result.subtasks });
}
};

return (
<div
className={`bg-[#1E1E1E] text-white rounded-lg shadow-lg transition-all duration-300 ease-in-out ${className} ${
isExpanded ? 'w-80' : 'w-12'
}`}
>
<div className="p-4 border-b border-gray-700 flex items-center justify-between">
<h3 className={`font-semibold ${isExpanded ? '' : 'hidden'}`}>AI Assistant</h3>
<button
onClick={() => setIsExpanded(!isExpanded)}
className="p-1 hover:bg-gray-700 rounded transition-colors"
aria-label={isExpanded ? 'Collapse panel' : 'Expand panel'}
>
{isExpanded ? '←' : '→'}
</button>
</div>

{isExpanded && (
<div className="p-4 space-y-6">
{error && (
<div className="bg-red-900/50 text-red-200 p-3 rounded-md text-sm">
{error}
</div>
)}

<div className="space-y-2">
<label className="block text-sm font-medium text-gray-300">
AI Agent
</label>
<select
value={selectedAgent}
onChange={(e) => setSelectedAgent(e.target.value)}
className="w-full px-3 py-2 bg-[#2A2A2A] rounded-md text-white focus:outline-none focus:ring-2 focus:ring-indigo-500"
>
<option value="">Select an agent</option>
<option value="gpt-4">GPT-4</option>
<option value="claude">Claude</option>
</select>
</div>

<div className="space-y-2">
<label className="block text-sm font-medium text-gray-300">
Context
</label>
<textarea
value={context}
onChange={(e) => setContext(e.target.value)}
className="w-full px-3 py-2 bg-[#2A2A2A] rounded-md text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500"
rows={3}
placeholder="Describe your current work context..."
/>
<button
onClick={handleGenerateSuggestions}
disabled={isProcessing || !selectedAgent}
className="w-full px-4 py-2 bg-indigo-600 hover:bg-indigo-700 disabled:bg-gray-600 rounded-md transition-colors"
>
{isProcessing ? 'Generating...' : 'Generate Task Suggestions'}
</button>
</div>

{suggestions.length > 0 && (
<div className="space-y-2">
<h4 className="font-medium text-gray-300">Suggestions</h4>
<div className="space-y-2 max-h-60 overflow-y-auto">
{suggestions.map((suggestion, index) => (
<div
key={index}
className="p-3 bg-[#2A2A2A] rounded-md cursor-pointer hover:bg-[#333333] transition-colors"
onClick={() => onTaskSuggestion(suggestion)}
>
<div className="font-medium">{suggestion.title}</div>
<div className="text-sm text-gray-400 mt-1">
{suggestion.description}
</div>
<div className="flex items-center gap-2 mt-2 text-sm">
<span className={`px-2 py-0.5 rounded-full ${
suggestion.priority === 'high'
? 'bg-red-900/50 text-red-200'
: suggestion.priority === 'medium'
? 'bg-yellow-900/50 text-yellow-200'
: 'bg-green-900/50 text-green-200'
}`}>
{suggestion.priority}
</span>
<span className="text-gray-400">
~{suggestion.estimatedTime} min
</span>
</div>
</div>
))}
</div>
</div>
)}

{selectedTask && (
<div className="space-y-4">
<div className="border-t border-gray-700 pt-4">
<h4 className="font-medium text-gray-300 mb-2">Selected Task Actions</h4>
<div className="space-y-2">
<button
onClick={handleAnalyzeTask}
disabled={isProcessing || !selectedAgent}
className="w-full px-4 py-2 bg-indigo-600 hover:bg-indigo-700 disabled:bg-gray-600 rounded-md transition-colors"
>
Analyze Progress
</button>
<button
onClick={handleGenerateSubtasks}
disabled={isProcessing || !selectedAgent}
className="w-full px-4 py-2 bg-indigo-600 hover:bg-indigo-700 disabled:bg-gray-600 rounded-md transition-colors"
>
Generate Subtasks
</button>
</div>
</div>

{analysis && (
<div className="space-y-2">
<h4 className="font-medium text-gray-300">Analysis</h4>
<div className="p-3 bg-[#2A2A2A] rounded-md space-y-3 max-h-60 overflow-y-auto">
<div>
<div className="text-sm font-medium text-gray-400">Progress</div>
<div>{analysis.progressAnalysis}</div>
</div>
<div>
<div className="text-sm font-medium text-gray-400">Potential Blockers</div>
<ul className="list-disc list-inside">
{analysis.potentialBlockers.map((blocker: string, index: number) => (
<li key={index}>{blocker}</li>
))}
</ul>
</div>
<div>
<div className="text-sm font-medium text-gray-400">Recommendations</div>
<ul className="list-disc list-inside">
{analysis.recommendations.map((rec: string, index: number) => (
<li key={index}>{rec}</li>
))}
</ul>
</div>
<div>
<div className="text-sm font-medium text-gray-400">Estimated Time to Completion</div>
<div>{analysis.estimatedTimeToCompletion} minutes</div>
</div>
</div>
</div>
)}
</div>
)}

{tasks.length > 1 && (
<div className="border-t border-gray-700 pt-4">
<button
onClick={handleOptimizeOrder}
disabled={isProcessing || !selectedAgent}
className="w-full px-4 py-2 bg-indigo-600 hover:bg-indigo-700 disabled:bg-gray-600 rounded-md transition-colors"
>
Optimize Task Order
</button>
</div>
)}
</div>
)}
</div>
);
};

export default AIAssistantPanel;
16 changes: 16 additions & 0 deletions app/components/LoadingScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use client";

import React from 'react';

const LoadingScreen = () => {
return (
<div className="fixed inset-0 bg-[#111111] flex items-center justify-center z-50">
<div className="text-center">
<div className="text-2xl font-bold text-white mb-4">Loading...</div>
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-indigo-500 mx-auto"></div>
</div>
</div>
);
};

export default LoadingScreen;
48 changes: 38 additions & 10 deletions app/components/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { useState } from 'react';
import { useRouter } from 'next/navigation';
import { useAuthContext } from '../providers/AuthProvider';
import { Button } from './ui/button';
import { Input } from './ui/input';
import { Label } from './ui/label';
import LoadingScreen from './LoadingScreen';
import {
Card,
CardContent,
Expand All @@ -15,28 +15,47 @@ import {
const LoginForm = () => {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [showLoadingScreen, setShowLoadingScreen] = useState(false);
const { loginUser, continueWithoutAuth } = useAuthContext();
const router = useRouter();

const handleSubmit = async (event: React.FormEvent) => {
event.preventDefault();
setIsLoading(true);
try {
const response = await loginUser(username, password);
if (response.success) {
router.push('/');
const result = await loginUser(username, password);
if (result.success) {
setShowLoadingScreen(true);
}
} catch (error: any) {
console.error('Login failed', error);
} finally {
setIsLoading(false);
}
};

const handleSkipAuth = async () => {
const result = await continueWithoutAuth();
if (result.success) {
router.push('/');
setIsLoading(true);
try {
const result = await continueWithoutAuth();
console.log('Continue without auth result:', result);
if (result.success) {
setShowLoadingScreen(true);
// Keep loading screen visible during transition
await new Promise(resolve => setTimeout(resolve, 1000));
} else {
throw new Error(result.message);
}
} catch (error) {
console.error('Error in handleSkipAuth:', error);
setIsLoading(false);
}
};

if (showLoadingScreen) {
return <LoadingScreen />;
}

return (
<Card className="w-[350px] border border-gray-700">
<CardHeader>
Expand All @@ -53,6 +72,7 @@ const LoginForm = () => {
value={username}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setUsername(e.target.value)}
required
disabled={isLoading}
/>
</div>
<div className="space-y-2">
Expand All @@ -63,17 +83,25 @@ const LoginForm = () => {
value={password}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setPassword(e.target.value)}
required
disabled={isLoading}
/>
</div>
<div className="space-y-2">
<Button type="submit" className="w-full bg-blue-600 hover:bg-blue-700">Login</Button>
<Button
type="submit"
className="w-full bg-blue-600 hover:bg-blue-700"
disabled={isLoading}
>
{isLoading ? 'Loading...' : 'Login'}
</Button>
<Button
type="button"
variant="outline"
className="w-full border-gray-700 hover:bg-gray-800"
onClick={handleSkipAuth}
disabled={isLoading}
>
Continue without Login
{isLoading ? 'Loading...' : 'Continue without Login'}
</Button>
</div>
</form>
Expand Down
Loading

0 comments on commit e2e5d7e

Please sign in to comment.