Files
edr-platform/apps/edr-freight-api/src/modules/notifications/notifications.service.ts
2026-07-16 00:33:31 +00:00

72 lines
2.6 KiB
TypeScript

import {
Injectable,
Logger,
NotFoundException,
ServiceUnavailableException,
} 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<StrategyMethod, NotificationStrategy>
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();
}
// A strategy returning false (or throwing) is a real delivery failure — do
// not swallow it. Surface it so callers observe the failure (existing
// callers wrap directSend in try/catch for best-effort notifications).
const sent = await strategy.send(recipient, message);
if (!sent) {
this.logger.error(
`Notification via ${method} to ${recipient} failed to send`,
);
throw new ServiceUnavailableException(
`Failed to send ${method} notification`,
);
}
this.logger.log(`Notification via ${method} to ${recipient} sent`);
}
async notifyDriverVehicleAssignment(params: {
driverPhone: string;
driverName: string;
vehiclePlateNumber: string;
bookingReference: string;
pickupAddress?: string | null;
destinationYard?: string | null;
}): Promise<void> {
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)}`);
}
}
}