Skip to content

[Bug] - Greeting message uses incorrect timezone (Issue #8580)#8735

Open
Ivanq50 wants to merge 2 commits intomakeplane:previewfrom
WSU-CptS-481-Spring-2026:fix-8580-greeting-message
Open

[Bug] - Greeting message uses incorrect timezone (Issue #8580)#8735
Ivanq50 wants to merge 2 commits intomakeplane:previewfrom
WSU-CptS-481-Spring-2026:fix-8580-greeting-message

Conversation

@Ivanq50
Copy link

@Ivanq50 Ivanq50 commented Mar 9, 2026

Description

Added logic to select the correct timezone for the user instead of defaulting to UTC. Reads the profile timezone and treats values like UTC, etc/UTC, any variance of UTC, or missing/empty values as "unset/default". If it is unset/default, it falls back to browser/OS timezone, otherwise, it uses the profile timezone.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

Screenshots and Media (if applicable)

Correct time: 2:33PM PST
greeting-message-before
Correct time: 2:22PM PST (24 hour)
greeting-message-after

Test Scenarios

References

https://github.com/makeplane/plane/issues/8580

yevin215 and others added 2 commits March 5, 2026 22:57
… of user's local timezone. We now use the timezone on the OS/Browser when it is defaulted to UTC.
Copilot AI review requested due to automatic review settings March 9, 2026 03:39
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 9, 2026

📝 Walkthrough

Walkthrough

The changes introduce a new normalizeBasePath helper function across multiple Vite and React Router configuration files to standardize base path handling. Additionally, timezone logic is improved in a user-greetings component to validate and conditionally apply timezone information based on user profile data.

Changes

Cohort / File(s) Summary
Base path normalization
apps/admin/react-router.config.ts, apps/admin/vite.config.ts, apps/space/react-router.config.ts, apps/space/vite.config.ts
Replaced joinUrlPath with new normalizeBasePath helper that trims input, normalizes empty/"/" to "/", and ensures single leading/trailing slashes. Updated basename configuration in React Router configs and base option in Vite configs. Removed unused joinUrlPath imports.
Timezone validation
apps/web/core/components/home/user-greetings.tsx
Enhanced timezone handling to validate user_timezone (treating empty, "UTC", "Etc/UTC", and case-insensitive variants as unset). Conditionally applies valid timezone to Intl.DateTimeFormat calls via spread operator, with fallback to browser timezone when no valid profile zone exists.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Paths now normalized, clean and bright,
Timezones validated, getting it right,
Helper functions hop through the code,
With leading slashes on the road,
Our configs dance in harmony's light!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main bug fix (incorrect timezone in greeting message) and references the issue number, accurately summarizing the primary change.
Description check ✅ Passed The pull request description is mostly complete with a detailed explanation of changes, type of change clearly marked, and supporting evidence.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes incorrect “Good morning/afternoon/evening” greetings by computing the current hour/date using an appropriate timezone (preferring a real user profile timezone and otherwise falling back to the browser/OS timezone). Also adjusts how Space/Admin base paths are derived from env vars.

Changes:

  • Update UserGreetingsView to derive a timeZone and apply it consistently to hour/date/weekday/time formatting.
  • Replace joinUrlPath usage in Space/Admin Vite + React Router configs with a local normalizeBasePath helper for consistent leading/trailing slashes.
  • Remove now-unused joinUrlPath imports from the affected config files.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
apps/web/core/components/home/user-greetings.tsx Applies a derived timezone to greeting/date/time formatting to avoid UTC-default greetings.
apps/space/vite.config.ts Normalizes VITE_SPACE_BASE_PATH via a local helper before passing to Vite base.
apps/space/react-router.config.ts Normalizes VITE_SPACE_BASE_PATH before passing to React Router basename.
apps/admin/vite.config.ts Normalizes VITE_ADMIN_BASE_PATH via a local helper before passing to Vite base.
apps/admin/react-router.config.ts Normalizes VITE_ADMIN_BASE_PATH before passing to React Router basename.

Comment on lines +3 to +7
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
};
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normalizeBasePath is duplicated in both the router config and Vite config for this app. Consider importing it from a shared helper to ensure base and basename stay consistent if the normalization logic changes.

Copilot uses AI. Check for mistakes.
Comment on lines +7 to +11
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
};
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normalizeBasePath is duplicated here and in apps/admin/react-router.config.ts (and also duplicated in the space app). Consider extracting this into a shared helper to avoid future drift in base path normalization.

