namespace IronServices.Client; /// /// API client for IronNotify operations. /// Access via IronServicesClient.Notify /// public class NotifyApi { private readonly IronServicesClient _client; private readonly string _baseUrl; internal NotifyApi(IronServicesClient client, string baseUrl) { _client = client; _baseUrl = baseUrl; } private string Url(string endpoint) => IronServicesClient.BuildUrl(_baseUrl, endpoint); #region Notifications /// /// Get notifications for the current user. /// public async Task> GetNotificationsAsync(string? appSlug = null, bool unreadOnly = false, int page = 1, int pageSize = 50, CancellationToken ct = default) { var query = new List { $"page={page}", $"pageSize={pageSize}" }; if (unreadOnly) query.Add("isRead=false"); if (!string.IsNullOrEmpty(appSlug)) query.Add($"type={appSlug}"); var queryString = "?" + string.Join("&", query); var result = await _client.GetAsync(Url($"api/v1/notifications{queryString}"), ct); return result?.Notifications ?? []; } /// /// Get unread notification count. /// public async Task GetUnreadCountAsync(CancellationToken ct = default) { var result = await _client.GetAsync(Url("api/v1/notifications/unread-count"), ct); return result?.Count ?? result?.UnreadCount ?? 0; } /// /// Mark a notification as read. /// public async Task MarkAsReadAsync(Guid notificationId, CancellationToken ct = default) { await _client.PutAsync(Url($"api/v1/notifications/{notificationId}/read"), new { }, ct); } /// /// Mark all notifications as read. /// public async Task MarkAllAsReadAsync(CancellationToken ct = default) { await _client.PutAsync(Url("api/v1/notifications/read-all"), new { }, ct); } /// /// Acknowledge a notification (marks as read). /// public async Task AcknowledgeAsync(Guid notificationId, CancellationToken ct = default) { await MarkAsReadAsync(notificationId, ct); } /// /// Get a specific notification by ID. /// public async Task GetNotificationAsync(Guid notificationId, CancellationToken ct = default) { return await _client.GetAsync(Url($"api/v1/notifications/{notificationId}"), ct); } /// /// Resolve a notification. /// public async Task ResolveAsync(Guid notificationId, string? resolution = null, CancellationToken ct = default) { await _client.PostAsync(Url($"api/v1/notifications/{notificationId}/resolve"), new { resolution }, ct); } /// /// Get notification preferences. /// public async Task GetNotificationPreferencesAsync(CancellationToken ct = default) { return await _client.GetAsync(Url("api/v1/notifications/preferences"), ct); } /// /// Update notification preferences. /// public async Task UpdateNotificationPreferencesAsync(NotificationPreferences prefs, CancellationToken ct = default) { await _client.PutAsync(Url("api/v1/notifications/preferences"), prefs, ct); } #endregion #region Apps /// /// Get all apps for the tenant. /// public async Task> GetMyAppsAsync(CancellationToken ct = default) { return await _client.GetAsync>(Url("api/v1/apps"), ct) ?? []; } /// /// Get a specific app by ID. /// public async Task GetAppAsync(Guid appId, CancellationToken ct = default) { return await _client.GetAsync(Url($"api/v1/apps/{appId}"), ct); } /// /// Get an app by slug. /// public async Task GetAppBySlugAsync(string slug, CancellationToken ct = default) { return await _client.GetAsync(Url($"api/v1/apps/by-slug/{slug}"), ct); } #endregion #region Members & On-Call /// /// Get all team members. /// public async Task> GetTeamMembersAsync(CancellationToken ct = default) { return await _client.GetAsync>(Url("api/v1/members"), ct) ?? []; } /// /// Get current on-call member. /// public async Task GetOnCallMemberAsync(Guid? teamId = null, CancellationToken ct = default) { var query = teamId.HasValue ? $"?teamId={teamId}" : ""; return await _client.GetAsync(Url($"api/v1/members/on-call{query}"), ct); } /// /// Get on-call status for the current user. /// public async Task GetOnCallStatusAsync(CancellationToken ct = default) { var member = await GetOnCallMemberAsync(ct: ct); if (member == null) return new OnCallStatus { IsOnCall = false }; return new OnCallStatus { IsOnCall = true, OnCallUserName = member.Name, OnCallUserEmail = member.Email }; } /// /// Set on-call status for a member. /// public async Task SetOnCallAsync(Guid memberId, bool isOnCall, CancellationToken ct = default) { return await _client.PostAsync(Url($"api/v1/members/{memberId}/on-call"), new { isOnCall }, ct); } /// /// Take on-call shift for current user. /// public async Task TakeOnCallAsync(CancellationToken ct = default) { // This would need the current user's member ID - placeholder for now await Task.CompletedTask; } /// /// End on-call shift for current user. /// public async Task EndOnCallAsync(CancellationToken ct = default) { // This would need the current user's member ID - placeholder for now await Task.CompletedTask; } /// /// Request coverage from another team member. /// public async Task RequestCoverageAsync(Guid memberId, CancellationToken ct = default) { // Placeholder - would send notification to member await Task.CompletedTask; } /// /// Get today's on-call schedule. /// public async Task> GetScheduleAsync(CancellationToken ct = default) { // Placeholder - schedule endpoint not implemented in backend return await Task.FromResult(new List()); } #endregion #region App Muting /// /// Mute notifications from an app. /// public async Task MuteAppAsync(string appSlug, int? minutes = null, CancellationToken ct = default) { // Placeholder - mute endpoint not implemented in backend await Task.CompletedTask; } /// /// Unmute notifications from an app. /// public async Task UnmuteAppAsync(string appSlug, CancellationToken ct = default) { // Placeholder - unmute endpoint not implemented in backend await Task.CompletedTask; } #endregion #region Teams /// /// Get all teams. /// public async Task> GetTeamsAsync(CancellationToken ct = default) { return await _client.GetAsync>(Url("api/v1/teams"), ct) ?? []; } /// /// Get a specific team. /// public async Task GetTeamAsync(Guid teamId, CancellationToken ct = default) { return await _client.GetAsync(Url($"api/v1/teams/{teamId}"), ct); } /// /// Get members of a specific team. /// public async Task> GetTeamMembersAsync(Guid teamId, CancellationToken ct = default) { return await _client.GetAsync>(Url($"api/v1/teams/{teamId}/members"), ct) ?? []; } #endregion } public class NotificationsResponse { public List Notifications { get; set; } = []; public int TotalCount { get; set; } public int UnreadCount { get; set; } public int Page { get; set; } public int PageSize { get; set; } } public class TeamInfo { public Guid Id { get; set; } public string Name { get; set; } = string.Empty; public string? Description { get; set; } public int MemberCount { get; set; } public DateTime CreatedAt { get; set; } }