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 (
<TouchableOpacity
style={[styles.statCard, { backgroundColor: colors.card }]}
onPress={onPress}
activeOpacity={onPress ? 0.7 : 1}
disabled={!onPress}
>
<View style={[styles.iconContainer, { backgroundColor: color + '20' }]}>
<Ionicons name={icon} size={24} color={color} />
</View>
<Text style={[styles.statValue, { color: colors.text }]}>{value}</Text>
<Text style={[styles.statTitle, { color: colors.secondaryText }]}>
{title}
</Text>
</TouchableOpacity>
);
}
interface QuickTaskItemProps {
task: TaskSummary;
onPress: () => void;
}
function QuickTaskItem({ task, onPress }: QuickTaskItemProps) {
const colorScheme = useColorScheme() ?? 'light';
const colors = Colors[colorScheme];
return (
<TouchableOpacity
style={[styles.quickTaskItem, { backgroundColor: colors.card }]}
onPress={onPress}
activeOpacity={0.7}
>
<TaskStatusBadge status={task.status} size="small" />
<View style={styles.quickTaskContent}>
<Text
style={[styles.quickTaskName, { color: colors.text }]}
numberOfLines={1}
>
{task.name}
</Text>
{task.progressSummary && (
<Text
style={[styles.quickTaskSummary, { color: colors.secondaryText }]}
numberOfLines={1}
>
{task.progressSummary}
</Text>
)}
</View>
<Ionicons name="chevron-forward" size={16} color={colors.secondaryText} />
</TouchableOpacity>
);
}
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 (
<ScrollView
style={[styles.container, { backgroundColor: colors.background }]}
contentContainerStyle={styles.content}
refreshControl={
<RefreshControl
refreshing={isRefreshing}
onRefresh={handleRefresh}
tintColor={colors.tint}
/>
}
>
{/* Stats Grid */}
<View style={styles.statsGrid}>
<StatCard
title="Running"
value={counts?.running ?? 0}
icon="play-circle"
color={TaskStatusColors.running.dot}
onPress={() => router.push('/(tabs)/tasks')}
/>
<StatCard
title="Questions"
value={questionCount}
icon="help-circle"
color="#f59e0b"
onPress={questionCount > 0 ? () => router.push('/(tabs)/tasks') : undefined}
/>
<StatCard
title="Completed"
value={counts?.completed ?? 0}
icon="checkmark-circle"
color={TaskStatusColors.done.dot}
onPress={() => router.push('/(tabs)/tasks')}
/>
<StatCard
title="Failed"
value={counts?.failed ?? 0}
icon="alert-circle"
color={TaskStatusColors.failed.dot}
onPress={counts?.failed ? () => router.push('/(tabs)/tasks') : undefined}
/>
</View>
{/* Pending Questions Alert */}
{questionCount > 0 && (
<TouchableOpacity
style={[styles.alertBanner, { backgroundColor: '#fef3c7' }]}
onPress={() => router.push('/(tabs)/tasks')}
activeOpacity={0.7}
>
<Ionicons name="help-circle" size={24} color="#92400e" />
<View style={styles.alertContent}>
<Text style={[styles.alertTitle, { color: '#92400e' }]}>
{questionCount} Question{questionCount !== 1 ? 's' : ''} Waiting
</Text>
<Text style={[styles.alertSubtitle, { color: '#b45309' }]}>
Tap to review and respond
</Text>
</View>
<Ionicons name="chevron-forward" size={20} color="#92400e" />
</TouchableOpacity>
)}
{/* Running Tasks */}
{runningTasks.length > 0 && (
<View style={styles.section}>
<View style={styles.sectionHeader}>
<Text style={[styles.sectionTitle, { color: colors.text }]}>
Running Tasks
</Text>
<TouchableOpacity onPress={() => router.push('/(tabs)/tasks')}>
<Text style={[styles.seeAllButton, { color: colors.tint }]}>
See All
</Text>
</TouchableOpacity>
</View>
<View style={styles.taskList}>
{runningTasks.slice(0, 3).map((task) => (
<QuickTaskItem
key={task.id}
task={task}
onPress={() => router.push(`/task/${task.id}`)}
/>
))}
</View>
</View>
)}
{/* Needs Attention */}
{attentionTasks.length > 0 && (
<View style={styles.section}>
<View style={styles.sectionHeader}>
<Text style={[styles.sectionTitle, { color: colors.text }]}>
Needs Attention
</Text>
<TouchableOpacity onPress={() => router.push('/(tabs)/tasks')}>
<Text style={[styles.seeAllButton, { color: colors.tint }]}>
See All
</Text>
</TouchableOpacity>
</View>
<View style={styles.taskList}>
{attentionTasks.slice(0, 3).map((task) => (
<QuickTaskItem
key={task.id}
task={task}
onPress={() => router.push(`/task/${task.id}`)}
/>
))}
</View>
</View>
)}
{/* Empty State */}
{!isLoadingTasks && (!tasks || tasks.length === 0) && (
<View style={styles.emptyState}>
<Ionicons
name="cube-outline"
size={64}
color={colors.secondaryText}
/>
<Text style={[styles.emptyTitle, { color: colors.text }]}>
No tasks yet
</Text>
<Text style={[styles.emptyMessage, { color: colors.secondaryText }]}>
Tasks created from contracts will appear here
</Text>
</View>
)}
</ScrollView>
);
}
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',
},
});