diff --git a/frontend/src/composables/useGlobalNow.ts b/frontend/src/composables/useGlobalNow.ts index 83d9cf9ef..c5e3510e7 100644 --- a/frontend/src/composables/useGlobalNow.ts +++ b/frontend/src/composables/useGlobalNow.ts @@ -1,4 +1,4 @@ -import { ref } from 'vue' +import { getCurrentInstance, ref } from 'vue' import { createGlobalState, useIntervalFn } from '@vueuse/core' import { onBeforeRouteUpdate } from 'vue-router' @@ -18,10 +18,14 @@ export const useGlobalNow = createGlobalState(() => { useIntervalFn(update, GLOBAL_NOW_INTERVAL, { immediate: true }) - // ensure the now value is refreshed when the route changes - onBeforeRouteUpdate(() => { - update() - }) + // Now that this state can be initialised from a plain helper (formatDateSince), the + // first caller is not guaranteed to be a component — guard the route hook accordingly. + if (getCurrentInstance()) { + // ensure the now value is refreshed when the route changes + onBeforeRouteUpdate(() => { + update() + }) + } return { now, diff --git a/frontend/src/helpers/time/formatDate.ts b/frontend/src/helpers/time/formatDate.ts index 4ff9a4da5..ed7f4a3d7 100644 --- a/frontend/src/helpers/time/formatDate.ts +++ b/frontend/src/helpers/time/formatDate.ts @@ -5,6 +5,7 @@ import {i18n} from '@/i18n' import {createSharedComposable} from '@vueuse/core' import {computed, toValue, type MaybeRefOrGetter} from 'vue' import {useDateDisplay} from '@/composables/useDateDisplay' +import {useGlobalNow} from '@/composables/useGlobalNow' import {useTimeFormat} from '@/composables/useTimeFormat' import {DATE_DISPLAY, type DateDisplay} from '@/constants/dateDisplay' import {TIME_FORMAT, type TimeFormat} from '@/constants/timeFormat' @@ -49,8 +50,13 @@ export const formatDateSince = (date: Date | string | null) => { const locale = DAYJS_LOCALE_MAPPING[i18n.global.locale.value.toLowerCase()] ?? 'en' + // Computing the relative string against the shared, ticking `now` (instead of fromNow's + // internal Date.now()) makes every reactive caller re-render on the 60s tick, so open views + // don't keep showing a stale "x minutes ago". + const {now} = useGlobalNow() + return date - ? dayjs(date).locale(locale).fromNow() + ? dayjs(date).locale(locale).from(now.value) : '' }