Copilot uses AI. Check for mistakes.
Comment on lines +3 to +7
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
};
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The base path normalization logic is duplicated between this file and apps/admin/vite.config.ts (and similarly in apps/space). Consider moving normalizeBasePath to a shared helper module and importing it so config files remain consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +33
// Use profile timezone when set to a real zone; treat UTC/Etc/UTC as unset (common
// backend default) so we show local time. Otherwise use browser/OS timezone.
const profileZone = user?.user_timezone?.trim();
const isUtcDefault =
!profileZone || profileZone === "UTC" || profileZone === "Etc/UTC" || profileZone.toLowerCase() === "utc";
const timeZone = isUtcDefault
? typeof Intl !== "undefined" && Intl.DateTimeFormat
? Intl.DateTimeFormat().resolvedOptions().timeZone
: undefined
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isUtcDefault currently has redundant checks (profileZone === "UTC" and profileZone.toLowerCase() === "utc" overlap). Consider normalizing once (e.g., const normalized = profileZone?.trim().toUpperCase()) and comparing against a small set to keep the intent clear and avoid repeated string ops.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +7 to +11
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
};
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normalizeBasePath is now duplicated here and in the corresponding react-router.config.ts (and similarly in apps/admin). Consider extracting this helper into a small shared module (e.g., apps/space/config/base-path.ts or a utilities package) so the normalization rules don’t diverge over time.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/admin/react-router.config.ts`:
- Around line 3-6: normalizeBasePath currently preserves accidental internal
'//' from VITE_ADMIN_BASE_PATH which can change router basename; update
normalizeBasePath to canonicalize repeated slashes by collapsing any consecutive
slashes into a single slash (e.g., apply a global replace like replace(/\/+/g,
"/")) after trimming, then ensure the result has a single leading and single
trailing slash (still returning "/" for empty/root). Modify the
normalizeBasePath function so it both trims and normalizes internal duplicate
slashes before returning the final basename.

In `@apps/admin/vite.config.ts`:
- Around line 7-10: normalizeBasePath currently preserves internal duplicate
slashes (e.g., "admin//preview") causing wrong Vite base; update
normalizeBasePath to collapse consecutive "/" into a single "/" before
stripping/adding edges so internal "//" becomes "/". Specifically, in
normalizeBasePath (and where VITE_ADMIN_BASE_PATH is used) perform a global
collapse of repeated separators (e.g., via a replace of /\/+/g with "/"), then
remove leading/trailing slashes and wrap with a single leading and trailing "/"
as the final return value.

In `@apps/space/react-router.config.ts`:
- Around line 3-6: normalizeBasePath currently only trims ends and preserves
internal duplicate slashes; update normalizeBasePath to collapse repeated
slashes inside the path before trimming and assembling the final basename (e.g.,
run a global collapse like replacing /{2,} with / on the value or trimmed
value), then strip leading/trailing slashes and return "/" for empty root;
locate the function normalizeBasePath to apply this change so inputs like
"space//beta" become "/space/beta/" consistently.

In `@apps/space/vite.config.ts`:
- Around line 7-10: The normalizeBasePath function currently preserves internal
double slashes (e.g., "space//beta") which causes Vite base to emit
"/space//beta/"; update normalizeBasePath to collapse consecutive slashes into a
single slash after trimming so the output aligns with the router basename: in
the normalizeBasePath function (and any related callers) replace sequences of
multiple "/" within the path (e.g., via a regex that squeezes /{2,} to "/")
before adding the leading/trailing "/" so inputs like "space//beta" become
"/space/beta/".

In `@apps/web/core/components/home/user-greetings.tsx`:
- Around line 27-34: Normalize the profileZone before comparing so "Etc/UTC" is
matched case-insensitively: compute a trimmed, lowercased variant of
user?.user_timezone (e.g., profileZoneNormalized =
user?.user_timezone?.trim().toLowerCase()) and update isUtcDefault to check
against normalized values ("utc" and "etc/utc") instead of the current
case-sensitive checks; keep the rest of the timeZone logic the same and
reference the existing identifiers profileZone, isUtcDefault, and timeZone when
making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c90e344d-6dc7-4571-9870-17f605759614

📥 Commits

Reviewing files that changed from the base of the PR and between 6627282 and 73cd980.

📒 Files selected for processing (5)
  • apps/admin/react-router.config.ts
  • apps/admin/vite.config.ts
  • apps/space/react-router.config.ts
  • apps/space/vite.config.ts
  • apps/web/core/components/home/user-greetings.tsx

Comment on lines +3 to +6
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Keep basename canonical here as well.

normalizeBasePath now preserves accidental internal //, so the admin router basename changes for env values that the old path joiner would have normalized. That leaves routing behavior dependent on slash typos in VITE_ADMIN_BASE_PATH.

Possible fix
 const normalizeBasePath = (value: string): string => {
   const trimmed = value.trim();
   if (!trimmed || trimmed === "/") return "/";
-  return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
+  return `/${trimmed.replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "")}/`;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "")}/`;
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/admin/react-router.config.ts` around lines 3 - 6, normalizeBasePath
currently preserves accidental internal '//' from VITE_ADMIN_BASE_PATH which can
change router basename; update normalizeBasePath to canonicalize repeated
slashes by collapsing any consecutive slashes into a single slash (e.g., apply a
global replace like replace(/\/+/g, "/")) after trimming, then ensure the result
has a single leading and single trailing slash (still returning "/" for
empty/root). Modify the normalizeBasePath function so it both trims and
normalizes internal duplicate slashes before returning the final basename.

Comment on lines +7 to +10
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Normalize duplicate separators before setting Vite base.

This version preserves internal //, so VITE_ADMIN_BASE_PATH="admin//preview" now produces /admin//preview/. That regresses the old joinUrlPath behavior and can send the admin bundle to the wrong asset prefix.

Possible fix
 const normalizeBasePath = (value: string): string => {
   const trimmed = value.trim();
   if (!trimmed || trimmed === "/") return "/";
-  return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
+  return `/${trimmed.replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "")}/`;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "")}/`;
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/admin/vite.config.ts` around lines 7 - 10, normalizeBasePath currently
preserves internal duplicate slashes (e.g., "admin//preview") causing wrong Vite
base; update normalizeBasePath to collapse consecutive "/" into a single "/"
before stripping/adding edges so internal "//" becomes "/". Specifically, in
normalizeBasePath (and where VITE_ADMIN_BASE_PATH is used) perform a global
collapse of repeated separators (e.g., via a replace of /\/+/g with "/"), then
remove leading/trailing slashes and wrap with a single leading and trailing "/"
as the final return value.

Comment on lines +3 to +6
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Collapse repeated slashes before assigning basename.

normalizeBasePath only trims the ends, so VITE_SPACE_BASE_PATH="space//beta" now becomes /space//beta/. The previous joinUrlPath flow normalized duplicate separators, and React Router will mount under a different basename for the same env value.

Possible fix
 const normalizeBasePath = (value: string): string => {
   const trimmed = value.trim();
   if (!trimmed || trimmed === "/") return "/";
-  return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
+  return `/${trimmed.replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "")}/`;
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/space/react-router.config.ts` around lines 3 - 6, normalizeBasePath
currently only trims ends and preserves internal duplicate slashes; update
normalizeBasePath to collapse repeated slashes inside the path before trimming
and assembling the final basename (e.g., run a global collapse like replacing
/{2,} with / on the value or trimmed value), then strip leading/trailing slashes
and return "/" for empty root; locate the function normalizeBasePath to apply
this change so inputs like "space//beta" become "/space/beta/" consistently.

