1+
2+ using Aquiis . SimpleStart . Core . Constants ;
3+ using Aquiis . SimpleStart . Core . Interfaces . Services ;
4+ using Aquiis . SimpleStart . Core . Services ;
5+ using Aquiis . SimpleStart . Infrastructure . Data ;
6+ using Aquiis . SimpleStart . Shared . Services ;
7+ using Microsoft . EntityFrameworkCore ;
8+ using Microsoft . Extensions . Options ;
9+
10+ namespace Aquiis . SimpleStart . Application . Services ;
11+ public class NotificationService : BaseService < Notification >
12+ {
13+ private readonly IEmailService _emailService ;
14+ private readonly ISMSService _smsService ;
15+ private new readonly ILogger < NotificationService > _logger ;
16+
17+ public NotificationService (
18+ ApplicationDbContext context ,
19+ UserContextService userContext ,
20+ IEmailService emailService ,
21+ ISMSService smsService ,
22+ IOptions < ApplicationSettings > appSettings ,
23+ ILogger < NotificationService > logger )
24+ : base ( context , logger , userContext , appSettings )
25+ {
26+ _emailService = emailService ;
27+ _smsService = smsService ;
28+ _logger = logger ;
29+ }
30+
31+ /// <summary>
32+ /// Create and send a notification to a user
33+ /// </summary>
34+ public async Task < Notification > SendNotificationAsync (
35+ string recipientUserId ,
36+ string title ,
37+ string message ,
38+ string type ,
39+ string category ,
40+ Guid ? relatedEntityId = null ,
41+ string ? relatedEntityType = null )
42+ {
43+ var organizationId = await _userContext . GetActiveOrganizationIdAsync ( ) ;
44+
45+ // Get user preferences
46+ var preferences = await GetNotificationPreferencesAsync ( recipientUserId ) ;
47+
48+ var notification = new Notification
49+ {
50+ Id = Guid . NewGuid ( ) ,
51+ OrganizationId = organizationId ! . Value ,
52+ RecipientUserId = recipientUserId ,
53+ Title = title ,
54+ Message = message ,
55+ Type = type ,
56+ Category = category ,
57+ RelatedEntityId = relatedEntityId ,
58+ RelatedEntityType = relatedEntityType ,
59+ SentOn = DateTime . UtcNow ,
60+ IsRead = false ,
61+ SendInApp = preferences . EnableInAppNotifications ,
62+ SendEmail = preferences . EnableEmailNotifications && ShouldSendEmail ( category , preferences ) ,
63+ SendSMS = preferences . EnableSMSNotifications && ShouldSendSMS ( category , preferences )
64+ } ;
65+
66+ // Save in-app notification
67+ await CreateAsync ( notification ) ;
68+
69+ // Send email if enabled
70+ if ( notification . SendEmail && ! string . IsNullOrEmpty ( preferences . EmailAddress ) )
71+ {
72+ try
73+ {
74+ await _emailService . SendEmailAsync (
75+ preferences . EmailAddress ,
76+ title ,
77+ message ) ;
78+
79+ notification . EmailSent = true ;
80+ notification . EmailSentOn = DateTime . UtcNow ;
81+ }
82+ catch ( Exception ex )
83+ {
84+ _logger . LogError ( ex , $ "Failed to send email notification to { recipientUserId } ") ;
85+ notification . EmailError = ex . Message ;
86+ }
87+ }
88+
89+ // Send SMS if enabled
90+ if ( notification . SendSMS && ! string . IsNullOrEmpty ( preferences . PhoneNumber ) )
91+ {
92+ try
93+ {
94+ await _smsService . SendSMSAsync (
95+ preferences . PhoneNumber ,
96+ $ "{ title } : { message } ") ;
97+
98+ notification . SMSSent = true ;
99+ notification . SMSSentOn = DateTime . UtcNow ;
100+ }
101+ catch ( Exception ex )
102+ {
103+ _logger . LogError ( ex , $ "Failed to send SMS notification to { recipientUserId } ") ;
104+ notification . SMSError = ex . Message ;
105+ }
106+ }
107+
108+ await UpdateAsync ( notification ) ;
109+
110+ return notification ;
111+ }
112+
113+ /// <summary>
114+ /// Mark notification as read
115+ /// </summary>
116+ public async Task MarkAsReadAsync ( Guid notificationId )
117+ {
118+ var notification = await GetByIdAsync ( notificationId ) ;
119+ if ( notification == null ) return ;
120+
121+ notification . IsRead = true ;
122+ notification . ReadOn = DateTime . UtcNow ;
123+
124+ await UpdateAsync ( notification ) ;
125+ }
126+
127+ /// <summary>
128+ /// Get unread notifications for current user
129+ /// </summary>
130+ public async Task < List < Notification > > GetUnreadNotificationsAsync ( )
131+ {
132+ var userId = await _userContext . GetUserIdAsync ( ) ;
133+ var organizationId = await _userContext . GetActiveOrganizationIdAsync ( ) ;
134+
135+ return await _context . Notifications
136+ . Where ( n => n . OrganizationId == organizationId
137+ && n . RecipientUserId == userId
138+ && ! n . IsRead
139+ && ! n . IsDeleted )
140+ . OrderByDescending ( n => n . SentOn )
141+ . Take ( 50 )
142+ . ToListAsync ( ) ;
143+ }
144+
145+ /// <summary>
146+ /// Get notification history for current user
147+ /// </summary>
148+ public async Task < List < Notification > > GetNotificationHistoryAsync ( int count = 100 )
149+ {
150+ var userId = await _userContext . GetUserIdAsync ( ) ;
151+ var organizationId = await _userContext . GetActiveOrganizationIdAsync ( ) ;
152+
153+ return await _context . Notifications
154+ . Where ( n => n . OrganizationId == organizationId
155+ && n . RecipientUserId == userId
156+ && ! n . IsDeleted )
157+ . OrderByDescending ( n => n . SentOn )
158+ . Take ( count )
159+ . ToListAsync ( ) ;
160+ }
161+
162+ /// <summary>
163+ /// Get or create notification preferences for user
164+ /// </summary>
165+ private async Task < NotificationPreferences > GetNotificationPreferencesAsync ( string userId )
166+ {
167+ var organizationId = await _userContext . GetActiveOrganizationIdAsync ( ) ;
168+
169+ var preferences = await _context . NotificationPreferences
170+ . FirstOrDefaultAsync ( p => p . OrganizationId == organizationId
171+ && p . UserId == userId
172+ && ! p . IsDeleted ) ;
173+
174+ if ( preferences == null )
175+ {
176+ // Create default preferences
177+ preferences = new NotificationPreferences
178+ {
179+ Id = Guid . NewGuid ( ) ,
180+ OrganizationId = organizationId ! . Value ,
181+ UserId = userId ,
182+ EnableInAppNotifications = true ,
183+ EnableEmailNotifications = true ,
184+ EnableSMSNotifications = false ,
185+ EmailLeaseExpiring = true ,
186+ EmailPaymentDue = true ,
187+ EmailPaymentReceived = true ,
188+ EmailApplicationStatusChange = true ,
189+ EmailMaintenanceUpdate = true ,
190+ EmailInspectionScheduled = true
191+ } ;
192+
193+ _context . NotificationPreferences . Add ( preferences ) ;
194+ await _context . SaveChangesAsync ( ) ;
195+ }
196+
197+ return preferences ;
198+ }
199+
200+ private bool ShouldSendEmail ( string category , NotificationPreferences prefs )
201+ {
202+ return category switch
203+ {
204+ NotificationConstants . Categories . Lease => prefs . EmailLeaseExpiring ,
205+ NotificationConstants . Categories . Payment => prefs . EmailPaymentDue ,
206+ NotificationConstants . Categories . Application => prefs . EmailApplicationStatusChange ,
207+ NotificationConstants . Categories . Maintenance => prefs . EmailMaintenanceUpdate ,
208+ NotificationConstants . Categories . Inspection => prefs . EmailInspectionScheduled ,
209+ _ => true
210+ } ;
211+ }
212+
213+ private bool ShouldSendSMS ( string category , NotificationPreferences prefs )
214+ {
215+ return category switch
216+ {
217+ NotificationConstants . Categories . Payment => prefs . SMSPaymentDue ,
218+ NotificationConstants . Categories . Maintenance => prefs . SMSMaintenanceEmergency ,
219+ NotificationConstants . Categories . Lease => prefs . SMSLeaseExpiringUrgent ,
220+ _ => false
221+ } ;
222+ }
223+ }
0 commit comments