191 lines
5.5 KiB
TypeScript
191 lines
5.5 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 { useTranslation } from 'react-i18next';
|
|
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);
|
|
const { t } = useTranslation();
|
|
|
|
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();
|
|
}
|
|
}
|
|
}, []);
|
|
|
|
|
|
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',
|
|
}
|
|
});
|