taskeep-app/app/(tabs)/index.tsx
2025-07-22 14:04:38 +02:00

206 lines
5.9 KiB
TypeScript

import { Pressable, ScrollView, StyleSheet, View } from 'react-native';
import Ionicons from '@expo/vector-icons/Ionicons';
import { useFocusEffect } from 'expo-router';
import { navigate } from 'expo-router/build/global-state/routing';
import React, { useEffect, useState } from 'react';
import { PermissionsAndroid, Platform } from 'react-native';
import { TaskItem } from '../../components/taskItem';
import { ThemedText } from '../../components/ThemedText';
import { ThemedView } from '../../components/ThemedView';
import { Category, CategoryQuery } from '../../models/category';
import { Task, TaskQuery } from '../../models/task';
import { CategoryRepository } from '../../repositories/CategoryRepository';
import { TaskRepository } from '../../repositories/TaskRepository';
import { SQLiteDataService } from '../../services/data/sqliteDataService';
export const checkApplicationPermission = async () => {
if (Platform.OS === 'android') {
try {
await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS,
);
} catch (error) {
}
}
}
const categoryRepository = new CategoryRepository(new SQLiteDataService<Category>(CategoryQuery));
const taskRepository = new TaskRepository(new SQLiteDataService<Task>(TaskQuery));
export default function HomeScreen() {
const [tasks, setTasks] = useState<Task[]>([]);
const [categories, setCategories] = useState<Category[]>([]);
const [ready, setReady] = useState(false);
useEffect(() => { // Initial data fetch
(async () => {
console.log("Fetching categories...");
try {
const fetchedCategories = await categoryRepository.findAll();
if (fetchedCategories.length === 0) {
// If no categories, create a default one
const defaultCategory = new Category("Uncategorized", "🤷‍♂️");
const createdCat = await categoryRepository.create(defaultCategory);
setCategories([createdCat]);
} else {
setCategories(fetchedCategories);
}
} catch (error) {
console.error("Error fetching categories:", error);
}
try {
console.log("Fetching tasks...");
RefreshTasks();
} catch (error) {
console.error("Error fetching categories or tasks:", error);
}
setReady(true);
})();
}, []);
useEffect(() => { // NOTIFICATION HANDLER
if (Platform.OS !== 'web') {
if (Platform.OS === 'android') {
checkApplicationPermission();
}
}
}, []);
async function schedulePushNotification() {
if (Platform.OS === 'web' || initiated.current) return;
initiated.current = true;
await Notifications.cancelAllScheduledNotificationsAsync();
await Notifications.dismissAllNotificationsAsync();
await Notifications.scheduleNotificationAsync({
content: {
title: `${t("remember_notification_title")} 🌠`,
body: t("remember_notification_body"),
},
trigger: {
hour: 22,
minute: 0,
repeats: true
},
});
}
const RefreshTasks = async () => {
try {
const fetchedTasks = await taskRepository.findAll();
fetchedTasks.sort((a, b) => {
return (a.daysToRedo! * 24 * 3600 * 1000 - (Date.now() - a.lastDone!)) - ((b.daysToRedo! * 24 * 3600 * 1000) - (Date.now() - b.lastDone!));
});
console.log("Tasks fetched:", fetchedTasks);
setTasks(fetchedTasks);
} catch (error) {
console.error("Error refreshing tasks:", error);
}
}
const RefreshCategories = async () => {
try {
const fetchedCategories = await categoryRepository.findAll();
setCategories(fetchedCategories);
} catch (error) {
console.error("Error refreshing categories:", error);
}
}
useEffect(() => {
if (ready) {
(async () => {
await RefreshTasks();
await RefreshCategories();
})();
}
}, [ready]);
//On layout focus to refresh tasks
useFocusEffect(React.useCallback(() => {
console.log("focus");
(async () => {
await RefreshTasks();
await RefreshCategories();
})();
}, []));
return (
<ThemedView style={styles.mainContainer}>
<ThemedView style={styles.headerContainer}>
<ThemedText type="title" style={
{
color: '#fff',
}
}>Taskeep!</ThemedText>
<Pressable onPress={() => {
navigate('./taskForm', {})
}}>
<Ionicons name='add-circle-sharp' size={32} color="#fff" />
</Pressable>
</ThemedView>
<ThemedText style={{ padding: 24 }} type="subtitle">Your Tasks</ThemedText>
<ScrollView style={styles.scrollView}>
{tasks.map((task, index) => (
<TaskItem categories={categories} key={Date.now() + "-" + task.id} task={task} onUpdate={() => {
RefreshTasks();
}} />
))}
{tasks.length === 0 && (<>
<ThemedText type="defaultSemiBold" style={{ textAlign: 'center', marginTop: 20 }}>
No tasks available.
</ThemedText>
<ThemedText type="default" style={{ textAlign: 'center', marginTop: 20 }}>
Add a task to get started!
</ThemedText>
</>)}
<View style={{ height: 50 }} />
</ScrollView>
</ThemedView>
);
}
const styles = StyleSheet.create({
mainContainer: {
flex: 1,
},
headerContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
gap: 8,
paddingHorizontal: 24,
paddingTop: 50,
paddingBottom: 18,
backgroundColor: '#6a254fff',
},
scrollView: {
paddingHorizontal: 24,
flex: 1,
},
stepContainer: {
gap: 8,
marginBottom: 8,
},
reactLogo: {
height: 178,
width: 290,
bottom: 0,
left: 0,
position: 'absolute',
},
addButton: {
backgroundColor: '#b91f7eff',
height: 50,
color: '#fff',
borderRadius: 8,
padding: 10,
lineHeight: 30,
alignItems: 'center',
justifyContent: 'center',
}
});