import React from 'react';
import {
View,
Text,
StyleSheet,
ScrollView,
TouchableOpacity,
useColorScheme,
RefreshControl,
} from 'react-native';
import { useRouter } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
import { Colors, TaskStatusColors } from '../../constants/Colors';
import { useTasks, getTaskCounts } from '../../hooks/useTasks';
import { usePendingQuestions } from '../../hooks/useQuestions';
import { TaskStatusBadge } from '../../components/TaskStatusBadge';
import type { TaskSummary } from '../../lib/api';
interface StatCardProps {
title: string;
value: number;
icon: keyof typeof Ionicons.glyphMap;
color: string;
onPress?: () => void;
}
function StatCard({ title, value, icon, color, onPress }: StatCardProps) {
const colorScheme = useColorScheme() ?? 'light';
const colors = Colors[colorScheme];
return (
{value}
{title}
);
}
interface QuickTaskItemProps {
task: TaskSummary;
onPress: () => void;
}
function QuickTaskItem({ task, onPress }: QuickTaskItemProps) {
const colorScheme = useColorScheme() ?? 'light';
const colors = Colors[colorScheme];
return (
{task.name}
{task.progressSummary && (
{task.progressSummary}
)}
);
}
export default function DashboardScreen() {
const colorScheme = useColorScheme() ?? 'light';
const colors = Colors[colorScheme];
const router = useRouter();
const {
data: tasks,
isLoading: isLoadingTasks,
refetch: refetchTasks,
isRefetching: isRefetchingTasks,
} = useTasks();
const {
data: questions,
isLoading: isLoadingQuestions,
refetch: refetchQuestions,
isRefetching: isRefetchingQuestions,
} = usePendingQuestions();
const isRefreshing = isRefetchingTasks || isRefetchingQuestions;
const handleRefresh = () => {
refetchTasks();
refetchQuestions();
};
// Calculate counts
const counts = tasks ? getTaskCounts(tasks) : null;
const questionCount = questions?.length ?? 0;
// Get running tasks for quick access
const runningTasks = tasks?.filter((t) =>
['running', 'initializing', 'starting'].includes(t.status)
) ?? [];
// Get tasks needing attention (blocked, paused, or with questions)
const attentionTasks = tasks?.filter((t) =>
['blocked', 'paused'].includes(t.status)
) ?? [];
return (
}
>
{/* Stats Grid */}
router.push('/(tabs)/tasks')}
/>
0 ? () => router.push('/(tabs)/tasks') : undefined}
/>
router.push('/(tabs)/tasks')}
/>
router.push('/(tabs)/tasks') : undefined}
/>
{/* Pending Questions Alert */}
{questionCount > 0 && (
router.push('/(tabs)/tasks')}
activeOpacity={0.7}
>
{questionCount} Question{questionCount !== 1 ? 's' : ''} Waiting
Tap to review and respond
)}
{/* Running Tasks */}
{runningTasks.length > 0 && (
Running Tasks
router.push('/(tabs)/tasks')}>
See All
{runningTasks.slice(0, 3).map((task) => (
router.push(`/task/${task.id}`)}
/>
))}
)}
{/* Needs Attention */}
{attentionTasks.length > 0 && (
Needs Attention
router.push('/(tabs)/tasks')}>
See All
{attentionTasks.slice(0, 3).map((task) => (
router.push(`/task/${task.id}`)}
/>
))}
)}
{/* Empty State */}
{!isLoadingTasks && (!tasks || tasks.length === 0) && (
No tasks yet
Tasks created from contracts will appear here
)}
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
content: {
padding: 16,
gap: 20,
},
statsGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 12,
},
statCard: {
flex: 1,
minWidth: '45%',
padding: 16,
borderRadius: 12,
alignItems: 'center',
gap: 8,
},
iconContainer: {
width: 48,
height: 48,
borderRadius: 24,
alignItems: 'center',
justifyContent: 'center',
},
statValue: {
fontSize: 28,
fontWeight: '700',
},
statTitle: {
fontSize: 14,
fontWeight: '500',
},
alertBanner: {
flexDirection: 'row',
alignItems: 'center',
padding: 16,
borderRadius: 12,
gap: 12,
},
alertContent: {
flex: 1,
},
alertTitle: {
fontSize: 16,
fontWeight: '600',
},
alertSubtitle: {
fontSize: 13,
marginTop: 2,
},
section: {
gap: 12,
},
sectionHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
sectionTitle: {
fontSize: 18,
fontWeight: '600',
},
seeAllButton: {
fontSize: 14,
fontWeight: '500',
},
taskList: {
gap: 8,
},
quickTaskItem: {
flexDirection: 'row',
alignItems: 'center',
padding: 12,
borderRadius: 10,
gap: 12,
},
quickTaskContent: {
flex: 1,
gap: 2,
},
quickTaskName: {
fontSize: 15,
fontWeight: '500',
},
quickTaskSummary: {
fontSize: 13,
},
emptyState: {
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 48,
gap: 12,
},
emptyTitle: {
fontSize: 18,
fontWeight: '600',
},
emptyMessage: {
fontSize: 14,
textAlign: 'center',
},
});