/** * Application Use Cases: Notification Preferences * * Manages user notification preferences. */ import type { AsyncUseCase , Logger } from '@core/shared/application'; import { NotificationPreference } from '../../domain/entities/NotificationPreference'; import type { ChannelPreference, TypePreference } from '../../domain/entities/NotificationPreference'; import type { INotificationPreferenceRepository } from '../../domain/repositories/INotificationPreferenceRepository'; import type { NotificationType, NotificationChannel } from '../../domain/types/NotificationTypes'; import { NotificationDomainError } from '../../domain/errors/NotificationDomainError'; /** * Query: GetNotificationPreferencesQuery */ export class GetNotificationPreferencesQuery implements AsyncUseCase { constructor( private readonly preferenceRepository: INotificationPreferenceRepository, private readonly logger: Logger, ) {} async execute(driverId: string): Promise { this.logger.debug(`Fetching notification preferences for driver: ${driverId}`); try { const preferences = await this.preferenceRepository.getOrCreateDefault(driverId); this.logger.info(`Successfully fetched preferences for driver: ${driverId}`); return preferences; } catch (error) { this.logger.error(`Failed to fetch preferences for driver: ${driverId}`, error); throw error; } } } /** * Use Case: UpdateChannelPreferenceUseCase */ export interface UpdateChannelPreferenceCommand { driverId: string; channel: NotificationChannel; preference: ChannelPreference; } export class UpdateChannelPreferenceUseCase implements AsyncUseCase { constructor( private readonly preferenceRepository: INotificationPreferenceRepository, private readonly logger: Logger, ) {} async execute(command: UpdateChannelPreferenceCommand): Promise { this.logger.debug(`Updating channel preference for driver: ${command.driverId}, channel: ${command.channel}, preference: ${command.preference}`); try { const preferences = await this.preferenceRepository.getOrCreateDefault(command.driverId); const updated = preferences.updateChannel(command.channel, command.preference); await this.preferenceRepository.save(updated); this.logger.info(`Successfully updated channel preference for driver: ${command.driverId}`); } catch (error) { this.logger.error(`Failed to update channel preference for driver: ${command.driverId}, channel: ${command.channel}`, error); throw error; } } } /** * Use Case: UpdateTypePreferenceUseCase */ export interface UpdateTypePreferenceCommand { driverId: string; type: NotificationType; preference: TypePreference; } export class UpdateTypePreferenceUseCase implements AsyncUseCase { constructor( private readonly preferenceRepository: INotificationPreferenceRepository, private readonly logger: Logger, ) {} async execute(command: UpdateTypePreferenceCommand): Promise { this.logger.debug(`Updating type preference for driver: ${command.driverId}, type: ${command.type}, preference: ${command.preference}`); try { const preferences = await this.preferenceRepository.getOrCreateDefault(command.driverId); const updated = preferences.updateTypePreference(command.type, command.preference); await this.preferenceRepository.save(updated); this.logger.info(`Successfully updated type preference for driver: ${command.driverId}`); } catch (error) { this.logger.error(`Failed to update type preference for driver: ${command.driverId}, type: ${command.type}`, error); throw error; } } } /** * Use Case: UpdateQuietHoursUseCase */ export interface UpdateQuietHoursCommand { driverId: string; startHour: number | undefined; endHour: number | undefined; } export class UpdateQuietHoursUseCase implements AsyncUseCase { constructor( private readonly preferenceRepository: INotificationPreferenceRepository, private readonly logger: Logger, ) {} async execute(command: UpdateQuietHoursCommand): Promise { this.logger.debug(`Updating quiet hours for driver: ${command.driverId}, startHour: ${command.startHour}, endHour: ${command.endHour}`); try { // Validate hours if provided if (command.startHour !== undefined && (command.startHour < 0 || command.startHour > 23)) { this.logger.warn(`Invalid start hour provided for driver: ${command.driverId}. startHour: ${command.startHour}`); throw new NotificationDomainError('Start hour must be between 0 and 23'); } if (command.endHour !== undefined && (command.endHour < 0 || command.endHour > 23)) { this.logger.warn(`Invalid end hour provided for driver: ${command.driverId}. endHour: ${command.endHour}`); throw new NotificationDomainError('End hour must be between 0 and 23'); } const preferences = await this.preferenceRepository.getOrCreateDefault(command.driverId); const updated = preferences.updateQuietHours(command.startHour, command.endHour); await this.preferenceRepository.save(updated); this.logger.info(`Successfully updated quiet hours for driver: ${command.driverId}`); } catch (error) { this.logger.error(`Failed to update quiet hours for driver: ${command.driverId}`, error); throw error; } } } /** * Use Case: SetDigestModeUseCase */ export interface SetDigestModeCommand { driverId: string; enabled: boolean; frequencyHours?: number; } export class SetDigestModeUseCase implements AsyncUseCase { constructor( private readonly preferenceRepository: INotificationPreferenceRepository, ) {} async execute(command: SetDigestModeCommand): Promise { if (command.frequencyHours !== undefined && command.frequencyHours < 1) { throw new NotificationDomainError('Digest frequency must be at least 1 hour'); } const preferences = await this.preferenceRepository.getOrCreateDefault(command.driverId); const updated = preferences.setDigestMode(command.enabled, command.frequencyHours); await this.preferenceRepository.save(updated); } }