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.
This commit is contained in:
Adam Moussa 2026-04-20 13:49:45 -04:00
parent 899ee7b83d
commit 06bde26aff

View file

@ -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<ApplicationUser> _users;
public FollowUpController(ApplicationDbContext db)
public FollowUpController(ApplicationDbContext db, UserManager<ApplicationUser> users)
{
_db = db;
_users = users;
}
[HttpGet("GetFollowUpList")]
public IActionResult GetFollowUps(
public async Task<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> 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" });
}
}