diff --git a/components/ActiveTasks.js b/components/ActiveTasks.js
index a0162f10..104a408e 100644
--- a/components/ActiveTasks.js
+++ b/components/ActiveTasks.js
@@ -1,77 +1,108 @@
-import React, { useState, useEffect } from 'react';
-import { View, Text, TouchableOpacity, Switch } from 'react-native';
-import { useNavigation } from '@react-navigation/native';
-import { format, startOfMonth, endOfMonth, parseISO, isSameMonth } from 'date-fns';
-import styles from '../styles/ActiveTasksStyle';
-import { fetchTasksForUser } from '../services/AuthAPI';
-import eventEmitter from '../components/EventEmitter';
-import { useCurrentMonth } from './CurrentMonthContext';
-
+import React, { useState, useEffect } from "react";
+import { View, Text, TouchableOpacity, Switch } from "react-native";
+import { useNavigation } from "@react-navigation/native";
+import {
+ format,
+ startOfMonth,
+ endOfMonth,
+ parseISO,
+ isSameMonth,
+} from "date-fns";
+import styles from "../styles/ActiveTasksStyle";
+import { fetchTasksForUser } from "../services/AuthAPI";
+import eventEmitter from "../components/EventEmitter";
+import { useCurrentMonth } from "./CurrentMonthContext";
const ActiveTasks = ({ userID }) => {
- const navigation = useNavigation();
- const { currentMonth } = useCurrentMonth();
- const [categories, setCategories] = useState([
- { label: 'School', color: '#FFA07A' },
- { label: 'Work', color: '#20B2AA' },
- { label: 'Personal', color: '#778899' },
- { label: 'Gym', color: '#FFD700' },
- ]);
- const [currentMonthOnly, setCurrentMonthOnly] = useState(false);
+ const navigation = useNavigation();
+ const { currentMonth } = useCurrentMonth();
+ const [categories, setCategories] = useState([
+ { label: "School", color: "#FFA07A" },
+ { label: "Work", color: "#20B2AA" },
+ { label: "Personal", color: "#778899" },
+ { label: "Gym", color: "#FFD700" },
+ ]);
+ const [currentMonthOnly, setCurrentMonthOnly] = useState(false);
- 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 })}
- >
- {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 51b8ea5e..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 {
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;