fix(sessions): add defensive null checks for dates to prevent crashes

- Add null validation in SessionsTable, SessionInfo, SessionActivity, and DateDistance
- Log missing date fields in development mode only
- Display '—' placeholder when dates are null instead of crashing
- Addresses RangeError: Invalid time value on Sessions tab
This commit is contained in:
Arthur Sepiol 2025-11-14 13:15:36 +03:00
parent 7ac5913c86
commit ffd6fd666c
5 changed files with 49 additions and 5 deletions

2
pnpm-lock.yaml generated
View file

@ -364,8 +364,6 @@ importers:
specifier: ^5.9.3
version: 5.9.3
dist: {}
packages:
'@ampproject/remapping@2.3.0':

View file

@ -42,6 +42,19 @@ export function SessionActivity({
<LoadingPanel data={data} isLoading={isLoading} error={error}>
<Column gap>
{data?.map(({ eventId, createdAt, urlPath, eventName, visitId, hasData }) => {
if (!createdAt) {
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
console.error('[SessionActivity] Event missing createdAt', {
eventId,
visitId,
urlPath,
eventName,
});
}
return null;
}
const showHeader = !lastDay || !isSameDay(new Date(lastDay), new Date(createdAt));
lastDay = createdAt;

View file

@ -11,6 +11,18 @@ export function SessionInfo({ data }) {
const { formatValue } = useFormat();
const { getRegionName } = useRegionNames(locale);
if (process.env.NODE_ENV !== 'production') {
if (!data.lastAt || !data.firstAt) {
// eslint-disable-next-line no-console
console.error('[SessionInfo] Session missing date fields', {
sessionId: data.id,
hasLastAt: !!data.lastAt,
hasFirstAt: !!data.firstAt,
distinctId: data.distinctId,
});
}
}
return (
<Grid columns="repeat(auto-fit, minmax(200px, 1fr)" gap>
<Info label={formatMessage(labels.distinctId)} icon={<KeyRound />}>
@ -18,11 +30,11 @@ export function SessionInfo({ data }) {
</Info>
<Info label={formatMessage(labels.lastSeen)} icon={<Calendar />}>
<DateDistance date={new Date(data.lastAt)} />
{data.lastAt ? <DateDistance date={new Date(data.lastAt)} /> : '—'}
</Info>
<Info label={formatMessage(labels.firstSeen)} icon={<Calendar />}>
<DateDistance date={new Date(data.firstAt)} />
{data.firstAt ? <DateDistance date={new Date(data.firstAt)} /> : '—'}
</Info>
<Info

View file

@ -51,7 +51,20 @@ export function SessionsTable(props: DataTableProps) {
)}
</DataColumn>
<DataColumn id="lastAt" label={formatMessage(labels.lastSeen)}>
{(row: any) => <DateDistance date={new Date(row.createdAt)} />}
{(row: any) => {
if (!row.createdAt) {
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
console.error('[SessionsTable] Session missing createdAt', {
sessionId: row.id,
visits: row.visits,
views: row.views,
});
}
return '—';
}
return <DateDistance date={new Date(row.createdAt)} />;
}}
</DataColumn>
</DataTable>
);

View file

@ -6,6 +6,14 @@ export function DateDistance({ date }: { date: Date }) {
const { formatTimezoneDate } = useTimezone();
const { dateLocale } = useLocale();
if (!date || isNaN(date.getTime())) {
if (process.env.NODE_ENV !== 'production') {
// eslint-disable-next-line no-console
console.error('[DateDistance] Invalid date received', { date });
}
return <Text></Text>;
}
return (
<Text title={formatTimezoneDate(date.toISOString(), 'PPPpp')}>
{formatDistanceToNow(date, { addSuffix: true, locale: dateLocale })}