import React, { useState, useCallback, useMemo } from 'react';
import {
View,
Text,
StyleSheet,
SectionList,
RefreshControl,
useColorScheme,
TextInput,
TouchableOpacity,
} from 'react-native';
import { useRouter } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
import { Colors } from '../../constants/Colors';
import { useTasks, groupTasksByStatus } from '../../hooks/useTasks';
import { TaskListItem } from '../../components/TaskListItem';
import { TaskListSkeleton } from '../../components/TaskListSkeleton';
import { EmptyState } from '../../components/EmptyState';
import type { TaskSummary } from '../../lib/api';
interface Section {
title: string;
data: TaskSummary[];
}
export default function TasksScreen() {
const colorScheme = useColorScheme() ?? 'light';
const colors = Colors[colorScheme];
const router = useRouter();
const [searchQuery, setSearchQuery] = useState('');
const { data: tasks, isLoading, isError, refetch, isRefetching } = useTasks();
// Group and filter tasks
const sections = useMemo(() => {
if (!tasks) return [];
// Filter by search query
const filteredTasks = searchQuery
? tasks.filter(
(task) =>
task.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
task.contractName?.toLowerCase().includes(searchQuery.toLowerCase())
)
: tasks;
// Group by status
const groups = groupTasksByStatus(filteredTasks);
const result: Section[] = [];
if (groups.running.length > 0) {
result.push({ title: 'Running', data: groups.running });
}
if (groups.blocked.length > 0) {
result.push({ title: 'Needs Attention', data: groups.blocked });
}
if (groups.pending.length > 0) {
result.push({ title: 'Pending', data: groups.pending });
}
if (groups.completed.length > 0) {
result.push({ title: 'Completed', data: groups.completed });
}
return result;
}, [tasks, searchQuery]);
const handleTaskPress = useCallback(
(task: TaskSummary) => {
router.push(`/task/${task.id}`);
},
[router]
);
const handleRefresh = useCallback(() => {
refetch();
}, [refetch]);
const clearSearch = useCallback(() => {
setSearchQuery('');
}, []);
// Render loading state
if (isLoading) {
return (
<View style={[styles.container, { backgroundColor: colors.background }]}>
<TaskListSkeleton />
</View>
);
}
// Render error state
if (isError) {
return (
<View style={[styles.container, { backgroundColor: colors.background }]}>
<EmptyState
icon="alert-circle-outline"
title="Failed to load tasks"
message="Pull down to retry"
/>
</View>
);
}
// Render empty state
if (!tasks || tasks.length === 0) {
return (
<View style={[styles.container, { backgroundColor: colors.background }]}>
<EmptyState
icon="cube-outline"
title="No tasks yet"
message="Tasks created from contracts will appear here"
/>
</View>
);
}
return (
<View style={[styles.container, { backgroundColor: colors.background }]}>
{/* Search bar */}
<View
style={[
styles.searchContainer,
{
backgroundColor: colors.secondaryBackground,
borderColor: colors.border,
},
]}
>
<Ionicons name="search" size={18} color={colors.secondaryText} />
<TextInput
style={[styles.searchInput, { color: colors.text }]}
placeholder="Search tasks..."
placeholderTextColor={colors.secondaryText}
value={searchQuery}
onChangeText={setSearchQuery}
autoCapitalize="none"
autoCorrect={false}
/>
{searchQuery.length > 0 && (
<TouchableOpacity onPress={clearSearch}>
<Ionicons name="close-circle" size={18} color={colors.secondaryText} />
</TouchableOpacity>
)}
</View>
{/* Task list */}
<SectionList
sections={sections}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<TaskListItem task={item} onPress={handleTaskPress} />
)}
renderSectionHeader={({ section }) => (
<View
style={[
styles.sectionHeader,
{ backgroundColor: colors.secondaryBackground },
]}
>
<Text style={[styles.sectionTitle, { color: colors.text }]}>
{section.title}
</Text>
<Text style={[styles.sectionCount, { color: colors.secondaryText }]}>
{section.data.length}
</Text>
</View>
)}
refreshControl={
<RefreshControl
refreshing={isRefetching}
onRefresh={handleRefresh}
tintColor={colors.tint}
/>
}
ListEmptyComponent={
searchQuery ? (
<EmptyState
icon="search-outline"
title="No matching tasks"
message={`No tasks match "${searchQuery}"`}
/>
) : null
}
stickySectionHeadersEnabled
contentContainerStyle={sections.length === 0 ? styles.emptyContent : undefined}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
searchContainer: {
flexDirection: 'row',
alignItems: 'center',
margin: 16,
paddingHorizontal: 12,
paddingVertical: 10,
borderRadius: 10,
borderWidth: StyleSheet.hairlineWidth,
gap: 8,
},
searchInput: {
flex: 1,
fontSize: 16,
padding: 0,
},
sectionHeader: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: 16,
paddingVertical: 8,
},
sectionTitle: {
fontSize: 14,
fontWeight: '600',
textTransform: 'uppercase',
letterSpacing: 0.5,
},
sectionCount: {
fontSize: 14,
fontWeight: '500',
},
emptyContent: {
flex: 1,
},
});