import os import pandas as pd from datetime import datetime import streamlit as st import uuid # For generating unique IDs import shutil # To create a backup of the file class TaskManager: TASKS_FILE = "tasks.csv" BACKUP_FILE = "tasks_backup.csv" CATEGORIES = ['Learning', 'Gym', 'Personal', 'Family', 'Work', 'Prayer'] def __init__(self): if 'tasks' not in st.session_state: st.session_state.tasks = self.load_tasks() def backup_csv(self): """Create a backup of the current tasks file.""" if os.path.exists(self.TASKS_FILE): shutil.copy(self.TASKS_FILE, self.BACKUP_FILE) def restore_from_backup(self): """Restore tasks from backup if needed.""" if os.path.exists(self.BACKUP_FILE): shutil.copy(self.BACKUP_FILE, self.TASKS_FILE) def load_tasks(self): # Check if the file exists and has data if os.path.exists(self.TASKS_FILE) and os.path.getsize(self.TASKS_FILE) > 0: try: return pd.read_csv(self.TASKS_FILE, parse_dates=['Task Time']).to_dict(orient='records') except pd.errors.EmptyDataError: return [] # Return empty list if CSV is empty else: # If file doesn't exist, initialize it with an empty DataFrame and correct columns df = pd.DataFrame(columns=["Task ID", "Task Name", "Task Time", "Task Duration (hours)", "Task Duration (minutes)", "Category"]) df.to_csv(self.TASKS_FILE, index=False) return [] # Return an empty list to the session state def save_tasks(self, tasks): """Save tasks to the CSV file after making a backup.""" if tasks: # Only save if tasks are not empty # Backup the current file before saving self.backup_csv() df = pd.DataFrame(tasks) df.to_csv(self.TASKS_FILE, index=False) else: # Prevent overwriting the file with an empty DataFrame st.warning("No tasks to save. File write skipped to prevent data loss.") def add_task(self, task_name, task_time, task_duration_hours, task_duration_minutes, task_category): # Ensure valid task details are being added if task_name and task_category: task_time_full = datetime.combine(datetime.today(), task_time) task_id = str(uuid.uuid4()) # Generate a unique ID using uuid4 task_entry = { "Task ID": task_id, "Task Name": task_name, "Task Time": task_time_full, "Task Duration (hours)": int(task_duration_hours), "Task Duration (minutes)": int(task_duration_minutes), "Category": task_category } st.session_state.tasks.append(task_entry) self.save_tasks(st.session_state.tasks) st.success(f"Task '{task_name}' added successfully!") # Reload tasks to ensure consistency st.session_state.tasks = self.load_tasks() else: st.error("Task name and category are required.") def delete_task_by_id(self, task_id): task_found = False for index, task in enumerate(st.session_state.tasks): if task['Task ID'] == task_id: st.session_state.tasks.pop(index) task_found = True break if task_found: self.save_tasks(st.session_state.tasks) st.success(f"Task with ID '{task_id}' deleted.") # Reload tasks to ensure consistency st.session_state.tasks = self.load_tasks() else: st.error(f"Task with ID '{task_id}' not found.") def generate_report(self, timeframe): df = pd.DataFrame(st.session_state.tasks) if df.empty: return pd.DataFrame() # Return empty DataFrame if no tasks are present # Ensure the 'Task Time' is in datetime format df['Task Time'] = pd.to_datetime(df['Task Time']) if timeframe == 'daily': report = df[df['Task Time'].dt.date == pd.Timestamp.today().date()] elif timeframe == 'weekly': week_start = pd.Timestamp.today() - pd.DateOffset(days=pd.Timestamp.today().dayofweek) report = df[(df['Task Time'] >= week_start) & (df['Task Time'] < pd.Timestamp.today() + pd.DateOffset(days=1))] elif timeframe == 'monthly': report = df[df['Task Time'].dt.month == pd.Timestamp.today().month] elif timeframe == 'yearly': report = df[df['Task Time'].dt.year == pd.Timestamp.today().year] else: report = pd.DataFrame() # Empty DataFrame for unsupported timeframes report['Total Duration'] = report['Task Duration (hours)'] + report['Task Duration (minutes)'] / 60.0 return report