diff --git a/DysonNetwork.Pass/Account/NotableDay.cs b/DysonNetwork.Pass/Account/NotableDay.cs index cbbd258..81f11c8 100644 --- a/DysonNetwork.Pass/Account/NotableDay.cs +++ b/DysonNetwork.Pass/Account/NotableDay.cs @@ -28,6 +28,7 @@ public class NotableDay public Instant Date { get; set; } public string? LocalName { get; set; } public string? GlobalName { get; set; } + public string? LocalizableKey { get; set; } public string? CountryCode { get; set; } public NotableHolidayType[] Holidays { get; set; } = []; diff --git a/DysonNetwork.Pass/Account/NotableDaysController.cs b/DysonNetwork.Pass/Account/NotableDaysController.cs index 6880293..12f45c8 100644 --- a/DysonNetwork.Pass/Account/NotableDaysController.cs +++ b/DysonNetwork.Pass/Account/NotableDaysController.cs @@ -77,4 +77,52 @@ public class NotableDaysController(NotableDaysService days) : ControllerBase } return Ok(result); } + + [HttpGet("{regionCode}/current")] + public async Task> GetCurrentHoliday(string regionCode) + { + var result = await days.GetCurrentHoliday(regionCode); + if (result == null) + { + return NotFound("No holiday today"); + } + return Ok(result); + } + + [HttpGet("me/current")] + [Authorize] + public async Task> GetAccountCurrentHoliday() + { + if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized(); + + var region = currentUser.Region; + if (string.IsNullOrWhiteSpace(region)) region = "us"; + + var result = await days.GetCurrentHoliday(region); + if (result == null) + { + return NotFound("No holiday today"); + } + return Ok(result); + } + + [HttpGet("{regionCode}/recent")] + public async Task>> GetRecentNotableDay(string regionCode) + { + var result = await days.GetCurrentAndNextHoliday(regionCode); + return Ok(result); + } + + [HttpGet("me/recent")] + [Authorize] + public async Task>> GetAccountRecentNotableDay() + { + if (HttpContext.Items["CurrentUser"] is not SnAccount currentUser) return Unauthorized(); + + var region = currentUser.Region; + if (string.IsNullOrWhiteSpace(region)) region = "us"; + + var result = await days.GetCurrentAndNextHoliday(region); + return Ok(result); + } } diff --git a/DysonNetwork.Pass/Account/NotableDaysService.cs b/DysonNetwork.Pass/Account/NotableDaysService.cs index 46dedbe..eddcf74 100644 --- a/DysonNetwork.Pass/Account/NotableDaysService.cs +++ b/DysonNetwork.Pass/Account/NotableDaysService.cs @@ -27,12 +27,123 @@ public class NotableDaysService(ICacheService cache) var holidays = await holidayClient.GetHolidaysAsync(year.Value, regionCode); var days = holidays?.Select(NotableDay.FromNagerHoliday).ToList() ?? []; + // Add global holidays that are available for all regions + var globalDays = GetGlobalHolidays(year.Value); + foreach (var globalDay in globalDays.Where(globalDay => + !days.Any(d => d.Date.Equals(globalDay.Date) && d.GlobalName == globalDay.GlobalName))) + { + days.Add(globalDay); + } + // Cache the result for 1 day (holiday data doesn't change frequently) await cache.SetAsync(cacheKey, days, TimeSpan.FromDays(1)); return days; } + private static List GetGlobalHolidays(int year) + { + var globalDays = new List(); + + // Christmas Day - December 25 + var christmas = new NotableDay + { + Date = Instant.FromDateTimeUtc(new DateTime(year, 12, 25, 0, 0, 0, DateTimeKind.Utc)), + LocalName = "Christmas", + GlobalName = "Christmas", + LocalizableKey = "Christmas", + CountryCode = null, + Holidays = [NotableHolidayType.Public] + }; + globalDays.Add(christmas); + + // New Year's Day - January 1 + var newYear = new NotableDay + { + Date = Instant.FromDateTimeUtc(new DateTime(year, 1, 1, 0, 0, 0, DateTimeKind.Utc)), + LocalName = "New Year's Day", + GlobalName = "New Year's Day", + LocalizableKey = "NewYear", + CountryCode = null, + Holidays = [NotableHolidayType.Public] + }; + globalDays.Add(newYear); + + // Valentine's Day - February 14 + var valentine = new NotableDay + { + Date = Instant.FromDateTimeUtc(new DateTime(year, 2, 14, 0, 0, 0, DateTimeKind.Utc)), + LocalName = "Valentine's Day", + GlobalName = "Valentine's Day", + LocalizableKey = "ValentineDay", + CountryCode = null, + Holidays = [NotableHolidayType.Observance] + }; + globalDays.Add(valentine); + + // April Fools' Day - April 1 + var aprilFools = new NotableDay + { + Date = Instant.FromDateTimeUtc(new DateTime(year, 4, 1, 0, 0, 0, DateTimeKind.Utc)), + LocalName = "April Fools' Day", + GlobalName = "April Fools' Day", + LocalizableKey = "AprilFoolsDay", + CountryCode = null, + Holidays = [NotableHolidayType.Observance] + }; + globalDays.Add(aprilFools); + + // International Workers' Day - May 1 + var workersDay = new NotableDay + { + Date = Instant.FromDateTimeUtc(new DateTime(year, 5, 1, 0, 0, 0, DateTimeKind.Utc)), + LocalName = "International Workers' Day", + GlobalName = "International Workers' Day", + LocalizableKey = "WorkersDay", + CountryCode = null, + Holidays = [NotableHolidayType.Public] + }; + globalDays.Add(workersDay); + + // Children's Day - June 1 + var childrenDay = new NotableDay + { + Date = Instant.FromDateTimeUtc(new DateTime(year, 6, 1, 0, 0, 0, DateTimeKind.Utc)), + LocalName = "Children's Day", + GlobalName = "Children's Day", + LocalizableKey = "ChildrenDay", + CountryCode = null, + Holidays = [NotableHolidayType.Public] + }; + globalDays.Add(childrenDay); + + // World Environment Day - June 5 + var environmentDay = new NotableDay + { + Date = Instant.FromDateTimeUtc(new DateTime(year, 6, 5, 0, 0, 0, DateTimeKind.Utc)), + LocalName = "World Environment Day", + GlobalName = "World Environment Day", + LocalizableKey = "EnvironmentDay", + CountryCode = null, + Holidays = [NotableHolidayType.Observance] + }; + globalDays.Add(environmentDay); + + // Halloween - October 31 + var halloween = new NotableDay + { + Date = Instant.FromDateTimeUtc(new DateTime(year, 10, 31, 0, 0, 0, DateTimeKind.Utc)), + LocalName = "Halloween", + GlobalName = "Halloween", + LocalizableKey = "Halloween", + CountryCode = null, + Holidays = [NotableHolidayType.Observance] + }; + globalDays.Add(halloween); + + return globalDays; + } + public async Task GetNextHoliday(string regionCode) { var currentDate = SystemClock.Instance.GetCurrentInstant(); @@ -52,4 +163,37 @@ public class NotableDaysService(ICacheService cache) return nextHoliday; } + + public async Task GetCurrentHoliday(string regionCode) + { + var currentDate = SystemClock.Instance.GetCurrentInstant(); + var currentYear = currentDate.InUtc().Year; + + var currentYearHolidays = await GetNotableDays(currentYear, regionCode); + + // Find the holiday that is today + var todayHoliday = currentYearHolidays + .FirstOrDefault(day => day.Date.InUtc().Date == currentDate.InUtc().Date); + + return todayHoliday; + } + + public async Task> GetCurrentAndNextHoliday(string regionCode) + { + var result = new List(); + + var current = await GetCurrentHoliday(regionCode); + if (current != null) + { + result.Add(current); + } + + var next = await GetNextHoliday(regionCode); + if (next != null && (current == null || !next.Date.Equals(current.Date))) + { + result.Add(next); + } + + return result; + } }