All files / src/hooks useNow.ts

100% Statements 21/21
100% Branches 6/6
100% Functions 6/6
100% Lines 18/18

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37            16x   16x 16x 16x       16x 627x 627x 232x 232x 75x 265x     627x 627x 627x 232x 232x         3835x     1435x  
// SPDX-License-Identifier: GPL-3.0-only
// Copyright (C) 2026 Max Boksem. See NOTICE for additional terms under GPLv3 section 7.
 
import { useSyncExternalStore } from "react";
import { nowSeconds } from "@/lib/date";
 
export const NOW_TICK_MS = 30_000;
 
let now = nowSeconds();
let timer: ReturnType<typeof setInterval> | null = null;
const listeners = new Set<() => void>();
 
// One timer serves every component on screen, and it only runs while one of
// them is mounted.
const subscribe = (listener: () => void) => {
	listeners.add(listener);
	if (timer === null) {
		now = nowSeconds();
		timer = setInterval(() => {
			now = nowSeconds();
			listeners.forEach((l) => l());
		}, NOW_TICK_MS);
	}
	return () => {
		listeners.delete(listener);
		if (listeners.size === 0 && timer !== null) {
			clearInterval(timer);
			timer = null;
		}
	};
};
 
const getSnapshot = () => now;
 
/** The current Unix time in seconds, updated every 30 seconds. */
export const useNow = (): number => useSyncExternalStore(subscribe, getSnapshot);