refactor(notifications): quiet-hours uses shared tested time-window helper
isInQuietHours was a hand-rolled, untested duplicate of the overnight-window logic. Replace it with the shared, unit-tested isWithinTimeWindow (utils/ timeWindow.ts) - identical behavior for valid HH:MM inputs, more robust on malformed ones (returns false rather than doing NaN math), and now covered by timeWindow.test.ts. One implementation instead of two. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import {
|
|||||||
import { focusAssistActiveAtom } from '../../state/focusAssist';
|
import { focusAssistActiveAtom } from '../../state/focusAssist';
|
||||||
import { manualDndAtom } from '../../state/manualDnd';
|
import { manualDndAtom } from '../../state/manualDnd';
|
||||||
import { isSnoozeActive, notificationSnoozeUntilAtom } from '../../state/notificationSnooze';
|
import { isSnoozeActive, notificationSnoozeUntilAtom } from '../../state/notificationSnooze';
|
||||||
|
import { isWithinTimeWindow } from '../../utils/timeWindow';
|
||||||
import { roomToUnreadAtom } from '../../state/room/roomToUnread';
|
import { roomToUnreadAtom } from '../../state/room/roomToUnread';
|
||||||
import LogoSVG from '../../../../public/res/lotus.png';
|
import LogoSVG from '../../../../public/res/lotus.png';
|
||||||
import LogoUnreadSVG from '../../../../public/res/lotus-unread.png';
|
import LogoUnreadSVG from '../../../../public/res/lotus-unread.png';
|
||||||
@@ -69,18 +70,6 @@ import {
|
|||||||
// the async invite-atom population lands first and isn't mistaken for new invites.
|
// the async invite-atom population lands first and isn't mistaken for new invites.
|
||||||
const INVITE_NOTIFY_ARM_DELAY_MS = 3000;
|
const INVITE_NOTIFY_ARM_DELAY_MS = 3000;
|
||||||
|
|
||||||
function isInQuietHours(start: string, end: string): boolean {
|
|
||||||
const now = new Date();
|
|
||||||
const [sh, sm] = start.split(':').map(Number);
|
|
||||||
const [eh, em] = end.split(':').map(Number);
|
|
||||||
const cur = now.getHours() * 60 + now.getMinutes();
|
|
||||||
const s = sh! * 60 + (sm ?? 0);
|
|
||||||
const e = eh! * 60 + (em ?? 0);
|
|
||||||
// start===end means zero-length window → treat as disabled (no quiet hours)
|
|
||||||
if (s === e) return false;
|
|
||||||
return s < e ? cur >= s && cur < e : cur >= s || cur < e;
|
|
||||||
}
|
|
||||||
|
|
||||||
function SystemEmojiFeature() {
|
function SystemEmojiFeature() {
|
||||||
const [twitterEmoji] = useSetting(settingsAtom, 'twitterEmoji');
|
const [twitterEmoji] = useSetting(settingsAtom, 'twitterEmoji');
|
||||||
|
|
||||||
@@ -259,7 +248,7 @@ function InviteNotifications() {
|
|||||||
focusAssistActive ||
|
focusAssistActive ||
|
||||||
manualDnd ||
|
manualDnd ||
|
||||||
isSnoozeActive(snoozeUntil) ||
|
isSnoozeActive(snoozeUntil) ||
|
||||||
(quietHoursEnabled && isInQuietHours(quietHoursStart, quietHoursEnd));
|
(quietHoursEnabled && isWithinTimeWindow(quietHoursStart, quietHoursEnd));
|
||||||
if (quietActive) return;
|
if (quietActive) return;
|
||||||
|
|
||||||
if (showNotifications && notificationPermission('granted')) {
|
if (showNotifications && notificationPermission('granted')) {
|
||||||
@@ -539,7 +528,7 @@ function MessageNotifications() {
|
|||||||
focusAssistActive ||
|
focusAssistActive ||
|
||||||
manualDnd ||
|
manualDnd ||
|
||||||
isSnoozeActive(snoozeUntil) ||
|
isSnoozeActive(snoozeUntil) ||
|
||||||
(quietHoursEnabled && isInQuietHours(quietHoursStart, quietHoursEnd));
|
(quietHoursEnabled && isWithinTimeWindow(quietHoursStart, quietHoursEnd));
|
||||||
if (quietActive) return;
|
if (quietActive) return;
|
||||||
|
|
||||||
if (showNotifications && notificationPermission('granted')) {
|
if (showNotifications && notificationPermission('granted')) {
|
||||||
|
|||||||
Reference in New Issue
Block a user