59 lines
2.2 KiB
TypeScript
59 lines
2.2 KiB
TypeScript
// ntfy-style priority scale (docs/migration-ntfy.md) — reused here so a
|
|
// value already familiar to anyone migrating from ntfy behaves the way
|
|
// they'd expect: "min"/1 means "log it, don't buzz the phone."
|
|
const PRIORITY_ALIASES: Record<string, number> = {
|
|
min: 1,
|
|
low: 2,
|
|
default: 3,
|
|
high: 4,
|
|
urgent: 5,
|
|
max: 5,
|
|
}
|
|
|
|
const DEFAULT_PRIORITY = 3
|
|
const MIN_PRIORITY_NO_PUSH = 1
|
|
|
|
export function resolvePriority(raw: string | null | undefined): number {
|
|
if (!raw) return DEFAULT_PRIORITY
|
|
const trimmed = raw.trim().toLowerCase()
|
|
// The `in` check above guarantees the key exists.
|
|
if (trimmed in PRIORITY_ALIASES) return PRIORITY_ALIASES[trimmed]!
|
|
const parsed = Number(trimmed)
|
|
return Number.isFinite(parsed) ? parsed : DEFAULT_PRIORITY
|
|
}
|
|
|
|
// "min" priority notifications are stored and shown in-app like any other
|
|
// — they just don't trigger a push, so a noisy automation can stay in its
|
|
// normal topic instead of needing a dedicated quiet topic.
|
|
export function isQuietPriority(raw: string | null | undefined): boolean {
|
|
return resolvePriority(raw) <= MIN_PRIORITY_NO_PUSH
|
|
}
|
|
|
|
// Household-wide "quiet hours" window (Admin > System) — true when `now`
|
|
// falls inside [start, end) in the given IANA timezone. Handles a window
|
|
// that wraps past midnight (e.g. 23:00-07:00) by checking OR instead of
|
|
// AND once start > end.
|
|
export function isWithinQuietHours(start: string, end: string, timezone: string, now = new Date()): boolean {
|
|
const parts = new Intl.DateTimeFormat('en-GB', {
|
|
timeZone: timezone,
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hourCycle: 'h23',
|
|
}).formatToParts(now)
|
|
const hour = Number(parts.find((p) => p.type === 'hour')?.value ?? '0')
|
|
const minute = Number(parts.find((p) => p.type === 'minute')?.value ?? '0')
|
|
const nowMinutes = hour * 60 + minute
|
|
|
|
const [startH, startM] = start.split(':').map(Number)
|
|
const [endH, endM] = end.split(':').map(Number)
|
|
const startMinutes = (startH ?? 0) * 60 + (startM ?? 0)
|
|
const endMinutes = (endH ?? 0) * 60 + (endM ?? 0)
|
|
|
|
if (startMinutes === endMinutes) return false
|
|
|
|
if (startMinutes < endMinutes) {
|
|
return nowMinutes >= startMinutes && nowMinutes < endMinutes
|
|
}
|
|
return nowMinutes >= startMinutes || nowMinutes < endMinutes
|
|
}
|