mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 10:43: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",
|
"region": "us-east-1",
|
||||||
"configuration" : "Debug",
|
"configuration": "Debug",
|
||||||
"framework" : "net8.0",
|
"framework": "net8.0",
|
||||||
"self-contained" : true,
|
"self-contained": true,
|
||||||
"application" : "SeaHavenIndustries",
|
"application": "SeaHavenIndustries",
|
||||||
"environment" : "SeaHavenIndustries-dev",
|
"environment": "SeaHavenIndustries-dev",
|
||||||
"enable-xray" : false,
|
"enable-xray": false,
|
||||||
"enhanced-health-type" : "basic",
|
"enhanced-health-type": "basic",
|
||||||
"additional-options" : "",
|
"additional-options": "",
|
||||||
"proxy-server" : "nginx"
|
"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<FollowUps> FollowUps { get; set; }
|
||||||
public DbSet<PMSchedules> PMSchedules { get; set; }
|
public DbSet<PMSchedules> PMSchedules { get; set; }
|
||||||
public DbSet<ContactDetails> ContactDetails { get; set; }
|
public DbSet<ContactDetails> ContactDetails { get; set; }
|
||||||
|
public DbSet<Events> Events { get; set; }
|
||||||
|
|
||||||
// Employee related DbSets
|
// Employee related DbSets
|
||||||
public DbSet<EmployeeAddress> EmployeeAddresses { get; set; }
|
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