Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 41 additions & 41 deletions app/components/Agents/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,43 @@ export const AgentsMain: React.FC<{ isSidebarOpen?: boolean }> = ({
const userAddress = getAddress();
const hasSession = isAuthenticated || !!userAddress;

const loadEnabledAgents = useCallback(async () => {
const userAddress = getAddress();
if (!userAddress) return;

try {
const response = await fetch(
`/api/agents/status?walletAddress=${userAddress}`
);
if (response.ok) {
const data = await response.json();
setEnabledAgents(data.agents || []);
}
} catch (error) {
console.error('Failed to load enabled agents:', error);
}
}, [getAddress]);

const loadUserConfig = useCallback(async () => {
const userAddress = getAddress();
if (!userAddress) return;

try {
const response = await fetch('/api/agents/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ walletAddress: userAddress }),
});

if (response.ok) {
const data = await response.json();
setUserConfig(data.config || {});
}
} catch (error) {
console.error('Failed to load user agent config:', error);
}
}, [getAddress]);

const loadUserAgentData = useCallback(async () => {
const walletAddr = getAddress();
if (!walletAddr) return;
Expand All @@ -98,9 +135,9 @@ export const AgentsMain: React.FC<{ isSidebarOpen?: boolean }> = ({
isClosable: true,
});
}
}, [getAddress, toast]);
}, [getAddress, toast, loadEnabledAgents, loadUserConfig]);

const loadAvailableAgents = async () => {
const loadAvailableAgents = useCallback(async () => {
try {
const response = await fetch('/api/agents/available');
if (response.ok) {
Expand Down Expand Up @@ -133,51 +170,14 @@ export const AgentsMain: React.FC<{ isSidebarOpen?: boolean }> = ({
} catch (error) {
console.error('Failed to load available agents:', error);
}
};

const loadEnabledAgents = async () => {
const userAddress = getAddress();
if (!userAddress) return;

try {
const response = await fetch(
`/api/agents/status?walletAddress=${userAddress}`
);
if (response.ok) {
const data = await response.json();
setEnabledAgents(data.agents || []);
}
} catch (error) {
console.error('Failed to load enabled agents:', error);
}
};

const loadUserConfig = async () => {
const userAddress = getAddress();
if (!userAddress) return;

try {
const response = await fetch('/api/agents/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ walletAddress: userAddress }),
});

if (response.ok) {
const data = await response.json();
setUserConfig(data.config || {});
}
} catch (error) {
console.error('Failed to load user agent config:', error);
}
};
}, [defaultsInitialized]);

// Load available agents immediately (no auth needed)
useEffect(() => {
loadAvailableAgents().finally(() => {
setGlobalLoading(false);
});
}, []);
}, [loadAvailableAgents]);

// Load user-specific data when authenticated
useEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion app/components/Auth/AutoAuth.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const AutoAuth = () => {
if (isConnected && address && !isAuthenticated) {
authenticate();
}
}, [isConnected, address, isAuthenticated]);
}, [isConnected, address, isAuthenticated, authenticate]);

// No UI is rendered
return null;
Expand Down
11 changes: 11 additions & 0 deletions app/components/Chat/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ChatInput } from '@/components/ChatInput';
import PrefilledOptions from '@/components/ChatInput/PrefilledOptions';
import { JobsList } from '@/components/JobsList';
import { JobSuggestions } from '@/components/JobSuggestions';
import { MessageList } from '@/components/MessageList';
import { StatsCarousel } from '@/components/StatsCarousel';
import { useChatContext } from '@/contexts/chat/useChatContext';
Expand Down Expand Up @@ -485,6 +486,11 @@ export const Chat: FC<{
</Box>
</Box>

{/* Mobile Job Suggestions */}
<Box mb={3}>
<JobSuggestions isVisible={true} />
</Box>

<ChatInput
onSubmit={handleSubmit}
disabled={isSubmitting || showLoading}
Expand Down Expand Up @@ -655,6 +661,11 @@ export const Chat: FC<{
</Box>
)}

{/* Job Suggestions */}
<Box width="100%">
<JobSuggestions isVisible={true} />
</Box>

{/* Jobs List - directly under input/options */}
<Box width="100%">
<JobsList
Expand Down
2 changes: 1 addition & 1 deletion app/components/ErrorBackendModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const ErrorBackendModal: FC<ErrorBackendModalProps> = ({ show }) => {
} else if (!show && isOpen) {
onClose();
}
}, [show, isOpen]);
}, [show, isOpen, onClose, onOpen]);



