mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 09:33:13 +00:00
calander
This commit is contained in:
parent
a9fc4b8701
commit
19994ef725
7 changed files with 1000 additions and 11 deletions
306
Api.SeaHavenIndustries/Controllers/CalendarController.cs
Normal file
306
Api.SeaHavenIndustries/Controllers/CalendarController.cs
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Api.SeaHavenIndustries.DTOs;
|
||||
using Data.SeaHavenIndustries;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Api.SeaHavenIndustries.Controllers
|
||||
{
|
||||
//[Authorize] // Uncomment when authentication is needed
|
||||
[ApiController]
|
||||
[Route("api/Calendar")]
|
||||
public class CalendarController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly ApplicationDbContext _db;
|
||||
|
||||
public CalendarController(UserManager<ApplicationUser> userManager, ApplicationDbContext db)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// CREATE EVENT
|
||||
// ===================================================================================
|
||||
[HttpPost]
|
||||
[Route("AddEvent")]
|
||||
public async Task<IActionResult> AddEvent(EditEvent_DTO eventDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var model = new Events
|
||||
{
|
||||
Title = eventDto.Title,
|
||||
Description = eventDto.Description,
|
||||
Location = eventDto.Location,
|
||||
RecordID = eventDto.RecordID,
|
||||
RecordName = eventDto.RecordName,
|
||||
RecordTargetType = eventDto.RecordTargetType,
|
||||
ReminderMinutes = eventDto.ReminderMinutes,
|
||||
EventColor = eventDto.EventColor,
|
||||
StartDate = eventDto.StartDate,
|
||||
StartTime = eventDto.StartTime,
|
||||
EndDate = eventDto.EndDate,
|
||||
EndTime = eventDto.EndTime,
|
||||
AllDay = eventDto.AllDay,
|
||||
CreatedDate = DateTime.Now,
|
||||
IsDeleted = false
|
||||
};
|
||||
|
||||
_db.Events.Add(model);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
return Ok(new DataResponse { Message = "Event Created Successfully", Status = "200" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// UPDATE EVENT
|
||||
// ===================================================================================
|
||||
[HttpPost]
|
||||
[Route("EditEvent")]
|
||||
public async Task<IActionResult> EditEvent(EditEvent_DTO eventDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!eventDto.Id.HasValue)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = "Event ID is required for editing" });
|
||||
}
|
||||
|
||||
var model = await _db.Events.FindAsync(eventDto.Id.Value);
|
||||
if (model == null || model.IsDeleted == true)
|
||||
{
|
||||
return NotFound(new Response { Status = "Error", Message = "Event not found" });
|
||||
}
|
||||
|
||||
model.Title = eventDto.Title;
|
||||
model.Description = eventDto.Description;
|
||||
model.Location = eventDto.Location;
|
||||
model.RecordID = eventDto.RecordID;
|
||||
model.RecordName = eventDto.RecordName;
|
||||
model.RecordTargetType = eventDto.RecordTargetType;
|
||||
model.ReminderMinutes = eventDto.ReminderMinutes;
|
||||
model.EventColor = eventDto.EventColor;
|
||||
model.StartDate = eventDto.StartDate;
|
||||
model.StartTime = eventDto.StartTime;
|
||||
model.EndDate = eventDto.EndDate;
|
||||
model.EndTime = eventDto.EndTime;
|
||||
model.AllDay = eventDto.AllDay;
|
||||
model.LastModificationTime = DateTime.Now;
|
||||
|
||||
_db.Events.Update(model);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
return Ok(new DataResponse { Message = "Event Updated Successfully", Status = "200" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// GET EVENT BY ID
|
||||
// ===================================================================================
|
||||
[HttpGet]
|
||||
[Route("GetEventById/{id}")]
|
||||
public async Task<IActionResult> GetEventById(int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var model = await _db.Events
|
||||
.Where(e => e.Id == id && e.IsDeleted != true)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (model == null)
|
||||
{
|
||||
return NotFound(new Response { Status = "Error", Message = "Event not found" });
|
||||
}
|
||||
|
||||
var dto = new Event_DTO
|
||||
{
|
||||
Id = model.Id,
|
||||
Title = model.Title,
|
||||
Description = model.Description,
|
||||
Location = model.Location,
|
||||
RecordID = model.RecordID,
|
||||
RecordName = model.RecordName,
|
||||
RecordTargetType = model.RecordTargetType,
|
||||
ReminderMinutes = model.ReminderMinutes,
|
||||
EventColor = model.EventColor,
|
||||
StartDate = model.StartDate,
|
||||
StartTime = model.StartTime,
|
||||
EndDate = model.EndDate,
|
||||
EndTime = model.EndTime,
|
||||
AllDay = model.AllDay,
|
||||
CreatedDate = model.CreatedDate,
|
||||
createdby = model.createdby
|
||||
};
|
||||
|
||||
return Ok(new DataResponse { Message = "Success", Status = "200", Data = dto });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// DELETE EVENT
|
||||
// ===================================================================================
|
||||
[HttpDelete]
|
||||
[Route("DeleteEvent/{id}")]
|
||||
public async Task<IActionResult> DeleteEvent(int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var model = await _db.Events.FindAsync(id);
|
||||
if (model == null)
|
||||
{
|
||||
return NotFound(new Response { Status = "Error", Message = "Event not found" });
|
||||
}
|
||||
|
||||
// Soft delete
|
||||
model.IsDeleted = true;
|
||||
model.DeletionTime = DateTime.Now;
|
||||
|
||||
_db.Events.Update(model);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
return Ok(new DataResponse { Message = "Event Deleted Successfully", Status = "200" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// GET EVENTS LIST (WITH PAGINATION AND FILTERS)
|
||||
// ===================================================================================
|
||||
[HttpGet]
|
||||
[Route("GetEventList")]
|
||||
public IActionResult GetEventList(string? search = "", int page = 1, int pageSize = 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
var query = _db.Events.Where(e => e.IsDeleted != true);
|
||||
|
||||
// Apply search filter if provided
|
||||
if (!string.IsNullOrWhiteSpace(search))
|
||||
{
|
||||
var searchLower = search.ToLower();
|
||||
query = query.Where(e =>
|
||||
e.Title.ToLower().Contains(searchLower) ||
|
||||
(e.Description != null && e.Description.ToLower().Contains(searchLower)) ||
|
||||
(e.Location != null && e.Location.ToLower().Contains(searchLower))
|
||||
);
|
||||
}
|
||||
|
||||
// IMPORTANT: Calculate totalCount AFTER applying filters
|
||||
var totalCount = query.Count();
|
||||
|
||||
// Apply pagination
|
||||
var events = query
|
||||
.OrderByDescending(e => e.StartDate)
|
||||
.ThenByDescending(e => e.CreatedDate)
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.Select(e => new Event_DTO
|
||||
{
|
||||
Id = e.Id,
|
||||
Title = e.Title,
|
||||
Description = e.Description,
|
||||
Location = e.Location,
|
||||
RecordID = e.RecordID,
|
||||
RecordName = e.RecordName,
|
||||
RecordTargetType = e.RecordTargetType,
|
||||
ReminderMinutes = e.ReminderMinutes,
|
||||
EventColor = e.EventColor,
|
||||
StartDate = e.StartDate,
|
||||
StartTime = e.StartTime,
|
||||
EndDate = e.EndDate,
|
||||
EndTime = e.EndTime,
|
||||
AllDay = e.AllDay,
|
||||
CreatedDate = e.CreatedDate,
|
||||
createdby = e.createdby
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return Ok(new DataResponse
|
||||
{
|
||||
Message = "Success",
|
||||
Status = "200",
|
||||
Data = new { rows = events, totalCount }
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// GET EVENTS FOR CALENDAR (Date Range Filter)
|
||||
// ===================================================================================
|
||||
[HttpGet]
|
||||
[Route("GetEventsForCalendar")]
|
||||
public IActionResult GetEventsForCalendar([FromQuery] DateTime? start, [FromQuery] DateTime? end)
|
||||
{
|
||||
try
|
||||
{
|
||||
var query = _db.Events.Where(e => e.IsDeleted != true);
|
||||
|
||||
// Filter by date range if provided
|
||||
if (start.HasValue && end.HasValue)
|
||||
{
|
||||
query = query.Where(e =>
|
||||
(e.StartDate >= start.Value && e.StartDate <= end.Value) ||
|
||||
(e.EndDate >= start.Value && e.EndDate <= end.Value) ||
|
||||
(e.StartDate <= start.Value && e.EndDate >= end.Value)
|
||||
);
|
||||
}
|
||||
|
||||
var events = query
|
||||
.Select(e => new Event_DTO
|
||||
{
|
||||
Id = e.Id,
|
||||
Title = e.Title,
|
||||
Description = e.Description,
|
||||
Location = e.Location,
|
||||
RecordID = e.RecordID,
|
||||
RecordName = e.RecordName,
|
||||
RecordTargetType = e.RecordTargetType,
|
||||
ReminderMinutes = e.ReminderMinutes,
|
||||
EventColor = e.EventColor,
|
||||
StartDate = e.StartDate,
|
||||
StartTime = e.StartTime,
|
||||
EndDate = e.EndDate,
|
||||
EndTime = e.EndTime,
|
||||
AllDay = e.AllDay,
|
||||
CreatedDate = e.CreatedDate,
|
||||
createdby = e.createdby
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return Ok(new DataResponse { Message = "Success", Status = "200", Data = events });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
48
Api.SeaHavenIndustries/DTOs/EditEvent_DTO.cs
Normal file
48
Api.SeaHavenIndustries/DTOs/EditEvent_DTO.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Api.SeaHavenIndustries.DTOs
|
||||
{
|
||||
/// <summary>
|
||||
/// DTO for POST/PUT requests - Create/Edit Event
|
||||
/// Used to create or update event information
|
||||
/// </summary>
|
||||
public class EditEvent_DTO
|
||||
{
|
||||
public int? Id { get; set; } // Null for create, populated for edit
|
||||
|
||||
[Required(ErrorMessage = "Please enter a title")]
|
||||
[StringLength(100, ErrorMessage = "Title cannot be longer than 100 characters")]
|
||||
public string Title { get; set; } = null!;
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
[StringLength(150, ErrorMessage = "Location cannot be longer than 150 characters")]
|
||||
public string? Location { get; set; }
|
||||
|
||||
public int? RecordID { get; set; }
|
||||
public string? RecordName { get; set; }
|
||||
public string? RecordTargetType { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "The Remind Attendees field is required")]
|
||||
public int ReminderMinutes { get; set; } = 15;
|
||||
|
||||
[Required(ErrorMessage = "The Select a Calendar Color field is required")]
|
||||
public string EventColor { get; set; } = "primary";
|
||||
|
||||
[Required(ErrorMessage = "Please select a start date")]
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Please select a start time")]
|
||||
public string StartTime { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Please select an end date")]
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Please select an end time")]
|
||||
public string EndTime { get; set; } = null!;
|
||||
|
||||
public bool AllDay { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
||||
33
Api.SeaHavenIndustries/DTOs/Event_DTO.cs
Normal file
33
Api.SeaHavenIndustries/DTOs/Event_DTO.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
|
||||
namespace Api.SeaHavenIndustries.DTOs
|
||||
{
|
||||
/// <summary>
|
||||
/// DTO for GET responses - Event data
|
||||
/// Used to return event information to the client
|
||||
/// </summary>
|
||||
public class Event_DTO
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Title { get; set; } = null!;
|
||||
public string? Description { get; set; }
|
||||
public string? Location { get; set; }
|
||||
|
||||
public int? RecordID { get; set; }
|
||||
public string? RecordName { get; set; }
|
||||
public string? RecordTargetType { get; set; }
|
||||
|
||||
public int ReminderMinutes { get; set; }
|
||||
public string EventColor { get; set; } = null!;
|
||||
|
||||
public DateTime StartDate { get; set; }
|
||||
public string? StartTime { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
public string? EndTime { get; set; }
|
||||
public bool AllDay { get; set; }
|
||||
|
||||
public DateTime? CreatedDate { get; set; }
|
||||
public string? createdby { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
|
||||
{
|
||||
"region" : "us-east-1",
|
||||
"configuration" : "Debug",
|
||||
"framework" : "net8.0",
|
||||
"self-contained" : true,
|
||||
"application" : "SeaHavenIndustries",
|
||||
"environment" : "SeaHavenIndustries-dev",
|
||||
"enable-xray" : false,
|
||||
"enhanced-health-type" : "basic",
|
||||
"additional-options" : "",
|
||||
"proxy-server" : "nginx"
|
||||
"region": "us-east-1",
|
||||
"configuration": "Debug",
|
||||
"framework": "net8.0",
|
||||
"self-contained": true,
|
||||
"application": "SeaHavenIndustries",
|
||||
"environment": "SeaHavenIndustries-dev",
|
||||
"enable-xray": false,
|
||||
"enhanced-health-type": "basic",
|
||||
"additional-options": "",
|
||||
"proxy-server": "nginx"
|
||||
}
|
||||
553
Api.SeaHavenIndustries/eventapicontext.txt
Normal file
553
Api.SeaHavenIndustries/eventapicontext.txt
Normal file
|
|
@ -0,0 +1,553 @@
|
|||
/*
|
||||
===================================================================================
|
||||
CALENDAR/EVENTS MODULE - COMPLETE IMPLEMENTATION
|
||||
===================================================================================
|
||||
This file contains everything needed for the Calendar/Events module:
|
||||
1. Events Model (Database Entity)
|
||||
2. Event_DTO (for GET responses)
|
||||
3. EditEvent_DTO (for POST/PUT requests)
|
||||
4. CalendarController (API endpoints)
|
||||
5. SQL Script for database table creation and sample data
|
||||
|
||||
Author: AI Agent
|
||||
Date: 2026-03-30
|
||||
===================================================================================
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Api.SeaHavenIndustries.DTOs;
|
||||
using Data.SeaHavenIndustries;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
// ===================================================================================
|
||||
// SECTION 1: DATABASE MODEL (Data.SeaHavenIndustries/Models/Events.cs)
|
||||
// ===================================================================================
|
||||
|
||||
namespace Data.SeaHavenIndustries
|
||||
{
|
||||
public class Events : FullAuditEntity
|
||||
{
|
||||
public string Title { get; set; } = null!;
|
||||
public string? Description { get; set; }
|
||||
public string? Location { get; set; }
|
||||
|
||||
// Related Record (can link to Accounts, Contacts, Work Orders, etc.)
|
||||
public int? RecordID { get; set; }
|
||||
public string? RecordName { get; set; }
|
||||
public string? RecordTargetType { get; set; }
|
||||
|
||||
// Reminder Settings
|
||||
public int ReminderMinutes { get; set; } = 15; // Default: 15 minutes before
|
||||
|
||||
// Color for calendar display
|
||||
public string EventColor { get; set; } = "primary"; // primary, success, info, warning, danger
|
||||
|
||||
// Schedule
|
||||
public DateTime StartDate { get; set; }
|
||||
public string? StartTime { get; set; } // e.g., "08:00 AM"
|
||||
public DateTime EndDate { get; set; }
|
||||
public string? EndTime { get; set; } // e.g., "08:30 AM"
|
||||
public bool AllDay { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// SECTION 2: DTOs (Api.SeaHavenIndustries/DTOs/Event_DTO.cs)
|
||||
// ===================================================================================
|
||||
|
||||
namespace Api.SeaHavenIndustries.DTOs
|
||||
{
|
||||
// DTO for GET responses
|
||||
public class Event_DTO
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Title { get; set; } = null!;
|
||||
public string? Description { get; set; }
|
||||
public string? Location { get; set; }
|
||||
|
||||
public int? RecordID { get; set; }
|
||||
public string? RecordName { get; set; }
|
||||
public string? RecordTargetType { get; set; }
|
||||
|
||||
public int ReminderMinutes { get; set; }
|
||||
public string EventColor { get; set; } = null!;
|
||||
|
||||
public DateTime StartDate { get; set; }
|
||||
public string? StartTime { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
public string? EndTime { get; set; }
|
||||
public bool AllDay { get; set; }
|
||||
|
||||
public DateTime? CreatedDate { get; set; }
|
||||
public string? createdby { get; set; }
|
||||
}
|
||||
|
||||
// DTO for POST/PUT requests (Create/Edit)
|
||||
public class EditEvent_DTO
|
||||
{
|
||||
public int? Id { get; set; } // Null for create, populated for edit
|
||||
|
||||
[Required(ErrorMessage = "Please enter a title")]
|
||||
[StringLength(100, ErrorMessage = "Title cannot be longer than 100 characters")]
|
||||
public string Title { get; set; } = null!;
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
[StringLength(150, ErrorMessage = "Location cannot be longer than 150 characters")]
|
||||
public string? Location { get; set; }
|
||||
|
||||
public int? RecordID { get; set; }
|
||||
public string? RecordName { get; set; }
|
||||
public string? RecordTargetType { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "The Remind Attendees field is required")]
|
||||
public int ReminderMinutes { get; set; } = 15;
|
||||
|
||||
[Required(ErrorMessage = "The Select a Calendar Color field is required")]
|
||||
public string EventColor { get; set; } = "primary";
|
||||
|
||||
[Required(ErrorMessage = "Please select a start date")]
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Please select a start time")]
|
||||
public string StartTime { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Please select an end date")]
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Please select an end time")]
|
||||
public string EndTime { get; set; } = null!;
|
||||
|
||||
public bool AllDay { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// SECTION 3: CONTROLLER (Api.SeaHavenIndustries/Controllers/CalendarController.cs)
|
||||
// ===================================================================================
|
||||
|
||||
namespace Api.SeaHavenIndustries.Controllers
|
||||
{
|
||||
//[Authorize] // Uncomment when authentication is needed
|
||||
[ApiController]
|
||||
[Route("api/Calendar")]
|
||||
public class CalendarController : Controller
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly ApplicationDbContext _db;
|
||||
|
||||
public CalendarController(UserManager<ApplicationUser> userManager, ApplicationDbContext db)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_db = db;
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// CREATE EVENT
|
||||
// ===================================================================================
|
||||
[HttpPost]
|
||||
[Route("AddEvent")]
|
||||
public async Task<IActionResult> AddEvent(EditEvent_DTO eventDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var model = new Events
|
||||
{
|
||||
Title = eventDto.Title,
|
||||
Description = eventDto.Description,
|
||||
Location = eventDto.Location,
|
||||
RecordID = eventDto.RecordID,
|
||||
RecordName = eventDto.RecordName,
|
||||
RecordTargetType = eventDto.RecordTargetType,
|
||||
ReminderMinutes = eventDto.ReminderMinutes,
|
||||
EventColor = eventDto.EventColor,
|
||||
StartDate = eventDto.StartDate,
|
||||
StartTime = eventDto.StartTime,
|
||||
EndDate = eventDto.EndDate,
|
||||
EndTime = eventDto.EndTime,
|
||||
AllDay = eventDto.AllDay,
|
||||
CreatedDate = DateTime.Now,
|
||||
IsDeleted = false
|
||||
};
|
||||
|
||||
_db.Events.Add(model);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
return Ok(new DataResponse { Message = "Event Created Successfully", Status = "200" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// UPDATE EVENT
|
||||
// ===================================================================================
|
||||
[HttpPost]
|
||||
[Route("EditEvent")]
|
||||
public async Task<IActionResult> EditEvent(EditEvent_DTO eventDto)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!eventDto.Id.HasValue)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = "Event ID is required for editing" });
|
||||
}
|
||||
|
||||
var model = await _db.Events.FindAsync(eventDto.Id.Value);
|
||||
if (model == null || model.IsDeleted == true)
|
||||
{
|
||||
return NotFound(new Response { Status = "Error", Message = "Event not found" });
|
||||
}
|
||||
|
||||
model.Title = eventDto.Title;
|
||||
model.Description = eventDto.Description;
|
||||
model.Location = eventDto.Location;
|
||||
model.RecordID = eventDto.RecordID;
|
||||
model.RecordName = eventDto.RecordName;
|
||||
model.RecordTargetType = eventDto.RecordTargetType;
|
||||
model.ReminderMinutes = eventDto.ReminderMinutes;
|
||||
model.EventColor = eventDto.EventColor;
|
||||
model.StartDate = eventDto.StartDate;
|
||||
model.StartTime = eventDto.StartTime;
|
||||
model.EndDate = eventDto.EndDate;
|
||||
model.EndTime = eventDto.EndTime;
|
||||
model.AllDay = eventDto.AllDay;
|
||||
model.LastModificationTime = DateTime.Now;
|
||||
|
||||
_db.Events.Update(model);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
return Ok(new DataResponse { Message = "Event Updated Successfully", Status = "200" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// GET EVENT BY ID
|
||||
// ===================================================================================
|
||||
[HttpGet]
|
||||
[Route("GetEventById/{id}")]
|
||||
public async Task<IActionResult> GetEventById(int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var model = await _db.Events
|
||||
.Where(e => e.Id == id && e.IsDeleted != true)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (model == null)
|
||||
{
|
||||
return NotFound(new Response { Status = "Error", Message = "Event not found" });
|
||||
}
|
||||
|
||||
var dto = new Event_DTO
|
||||
{
|
||||
Id = model.Id,
|
||||
Title = model.Title,
|
||||
Description = model.Description,
|
||||
Location = model.Location,
|
||||
RecordID = model.RecordID,
|
||||
RecordName = model.RecordName,
|
||||
RecordTargetType = model.RecordTargetType,
|
||||
ReminderMinutes = model.ReminderMinutes,
|
||||
EventColor = model.EventColor,
|
||||
StartDate = model.StartDate,
|
||||
StartTime = model.StartTime,
|
||||
EndDate = model.EndDate,
|
||||
EndTime = model.EndTime,
|
||||
AllDay = model.AllDay,
|
||||
CreatedDate = model.CreatedDate,
|
||||
createdby = model.createdby
|
||||
};
|
||||
|
||||
return Ok(new DataResponse { Message = "Success", Status = "200", Data = dto });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================================
|
||||
// DELETE EVENT
|
||||
// ===================================================================================
|
||||
[HttpDelete]
|
||||
[Route("DeleteEvent/{id}")]
|
||||
public async Task<IActionResult> DeleteEvent(int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var model = await _db.Events.FindAsync(id);
|
||||
if (model == null)
|
||||
{
|
||||
return NotFound(new Response { Status = "Error", Message = "Event not found" });
|
||||
}
|
||||
|
||||
// Soft delete
|
||||
model.IsDeleted = true;
|
||||
model.DeletionTime = DateTime.Now;
|
||||
|
||||
_db.Events.Update(model);
|
||||
await _db.SaveChangesAsync();
|
||||
|
||||
return Ok(new DataResponse { Message = "Event Deleted Successfully", Status = "200" });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// GET EVENTS LIST (WITH PAGINATION AND FILTERS)
|
||||
// ===================================================================================
|
||||
[HttpPost]
|
||||
[Route("GetEventList")]
|
||||
public IActionResult GetEventList(Pagination_DTO dto)
|
||||
{
|
||||
try
|
||||
{
|
||||
var query = _db.Events.Where(e => e.IsDeleted != true);
|
||||
|
||||
// Apply search filter if provided
|
||||
if (!string.IsNullOrWhiteSpace(dto.Search))
|
||||
{
|
||||
query = query.Where(e =>
|
||||
e.Title.Contains(dto.Search) ||
|
||||
(e.Description != null && e.Description.Contains(dto.Search)) ||
|
||||
(e.Location != null && e.Location.Contains(dto.Search))
|
||||
);
|
||||
}
|
||||
|
||||
// IMPORTANT: Calculate totalCount AFTER applying filters
|
||||
var totalCount = query.Count();
|
||||
|
||||
// Apply pagination
|
||||
var events = query
|
||||
.OrderByDescending(e => e.StartDate)
|
||||
.ThenByDescending(e => e.CreatedDate)
|
||||
.Skip((dto.PageNumber - 1) * dto.PageSize)
|
||||
.Take(dto.PageSize)
|
||||
.Select(e => new Event_DTO
|
||||
{
|
||||
Id = e.Id,
|
||||
Title = e.Title,
|
||||
Description = e.Description,
|
||||
Location = e.Location,
|
||||
RecordID = e.RecordID,
|
||||
RecordName = e.RecordName,
|
||||
RecordTargetType = e.RecordTargetType,
|
||||
ReminderMinutes = e.ReminderMinutes,
|
||||
EventColor = e.EventColor,
|
||||
StartDate = e.StartDate,
|
||||
StartTime = e.StartTime,
|
||||
EndDate = e.EndDate,
|
||||
EndTime = e.EndTime,
|
||||
AllDay = e.AllDay,
|
||||
CreatedDate = e.CreatedDate,
|
||||
createdby = e.createdby
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return Ok(new DataResponse
|
||||
{
|
||||
Message = "Success",
|
||||
Status = "200",
|
||||
Data = new { rows = events, totalCount }
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================================
|
||||
// GET EVENTS FOR CALENDAR (Date Range Filter)
|
||||
// ===================================================================================
|
||||
[HttpGet]
|
||||
[Route("GetEventsForCalendar")]
|
||||
public IActionResult GetEventsForCalendar([FromQuery] DateTime? start, [FromQuery] DateTime? end)
|
||||
{
|
||||
try
|
||||
{
|
||||
var query = _db.Events.Where(e => e.IsDeleted != true);
|
||||
|
||||
// Filter by date range if provided
|
||||
if (start.HasValue && end.HasValue)
|
||||
{
|
||||
query = query.Where(e =>
|
||||
(e.StartDate >= start.Value && e.StartDate <= end.Value) ||
|
||||
(e.EndDate >= start.Value && e.EndDate <= end.Value) ||
|
||||
(e.StartDate <= start.Value && e.EndDate >= end.Value)
|
||||
);
|
||||
}
|
||||
|
||||
var events = query
|
||||
.Select(e => new Event_DTO
|
||||
{
|
||||
Id = e.Id,
|
||||
Title = e.Title,
|
||||
Description = e.Description,
|
||||
Location = e.Location,
|
||||
RecordID = e.RecordID,
|
||||
RecordName = e.RecordName,
|
||||
RecordTargetType = e.RecordTargetType,
|
||||
ReminderMinutes = e.ReminderMinutes,
|
||||
EventColor = e.EventColor,
|
||||
StartDate = e.StartDate,
|
||||
StartTime = e.StartTime,
|
||||
EndDate = e.EndDate,
|
||||
EndTime = e.EndTime,
|
||||
AllDay = e.AllDay,
|
||||
CreatedDate = e.CreatedDate,
|
||||
createdby = e.createdby
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return Ok(new DataResponse { Message = "Success", Status = "200", Data = events });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return BadRequest(new Response { Status = "Error", Message = ex.Message });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================================================================================
|
||||
SECTION 4: DATABASE SETUP
|
||||
===================================================================================
|
||||
|
||||
STEP 1: Add Events DbSet to ApplicationDbContext.cs
|
||||
-------------------------------------------------------
|
||||
Add this line in the ApplicationDbContext class (around line 48):
|
||||
|
||||
public DbSet<Events> Events { get; set; }
|
||||
|
||||
|
||||
STEP 2: Create Database Migration
|
||||
-------------------------------------------------------
|
||||
Run these commands in the terminal from the Api.SeaHavenIndustries project directory:
|
||||
|
||||
dotnet ef migrations add AddEventsTable --project ../Data.SeaHavenIndustries
|
||||
dotnet ef database update
|
||||
|
||||
|
||||
STEP 3: SQL Script for Manual Table Creation (Alternative to migrations)
|
||||
-------------------------------------------------------
|
||||
*/
|
||||
|
||||
-- SQL SCRIPT TO CREATE EVENTS TABLE
|
||||
/*
|
||||
CREATE TABLE Events (
|
||||
Id INT PRIMARY KEY IDENTITY(1,1),
|
||||
Title NVARCHAR(100) NOT NULL,
|
||||
Description NVARCHAR(MAX) NULL,
|
||||
Location NVARCHAR(150) NULL,
|
||||
|
||||
RecordID INT NULL,
|
||||
RecordName NVARCHAR(255) NULL,
|
||||
RecordTargetType NVARCHAR(50) NULL,
|
||||
|
||||
ReminderMinutes INT NOT NULL DEFAULT 15,
|
||||
EventColor NVARCHAR(20) NOT NULL DEFAULT 'primary',
|
||||
|
||||
StartDate DATETIME NOT NULL,
|
||||
StartTime NVARCHAR(10) NULL,
|
||||
EndDate DATETIME NOT NULL,
|
||||
EndTime NVARCHAR(10) NULL,
|
||||
AllDay BIT NOT NULL DEFAULT 0,
|
||||
|
||||
-- Audit fields
|
||||
IsDeleted BIT NULL,
|
||||
createdby NVARCHAR(450) NULL,
|
||||
DeleterUserId NVARCHAR(450) NULL,
|
||||
DeletionTime DATETIME NULL,
|
||||
CreatedDate DATETIME NULL,
|
||||
LastModificationTime DATETIME NULL,
|
||||
LastModifierUserId INT NULL
|
||||
);
|
||||
|
||||
-- Insert sample data
|
||||
INSERT INTO Events (Title, Description, Location, StartDate, StartTime, EndDate, EndTime, AllDay, EventColor, ReminderMinutes, CreatedDate, IsDeleted)
|
||||
VALUES
|
||||
('Team Meeting', 'Weekly team sync', 'Conference Room A', '2026-04-01', '10:00 AM', '2026-04-01', '11:00 AM', 0, 'primary', 15, GETDATE(), 0),
|
||||
('Client Presentation', 'Q1 Results Review with ABC Corp', 'Virtual - Zoom', '2026-04-03', '02:00 PM', '2026-04-03', '03:30 PM', 0, 'success', 30, GETDATE(), 0),
|
||||
('Project Deadline', 'Final delivery for Project Phoenix', NULL, '2026-04-05', NULL, '2026-04-05', NULL, 1, 'danger', 1440, GETDATE(), 0),
|
||||
('Training Session', 'New system training for all employees', 'Main Office', '2026-04-08', '09:00 AM', '2026-04-08', '12:00 PM', 0, 'info', 60, GETDATE(), 0),
|
||||
('Equipment Maintenance', 'Scheduled maintenance for all assets', 'Warehouse', '2026-04-10', '08:00 AM', '2026-04-10', '05:00 PM', 0, 'warning', 120, GETDATE(), 0);
|
||||
*/
|
||||
|
||||
/*
|
||||
===================================================================================
|
||||
SECTION 5: IMPLEMENTATION CHECKLIST
|
||||
===================================================================================
|
||||
|
||||
BACKEND SETUP:
|
||||
--------------
|
||||
1. ✓ Create Events.cs in Data.SeaHavenIndustries/Models/
|
||||
2. ✓ Create Event_DTO.cs in Api.SeaHavenIndustries/DTOs/
|
||||
3. ✓ Create EditEvent_DTO.cs in Api.SeaHavenIndustries/DTOs/
|
||||
4. ✓ Create CalendarController.cs in Api.SeaHavenIndustries/Controllers/
|
||||
5. ☐ Add DbSet<Events> to ApplicationDbContext.cs
|
||||
6. ☐ Run migrations (or execute SQL script)
|
||||
7. ☐ Test all endpoints using Postman/Swagger
|
||||
|
||||
FRONTEND SETUP (Next Step):
|
||||
---------------------------
|
||||
1. ☐ Create src/pages/calendar/CalendarPage.js (List view with FullCalendar)
|
||||
2. ☐ Create src/pages/calendar/EventFormPage.js (Create/Edit form)
|
||||
3. ☐ Create src/pages/calendar/api.js (API calls)
|
||||
4. ☐ Add routes to App.js
|
||||
5. ☐ Install FullCalendar: npm install @fullcalendar/react @fullcalendar/daygrid @fullcalendar/timegrid @fullcalendar/interaction
|
||||
|
||||
API ENDPOINTS SUMMARY:
|
||||
---------------------
|
||||
POST /api/Calendar/AddEvent - Create new event
|
||||
POST /api/Calendar/EditEvent - Update existing event
|
||||
GET /api/Calendar/GetEventById/{id} - Get single event by ID
|
||||
DELETE /api/Calendar/DeleteEvent/{id} - Delete event (soft delete)
|
||||
POST /api/Calendar/GetEventList - Get paginated list with search
|
||||
GET /api/Calendar/GetEventsForCalendar - Get events for calendar view (with date range)
|
||||
|
||||
KEY FEATURES IMPLEMENTED:
|
||||
-------------------------
|
||||
✓ CRUD operations (Create, Read, Update, Delete)
|
||||
✓ Pagination with search filter
|
||||
✓ Date range filtering for calendar view
|
||||
✓ Soft delete (IsDeleted flag)
|
||||
✓ Related record linking (RecordID, RecordName, RecordTargetType)
|
||||
✓ Color coding for calendar display
|
||||
✓ All-day event support
|
||||
✓ Reminder settings
|
||||
✓ Proper error handling
|
||||
✓ Consistent with existing controller patterns (AssetController)
|
||||
✓ Fixed pagination bug (totalCount calculated AFTER filters)
|
||||
|
||||
NOTES:
|
||||
------
|
||||
- EventColor values: 'primary', 'success', 'info', 'warning', 'danger'
|
||||
- ReminderMinutes: 0=Never, 5, 10, 15, 30, 60, 120, 240, 360, 720, 1440 (1 day)
|
||||
- StartTime/EndTime format: "08:00 AM", "02:30 PM", etc.
|
||||
- AllDay: When true, time fields can be null/ignored
|
||||
- RecordTargetType: Can be "Account", "Contact", "WorkOrder", "FollowUp", etc.
|
||||
|
||||
===================================================================================
|
||||
END OF FILE
|
||||
===================================================================================
|
||||
*/
|
||||
|
|
@ -46,6 +46,7 @@ namespace Data.SeaHavenIndustries
|
|||
public DbSet<FollowUps> FollowUps { get; set; }
|
||||
public DbSet<PMSchedules> PMSchedules { get; set; }
|
||||
public DbSet<ContactDetails> ContactDetails { get; set; }
|
||||
public DbSet<Events> Events { get; set; }
|
||||
|
||||
// Employee related DbSets
|
||||
public DbSet<EmployeeAddress> EmployeeAddresses { get; set; }
|
||||
|
|
|
|||
49
Data.SeaHavenIndustries/Models/Events.cs
Normal file
49
Data.SeaHavenIndustries/Models/Events.cs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Data.SeaHavenIndustries
|
||||
{
|
||||
/// <summary>
|
||||
/// Events entity for Calendar/Events module
|
||||
/// Tracks calendar events, appointments, meetings, etc.
|
||||
/// </summary>
|
||||
public class Events : FullAuditEntity
|
||||
{
|
||||
[Required]
|
||||
[StringLength(100)]
|
||||
public string Title { get; set; } = null!;
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
[StringLength(150)]
|
||||
public string? Location { get; set; }
|
||||
|
||||
// Related Record (can link to Accounts, Contacts, Work Orders, etc.)
|
||||
public int? RecordID { get; set; }
|
||||
public string? RecordName { get; set; }
|
||||
public string? RecordTargetType { get; set; }
|
||||
|
||||
// Reminder Settings
|
||||
public int ReminderMinutes { get; set; } = 15; // Default: 15 minutes before
|
||||
|
||||
// Color for calendar display
|
||||
[StringLength(20)]
|
||||
public string EventColor { get; set; } = "primary"; // primary, success, info, warning, danger
|
||||
|
||||
// Schedule
|
||||
[Required]
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
[StringLength(10)]
|
||||
public string? StartTime { get; set; } // e.g., "08:00 AM"
|
||||
|
||||
[Required]
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
[StringLength(10)]
|
||||
public string? EndTime { get; set; } // e.g., "08:30 AM"
|
||||
|
||||
public bool AllDay { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Add table
Reference in a new issue