101 lines
2.9 KiB
C#
101 lines
2.9 KiB
C#
using System.Globalization;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Logging;
|
|
using PlotLine.Services;
|
|
|
|
namespace PlotLine.Controllers;
|
|
|
|
[Authorize]
|
|
public sealed class StoryCalendarController(IStoryCalendarService calendar, ILogger<StoryCalendarController> logger) : Controller
|
|
{
|
|
public async Task<IActionResult> Index(int projectId, int? bookId, string? month, string? date)
|
|
{
|
|
if (projectId == 0)
|
|
{
|
|
return BadRequest("ProjectID is required.");
|
|
}
|
|
|
|
var selectedMonth = ParseMonth(month);
|
|
var selectedDate = ParseDate(date);
|
|
var model = await calendar.GetAsync(projectId, bookId, selectedMonth, selectedDate);
|
|
return model is null ? NotFound() : View(model);
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<IActionResult> DayDetails(int projectId, int? bookId, string? date)
|
|
{
|
|
if (projectId == 0)
|
|
{
|
|
return BadRequest("ProjectID is required.");
|
|
}
|
|
|
|
var selectedDate = ParseDate(date);
|
|
if (!selectedDate.HasValue)
|
|
{
|
|
return BadRequest("Date is required.");
|
|
}
|
|
|
|
try
|
|
{
|
|
var model = await calendar.GetAsync(projectId, bookId, FirstOfMonth(selectedDate.Value), selectedDate);
|
|
return model is null ? NotFound() : PartialView("_StoryCalendarDayDetails", model.DayDetails);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.LogError(ex, "Failed to load Story Calendar day details for project {ProjectID} and date {StoryDate}.", projectId, date);
|
|
return StatusCode(StatusCodes.Status500InternalServerError, "The selected story date could not be loaded.");
|
|
}
|
|
}
|
|
|
|
[HttpPost]
|
|
[ValidateAntiForgeryToken]
|
|
public IActionResult ApplyFilters(int projectId, int? bookId, string? month)
|
|
{
|
|
return RedirectToAction(nameof(Index), new
|
|
{
|
|
projectId,
|
|
bookId,
|
|
month
|
|
});
|
|
}
|
|
|
|
private static DateOnly? ParseMonth(string? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return DateOnly.TryParseExact(
|
|
$"{value.Trim()}-01",
|
|
"yyyy-MM-dd",
|
|
CultureInfo.InvariantCulture,
|
|
DateTimeStyles.None,
|
|
out var parsed)
|
|
? new DateOnly(parsed.Year, parsed.Month, 1)
|
|
: null;
|
|
}
|
|
|
|
private static DateOnly? ParseDate(string? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return DateOnly.TryParseExact(
|
|
value.Trim(),
|
|
"yyyy-MM-dd",
|
|
CultureInfo.InvariantCulture,
|
|
DateTimeStyles.None,
|
|
out var parsed)
|
|
? parsed
|
|
: null;
|
|
}
|
|
|
|
private static DateOnly FirstOfMonth(DateOnly date)
|
|
=> new(date.Year, date.Month, 1);
|
|
}
|