Files
2026-01-16 16:46:57 +01:00

72 lines
2.2 KiB
TypeScript

import type { ValueObject } from '@core/shared/domain/ValueObject';
import { NotificationDomainError } from '../errors/NotificationDomainError';
export interface QuietHoursProps {
startHour: number;
endHour: number;
}
/**
* Value Object: QuietHours
*
* Encapsulates a daily quiet-hours window using 0-23 hour indices and
* provides logic to determine whether a given hour falls within the window.
*
* Supports both normal ranges (start < end) and overnight ranges (start > end).
*/
export class QuietHours implements ValueObject<QuietHoursProps> {
public readonly props: QuietHoursProps;
private constructor(startHour: number, endHour: number) {
this.props = { startHour, endHour };
}
/**
* Factory with validation.
* - Hours must be integers between 0 and 23.
* - Start and end cannot be equal (would mean a 0-length window).
*/
static create(startHour: number, endHour: number): QuietHours {
QuietHours.assertValidHour(startHour, 'Start hour');
QuietHours.assertValidHour(endHour, 'End hour');
if (startHour === endHour) {
throw new NotificationDomainError('Quiet hours start and end cannot be the same', 'validation');
}
return new QuietHours(startHour, endHour);
}
private static assertValidHour(value: number, label: string): void {
if (!Number.isInteger(value)) {
throw new NotificationDomainError(`${label} must be an integer between 0 and 23`, 'validation');
}
if (value < 0 || value > 23) {
throw new NotificationDomainError(`${label} must be between 0 and 23`, 'validation');
}
}
/**
* Returns true if the given hour (0-23) lies within the quiet window.
*/
containsHour(hour: number): boolean {
QuietHours.assertValidHour(hour, 'Hour');
const { startHour, endHour } = this.props;
if (startHour < endHour) {
// Normal range (e.g., 22:00 to 23:59 is NOT this case, but 1:00 to 7:00 is)
return hour >= startHour && hour < endHour;
}
// Overnight range (e.g., 22:00 to 07:00)
return hour >= startHour || hour < endHour;
}
equals(other: ValueObject<QuietHoursProps>): boolean {
return (
this.props.startHour === other.props.startHour &&
this.props.endHour === other.props.endHour
);
}
}