mirror of
https://github.com/Permissionless-Software-Foundation/psf-memo.git
synced 2026-09-21 16:52:01 -07:00
Implement topic metadata columns
Add lastSeen and followerCount to topicSummaries across the indexer, DB, and client. The indexer now tracks the newest post seen time, updates follower counts idempotently on follow/unfollow, and preserves post metadata. The DB exposes lastSeen and followerCount from GET /topics and rebuilds both from the rooms store in the backfill. The client renders the four-column topics page with relative-time labels. By coder.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Unit tests for the relative-time formatter used by the topics page.
|
||||
*/
|
||||
|
||||
'use strict'
|
||||
|
||||
const test = require('node:test')
|
||||
const assert = require('node:assert/strict')
|
||||
const { relativeTime } = require('../../src/services/relative-time')
|
||||
|
||||
const NOW = 1800000000000
|
||||
const HOUR = 60 * 60 * 1000
|
||||
const DAY = 24 * HOUR
|
||||
|
||||
test('returns "No posts" when there is no last-seen time', () => {
|
||||
assert.equal(relativeTime(0, NOW), 'No posts')
|
||||
assert.equal(relativeTime(null, NOW), 'No posts')
|
||||
assert.equal(relativeTime(undefined, NOW), 'No posts')
|
||||
})
|
||||
|
||||
test('returns "Less than an hour ago" for under an hour', () => {
|
||||
assert.equal(relativeTime(NOW - 1, NOW), 'Less than an hour ago')
|
||||
assert.equal(relativeTime(NOW - (HOUR - 1), NOW), 'Less than an hour ago')
|
||||
})
|
||||
|
||||
test('returns "1 hour ago" at exactly one hour', () => {
|
||||
assert.equal(relativeTime(NOW - HOUR, NOW), '1 hour ago')
|
||||
})
|
||||
|
||||
test('returns whole hours under a day', () => {
|
||||
assert.equal(relativeTime(NOW - 2 * HOUR, NOW), '2 hours ago')
|
||||
assert.equal(relativeTime(NOW - 5 * HOUR, NOW), '5 hours ago')
|
||||
assert.equal(relativeTime(NOW - 23 * HOUR, NOW), '23 hours ago')
|
||||
})
|
||||
|
||||
test('returns "1 day ago" at exactly one day', () => {
|
||||
assert.equal(relativeTime(NOW - DAY, NOW), '1 day ago')
|
||||
})
|
||||
|
||||
test('returns whole days at or beyond a day', () => {
|
||||
assert.equal(relativeTime(NOW - 2 * DAY, NOW), '2 days ago')
|
||||
assert.equal(relativeTime(NOW - 30 * DAY, NOW), '30 days ago')
|
||||
})
|
||||
|
||||
test('floors partial hours and days', () => {
|
||||
assert.equal(relativeTime(NOW - (5 * HOUR + 59 * 60 * 1000), NOW), '5 hours ago')
|
||||
assert.equal(relativeTime(NOW - (2 * DAY + 23 * HOUR), NOW), '2 days ago')
|
||||
})
|
||||
@@ -110,6 +110,34 @@ test('getTopic returns null when the topic is not loaded', async () => {
|
||||
assert.equal(page.getTopic('bitcoin'), null)
|
||||
})
|
||||
|
||||
test('getLastSeenLabel formats the topic last-seen time', async () => {
|
||||
const page = new TopicDiscoveryPage({
|
||||
memoDb: makeMemoDb({ topics: [{ room: 'bitcoin', postCount: 1, lastSeen: 1799998200000 }] })
|
||||
})
|
||||
|
||||
await page.load()
|
||||
|
||||
assert.equal(page.getLastSeenLabel('bitcoin', 1800000000000), 'Less than an hour ago')
|
||||
})
|
||||
|
||||
test('getLastSeenLabel returns "No posts" for a topic with no posts', async () => {
|
||||
const page = new TopicDiscoveryPage({
|
||||
memoDb: makeMemoDb({ topics: [{ room: 'lone', postCount: 0, lastSeen: 0 }] })
|
||||
})
|
||||
|
||||
await page.load()
|
||||
|
||||
assert.equal(page.getLastSeenLabel('lone', 1800000000000), 'No posts')
|
||||
})
|
||||
|
||||
test('getLastSeenLabel returns null for an unknown topic', async () => {
|
||||
const page = new TopicDiscoveryPage({ memoDb: makeMemoDb({ topics: [] }) })
|
||||
|
||||
await page.load()
|
||||
|
||||
assert.equal(page.getLastSeenLabel('missing', 1800000000000), null)
|
||||
})
|
||||
|
||||
test('openTopic navigates to the encoded topic feed path', () => {
|
||||
const calls = []
|
||||
const page = new TopicDiscoveryPage({
|
||||
|
||||
Reference in New Issue
Block a user