Merge pull request #195 from cita-777/codex/site-announcement-timezone-fix

[codex] prefer client timezone for site announcements
This commit is contained in:
Cita
2026-03-20 14:18:01 +08:00
committed by GitHub
4 changed files with 28 additions and 2 deletions
+2 -1
View File
@@ -6,6 +6,7 @@ import { clearFocusParams, readFocusAnnouncementId } from './helpers/navigationF
import {
formatSiteAnnouncementSeenAt,
readClientTimeZone,
resolveSiteAnnouncementTimeZone,
SiteAnnouncementContent,
} from './helpers/siteAnnouncementPresentation.js';
import { tr } from '../i18n.js';
@@ -44,7 +45,7 @@ export default function SiteAnnouncements() {
const rowRefs = useRef<Map<number, HTMLDivElement>>(new Map());
const highlightTimerRef = useRef<number | null>(null);
const viewerTimeZone = useMemo(() => readClientTimeZone(), []);
const displayTimeZone = serverTimeZone || viewerTimeZone;
const displayTimeZone = resolveSiteAnnouncementTimeZone(viewerTimeZone, serverTimeZone);
const siteNameById = useMemo(() => {
const map = new Map<number, string>();
@@ -5,6 +5,7 @@ import {
SiteAnnouncementContent,
formatSiteAnnouncementSeenAt,
readClientTimeZone,
resolveSiteAnnouncementTimeZone,
} from './siteAnnouncementPresentation.js';
type BrowserGlobals = {
@@ -85,6 +86,11 @@ describe('siteAnnouncementPresentation helpers', () => {
expect(formatSiteAnnouncementSeenAt('2026-03-20 04:23:27', 'Asia/Shanghai')).toBe('2026/03/20 12:23:27');
});
it('prefers client timezone over server timezone', () => {
expect(resolveSiteAnnouncementTimeZone('Asia/Shanghai', 'UTC')).toBe('Asia/Shanghai');
expect(resolveSiteAnnouncementTimeZone('', 'UTC')).toBe('UTC');
});
it('reads the browser timezone when available', () => {
expect(readClientTimeZone()).toBeTruthy();
});
@@ -340,6 +340,17 @@ export function readClientTimeZone(): string | undefined {
}
}
export function resolveSiteAnnouncementTimeZone(
clientTimeZone?: string | null,
serverTimeZone?: string | null,
): string | undefined {
const client = String(clientTimeZone || '').trim();
if (client) return client;
const server = String(serverTimeZone || '').trim();
return server || undefined;
}
export function formatSiteAnnouncementSeenAt(
value: string | null | undefined,
timeZone = readClientTimeZone(),
+9 -1
View File
@@ -21,6 +21,14 @@ vi.mock('../api.js', () => ({
api: apiMock,
}));
vi.mock('./helpers/siteAnnouncementPresentation.js', async () => {
const actual = await vi.importActual<typeof import('./helpers/siteAnnouncementPresentation.js')>('./helpers/siteAnnouncementPresentation.js');
return {
...actual,
readClientTimeZone: () => 'Asia/Shanghai',
};
});
async function flushMicrotasks() {
await act(async () => {
await Promise.resolve();
@@ -107,7 +115,7 @@ describe('SiteAnnouncements page', () => {
expect(apiMock.getRuntimeSettings).toHaveBeenCalled();
expect(JSON.stringify(root!.toJSON())).toContain('站点公告');
expect(JSON.stringify(root!.toJSON())).toContain('Maintenance');
expect(JSON.stringify(root!.toJSON())).toContain('2026/03/20 04:23:27');
expect(JSON.stringify(root!.toJSON())).toContain('2026/03/20 12:23:27');
const highlightedRows = root!.root.findAll((node) => {
const className = typeof node.props.className === 'string' ? node.props.className : '';