From 9c3cb3a0ee45e0b12e05cb7c962a01ebd551b1e1 Mon Sep 17 00:00:00 2001 From: 2003dinijay Date: Thu, 2 Jul 2026 16:23:12 +0530 Subject: [PATCH 1/2] [Customer Portal][Microapp] fix: guard against invalid user timezone from /me The /me endpoint returns the ServiceNow placeholder --None-- when a user has no timezone set. This passed the nullish check in useDateTime and crashed dayjs.tz() with RangeError: invalid time zone, breaking the Support page lists. useDateTime now validates the timezone via Intl and falls back to the device timezone; MeProvider normalizes --None-- to undefined at the data boundary. --- .../microapp/src/context/me/MeProvider.tsx | 3 ++- .../microapp/src/utils/useDateTime.ts | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/customer-portal/microapp/src/context/me/MeProvider.tsx b/apps/customer-portal/microapp/src/context/me/MeProvider.tsx index eb1ef12008..fe785d7435 100644 --- a/apps/customer-portal/microapp/src/context/me/MeProvider.tsx +++ b/apps/customer-portal/microapp/src/context/me/MeProvider.tsx @@ -70,7 +70,8 @@ export default function MeProvider({ children }: { children: React.ReactNode }) id: meData.id, roles: meData.roles, isAdmin: meData.roles.includes(ADMIN_USER_ROLE), - timezone: meData.timezone, + // ServiceNow returns "--None--" for unset choice fields; treat it as absent. + timezone: meData.timezone && meData.timezone !== "--None--" ? meData.timezone : undefined, }} > {children} diff --git a/apps/customer-portal/microapp/src/utils/useDateTime.ts b/apps/customer-portal/microapp/src/utils/useDateTime.ts index 859c5ae573..cae6b031c4 100644 --- a/apps/customer-portal/microapp/src/utils/useDateTime.ts +++ b/apps/customer-portal/microapp/src/utils/useDateTime.ts @@ -8,9 +8,25 @@ dayjs.extend(utc); dayjs.extend(timezone); dayjs.extend(relativeTime); +/** + * Returns the given timezone if it is a valid IANA identifier, otherwise + * falls back to the device timezone. Guards against placeholder values + * (e.g. ServiceNow's "--None--") that would make Intl/dayjs throw. + */ +const resolveTimezone = (timezone?: string): string => { + const fallback = Intl.DateTimeFormat().resolvedOptions().timeZone; + if (!timezone) return fallback; + try { + Intl.DateTimeFormat(undefined, { timeZone: timezone }); + return timezone; + } catch { + return fallback; + } +}; + export function useDateTime() { const { timezone } = useMe(); - const tz = timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone; + const tz = resolveTimezone(timezone); const toUtc = (date: Date | string) => { if (date instanceof Date) { From df3feb8ec3938a50ad5b289d32508559cd3f1ea1 Mon Sep 17 00:00:00 2001 From: Dinithi Nanayakkara <166215353+2003dinijay@users.noreply.github.com> Date: Thu, 2 Jul 2026 17:12:33 +0530 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- apps/customer-portal/microapp/src/utils/useDateTime.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/customer-portal/microapp/src/utils/useDateTime.ts b/apps/customer-portal/microapp/src/utils/useDateTime.ts index cae6b031c4..2ffa95db1a 100644 --- a/apps/customer-portal/microapp/src/utils/useDateTime.ts +++ b/apps/customer-portal/microapp/src/utils/useDateTime.ts @@ -13,12 +13,12 @@ dayjs.extend(relativeTime); * falls back to the device timezone. Guards against placeholder values * (e.g. ServiceNow's "--None--") that would make Intl/dayjs throw. */ -const resolveTimezone = (timezone?: string): string => { +const resolveTimezone = (tz?: string): string => { const fallback = Intl.DateTimeFormat().resolvedOptions().timeZone; - if (!timezone) return fallback; + if (!tz) return fallback; try { - Intl.DateTimeFormat(undefined, { timeZone: timezone }); - return timezone; + Intl.DateTimeFormat(undefined, { timeZone: tz }); + return tz; } catch { return fallback; }