import React, { useState, useCallback, useContext } from 'react';
import {
View, Text, StyleSheet, SectionList, TouchableOpacity,
RefreshControl, StatusBar, Alert, Linking
} from 'react-native';
import { useFocusEffect } from '@react-navigation/native';
import { AuthContext } from '../context/AuthContext';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import api from '../services/api';
import Colors from '../constants/Colors';
const TasksScreen = ({ navigation }) => {
const { userInfo } = useContext(AuthContext);
const insets = useSafeAreaInsets();
const [sections, setSections] = useState([]);
const [refreshing, setRefreshing] = useState(false);
const [activeFilter, setActiveFilter] = useState('ALL'); // ALL, PENDING, DONE
const groupByDay = (followups) => {
const map = {};
const today = new Date();
today.setHours(0, 0, 0, 0);
const tomorrow = new Date(today.getTime() + 86400000);
followups.forEach(f => {
const d = new Date(f.date);
d.setHours(0, 0, 0, 0);
let label;
if (d.getTime() === today.getTime()) label = 'Today';
else if (d.getTime() < today.getTime()) label = `Overdue — ${d.toLocaleDateString('en-IN', { day: 'numeric', month: 'short' })}`;
else if (d.getTime() === tomorrow.getTime()) label = 'Tomorrow';
else label = d.toLocaleDateString('en-IN', { weekday: 'long', day: 'numeric', month: 'short' });
if (!map[label]) map[label] = { title: label, data: [], ts: d.getTime() };
map[label].data.push(f);
});
return Object.values(map).sort((a, b) => a.ts - b.ts);
};
const fetchTasks = async () => {
try {
const params = new URLSearchParams({ userId: userInfo.id });
if (activeFilter !== 'ALL') params.append('status', activeFilter);
const res = await api.get(`/followups?${params.toString()}`);
setSections(groupByDay(res.data));
} catch (e) {
console.error('TasksScreen fetch error', e);
} finally {
setRefreshing(false);
}
};
useFocusEffect(useCallback(() => { fetchTasks(); }, [activeFilter]));
const handleMarkDone = async (id) => {
Alert.alert('Mark as Done?', 'This will complete the task and dismiss the notification.', [
{ text: 'Cancel', style: 'cancel' },
{
text: 'Done ✓', onPress: async () => {
try {
await api.patch(`/followups/${id}`, { status: 'DONE' });
fetchTasks();
} catch (e) {
Alert.alert('Error', 'Could not update task.');
}
}
}
]);
};
const handleCall = (phone) => {
if (!phone) return;
Linking.openURL(`tel:${phone}`);
};
const renderTask = ({ item }) => {
const isPending = item.status === 'PENDING';
const isOverdue = isPending && new Date(item.date) < new Date();
return (
{item.client?.name || 'Unknown Client'}
{item.client?.phone && (
handleCall(item.client.phone)}>
📞
)}
{item.notes}
{new Date(item.date).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}
{item.user?.name ? ` • Assigned by ${item.user.name}` : ''}
{isPending && (
handleMarkDone(item.id)}>
Done
)}
{!isPending && (
✓
)}
);
};
return (
My Tasks
Sorted by date
{['ALL', 'PENDING', 'DONE'].map(f => (
setActiveFilter(f)}
>
{f}
))}
item.id}
renderItem={renderTask}
renderSectionHeader={({ section }) => (
{section.title}
{section.data.length} task{section.data.length !== 1 ? 's' : ''}
)}
refreshControl={ { setRefreshing(true); fetchTasks(); }} colors={[Colors.primary]} />}
contentContainerStyle={{ paddingBottom: 40 }}
ListEmptyComponent={
🎉
All Clear!
No tasks match this filter.
}
/>
);
};
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#f1f5f9' },
header: { backgroundColor: Colors.primary, paddingHorizontal: 20, paddingBottom: 20 },
headerTitle: { color: 'white', fontSize: 26, fontWeight: '900' },
headerSub: { color: 'rgba(255,255,255,0.7)', fontSize: 12, marginTop: 2, marginBottom: 14 },
filterRow: { flexDirection: 'row', gap: 8 },
filterBtn: { paddingHorizontal: 16, paddingVertical: 6, borderRadius: 20, backgroundColor: 'rgba(255,255,255,0.2)' },
filterBtnActive: { backgroundColor: 'white' },
filterText: { color: 'rgba(255,255,255,0.8)', fontSize: 12, fontWeight: '700' },
filterTextActive: { color: Colors.primary },
sectionHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 16, paddingTop: 20, paddingBottom: 8 },
sectionTitle: { fontSize: 13, fontWeight: '900', color: '#475569', textTransform: 'uppercase', letterSpacing: 0.5 },
sectionCount: { fontSize: 11, color: '#94a3b8', fontWeight: '700' },
card: { backgroundColor: 'white', marginHorizontal: 16, marginBottom: 8, borderRadius: 14, padding: 14, flexDirection: 'row', alignItems: 'center', elevation: 2, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.06, shadowRadius: 4 },
cardOverdue: { borderLeftWidth: 4, borderLeftColor: '#ef4444' },
cardDone: { opacity: 0.65 },
dot: { width: 10, height: 10, borderRadius: 5, marginRight: 12 },
clientName: { fontSize: 14, fontWeight: '800', color: '#1e293b', marginBottom: 3, flex: 1 },
callIcon: { fontSize: 18, paddingHorizontal: 10 },
notes: { fontSize: 12, color: '#64748b', lineHeight: 17, marginBottom: 5 },
time: { fontSize: 10, color: '#94a3b8', fontWeight: '600' },
doneBtn: { backgroundColor: Colors.primary, paddingHorizontal: 14, paddingVertical: 8, borderRadius: 10, marginLeft: 10 },
doneBtnText: { color: 'white', fontSize: 11, fontWeight: '900' },
completedBadge: { width: 28, height: 28, borderRadius: 14, backgroundColor: '#dcfce7', justifyContent: 'center', alignItems: 'center', marginLeft: 10 },
completedText: { color: '#16a34a', fontWeight: '900', fontSize: 14 },
empty: { alignItems: 'center', paddingTop: 80 },
emptyIcon: { fontSize: 48, marginBottom: 12 },
emptyTitle: { fontSize: 18, fontWeight: '800', color: '#1e293b' },
emptySub: { fontSize: 13, color: '#94a3b8', marginTop: 6 },
});
export default TasksScreen;