- Introduced `PageSeo` component for managing page metadata for social sharing. - Created Open Graph image templates using SVG and static fonts for better visual representation. - Implemented service alert management with functions to check active alerts and format route numbers. - Added utility functions for generating and watching alert validity. - Developed a script to generate Open Graph images dynamically based on page content. - Included tests for service alert functionalities to ensure correctness and reliability.
58 lines
1.6 KiB
TypeScript
58 lines
1.6 KiB
TypeScript
import type { ServiceAlert } from './ridebus';
|
|
|
|
export function isAlertActive(alert: ServiceAlert, now: number): boolean {
|
|
return (
|
|
Date.parse(alert.startTime) <= now &&
|
|
(alert.endTime === null || now < Date.parse(alert.endTime))
|
|
);
|
|
}
|
|
|
|
export function getActiveAlerts(
|
|
alerts: ServiceAlert[],
|
|
cityId: number,
|
|
now: number
|
|
): ServiceAlert[] {
|
|
const seen = new Set<number>();
|
|
return alerts.filter((alert) => {
|
|
if (
|
|
alert.cityId !== cityId ||
|
|
seen.has(alert.id) ||
|
|
!isAlertActive(alert, now)
|
|
)
|
|
return false;
|
|
seen.add(alert.id);
|
|
return true;
|
|
});
|
|
}
|
|
|
|
export function formatAlertRouteNumbers(alert: ServiceAlert): string {
|
|
return alert.routeNumbers.map((number) => `№${number}`).join(' · ');
|
|
}
|
|
|
|
// Recheck the current data at each start/end boundary, independently of polling.
|
|
// Long timers are capped because browsers store their delay as a signed int32.
|
|
export function watchAlertValidity(
|
|
alerts: ServiceAlert[],
|
|
onChange: () => void
|
|
) {
|
|
let timer: ReturnType<typeof setTimeout>;
|
|
function schedule() {
|
|
const now = Date.now();
|
|
const next = alerts
|
|
.flatMap((alert) => [alert.startTime, alert.endTime])
|
|
.filter((time): time is string => time !== null)
|
|
.map(Date.parse)
|
|
.filter((time) => time > now)
|
|
.reduce((earliest, time) => Math.min(earliest, time), Infinity);
|
|
if (Number.isFinite(next))
|
|
timer = setTimeout(refresh, Math.min(next - now, 2147483647));
|
|
}
|
|
function refresh() {
|
|
onChange();
|
|
schedule();
|
|
}
|
|
// Also cover a boundary crossed between render and effect subscription.
|
|
timer = setTimeout(refresh, 0);
|
|
return () => clearTimeout(timer);
|
|
}
|