import { useState, useEffect, useCallback } from 'react'; import { View, Text, FlatList, TouchableOpacity, StyleSheet, RefreshControl, Alert, TextInput, Modal, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { useAuthContext } from '../../lib/AuthContext'; import * as api from '../../lib/api'; const PRIORITY_COLORS: Record = { high: '#EF4444', medium: '#F59E0B', low: '#22C55E', }; const STATUS_ICONS: Record = { todo: 'ellipse-outline', in_progress: 'time-outline', done: 'checkmark-circle', }; export default function TasksScreen() { const { token } = useAuthContext(); const [tasks, setTasks] = useState([]); const [groups, setGroups] = useState([]); const [refreshing, setRefreshing] = useState(false); const [showAdd, setShowAdd] = useState(false); const [newTitle, setNewTitle] = useState(''); const [filter, setFilter] = useState('all'); const loadData = useCallback(async () => { if (!token) return; try { const [tasksRes, groupsRes] = await Promise.all([ api.getTasks(token), api.getGroups(token), ]); setTasks(tasksRes.data || []); setGroups(groupsRes.data || []); } catch (err: any) { Alert.alert('Chyba', err.message); } }, [token]); useEffect(() => { loadData(); }, [loadData]); const onRefresh = useCallback(async () => { setRefreshing(true); await loadData(); setRefreshing(false); }, [loadData]); const addTask = async () => { if (!newTitle.trim() || !token) return; try { await api.createTask(token, { title: newTitle.trim() }); setNewTitle(''); setShowAdd(false); await loadData(); } catch (err: any) { Alert.alert('Chyba', err.message); } }; const toggleTask = async (task: any) => { if (!token) return; const newStatus = task.status === 'done' ? 'todo' : 'done'; try { await api.updateTask(token, task.id, { status: newStatus }); await loadData(); } catch (err: any) { Alert.alert('Chyba', err.message); } }; const filteredTasks = filter === 'all' ? tasks : tasks.filter((t) => t.status === filter); const getGroupColor = (groupId: string) => { const group = groups.find((g) => g.id === groupId); return group?.color || '#64748B'; }; const renderTask = ({ item }: { item: any }) => ( toggleTask(item)} activeOpacity={0.7} > {item.title} {item.group_name && ( {item.group_name} )} {item.priority && ( )} ); return ( {/* Filter bar */} {['all', 'todo', 'in_progress', 'done'].map((f) => ( setFilter(f)} > {f === 'all' ? 'Vse' : f === 'todo' ? 'K provedeni' : f === 'in_progress' ? 'Rozpracovano' : 'Hotovo'} ))} {/* Task list */} item.id?.toString()} renderItem={renderTask} refreshControl={ } contentContainerStyle={styles.listContent} ListEmptyComponent={ Zatim zadne ukoly } /> {/* FAB */} setShowAdd(true)} > {/* Add task modal */} Novy ukol { setShowAdd(false); setNewTitle(''); }} > Zrusit Pridat ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#F8FAFC' }, filterBar: { flexDirection: 'row', padding: 12, gap: 8, backgroundColor: '#fff', borderBottomWidth: 1, borderBottomColor: '#E2E8F0', }, filterBtn: { paddingHorizontal: 12, paddingVertical: 6, borderRadius: 16, backgroundColor: '#F1F5F9', }, filterBtnActive: { backgroundColor: '#3B82F6' }, filterText: { fontSize: 13, color: '#64748B' }, filterTextActive: { color: '#fff', fontWeight: '600' }, listContent: { padding: 12, paddingBottom: 80 }, taskCard: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', backgroundColor: '#fff', borderRadius: 12, padding: 16, marginBottom: 8, shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.05, shadowRadius: 3, elevation: 2, }, taskLeft: { flexDirection: 'row', alignItems: 'center', flex: 1 }, taskInfo: { marginLeft: 12, flex: 1 }, taskTitle: { fontSize: 15, color: '#1E293B', fontWeight: '500' }, taskDone: { textDecorationLine: 'line-through', color: '#94A3B8', }, groupBadge: { marginTop: 4, paddingHorizontal: 8, paddingVertical: 2, borderRadius: 8, alignSelf: 'flex-start' }, groupBadgeText: { fontSize: 11, fontWeight: '600' }, priorityDot: { width: 10, height: 10, borderRadius: 5 }, empty: { alignItems: 'center', marginTop: 60 }, emptyText: { color: '#94A3B8', fontSize: 16, marginTop: 12 }, fab: { position: 'absolute', right: 20, bottom: 20, width: 56, height: 56, borderRadius: 28, backgroundColor: '#3B82F6', alignItems: 'center', justifyContent: 'center', shadowColor: '#3B82F6', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.3, shadowRadius: 8, elevation: 6, }, modalOverlay: { flex: 1, backgroundColor: 'rgba(0,0,0,0.4)', justifyContent: 'flex-end', }, modalContent: { backgroundColor: '#fff', borderTopLeftRadius: 20, borderTopRightRadius: 20, padding: 24, paddingBottom: 40, }, modalTitle: { fontSize: 18, fontWeight: '700', color: '#1E293B', marginBottom: 16 }, input: { borderWidth: 1, borderColor: '#E2E8F0', borderRadius: 12, padding: 14, fontSize: 16, backgroundColor: '#F8FAFC', }, modalActions: { flexDirection: 'row', justifyContent: 'flex-end', gap: 12, marginTop: 16, }, cancelBtn: { paddingHorizontal: 20, paddingVertical: 10 }, cancelText: { color: '#64748B', fontSize: 15 }, addBtn: { backgroundColor: '#3B82F6', paddingHorizontal: 24, paddingVertical: 10, borderRadius: 10, }, addBtnText: { color: '#fff', fontSize: 15, fontWeight: '600' }, });