Skip to content

context-aware greeting system, update deps#7

Merged
alvinsjoy merged 5 commits intomainfrom
dev
Apr 21, 2026
Merged

context-aware greeting system, update deps#7
alvinsjoy merged 5 commits intomainfrom
dev

Conversation

@alvinsjoy
Copy link
Copy Markdown
Member

No description provided.

@alvinsjoy alvinsjoy requested a review from Copilot April 21, 2026 05:34
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

Warning

Rate limit exceeded

@alvinsjoy has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 44 minutes and 9 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 44 minutes and 9 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 454ccc5e-38b0-4a92-9036-d8a644c9aa4b

📥 Commits

Reviewing files that changed from the base of the PR and between 29d828d and a89c106.

📒 Files selected for processing (2)
  • components/greeting.tsx
  • lib/greetings.ts
📝 Walkthrough

Walkthrough

Adds a client-side Greeting component and integrates it into the chat empty state, updates timestamp rendering to suppress hydration warnings, changes date-format exports/timezone handling, makes the sidebar brand a Next.js Link, and bumps several package versions.

Changes

Cohort / File(s) Summary
Greeting component & usage
components/greeting.tsx, components/chat-area.tsx
Adds a client-side Greeting component (GreetingProps) and replaces the chat empty-state static title with <Greeting userName={userName} />; includes hydration placeholder handling.
Timestamp hydration & UI tweaks
components/chat-area.tsx, components/chat-sidebar.tsx
Adds suppressHydrationWarning to spans rendering formatted dates/times; adjusts empty-state paragraph styling; wraps sidebar brand in next/link pointing to /.
Greeting logic
lib/greetings.ts
New exported getGreeting(fullName: string) implementing time- and weekday-aware template selection, first-name parsing, and randomized template choice.
Date formatting changes
lib/date-format.ts
Exports APP_DATE_LOCALE, removes APP_TIME_ZONE; most formatters no longer pass an explicit timeZone (day-key uses UTC for determinism).
Dependencies
package.json
Bumps versions for better-auth, next, react, react-dom, and related @types/* entries.

Sequence Diagram(s)

sequenceDiagram
  participant User as User (Browser)
  participant ChatArea as ChatArea
  participant Greeting as Greeting Component
  participant GreetingsLib as lib/greetings
  participant DateFmt as lib/date-format

  User->>ChatArea: open chat / empty state
  ChatArea->>Greeting: render(userName)
  Greeting->>GreetingsLib: getGreeting(userName)
  GreetingsLib->>DateFmt: read APP_DATE_LOCALE / compute hour & weekday
  DateFmt-->>GreetingsLib: locale/format parts
  GreetingsLib-->>Greeting: greeting string
  Greeting-->>ChatArea: heading content
  ChatArea-->>User: display greeting
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hop through hours and days to say,
Your name, a smile, a gentle ray.
A greeting sprung from time and cheer,
I whisper "hello" — glad you're here!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author, making it impossible to assess whether the description relates to the changeset. Add a pull request description that explains the purpose and context of the changes, including the greeting system implementation and dependency updates.
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the two main changes: introducing a context-aware greeting system and updating dependencies. It accurately reflects the primary objectives of the PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

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
Copy Markdown
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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/chat-sidebar.tsx (1)

158-169: ⚠️ Potential issue | 🟡 Minor

Brand link inside the chat app points to / — confirm this is intentional.

The sidebar is rendered inside /chat/*, so clicking the brand will pull the authenticated user out to the marketing root. If the intent is a “home of the app,” consider pointing to /chat (the chat index) instead, or keeping this but ensuring / gracefully redirects authenticated users.

Also, since this Link is a descendant of a SidebarMenuButton/trigger context, verify no nested interactive-element warnings arise from Radix in dev mode.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/chat-sidebar.tsx` around lines 158 - 169, The brand Link currently
uses href="/" which will navigate users out of the chat area; change the Link's
href to "/chat" (modify the Link element around Image and the "Pointer RAG"
span) if the intended in-app home is the chat index, or alternatively ensure
server/client routing redirects authenticated users from "/" to "/chat". Also
inspect the parent SidebarMenuButton/trigger context for nested interactive
elements and, if Radix warns in dev, either make the Link a non-interactive
wrapper (e.g., replace with a plain div) or use Radix's asChild pattern so the
Link does not create a nested interactive element.
🧹 Nitpick comments (2)
components/greeting.tsx (1)

10-23: Minor: greeting won't refresh across a long-lived session / midnight crossing.

getGreeting is only recomputed when userName changes. If a user keeps the empty-chat view open across a time-of-day boundary (e.g. past midnight, or 17:00 evening tick-over) the greeting becomes stale. Not a blocker for this empty state, but worth considering a cheap interval or a recompute on visibilitychange.

Also, the placeholder string "Welcome" on Line 19 can be replaced with &nbsp; or aria-hidden to avoid screen readers announcing "Welcome" then the real greeting on hydration.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/greeting.tsx` around lines 10 - 23, The Greeting component
currently only recomputes getGreeting when userName changes, so the greeting can
become stale across time boundaries; update the useEffect in Greeting to also
recompute periodically (e.g., setInterval every minute) and on document
visibilitychange (recompute when visibility becomes visible) and clear
listeners/interval on cleanup to avoid leaks; also replace the visible
placeholder string "Welcome" with a non-voicing placeholder (e.g., use a
non-breaking space or add aria-hidden on the placeholder h2) so screen readers
don’t announce the placeholder before hydration.
lib/greetings.ts (1)

48-57: Duplicate "Welcome to the weekend" template across Saturday and Sunday.

Minor DRY nit: the same template is declared for both day:Saturday and day:Sunday. Consider introducing a day:Weekend condition (or weekend akin to daytime) to avoid copy-paste drift.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/greetings.ts` around lines 48 - 57, The greetings array contains
duplicate entries using the same template "Welcome to the weekend, {first_name}"
for both condition "day:Saturday" and "day:Sunday"; replace those two entries
with a single entry using a unified condition (e.g., "day:Weekend" or "weekend")
and update any logic that evaluates conditions to recognize the new "Weekend"
value; specifically, remove the two objects that reference "Welcome to the
weekend, {first_name}" with "day:Saturday" and "day:Sunday" and add one object
with that template and the unified condition, and ensure condition-evaluation
code (wherever day conditions are parsed/checked) accepts the new
"Weekend"/"weekend" token.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/greetings.ts`:
- Line 34: The greeting template object in lib/greetings.ts with template "It's
late-night {first_name}" is awkward; update the template string in that object
(the entry with template and condition "night") to include appropriate
punctuation or rewording (e.g., "It's late-night, {first_name}" or "Burning the
midnight oil, {first_name}?") so it matches the tone/format of the other
templates; locate the object by its template key and the condition "night" and
replace the template value accordingly.
- Around line 83-91: The hour parsing can yield 24 at midnight causing incorrect
bucket selection; update the logic around hourFormatter/hourPart/hour to
normalize 24 to 0 (or set hourCycle: "h23" on the Intl.DateTimeFormat options)
and ensure hour is an integer in 0..23 before any comparison (i.e., when
computing hour from hourPart.value, if parsed value === 24 set to 0); apply this
change where hourFormatter, hourPart and hour are defined so downstream checks
like hour >= 21 || hour < 5 behave correctly.

In `@package.json`:
- Around line 45-59: package.json currently pins `@better-auth/cli` to ^1.4.21
while runtime uses better-auth ^1.6.5, which can cause schema/CLI/runtime drift;
update the `@better-auth/cli` dependency to ^1.6.x (match the runtime major/minor)
in package.json so the CLI and runtime versions align, then run your package
manager to reinstall and verify lib/auth.ts integrations (createAuthMiddleware,
prismaAdapter, nextCookies, APIError) still work with the updated CLI.

---

Outside diff comments:
In `@components/chat-sidebar.tsx`:
- Around line 158-169: The brand Link currently uses href="/" which will
navigate users out of the chat area; change the Link's href to "/chat" (modify
the Link element around Image and the "Pointer RAG" span) if the intended in-app
home is the chat index, or alternatively ensure server/client routing redirects
authenticated users from "/" to "/chat". Also inspect the parent
SidebarMenuButton/trigger context for nested interactive elements and, if Radix
warns in dev, either make the Link a non-interactive wrapper (e.g., replace with
a plain div) or use Radix's asChild pattern so the Link does not create a nested
interactive element.

---

Nitpick comments:
In `@components/greeting.tsx`:
- Around line 10-23: The Greeting component currently only recomputes
getGreeting when userName changes, so the greeting can become stale across time
boundaries; update the useEffect in Greeting to also recompute periodically
(e.g., setInterval every minute) and on document visibilitychange (recompute
when visibility becomes visible) and clear listeners/interval on cleanup to
avoid leaks; also replace the visible placeholder string "Welcome" with a
non-voicing placeholder (e.g., use a non-breaking space or add aria-hidden on
the placeholder h2) so screen readers don’t announce the placeholder before
hydration.

In `@lib/greetings.ts`:
- Around line 48-57: The greetings array contains duplicate entries using the
same template "Welcome to the weekend, {first_name}" for both condition
"day:Saturday" and "day:Sunday"; replace those two entries with a single entry
using a unified condition (e.g., "day:Weekend" or "weekend") and update any
logic that evaluates conditions to recognize the new "Weekend" value;
specifically, remove the two objects that reference "Welcome to the weekend,
{first_name}" with "day:Saturday" and "day:Sunday" and add one object with that
template and the unified condition, and ensure condition-evaluation code
(wherever day conditions are parsed/checked) accepts the new "Weekend"/"weekend"
token.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: c115c7c2-58ee-4011-b430-e766e852d889

📥 Commits

Reviewing files that changed from the base of the PR and between de19734 and c894291.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • components/chat-area.tsx
  • components/chat-sidebar.tsx
  • components/greeting.tsx
  • lib/date-format.ts
  • lib/greetings.ts
  • package.json

Comment thread lib/greetings.ts Outdated
Comment thread lib/greetings.ts Outdated
Comment thread package.json
Comment on lines +45 to +59
"better-auth": "^1.6.5",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "1.0.4",
"date-fns": "4.1.0",
"embla-carousel-react": "8.5.1",
"input-otp": "1.4.1",
"lucide-react": "^0.454.0",
"next": "16.0.10",
"next": "^16.2.4",
"next-themes": "^0.4.6",
"pg": "^8.17.1",
"radix-ui": "^1.4.3",
"react": "19.2.0",
"react": "^19.2.5",
"react-day-picker": "9.8.0",
"react-dom": "19.2.0",
"react-dom": "^19.2.5",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
for pkg in better-auth next react react-dom `@better-auth/cli`; do
  echo "=== $pkg ==="
  curl -s "https://registry.npmjs.org/${pkg}" | jq -r '.["dist-tags"], (.versions | keys | .[-5:])'
done
gh api graphql -f query='
{
  a: securityVulnerabilities(first: 5, ecosystem: NPM, package: "better-auth") { nodes { advisory { summary severity } vulnerableVersionRange firstPatchedVersion { identifier } } }
  b: securityVulnerabilities(first: 5, ecosystem: NPM, package: "next")        { nodes { advisory { summary severity } vulnerableVersionRange firstPatchedVersion { identifier } } }
  c: securityVulnerabilities(first: 5, ecosystem: NPM, package: "react")       { nodes { advisory { summary severity } vulnerableVersionRange firstPatchedVersion { identifier } } }
}'

Repository: PointerRAG/Project

Length of output: 4640


🏁 Script executed:

fd -type f -name "auth.ts" -o -name "auth-client.ts" | head -20

Repository: PointerRAG/Project

Length of output: 232


🏁 Script executed:

# Check if better-auth changelog or release notes are available, or search for API usage patterns
rg "(createAuthMiddleware|prismaAdapter|nextCookies|APIError)" -t ts -t js --max-count=20

Repository: PointerRAG/Project

Length of output: 541


🌐 Web query:

better-auth 1.6.5 release notes changelog breaking changes 1.4 to 1.6

💡 Result:

v1.6.5 Release Notes (Apr 16, 2026): Bug fixes - Clarified test utils plugin production usage (#9119). Fixed session refresh after /change-password and /revoke-other-sessions (#9087). @better-auth/oauth-provider security fix for GHSA-xr8f-h2gw-9xh6 authorization bypass (first patched in 1.6.5). From 1.4 to 1.6 Breaking Changes (key ones in 1.6.0, Apr 6, 2026): - session.freshAge now uses createdAt instead of updatedAt (#8762). Migration: Set session: { freshAge: 0 } to disable. - Deprecated oidc-provider plugin in favor of @better-auth/oauth-provider (#8985). - @better-auth/sso: SAML InResponseTo validation enabled by default (#8736). Migration: sso({ saml: { enableInResponseToValidation: false } }). - @better-auth/mongo-adapter: UUIDs stored as native BSON UUID (#8681). - @better-auth/oauth-provider: secondaryStorage requires storeSessionInDatabase: true (#8894). - @better-auth/scim: Management endpoints require authorization, e.g. scim({ requiredRole: ["admin", "owner"] }). 1.4 Breaking Changes (Nov 2025): Change-email uses emailVerification.sendVerificationEmail. forgotPassword -> requestPasswordReset. /account-info POST -> GET. Plugin callbacks: request -> ctx. Passkey to separate package. API key mock-sessions disabled by default. Removed advanced.generateId. Full details in GitHub releases (v1.6.0 to v1.6.5 mostly bug fixes/features post-1.4) and official changelog. No single upgrade guide found; check each release.

Citations:


Align @better-auth/cli with runtime version to avoid schema drift.

All specified versions are published and free of open advisories. The APIs used in lib/auth.ts (createAuthMiddleware, prismaAdapter, nextCookies, APIError) do not appear in better-auth's 1.4→1.6 breaking change list, indicating compatibility.

However, @better-auth/cli is pinned to ^1.4.21 while the runtime is at ^1.6.5. Upgrade the CLI to ^1.6.x to prevent potential schema drift and CLI/runtime version misalignment.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 45 - 59, package.json currently pins
`@better-auth/cli` to ^1.4.21 while runtime uses better-auth ^1.6.5, which can
cause schema/CLI/runtime drift; update the `@better-auth/cli` dependency to ^1.6.x
(match the runtime major/minor) in package.json so the CLI and runtime versions
align, then run your package manager to reinstall and verify lib/auth.ts
integrations (createAuthMiddleware, prismaAdapter, nextCookies, APIError) still
work with the updated CLI.

Copy link
Copy Markdown
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

Introduces a context-aware greeting shown in the chat empty state and updates several frontend/auth dependencies.

Changes:

  • Added a new greeting generator (lib/greetings.ts) that selects a greeting based on local time/day in the app timezone.
  • Added a client Greeting component and wired it into the chat empty state UI.
  • Bumped better-auth, next, react, and related type packages (plus lockfile updates).

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
package.json Updates core framework/auth dependency versions and version ranges.
package-lock.json Regenerates lockfile to reflect updated dependency graph.
lib/greetings.ts New context-aware greeting selection utility.
lib/date-format.ts Exports app locale/timezone constants for reuse.
components/greeting.tsx New client component to render a greeting post-hydration.
components/chat-sidebar.tsx Makes the sidebar brand/header clickable via next/link.
components/chat-area.tsx Uses the new Greeting component in the empty-state UI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/greetings.ts Outdated
* Extracts the first name from the full name for a friendlier tone.
*/
export function getGreeting(fullName: string): string {
const firstName = fullName.split(/\s+/)[0] || "there";
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

getGreeting derives firstName from fullName.split(/\s+/)[0], which returns an empty string when fullName has leading whitespace (e.g., " John Doe"), causing the fallback "there" to be used even though a real name exists. Trim (and/or filter out empty parts) before taking the first token so leading/trailing whitespace doesn’t break personalization.

Suggested change
const firstName = fullName.split(/\s+/)[0] || "there";
const firstName = fullName.trim().split(/\s+/)[0] || "there";

Copilot uses AI. Check for mistakes.
Comment thread lib/greetings.ts Outdated
const hourPart = hourFormatter
.formatToParts(now)
.find((p) => p.type === "hour");
const hour = hourPart ? parseInt(hourPart.value, 10) : new Date().getHours();
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The fallback new Date().getHours() uses the server/client local timezone (and a different Date instance) rather than APP_TIME_ZONE, so if hourPart is ever missing the greeting can become incorrect for the app’s configured timezone. Prefer deriving the fallback hour from the same now value in APP_TIME_ZONE (or pick a deterministic default) to keep behavior consistent.

Suggested change
const hour = hourPart ? parseInt(hourPart.value, 10) : new Date().getHours();
const hour = hourPart ? parseInt(hourPart.value, 10) : 12;

Copilot uses AI. Check for mistakes.
Comment thread package.json
Comment on lines +53 to +59
"next": "^16.2.4",
"next-themes": "^0.4.6",
"pg": "^8.17.1",
"radix-ui": "^1.4.3",
"react": "19.2.0",
"react": "^19.2.5",
"react-day-picker": "9.8.0",
"react-dom": "19.2.0",
"react-dom": "^19.2.5",
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

Changing next, react, and react-dom from pinned versions to caret ranges means fresh installs (or lockfile regenerations) can silently pick up newer minor/patch releases, which can introduce framework-level behavior changes without a code review. Consider pinning these core runtime versions (or documenting why ranges are preferred) to keep deploys reproducible.

Copilot uses AI. Check for mistakes.
@alvinsjoy
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
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

Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/greetings.ts Outdated
const eligible = GREETINGS.filter((g) => {
switch (g.condition) {
case "always":
return true;
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

In eligible, the "always" condition returns true, so generic greetings are always included in the selection pool and can crowd out the time/day-specific greetings; it also makes the later eligible.length > 0 ? eligible : ... fallback effectively redundant. If the intent is for always to be a fallback only, exclude always from eligible and only use it when no other conditions match (or explicitly prioritize non-always greetings).

Suggested change
return true;
return false;

Copilot uses AI. Check for mistakes.
Comment thread lib/greetings.ts Outdated
Comment on lines +88 to +94
const hourPart = hourFormatter
.formatToParts(now)
.find((p) => p.type === "hour");
const parsedHour = hourPart ? parseInt(hourPart.value, 10) : NaN;
const hour = Number.isFinite(parsedHour)
? parsedHour % 24
: new Date().getHours();
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The fallback new Date().getHours() uses the server/client local timezone rather than APP_TIME_ZONE, which can produce the wrong greeting if formatToParts() ever fails. Consider deriving the fallback hour using the same Intl.DateTimeFormat/APP_TIME_ZONE logic (or reuse hourFormatter.formatToParts(now) with a safer parse) so the timezone is consistent.

Suggested change
const hourPart = hourFormatter
.formatToParts(now)
.find((p) => p.type === "hour");
const parsedHour = hourPart ? parseInt(hourPart.value, 10) : NaN;
const hour = Number.isFinite(parsedHour)
? parsedHour % 24
: new Date().getHours();
const fallbackHourFormatter = new Intl.DateTimeFormat("en-US", {
hour: "numeric",
hourCycle: "h23",
timeZone: APP_TIME_ZONE,
});
const hourPart = hourFormatter
.formatToParts(now)
.find((p) => p.type === "hour");
const parsedHour = hourPart
? parseInt(hourPart.value, 10)
: parseInt(fallbackHourFormatter.format(now), 10);
const hour = Number.isFinite(parsedHour) ? parsedHour % 24 : 0;

Copilot uses AI. Check for mistakes.
Comment thread lib/greetings.ts Outdated

/**
* Returns a context-aware greeting based on the current time and day of week,
* using the app's configured timezone (Asia/Kolkata).
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The doc comment hard-codes the timezone name ("Asia/Kolkata") even though the implementation uses APP_TIME_ZONE. To avoid the comment becoming stale if the app timezone changes, consider rephrasing it to reference the configured app timezone rather than a specific value.

Suggested change
* using the app's configured timezone (Asia/Kolkata).
* using the app's configured timezone.

Copilot uses AI. Check for mistakes.
Comment thread components/greeting.tsx Outdated

// Render transparent placeholder on server / before hydration to avoid layout shift
if (greeting === null) {
return <h2 className="mb-2 text-3xl font-semibold invisible">Welcome</h2>;
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The invisible placeholder heading still contains readable text ("Welcome"). Depending on assistive tech, hidden text can sometimes be announced or included in virtual buffers. Consider marking the placeholder aria-hidden="true" (and/or using an empty non-breaking space) so screen readers don’t encounter a transient heading that is immediately replaced after hydration.

Suggested change
return <h2 className="mb-2 text-3xl font-semibold invisible">Welcome</h2>;
return (
<h2
className="mb-2 text-3xl font-semibold invisible"
aria-hidden="true"
>
&nbsp;
</h2>
);

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
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.

🧹 Nitpick comments (1)
lib/greetings.ts (1)

129-132: Fallback branch is unreachable.

Since every "always" template unconditionally passes the filter at Line 109-110, eligible always contains at least all "always" entries, so eligible.length > 0 is always true and the else branch is dead code. You can safely simplify to const pool = eligible;, or drop the ternary entirely.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/greetings.ts` around lines 129 - 132, The fallback ternary that sets
const pool to eligible ? eligible : GREETINGS.filter(...) is dead because
eligible already includes all "always" templates (the earlier filter guarantees
those are present), so simplify by removing the unreachable branch and set pool
directly to eligible (i.e., replace the ternary with const pool = eligible) to
eliminate the dead code; reference symbols: pool, eligible, GREETINGS.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@lib/greetings.ts`:
- Around line 129-132: The fallback ternary that sets const pool to eligible ?
eligible : GREETINGS.filter(...) is dead because eligible already includes all
"always" templates (the earlier filter guarantees those are present), so
simplify by removing the unreachable branch and set pool directly to eligible
(i.e., replace the ternary with const pool = eligible) to eliminate the dead
code; reference symbols: pool, eligible, GREETINGS.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: f784d79c-3d71-4cfb-8d18-15c893a18bf3

📥 Commits

Reviewing files that changed from the base of the PR and between c894291 and 8759986.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (1)
  • lib/greetings.ts

Copy link
Copy Markdown
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: 2

🧹 Nitpick comments (1)
lib/greetings.ts (1)

135-136: Optional: guard against empty pool.

pool[Math.floor(Math.random() * pool.length)] will return undefined if pool is ever empty, and line 136 would then throw on .template. Today alwaysGreetings is non-empty because the GREETINGS array includes unconditional entries, so this is safe. A small defensive assertion or fallback guards against future edits to GREETINGS that could accidentally remove all "always" templates.

Proposed defensive change
-  const selected = pool[Math.floor(Math.random() * pool.length)];
-  return selected.template.replaceAll("{first_name}", firstName);
+  const selected =
+    pool[Math.floor(Math.random() * pool.length)] ??
+    { template: "Hi {first_name}", condition: "always" as const };
+  return selected.template.replaceAll("{first_name}", firstName);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/greetings.ts` around lines 135 - 136, Guard against an empty pool before
selecting — if pool.length === 0, return a sensible fallback (e.g., a default
string or a fallback template with "{first_name}") or throw a clear error;
specifically modify the selection logic around the variables pool and selected
so you only access selected.template when selected is defined (check pool length
first and then compute selected = pool[Math.floor(...)] and replace
"{first_name}" on a guaranteed string).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@components/chat-area.tsx`:
- Line 324: The span using suppressHydrationWarning in ChatArea is hiding a real
SSR/client mismatch for message timestamps; either ensure ChatArea is truly a
client component that only renders timestamps after client-side fetch, or
implement the pre-hydration placeholder pattern used in components/greeting.tsx:
render a stable placeholder (e.g., empty/placeholder timestamp) during SSR and
swap to the real timestamp after hydration in the ChatArea component (target the
span with class "min-w-max text-xs font-semibold text-muted-foreground" that
currently has suppressHydrationWarning), so server-rendered times are never
shown and hydration mismatches are avoided.

In `@lib/greetings.ts`:
- Around line 128-133: The comment states an 80% chance for specific greetings
but the code uses Math.random() < 0.6 (60%); update the condition to
Math.random() < 0.8 so the selection logic for pool (using specificGreetings vs
alwaysGreetings) matches the comment, ensuring the variables specificGreetings,
alwaysGreetings and pool reflect the intended 80% probability.

---

Nitpick comments:
In `@lib/greetings.ts`:
- Around line 135-136: Guard against an empty pool before selecting — if
pool.length === 0, return a sensible fallback (e.g., a default string or a
fallback template with "{first_name}") or throw a clear error; specifically
modify the selection logic around the variables pool and selected so you only
access selected.template when selected is defined (check pool length first and
then compute selected = pool[Math.floor(...)] and replace "{first_name}" on a
guaranteed string).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: aaa43371-2c98-40c6-86db-95c8a7358f2a

📥 Commits

Reviewing files that changed from the base of the PR and between 8759986 and 27bc44a.

📒 Files selected for processing (4)
  • components/chat-area.tsx
  • components/chat-sidebar.tsx
  • lib/date-format.ts
  • lib/greetings.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/chat-sidebar.tsx

Comment thread components/chat-area.tsx
<div className="my-2 flex items-center gap-1">
<Separator className="flex-1" />
<span className="min-w-max text-xs font-semibold text-muted-foreground">
<span className="min-w-max text-xs font-semibold text-muted-foreground" suppressHydrationWarning>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

suppressHydrationWarning is a workaround, not a fix — verify SSR path.

suppressHydrationWarning silences the mismatch but does not prevent the server from rendering a timestamp string under the server's timezone that differs from the client's render. If the server renders these spans (e.g., initial page load with historical messages), end users will briefly see times in the server's TZ before the client re-renders after hydration. Given the TZ removal in lib/date-format.ts, this is now an expected difference.

If ChatArea is indeed a client component that only renders message timestamps after client-side data fetch, this is fine. Otherwise, consider the same pattern used by components/greeting.tsx (render a placeholder pre-hydration, real value post-hydration) to avoid the brief flash of incorrect times.

Also applies to: 381-381

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/chat-area.tsx` at line 324, The span using
suppressHydrationWarning in ChatArea is hiding a real SSR/client mismatch for
message timestamps; either ensure ChatArea is truly a client component that only
renders timestamps after client-side fetch, or implement the pre-hydration
placeholder pattern used in components/greeting.tsx: render a stable placeholder
(e.g., empty/placeholder timestamp) during SSR and swap to the real timestamp
after hydration in the ChatArea component (target the span with class "min-w-max
text-xs font-semibold text-muted-foreground" that currently has
suppressHydrationWarning), so server-rendered times are never shown and
hydration mismatches are avoided.

Comment thread lib/greetings.ts Outdated
Comment on lines +128 to +133
// If we have specific greetings, give them an 80% chance to be used over generic ones
// to avoid generic greetings crowding out the context-aware ones.
const pool =
specificGreetings.length > 0 && Math.random() < 0.6
? specificGreetings
: alwaysGreetings;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Comment and code disagree on the specific-vs-generic probability.

The comment says "80% chance" but Math.random() < 0.6 gives specific greetings only a 60% probability. Either update the number or the comment.

Proposed fix
-  // If we have specific greetings, give them an 80% chance to be used over generic ones
-  // to avoid generic greetings crowding out the context-aware ones.
-  const pool =
-    specificGreetings.length > 0 && Math.random() < 0.6
-      ? specificGreetings
-      : alwaysGreetings;
+  // If we have specific greetings, give them a 60% chance to be used over generic ones
+  // to avoid generic greetings crowding out the context-aware ones.
+  const pool =
+    specificGreetings.length > 0 && Math.random() < 0.6
+      ? specificGreetings
+      : alwaysGreetings;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/greetings.ts` around lines 128 - 133, The comment states an 80% chance
for specific greetings but the code uses Math.random() < 0.6 (60%); update the
condition to Math.random() < 0.8 so the selection logic for pool (using
specificGreetings vs alwaysGreetings) matches the comment, ensuring the
variables specificGreetings, alwaysGreetings and pool reflect the intended 80%
probability.

Copy link
Copy Markdown
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

Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/date-format.ts
Comment on lines 20 to 24
const dayKeyFormatter = new Intl.DateTimeFormat("en-CA", {
year: "numeric",
month: "2-digit",
day: "2-digit",
timeZone: APP_TIME_ZONE,
});
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

dayKeyFormatter no longer specifies a timeZone, so getStableDayKey() depends on the runtime timezone (server vs browser) and may produce different day keys for the same timestamp. Since ChatArea uses this to decide whether to render date dividers, this can cause hydration mismatches (dividers appearing/disappearing) around day boundaries. Consider making getStableDayKey timezone-invariant (e.g., derive the key from new Date(ts).toISOString().slice(0,10) / UTC) or explicitly pass a fixed timeZone for the day-key formatter while keeping display formatting local.

Copilot uses AI. Check for mistakes.
Comment thread components/chat-area.tsx
Comment on lines 313 to 327
const sameRoleAsNext = message.role === nextMessage?.role;
const showDateDivider =
ts !== null &&
(prevTs === null ||
getStableDayKey(ts) !== getStableDayKey(prevTs));

return (
<React.Fragment key={message.id}>
{showDateDivider && ts !== null && (
<div className="my-2 flex items-center gap-1">
<Separator className="flex-1" />
<span className="min-w-max text-xs font-semibold text-muted-foreground">
<span className="min-w-max text-xs font-semibold text-muted-foreground" suppressHydrationWarning>
{formatChatLongDate(ts)}
</span>
<Separator className="flex-1" />
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

Adding suppressHydrationWarning hides the warning for the date text, but the date-divider structure can still differ between server and client because showDateDivider depends on getStableDayKey(ts) (which is now timezone-dependent after removing the fixed timeZone). That can lead to real hydration errors (extra/missing divider elements), not just warnings. To avoid this, make the day-key computation deterministic across environments (e.g., UTC-based) or defer rendering dividers until after hydration.

Copilot uses AI. Check for mistakes.
Comment thread package.json
"@vercel/analytics": "1.3.1",
"autoprefixer": "^10.4.20",
"better-auth": "^1.4.15",
"better-auth": "^1.6.5",
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

better-auth is being updated to ^1.6.5, but @better-auth/cli remains on ^1.4.21 (see devDependencies). The lockfile now includes both 1.4.x and 1.6.x Better Auth packages, which risks version-skew between the CLI/migrations and runtime library. Consider bumping @better-auth/cli to a compatible 1.6.x version (or explicitly validating compatibility) to keep tooling aligned.

Suggested change
"better-auth": "^1.6.5",
"better-auth": "^1.4.21",

Copilot uses AI. Check for mistakes.
Comment thread lib/greetings.ts Outdated
Comment on lines +128 to +133
// If we have specific greetings, give them an 80% chance to be used over generic ones
// to avoid generic greetings crowding out the context-aware ones.
const pool =
specificGreetings.length > 0 && Math.random() < 0.6
? specificGreetings
: alwaysGreetings;
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

The comment says context-specific greetings have an 80% chance to be used, but the code uses Math.random() < 0.6 (60%). Please align the comment and the probability constant so they match (either change the threshold to 0.8 or update the comment).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
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: 1

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

Inline comments:
In `@lib/greetings.ts`:
- Around line 135-136: The current call
selected.template.replaceAll("{first_name}", firstName) lets user-derived
firstName be interpreted for $-style substitution tokens; change it to use a
replacer function so the replacement is used literally, e.g.
replaceAll("{first_name}", () => firstName), ensuring the literal firstName
(from the selected/ pool context) is inserted without $ token expansion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ec937474-2a67-4971-9943-b6ef6efe75b5

📥 Commits

Reviewing files that changed from the base of the PR and between 27bc44a and 29d828d.

📒 Files selected for processing (2)
  • lib/date-format.ts
  • lib/greetings.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/date-format.ts

Comment thread lib/greetings.ts Outdated
@alvinsjoy alvinsjoy merged commit bd2678e into main Apr 21, 2026
1 check passed
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.

2 participants