From 06bde26affaa98e7eb93e0d36fefd466a0da2472 Mon Sep 17 00:00:00 2001 From: Adam Moussa <166072409+amoussa1229@users.noreply.github.com> Date: Mon, 20 Apr 2026 13:49:45 -0400 Subject: [PATCH] Wire FollowUp controller for real CRUD Adds GetById and Delete; switches list filter from completed=bool to status=string; expands list payload with FK ids, ScheduleStartTime, and joined CreatedByName so the frontend edit form can prefill and the list can show who created each item. Requires auth and stamps createdby from the logged-in user on Create. --- .../Controllers/FollowUpController.cs | 152 +++++++++++++++--- 1 file changed, 133 insertions(+), 19 deletions(-) diff --git a/Api.SeaHavenIndustries/Controllers/FollowUpController.cs b/Api.SeaHavenIndustries/Controllers/FollowUpController.cs index 751f27d..9793ea6 100644 --- a/Api.SeaHavenIndustries/Controllers/FollowUpController.cs +++ b/Api.SeaHavenIndustries/Controllers/FollowUpController.cs @@ -1,28 +1,34 @@ -using Api.SeaHavenIndustries.DTOs; +using System.Security.Claims; +using Api.SeaHavenIndustries.DTOs; using Data.SeaHavenIndustries; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; [ApiController] +[Authorize] [Route("api/FollowUp")] [Route("api/followups")] public class FollowUpController : ControllerBase { private readonly ApplicationDbContext _db; + private readonly UserManager _users; - public FollowUpController(ApplicationDbContext db) + public FollowUpController(ApplicationDbContext db, UserManager users) { _db = db; + _users = users; } [HttpGet("GetFollowUpList")] - public IActionResult GetFollowUps( + public async Task GetFollowUps( string? search = "", - bool completed = false, + string? status = "Open", int page = 1, int pageSize = 12) { - var status = completed ? "Completed" : "Open"; + status = string.IsNullOrWhiteSpace(status) ? "Open" : status; var query = _db.FollowUps .Include(x => x.Employee) @@ -33,24 +39,21 @@ public class FollowUpController : ControllerBase if (!string.IsNullOrWhiteSpace(search)) { - search = search.ToLower(); + var s = search.ToLower(); query = query.Where(x => - (x.Reason ?? "").ToLower().Contains(search) || - (x.Account != null && (x.Account.Name ?? "").ToLower().Contains(search)) || + (x.Reason ?? "").ToLower().Contains(s) || + (x.Account != null && (x.Account.Name ?? "").ToLower().Contains(s)) || (x.Employee != null && - ( - ((x.Employee.FirstName ?? "") + " " + (x.Employee.LastName ?? "")) - .ToLower() - .Contains(search) - ) + (((x.Employee.FirstName ?? "") + " " + (x.Employee.LastName ?? "")) + .ToLower().Contains(s)) ) ); } - var totalCount = query.Count(); + var totalCount = await query.CountAsync(); - var data = query + var rows = await query .OrderByDescending(x => x.Id) .Skip((page - 1) * pageSize) .Take(pageSize) @@ -59,16 +62,63 @@ public class FollowUpController : ControllerBase x.Id, x.Reason, x.ScheduleDate, - Account = x.Account != null ? x.Account.Name : "", + x.ScheduleStartTime, + x.EmployeeId, + x.WorkOrderId, + x.AccountId, + x.LocationId, + AccountName = x.Account != null ? x.Account.Name : "", AssignedTo = x.Employee != null ? (x.Employee.FirstName + " " + x.Employee.LastName) : "", LocationName = x.Location != null ? x.Location.Name : "", WorkOrderNumber = x.WorkOrder != null ? x.WorkOrder.WorkerOrderNumber : "", - x.Status + InternalWONumber = x.WorkOrder != null ? x.WorkOrder.InternalWONumber : "", + x.Status, + x.CreatedDate, + CreatedById = x.createdby }) + .ToListAsync(); + + var creatorIds = rows + .Select(r => r.CreatedById) + .Where(id => !string.IsNullOrEmpty(id)) + .Distinct() .ToList(); + var creators = await _db.Users + .Where(u => creatorIds.Contains(u.Id)) + .Select(u => new { u.Id, u.FirstName, u.LastName, u.UserName }) + .ToDictionaryAsync(u => u.Id, u => u); + + string NameFor(string? userId) + { + if (string.IsNullOrEmpty(userId) || !creators.TryGetValue(userId, out var u)) return ""; + var full = ((u.FirstName ?? "") + " " + (u.LastName ?? "")).Trim(); + return string.IsNullOrWhiteSpace(full) ? (u.UserName ?? "") : full; + } + + var data = rows.Select(r => new + { + r.Id, + r.Reason, + r.ScheduleDate, + r.ScheduleStartTime, + r.EmployeeId, + r.WorkOrderId, + r.AccountId, + r.LocationId, + r.AccountName, + r.AssignedTo, + r.LocationName, + r.WorkOrderNumber, + r.InternalWONumber, + r.Status, + r.CreatedDate, + r.CreatedById, + CreatedByName = NameFor(r.CreatedById) + }).ToList(); + return Ok(new Pagination_DTO { Data = data, @@ -79,10 +129,61 @@ public class FollowUpController : ControllerBase }); } + [HttpGet("GetById")] + public async Task GetById(int id) + { + var model = await _db.FollowUps + .Include(x => x.Employee) + .Include(x => x.Account) + .Include(x => x.Location) + .Include(x => x.WorkOrder) + .FirstOrDefaultAsync(x => x.Id == id); + + if (model == null) return NotFound(); + + string createdByName = ""; + if (!string.IsNullOrEmpty(model.createdby)) + { + var u = await _db.Users + .Where(x => x.Id == model.createdby) + .Select(x => new { x.FirstName, x.LastName, x.UserName }) + .FirstOrDefaultAsync(); + if (u != null) + { + var n = ((u.FirstName ?? "") + " " + (u.LastName ?? "")).Trim(); + createdByName = string.IsNullOrWhiteSpace(n) ? (u.UserName ?? "") : n; + } + } + + return Ok(new + { + model.Id, + model.Reason, + model.ScheduleDate, + model.ScheduleStartTime, + model.EmployeeId, + model.WorkOrderId, + model.AccountId, + model.LocationId, + AccountName = model.Account?.Name ?? "", + AssignedTo = model.Employee != null + ? (model.Employee.FirstName + " " + model.Employee.LastName) + : "", + LocationName = model.Location?.Name ?? "", + WorkOrderNumber = model.WorkOrder?.WorkerOrderNumber ?? "", + InternalWONumber = model.WorkOrder?.InternalWONumber ?? "", + model.Status, + model.CreatedDate, + CreatedById = model.createdby, + CreatedByName = createdByName + }); + } [HttpPost("Create")] public async Task Create(FollowUp_DTO dto) { + var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); + var model = new FollowUps { Reason = dto.Reason, @@ -93,13 +194,14 @@ public class FollowUpController : ControllerBase AccountId = dto.AccountId, LocationId = dto.LocationId, Status = "Open", - CreatedDate = DateTime.UtcNow + CreatedDate = DateTime.UtcNow, + createdby = userId }; _db.FollowUps.Add(model); await _db.SaveChangesAsync(); - return Ok(new DataResponse { Status = "200", Message = "Follow Up created" }); + return Ok(new DataResponse { Status = "200", Message = "Follow Up created", Data = model.Id }); } [HttpPost("Update")] @@ -146,4 +248,16 @@ public class FollowUpController : ControllerBase return Ok(); } + + [HttpPost("Delete")] + public async Task Delete(int id) + { + var model = await _db.FollowUps.FindAsync(id); + if (model == null) return NotFound(); + + _db.FollowUps.Remove(model); + await _db.SaveChangesAsync(); + + return Ok(new DataResponse { Status = "200", Message = "Follow Up deleted" }); + } }