diff --git a/src/Koogle.Domain/Interfaces/IEmailService.cs b/src/Koogle.Domain/Interfaces/IEmailService.cs new file mode 100644 index 0000000..bd62575 --- /dev/null +++ b/src/Koogle.Domain/Interfaces/IEmailService.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Koogle.Domain.Interfaces +{ + /// + /// Service interface for email notifications. + /// + public interface IEmailService + { + /// + /// Sends notification to club admins about a new membership request. + /// + /// The club receiving the membership request. + /// Display name of the requesting user. + /// Email of the requesting user. + /// Cancellation token. + Task SendMembershipRequestNotificationAsync( + Guid clubId, + string userDisplayName, + string userEmail, + CancellationToken ct = default); + + /// + /// Sends notification to user that their membership was approved. + /// + /// Email of the approved user. + /// Name of the club. + /// Cancellation token. + Task SendMembershipApprovedAsync( + string userEmail, + string clubName, + CancellationToken ct = default); + + /// + /// Sends notification to user that their membership was rejected. + /// + /// Email of the rejected user. + /// Name of the club. + /// Optional rejection reason. + /// Cancellation token. + Task SendMembershipRejectedAsync( + string userEmail, + string clubName, + string? reason, + CancellationToken ct = default); + } +} diff --git a/src/Koogle.Infrastructure/DependencyInjection.cs b/src/Koogle.Infrastructure/DependencyInjection.cs index 3fd9522..67fb679 100644 --- a/src/Koogle.Infrastructure/DependencyInjection.cs +++ b/src/Koogle.Infrastructure/DependencyInjection.cs @@ -4,6 +4,7 @@ using Koogle.Infrastructure.Data; using Koogle.Infrastructure.Identity; using Koogle.Infrastructure.Repositories; using Koogle.Infrastructure.Security; +using Koogle.Infrastructure.Services; using KoogleApp.Data; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; @@ -84,6 +85,9 @@ public static class DependencyInjection services.AddScoped(); services.AddScoped(); + // Services + services.AddScoped(); + services.AddCascadingAuthenticationState(); return services; diff --git a/src/Koogle.Infrastructure/Services/StubEmailService.cs b/src/Koogle.Infrastructure/Services/StubEmailService.cs new file mode 100644 index 0000000..1f6c4c2 --- /dev/null +++ b/src/Koogle.Infrastructure/Services/StubEmailService.cs @@ -0,0 +1,80 @@ +using Koogle.Domain.Interfaces; +using Microsoft.Extensions.Logging; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Koogle.Infrastructure.Services; + +/// +/// Stub email service that logs instead of sending emails. +/// TODO: Replace with actual SMTP implementation. +/// +public class StubEmailService : IEmailService +{ + private readonly ILogger _logger; + + /// + /// Creates a new StubEmailService instance. + /// + public StubEmailService(ILogger logger) + { + _logger = logger; + } + + /// + public Task SendMembershipRequestNotificationAsync( + Guid clubId, + string userDisplayName, + string userEmail, + CancellationToken ct = default) + { + _logger.LogInformation( + "[EMAIL STUB] Membership request notification - ClubId: {ClubId}, User: {UserDisplayName} ({UserEmail})", + clubId, userDisplayName, userEmail); + + // TODO: Implement actual email sending via SMTP + // - Get club admin emails from database + // - Build notification template + // - Send via configured SMTP provider + + return Task.CompletedTask; + } + + /// + public Task SendMembershipApprovedAsync( + string userEmail, + string clubName, + CancellationToken ct = default) + { + _logger.LogInformation( + "[EMAIL STUB] Membership approved - To: {UserEmail}, Club: {ClubName}", + userEmail, clubName); + + // TODO: Implement actual email sending via SMTP + // - Build approval notification template + // - Include link to dashboard + // - Send via configured SMTP provider + + return Task.CompletedTask; + } + + /// + public Task SendMembershipRejectedAsync( + string userEmail, + string clubName, + string? reason, + CancellationToken ct = default) + { + _logger.LogInformation( + "[EMAIL STUB] Membership rejected - To: {UserEmail}, Club: {ClubName}, Reason: {Reason}", + userEmail, clubName, reason ?? "(no reason provided)"); + + // TODO: Implement actual email sending via SMTP + // - Build rejection notification template + // - Include reason if provided + // - Send via configured SMTP provider + + return Task.CompletedTask; + } +}