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] && (
+
+
+ )}
)}
/>
@@ -99,4 +145,4 @@ const DailyView = ({ userID, selectedDate, navigation, isBirthday, userName }) =
);
};
-export default DailyView;
\ No newline at end of file
+export default DailyView;
diff --git a/components/EventEmitter.js b/components/EventEmitter.js
index eaffb90c..dbb8589e 100644
--- a/components/EventEmitter.js
+++ b/components/EventEmitter.js
@@ -17,11 +17,32 @@ class EventEmitter {
const event = this.events[eventName];
if (event) {
event.forEach(fn => {
- fn.call(null, data);
+ try {
+ fn.call(null, data);
+ } catch (error) {
+ console.error(`Error calling event handler for ${eventName}`, error);
+ }
});
}
}
+
+ once(eventName, fn) {
+ const onceWrapper = (data) => {
+ fn(data);
+ this.unsubscribe(eventName, onceWrapper);
+ };
+ this.subscribe(eventName, onceWrapper);
+ }
+
+ unsubscribe(eventName, fn) {
+ if (this.events[eventName]) {
+ this.events[eventName] = this.events[eventName].filter(eventFn => fn !== eventFn);
+ if (this.events[eventName].length === 0) {
+ delete this.events[eventName];
+ }
+ }
+ }
}
const eventEmitter = new EventEmitter();
-export default eventEmitter;
\ No newline at end of file
+export default eventEmitter;
diff --git a/screens/CategoryTasksView.js b/screens/CategoryTasksView.js
index 5ff937fd..474ec6d5 100644
--- a/screens/CategoryTasksView.js
+++ b/screens/CategoryTasksView.js
@@ -28,7 +28,15 @@ const CategoryTasksView = ({ route, navigation }) => {
return () => unsubscribe();
}, [category, userID]);
+ // Set navigation options dynamically
+ useEffect(() => {
+ navigation.setOptions({
+ headerTitle: `${category} Active Tasks`
+ });
+ }, [category, navigation]);
+
return (
+<<<<<<< HEAD
navigation.goBack()}>
@@ -38,6 +46,9 @@ const CategoryTasksView = ({ route, navigation }) => {
+=======
+
+>>>>>>> c19cac2c10a840941d2d298e91960d273d6a61ea
item.id.toString()}
diff --git a/services/AuthAPI.js b/services/AuthAPI.js
index 34768846..12280112 100644
--- a/services/AuthAPI.js
+++ b/services/AuthAPI.js
@@ -17,7 +17,7 @@ import {
deleteDoc,
collection,
} from "firebase/firestore";
-
+import eventEmitter from "../components/EventEmitter";
import { initializeAuth, getReactNativePersistence } from "firebase/auth";
import AsyncStorage from "@react-native-async-storage/async-storage";
@@ -582,4 +582,4 @@ export const cleanUserData = async () => {
};
// Export the AsyncStorage getData function if needed elsewhere
-export { getData };
+export { getData };
\ No newline at end of file