Comment on lines +7 to +10
const normalizeBasePath = (value: string): string => {
const trimmed = value.trim();
if (!trimmed || trimmed === "/") return "/";
return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Preserve the old path normalization for Vite base.

This helper now leaves internal // intact. A value like VITE_SPACE_BASE_PATH="space//beta" will emit assets under /space//beta/, which is a behavior change from the old joinUrlPath flow. Please normalize repeated separators here so base stays aligned with the router basename.

Possible fix
 const normalizeBasePath = (value: string): string => {
   const trimmed = value.trim();
   if (!trimmed || trimmed === "/") return "/";
-  return `/${trimmed.replace(/^\/+|\/+$/g, "")}/`;
+  return `/${trimmed.replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "")}/`;
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/space/vite.config.ts` around lines 7 - 10, The normalizeBasePath
function currently preserves internal double slashes (e.g., "space//beta") which
causes Vite base to emit "/space//beta/"; update normalizeBasePath to collapse
consecutive slashes into a single slash after trimming so the output aligns with
the router basename: in the normalizeBasePath function (and any related callers)
replace sequences of multiple "/" within the path (e.g., via a regex that
squeezes /{2,} to "/") before adding the leading/trailing "/" so inputs like
"space//beta" become "/space/beta/".

Comment on lines +27 to +34
const profileZone = user?.user_timezone?.trim();
const isUtcDefault =
!profileZone || profileZone === "UTC" || profileZone === "Etc/UTC" || profileZone.toLowerCase() === "utc";
const timeZone = isUtcDefault
? typeof Intl !== "undefined" && Intl.DateTimeFormat
? Intl.DateTimeFormat().resolvedOptions().timeZone
: undefined
: profileZone;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Etc/UTC is still case-sensitive here.

The fallback only matches the exact "Etc/UTC" spelling. Values like "etc/utc" or "ETC/UTC" — which the PR description calls out as defaults too — will still be treated as real profile zones, so those users keep seeing UTC instead of their local time.

Possible fix
   const profileZone = user?.user_timezone?.trim();
-  const isUtcDefault =
-    !profileZone || profileZone === "UTC" || profileZone === "Etc/UTC" || profileZone.toLowerCase() === "utc";
+  const isUtcDefault = !profileZone || /^(?:etc\/)?utc$/i.test(profileZone);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/core/components/home/user-greetings.tsx` around lines 27 - 34,
Normalize the profileZone before comparing so "Etc/UTC" is matched
case-insensitively: compute a trimmed, lowercased variant of user?.user_timezone
(e.g., profileZoneNormalized = user?.user_timezone?.trim().toLowerCase()) and
update isUtcDefault to check against normalized values ("utc" and "etc/utc")
instead of the current case-sensitive checks; keep the rest of the timeZone
logic the same and reference the existing identifiers profileZone, isUtcDefault,
and timeZone when making the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants