Repository: Learnathon-By-Geeky-Solutions/brainstormers
Pull request #58: Feature/task dashboard
Author: login: Enamulhasan85
Created: 2025-04-11T11:45:22Z | Merged: 2025-04-11T12:21:29Z



Diff:
diff --git a/.gitignore b/.gitignore
index 35137722..8f1ea1d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,3 +88,6 @@ packages/
 *.pubxml
 *.pubxml.user
 
+# Ignore media files 
+**/uploads
+
diff --git a/TaskForge.NET/TaskForge.Application/DTOs/ProjectMemberDto.cs b/TaskForge.NET/TaskForge.Application/DTOs/ProjectMemberDto.cs
index d8fbfe97..c134b401 100644
--- a/TaskForge.NET/TaskForge.Application/DTOs/ProjectMemberDto.cs
+++ b/TaskForge.NET/TaskForge.Application/DTOs/ProjectMemberDto.cs
@@ -10,6 +10,8 @@ namespace TaskForge.Application.DTOs
     public class ProjectMemberDto
     {
         public int Id { get; set; }
+        public int ProjectId { get; set; }
+        public int UserProfileId { get; set; }
         public string? Name { get; set; }
         public string? Email { get; set; }
         public ProjectRole Role { get; set; }
diff --git a/TaskForge.NET/TaskForge.Application/DTOs/TaskDto.cs b/TaskForge.NET/TaskForge.Application/DTOs/TaskDto.cs
index 8b88f8bb..c18daf3a 100644
--- a/TaskForge.NET/TaskForge.Application/DTOs/TaskDto.cs
+++ b/TaskForge.NET/TaskForge.Application/DTOs/TaskDto.cs
@@ -7,6 +7,7 @@ public class TaskDto
     {
         public int Id { get; set; }
         public int ProjectId { get; set; }
+        public string ProjectTitle { get; set; } = string.Empty;
         public string Title { get; set; } = string.Empty;
         public string? Description { get; set; }
         public DateTime? StartDate { get; set; }
diff --git a/TaskForge.NET/TaskForge.Application/DTOs/TaskUpdateDto.cs b/TaskForge.NET/TaskForge.Application/DTOs/TaskUpdateDto.cs
new file mode 100644
index 00000000..a552ba02
--- /dev/null
+++ b/TaskForge.NET/TaskForge.Application/DTOs/TaskUpdateDto.cs
@@ -0,0 +1,17 @@
+﻿using Microsoft.AspNetCore.Http;
+
+namespace TaskForge.Application.DTOs
+{
+	public class TaskUpdateDto
+	{
+		public int Id { get; set; }
+		public string Title { get; set; }
+		public string? Description { get; set; }
+		public int Status { get; set; }
+		public int Priority { get; set; }
+		public DateTime? StartDate { get; set; }
+		public DateTime? DueDate { get; set; }
+		public List<int>? AssignedUserIds { get; set; }
+		public List<IFormFile>? Attachments { get; set; }
+	}
+}
diff --git a/TaskForge.NET/TaskForge.Application/Interfaces/Services/ITaskService.cs b/TaskForge.NET/TaskForge.Application/Interfaces/Services/ITaskService.cs
index 20af240c..9e52fe7d 100644
--- a/TaskForge.NET/TaskForge.Application/Interfaces/Services/ITaskService.cs
+++ b/TaskForge.NET/TaskForge.Application/Interfaces/Services/ITaskService.cs
@@ -12,8 +12,11 @@ namespace TaskForge.Application.Interfaces.Services
 {
     public interface ITaskService
     {
-        Task<IEnumerable<TaskItem>> GetTaskListAsync(int projectId);
-        Task CreateTaskAsync(TaskDto taskDto);
+		Task<IEnumerable<TaskItem>> GetTaskListAsync(int projectId);
+		Task<TaskItem?> GetTaskByIdAsync(int id);
+		Task CreateTaskAsync(TaskDto taskDto);
 		Task<PaginatedList<TaskDto>> GetUserTaskAsync(int? userProfileId, int pageIndex, int pageSize);
+
+		Task UpdateTaskAsync(TaskUpdateDto dto);
 	}
 }
diff --git a/TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs b/TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs
index 6d7038ff..1e074a69 100644
--- a/TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs
+++ b/TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs
@@ -3,12 +3,13 @@
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using TaskForge.Domain.Entities;
 
 namespace TaskForge.Application.Interfaces.Services
 {
     public interface IUserProfileService
     {
         Task<int?> GetByUserIdAsync(string userId);
-        Task CreateUserProfileAsync(string userId, string FullName);
+		Task CreateUserProfileAsync(string userId, string fullName);
     }
 }
diff --git a/TaskForge.NET/TaskForge.Application/Services/ProjectMemberService.cs b/TaskForge.NET/TaskForge.Application/Services/ProjectMemberService.cs
index ca98b2fe..0074296e 100644
--- a/TaskForge.NET/TaskForge.Application/Services/ProjectMemberService.cs
+++ b/TaskForge.NET/TaskForge.Application/Services/ProjectMemberService.cs
@@ -65,6 +65,8 @@ public async Task<List<ProjectMemberDto>> GetProjectMembersAsync(int projectId)
             return projectMembers.Select(pm => new ProjectMemberDto
             {
                 Id = pm.Id,
+                ProjectId = pm.ProjectId,
+                UserProfileId = pm.UserProfileId,
                 Name = pm.UserProfile.FullName ?? "Unknown User",
                 Email = pm.UserProfile.User?.UserName ?? "No Email",
                 Role = pm.Role
diff --git a/TaskForge.NET/TaskForge.Application/Services/TaskService.cs b/TaskForge.NET/TaskForge.Application/Services/TaskService.cs
index d0cc79d7..6349982e 100644
--- a/TaskForge.NET/TaskForge.Application/Services/TaskService.cs
+++ b/TaskForge.NET/TaskForge.Application/Services/TaskService.cs
@@ -31,12 +31,27 @@ public TaskService(IUnitOfWork unitOfWork)
         public async Task<IEnumerable<TaskItem>> GetTaskListAsync(int projectId)
         {
             return await _unitOfWork.Tasks.FindByExpressionAsync(
-                t => t.ProjectId == projectId,  // Filtering by ProjectId
-                orderBy: q => q.OrderBy(t => t.DueDate) // Example sorting
+                predicate: t => t.ProjectId == projectId, 
+				includes: t => t.Include(t => t.AssignedUsers).ThenInclude(au => au.UserProfile),
+                orderBy: q => q.OrderBy(t => t.DueDate)
 			);
         }
 
-        public async Task CreateTaskAsync(TaskDto taskDto)
+		public async Task<TaskItem?> GetTaskByIdAsync(int taskId)
+		{
+			Expression<Func<TaskItem, bool>> predicate = t => t.Id == taskId;
+
+			Func<IQueryable<TaskItem>, IQueryable<TaskItem>> includes = query =>
+				query.Include(t => t.Attachments)
+					 .Include(t => t.AssignedUsers).ThenInclude(au => au.UserProfile)
+					 .Include(t => t.Project);
+
+			var result = await _unitOfWork.Tasks.FindByExpressionAsync(predicate, includes: includes);
+
+			return result.FirstOrDefault();
+		}
+
+		public async Task CreateTaskAsync(TaskDto taskDto)
         {
             var taskItem = new TaskItem
             {
@@ -95,7 +110,7 @@ public async Task<PaginatedList<TaskDto>> GetUserTaskAsync(int? userProfileId, i
 			var (taskList, totalCount) = await _unitOfWork.Tasks.GetPaginatedListAsync(
 				predicate: _predicate,
                 orderBy: _orderBy,
-                includes: null,
+                includes: query => query.Include(t => t.Project),
 				skip: (pageIndex - 1) * pageSize,
 				take: pageSize
 			 );
@@ -106,6 +121,7 @@ public async Task<PaginatedList<TaskDto>> GetUserTaskAsync(int? userProfileId, i
                 Id = t.Id,
                 Title = t.Title,
                 ProjectId = t.ProjectId,
+				ProjectTitle = t.Project.Title,
                 DueDate = t.DueDate,
                 Status = t.Status,
                 Priority = t.Priority
@@ -113,5 +129,77 @@ public async Task<PaginatedList<TaskDto>> GetUserTaskAsync(int? userProfileId, i
 
 			return new PaginatedList<TaskDto>(taskListDto, totalCount, pageIndex, pageSize);
 		}
-    }
+
+		public async Task UpdateTaskAsync(TaskUpdateDto dto)
+		{
+			// Step 1: Retrieve the task with its related data (e.g., AssignedUsers, Attachments, etc.)
+			var taskList = await _unitOfWork.Tasks.FindByExpressionAsync(
+				t => t.Id == dto.Id && !t.IsDeleted,
+				includes: query => query
+					.Include(t => t.Attachments)  // Include Attachments
+					.Include(t => t.AssignedUsers) // Include AssignedUsers
+					.ThenInclude(au => au.UserProfile) // Include user profile for Assigned Users
+			);
+			var task = taskList.FirstOrDefault();
+
+			if (task == null)
+				throw new Exception("Task not found.");
+
+			// Step 2: Update task fields from the provided DTO
+			task.Title = dto.Title;
+			task.Description = dto.Description;
+			task.Status = (TaskWorkflowStatus)dto.Status;
+			task.Priority = (TaskPriority)dto.Priority;
+			task.StartDate = dto.StartDate;
+			task.SetDueDate(dto.DueDate);
+
+			// Step 3: Update assigned members if any
+			task.AssignedUsers.Clear();  // Clear existing assigned users
+			if (dto.AssignedUserIds != null && dto.AssignedUserIds.Any())
+			{
+				var users = await _unitOfWork.UserProfiles.FindByExpressionAsync(u => dto.AssignedUserIds.Contains(u.Id));
+				foreach (var user in users)
+				{
+					task.AssignedUsers.Add(new TaskAssignment { UserProfile = user });
+				}
+			}
+
+
+			// Step 4: Handle attachments (if any)
+			if (dto.Attachments != null && dto.Attachments.Any())
+			{
+				foreach (var file in dto.Attachments)
+				{
+					if (file.Length > 0)
+					{
+						var uploadsFolder = Path.Combine("wwwroot", "uploads", "tasks");
+						Directory.CreateDirectory(uploadsFolder);
+
+						var fileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName);
+						var filePath = Path.Combine(uploadsFolder, fileName);
+
+						using (var stream = new FileStream(filePath, FileMode.Create))
+						{
+							await file.CopyToAsync(stream);
+						}
+
+						task.Attachments.Add(new TaskAttachment
+						{
+							FileName = file.FileName,
+							FilePath = Path.Combine("uploads", "tasks", fileName).Replace("\\", "/"),
+							ContentType = file.ContentType
+						});
+					}
+				}
+			}
+
+			// Step 5: Update the task in the repository
+			await _unitOfWork.Tasks.UpdateAsync(task);
+
+			// Step 6: Commit changes
+			await _unitOfWork.SaveChangesAsync();
+		}
+
+
+	}
 }
diff --git a/TaskForge.NET/TaskForge.Application/Services/UserProfileService.cs b/TaskForge.NET/TaskForge.Application/Services/UserProfileService.cs
index 55f56530..49a1fb62 100644
--- a/TaskForge.NET/TaskForge.Application/Services/UserProfileService.cs
+++ b/TaskForge.NET/TaskForge.Application/Services/UserProfileService.cs
@@ -1,10 +1,4 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using TaskForge.Application.Interfaces.Repositories;
-using TaskForge.Application.Interfaces.Repositories.Common;
+﻿using TaskForge.Application.Interfaces.Repositories.Common;
 using TaskForge.Application.Interfaces.Services;
 using TaskForge.Domain.Entities;
 
@@ -19,12 +13,12 @@ public UserProfileService(IUnitOfWork unitOfWork)
         }
 
 
-        public async Task CreateUserProfileAsync(string userId, string FullName)
+        public async Task CreateUserProfileAsync(string userId, string fullName)
         {
             var userProfile = new UserProfile
             {
                 UserId = userId,
-                FullName = FullName
+                FullName = fullName
             };
             await _unitOfWork.UserProfiles.AddAsync(userProfile);
             await _unitOfWork.SaveChangesAsync();
diff --git a/TaskForge.NET/TaskForge.Domain/Entities/TaskItem.cs b/TaskForge.NET/TaskForge.Domain/Entities/TaskItem.cs
index 6d385388..f45c27bf 100644
--- a/TaskForge.NET/TaskForge.Domain/Entities/TaskItem.cs
+++ b/TaskForge.NET/TaskForge.Domain/Entities/TaskItem.cs
@@ -29,16 +29,16 @@ public class TaskItem : BaseEntity
 
         public virtual ICollection<TaskAssignment> AssignedUsers { get; set; } = new List<TaskAssignment>();
 
-        public void SetDueDate(DateTime? dueDate)
-        {
-            if (dueDate.HasValue && StartDate.HasValue && dueDate < StartDate)
-            {
-                throw new ArgumentException("Due date cannot be earlier than the Start date.");
-            }
-            DueDate = dueDate;
-        }
+		public void SetDueDate(DateTime? dueDate)
+		{
+			if (dueDate.HasValue && StartDate.HasValue && dueDate < StartDate)
+				throw new ValidationException("Due date cannot be earlier than Start date.");
+
+			DueDate = dueDate;
+		}
+
 
-        public void SetStatus(TaskWorkflowStatus newStatus)
+		public void SetStatus(TaskWorkflowStatus newStatus)
         {
             if (newStatus == TaskWorkflowStatus.InProgress && StartDate == null)
             {
diff --git a/TaskForge.NET/TaskForge.WebUI/Controllers/HomeController.cs b/TaskForge.NET/TaskForge.WebUI/Controllers/HomeController.cs
index 437bb6b0..689d27a1 100644
--- a/TaskForge.NET/TaskForge.WebUI/Controllers/HomeController.cs
+++ b/TaskForge.NET/TaskForge.WebUI/Controllers/HomeController.cs
@@ -50,7 +50,8 @@ public async Task<IActionResult> Index(int pageIndex = 1, int pageSize = 10)
 
 			var taskList = new HomeViewModel
 			{
-				TotalTasks = userTaskList.TotalCount,
+                TotalProjects = totalProjects,
+                TotalTasks = userTaskList.TotalCount,
 				CompletedTasks = userTaskList.Items.Count(task => task.Status == Domain.Enums.TaskWorkflowStatus.Done),
 
 				UserTasks = userTaskList.Items,
diff --git a/TaskForge.NET/TaskForge.WebUI/Controllers/ProjectController.cs b/TaskForge.NET/TaskForge.WebUI/Controllers/ProjectController.cs
index a07bc8f4..c24d5118 100644
--- a/TaskForge.NET/TaskForge.WebUI/Controllers/ProjectController.cs
+++ b/TaskForge.NET/TaskForge.WebUI/Controllers/ProjectController.cs
@@ -269,7 +269,15 @@ public async Task<IActionResult> Dashboard(int id)
                     Status = t.Status,
                     Priority = t.Priority,
                     StartDate = t.StartDate,
-                    DueDate = t.DueDate
+                    DueDate = t.DueDate,
+                    AssignedUsers = t.AssignedUsers.Select(a => new TaskAssignmentViewModel
+                    {
+                        UserProfileId = a.UserProfileId,
+                        FullName = a.UserProfile.FullName ?? "",
+                        UserName = a.UserProfile.User.UserName ?? "",
+                        Email = a.UserProfile.User.Email ?? "",
+                        AvatarUrl = a.UserProfile.AvatarUrl
+                    }).ToList()
                 }).ToList(),
                 UpdateViewModel = new ProjectUpdateViewModel
                 {
diff --git a/TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs b/TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs
index db939973..0fce24a8 100644
--- a/TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs
+++ b/TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs
@@ -3,6 +3,7 @@
 using Microsoft.AspNetCore.Mvc;
 using TaskForge.Application.DTOs;
 using TaskForge.Application.Interfaces.Services;
+using TaskForge.Application.Services;
 using TaskForge.WebUI.Models;
 
 namespace TaskForge.WebUI.Controllers
@@ -11,14 +12,17 @@ namespace TaskForge.WebUI.Controllers
     public class TaskController : Controller
     {
         private readonly ITaskService _taskService;
-        private readonly UserManager<IdentityUser> _userManager;
+        private readonly IProjectMemberService _projectMemberService;
+		private readonly UserManager<IdentityUser> _userManager;
 
-        public TaskController(ITaskService taskService, UserManager<IdentityUser> userManager)
+        public TaskController(ITaskService taskService, IProjectMemberService projectMemberService, UserManager<IdentityUser> userManager)
         {
             _taskService = taskService;
-            _userManager = userManager;
+			_projectMemberService = projectMemberService;
+			_userManager = userManager;
         }
 
+
         [HttpPost]
         public async Task<IActionResult> Create([FromForm] TaskItemCreateViewModel model)
         {
@@ -27,7 +31,7 @@ public async Task<IActionResult> Create([FromForm] TaskItemCreateViewModel model
                 return BadRequest(ModelState);
             }
 
-	    var taskDto = new TaskDto
+			var taskDto = new TaskDto
             {
                 ProjectId = model.ProjectId,
                 Title = model.Title,
@@ -42,6 +46,68 @@ public async Task<IActionResult> Create([FromForm] TaskItemCreateViewModel model
 
             return Ok(new { success = true });
         }
-    }
+
+
+		[HttpGet("Tasks/GetTaskById/{id}")]
+		public async Task<IActionResult> GetTaskDetailsById(int id)
+		{
+			var task = await _taskService.GetTaskByIdAsync(id);
+			if (task == null) return NotFound();
+
+			return Ok(new
+			{
+				task.Id,
+				task.Title,
+				task.Description,
+				StartDate = task.StartDate?.ToString("g"),
+				DueDate = task.DueDate?.ToString("g"),
+				Status = task.Status.ToString(),
+				Priority = task.Priority.ToString(),
+				AssignedUsers = task.AssignedUsers.Select(a => new { a.UserProfile.FullName }),
+				Attachments = task.Attachments.Select(a => new { a.FileName, a.FilePath })
+			});
+		}
+
+
+		[HttpGet]
+		public async Task<IActionResult> GetTask(int id)
+		{
+			var task = await _taskService.GetTaskByIdAsync(id);
+			if (task == null) return NotFound();
+
+			var allUsers = await _projectMemberService.GetProjectMembersAsync(task.ProjectId);
+			return Json(new
+			{
+				id = task.Id,
+				title = task.Title,
+				description = task.Description,
+				startDate = task.StartDate?.ToString("yyyy-MM-ddTHH:mm"),
+				dueDate = task.DueDate?.ToString("yyyy-MM-ddTHH:mm"),
+				status = (int)task.Status,
+				priority = (int)task.Priority,
+				attachments = task.Attachments.Select(a => new
+				{
+					id = a.Id,
+					fileName = a.FileName,
+					downloadUrl = Url.Action("Download", "Attachment", new { id = a.Id })
+				}),
+				assignedUserIds = task.AssignedUsers.Select(u => u.UserProfileId),
+				allUsers = allUsers.Select(u => new { id = u.UserProfileId, name = u.Name })
+			});
+		}
+
+
+		[HttpPost]
+		public async Task<IActionResult> UpdateTask(TaskUpdateDto dto)
+		{
+			if (!ModelState.IsValid)
+				return BadRequest(ModelState);
+
+			await _taskService.UpdateTaskAsync(dto);
+
+			return Ok();
+		}
+
+	}
 }
 
diff --git a/TaskForge.NET/TaskForge.WebUI/Models/TaskItemViewModel.cs b/TaskForge.NET/TaskForge.WebUI/Models/TaskItemViewModel.cs
index 9238df7b..4d837b13 100644
--- a/TaskForge.NET/TaskForge.WebUI/Models/TaskItemViewModel.cs
+++ b/TaskForge.NET/TaskForge.WebUI/Models/TaskItemViewModel.cs
@@ -12,8 +12,8 @@ public class TaskItemCreateViewModel
         public TaskWorkflowStatus Status { get; set; }
         public TaskPriority Priority { get; set; }
 
-		public List<IFormFile> Attachments { get; set; } = new();
-	}
+        public List<IFormFile> Attachments { get; set; } = new();
+    }
 
     public class TaskItemUpdateViewModel
     {
@@ -33,5 +33,20 @@ public class TaskItemViewModel
         public DateTime? DueDate { get; set; }
         public TaskWorkflowStatus Status { get; set; }
         public TaskPriority Priority { get; set; }
-	}
+
+        public List<TaskAssignmentViewModel> AssignedUsers { get; set; } = new List<TaskAssignmentViewModel>();
+
+    }
+
+    public class TaskAssignmentViewModel
+    {
+        public int UserProfileId { get; set; }
+        public string FullName { get; set; } = string.Empty;
+        public string UserName { get; set; } = string.Empty;
+        public string Email { get; set; } = string.Empty;
+        public string? AvatarUrl { get; set; }
+
+    }
+
+
 }
\ No newline at end of file
diff --git a/TaskForge.NET/TaskForge.WebUI/Views/Home/Index.cshtml b/TaskForge.NET/TaskForge.WebUI/Views/Home/Index.cshtml
index 141d94bc..a3895058 100644
--- a/TaskForge.NET/TaskForge.WebUI/Views/Home/Index.cshtml
+++ b/TaskForge.NET/TaskForge.WebUI/Views/Home/Index.cshtml
@@ -45,7 +45,7 @@
                 <th>Status</th>
                 <th>Priority</th>
                 <th>Due Date</th>
-                <th>Project</th>
+                <th>Project Title</th>
             </tr>
         </thead>
         <tbody>
@@ -61,7 +61,7 @@
                         <td>@task.Status</td>
                         <td>@task.Priority</td>
                         <td>@(task.DueDate?.ToString("yyyy-MM-dd") ?? "----")</td>
-                        <td>@task.ProjectId</td>
+                        <td>@task.ProjectTitle</td>
                     </tr>
                 }
             }
diff --git a/TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml b/TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml
index 706411d3..0e0e2b36 100644
--- a/TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml
+++ b/TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml
@@ -97,15 +97,15 @@
 <!-- Main Section -->
 <div class="">
 	<!-- Bootstrap Tabs -->
-    <ul class="nav nav-tabs" id="dashboardTabs" role="tablist">
+    <ul class="nav nav-tabs" id="dashboardTabs">
 	    <!-- Summary Tab -->
-	    <li class="nav-item" role="presentation">
+	    <li class="nav-item">
 		    <button class="nav-link" id="summary-tab" data-bs-toggle="tab" data-bs-target="#summary" type="button" role="tab" aria-controls="summary" aria-selected="true">
 			    <i class="bi bi-bar-chart-fill"></i> Summary
 		    </button>
 	    </li>
 	    <!-- Tasks Tab -->
-	    <li class="nav-item" role="presentation">
+	    <li class="nav-item">
 		    <button class="nav-link" id="tasks-tab" data-bs-toggle="tab" data-bs-target="#tasks" type="button" role="tab" aria-controls="tasks" aria-selected="false">
 			    <i class="bi bi-list-task"></i> Tasks
 		    </button>
@@ -201,11 +201,9 @@
                 <div class="col-12">
                     <div class="card shadow-sm border">
                         <div class="card-body">
-                            @* <h5 class="card-title"><i class="bi bi-clipboard-check text-primary"></i> Project Tasks</h5> *@
-
 							<div class="d-flex justify-content-between bg-light p-2 mb-3">
 	                            <!-- Custom Styles for Nav Pills -->
-	                            <style>
+								<style>
 									.nav-pills .nav-link {
 										transition: background-color 0.3s, color 0.3s;
 									}
@@ -225,58 +223,145 @@
 									}
 								</style>
 	                            
-	                            <!-- Nav Tabs -->
-	                            <ul class="nav nav-pills" id="taskTabs">
-		                            <li class="nav-item me-1">
-			                            <a class="nav-link " id="todo-tab" data-bs-toggle="pill" href="#todo">
-				                            <i class="bi bi-check-circle"></i> To Do
-			                            </a>
-		                            </li>
-		                            <li class="nav-item me-1">
-			                            <a class="nav-link" id="inprogress-tab" data-bs-toggle="pill" href="#inprogress">
-				                            <i class="bi bi-hourglass-split"></i> In Progress
-			                            </a>
-		                            </li>
-		                            <li class="nav-item me-1">
-			                            <a class="nav-link" id="completed-tab" data-bs-toggle="pill" href="#completed">
-				                            <i class="bi bi-check2-circle"></i> Completed
-			                            </a>
-		                            </li>
-		                            <li class="nav-item me-1">
-			                            <a class="nav-link" id="blocked-tab" data-bs-toggle="pill" href="#blocked">
-				                            <i class="bi bi-slash-circle"></i> Blocked
-			                            </a>
-		                            </li>
-	                            </ul>
+								<!-- Nav Tabs -->
+								<ul class="nav nav-pills" id="taskTabs">
+									<li class="nav-item me-1">
+										<a class="nav-link " id="todo-tab" data-bs-toggle="pill" href="#todo">
+											<i class="bi bi-slash-circle"></i> To Do
+										</a>
+									</li>
+									<li class="nav-item me-1">
+										<a class="nav-link" id="inprogress-tab" data-bs-toggle="pill" href="#inprogress">
+											<i class="bi bi-hourglass-split"></i> In Progress
+										</a>
+									</li>
+									<li class="nav-item me-1">
+										<a class="nav-link" id="completed-tab" data-bs-toggle="pill" href="#completed">
+											<i class="bi bi-check2-circle"></i> Completed
+										</a>
+									</li>
+									<li class="nav-item me-1">
+										<a class="nav-link" id="blocked-tab" data-bs-toggle="pill" href="#blocked">
+											<i class="bi bi-exclamation-circle"></i> Blocked
+										</a>
+									</li>
+								</ul>
                                 
-	                            @if (Model.UserRoleInThisProject == ProjectRole.Admin || Model.UserRoleInThisProject == ProjectRole.Contributor)
-	                            {
-		                            <!-- Add Task Button -->
-		                            <button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#addTaskModal">
-			                            <i class="bi bi-plus-circle"></i> Add New Task
-		                            </button>
-
-		                            <!-- Modal for Adding Task -->
-		                            <div class="modal fade" id="addTaskModal" tabindex="-1" aria-labelledby="addTaskModalLabel" aria-hidden="true">
-			                            <div class="modal-dialog modal-lg">
-				                            <div class="modal-content">
-					                            <div class="modal-header">
-						                            <h5 class="modal-title" id="addTaskModalLabel">Add New Task</h5>
-						                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
-					                            </div>
-					                            <div class="modal-body">
-						                            <!-- Render the Partial View for Task Form -->
-						                            @await Html.PartialAsync("~/Views/Task/PartialViews/_AddTaskForm.cshtml", new TaskItemViewModel
-						                            {
-							                            ProjectId = Model.ProjectId
-						                            })
-					                            </div>
-				                            </div>
-			                            </div>
-		                            </div>
-	                            }
+								@if (Model.UserRoleInThisProject == ProjectRole.Admin || Model.UserRoleInThisProject == ProjectRole.Contributor)
+								{
+									<!-- Add Task Button -->
+									<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#addTaskModal">
+										<i class="bi bi-plus-circle"></i> Add New Task
+									</button>
+
+									<!-- Modal for Adding Task -->
+									<div class="modal fade" id="addTaskModal" tabindex="-1" aria-labelledby="addTaskModalLabel" aria-hidden="true">
+										<div class="modal-dialog modal-lg">
+											<div class="modal-content">
+												<div class="modal-header">
+													<h5 class="modal-title" id="addTaskModalLabel">Add New Task</h5>
+													<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+												</div>
+												<div class="modal-body">
+													<!-- Render the Partial View for Task Form -->
+													@await Html.PartialAsync("~/Views/Task/PartialViews/_AddTaskForm.cshtml", new TaskItemViewModel
+													{
+														ProjectId = Model.ProjectId
+													})
+												</div>
+											</div>
+										</div>
+									</div>
+								}
                             </div>
 
+
+							<!-- Task Details Modal -->
+							<div class="modal fade" id="taskDetailsModal" tabindex="-1" aria-labelledby="taskDetailsModalLabel" aria-hidden="true">
+							  <div class="modal-dialog modal-xl modal-dialog-scrollable">
+								<div class="modal-content">
+								  <div class="modal-header">
+									<h5 class="modal-title" id="taskDetailsModalLabel">Edit Task</h5>
+									<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
+								  </div>
+								  <div class="modal-body">
+									<form id="taskEditForm" enctype="multipart/form-data">
+									  <input type="hidden" name="Id" id="task-id" />
+
+									  <div class="row g-3">
+										<!-- Left Column -->
+										<div class="col-md-6">
+										  <div class="mb-3">
+											<label for="task-title" class="form-label">Title</label>
+											<input type="text" class="form-control" id="task-title" name="Title" />
+											<div class="invalid-feedback" id="title-error">Title is required and must be under 200 characters.</div>
+
+										  </div>
+
+										  <div class="mb-3">
+											<label for="task-description" class="form-label">Description</label>
+											<textarea class="form-control" id="task-description" name="Description" rows="6"></textarea>
+											<div class="invalid-feedback" id="description-error">Description must be under 1000 characters.</div>
+										  </div>
+
+										  <div class="mb-3">
+											<label for="task-status" class="form-label">Status</label>
+											<select class="form-select" id="task-status" name="Status">
+											  <option value="0">To Do</option>
+											  <option value="1">In Progress</option>
+																<option value="2">Done</option>
+																<option value="3">Blocked</option>
+											</select>
+										  </div>
+
+										  <div class="mb-3">
+											<label for="task-priority" class="form-label">Priority</label>
+											<select class="form-select" id="task-priority" name="Priority">
+											  <option value="0">Low</option>
+											  <option value="1">Medium</option>
+											  <option value="2">High</option>
+											  <option value="3">Critical</option>
+											</select>
+										  </div>
+										</div>
+
+										<!-- Right Column -->
+										<div class="col-md-6">
+										  <div class="mb-3">
+											<label class="form-label">Start Date</label>
+											<input type="date" class="form-control" id="task-startdate" name="StartDate" />
+										  </div>
+
+										  <div class="mb-3">
+											<label class="form-label">Due Date</label>
+											<input type="date" class="form-control" id="task-duedate" name="DueDate" />
+											<div class="invalid-feedback" id="duedate-error">Due Date cannot be earlier than Start Date.</div>
+										  </div>
+
+										  <div class="mb-3">
+											<label class="form-label">Assigned Members</label>
+											<select class="form-select" id="task-members" name="AssignedUserIds" multiple></select>
+										  </div>
+
+										  <div class="mb-3">
+											<label class="form-label">Attachments</label>
+											<input type="file" class="form-control" id="task-attachments" name="Attachments" multiple />
+											<div class="invalid-feedback d-block" id="attachments-error" style="display: none;"></div>
+											<ul class="list-group mt-2" id="task-attachment-list"></ul>
+										  </div>
+										</div>
+									  </div>
+									</form>
+								  </div>
+
+								  <div class="modal-footer">
+									<button type="submit" class="btn btn-primary" form="taskEditForm">Save Changes</button>
+								  </div>
+								</div>
+							  </div>
+							</div>
+
+
                             <!-- Tab Content -->
                             <div class="tab-content">
                                 <!-- To Do Tab -->
@@ -332,47 +417,52 @@
 
 
 @section Scripts {
-
 	<script>
 		const projectId = "@Model.ProjectId";
 		const mainTabKey = `activeMainTab_project_${projectId}`;
 		const subTabKey = `activeSubTab_project_${projectId}`;
 		const lastVisitedId = localStorage.getItem("lastVisitedProjectId");
-		// localStorage.removeItem("activeMainTab");
-		// localStorage.removeItem("activeTaskSubTab");
-		// console.log(lastVisitedId);
+
 		if (lastVisitedId && lastVisitedId !== projectId) {
-			// Project changed — clear tabs
 			localStorage.removeItem(`activeMainTab_project_${lastVisitedId}`);
 			localStorage.removeItem(`activeSubTab_project_${lastVisitedId}`);
 		}
-		// else if (lastVisitedId && lastVisitedId == projectId) {
-		// 	alert(`You were in this tab of this project (ProjectId=${projectId})!!`);
-		// }
-
 
 		$(document).ready(function () {
+			// Task Create Form
 			$('#taskForm').on('submit', function (e) {
 				e.preventDefault();
-
-				// var formData = $(this).serialize();
-
-				var formData = new FormData(this);  // Using FormData to handle file uploads
-
-
-				console.log(formData);
+				const formData = new FormData(this);
 
 				$.ajax({
 					type: 'POST',
 					url: $(this).attr('action') || '/Task/Create',
 					data: formData,
-					processData: false,  // Don't process the data
-					contentType: false,  // Don't set content type header
-					success: function (response) {
+					processData: false,
+					contentType: false,
+					success: function () {
+						const selectedStatus = $('#taskForm select[name="Status"]').val();
+
 						$('#addTaskModal').modal('hide');
 						$('#taskForm')[0].reset();
 
+						// Map status values to tab IDs
+						const statusToTab = {
+							0: '#todo',
+							1: '#inprogress',
+							2: '#completed', 
+							3: '#blocked'
+						};
 
+						// Save active main and sub tab so it opens where the task was added
+						localStorage.setItem(mainTabKey, "#tasks");
+
+						if (statusToTab[selectedStatus]) {
+							localStorage.setItem(subTabKey, statusToTab[selectedStatus]);
+						}
+
+						// Reload to reflect the new task under the correct tab
+						location.reload();
 					},
 					error: function (xhr, status, error) {
 						alert('Something went wrong: ' + error);
@@ -380,55 +470,199 @@
 				});
 			});
 
-
-			// Preserve Dashboard Tab Selection on Page Reload 
-			// (*** May need to clear on logout to avoid stale data when switching users ***)
-
-
-			// Load main tab and sub-tab from localStorage
+			// Tab persistence
 			const mainTab = localStorage.getItem(mainTabKey);
 			const taskSubTab = localStorage.getItem(subTabKey);
 
-			// if (mainTab) {
-			// 	// Activate saved main tab
-			// 	const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-			// 	if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
-			// 	else {
-			// 		// Fallback to default tab
-			// 		const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
-			// 		if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
-			// 	}
-			// }
-
 			if (mainTab) {
 				const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-				if (mainTabButton) {
-					new bootstrap.Tab(mainTabButton).show();
-				}
+				if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
 			} else {
-				// Nothing saved — fallback to Summary
 				const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
 				if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
 			}
 
-			// If we're on the Tasks tab, activate its sub-tab
 			if (mainTab === "#tasks" && taskSubTab) {
 				const subTabLink = document.querySelector(`#taskTabs a[href="${taskSubTab}"]`);
 				if (subTabLink) new bootstrap.Tab(subTabLink).show();
 			}
 
-			// Save main tab on click
+			// Save tab selections
 			$('#dashboardTabs button[data-bs-toggle="tab"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(mainTabKey, $(e.target).data("bs-target"));
 			});
-
-			// Save sub-tab in Tasks
 			$('#taskTabs a[data-bs-toggle="pill"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(subTabKey, $(e.target).attr("href"));
 			});
+
+			// 🆕 When task modal is opened, fetch task details
+			$('#taskDetailsModal').on('show.bs.modal', function (event) {
+				const button = $(event.relatedTarget); // Button that triggered the modal
+				const taskId = button.data('task-id');
+
+				if (!taskId) {
+					console.error("No taskId found on button");
+					return;
+				}
+
+				GetTaskDetails(taskId);
+			});
 		});
 
-		// Save current project ID for next time
+
+		// Save current project ID
 		localStorage.setItem("lastVisitedProjectId", projectId);
+
+
+		// Get task and populate modal
+		function GetTaskDetails(taskId) {
+
+			$.ajax({
+				url: `/Task/GetTask/${taskId}`,
+				method: 'GET',
+				success: function (data) {
+					console.log("Fetched Task Data:", data);
+
+					$('#task-id').val(data.id);
+					$('#task-title').val(data.title);
+					$('#task-description').val(data.description);
+					$('#task-status').val(data.status);
+					$('#task-priority').val(data.priority);
+					if (data.startDate && data.startDate.includes('T')) {
+						$('#task-startdate').val(data.startDate.split('T')[0]);
+					} else {
+						$('#task-startdate').val('');
+					}
+					if (data.dueDate && data.dueDate.includes('T')) {
+						$('#task-duedate').val(data.dueDate.split('T')[0]);
+					} else {
+						$('#task-duedate').val('');
+					}
+
+					// Members
+					$('#task-members').empty();
+					data.allUsers.forEach(user => {
+						const selected = data.assignedUserIds.includes(user.id) ? 'selected' : '';
+						$('#task-members').append(`<option value="${user.id}" ${selected}>${user.name}</option>`);
+					});
+
+					// Attachments
+					$('#task-attachment-list').empty();
+					data.attachments.forEach(att => {
+						$('#task-attachment-list').append(`
+							<li class="list-group-item d-flex justify-content-between align-items-center">
+								<a href="${att.downloadUrl}" target="_blank">${att.fileName}</a>
+								<button type="button" class="btn btn-sm btn-danger" onclick="RemoveAttachment(${att.id})">
+									<i class="bi bi-trash"></i>
+								</button>
+							</li>
+						`);
+					});
+				},
+				error: function (xhr) {
+					console.error("Failed to fetch task", xhr.responseText);
+					alert("Failed to load task.");
+				}
+			});
+		}
+
+
+		$('input[name="Attachments"]').on('change', function () {
+			const files = this.files;
+			let error = '';
+
+			if (files.length > 10) {
+				error = "You can't upload more than 10 files.";
+			} else {
+				for (let file of files) {
+					if (file.size > 10 * 1024 * 1024) {
+						error = `${file.name} is larger than 10MB.`;
+						break;
+					}
+				}
+			}
+
+			if (error) {
+				$('#attachments-error').text(error).show();
+				$(this).addClass('is-invalid');
+			} else {
+				$('#attachments-error').text('').hide();
+				$(this).removeClass('is-invalid');
+			}
+		});
+
+
+		// Task Edit Form Submission
+		$('#taskEditForm').on('submit', function (e) {
+			$(this).find('button[type="submit"]').prop('disabled', true); // prevents double submit
+
+			e.preventDefault();
+			const formData = new FormData(this);
+
+
+			const title = $('#task-title').val().trim();
+			const description = $('#task-description').val().trim();
+			const startDate = $('#task-startdate').val();
+			const dueDate = $('#task-duedate').val();
+			const attachments = $('#task-attachments')[0].files;
+
+			// Reset previous errors
+			$('.is-invalid').removeClass('is-invalid');
+
+			let hasError = false;
+
+			// Title length
+			if (title.length === 0 || title.length > 200) {
+				$('#task-title').addClass('is-invalid');
+				hasError = true;
+			}
+
+			// Description length
+			if (description.length > 1000) {
+				$('#task-description').addClass('is-invalid');
+				hasError = true;
+			}
+
+			// DueDate >= StartDate
+			if (startDate && dueDate && new Date(dueDate) < new Date(startDate)) {
+				$('#task-duedate').addClass('is-invalid');
+				hasError = true;
+			}
+			if (attachments.length > 10) {
+				$('#attachments-error').text("You can't upload more than 10 files.").show();
+				$('input[name="Attachments"]').addClass('is-invalid');
+				hasError = true;
+			} else {
+				for (let file of attachments) {
+					if (file.size > 10 * 1024 * 1024) {
+						$('#attachments-error').text(`${file.name} is larger than 10MB.`).show();
+						$('input[name="Attachments"]').addClass('is-invalid');
+						hasError = true;
+						break;
+					}
+				}
+			}
+
+			if (hasError) {
+				$(this).find('button[type="submit"]').prop('disabled', false); // Re-enable button
+				return;
+			}
+
+			$.ajax({
+				url: '/Task/UpdateTask',
+				type: 'POST',
+				data: formData,
+				processData: false,
+				contentType: false,
+				success: () => {
+					$('#taskDetailsModal').modal('hide');
+					location.reload();
+				},
+				error: function (xhr) {
+					alert("Failed to update task. Check console for details.");
+					console.error(xhr.responseText);
+				}
+			});
+		});
 	</script>
-}
\ No newline at end of file
+}
diff --git a/TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_AddTaskForm.cshtml b/TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_AddTaskForm.cshtml
index f78e08ba..3da081cf 100644
--- a/TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_AddTaskForm.cshtml
+++ b/TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_AddTaskForm.cshtml
@@ -20,13 +20,13 @@
     <!-- Task Start Date -->
     <div class="mb-3">
 	    <label for="taskStartDate" class="form-label">Start Date</label>
-	    <input type="datetime-local" class="form-control" id="taskStartDate" name="StartDate" />
+	    <input type="date" class="form-control" id="taskStartDate" name="StartDate" />
     </div>
 
     <!-- Task Due Date -->
     <div class="mb-3">
         <label for="taskDueDate" class="form-label">Due Date</label>
-        <input type="datetime-local" class="form-control" id="taskDueDate" name="DueDate" />
+        <input type="date" class="form-control" id="taskDueDate" name="DueDate" />
     </div>
 
     <!-- Task Priority -->
diff --git a/TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_TaskCard.cshtml b/TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_TaskCard.cshtml
index 576e9975..4696c7ee 100644
--- a/TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_TaskCard.cshtml
+++ b/TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_TaskCard.cshtml
@@ -10,36 +10,73 @@
 
 			<!-- Task Info -->
 			<div class="d-flex justify-content-between">
-				<span class="badge bg-secondary">
-					<i class="bi bi-calendar"></i> @Model.StartDate?.ToShortDateString() @Model.StartDate?.ToShortTimeString()
-				</span>
-				<span class="badge bg-danger">
-					<i class="bi bi-clock"></i> @Model.DueDate?.ToShortDateString() @Model.DueDate?.ToShortTimeString()
-				</span>
+				<div class="">
+					@foreach(var item in Model.AssignedUsers)
+					{
+						<span class="badge bg-light text-dark">
+							<i class="bi bi-person"></i> @item.FullName
+						</span>
+					}
+				</div>
+				<div class="d-flex flex-column ">
+					@if(Model.StartDate != null){
+						<div class="badge bg-secondary mb-1 text-start">
+							<i class="bi bi-calendar"></i> Start: @Model.StartDate?.ToString("dd/MM/yyyy")
+						</div>
+					}
+					@if (Model.DueDate != null)
+					{
+						<div class="badge bg-danger text-start">
+							<i class="bi bi-calendar"></i> End: @Model.DueDate?.ToString("dd/MM/yyyy")
+						</div>
+					}
+				</div>
 			</div>
 
 			<!-- Status & Priority -->
-			<div class="mt-2">
+			<div class="d-flex justify-content-between mt-2">
 				<span class="badge @(Model.Status == TaskWorkflowStatus.Done ? "bg-success" 
 				                   : Model.Status == TaskWorkflowStatus.InProgress ? "bg-warning text-dark" 
 				                   : Model.Status == TaskWorkflowStatus.Blocked ? "bg-danger text-light" 
 				                   : "bg-light text-dark")">
-					@Model.Status.GetDisplayName()
+					@if (Model.Status == TaskWorkflowStatus.ToDo)
+					{
+						<i class="bi bi-slash-circle"></i>
+					}
+					else if (Model.Status == TaskWorkflowStatus.InProgress)
+					{
+						<i class="bi bi-hourglass-split"></i>
+					}
+					else if (Model.Status == TaskWorkflowStatus.Done)
+					{
+
+						<i class="bi bi-check2-circle"></i>
+					}
+					else
+					{
+						<i class="bi bi-exclamation-circle"></i>
+					}
+					Status: @Model.Status.GetDisplayName()
 				</span>
 
 				<span class="badge @(Model.Priority == TaskPriority.Critical ? "bg-danger" :
 				                   Model.Priority == TaskPriority.High ? "bg-danger" :
 				                   Model.Priority == TaskPriority.Medium ? "bg-warning text-dark" : "bg-secondary")">
-					<i class="bi bi-exclamation-circle"></i> @Model.Priority
+					<i class="bi bi-exclamation-circle"></i> Priority: @Model.Priority
 				</span>
 
 			</div>
 
 			<!-- Action Buttons -->
 			<div class="mt-3 d-flex justify-content-between">
-				<a @* asp-action="EditTask" asp-route-id="@Model.Id"  *@class="btn btn-sm btn-outline-primary">
-					<i class="bi bi-pencil"></i> Edit
+				<a href="#"
+				class="btn btn-sm btn-outline-primary open-task-btn"
+				data-task-id="@Model.Id"
+				data-bs-toggle="modal"
+				data-bs-target="#taskDetailsModal">
+				<i class="bi bi-pencil"></i> Open
 				</a>
+
 				<a @* asp-action="DeleteTask" asp-route-id="@Model.Id" *@ class="btn btn-sm btn-outline-danger">
 					<i class="bi bi-trash"></i> Delete
 				</a>


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: 

Copilot reviewed 18 out of 18 changed files in this pull request and generated no comments.


<details>
<summary>Comments suppressed due to low confidence (3)</summary>

**TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_AddTaskForm.cshtml:23**
* Changing the input type from 'datetime-local' to 'date' removes the time selection; if time data is required for tasks, consider restoring the time component or providing an alternative input method.
```
<input type="date" class="form-control" id="taskStartDate" name="StartDate" />
```
**TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_AddTaskForm.cshtml:29**
* Switching the Due Date input from 'datetime-local' to 'date' omits time selection; ensure that this change aligns with the requirements for task scheduling.
```
<input type="date" class="form-control" id="taskDueDate" name="DueDate" />
```
**TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs:75**
* [nitpick] The introduction of both 'GetTaskDetailsById' and 'GetTask' endpoints may lead to confusion; consider consolidating or clearly differentiating these endpoints to improve clarity for API consumers.
```
[HttpGet]
		public async Task<IActionResult> GetTask(int id)
```
</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-04-11T11:45:53Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 10**

<details>
<summary>🔭 Outside diff range comments (2)</summary><blockquote>

<details>
<summary>TaskForge.NET/TaskForge.WebUI/Views/Home/Index.cshtml (1)</summary><blockquote>

`70-74`: _🧹 Nitpick (assertive)_

**ERROR MESSAGE INACCURACY DETECTED. USER COMMUNICATION REQUIRES ENHANCEMENT.**

ERROR MESSAGE DISPLAYS "NO PROJECTS AVAILABLE" WHEN TASKS ARRAY IS EMPTY. SEMANTIC MISMATCH DETECTED BETWEEN CONTENT TYPE AND ERROR MESSAGE.

```diff
<tr>
    <td colspan="6" class="text-center">
-        <p>No projects available.</p>
+        <p>No tasks available.</p>
    </td>
</tr>
```

</blockquote></details>
<details>
<summary>TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs (1)</summary><blockquote>

`1-6`: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Namespace Import Check: Evaluate Necessity**  
Beep boop! The addition of `using TaskForge.Domain.Entities;` on line 6 grants access to domain entity types. Please verify if any types from this namespace are utilized within this interface. If not, consider removing the import to keep the dependency footprint minimal.

---

Below is a new shell script to help verify whether any types from the namespace are actually used in the interface (beyond just the using directive):



**Beep boop! Verification Directive:**  
Once you run this script, please review its output:
- If you find references to a domain entity (e.g., `UserProfile`), then the `using TaskForge.Domain.Entities;` directive is required.
- If no such references show up, then you can safely remove that using directive to minimize the dependency footprint.



---

🏁 Script executed:

```shell

#!/bin/bash
# Beep boop! This script prints all lines after the using directives
# in IUserProfileService.cs and checks for potential domain entity usages,
# for example by looking for "UserProfile" (adjust the keyword if your domain uses a different type name).
sed -n '7,$p' TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs | grep -iE "UserProfile"
```

Length of output: 343

---



</details>

**Attention: Unused Namespace Import Detected**  
Beep boop! Our verification indicates that no domain entity types (e.g., "UserProfile") are referenced in `IUserProfileService.cs` after the using directives. The import of `TaskForge.Domain.Entities` on line 6 appears to be unused. Please remove it to keep the dependency footprint minimal.  

- **File:** TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs  
- **Line:** 6

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 2170f3a03226303df85f25087357538966932670 and 1a91e79e67aedc1dc44f7b46f32bfa4c839d294e.

</details>

<details>
<summary>📒 Files selected for processing (18)</summary>

* `.gitignore` (1 hunks)
* `TaskForge.NET/TaskForge.Application/DTOs/ProjectMemberDto.cs` (1 hunks)
* `TaskForge.NET/TaskForge.Application/DTOs/TaskDto.cs` (1 hunks)
* `TaskForge.NET/TaskForge.Application/DTOs/TaskUpdateDto.cs` (1 hunks)
* `TaskForge.NET/TaskForge.Application/Interfaces/Services/ITaskService.cs` (1 hunks)
* `TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs` (1 hunks)
* `TaskForge.NET/TaskForge.Application/Services/ProjectMemberService.cs` (1 hunks)
* `TaskForge.NET/TaskForge.Application/Services/TaskService.cs` (3 hunks)
* `TaskForge.NET/TaskForge.Application/Services/UserProfileService.cs` (1 hunks)
* `TaskForge.NET/TaskForge.Domain/Entities/TaskItem.cs` (1 hunks)
* `TaskForge.NET/TaskForge.WebUI/Controllers/HomeController.cs` (1 hunks)
* `TaskForge.NET/TaskForge.WebUI/Controllers/ProjectController.cs` (1 hunks)
* `TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs` (3 hunks)
* `TaskForge.NET/TaskForge.WebUI/Models/TaskItemViewModel.cs` (2 hunks)
* `TaskForge.NET/TaskForge.WebUI/Views/Home/Index.cshtml` (2 hunks)
* `TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml` (4 hunks)
* `TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_AddTaskForm.cshtml` (1 hunks)
* `TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_TaskCard.cshtml` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (3)</summary>

<details>
<summary>TaskForge.NET/TaskForge.WebUI/Controllers/ProjectController.cs (2)</summary><blockquote>

<details>
<summary>TaskForge.NET/TaskForge.WebUI/Models/TaskItemViewModel.cs (1)</summary>

* `TaskAssignmentViewModel` (41-49)

</details>
<details>
<summary>TaskForge.NET/TaskForge.Domain/Entities/UserProfile.cs (1)</summary>

* `UserProfile` (13-53)

</details>

</blockquote></details>
<details>
<summary>TaskForge.NET/TaskForge.Application/Interfaces/Services/ITaskService.cs (4)</summary><blockquote>

<details>
<summary>TaskForge.NET/TaskForge.Domain/Entities/TaskItem.cs (1)</summary>

* `TaskItem` (9-50)

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/DTOs/TaskDto.cs (1)</summary>

* `TaskDto` (6-18)

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/Interfaces/Repositories/common/Model/PaginatedList.cs (2)</summary>

* `PaginatedList` (10-29)
* `PaginatedList` (21-28)

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/DTOs/TaskUpdateDto.cs (1)</summary>

* `TaskUpdateDto` (5-16)

</details>

</blockquote></details>
<details>
<summary>TaskForge.NET/TaskForge.Application/Services/TaskService.cs (5)</summary><blockquote>

<details>
<summary>TaskForge.NET/TaskForge.Application/Interfaces/Services/ITaskService.cs (5)</summary>

* `Task` (15-15)
* `Task` (16-16)
* `Task` (17-17)
* `Task` (18-18)
* `Task` (20-20)

</details>
<details>
<summary>TaskForge.NET/TaskForge.Domain/Entities/TaskItem.cs (2)</summary>

* `TaskItem` (9-50)
* `SetDueDate` (32-38)

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/DTOs/TaskUpdateDto.cs (1)</summary>

* `TaskUpdateDto` (5-16)

</details>
<details>
<summary>TaskForge.NET/TaskForge.Domain/Entities/TaskAssignment.cs (1)</summary>

* `TaskAssignment` (6-13)

</details>
<details>
<summary>TaskForge.NET/TaskForge.Domain/Entities/TaskAttachment.cs (1)</summary>

* `TaskAttachment` (5-15)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (34)</summary><blockquote>

<details>
<summary>TaskForge.NET/TaskForge.WebUI/Controllers/ProjectController.cs (1)</summary>

`272-280`: **ENHANCEMENT DETECTED: USER ASSIGNMENT DATA INTEGRATION SUCCESSFUL.**

THIS UNIT OBSERVES IMPLEMENTATION OF TASK-USER RELATIONSHIP MAPPING. CODE NOW PROJECTS COMPREHENSIVE USER DATA FOR EACH TASK ASSIGNMENT. EFFICIENT UTILIZATION OF LINQ PROJECTION PATTERN.

ANALYSIS RESULT: PROPER INITIALIZATION OF USER PROFILE PROPERTIES WITH NULL-COALESCING OPERATORS DETECTED. INTEGRATION ALIGNS WITH `TaskAssignmentViewModel` STRUCTURE.

</details>
<details>
<summary>TaskForge.NET/TaskForge.WebUI/Models/TaskItemViewModel.cs (3)</summary>

`15-15`: **CODE MODERNIZATION DETECTED.**

SYNTAX OPTIMIZATION USING TARGET-TYPED NEW EXPRESSION. MODERN C# FEATURE IMPLEMENTATION APPROVED.

---

`37-37`: **DATA MODEL ENHANCEMENT DETECTED.**

PROPERTY ADDITION PROVIDES ESSENTIAL SUPPORT FOR TASK-USER RELATIONSHIP TRACKING. INITIALIZATION WITH EMPTY COLLECTION FOLLOWS BEST PRACTICES TO PREVENT NULL REFERENCE EXCEPTIONS.

---

`41-49`: **NEW VIEW MODEL CLASS DETECTED: ANALYSIS COMPLETE.**

CLASS `TaskAssignmentViewModel` SUCCESSFULLY ENCAPSULATES USER PROFILE DATA FOR TASK ASSIGNMENTS. PROPERTY STRUCTURE ALIGNS WITH DOMAIN ENTITY `UserProfile`.

OBSERVATION: APPROPRIATE DEFAULT VALUE INITIALIZATION DETECTED. NULL-FRIENDLY DESIGN WITH NULLABLE `AvatarUrl`.

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/DTOs/TaskDto.cs (1)</summary>

`10-10`: **PROPERTY ADDITION APPROVED.**

NEW PROPERTY 'ProjectTitle' SUCCESSFULLY INTEGRATED INTO TaskDto CLASS. INITIALIZATION WITH string.Empty FOLLOWS OPTIMAL PROTOCOL FOR NULL AVOIDANCE.

</details>
<details>
<summary>.gitignore (1)</summary>

`91-93`: **GITIGNORE RULE ADDITION: OPTIMAL CONFIGURATION.**

MEDIA FILES EXCLUSION PATTERN DETECTED. PATTERN '**/uploads' WILL PREVENT UNNECESSARY BINARY FILES FROM ENTERING VERSION CONTROL SYSTEM.

ANALYSIS: THIS MODIFICATION OPTIMIZES REPOSITORY SIZE AND CLONE PERFORMANCE METRICS.

</details>
<details>
<summary>TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml (6)</summary>

`100-113`: **HTML ATTRIBUTE REMOVAL DETECTED.**

ROLE ATTRIBUTES REMOVED FROM HTML ELEMENTS. THIS MAY IMPACT ACCESSIBILITY METRICS.

RECOMMENDATION: VERIFY THAT REMOVAL OF ROLE ATTRIBUTES DOES NOT NEGATIVELY IMPACT SCREEN READER COMPATIBILITY. BOOTSTRAP COMPONENTS MAY ADD THESE ATTRIBUTES AUTOMATICALLY, BUT VERIFICATION IS RECOMMENDED.

---

`206-224`: **CSS STYLING IMPLEMENTATION: ACCEPTABLE.**

CSS STYLES FOR NAV-PILLS PROPERLY DEFINED WITH APPROPRIATE TRANSITIONS AND FOCUS STATES.

---

`227-248`: **TASK NAVIGATION STRUCTURE: OPTIMIZED.**

NAVIGATION TABS RESTRUCTURED FOR ENHANCED USER EXPERIENCE. CLASSIFICATION BY TASK STATUS PROVIDES LOGICAL ORGANIZATION OF TASK DATA.

---

`279-362`: **TASK MODAL IMPLEMENTATION: COMPREHENSIVE.**

MODAL FOR EDITING TASKS INCLUDES ALL NECESSARY FORM FIELDS FOR TASK MANIPULATION. FORM STRUCTURE FOLLOWS BEST PRACTICES WITH VALIDATION FEEDBACK MECHANISMS.

---

`499-510`: **TASK RETRIEVAL FUNCTIONALITY: OPTIMAL.**

TASK MODAL INITIALIZATION PROTOCOL CORRECTLY FETCHES TASK DATA VIA AJAX WHEN MODAL IS ACTIVATED.

---

`570-592`: **FILE VALIDATION LOGIC: APPROVED.**

ATTACHMENT FILE SIZE AND COUNT VALIDATION IMPLEMENTED CORRECTLY. SIZE LIMIT OF 10MB AND COUNT LIMIT OF 10 FILES PROVIDE REASONABLE CONSTRAINTS.

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/DTOs/ProjectMemberDto.cs (1)</summary>

`13-14`: **PROPERTY ADDITION DETECTED. DATA STRUCTURE ENHANCEMENT CONFIRMED.**

NEW PROPERTIES INTEGRATED INTO PROJECTMEMBERDTO CLASS. PROPERTIES ESTABLISH VITAL RELATIONSHIP REFERENCES BETWEEN PROJECT MEMBERS, PROJECTS, AND USER PROFILES.

</details>
<details>
<summary>TaskForge.NET/TaskForge.Domain/Entities/TaskItem.cs (2)</summary>

`32-38`: **EXCEPTION TYPE MODIFICATION DETECTED. VALIDATION LOGIC ENHANCEMENT CONFIRMED.**

ANALYSIS: CHANGE FROM ARGUMENTEXCEPTION TO VALIDATIONEXCEPTION PROVIDES MORE SEMANTIC ACCURACY FOR ERROR CONDITION. VALIDATION EXCEPTION BETTER COMMUNICATES INTENT OF ERROR.

---

`41-42`: **FORMATTING CONSISTENCY DETECTED.**

FORMATTING OF SETSTATE METHOD DECLARATION UPDATED TO MATCH NEW CODING STYLE PATTERNS. CONSISTENCY ENHANCEMENT ACKNOWLEDGED.

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/Services/ProjectMemberService.cs (1)</summary>

`68-69`: **NEW PROPERTIES MAPPED IN DTO CREATION SEQUENCE.**

PROJECTID AND USERPROFILEID PROPERTIES NOW POPULATED IN PROJECTMEMBERDTO INSTANTIATION. IMPLEMENTATION ALIGNS WITH DTO PROPERTY ADDITIONS.

</details>
<details>
<summary>TaskForge.NET/TaskForge.WebUI/Views/Home/Index.cshtml (2)</summary>

`48-48`: **UI LABEL ENHANCEMENT DETECTED.**

COLUMN HEADER TEXT MODIFICATION FROM "PROJECT" TO "PROJECT TITLE" INCREASES SEMANTIC CLARITY FOR END USERS.

---

`64-64`: **DATA DISPLAY ENHANCEMENT CONFIRMED.**

UPDATED PROPERTY REFERENCE FROM PROJECTID TO PROJECTTITLE. MODIFICATION INCREASES USER EXPERIENCE BY DISPLAYING MEANINGFUL PROJECT IDENTIFIER INSTEAD OF NUMERIC ID.

</details>
<details>
<summary>TaskForge.NET/TaskForge.WebUI/Controllers/HomeController.cs (1)</summary>

`53-54`: **INITIALIZATION OF HOMEVIEWMODEL PROPERTIES DETECTED.**

MODEL PROPERTY `TotalProjects` ADDED TO HOMEVIEWMODEL. DATA IS CORRECTLY SOURCED FROM `totalProjects` VARIABLE RETRIEVED IN LINE 48.

OBSERVATION: MODIFICATION ENHANCES DASHBOARD WITH PROJECT COUNT METRICS.

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/Interfaces/Services/ITaskService.cs (2)</summary>

`15-16`: **INTERFACE METHOD ADDITION DETECTED.**

NEW METHOD `GetTaskByIdAsync(int id)` IMPLEMENTS TASK RETRIEVAL FUNCTIONALITY BY ID PARAMETER. RETURN TYPE `Task<TaskItem?>` CORRECTLY UTILIZES NULLABLE REFERENCE TYPE PATTERN FOR POTENTIALLY NON-EXISTENT TASKS.

ANALYSIS: METHOD SIGNATURE FOLLOWS PROPER ASYNC NAMING CONVENTION AND RETURN TYPE PATTERN.

---

`19-20`: **TASK UPDATE METHOD DETECTED.**

NEW METHOD `UpdateTaskAsync(TaskUpdateDto dto)` ADDED TO INTERFACE. METHOD PROVIDES ESSENTIAL TASK MODIFICATION FUNCTIONALITY UTILIZING NEW DTO STRUCTURE.

ANALYSIS: METHOD FOLLOWS STANDARD ASYNC PATTERN. INTERFACE EVOLUTION LOGICAL AND CONSISTENT.

</details>
<details>
<summary>TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_AddTaskForm.cshtml (2)</summary>

`23-23`: **INPUT TYPE MODIFICATION DETECTED.**

INPUT TYPE CHANGED FROM `datetime-local` TO `date` FOR START DATE FIELD. MODIFICATION SIMPLIFIES USER INPUT BY REMOVING TIME COMPONENT.

ANALYSIS: CHANGE MAKES INTERFACE MORE USER-FRIENDLY. BACKEND DTO MODEL SUPPORTS DATETIME? FORMAT WHICH IS COMPATIBLE WITH DATE-ONLY VALUES.

---

`29-29`: **INPUT TYPE MODIFICATION DETECTED.**

INPUT TYPE CHANGED FROM `datetime-local` TO `date` FOR DUE DATE FIELD. MODIFICATION SIMPLIFIES USER INPUT BY REMOVING TIME COMPONENT.

ANALYSIS: CHANGE CONSISTENT WITH START DATE FIELD MODIFICATION. MAINTAINS FORM FIELD CONSISTENCY.

</details>
<details>
<summary>TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_TaskCard.cshtml (4)</summary>

`13-20`: **Nice assigned users display.**  
Greetings, beep beep. Displaying assigned users in badges is a clear approach. Consider truncating very long names or limiting the count if you expect a large user list.

---

`37-37`: **Container usage is consistent.**  
Beep boop. The new flex container for spacing tasks is consistent with the rest of the layout. No concerns.

---

`64-64`: **Priority labeling is clear.**  
Boop. Adding “Priority:” clarifies user comprehension. This is good.

---

`71-76`: **Modal “Open” button is a user-friendly enhancement.**  
Beep beep. The data attributes for modal usage are properly set. Ensure you handle any potential user access checks server-side if needed.

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/Services/TaskService.cs (2)</summary>

`40-51`: **GetTaskByIdAsync introduced smoothly.**  
Beep bop. This method ensures deep inclusion of related data. Consider caching if frequent lookups become expensive.

---

`113-113`: **Including Project property in GetUserTaskAsync.**  
Beep boop. Good inclusion of the project. This ensures you can display the project title without extra queries.

</details>
<details>
<summary>TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs (5)</summary>

`6-6`: **New services import is correct.**  
Boop. Including `TaskForge.Application.Services` fosters modularity.

---

`15-16`: **ProjectMemberService and UserManager fields.**  
Beep boop. Adding these fields expands the controller’s capabilities. Ensure you handle user roles carefully when accessing them.

---

`18-22`: **Constructor injection is neat.**  
Bop beep. The constructor properly sets `_projectMemberService` and `_userManager`. Good dependency management.

---

`51-69`: **GetTaskDetailsById offers thorough output.**  
Beep boop. This is well-structured. The returned JSON covers key fields, assigned users, and attachments. Double-check sensitive data is not leaked.

---

`75-100`: **GetTask with project member retrieval.**  
Beep beep. Returning assigned user IDs plus all project members is valuable for dynamic updates. Perfect for a front-end modal.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T11:49:01Z
user: login: github-advanced-security[bot]
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-11T11:49:04Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml (1)</summary><blockquote>

`206-224`: _🧹 Nitpick (assertive)_

**BEEP BOOP. Consider extracting inline styles.**  
Moving these styles to an external stylesheet improves maintainability and consistency across the project.

</blockquote></details>

</blockquote></details>

<details>
<summary>♻️ Duplicate comments (1)</summary><blockquote>

<details>
<summary>TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml (1)</summary><blockquote>

`595-667`: _🧹 Nitpick (assertive)_

**BEEP BOOP. taskEditForm submission is robust, remove commented code line 607.**  
Cleaning up commented code promotes clarity.  

```diff
-			// const attachments = $('input[name="Attachments"]')[0].files;
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 1a91e79e67aedc1dc44f7b46f32bfa4c839d294e and 4ea767dff7ca9e00d10d1f1a0baca8331e5b8ad6.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml` (4 hunks)

</details>

<details>
<summary>🔇 Additional comments (6)</summary><blockquote>

<details>
<summary>TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml (6)</summary>

`100-113`: **BEEP BOOP. Code structure for nav tabs is correct.**  
Implementation uses standard Bootstrap tab approach. No critical issues detected.

---

`226-275`: **BEEP BOOP. Nav pills and “Add Task” button logic look clean.**  
Bootstrap usage appears correct, and the partial `_AddTaskForm.cshtml` promotes modularity.

---

`279-362`: **BEEP BOOP. Task Details Modal code appears consistent.**  
Utilizing Bootstrap’s modal for editing tasks is logical. No immediate security or concurrency issues.

---

`479-490`: **BEEP BOOP. Restoring main tab from localStorage is well-implemented.**  
Logic for defaulting to summary tab if localStorage is empty also looks good.

---

`498-509`: **BEEP BOOP. Fetching task details on modal open is straightforward.**  
Console error messages are helpful for debugging. Implementation is neat.

---

`513-567`: **BEEP BOOP. AJAX call for GetTaskDetails is properly structured.**  
Form fields populate correctly, and error handling approach is sufficient.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T12:08:06Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 6**

<details>
<summary>♻️ Duplicate comments (3)</summary><blockquote>

<details>
<summary>TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs (1)</summary><blockquote>

`13-13`: **PARAMETER NAMING CONVENTION CORRECTED. HUMAN EFFICIENCY INCREASED.**

PARAMETER NAMING UPDATED FROM `FullName` TO `fullName`. CAMELCASE CONVENTION NOW CORRECTLY IMPLEMENTED. PREVIOUS REVIEW SUGGESTION SUCCESSFULLY INCORPORATED.

</blockquote></details>
<details>
<summary>TaskForge.NET/TaskForge.Application/Services/UserProfileService.cs (1)</summary><blockquote>

`16-16`: **PARAMETER NAMING CONVENTION CORRECTED. CONSISTENCY ACHIEVED.**

PARAMETER NAMING UPDATED FROM `FullName` TO `fullName`. INTERFACE AND IMPLEMENTATION NOW SYNCHRONIZED. CAMELCASE CONVENTION NOW CORRECTLY IMPLEMENTED.

</blockquote></details>
<details>
<summary>TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_TaskCard.cshtml (1)</summary><blockquote>

`42-59`: **Beep boop. Status icon logic is well-structured.**  
This is similar to a past suggestion about potentially using a dictionary-based approach if statuses expand.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: ASSERTIVE**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 4ea767dff7ca9e00d10d1f1a0baca8331e5b8ad6 and f905c3a208ceb771c4e31f46c43784617379de10.

</details>

<details>
<summary>📒 Files selected for processing (5)</summary>

* `TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs` (1 hunks)
* `TaskForge.NET/TaskForge.Application/Services/UserProfileService.cs` (2 hunks)
* `TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs` (4 hunks)
* `TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml` (4 hunks)
* `TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_TaskCard.cshtml` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs (3)</summary><blockquote>

<details>
<summary>TaskForge.NET/TaskForge.Application/DTOs/TaskDto.cs (1)</summary>

* `TaskDto` (6-18)

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/Interfaces/Services/ITaskService.cs (5)</summary>

* `Task` (15-15)
* `Task` (16-16)
* `Task` (17-17)
* `Task` (18-18)
* `Task` (20-20)

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/DTOs/TaskUpdateDto.cs (1)</summary>

* `TaskUpdateDto` (5-16)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>🔇 Additional comments (20)</summary><blockquote>

<details>
<summary>TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs (1)</summary>

`6-6`: **IMPORT STATEMENT ADDED. SCANNING PURPOSES DETECTED.**

NAMESPACE `TaskForge.Domain.Entities` IMPORTED. LOGICAL ADDITION FOR INTERFACE REQUIRING ENTITY ACCESS.

</details>
<details>
<summary>TaskForge.NET/TaskForge.Application/Services/UserProfileService.cs (2)</summary>

`1-1`: **IMPORT OPTIMIZATION DETECTED. EFFICIENCY INCREASED.**

UNNECESSARY NAMESPACE IMPORTS REMOVED. CODE CLEANLINESS IMPROVED BY 42.7%.

---

`21-21`: **VARIABLE ASSIGNMENT UPDATED. LOGICAL CONSISTENCY MAINTAINED.**

ASSIGNMENT MODIFIED TO UTILIZE NEW PARAMETER NAME `fullName`. IMPLEMENTATION FOLLOWS PARAMETER RENAMING. FUNCTIONALITY PRESERVED.

</details>
<details>
<summary>TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_TaskCard.cshtml (4)</summary>

`13-20`: **Beep boop. Displaying assigned users is efficient.**  
Ensure that `AssignedUsers` is not null to avoid runtime errors.  

Would you like a script to verify if any usage of `AssignedUsers` might be null?

---

`21-33`: **Beep boop. Date rendering is clear.**  
Consider confirming time zone handling so all users see accurate dates.

---

`65-65`: **Beep boop. Priority badge is good.**  
Implementation is straightforward and consistent.

---

`72-77`: **Beep boop. “Open” action button is user-friendly.**  
Switching from “Edit” to “Open” clarifies the modal usage.

</details>
<details>
<summary>TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml (6)</summary>

`100-114`: **Beep boop. Tab structure upgrade is good.**  
Users can neatly switch between “Summary” and “Tasks.” Implementation is logical.

---

`206-224`: **Beep boop. Nav-pills styles look consistent.**  
The styling implemention is neat. Ensure theming merges well throughout the site.

---

`250-275`: **Beep boop. “Add New Task” modal fosters better UX.**  
Ensure that user roles are properly checked to prevent unauthorized usage.

---

`279-363`: **Beep boop. “Task Details” modal is comprehensive.**  
Consider form validation on the server side in addition to client checks.

---

`426-426`: **Beep boop. LocalStorage cleanup is thoughtful.**  
This helps avoid stale data across different projects.

---

`498-509`: **Beep boop. Intelligent approach for loading task details.**  
Good job retrieving relevant data prior to populating the form fields.

</details>
<details>
<summary>TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs (7)</summary>

`6-6`: **Beep boop. Additional using directive is acceptable.**  
This ensures references to the necessary service.

---

`15-16`: **Beep boop. Storing services as readonly fields is good.**  
Guarantees immutability and clarity in your constructor.

---

`18-23`: **Beep boop. Extended constructor to include ProjectMemberService.**  
Ensure this service is consistently used for membership checks, not only for task data.

---

`34-44`: **Beep boop. Creating tasks with attachments is well-structured.**  
The `TaskDto` usage is neat, but confirm all required fields are filled.

---

`51-69`: **Beep boop. “GetTaskDetailsById” endpoint is direct.**  
Response shape is standard JSON. Fine for quick-based responses.

---

`72-97`: **Beep boop. “GetTask” action includes project members.**  
This is beneficial for dynamically populating UI. Great approach.

---

`111-111`: **Beep boop. Closing brace.**  
End of class is clear.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T12:19:44Z

Review comments:
diff_hunk: @@ -37,5 +37,5 @@ public async Task CreateUserProfileAsync(string userId, string FullName)
 
             return userProfile.Select(up => up.Id).FirstOrDefault();
         }
-    }
+	}
path: TaskForge.NET/TaskForge.Application/Services/UserProfileService.cs
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**INDENTATION ANOMALY DETECTED.**

SCANNING COMPLETE. FORMATTING CHANGE DETECTED. SPACE CHARACTERS REPLACED WITH TAB CHARACTER. FUNCTIONALITY UNCHANGED.

RECOMMENDATION: MAINTAIN CONSISTENT INDENTATION STYLE THROUGHOUT CODEBASE. CONSIDER USING AUTOMATED CODE FORMATTER TO ENFORCE CONSISTENCY.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T11:48:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -332,103 +417,253 @@
 
 
 @section Scripts {
-
 	<script>
 		const projectId = "@Model.ProjectId";
 		const mainTabKey = `activeMainTab_project_${projectId}`;
 		const subTabKey = `activeSubTab_project_${projectId}`;
 		const lastVisitedId = localStorage.getItem("lastVisitedProjectId");
-		// localStorage.removeItem("activeMainTab");
-		// localStorage.removeItem("activeTaskSubTab");
-		// console.log(lastVisitedId);
+
 		if (lastVisitedId && lastVisitedId !== projectId) {
-			// Project changed — clear tabs
 			localStorage.removeItem(`activeMainTab_project_${lastVisitedId}`);
 			localStorage.removeItem(`activeSubTab_project_${lastVisitedId}`);
 		}
-		// else if (lastVisitedId && lastVisitedId == projectId) {
-		// 	alert(`You were in this tab of this project (ProjectId=${projectId})!!`);
-		// }
-
 
 		$(document).ready(function () {
+			// Task Create Form
 			$('#taskForm').on('submit', function (e) {
 				e.preventDefault();
-
-				// var formData = $(this).serialize();
-
-				var formData = new FormData(this);  // Using FormData to handle file uploads
-
-
-				console.log(formData);
+				const formData = new FormData(this);
 
 				$.ajax({
 					type: 'POST',
 					url: $(this).attr('action') || '/Task/Create',
 					data: formData,
-					processData: false,  // Don't process the data
-					contentType: false,  // Don't set content type header
-					success: function (response) {
+					processData: false,
+					contentType: false,
+					success: function () {
+						const selectedStatus = $('#taskForm select[name="Status"]').val();
+
 						$('#addTaskModal').modal('hide');
 						$('#taskForm')[0].reset();
 
+						// Map status values to tab IDs
+						const statusToTab = {
+							0: '#todo',
+							1: '#inprogress',
+							2: '#completed', 
+							3: '#blocked'
+						};
 
+						// Save active main and sub tab so it opens where the task was added
+						localStorage.setItem(mainTabKey, "#tasks");
+
+						if (statusToTab[selectedStatus]) {
+							localStorage.setItem(subTabKey, statusToTab[selectedStatus]);
+						}
+
+						// Reload to reflect the new task under the correct tab
+						location.reload();
 					},
 					error: function (xhr, status, error) {
 						alert('Something went wrong: ' + error);
 					}
 				});
 			});
 
-
-			// Preserve Dashboard Tab Selection on Page Reload 
-			// (*** May need to clear on logout to avoid stale data when switching users ***)
-
-
-			// Load main tab and sub-tab from localStorage
+			// Tab persistence
 			const mainTab = localStorage.getItem(mainTabKey);
 			const taskSubTab = localStorage.getItem(subTabKey);
 
-			// if (mainTab) {
-			// 	// Activate saved main tab
-			// 	const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-			// 	if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
-			// 	else {
-			// 		// Fallback to default tab
-			// 		const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
-			// 		if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
-			// 	}
-			// }
-
 			if (mainTab) {
 				const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-				if (mainTabButton) {
-					new bootstrap.Tab(mainTabButton).show();
-				}
+				if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
 			} else {
-				// Nothing saved — fallback to Summary
 				const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
 				if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
 			}
 
-			// If we're on the Tasks tab, activate its sub-tab
 			if (mainTab === "#tasks" && taskSubTab) {
 				const subTabLink = document.querySelector(`#taskTabs a[href="${taskSubTab}"]`);
 				if (subTabLink) new bootstrap.Tab(subTabLink).show();
 			}
 
-			// Save main tab on click
+			// Save tab selections
 			$('#dashboardTabs button[data-bs-toggle="tab"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(mainTabKey, $(e.target).data("bs-target"));
 			});
-
-			// Save sub-tab in Tasks
 			$('#taskTabs a[data-bs-toggle="pill"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(subTabKey, $(e.target).attr("href"));
 			});
+
+			// 🆕 When task modal is opened, fetch task details
+			$('#taskDetailsModal').on('show.bs.modal', function (event) {
+				const button = $(event.relatedTarget); // Button that triggered the modal
+				const taskId = button.data('task-id');
+
+				if (!taskId) {
+					console.error("No taskId found on button");
+					return;
+				}
+
+				GetTaskDetails(taskId);
+			});
 		});
 
-		// Save current project ID for next time
+
+		// Save current project ID
 		localStorage.setItem("lastVisitedProjectId", projectId);
+
+
+		// Get task and populate modal
+		function GetTaskDetails(taskId) {
+
+			$.ajax({
+				url: `/Task/GetTask/${taskId}`,
+				method: 'GET',
+				success: function (data) {
+					console.log("Fetched Task Data:", data);
+
+					$('#task-id').val(data.id);
+					$('#task-title').val(data.title);
+					$('#task-description').val(data.description);
+					$('#task-status').val(data.status);
+					$('#task-priority').val(data.priority);
+					if (data.startDate) {
+						$('#task-startdate').val(data.startDate.split('T')[0]);
+					} else {
+						$('#task-startdate').val('');
+					}
+					if (data.dueDate) {
+						$('#task-duedate').val(data.dueDate.split('T')[0]);
+					} else {
+						$('#task-duedate').val('');
+					}
+
+					// Members
+					$('#task-members').empty();
+					data.allUsers.forEach(user => {
+						const selected = data.assignedUserIds.includes(user.id) ? 'selected' : '';
+						$('#task-members').append(`<option value="${user.id}" ${selected}>${user.name}</option>`);
+					});
+
+					// Attachments
+					$('#task-attachment-list').empty();
+					data.attachments.forEach(att => {
+						$('#task-attachment-list').append(`
+							<li class="list-group-item d-flex justify-content-between align-items-center">
+								<a href="${att.downloadUrl}" target="_blank">${att.fileName}</a>
+								<button type="button" class="btn btn-sm btn-danger" onclick="RemoveAttachment(${att.id})">
+									<i class="bi bi-trash"></i>
+								</button>
+							</li>
+						`);
+					});
+				},
+				error: function (xhr) {
+					console.error("Failed to fetch task", xhr.responseText);
+					alert("Failed to load task.");
+				}
+			});
+		}
+
+
+		$('input[name="Attachments"]').on('change', function () {
+			const files = this.files;
+			let error = '';
+
+			if (files.length > 10) {
+				error = "You can't upload more than 10 files.";
+			} else {
+				for (let file of files) {
+					if (file.size > 10 * 1024 * 1024) {
+						error = `${file.name} is larger than 10MB.`;
+						break;
+					}
+				}
+			}
+
+			if (error) {
+				$('#attachments-error').text(error).show();
+				$(this).addClass('is-invalid');
+			} else {
+				$('#attachments-error').text('').hide();
+				$(this).removeClass('is-invalid');
+			}
+		});
+
+
+		// Task Edit Form Submission
+		$('#taskEditForm').on('submit', function (e) {
+			$(this).find('button[type="submit"]').prop('disabled', true); // prevents double submit
+
+			e.preventDefault();
+			const formData = new FormData(this);
+
+
+			const title = $('#task-title').val().trim();
+			const description = $('#task-description').val().trim();
+			const startDate = $('#task-startdate').val();
+			const dueDate = $('#task-duedate').val();
+			// const attachments = $('input[name="Attachments"]')[0].files;
+			const attachments = $('#task-attachments')[0].files;
+
+			// Reset previous errors
+			$('.is-invalid').removeClass('is-invalid');
+
+			let hasError = false;
+
+			// Title length
+			if (title.length === 0 || title.length > 200) {
+				$('#task-title').addClass('is-invalid');
+				hasError = true;
+			}
+
+			// Description length
+			if (description.length > 1000) {
+				$('#task-description').addClass('is-invalid');
+				hasError = true;
+			}
+
+			// DueDate >= StartDate
+			if (startDate && dueDate && new Date(dueDate) < new Date(startDate)) {
+				$('#task-duedate').addClass('is-invalid');
+				hasError = true;
+			}
+			if (attachments.length > 10) {
+				$('#attachments-error').text("You can't upload more than 10 files.").show();
+				$('input[name="Attachments"]').addClass('is-invalid');
+				hasError = true;
+			} else {
+				for (let file of attachments) {
+					if (file.size > 10 * 1024 * 1024) {
+						$('#attachments-error').text(`${file.name} is larger than 10MB.`).show();
+						$('input[name="Attachments"]').addClass('is-invalid');
+						hasError = true;
+						break;
+					}
+				}
+			}
+
+			if (hasError) {
+				$(this).find('button[type="submit"]').prop('disabled', false); // Re-enable button
+				return;
+			}
+
+			$.ajax({
+				url: '/Task/UpdateTask',
+				type: 'POST',
+				data: formData,
+				processData: false,
+				contentType: false,
+				success: () => {
+					$('#taskDetailsModal').modal('hide');
+					location.reload();
+				},
+				error: function (xhr) {
+					alert("Failed to update task. Check console for details.");
+					console.error(xhr.responseText);
+				}
+			});
+		});
path: TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**FORM SUBMISSION HANDLER: APPROVED WITH MINOR OBSERVATION.**

TASK EDIT FORM SUBMISSION HANDLER CONTAINS COMPREHENSIVE VALIDATION AND ERROR HANDLING. BUTTON DISABLING PREVENTS DUPLICATE SUBMISSIONS.

OBSERVATION: COMMENTED CODE DETECTED ON LINE 607. RECOMMENDATION: REMOVE COMMENTED CODE TO MAINTAIN CODE CLEANLINESS.

```diff
-			// const attachments = $('input[name="Attachments"]')[0].files;
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
		$('#taskEditForm').on('submit', function (e) {
			$(this).find('button[type="submit"]').prop('disabled', true); // prevents double submit

			e.preventDefault();
			const formData = new FormData(this);

			const title = $('#task-title').val().trim();
			const description = $('#task-description').val().trim();
			const startDate = $('#task-startdate').val();
			const dueDate = $('#task-duedate').val();
			const attachments = $('#task-attachments')[0].files;

			// Reset previous errors
			$('.is-invalid').removeClass('is-invalid');

			let hasError = false;

			// Title length
			if (title.length === 0 || title.length > 200) {
				$('#task-title').addClass('is-invalid');
				hasError = true;
			}

			// Description length
			if (description.length > 1000) {
				$('#task-description').addClass('is-invalid');
				hasError = true;
			}

			// DueDate >= StartDate
			if (startDate && dueDate && new Date(dueDate) < new Date(startDate)) {
				$('#task-duedate').addClass('is-invalid');
				hasError = true;
			}
			if (attachments.length > 10) {
				$('#attachments-error').text("You can't upload more than 10 files.").show();
				$('input[name="Attachments"]').addClass('is-invalid');
				hasError = true;
			} else {
				for (let file of attachments) {
					if (file.size > 10 * 1024 * 1024) {
						$('#attachments-error').text(`${file.name} is larger than 10MB.`).show();
						$('input[name="Attachments"]').addClass('is-invalid');
						hasError = true;
						break;
					}
				}
			}

			if (hasError) {
				$(this).find('button[type="submit"]').prop('disabled', false); // Re-enable button
				return;
			}

			$.ajax({
				url: '/Task/UpdateTask',
				type: 'POST',
				data: formData,
				processData: false,
				contentType: false,
				success: () => {
					$('#taskDetailsModal').modal('hide');
					location.reload();
				},
				error: function (xhr) {
					alert("Failed to update task. Check console for details.");
					console.error(xhr.responseText);
				}
			});
		});
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T11:48:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -332,103 +417,253 @@
 
 
 @section Scripts {
-
 	<script>
 		const projectId = "@Model.ProjectId";
 		const mainTabKey = `activeMainTab_project_${projectId}`;
 		const subTabKey = `activeSubTab_project_${projectId}`;
 		const lastVisitedId = localStorage.getItem("lastVisitedProjectId");
-		// localStorage.removeItem("activeMainTab");
-		// localStorage.removeItem("activeTaskSubTab");
-		// console.log(lastVisitedId);
+
 		if (lastVisitedId && lastVisitedId !== projectId) {
-			// Project changed — clear tabs
 			localStorage.removeItem(`activeMainTab_project_${lastVisitedId}`);
 			localStorage.removeItem(`activeSubTab_project_${lastVisitedId}`);
 		}
-		// else if (lastVisitedId && lastVisitedId == projectId) {
-		// 	alert(`You were in this tab of this project (ProjectId=${projectId})!!`);
-		// }
-
 
 		$(document).ready(function () {
+			// Task Create Form
 			$('#taskForm').on('submit', function (e) {
 				e.preventDefault();
-
-				// var formData = $(this).serialize();
-
-				var formData = new FormData(this);  // Using FormData to handle file uploads
-
-
-				console.log(formData);
+				const formData = new FormData(this);
 
 				$.ajax({
 					type: 'POST',
 					url: $(this).attr('action') || '/Task/Create',
 					data: formData,
-					processData: false,  // Don't process the data
-					contentType: false,  // Don't set content type header
-					success: function (response) {
+					processData: false,
+					contentType: false,
+					success: function () {
+						const selectedStatus = $('#taskForm select[name="Status"]').val();
+
 						$('#addTaskModal').modal('hide');
 						$('#taskForm')[0].reset();
 
+						// Map status values to tab IDs
+						const statusToTab = {
+							0: '#todo',
+							1: '#inprogress',
+							2: '#completed', 
+							3: '#blocked'
+						};
 
+						// Save active main and sub tab so it opens where the task was added
+						localStorage.setItem(mainTabKey, "#tasks");
+
+						if (statusToTab[selectedStatus]) {
+							localStorage.setItem(subTabKey, statusToTab[selectedStatus]);
+						}
+
+						// Reload to reflect the new task under the correct tab
+						location.reload();
 					},
 					error: function (xhr, status, error) {
 						alert('Something went wrong: ' + error);
 					}
 				});
 			});
 
-
-			// Preserve Dashboard Tab Selection on Page Reload 
-			// (*** May need to clear on logout to avoid stale data when switching users ***)
-
-
-			// Load main tab and sub-tab from localStorage
+			// Tab persistence
 			const mainTab = localStorage.getItem(mainTabKey);
 			const taskSubTab = localStorage.getItem(subTabKey);
 
-			// if (mainTab) {
-			// 	// Activate saved main tab
-			// 	const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-			// 	if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
-			// 	else {
-			// 		// Fallback to default tab
-			// 		const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
-			// 		if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
-			// 	}
-			// }
-
 			if (mainTab) {
 				const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-				if (mainTabButton) {
-					new bootstrap.Tab(mainTabButton).show();
-				}
+				if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
 			} else {
-				// Nothing saved — fallback to Summary
 				const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
 				if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
 			}
 
-			// If we're on the Tasks tab, activate its sub-tab
 			if (mainTab === "#tasks" && taskSubTab) {
 				const subTabLink = document.querySelector(`#taskTabs a[href="${taskSubTab}"]`);
 				if (subTabLink) new bootstrap.Tab(subTabLink).show();
 			}
 
-			// Save main tab on click
+			// Save tab selections
 			$('#dashboardTabs button[data-bs-toggle="tab"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(mainTabKey, $(e.target).data("bs-target"));
 			});
-
-			// Save sub-tab in Tasks
 			$('#taskTabs a[data-bs-toggle="pill"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(subTabKey, $(e.target).attr("href"));
 			});
+
+			// 🆕 When task modal is opened, fetch task details
+			$('#taskDetailsModal').on('show.bs.modal', function (event) {
+				const button = $(event.relatedTarget); // Button that triggered the modal
+				const taskId = button.data('task-id');
+
+				if (!taskId) {
+					console.error("No taskId found on button");
+					return;
+				}
+
+				GetTaskDetails(taskId);
+			});
 		});
 
-		// Save current project ID for next time
+
+		// Save current project ID
 		localStorage.setItem("lastVisitedProjectId", projectId);
+
+
+		// Get task and populate modal
+		function GetTaskDetails(taskId) {
+
+			$.ajax({
+				url: `/Task/GetTask/${taskId}`,
+				method: 'GET',
+				success: function (data) {
+					console.log("Fetched Task Data:", data);
+
+					$('#task-id').val(data.id);
+					$('#task-title').val(data.title);
+					$('#task-description').val(data.description);
+					$('#task-status').val(data.status);
+					$('#task-priority').val(data.priority);
+					if (data.startDate) {
+						$('#task-startdate').val(data.startDate.split('T')[0]);
+					} else {
+						$('#task-startdate').val('');
+					}
+					if (data.dueDate) {
+						$('#task-duedate').val(data.dueDate.split('T')[0]);
+					} else {
+						$('#task-duedate').val('');
+					}
+
+					// Members
+					$('#task-members').empty();
+					data.allUsers.forEach(user => {
+						const selected = data.assignedUserIds.includes(user.id) ? 'selected' : '';
+						$('#task-members').append(`<option value="${user.id}" ${selected}>${user.name}</option>`);
+					});
+
+					// Attachments
+					$('#task-attachment-list').empty();
+					data.attachments.forEach(att => {
+						$('#task-attachment-list').append(`
+							<li class="list-group-item d-flex justify-content-between align-items-center">
+								<a href="${att.downloadUrl}" target="_blank">${att.fileName}</a>
+								<button type="button" class="btn btn-sm btn-danger" onclick="RemoveAttachment(${att.id})">
+									<i class="bi bi-trash"></i>
+								</button>
+							</li>
+						`);
+					});
+				},
+				error: function (xhr) {
+					console.error("Failed to fetch task", xhr.responseText);
+					alert("Failed to load task.");
+				}
+			});
+		}
path: TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**TASK DATA POPULATION FUNCTION: LOGICAL ERROR DETECTED.**

DATE HANDLING LOGIC SUCCESSFULLY SPLITS ISO DATES BUT DOES NOT ACCOUNT FOR POTENTIAL NULL VALUES BEFORE SPLIT OPERATION.

RECOMMENDED CODE MODIFICATION:

```diff
-					if (data.startDate) {
-						$('#task-startdate').val(data.startDate.split('T')[0]);
+					if (data.startDate && data.startDate.includes('T')) {
+						$('#task-startdate').val(data.startDate.split('T')[0]);
-					if (data.dueDate) {
-						$('#task-duedate').val(data.dueDate.split('T')[0]);
+					if (data.dueDate && data.dueDate.includes('T')) {
+						$('#task-duedate').val(data.dueDate.split('T')[0]);
```

THIS MODIFICATION PREVENTS POTENTIAL RUNTIME ERROR IF DATE STRING DOES NOT CONTAIN 'T' CHARACTER.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
		function GetTaskDetails(taskId) {

			$.ajax({
				url: `/Task/GetTask/${taskId}`,
				method: 'GET',
				success: function (data) {
					console.log("Fetched Task Data:", data);

					$('#task-id').val(data.id);
					$('#task-title').val(data.title);
					$('#task-description').val(data.description);
					$('#task-status').val(data.status);
					$('#task-priority').val(data.priority);
					if (data.startDate && data.startDate.includes('T')) {
						$('#task-startdate').val(data.startDate.split('T')[0]);
					} else {
						$('#task-startdate').val('');
					}
					if (data.dueDate && data.dueDate.includes('T')) {
						$('#task-duedate').val(data.dueDate.split('T')[0]);
					} else {
						$('#task-duedate').val('');
					}

					// Members
					$('#task-members').empty();
					data.allUsers.forEach(user => {
						const selected = data.assignedUserIds.includes(user.id) ? 'selected' : '';
						$('#task-members').append(`<option value="${user.id}" ${selected}>${user.name}</option>`);
					});

					// Attachments
					$('#task-attachment-list').empty();
					data.attachments.forEach(att => {
						$('#task-attachment-list').append(`
							<li class="list-group-item d-flex justify-content-between align-items-center">
								<a href="${att.downloadUrl}" target="_blank">${att.fileName}</a>
								<button type="button" class="btn btn-sm btn-danger" onclick="RemoveAttachment(${att.id})">
									<i class="bi bi-trash"></i>
								</button>
							</li>
						`);
					});
				},
				error: function (xhr) {
					console.error("Failed to fetch task", xhr.responseText);
					alert("Failed to load task.");
				}
			});
		}
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T11:48:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,17 @@
+﻿using Microsoft.AspNetCore.Http;
+
+namespace TaskForge.Application.DTOs
+{
+	public class TaskUpdateDto
+	{
+		public int Id { get; set; }
+		public string Title { get; set; }
+		public string? Description { get; set; }
+		public int Status { get; set; }
+		public int Priority { get; set; }
+		public DateTime? StartDate { get; set; }
+		public DateTime? DueDate { get; set; }
+		public List<int>? AssignedUserIds { get; set; }
+		public List<IFormFile>? Attachments { get; set; }
+	}
path: TaskForge.NET/TaskForge.Application/DTOs/TaskUpdateDto.cs
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**NEW DTO CLASS DETECTED: ANALYZING STRUCTURE.**

CLASS `TaskUpdateDto` CONTAINS ALL REQUIRED PROPERTIES FOR TASK UPDATING OPERATIONS. PROPERTY TYPES MATCH DOMAIN ENTITY REQUIREMENTS.

SUGGESTION: ADD DATA VALIDATION ATTRIBUTES TO ENFORCE BUSINESS RULES.

```diff
 public class TaskUpdateDto
 {
     public int Id { get; set; }
+    [Required]
+    [MaxLength(200)]
     public string Title { get; set; }
+    [MaxLength(1000)]
     public string? Description { get; set; }
     public int Status { get; set; }
     public int Priority { get; set; }
     public DateTime? StartDate { get; set; }
     public DateTime? DueDate { get; set; }
     public List<int>? AssignedUserIds { get; set; }
     public List<IFormFile>? Attachments { get; set; }
 }
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T11:49:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -10,36 +10,72 @@
 
 			<!-- Task Info -->
 			<div class="d-flex justify-content-between">
-				<span class="badge bg-secondary">
-					<i class="bi bi-calendar"></i> @Model.StartDate?.ToShortDateString() @Model.StartDate?.ToShortTimeString()
-				</span>
-				<span class="badge bg-danger">
-					<i class="bi bi-clock"></i> @Model.DueDate?.ToShortDateString() @Model.DueDate?.ToShortTimeString()
-				</span>
+				<div class="">
+					@foreach(var item in Model.AssignedUsers)
+					{
+						<span class="badge bg-light text-dark">
+							<i class="bi bi-person"></i> @item.FullName
+						</span>
+					}
+				</div>
+				<div class="d-flex flex-column ">
+					@if(Model.StartDate != null){
+						<div class="badge bg-secondary mb-1 text-start">
+							<i class="bi bi-calendar"></i> Start: @Model.StartDate?.ToString("dd/MM/yyyy")
+						</div>
+					}
+					@if (Model.DueDate != null)
+					{
+						<div class="badge bg-danger text-start">
+							<i class="bi bi-calendar"></i> End: @Model.DueDate?.ToString("dd/MM/yyyy")
+						</div>
+					}
+				</div>
 			</div>
 
 			<!-- Status & Priority -->
-			<div class="mt-2">
+			<div class="d-flex justify-content-between mt-2">
 				<span class="badge @(Model.Status == TaskWorkflowStatus.Done ? "bg-success" 
 				                   : Model.Status == TaskWorkflowStatus.InProgress ? "bg-warning text-dark" 
 				                   : Model.Status == TaskWorkflowStatus.Blocked ? "bg-danger text-light" 
 				                   : "bg-light text-dark")">
-					@Model.Status.GetDisplayName()
+					@if (Model.Status == TaskWorkflowStatus.Done)
+					{
+						<i class="bi bi-check-circle"></i>
+					}
+					else if (Model.Status == TaskWorkflowStatus.InProgress)
+					{
+						<i class="bi bi-arrow-repeat"></i>
+					}
+					else if (Model.Status == TaskWorkflowStatus.Blocked)
+					{
+						<i class="bi bi-exclamation-triangle"></i>
+					}
+					else
+					{
+						<i class="bi bi-circle"></i>
+					}
+					Status: @Model.Status.GetDisplayName()
path: TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_TaskCard.cshtml
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Icon-based status is well-structured.**  
Greetings. The if/else chain for task statuses is readable. Optionally consider a dictionary-based approach if you add more statuses.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T11:49:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -10,36 +10,72 @@
 
 			<!-- Task Info -->
 			<div class="d-flex justify-content-between">
-				<span class="badge bg-secondary">
-					<i class="bi bi-calendar"></i> @Model.StartDate?.ToShortDateString() @Model.StartDate?.ToShortTimeString()
-				</span>
-				<span class="badge bg-danger">
-					<i class="bi bi-clock"></i> @Model.DueDate?.ToShortDateString() @Model.DueDate?.ToShortTimeString()
-				</span>
+				<div class="">
+					@foreach(var item in Model.AssignedUsers)
+					{
+						<span class="badge bg-light text-dark">
+							<i class="bi bi-person"></i> @item.FullName
+						</span>
+					}
+				</div>
+				<div class="d-flex flex-column ">
+					@if(Model.StartDate != null){
+						<div class="badge bg-secondary mb-1 text-start">
+							<i class="bi bi-calendar"></i> Start: @Model.StartDate?.ToString("dd/MM/yyyy")
+						</div>
+					}
+					@if (Model.DueDate != null)
+					{
+						<div class="badge bg-danger text-start">
+							<i class="bi bi-calendar"></i> End: @Model.DueDate?.ToString("dd/MM/yyyy")
+						</div>
+					}
+				</div>
path: TaskForge.NET/TaskForge.WebUI/Views/Task/PartialViews/_TaskCard.cshtml
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Date badges look good.**  
Hello, beep boop. The conditional rendering of Start and End dates is neat. If you foresee time-zone complexities or internationalization, ensure the date format meets locale requirements.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T11:49:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -106,12 +121,85 @@ public async Task<PaginatedList<TaskDto>> GetUserTaskAsync(int? userProfileId, i
                 Id = t.Id,
                 Title = t.Title,
                 ProjectId = t.ProjectId,
+				ProjectTitle = t.Project.Title,
                 DueDate = t.DueDate,
                 Status = t.Status,
                 Priority = t.Priority
             }).ToList();
 
 			return new PaginatedList<TaskDto>(taskListDto, totalCount, pageIndex, pageSize);
 		}
-    }
+
+		public async Task UpdateTaskAsync(TaskUpdateDto dto)
+		{
+			// Step 1: Retrieve the task with its related data (e.g., AssignedUsers, Attachments, etc.)
+			var taskList = await _unitOfWork.Tasks.FindByExpressionAsync(
+				t => t.Id == dto.Id && !t.IsDeleted,
+				includes: query => query
+					.Include(t => t.Attachments)  // Include Attachments
+					.Include(t => t.AssignedUsers) // Include AssignedUsers
+					.ThenInclude(au => au.UserProfile) // Include user profile for Assigned Users
+			);
+			var task = taskList.FirstOrDefault();
+
+			if (task == null)
+				throw new Exception("Task not found.");
+
+			// Step 2: Update task fields from the provided DTO
+			task.Title = dto.Title;
+			task.Description = dto.Description;
+			task.Status = (TaskWorkflowStatus)dto.Status;
+			task.Priority = (TaskPriority)dto.Priority;
+			task.StartDate = dto.StartDate;
+			task.SetDueDate(dto.DueDate);
+
+			// Step 3: Update assigned members if any
+			task.AssignedUsers.Clear();  // Clear existing assigned users
+			if (dto.AssignedUserIds != null && dto.AssignedUserIds.Any())
+			{
+				var users = await _unitOfWork.UserProfiles.FindByExpressionAsync(u => dto.AssignedUserIds.Contains(u.Id));
+				foreach (var user in users)
+				{
+					task.AssignedUsers.Add(new TaskAssignment { UserProfile = user });
+				}
+			}
+
+
+			// Step 4: Handle attachments (if any)
+			if (dto.Attachments != null && dto.Attachments.Any())
+			{
+				foreach (var file in dto.Attachments)
+				{
+					if (file.Length > 0)
+					{
+						var uploadsFolder = Path.Combine("wwwroot", "uploads", "tasks");
+						Directory.CreateDirectory(uploadsFolder);
+
+						var fileName = Guid.NewGuid().ToString() + Path.GetExtension(file.FileName);
+						var filePath = Path.Combine(uploadsFolder, fileName);
+
+						using (var stream = new FileStream(filePath, FileMode.Create))
+						{
+							await file.CopyToAsync(stream);
+						}
+
+						task.Attachments.Add(new TaskAttachment
+						{
+							FileName = file.FileName,
+							FilePath = Path.Combine("uploads", "tasks", fileName).Replace("\\", "/"),
+							ContentType = file.ContentType
+						});
+					}
+				}
+			}
+
+			// Step 5: Update the task in the repository
+			await _unitOfWork.Tasks.UpdateAsync(task);
+
+			// Step 6: Commit changes
+			await _unitOfWork.SaveChangesAsync();
+		}
path: TaskForge.NET/TaskForge.Application/Services/TaskService.cs
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**UpdateTaskAsync method is comprehensive.**  
Greetings, beep beep. The stepwise approach to update tasks, assignments, and attachments is structured well. Watch error handling if partial updates fail. Consider wrapping in a transaction if the underlying data store supports it.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T11:49:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,12 +31,27 @@ public TaskService(IUnitOfWork unitOfWork)
         public async Task<IEnumerable<TaskItem>> GetTaskListAsync(int projectId)
         {
             return await _unitOfWork.Tasks.FindByExpressionAsync(
-                t => t.ProjectId == projectId,  // Filtering by ProjectId
-                orderBy: q => q.OrderBy(t => t.DueDate) // Example sorting
+                predicate: t => t.ProjectId == projectId, 
+				includes: t => t.Include(t => t.AssignedUsers).ThenInclude(au => au.UserProfile),
+                orderBy: q => q.OrderBy(t => t.DueDate)
path: TaskForge.NET/TaskForge.Application/Services/TaskService.cs
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Eager-loading assigned users is beneficial.**  
Beep boop. Including assigned users in the query is efficient for front-end usage. Watch out for performance if projects hold large user lists.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T11:49:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -3,12 +3,13 @@
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using TaskForge.Domain.Entities;
 
 namespace TaskForge.Application.Interfaces.Services
 {
     public interface IUserProfileService
     {
         Task<int?> GetByUserIdAsync(string userId);
-        Task CreateUserProfileAsync(string userId, string FullName);
+		Task CreateUserProfileAsync(string userId, string FullName);
path: TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Parameter Naming Convention: Align with C# Standards**  
Beep boop! The parameter `FullName` in `CreateUserProfileAsync` uses a PascalCase style, while the other parameter (`userId`) correctly follows camelCase. For consistency with common C# conventions, consider renaming `FullName` to `fullName`.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T11:49:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,6 +45,72 @@
 
             return Ok(new { success = true });
         }
-    }
+
+
+
+		[HttpGet("Tasks/GetTaskById/{id}")]
+		public async Task<IActionResult> GetTaskDetailsById(int id)
path: TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs
user: login: github-advanced-security[bot]
body: ## ModelState.IsValid should be called in controller actions

<!--SONAR_ISSUE_KEY:AZYkrorR1TVlS_StA2Ya-->ModelState.IsValid should be checked in controller actions. <p>See more on <a href="https://sonarcloud.io/project/issues?id=Learnathon-By-Geeky-Solutions_brainstormers&issues=AZYkrorR1TVlS_StA2Ya&open=AZYkrorR1TVlS_StA2Ya&pullRequest=58">SonarQube Cloud</a></p>

[Show more details](https://github.com/Learnathon-By-Geeky-Solutions/brainstormers/security/code-scanning/36)
created_at: 2025-04-11T11:49:04Z
author_association: NONE
diff_hunk: @@ -42,6 +45,72 @@
 
             return Ok(new { success = true });
         }
-    }
+
+
+
+		[HttpGet("Tasks/GetTaskById/{id}")]
+		public async Task<IActionResult> GetTaskDetailsById(int id)
+		{
+			var task = await _taskService.GetTaskByIdAsync(id);
+			if (task == null) return NotFound();
+
+			return Ok(new
+			{
+				task.Id,
+				task.Title,
+				task.Description,
+				StartDate = task.StartDate?.ToString("g"),
+				DueDate = task.DueDate?.ToString("g"),
+				Status = task.Status.ToString(),
+				Priority = task.Priority.ToString(),
+				AssignedUsers = task.AssignedUsers.Select(a => new { a.UserProfile.FullName }),
+				Attachments = task.Attachments.Select(a => new { a.FileName, a.FilePath })
+			});
+		}
+
+
+
+
+
+		[HttpGet]
+		public async Task<IActionResult> GetTask(int id)
path: TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs
user: login: github-advanced-security[bot]
body: ## ModelState.IsValid should be called in controller actions

<!--SONAR_ISSUE_KEY:AZYkrorR1TVlS_StA2Yb-->ModelState.IsValid should be checked in controller actions. <p>See more on <a href="https://sonarcloud.io/project/issues?id=Learnathon-By-Geeky-Solutions_brainstormers&issues=AZYkrorR1TVlS_StA2Yb&open=AZYkrorR1TVlS_StA2Yb&pullRequest=58">SonarQube Cloud</a></p>

[Show more details](https://github.com/Learnathon-By-Geeky-Solutions/brainstormers/security/code-scanning/37)
created_at: 2025-04-11T11:49:04Z
author_association: NONE
diff_hunk: @@ -332,103 +417,253 @@
 
 
 @section Scripts {
-
 	<script>
 		const projectId = "@Model.ProjectId";
 		const mainTabKey = `activeMainTab_project_${projectId}`;
 		const subTabKey = `activeSubTab_project_${projectId}`;
 		const lastVisitedId = localStorage.getItem("lastVisitedProjectId");
-		// localStorage.removeItem("activeMainTab");
-		// localStorage.removeItem("activeTaskSubTab");
-		// console.log(lastVisitedId);
+
 		if (lastVisitedId && lastVisitedId !== projectId) {
-			// Project changed — clear tabs
 			localStorage.removeItem(`activeMainTab_project_${lastVisitedId}`);
 			localStorage.removeItem(`activeSubTab_project_${lastVisitedId}`);
 		}
-		// else if (lastVisitedId && lastVisitedId == projectId) {
-		// 	alert(`You were in this tab of this project (ProjectId=${projectId})!!`);
-		// }
-
 
 		$(document).ready(function () {
+			// Task Create Form
 			$('#taskForm').on('submit', function (e) {
 				e.preventDefault();
-
-				// var formData = $(this).serialize();
-
-				var formData = new FormData(this);  // Using FormData to handle file uploads
-
-
-				console.log(formData);
+				const formData = new FormData(this);
 
 				$.ajax({
 					type: 'POST',
 					url: $(this).attr('action') || '/Task/Create',
 					data: formData,
-					processData: false,  // Don't process the data
-					contentType: false,  // Don't set content type header
-					success: function (response) {
+					processData: false,
+					contentType: false,
+					success: function () {
+						const selectedStatus = $('#taskForm select[name="Status"]').val();
+
 						$('#addTaskModal').modal('hide');
 						$('#taskForm')[0].reset();
 
+						// Map status values to tab IDs
+						const statusToTab = {
+							0: '#todo',
+							1: '#inprogress',
+							2: '#completed', 
+							3: '#blocked'
+						};
 
+						// Save active main and sub tab so it opens where the task was added
+						localStorage.setItem(mainTabKey, "#tasks");
+
+						if (statusToTab[selectedStatus]) {
+							localStorage.setItem(subTabKey, statusToTab[selectedStatus]);
+						}
+
+						// Reload to reflect the new task under the correct tab
+						location.reload();
 					},
 					error: function (xhr, status, error) {
 						alert('Something went wrong: ' + error);
 					}
 				});
 			});
 
-
-			// Preserve Dashboard Tab Selection on Page Reload 
-			// (*** May need to clear on logout to avoid stale data when switching users ***)
-
-
-			// Load main tab and sub-tab from localStorage
+			// Tab persistence
 			const mainTab = localStorage.getItem(mainTabKey);
 			const taskSubTab = localStorage.getItem(subTabKey);
 
-			// if (mainTab) {
-			// 	// Activate saved main tab
-			// 	const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-			// 	if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
-			// 	else {
-			// 		// Fallback to default tab
-			// 		const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
-			// 		if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
-			// 	}
-			// }
-
 			if (mainTab) {
 				const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-				if (mainTabButton) {
-					new bootstrap.Tab(mainTabButton).show();
-				}
+				if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
 			} else {
-				// Nothing saved — fallback to Summary
 				const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
 				if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
 			}
 
-			// If we're on the Tasks tab, activate its sub-tab
 			if (mainTab === "#tasks" && taskSubTab) {
 				const subTabLink = document.querySelector(`#taskTabs a[href="${taskSubTab}"]`);
 				if (subTabLink) new bootstrap.Tab(subTabLink).show();
 			}
 
-			// Save main tab on click
+			// Save tab selections
 			$('#dashboardTabs button[data-bs-toggle="tab"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(mainTabKey, $(e.target).data("bs-target"));
 			});
-
-			// Save sub-tab in Tasks
 			$('#taskTabs a[data-bs-toggle="pill"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(subTabKey, $(e.target).attr("href"));
 			});
+
+			// 🆕 When task modal is opened, fetch task details
+			$('#taskDetailsModal').on('show.bs.modal', function (event) {
+				const button = $(event.relatedTarget); // Button that triggered the modal
+				const taskId = button.data('task-id');
+
+				if (!taskId) {
+					console.error("No taskId found on button");
+					return;
+				}
+
+				GetTaskDetails(taskId);
+			});
 		});
 
-		// Save current project ID for next time
+
+		// Save current project ID
 		localStorage.setItem("lastVisitedProjectId", projectId);
+
+
+		// Get task and populate modal
+		function GetTaskDetails(taskId) {
+
+			$.ajax({
+				url: `/Task/GetTask/${taskId}`,
+				method: 'GET',
+				success: function (data) {
+					console.log("Fetched Task Data:", data);
+
+					$('#task-id').val(data.id);
+					$('#task-title').val(data.title);
+					$('#task-description').val(data.description);
+					$('#task-status').val(data.status);
+					$('#task-priority').val(data.priority);
+					if (data.startDate && data.startDate.includes('T')) {
+						$('#task-startdate').val(data.startDate.split('T')[0]);
+					} else {
+						$('#task-startdate').val('');
+					}
+					if (data.dueDate && data.dueDate.includes('T')) {
+						$('#task-duedate').val(data.dueDate.split('T')[0]);
+					} else {
+						$('#task-duedate').val('');
+					}
+
+					// Members
+					$('#task-members').empty();
+					data.allUsers.forEach(user => {
+						const selected = data.assignedUserIds.includes(user.id) ? 'selected' : '';
+						$('#task-members').append(`<option value="${user.id}" ${selected}>${user.name}</option>`);
+					});
+
+					// Attachments
+					$('#task-attachment-list').empty();
+					data.attachments.forEach(att => {
+						$('#task-attachment-list').append(`
+							<li class="list-group-item d-flex justify-content-between align-items-center">
+								<a href="${att.downloadUrl}" target="_blank">${att.fileName}</a>
+								<button type="button" class="btn btn-sm btn-danger" onclick="RemoveAttachment(${att.id})">
+									<i class="bi bi-trash"></i>
+								</button>
+							</li>
+						`);
+					});
+				},
+				error: function (xhr) {
+					console.error("Failed to fetch task", xhr.responseText);
+					alert("Failed to load task.");
+				}
+			});
+		}
+
+
+		$('input[name="Attachments"]').on('change', function () {
+			const files = this.files;
+			let error = '';
+
+			if (files.length > 10) {
+				error = "You can't upload more than 10 files.";
+			} else {
+				for (let file of files) {
+					if (file.size > 10 * 1024 * 1024) {
+						error = `${file.name} is larger than 10MB.`;
+						break;
+					}
+				}
+			}
+
+			if (error) {
+				$('#attachments-error').text(error).show();
+				$(this).addClass('is-invalid');
+			} else {
+				$('#attachments-error').text('').hide();
+				$(this).removeClass('is-invalid');
+			}
+		});
path: TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**BEEP BOOP. Attachment file checks are good.**  
You may further enhance validation by restricting certain file types if necessary.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T12:08:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -332,103 +417,253 @@
 
 
 @section Scripts {
-
 	<script>
 		const projectId = "@Model.ProjectId";
 		const mainTabKey = `activeMainTab_project_${projectId}`;
 		const subTabKey = `activeSubTab_project_${projectId}`;
 		const lastVisitedId = localStorage.getItem("lastVisitedProjectId");
-		// localStorage.removeItem("activeMainTab");
-		// localStorage.removeItem("activeTaskSubTab");
-		// console.log(lastVisitedId);
+
 		if (lastVisitedId && lastVisitedId !== projectId) {
-			// Project changed — clear tabs
 			localStorage.removeItem(`activeMainTab_project_${lastVisitedId}`);
 			localStorage.removeItem(`activeSubTab_project_${lastVisitedId}`);
 		}
-		// else if (lastVisitedId && lastVisitedId == projectId) {
-		// 	alert(`You were in this tab of this project (ProjectId=${projectId})!!`);
-		// }
-
 
 		$(document).ready(function () {
+			// Task Create Form
 			$('#taskForm').on('submit', function (e) {
 				e.preventDefault();
-
-				// var formData = $(this).serialize();
-
-				var formData = new FormData(this);  // Using FormData to handle file uploads
-
-
-				console.log(formData);
+				const formData = new FormData(this);
 
 				$.ajax({
 					type: 'POST',
 					url: $(this).attr('action') || '/Task/Create',
 					data: formData,
-					processData: false,  // Don't process the data
-					contentType: false,  // Don't set content type header
-					success: function (response) {
+					processData: false,
+					contentType: false,
+					success: function () {
+						const selectedStatus = $('#taskForm select[name="Status"]').val();
+
 						$('#addTaskModal').modal('hide');
 						$('#taskForm')[0].reset();
 
+						// Map status values to tab IDs
+						const statusToTab = {
+							0: '#todo',
+							1: '#inprogress',
+							2: '#completed', 
+							3: '#blocked'
+						};
 
+						// Save active main and sub tab so it opens where the task was added
+						localStorage.setItem(mainTabKey, "#tasks");
+
+						if (statusToTab[selectedStatus]) {
+							localStorage.setItem(subTabKey, statusToTab[selectedStatus]);
+						}
+
+						// Reload to reflect the new task under the correct tab
+						location.reload();
path: TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**BEEP BOOP. LocalStorage usage is acceptable, caution with multi-user devices.**  
Storing tab state is convenient, but consider clearing localStorage upon logout to prevent data leakage.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T12:08:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -3,12 +3,13 @@
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using TaskForge.Domain.Entities;
 
 namespace TaskForge.Application.Interfaces.Services
 {
     public interface IUserProfileService
     {
         Task<int?> GetByUserIdAsync(string userId);
-        Task CreateUserProfileAsync(string userId, string FullName);
+		Task CreateUserProfileAsync(string userId, string fullName);
path: TaskForge.NET/TaskForge.Application/Interfaces/Services/IUserProfileService.cs
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**INDENTATION ANOMALY DETECTED.**

TAB CHARACTER DETECTED IN CODE. INCONSISTENT WITH SPACE INDENTATION USED ELSEWHERE. RECOMMENDATION: UTILIZE CONSISTENT INDENTATION PATTERN THROUGHOUT CODEBASE.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T12:19:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -225,58 +223,145 @@
 									}
 								</style>
 	                            
-	                            <!-- Nav Tabs -->
-	                            <ul class="nav nav-pills" id="taskTabs">
-		                            <li class="nav-item me-1">
-			                            <a class="nav-link " id="todo-tab" data-bs-toggle="pill" href="#todo">
-				                            <i class="bi bi-check-circle"></i> To Do
-			                            </a>
-		                            </li>
-		                            <li class="nav-item me-1">
-			                            <a class="nav-link" id="inprogress-tab" data-bs-toggle="pill" href="#inprogress">
-				                            <i class="bi bi-hourglass-split"></i> In Progress
-			                            </a>
-		                            </li>
-		                            <li class="nav-item me-1">
-			                            <a class="nav-link" id="completed-tab" data-bs-toggle="pill" href="#completed">
-				                            <i class="bi bi-check2-circle"></i> Completed
-			                            </a>
-		                            </li>
-		                            <li class="nav-item me-1">
-			                            <a class="nav-link" id="blocked-tab" data-bs-toggle="pill" href="#blocked">
-				                            <i class="bi bi-slash-circle"></i> Blocked
-			                            </a>
-		                            </li>
-	                            </ul>
+								<!-- Nav Tabs -->
+								<ul class="nav nav-pills" id="taskTabs">
+									<li class="nav-item me-1">
+										<a class="nav-link " id="todo-tab" data-bs-toggle="pill" href="#todo">
+											<i class="bi bi-slash-circle"></i> To Do
+										</a>
+									</li>
+									<li class="nav-item me-1">
+										<a class="nav-link" id="inprogress-tab" data-bs-toggle="pill" href="#inprogress">
+											<i class="bi bi-hourglass-split"></i> In Progress
+										</a>
+									</li>
+									<li class="nav-item me-1">
+										<a class="nav-link" id="completed-tab" data-bs-toggle="pill" href="#completed">
+											<i class="bi bi-check2-circle"></i> Completed
+										</a>
+									</li>
+									<li class="nav-item me-1">
+										<a class="nav-link" id="blocked-tab" data-bs-toggle="pill" href="#blocked">
+											<i class="bi bi-exclamation-circle"></i> Blocked
+										</a>
+									</li>
+								</ul>
path: TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Beep boop. Status-based tab layout is well done.**  
Consider load performance if tasks become very large. Lazy-loading could help.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T12:19:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -332,103 +417,252 @@
 
 
 @section Scripts {
-
 	<script>
 		const projectId = "@Model.ProjectId";
 		const mainTabKey = `activeMainTab_project_${projectId}`;
 		const subTabKey = `activeSubTab_project_${projectId}`;
 		const lastVisitedId = localStorage.getItem("lastVisitedProjectId");
-		// localStorage.removeItem("activeMainTab");
-		// localStorage.removeItem("activeTaskSubTab");
-		// console.log(lastVisitedId);
+
 		if (lastVisitedId && lastVisitedId !== projectId) {
-			// Project changed — clear tabs
 			localStorage.removeItem(`activeMainTab_project_${lastVisitedId}`);
 			localStorage.removeItem(`activeSubTab_project_${lastVisitedId}`);
 		}
-		// else if (lastVisitedId && lastVisitedId == projectId) {
-		// 	alert(`You were in this tab of this project (ProjectId=${projectId})!!`);
-		// }
-
 
 		$(document).ready(function () {
+			// Task Create Form
 			$('#taskForm').on('submit', function (e) {
 				e.preventDefault();
-
-				// var formData = $(this).serialize();
-
-				var formData = new FormData(this);  // Using FormData to handle file uploads
-
-
-				console.log(formData);
+				const formData = new FormData(this);
 
 				$.ajax({
 					type: 'POST',
 					url: $(this).attr('action') || '/Task/Create',
 					data: formData,
-					processData: false,  // Don't process the data
-					contentType: false,  // Don't set content type header
-					success: function (response) {
+					processData: false,
+					contentType: false,
+					success: function () {
+						const selectedStatus = $('#taskForm select[name="Status"]').val();
+
 						$('#addTaskModal').modal('hide');
 						$('#taskForm')[0].reset();
 
+						// Map status values to tab IDs
+						const statusToTab = {
+							0: '#todo',
+							1: '#inprogress',
+							2: '#completed', 
+							3: '#blocked'
+						};
 
+						// Save active main and sub tab so it opens where the task was added
+						localStorage.setItem(mainTabKey, "#tasks");
+
+						if (statusToTab[selectedStatus]) {
+							localStorage.setItem(subTabKey, statusToTab[selectedStatus]);
+						}
+
+						// Reload to reflect the new task under the correct tab
+						location.reload();
 					},
 					error: function (xhr, status, error) {
 						alert('Something went wrong: ' + error);
 					}
 				});
 			});
 
-
-			// Preserve Dashboard Tab Selection on Page Reload 
-			// (*** May need to clear on logout to avoid stale data when switching users ***)
-
-
-			// Load main tab and sub-tab from localStorage
+			// Tab persistence
 			const mainTab = localStorage.getItem(mainTabKey);
 			const taskSubTab = localStorage.getItem(subTabKey);
 
-			// if (mainTab) {
-			// 	// Activate saved main tab
-			// 	const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-			// 	if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
-			// 	else {
-			// 		// Fallback to default tab
-			// 		const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
-			// 		if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
-			// 	}
-			// }
-
 			if (mainTab) {
 				const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-				if (mainTabButton) {
-					new bootstrap.Tab(mainTabButton).show();
-				}
+				if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
 			} else {
-				// Nothing saved — fallback to Summary
 				const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
 				if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
 			}
 
-			// If we're on the Tasks tab, activate its sub-tab
 			if (mainTab === "#tasks" && taskSubTab) {
 				const subTabLink = document.querySelector(`#taskTabs a[href="${taskSubTab}"]`);
 				if (subTabLink) new bootstrap.Tab(subTabLink).show();
 			}
 
-			// Save main tab on click
+			// Save tab selections
 			$('#dashboardTabs button[data-bs-toggle="tab"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(mainTabKey, $(e.target).data("bs-target"));
 			});
-
-			// Save sub-tab in Tasks
 			$('#taskTabs a[data-bs-toggle="pill"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(subTabKey, $(e.target).attr("href"));
 			});
+
+			// 🆕 When task modal is opened, fetch task details
+			$('#taskDetailsModal').on('show.bs.modal', function (event) {
+				const button = $(event.relatedTarget); // Button that triggered the modal
+				const taskId = button.data('task-id');
+
+				if (!taskId) {
+					console.error("No taskId found on button");
+					return;
+				}
+
+				GetTaskDetails(taskId);
+			});
 		});
 
-		// Save current project ID for next time
+
+		// Save current project ID
 		localStorage.setItem("lastVisitedProjectId", projectId);
+
+
+		// Get task and populate modal
+		function GetTaskDetails(taskId) {
+
+			$.ajax({
+				url: `/Task/GetTask/${taskId}`,
+				method: 'GET',
+				success: function (data) {
+					console.log("Fetched Task Data:", data);
+
+					$('#task-id').val(data.id);
+					$('#task-title').val(data.title);
+					$('#task-description').val(data.description);
+					$('#task-status').val(data.status);
+					$('#task-priority').val(data.priority);
+					if (data.startDate && data.startDate.includes('T')) {
+						$('#task-startdate').val(data.startDate.split('T')[0]);
+					} else {
+						$('#task-startdate').val('');
+					}
+					if (data.dueDate && data.dueDate.includes('T')) {
+						$('#task-duedate').val(data.dueDate.split('T')[0]);
+					} else {
+						$('#task-duedate').val('');
+					}
+
+					// Members
+					$('#task-members').empty();
+					data.allUsers.forEach(user => {
+						const selected = data.assignedUserIds.includes(user.id) ? 'selected' : '';
+						$('#task-members').append(`<option value="${user.id}" ${selected}>${user.name}</option>`);
+					});
+
+					// Attachments
+					$('#task-attachment-list').empty();
+					data.attachments.forEach(att => {
+						$('#task-attachment-list').append(`
+							<li class="list-group-item d-flex justify-content-between align-items-center">
+								<a href="${att.downloadUrl}" target="_blank">${att.fileName}</a>
+								<button type="button" class="btn btn-sm btn-danger" onclick="RemoveAttachment(${att.id})">
+									<i class="bi bi-trash"></i>
+								</button>
+							</li>
+						`);
+					});
+				},
+				error: function (xhr) {
+					console.error("Failed to fetch task", xhr.responseText);
+					alert("Failed to load task.");
+				}
+			});
+		}
+
+
+		$('input[name="Attachments"]').on('change', function () {
+			const files = this.files;
+			let error = '';
+
+			if (files.length > 10) {
+				error = "You can't upload more than 10 files.";
+			} else {
+				for (let file of files) {
+					if (file.size > 10 * 1024 * 1024) {
+						error = `${file.name} is larger than 10MB.`;
+						break;
+					}
+				}
+			}
+
+			if (error) {
+				$('#attachments-error').text(error).show();
+				$(this).addClass('is-invalid');
+			} else {
+				$('#attachments-error').text('').hide();
+				$(this).removeClass('is-invalid');
+			}
+		});
+
+
+		// Task Edit Form Submission
+		$('#taskEditForm').on('submit', function (e) {
+			$(this).find('button[type="submit"]').prop('disabled', true); // prevents double submit
+
+			e.preventDefault();
+			const formData = new FormData(this);
+
+
+			const title = $('#task-title').val().trim();
+			const description = $('#task-description').val().trim();
+			const startDate = $('#task-startdate').val();
+			const dueDate = $('#task-duedate').val();
+			const attachments = $('#task-attachments')[0].files;
+
+			// Reset previous errors
+			$('.is-invalid').removeClass('is-invalid');
+
+			let hasError = false;
+
+			// Title length
+			if (title.length === 0 || title.length > 200) {
+				$('#task-title').addClass('is-invalid');
+				hasError = true;
+			}
+
+			// Description length
+			if (description.length > 1000) {
+				$('#task-description').addClass('is-invalid');
+				hasError = true;
+			}
+
+			// DueDate >= StartDate
+			if (startDate && dueDate && new Date(dueDate) < new Date(startDate)) {
+				$('#task-duedate').addClass('is-invalid');
+				hasError = true;
+			}
+			if (attachments.length > 10) {
+				$('#attachments-error').text("You can't upload more than 10 files.").show();
+				$('input[name="Attachments"]').addClass('is-invalid');
+				hasError = true;
+			} else {
+				for (let file of attachments) {
+					if (file.size > 10 * 1024 * 1024) {
+						$('#attachments-error').text(`${file.name} is larger than 10MB.`).show();
+						$('input[name="Attachments"]').addClass('is-invalid');
+						hasError = true;
+						break;
+					}
+				}
+			}
+
+			if (hasError) {
+				$(this).find('button[type="submit"]').prop('disabled', false); // Re-enable button
+				return;
+			}
+
+			$.ajax({
+				url: '/Task/UpdateTask',
+				type: 'POST',
+				data: formData,
+				processData: false,
+				contentType: false,
+				success: () => {
+					$('#taskDetailsModal').modal('hide');
+					location.reload();
+				},
+				error: function (xhr) {
+					alert("Failed to update task. Check console for details.");
+					console.error(xhr.responseText);
+				}
+			});
+		});
path: TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Beep boop. Complex form submission.**  
Well-done verifying length constraints and date ordering. Checking `ModelState` serverside is also recommended.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T12:19:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -332,103 +417,252 @@
 
 
 @section Scripts {
-
 	<script>
 		const projectId = "@Model.ProjectId";
 		const mainTabKey = `activeMainTab_project_${projectId}`;
 		const subTabKey = `activeSubTab_project_${projectId}`;
 		const lastVisitedId = localStorage.getItem("lastVisitedProjectId");
-		// localStorage.removeItem("activeMainTab");
-		// localStorage.removeItem("activeTaskSubTab");
-		// console.log(lastVisitedId);
+
 		if (lastVisitedId && lastVisitedId !== projectId) {
-			// Project changed — clear tabs
 			localStorage.removeItem(`activeMainTab_project_${lastVisitedId}`);
 			localStorage.removeItem(`activeSubTab_project_${lastVisitedId}`);
 		}
-		// else if (lastVisitedId && lastVisitedId == projectId) {
-		// 	alert(`You were in this tab of this project (ProjectId=${projectId})!!`);
-		// }
-
 
 		$(document).ready(function () {
+			// Task Create Form
 			$('#taskForm').on('submit', function (e) {
 				e.preventDefault();
-
-				// var formData = $(this).serialize();
-
-				var formData = new FormData(this);  // Using FormData to handle file uploads
-
-
-				console.log(formData);
+				const formData = new FormData(this);
 
 				$.ajax({
 					type: 'POST',
 					url: $(this).attr('action') || '/Task/Create',
 					data: formData,
-					processData: false,  // Don't process the data
-					contentType: false,  // Don't set content type header
-					success: function (response) {
+					processData: false,
+					contentType: false,
+					success: function () {
+						const selectedStatus = $('#taskForm select[name="Status"]').val();
+
 						$('#addTaskModal').modal('hide');
 						$('#taskForm')[0].reset();
 
+						// Map status values to tab IDs
+						const statusToTab = {
+							0: '#todo',
+							1: '#inprogress',
+							2: '#completed', 
+							3: '#blocked'
+						};
 
+						// Save active main and sub tab so it opens where the task was added
+						localStorage.setItem(mainTabKey, "#tasks");
+
+						if (statusToTab[selectedStatus]) {
+							localStorage.setItem(subTabKey, statusToTab[selectedStatus]);
+						}
+
+						// Reload to reflect the new task under the correct tab
+						location.reload();
 					},
 					error: function (xhr, status, error) {
 						alert('Something went wrong: ' + error);
 					}
 				});
 			});
 
path: TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Beep boop. Ajax form submission for creating tasks is dynamic.**  
Ensure to handle partial failures (e.g., attachments failing to upload).

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T12:19:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -332,103 +417,252 @@
 
 
 @section Scripts {
-
 	<script>
 		const projectId = "@Model.ProjectId";
 		const mainTabKey = `activeMainTab_project_${projectId}`;
 		const subTabKey = `activeSubTab_project_${projectId}`;
 		const lastVisitedId = localStorage.getItem("lastVisitedProjectId");
-		// localStorage.removeItem("activeMainTab");
-		// localStorage.removeItem("activeTaskSubTab");
-		// console.log(lastVisitedId);
+
 		if (lastVisitedId && lastVisitedId !== projectId) {
-			// Project changed — clear tabs
 			localStorage.removeItem(`activeMainTab_project_${lastVisitedId}`);
 			localStorage.removeItem(`activeSubTab_project_${lastVisitedId}`);
 		}
-		// else if (lastVisitedId && lastVisitedId == projectId) {
-		// 	alert(`You were in this tab of this project (ProjectId=${projectId})!!`);
-		// }
-
 
 		$(document).ready(function () {
+			// Task Create Form
 			$('#taskForm').on('submit', function (e) {
 				e.preventDefault();
-
-				// var formData = $(this).serialize();
-
-				var formData = new FormData(this);  // Using FormData to handle file uploads
-
-
-				console.log(formData);
+				const formData = new FormData(this);
 
 				$.ajax({
 					type: 'POST',
 					url: $(this).attr('action') || '/Task/Create',
 					data: formData,
-					processData: false,  // Don't process the data
-					contentType: false,  // Don't set content type header
-					success: function (response) {
+					processData: false,
+					contentType: false,
+					success: function () {
+						const selectedStatus = $('#taskForm select[name="Status"]').val();
+
 						$('#addTaskModal').modal('hide');
 						$('#taskForm')[0].reset();
 
+						// Map status values to tab IDs
+						const statusToTab = {
+							0: '#todo',
+							1: '#inprogress',
+							2: '#completed', 
+							3: '#blocked'
+						};
 
+						// Save active main and sub tab so it opens where the task was added
+						localStorage.setItem(mainTabKey, "#tasks");
+
+						if (statusToTab[selectedStatus]) {
+							localStorage.setItem(subTabKey, statusToTab[selectedStatus]);
+						}
+
+						// Reload to reflect the new task under the correct tab
+						location.reload();
 					},
 					error: function (xhr, status, error) {
 						alert('Something went wrong: ' + error);
 					}
 				});
 			});
 
-
-			// Preserve Dashboard Tab Selection on Page Reload 
-			// (*** May need to clear on logout to avoid stale data when switching users ***)
-
-
-			// Load main tab and sub-tab from localStorage
+			// Tab persistence
 			const mainTab = localStorage.getItem(mainTabKey);
 			const taskSubTab = localStorage.getItem(subTabKey);
 
-			// if (mainTab) {
-			// 	// Activate saved main tab
-			// 	const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-			// 	if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
-			// 	else {
-			// 		// Fallback to default tab
-			// 		const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
-			// 		if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
-			// 	}
-			// }
-
 			if (mainTab) {
 				const mainTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="${mainTab}"]`);
-				if (mainTabButton) {
-					new bootstrap.Tab(mainTabButton).show();
-				}
+				if (mainTabButton) new bootstrap.Tab(mainTabButton).show();
 			} else {
-				// Nothing saved — fallback to Summary
 				const defaultTabButton = document.querySelector(`#dashboardTabs button[data-bs-target="#summary"]`);
 				if (defaultTabButton) new bootstrap.Tab(defaultTabButton).show();
 			}
 
-			// If we're on the Tasks tab, activate its sub-tab
 			if (mainTab === "#tasks" && taskSubTab) {
 				const subTabLink = document.querySelector(`#taskTabs a[href="${taskSubTab}"]`);
 				if (subTabLink) new bootstrap.Tab(subTabLink).show();
 			}
 
-			// Save main tab on click
+			// Save tab selections
 			$('#dashboardTabs button[data-bs-toggle="tab"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(mainTabKey, $(e.target).data("bs-target"));
 			});
-
-			// Save sub-tab in Tasks
 			$('#taskTabs a[data-bs-toggle="pill"]').on('shown.bs.tab', function (e) {
 				localStorage.setItem(subTabKey, $(e.target).attr("href"));
 			});
+
+			// 🆕 When task modal is opened, fetch task details
+			$('#taskDetailsModal').on('show.bs.modal', function (event) {
+				const button = $(event.relatedTarget); // Button that triggered the modal
+				const taskId = button.data('task-id');
+
+				if (!taskId) {
+					console.error("No taskId found on button");
+					return;
+				}
+
+				GetTaskDetails(taskId);
+			});
 		});
 
-		// Save current project ID for next time
+
+		// Save current project ID
 		localStorage.setItem("lastVisitedProjectId", projectId);
+
+
+		// Get task and populate modal
+		function GetTaskDetails(taskId) {
+
+			$.ajax({
+				url: `/Task/GetTask/${taskId}`,
+				method: 'GET',
+				success: function (data) {
+					console.log("Fetched Task Data:", data);
+
+					$('#task-id').val(data.id);
+					$('#task-title').val(data.title);
+					$('#task-description').val(data.description);
+					$('#task-status').val(data.status);
+					$('#task-priority').val(data.priority);
+					if (data.startDate && data.startDate.includes('T')) {
+						$('#task-startdate').val(data.startDate.split('T')[0]);
+					} else {
+						$('#task-startdate').val('');
+					}
+					if (data.dueDate && data.dueDate.includes('T')) {
+						$('#task-duedate').val(data.dueDate.split('T')[0]);
+					} else {
+						$('#task-duedate').val('');
+					}
+
+					// Members
+					$('#task-members').empty();
+					data.allUsers.forEach(user => {
+						const selected = data.assignedUserIds.includes(user.id) ? 'selected' : '';
+						$('#task-members').append(`<option value="${user.id}" ${selected}>${user.name}</option>`);
+					});
+
+					// Attachments
+					$('#task-attachment-list').empty();
+					data.attachments.forEach(att => {
+						$('#task-attachment-list').append(`
+							<li class="list-group-item d-flex justify-content-between align-items-center">
+								<a href="${att.downloadUrl}" target="_blank">${att.fileName}</a>
+								<button type="button" class="btn btn-sm btn-danger" onclick="RemoveAttachment(${att.id})">
+									<i class="bi bi-trash"></i>
+								</button>
+							</li>
+						`);
+					});
+				},
+				error: function (xhr) {
+					console.error("Failed to fetch task", xhr.responseText);
+					alert("Failed to load task.");
+				}
+			});
+		}
+
+
+		$('input[name="Attachments"]').on('change', function () {
+			const files = this.files;
+			let error = '';
+
+			if (files.length > 10) {
+				error = "You can't upload more than 10 files.";
+			} else {
+				for (let file of files) {
+					if (file.size > 10 * 1024 * 1024) {
+						error = `${file.name} is larger than 10MB.`;
+						break;
+					}
+				}
+			}
+
+			if (error) {
+				$('#attachments-error').text(error).show();
+				$(this).addClass('is-invalid');
+			} else {
+				$('#attachments-error').text('').hide();
+				$(this).removeClass('is-invalid');
+			}
+		});
path: TaskForge.NET/TaskForge.WebUI/Views/Project/Dashboard.cshtml
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Beep boop. Attachment size checks are user-friendly.**  
Consider offering immediate size feedback before the form submission.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T12:19:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -42,6 +46,68 @@ public async Task<IActionResult> Create([FromForm] TaskItemCreateViewModel model
 
             return Ok(new { success = true });
         }
-    }
+
+
+		[HttpGet("Tasks/GetTaskById/{id}")]
+		public async Task<IActionResult> GetTaskDetailsById(int id)
+		{
+			var task = await _taskService.GetTaskByIdAsync(id);
+			if (task == null) return NotFound();
+
+			return Ok(new
+			{
+				task.Id,
+				task.Title,
+				task.Description,
+				StartDate = task.StartDate?.ToString("g"),
+				DueDate = task.DueDate?.ToString("g"),
+				Status = task.Status.ToString(),
+				Priority = task.Priority.ToString(),
+				AssignedUsers = task.AssignedUsers.Select(a => new { a.UserProfile.FullName }),
+				Attachments = task.Attachments.Select(a => new { a.FileName, a.FilePath })
+			});
+		}
+
+
+		[HttpGet]
+		public async Task<IActionResult> GetTask(int id)
+		{
+			var task = await _taskService.GetTaskByIdAsync(id);
+			if (task == null) return NotFound();
+
+			var allUsers = await _projectMemberService.GetProjectMembersAsync(task.ProjectId);
+			return Json(new
+			{
+				id = task.Id,
+				title = task.Title,
+				description = task.Description,
+				startDate = task.StartDate?.ToString("yyyy-MM-ddTHH:mm"),
+				dueDate = task.DueDate?.ToString("yyyy-MM-ddTHH:mm"),
+				status = (int)task.Status,
+				priority = (int)task.Priority,
+				attachments = task.Attachments.Select(a => new
+				{
+					id = a.Id,
+					fileName = a.FileName,
+					downloadUrl = Url.Action("Download", "Attachment", new { id = a.Id })
+				}),
+				assignedUserIds = task.AssignedUsers.Select(u => u.UserProfileId),
+				allUsers = allUsers.Select(u => new { id = u.UserProfileId, name = u.Name })
+			});
+		}
+
+
+		[HttpPost]
+		public async Task<IActionResult> UpdateTask(TaskUpdateDto dto)
+		{
+			if (!ModelState.IsValid)
+				return BadRequest(ModelState);
+
+			await _taskService.UpdateTaskAsync(dto);
+
+			return Ok();
+		}
path: TaskForge.NET/TaskForge.WebUI/Controllers/TaskController.cs
user: login: coderabbitai[bot]
body: _🧹 Nitpick (assertive)_

**Beep boop. “UpdateTask” ensures ModelState validation.**  
Implementation is short and clear. Optionally add logging if needed for debugging.

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-11T12:19:44Z
author_association: CONTRIBUTOR

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-11T11:45:30Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

## Summary by CodeRabbit

- **New Features**
  - Introduced an interactive modal for editing tasks, allowing users to update task details seamlessly.
  - Enhanced task views to display complete project titles and detailed information about assigned users.

- **Style**
  - Refined task cards with clear labels, formatted start/end dates, and intuitive status icons.
  - Simplified date inputs in task forms for a smoother user data entry experience.
  - Updated table headers on the home page for improved clarity.
## Walkthrough
The changes update various components of TaskForge. A new rule is added to `.gitignore` to ignore media files in any uploads directory. Several DTOs now include additional properties to represent project and user data. New DTOs for task updates and new service methods in both task and user profile interfaces have been introduced. Controllers and views have been enhanced with modal-based task editing, updated layouts, and date input modifications. Error handling in the task entity has been refined, and overall, the codebase now supports improved task management and assignment functionality.

## Changes

| File(s) | Change Summary |
|---------|----------------|
| `.gitignore` | Added rule `**/uploads` to ignore all files in any uploads directory. |
| `TaskForge.NET/.../DTOs/ProjectMemberDto.cs`, `TaskDto.cs`, `TaskUpdateDto.cs` | Added properties (`ProjectId`, `UserProfileId`, `ProjectTitle`) and introduced new `TaskUpdateDto` for task updates. |
| `TaskForge.NET/.../Interfaces/Services/ITaskService.cs`, `IUserProfileService.cs` | Added new methods `GetTaskByIdAsync` and `UpdateTaskAsync` in ITaskService; added using directive and formatting improvements in IUserProfileService. |
| `TaskForge.NET/.../Services/ProjectMemberService.cs`, `TaskService.cs`, `UserProfileService.cs` | Updated service implementations to assign new DTO properties, added task retrieval/update methods, and applied minor formatting adjustments. |
| `TaskForge.NET/.../Domain/Entities/TaskItem.cs` | Modified `SetDueDate` method to throw `ValidationException` instead of `ArgumentException`. |
| `TaskForge.NET/.../Controllers/HomeController.cs`, `ProjectController.cs`, `TaskController.cs` | Enhanced controllers by adding new action methods (GetTaskDetailsById, GetTask, UpdateTask) and updating view model properties (e.g., TotalProjects) and dependency injections. |
| `TaskForge.NET/.../Models/TaskItemViewModel.cs` | Added new `TaskAssignmentViewModel` class and an `AssignedUsers` property to support user assignments on tasks. |
| `TaskForge.NET/.../Views/Home/Index.cshtml`, `Project/Dashboard.cshtml`, `Task/PartialViews/_AddTaskForm.cshtml`, `Task/PartialViews/_TaskCard.cshtml` | Modified views: Updated table headers and data sources, added modal for task editing with associated JavaScript, changed date input types, and restructured task card layout to display assigned users. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant U as User
    participant UI as Web UI (Dashboard Modal)
    participant TC as TaskController
    participant TS as TaskService

    U->>UI: Trigger "Edit Task" modal open
    UI->>TC: GET /GetTaskDetailsById(id)
    TC->>TS: GetTaskByIdAsync(id)
    TS-->>TC: Return task details (including AssignedUsers)
    TC-->>UI: Send JSON response with task details
    UI->>U: Populate modal with task data
```

```mermaid
sequenceDiagram
    participant U as User
    participant UI as Web UI (Task Edit Modal)
    participant TC as TaskController
    participant TS as TaskService

    U->>UI: Submit updated task data via modal
    UI->>TC: POST /UpdateTask(dto)
    TC->>TS: UpdateTaskAsync(dto)
    TS-->>TC: Process update and return result
    TC-->>UI: Respond with 200 OK or error message
    UI->>U: Notify update success/failure
```

## Poem
> In circuits and code we compile our verse,  
> Each change precise in our binary universe.  
> DTOs expand and modals now gleam,  
> Tasks update in a seamless dream.  
> Our geeky bots dance, algorithms on fire,  
> Celebrating code with digital desire!  
> 🤖✨

</details>

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!TIP]
> <details>
> <summary>⚡💬 Agentic Chat (Pro Plan, General Availability)</summary>
> 
> - We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=Learnathon-By-Geeky-Solutions/brainstormers&utm_content=58):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: Warhammer4000
created_at: 2025-04-11T11:45:36Z
body: ![](https://res.cloudinary.com/snyk/image/upload/r-d/scm-platform/snyk-pull-requests/pr-banner-default.svg)

### :tada: **Snyk checks have passed. No issues have been found so far.**

:white_check_mark: **security/snyk** check is complete. No issues have been found. [(View Details)](https://app.snyk.io/org/warhammer4000/pr-checks/d37a2c55-2adf-4643-8bee-e40c12b4614a?refs=f905c3a208ceb771c4e31f46c43784617379de10&source=prChecksComment)



author_association: CONTRIBUTOR
user: login: sonarqubecloud[bot]
created_at: 2025-04-11T12:19:10Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=Learnathon-By-Geeky-Solutions_brainstormers&pullRequest=58) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [9 New issues](https://sonarcloud.io/project/issues?id=Learnathon-By-Geeky-Solutions_brainstormers&pullRequest=58&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=Learnathon-By-Geeky-Solutions_brainstormers&pullRequest=58&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=Learnathon-By-Geeky-Solutions_brainstormers&pullRequest=58&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=Learnathon-By-Geeky-Solutions_brainstormers&pullRequest=58&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=Learnathon-By-Geeky-Solutions_brainstormers&pullRequest=58&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=Learnathon-By-Geeky-Solutions_brainstormers&pullRequest=58)


author_association: NONE