Private
Public Access
Show the date on message timestamps that aren't from today
A bare "4:04 PM" gave no way to tell today's message from one sent last
week. Today stays time-only; older messages gain just enough date to
place them: "Yesterday 4:04 PM", a weekday for the past week ("Mon
4:04 PM"), then "Oct 2, 4:04 PM" (with the year if it isn't this one).
Hovering a time shows the full date. All in the viewer's local time.
A new calendar day now always starts a new message group. Previously a
same-sender run that crossed midnight within the 5-minute window (11:58
PM then 12:01 AM) stayed under one header, which would have put the
later message under the wrong day's timestamp. The grouping rule moves
out of MessageList into messageGrouping.ts so it's unit-tested.
useLocalDay refreshes "today" at local midnight and when a hidden tab
becomes visible again, so a tab left open overnight doesn't keep showing
yesterday's messages as a bare time. .message-time no longer wraps, and
.message-author can shrink, so a long display name can't push the longer
label out of the row on a phone.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
eb30dc1753
commit
62b5eec2fb
9 files changed
+323
-19
No files matched your search
@@ -0,0 +1,67 @@
|
||||
import { act, renderHook } from '@testing-library/react'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useLocalDay } from './useLocalDay'
|
||||
|
||||
function setVisibility(state: 'visible' | 'hidden') {
|
||||
Object.defineProperty(document, 'visibilityState', { configurable: true, get: () => state })
|
||||
}
|
||||
|
||||
describe('useLocalDay', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
setVisibility('visible')
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers()
|
||||
// Remove the own-property override so jsdom's real getter shows through again.
|
||||
delete (document as unknown as Record<string, unknown>).visibilityState
|
||||
})
|
||||
|
||||
it('rolls over to the next day when local midnight passes', () => {
|
||||
vi.setSystemTime(new Date(2026, 9, 9, 23, 59, 30))
|
||||
const { result } = renderHook(() => useLocalDay())
|
||||
expect(result.current.getDate()).toBe(9)
|
||||
|
||||
act(() => {
|
||||
vi.advanceTimersByTime(60_000)
|
||||
})
|
||||
expect(result.current.getDate()).toBe(10)
|
||||
})
|
||||
|
||||
it('refreshes when the tab becomes visible after the clock moved a day (e.g. a sleeping laptop)', () => {
|
||||
vi.setSystemTime(new Date(2026, 9, 9, 12, 0))
|
||||
const { result } = renderHook(() => useLocalDay())
|
||||
|
||||
// The clock jumps without any timer firing in between.
|
||||
vi.setSystemTime(new Date(2026, 9, 10, 12, 0))
|
||||
act(() => {
|
||||
document.dispatchEvent(new Event('visibilitychange'))
|
||||
})
|
||||
expect(result.current.getDate()).toBe(10)
|
||||
})
|
||||
|
||||
it('keeps the same value (no rerender) when visibility changes on the same day', () => {
|
||||
vi.setSystemTime(new Date(2026, 9, 9, 12, 0))
|
||||
const { result } = renderHook(() => useLocalDay())
|
||||
const first = result.current
|
||||
|
||||
vi.setSystemTime(new Date(2026, 9, 9, 18, 0))
|
||||
act(() => {
|
||||
document.dispatchEvent(new Event('visibilitychange'))
|
||||
})
|
||||
expect(result.current).toBe(first)
|
||||
})
|
||||
|
||||
it('ignores visibility changes while the tab is hidden', () => {
|
||||
vi.setSystemTime(new Date(2026, 9, 9, 12, 0))
|
||||
const { result } = renderHook(() => useLocalDay())
|
||||
|
||||
setVisibility('hidden')
|
||||
vi.setSystemTime(new Date(2026, 9, 10, 12, 0))
|
||||
act(() => {
|
||||
document.dispatchEvent(new Event('visibilitychange'))
|
||||
})
|
||||
expect(result.current.getDate()).toBe(9)
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user