import { Injectable, Logger, NotFoundException } from "@nestjs/common"; import { EmailNotificationStrategy } from "./strategies/notification.email.strategy"; import { NotificationStrategy } from "./strategies/notification.strategy"; import { SmsNotificationStrategy } from "./strategies/notification.sms.strategy"; type StrategyMethod = "sms" | "email" @Injectable() export class NotificationsService { private readonly logger = new Logger(NotificationsService.name); private readonly strategies: Map constructor(private readonly email: EmailNotificationStrategy, private readonly sms: SmsNotificationStrategy) { this.strategies = new Map([ ["sms", this.sms as NotificationStrategy], ["email", this.email as NotificationStrategy] ]) } /** * Dispatch a notification to an operator or customer. * TODO: wire to email/SMS provider (SendGrid, SMS API, etc.) via a mailer service. */ async directSend(method: StrategyMethod, recipient: string, message: string) { const strategy = this.strategies.get(method); if (!strategy) { throw new NotFoundException(); } const sent = await strategy.send(recipient, message); this.logger.log(`is sent - ${sent}`); } async notifyDriverVehicleAssignment(params: { driverPhone: string; driverName: string; vehiclePlateNumber: string; bookingReference: string; pickupAddress?: string | null; destinationYard?: string | null; }): Promise { const { driverPhone, driverName, vehiclePlateNumber, bookingReference, pickupAddress, destinationYard } = params; const message = `Dear ${driverName}, you have been assigned to a first-mile pickup. ` + `Booking: ${bookingReference}. Vehicle: ${vehiclePlateNumber}. ` + (pickupAddress ? `Pickup: ${pickupAddress}. ` : '') + (destinationYard ? `Destination: ${destinationYard}.` : ''); try { await this.directSend('sms', driverPhone, message); } catch (err) { this.logger.error(`Failed to notify driver ${driverName} (${driverPhone}): ${String(err)}`); } } }