diff --git a/components/ActiveTasks.js b/components/ActiveTasks.js index c0e1a39e..4c19b43e 100644 --- a/components/ActiveTasks.js +++ b/components/ActiveTasks.js @@ -22,62 +22,85 @@ const ActiveTasks = ({ userID }) => { const { theme } = useTheme(); const styles = getStyles(theme); - useEffect(() => { - const fetchAndCountTasks = async () => { - const startDate = startOfMonth(currentMonth); - const endDate = endOfMonth(currentMonth); - // Log to see if and when this function runs - console.log("Fetching tasks for month:", format(currentMonth, 'yyyy-MM')); - console.log("Current month only:", currentMonthOnly); + useEffect(() => { + const fetchAndCountTasks = async () => { + const startDate = startOfMonth(currentMonth); + const endDate = endOfMonth(currentMonth); + // Log to see if and when this function runs + console.log("Fetching tasks for month:", format(currentMonth, "yyyy-MM")); + console.log("Current month only:", currentMonthOnly); - // Fetch tasks for the whole month irrespective of the switch - const tasks = await fetchTasksForUser(userID, startDate.toISOString(), endDate.toISOString()); - const filteredTasks = currentMonthOnly ? tasks.filter(task => - isSameMonth(parseISO(task.date), currentMonth) - ) : tasks; + // Fetch tasks for the whole month irrespective of the switch + const tasks = await fetchTasksForUser( + userID, + startDate.toISOString(), + endDate.toISOString() + ); + const filteredTasks = currentMonthOnly + ? tasks.filter((task) => isSameMonth(parseISO(task.date), currentMonth)) + : tasks; - const updatedCategories = categories.map(category => { - const categoryTasks = filteredTasks.filter(task => task.type === category.label); - return { ...category, count: categoryTasks.length }; - }); - setCategories(updatedCategories); - }; + const updatedCategories = categories.map((category) => { + const categoryTasks = filteredTasks.filter( + (task) => task.type === category.label + ); + return { ...category, count: categoryTasks.length }; + }); + setCategories(updatedCategories); + }; - fetchAndCountTasks(); - // Listen to task updates, month changes, or toggle of currentMonthOnly - const unsubscribeTaskUpdated = eventEmitter.subscribe('taskUpdated', fetchAndCountTasks); - const unsubscribeMonthChange = eventEmitter.subscribe('monthChanged', fetchAndCountTasks); + fetchAndCountTasks(); + // Listen to task updates, month changes, or toggle of currentMonthOnly + const unsubscribeTaskUpdated = eventEmitter.subscribe( + "taskUpdated", + fetchAndCountTasks + ); + const unsubscribeMonthChange = eventEmitter.subscribe( + "monthChanged", + fetchAndCountTasks + ); + const unsubscribeTaskDeleted = eventEmitter.subscribe( + "taskDeleted", + fetchAndCountTasks + ); + const unsubscribeTaskAdded = eventEmitter.subscribe( + "taskAdded", + fetchAndCountTasks + ); - return () => { - unsubscribeTaskUpdated(); - unsubscribeMonthChange(); - }; - }, [userID, currentMonth, currentMonthOnly]); // Include currentMonthOnly in dependencies to trigger re-fetch + return () => { + unsubscribeTaskUpdated(); + unsubscribeMonthChange(); + unsubscribeTaskDeleted(); + unsubscribeTaskAdded(); + }; + }, [userID, currentMonth, currentMonthOnly]); // Include currentMonthOnly in dependencies to trigger re-fetch - return ( - - - Showing: {currentMonthOnly ? "This Month's Tasks" : "All Time Tasks"} - - - {categories.map((category, index) => ( - navigation.navigate('CategoryTasksView', { - category: category.label, - userID: userID, - })} - > - {category.count} - {category.label} - - ))} - - ); + return ( + + + + Showing: {currentMonthOnly ? "This Month's Tasks" : "All Time Tasks"} + + + + {categories.map((category, index) => ( + + navigation.navigate("CategoryTasksView", { + category: category.label, + userID, + }) + } + > + {category.count} + {category.label} + + ))} + + ); }; -export default ActiveTasks; \ No newline at end of file +export default ActiveTasks; diff --git a/components/AddTask.js b/components/AddTask.js index b5de0744..ba607015 100644 --- a/components/AddTask.js +++ b/components/AddTask.js @@ -1,5 +1,12 @@ import React, { useState } from "react"; -import { ScrollView, Alert, Pressable, Text, View, TextInput } from "react-native"; +import { + ScrollView, + Alert, + Pressable, + Text, + View, + TextInput, +} from "react-native"; import Header from "./Header"; import DateTimePicker from "./DateTimePicker"; import TypeSelector from "./TypeSelector"; @@ -42,57 +49,82 @@ const CreateTaskScreen = ({ route }) => { try { await saveTaskForUser(userID, taskData); Alert.alert("Success", "Task created successfully!"); - eventEmitter.emit("taskCreated"); + eventEmitter.emit("taskAdded"); + eventEmitter.emit("taskUpdated"); + eventEmitter.emit("monthChanged"); + eventEmitter.emit("completedTasks"); navigation.goBack(); + + // Clear all input fields after successful task creation + setTaskName(""); + setLocation(""); + setTaskType(""); + setComment(""); + setDate(new Date()); + setPriority("medium"); } catch (error) { - Alert.alert("Error", "There was an error creating your task. Please try again."); + Alert.alert( + "Error", + "There was an error creating your task. Please try again." + ); console.error("Error creating task:", error); } }; return ( - -
navigation.goBack()} /> - - - - - - Priority: - setPriority(itemValue)} - style={styles.priorityPicker} - testID="priority-selector" - > - - - - - - + + + navigation.goBack()}> + + + + Create Task + + + + +
navigation.goBack()} /> + + + + + + Priority: + setPriority(itemValue)} + style={styles.priorityPicker} + testID="priority-selector" + > + + + + + + + ); }; -export default CreateTaskScreen; \ No newline at end of file +export default CreateTaskScreen; diff --git a/components/Calendar.js b/components/Calendar.js index bab65a7e..b4e7a3f6 100644 --- a/components/Calendar.js +++ b/components/Calendar.js @@ -56,7 +56,11 @@ const Calendar = ({ userID, navigation, birthday, userName }) => { try { const start = startOfMonth(currentMonth); const end = endOfMonth(currentMonth); - const tasks = await fetchTasksForUser(userID, start.toISOString(), end.toISOString()); + const tasks = await fetchTasksForUser( + userID, + start.toISOString(), + end.toISOString() + ); setTasks(tasks); // Safeguard: Ensure 'start' and 'end' are Date objects before calling toISOString @@ -92,11 +96,23 @@ const Calendar = ({ userID, navigation, birthday, userName }) => { fetchTasks(); // Subscribe to the taskCreated event - const unsubscribe = eventEmitter.subscribe("taskCreated", fetchTasks); + const unsubscribeTaskAdded = eventEmitter.subscribe( + "taskAdded", + fetchTasks + ); + const unsubscribeTaskDeleted = eventEmitter.subscribe( + "taskDeleted", + fetchTasks + ); + const unsubscribeTaskUpdated = eventEmitter.subscribe( + "taskUpdated", + fetchTasks + ); // Unsubscribe from the event when the component unmounts return () => { - unsubscribe(); + unsubscribeTaskAdded(); + unsubscribeTaskDeleted(); }; }, [currentMonth, userID]); @@ -123,12 +139,12 @@ const Calendar = ({ userID, navigation, birthday, userName }) => { const nextMonth = () => { setCurrentMonth(addMonths(currentMonth, 1)); - eventEmitter.emit('monthChanged'); + eventEmitter.emit("monthChanged"); }; const prevMonth = () => { setCurrentMonth(subMonths(currentMonth, 1)); - eventEmitter.emit('monthChanged'); + eventEmitter.emit("monthChanged"); }; const onDateSelect = (day) => { @@ -190,50 +206,56 @@ const Calendar = ({ userID, navigation, birthday, userName }) => { ); }; -const renderDays = () => { - const startDay = startOfWeek(startOfMonth(currentMonth)); - const endDay = endOfWeek(endOfMonth(currentMonth)); - const daysArray = eachDayOfInterval({ start: startDay, end: endDay }); - - return daysArray.map((day, index) => { - const formattedDate = format(day, "yyyy-MM-dd"); - const dayTasks = tasks.filter(task => format(parseISO(task.date), "yyyy-MM-dd") === formattedDate); - const uniqueTaskTypes = [...new Set(dayTasks.map(task => task.type))]; - - return ( - onDateSelect(day)} - > - { + const startDay = startOfWeek(startOfMonth(currentMonth)); + const endDay = endOfWeek(endOfMonth(currentMonth)); + const daysArray = eachDayOfInterval({ start: startDay, end: endDay }); + + return daysArray.map((day, index) => { + const formattedDate = format(day, "yyyy-MM-dd"); + const dayTasks = tasks.filter( + (task) => format(parseISO(task.date), "yyyy-MM-dd") === formattedDate + ); + const uniqueTaskTypes = [...new Set(dayTasks.map((task) => task.type))]; + + return ( + onDateSelect(day)} > - {format(day, "d")} - - - {uniqueTaskTypes.map((type, typeIndex) => ( - - ))} - - - ); - }); -}; + + {format(day, "d")} + + + {uniqueTaskTypes.map((type, typeIndex) => ( + + ))} + + + ); + }); + }; useEffect(() => { const fetchTasks = async () => { try { @@ -383,4 +405,4 @@ const renderDays = () => { ); }; -export default Calendar; +export default Calendar; \ No newline at end of file diff --git a/components/DailyView.js b/components/DailyView.js index 2e026680..6dc85545 100644 --- a/components/DailyView.js +++ b/components/DailyView.js @@ -6,25 +6,34 @@ import { TouchableOpacity, Alert, StyleSheet, + Button, } from "react-native"; -import { format, parseISO, startOfDay, endOfDay } from "date-fns"; -import { deleteTask, fetchTasksForUser } from "../services/AuthAPI"; +import { format, parseISO, startOfDay, endOfDay, set } from "date-fns"; +import { deleteTask, fetchTasksForUser, updateTaskForUser } from "../services/AuthAPI"; import eventEmitter from "./EventEmitter"; import { useTheme } from "../services/ThemeContext"; import getStyles from "../styles/DailyViewStyles"; import BirthdayCelebration from "./BDCelebration"; -const DailyView = ({ userID, selectedDate, navigation, isBirthday, userName }) => { +const DailyView = ({ + userID, + selectedDate, + navigation, + isBirthday, + userName, +}) => { const [tasks, setTasks] = useState([]); const { theme } = useTheme(); const styles = getStyles(theme); - // Fetch tasks based on the selected date + // State to control the visibility of action buttons for each task + const [visibleTaskActions, setVisibleTaskActions] = useState({}); + const fetchTasks = async () => { try { const allTasks = await fetchTasksForUser(userID); const filteredTasks = allTasks.filter((task) => { - const taskDate = parseISO(task.date); // Convert the date string to a Date object + const taskDate = parseISO(task.date); return ( taskDate >= startOfDay(selectedDate) && taskDate <= endOfDay(selectedDate) @@ -40,58 +49,95 @@ const DailyView = ({ userID, selectedDate, navigation, isBirthday, userName }) = useEffect(() => { fetchTasks(); - // Subscribe to taskUpdated event to refresh tasks list whenever a task is updated - const unsubscribe = eventEmitter.subscribe("taskUpdated", fetchTasks); - - // Return a cleanup function to unsubscribe when the component unmounts - return () => unsubscribe(); - }, [selectedDate, userID]); // Adding userID as a dependency to handle any changes or re-initializations + const unsubscribeTaskUpdated = eventEmitter.subscribe( + "taskUpdated", + fetchTasks + ); + const unsubscribeMonthChange = eventEmitter.subscribe( + "monthChanged", + fetchTasks + ); + const unsubscribeTaskDeleted = eventEmitter.subscribe( + "taskDeleted", + fetchTasks + ); + const unsubscribeTaskAdded = eventEmitter.subscribe( + "taskAdded", + fetchTasks + ); + const unsubscribeCompletedTasks = eventEmitter.subscribe( + "completedTasks", + fetchTasks + ); + return () => { + unsubscribeTaskUpdated(); + unsubscribeMonthChange(); + unsubscribeTaskDeleted(); + unsubscribeTaskAdded(); + unsubscribeCompletedTasks(); + }; + }, [selectedDate, userID]); const onTaskDelete = async (taskId) => { try { await deleteTask(userID, taskId); - fetchTasks(); // Refetch tasks to reflect the deletion + eventEmitter.emit("taskDeleted", taskId); Alert.alert("Success", "Task deleted successfully."); + setVisibleTaskActions(prev => ({ ...prev, [taskId]: false })); // Hide buttons + setTasks(prevTasks => prevTasks.filter(t => t.id !== taskId)); } catch (error) { console.error("Error deleting task: ", error); Alert.alert("Error", "Failed to delete task."); } }; + const toggleCompletion = async (task) => { + const updatedStatus = !task.completed; + try { + await updateTaskForUser(userID, task.id, { completed: updatedStatus }); + eventEmitter.emit('taskUpdated'); + setTasks(prevTasks => + prevTasks.map(t => t.id === task.id ? { ...t, completed: updatedStatus } : t) + ); + } catch (error) { + console.error("Error updating task completion status: ", error); + Alert.alert("Error", "Failed to update task."); + } + }; + return ( Daily Tasks for {format(selectedDate, "PPP")} {isBirthday && ( - - 🎉 Happy Birthday! 🎉 - + 🎉 Happy Birthday! 🎉 )} - + item.id.toString()} renderItem={({ item }) => ( - {item.name} - - navigation.navigate('EditTaskScreen', { task: item, userId: userID })} - > - Edit - - onTaskDelete(item.id)} - > - Delete - - + + {item.name} {item.completed ? "✓" : ""} + + setVisibleTaskActions(prev => ({ + ...prev, + [item.id]: !prev[item.id] // Toggle visibility of action buttons + }))} + > + + + {visibleTaskActions[item.id] && ( + +