Expand Down
10 changes: 5 additions & 5 deletions app/components/JobSuggestions/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useEffect } from 'react';
import { useState, useEffect, useCallback } from 'react';
import {
Box,
VStack,
Expand Down Expand Up @@ -43,7 +43,7 @@ export const JobSuggestions: React.FC<JobSuggestionsProps> = ({
const { getAddress } = useWalletAddress();
const toast = useToast();

const fetchSuggestions = async () => {
const fetchSuggestions = useCallback(async () => {
const walletAddress = getAddress();
if (!walletAddress) return;

Expand All @@ -63,15 +63,15 @@ export const JobSuggestions: React.FC<JobSuggestionsProps> = ({
if (response.ok) {
const data = await response.json();
setSuggestions(data.suggestions || []);

trackEvent('job.suggestions_loaded');
}
} catch (error) {
console.error('Error fetching job suggestions:', error);
} finally {
setLoading(false);
}
};
}, [getAddress, userContext]);

const createJobFromSuggestion = async (suggestion: JobSuggestion) => {
const walletAddress = getAddress();
Expand Down Expand Up @@ -148,7 +148,7 @@ export const JobSuggestions: React.FC<JobSuggestionsProps> = ({
if (isVisible && suggestions.length === 0) {
fetchSuggestions();
}
}, [isVisible]);
}, [isVisible, fetchSuggestions, suggestions.length]);

if (!isVisible || suggestions.length === 0) {
return null;
Expand Down
91 changes: 8 additions & 83 deletions app/components/MessageCounter/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ export const MessageCounter: FC<MessageCounterProps> = ({
textAlign = 'center',
}) => {
const [stats, setStats] = useState<ComprehensiveStats | null>(null);
const [currentMessageIndex, setCurrentMessageIndex] = useState(0);

const fetchStats = useCallback(async () => {
try {
Expand All @@ -48,70 +47,18 @@ export const MessageCounter: FC<MessageCounterProps> = ({
return () => clearInterval(interval);
}, [fetchStats]);

// Carousel animation logic
useEffect(() => {
const messages = stats?.carouselMessages || [
'has completed 0 jobs',
'is ready to assist you',
'handles automated tasks',
'saves you time',
];

if (messages.length <= 1) return;

const interval = setInterval(() => {
setCurrentMessageIndex((prev) => (prev + 1) % messages.length);
}, 4000); // Change every 4 seconds

return () => clearInterval(interval);
}, [stats]);

const messages = stats?.carouselMessages || [
'has completed 0 jobs',
'is ready to assist you',
'handles automated tasks',
'saves you time',
];
// Single message display - no carousel needed
const message = stats?.carouselMessages?.[0] || 'has completed 0 total jobs to date';

return (
<Box
textAlign={textAlign}
position="relative"
height="40px"
overflow="hidden"
>
<style jsx global>{`
@keyframes slideUp {
0% {
transform: translateY(100%);
opacity: 0;
}
10% {
transform: translateY(0);
opacity: 1;
}
90% {
transform: translateY(0);
opacity: 1;
}
100% {
transform: translateY(-100%);
opacity: 0;
}
}

.carousel-text {
animation: slideUp 4s ease-in-out infinite;
}
`}</style>

<Box textAlign={textAlign}>
<Text
fontSize={fontSize}
fontWeight="500"
display="inline-flex"
alignItems="baseline"
>
{/* FreeAI is ALWAYS visible and fixed */}
{/* FreeAI branding */}
<Text
as="span"
background="linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
Expand All @@ -126,32 +73,10 @@ export const MessageCounter: FC<MessageCounterProps> = ({
{' '}
</Text>

{/* Carousel container - inline-block to stay on same line */}
<Box
as="span"
display="inline-block"
position="relative"
height="1.5em"
width="auto"
overflow="hidden"
verticalAlign="baseline"
>
{messages.map((msg, index) => (
<Text
key={`${msg}-${index}`}
as="span"
color={color}
position="absolute"
whiteSpace="nowrap"
transform={`translateY(${(index - currentMessageIndex) * 100}%)`}
transition="transform 0.5s ease-in-out"
opacity={index === currentMessageIndex ? 1 : 0}
display="block"
>
{msg}
</Text>
))}
</Box>
{/* Single message display */}
<Text as="span" color={color}>
{message}
</Text>
</Text>
</Box>
);
Expand Down
20 changes: 10 additions & 10 deletions app/components/Settings/A2AManagement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import {
Users,
XCircle,
} from 'lucide-react';
import React, { useEffect, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
import { useAccount } from 'wagmi';

interface A2AManagementProps {
Expand Down Expand Up @@ -116,14 +116,7 @@ export const A2AManagement: React.FC<A2AManagementProps> = ({ onSave }) => {
const [messageType, setMessageType] = useState<'text' | 'json'>('text');
const [sendingMessage, setSendingMessage] = useState(false);

// Load data on mount
useEffect(() => {
if (isAuthenticated) {
loadConnectedAgents();
}
}, [isAuthenticated]);

const loadConnectedAgents = async () => {
const loadConnectedAgents = useCallback(async () => {
const userAddress = getAddress();
if (!userAddress) return;

Expand All @@ -146,7 +139,14 @@ export const A2AManagement: React.FC<A2AManagementProps> = ({ onSave }) => {
} finally {
setGlobalLoading(false);
}
};
}, [getAddress, toast]);

// Load data on mount
useEffect(() => {
if (isAuthenticated) {
loadConnectedAgents();
}
}, [isAuthenticated, loadConnectedAgents]);

const handleDiscoverAgents = async () => {
const userAddress = getAddress();
Expand Down
Loading