Skip to content

fix: UI improvements and bug fixes#187

Merged
Israeltheminer merged 13 commits into
mainfrom
update-ui
Jan 12, 2026
Merged

fix: UI improvements and bug fixes#187
Israeltheminer merged 13 commits into
mainfrom
update-ui

Conversation

@Israeltheminer
Copy link
Copy Markdown
Collaborator

@Israeltheminer Israeltheminer commented Jan 12, 2026

Summary

Test plan

  • Verify chat messages don't duplicate when pagination kicks in (>10 messages)
  • Verify optimistic user messages don't duplicate when server responds
  • Test member display name update works correctly
  • Verify not-found page shows correct state based on auth

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Resolved duplicate message display in chat conversations
    • Fixed message streaming status synchronization
  • Improvements

    • Enhanced member display name editing with better concurrent update handling
    • Refined conversation panel and message spacing for improved visual layout
    • Improved authentication-aware routing on error pages
    • Optimized member profile display to prevent duplicate email entries
    • Better optimistic message synchronization with server updates

✏️ Tip: You can customize this high-level summary in your review settings.

Israeltheminer and others added 11 commits January 12, 2026 11:15
- Add check in user-button to only show email if different from displayName
- Add check in member-table to only show email if different from displayName
- Use flex-col and block spans for proper vertical stacking

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add updateMemberDisplayName mutation in convex/member.ts
- Create useUpdateMemberDisplayName hook with optimistic updates
- Update member-edit-dialog to save displayName changes
- Only call mutations when values actually change

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add horizontal padding to conversation panel container
- Remove inner padding from message bubble

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add synchronous render-time check to prevent showing optimistic message
when server message already exists. This eliminates the race condition
where both messages briefly appear during the window between server
message arrival and useEffect cleanup.

Closes #170

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update root not-found page to show appropriate UI based on
authentication state - redirects to dashboard for logged-in users
and shows login button for guests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move globals.css and layout.tsx from app/(app)/ to app/ root
directory. Remove duplicate dashboard not-found.tsx in favor of
root not-found page.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…cate rendering

The previous fix used a useRef for the timestamp, but this failed on new
thread creation because the component remounts during route navigation,
resetting the ref. The server message timestamp would then predate the
newly-set timestamp, causing the duplicate check to fail.

Changes:
- Add timestamp field to OptimisticMessage interface in layout context
- Set timestamp synchronously when user clicks send (before mutation)
- Remove useRef-based timestamp tracking and useEffect
- Add user message deduplication by id in threadMessages

The timestamp now persists across route changes, ensuring the matching
logic works correctly for both new threads and existing conversations.

Closes #170

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…nation

When pagination kicks in (>10 messages), old stream messages cached in
React state could appear without their corresponding user message.

Changes:
- Only include 'streaming' status in syncStreams (finished messages come
  from listUIMessages)
- Filter out orphaned assistant messages whose order is less than the
  minimum user message order
- Add content-based deduplication for assistant messages

Fixes #184

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unnecessary calc() wrapper in chat-header.tsx
- Remove redundant type cast in user-button.tsx
- Extract IIFE role check to named constant in user-button.tsx
- Add input validation in use-update-member-display-name.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 12, 2026

📝 Walkthrough

Walkthrough

This PR implements multiple UI and data-flow refinements across the platform dashboard. Changes include translation key updates for authentication skeleton components, substantial chat message handling improvements with deduplication and pagination-aware filtering using optimistic timestamps, member management enhancements supporting display name editing with optimistic updates, UI layout adjustments for conversations and headers, conversion of the root not-found page to a client component with authentication-aware rendering, and removal of the dashboard-specific not-found handler.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs


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

Copy link
Copy Markdown

@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: 4

Caution

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

⚠️ Outside diff range comments (1)
services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-edit-dialog.tsx (1)

95-117: Success toast shown even when no changes are made.

When neither role nor displayName has changed, promises remains empty. Promise.all([]) resolves successfully, so the success toast "memberUpdated" will display even though nothing was actually updated. This could confuse users.

Consider adding an early return or adjusting the toast:

Proposed fix
       const displayNameChanged = data.displayName !== original.displayName;
       if (displayNameChanged) {
         promises.push(
           updateMemberDisplayName({ memberId, displayName: data.displayName }),
         );
       }
 
+      if (promises.length === 0) {
+        // No actual changes to save
+        return;
+      }
+
       await Promise.all(promises);
🤖 Fix all issues with AI agents
In @services/platform/app/layout.tsx:
- Line 11: The root layout currently imports AppProviders from the route-group
directory using the updated import in layout.tsx which creates coupling; to fix,
move the AppProviders module out of the (app) route group into a shared location
(e.g., a new module named app-providers under a shared providers namespace like
@/providers/app-providers), update the export there, and update the import in
layout.tsx to reference the new shared path so the root layout no longer depends
on a route-group folder.

In @services/platform/components/user-button.tsx:
- Around line 154-159: The JSX contains an unnecessary IIFE used to compute the
render condition; extract the logic out of the JSX by defining a computed
variable (or useMemo) inside the component (e.g., compute userRole =
(memberContext?.role ?? '').toLowerCase(); const isAdminOrDeveloper = userRole
=== 'admin' || userRole === 'developer';) and then use that variable directly in
the JSX conditional (e.g., !loading && user && isAdminOrDeveloper) to remove the
IIFE.

In @services/platform/convex/member.ts:
- Around line 437-504: The updateMemberDisplayName mutation lacks server-side
validation for args.displayName; trim the incoming displayName (e.g., const
trimmedName = args.displayName.trim()), verify it's not empty and enforce
sensible constraints (max length like 256 and optional character rules) and
throw a clear Error if invalid, then use trimmedName in the Better Auth
updateMany call (replace update: { name: args.displayName } with update: { name:
trimmedName }). Ensure these checks occur before calling
components.betterAuth.adapter.updateMany in the updateMemberDisplayName handler.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro (Legacy)

📥 Commits

Reviewing files that changed from the base of the PR and between 72c3704 and ffeabd7.

📒 Files selected for processing (17)
  • services/platform/app/(app)/(auth)/log-in/[[...log-in]]/page.tsx
  • services/platform/app/(app)/(auth)/sign-up/[[...sign-up]]/page.tsx
  • services/platform/app/(app)/dashboard/[id]/chat/components/chat-header.tsx
  • services/platform/app/(app)/dashboard/[id]/chat/components/chat-interface.tsx
  • services/platform/app/(app)/dashboard/[id]/chat/layout.tsx
  • services/platform/app/(app)/dashboard/[id]/conversations/components/conversation-panel.tsx
  • services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx
  • services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-edit-dialog.tsx
  • services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-table.tsx
  • services/platform/app/(app)/dashboard/[id]/settings/organization/hooks/use-update-member-display-name.ts
  • services/platform/app/(app)/dashboard/not-found.tsx
  • services/platform/app/globals.css
  • services/platform/app/layout.tsx
  • services/platform/app/not-found.tsx
  • services/platform/components/user-button.tsx
  • services/platform/convex/member.ts
  • services/platform/convex/model/threads/get_thread_messages_streaming.ts
💤 Files with no reviewable changes (1)
  • services/platform/app/(app)/dashboard/not-found.tsx
🧰 Additional context used
🧠 Learnings (50)
📚 Learning: 2025-12-30T06:20:18.848Z
Learnt from: larryro
Repo: tale-project/tale PR: 37
File: services/platform/convex/model/conversations/validators.ts:31-39
Timestamp: 2025-12-30T06:20:18.848Z
Learning: In services/platform/convex/model/conversations/validators.ts, the messageValidator intentionally uses v.string() for the status field because message statuses are dynamic and come from different sources (email providers, internal state, etc.) and are not yet constrained to a fixed set of values.

Applied to files:

  • services/platform/convex/model/threads/get_thread_messages_streaming.ts
📚 Learning: 2025-12-26T03:04:07.995Z
Learnt from: larryro
Repo: tale-project/tale PR: 35
File: services/platform/convex/approvals.ts:51-62
Timestamp: 2025-12-26T03:04:07.995Z
Learning: In Convex approvals API (services/platform/convex/approvals.ts), continue the pattern of maintaining separate internalQuery functions for internal vs public API access (e.g., getApprovalInternal vs getApprovalById) even if implementations are identical. This separation preserves the ability to diverge access control patterns in the future without breaking call sites. Apply this guideline broadly to the Convex-related API files under services/platform/convex/, using the pattern services/platform/convex/**/*.ts to cover similar modules. Ensure new or refactored internal/public wrappers follow this convention and document intent where access rules may evolve.

Applied to files:

  • services/platform/convex/model/threads/get_thread_messages_streaming.ts
  • services/platform/convex/member.ts
📚 Learning: 2025-12-30T03:24:33.770Z
Learnt from: larryro
Repo: tale-project/tale PR: 36
File: services/platform/convex/wf_step_defs.ts:33-39
Timestamp: 2025-12-30T03:24:33.770Z
Learning: In Convex API files under services/platform/convex (e.g., wf_step_defs.ts and peers) refrain from delegating trivial single-line database calls like ctx.db.get(id) to model helpers. Use direct calls for simple operations with no extra business logic. Reserve model helpers for complex tasks (ordering, filtering, validation, transformation). This guideline applies to all .ts files in this Convex API area.

Applied to files:

  • services/platform/convex/model/threads/get_thread_messages_streaming.ts
  • services/platform/convex/member.ts
📚 Learning: 2026-01-05T01:44:20.855Z
Learnt from: larryro
Repo: tale-project/tale PR: 76
File: services/platform/convex/agent_tools/sub_agents/helpers/format_integrations.ts:73-111
Timestamp: 2026-01-05T01:44:20.855Z
Learning: Guideline: In Convex integration-related TypeScript files (e.g., services/platform/convex/agent_tools/sub_agents/helpers/format_integrations.ts and services/platform/convex/agent_tools/integrations/execute_batch_integration_internal.ts), avoid relying on generated types for optional fields. If you must access optional fields like sqlOperations or connector on Doc<'integrations'> and the generated type doesn’t capture them, use an explicit as any cast to access those fields, and document this rationale (as referenced in issue #79). During reviews, flag such casts, verify they’re necessary due to known type limitations, and ensure alternative type-safe approaches aren’t feasible before accepting the cast.

Applied to files:

  • services/platform/convex/model/threads/get_thread_messages_streaming.ts
  • services/platform/convex/member.ts
📚 Learning: 2026-01-07T05:04:32.489Z
Learnt from: larryro
Repo: tale-project/tale PR: 96
File: services/platform/convex/model/integrations/save_related_workflows.ts:45-76
Timestamp: 2026-01-07T05:04:32.489Z
Learning: In Convex workflow integration code (e.g., services/platform/convex/model/integrations/save_related_workflows.ts), prefer using targeted inline narrowing casts like (baseConfig as { variables?: Record<string, unknown> }).variables to access nested optional fields from dynamic config (Record<string, unknown>). This approach is preferable to blanket as any assertions and does not require extracting into a helper function. Apply this guidance to TypeScript files under services/platform/convex/**/*.ts for consistent, type-safe access to optional nested fields.

Applied to files:

  • services/platform/convex/model/threads/get_thread_messages_streaming.ts
  • services/platform/convex/member.ts
📚 Learning: 2025-12-30T06:21:13.183Z
Learnt from: larryro
Repo: tale-project/tale PR: 37
File: services/platform/convex/model/documents/validators.ts:89-102
Timestamp: 2025-12-30T06:21:13.183Z
Learning: Do not flag a missing trailing newline for TypeScript files in code reviews. POSIX text files should end with a trailing newline and Prettier (or your formatter) will enforce this. Treat the trailing newline as a non-issue in reviews for all TS files.

Applied to files:

  • services/platform/convex/model/threads/get_thread_messages_streaming.ts
  • services/platform/app/(app)/dashboard/[id]/settings/organization/hooks/use-update-member-display-name.ts
  • services/platform/convex/member.ts
📚 Learning: 2026-01-07T04:59:31.831Z
Learnt from: larryro
Repo: tale-project/tale PR: 96
File: services/platform/convex/model/customers/update_customers.ts:98-101
Timestamp: 2026-01-07T04:59:31.831Z
Learning: When accessing v.any() schema fields in Convex code (e.g., customer.metadata, conversation.metadata), after a runtime guard that ensures the value is an object (typeof val === 'object' && val !== null && !Array.isArray(val)), prefer applying an explicit TypeScript cast to Record<string, unknown> at the usage site. This maintains type safety and explicitness at each usage point without introducing dedicated type guard functions, while aligning with how dynamically-typed schema fields are handled in the codebase.

Applied to files:

  • services/platform/convex/model/threads/get_thread_messages_streaming.ts
  • services/platform/convex/member.ts
📚 Learning: 2025-11-25T04:37:44.394Z
Learnt from: CR
Repo: tale-project/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-11-25T04:37:44.394Z
Learning: Applies to **/*.{tsx,jsx} : Use semantic spacing classes when available: `p-1` for 4px, `p-2` for 8px, `m-1` for 4px, `m-2` for 8px

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/conversations/components/conversation-panel.tsx
  • services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx
📚 Learning: 2025-10-01T17:12:39.508Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-10-01T17:12:39.508Z
Learning: Applies to **/*.tsx : Replace p-[4px] with p-1

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/conversations/components/conversation-panel.tsx
  • services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx
📚 Learning: 2025-10-01T17:12:39.508Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-10-01T17:12:39.508Z
Learning: Applies to **/*.tsx : Replace p-[8px] with p-2

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/conversations/components/conversation-panel.tsx
  • services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx
📚 Learning: 2025-10-01T17:12:39.508Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-10-01T17:12:39.508Z
Learning: Applies to **/*.tsx : Replace m-[4px] with m-1

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/conversations/components/conversation-panel.tsx
  • services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx
  • services/platform/app/(app)/dashboard/[id]/chat/components/chat-header.tsx
📚 Learning: 2025-10-01T17:12:39.508Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-10-01T17:12:39.508Z
Learning: Applies to **/*.tsx : Replace m-[8px] with m-2

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/conversations/components/conversation-panel.tsx
  • services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx
  • services/platform/app/(app)/dashboard/[id]/chat/components/chat-header.tsx
📚 Learning: 2025-12-26T02:23:20.245Z
Learnt from: larryro
Repo: tale-project/tale PR: 35
File: services/platform/app/(app)/dashboard/[id]/chat/components/integration-approval-card.tsx:58-90
Timestamp: 2025-12-26T02:23:20.245Z
Learning: In services/platform/app/(app)/dashboard/[id]/chat/components/integration-approval-card.tsx, prefer reading the approving user from the authenticated session context rather than passing a userId from the frontend. The hardcoded 'user' string can be acceptable only as a temporary placeholder during the initial implementation until a user profile feature is added; plan to replace with proper user identity via session context or user service once backend supports it.

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/conversations/components/conversation-panel.tsx
  • services/platform/app/not-found.tsx
  • services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx
  • services/platform/app/(app)/dashboard/[id]/chat/components/chat-interface.tsx
  • services/platform/app/(app)/dashboard/[id]/chat/layout.tsx
  • services/platform/app/(app)/dashboard/[id]/chat/components/chat-header.tsx
  • services/platform/app/(app)/(auth)/log-in/[[...log-in]]/page.tsx
  • services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-table.tsx
  • services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-edit-dialog.tsx
  • services/platform/app/layout.tsx
  • services/platform/components/user-button.tsx
  • services/platform/app/(app)/(auth)/sign-up/[[...sign-up]]/page.tsx
📚 Learning: 2025-11-30T12:29:39.745Z
Learnt from: CR
Repo: tale-project/poc2 PR: 0
File: .cursor/rules/workspace_rules.mdc:0-0
Timestamp: 2025-11-30T12:29:39.745Z
Learning: Applies to **/app/**/page.tsx : Use `page.tsx` for server components by default in Next.js App Router

Applied to files:

  • services/platform/app/not-found.tsx
📚 Learning: 2025-08-21T14:59:36.874Z
Learnt from: CR
Repo: talecorp/lanserhof PR: 0
File: .cursorrules:0-0
Timestamp: 2025-08-21T14:59:36.874Z
Learning: Applies to app/**/page.tsx : Next.js App Router pages (page.tsx) are server components by default

Applied to files:

  • services/platform/app/not-found.tsx
📚 Learning: 2025-10-11T11:46:02.452Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursorrules:0-0
Timestamp: 2025-10-11T11:46:02.452Z
Learning: Applies to app/**/page.tsx : In App Router, page.tsx components are server components by default

Applied to files:

  • services/platform/app/not-found.tsx
📚 Learning: 2025-07-03T08:43:49.346Z
Learnt from: CR
Repo: talecorp/poc PR: 0
File: .cursor/rules/next-best-practice.mdc:0-0
Timestamp: 2025-07-03T08:43:49.346Z
Learning: Applies to app/**/*.tsx : Use server components for data fetching, database queries, and server-side logic

Applied to files:

  • services/platform/app/not-found.tsx
  • services/platform/app/layout.tsx
📚 Learning: 2025-08-21T14:59:36.874Z
Learnt from: CR
Repo: talecorp/lanserhof PR: 0
File: .cursorrules:0-0
Timestamp: 2025-08-21T14:59:36.874Z
Learning: Applies to {app,components}/**/*.{tsx,jsx} : Use 'use client' only when needed for interactions/state (client components)

Applied to files:

  • services/platform/app/not-found.tsx
📚 Learning: 2025-07-19T15:29:09.401Z
Learnt from: CR
Repo: talecorp/poc PR: 0
File: .cursorrules:0-0
Timestamp: 2025-07-19T15:29:09.401Z
Learning: Applies to **/page.tsx : In Next.js App Router, `page.tsx` files must be server components by default.

Applied to files:

  • services/platform/app/not-found.tsx
📚 Learning: 2025-07-03T08:43:49.346Z
Learnt from: CR
Repo: talecorp/poc PR: 0
File: .cursor/rules/next-best-practice.mdc:0-0
Timestamp: 2025-07-03T08:43:49.346Z
Learning: Applies to **/*.{tsx,jsx} : Use proper navigation with `useRouter` and `Link` components

Applied to files:

  • services/platform/app/not-found.tsx
📚 Learning: 2025-07-03T08:43:49.346Z
Learnt from: CR
Repo: talecorp/poc PR: 0
File: .cursor/rules/next-best-practice.mdc:0-0
Timestamp: 2025-07-03T08:43:49.346Z
Learning: Applies to app/**/page.tsx : `page.tsx` files: Always implement as server components by default

Applied to files:

  • services/platform/app/not-found.tsx
📚 Learning: 2025-10-11T11:46:02.452Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursorrules:0-0
Timestamp: 2025-10-11T11:46:02.452Z
Learning: Applies to **/*.tsx : Follow the required client component structure: imports, Props interface, hooks, effects, handlers, and render order; include 'use client' only when needed

Applied to files:

  • services/platform/app/not-found.tsx
  • services/platform/app/layout.tsx
📚 Learning: 2025-10-11T11:46:02.452Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursorrules:0-0
Timestamp: 2025-10-11T11:46:02.452Z
Learning: Applies to **/*.{tsx,jsx} : Use 'use client' only for components that need interactions or state

Applied to files:

  • services/platform/app/not-found.tsx
📚 Learning: 2025-08-21T14:59:36.874Z
Learnt from: CR
Repo: talecorp/lanserhof PR: 0
File: .cursorrules:0-0
Timestamp: 2025-08-21T14:59:36.874Z
Learning: Applies to {app,components}/**/*.{tsx,jsx} : Use Next.js Image component for all images

Applied to files:

  • services/platform/app/not-found.tsx
  • services/platform/app/layout.tsx
📚 Learning: 2025-10-01T17:12:39.508Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-10-01T17:12:39.508Z
Learning: Applies to **/*.tsx : Replace text-[20px] with text-xl

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx
📚 Learning: 2025-10-01T17:12:39.508Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-10-01T17:12:39.508Z
Learning: Applies to **/*.tsx : Replace text-[24px] with text-2xl

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx
📚 Learning: 2025-10-01T17:12:39.508Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-10-01T17:12:39.508Z
Learning: Applies to **/*.tsx : Replace text-[12px] with text-xs

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx
📚 Learning: 2025-10-01T17:12:39.508Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-10-01T17:12:39.508Z
Learning: Applies to **/*.tsx : Replace text-[14px] with text-sm

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx
📚 Learning: 2025-12-20T13:38:13.773Z
Learnt from: larryro
Repo: tale-project/tale PR: 30
File: services/platform/convex/model/chat_agent/chat_with_agent.ts:130-144
Timestamp: 2025-12-20T13:38:13.773Z
Learning: In services/platform/convex/model/chat_agent/chat_with_agent.ts, image fileIds are intentionally displayed as `*(fileId: ${attachment.fileId})*` in the markdown because the AI needs to reference them from thread history for re-analysis using the image tool. This is a business/developer tool, not consumer-facing, so technical metadata visibility is acceptable.

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/chat/components/chat-interface.tsx
📚 Learning: 2025-07-03T08:43:49.346Z
Learnt from: CR
Repo: talecorp/poc PR: 0
File: .cursor/rules/next-best-practice.mdc:0-0
Timestamp: 2025-07-03T08:43:49.346Z
Learning: Applies to **/*.{tsx,jsx} : Use Suspense for loading states in components

Applied to files:

  • services/platform/app/(app)/(auth)/log-in/[[...log-in]]/page.tsx
📚 Learning: 2025-11-25T04:37:44.394Z
Learnt from: CR
Repo: tale-project/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-11-25T04:37:44.394Z
Learning: Applies to **/*.{tsx,jsx} : ALWAYS use the Table component (`Table`, `TableHeader`, `TableBody`, `TableRow`, `TableHead`, `TableCell`) instead of custom flex layouts; apply proper column widths using rem units and use semantic colors for all text and backgrounds

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-table.tsx
📚 Learning: 2025-10-01T17:12:39.508Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-10-01T17:12:39.508Z
Learning: Applies to **/*.tsx : Always use the Table component instead of custom flex layouts for tabular data

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-table.tsx
📚 Learning: 2025-10-01T17:12:39.508Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-10-01T17:12:39.508Z
Learning: Applies to **/*.tsx : Use Table, TableHeader, TableBody, TableRow, TableHead, and TableCell components for tables

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-table.tsx
📚 Learning: 2025-10-01T17:12:39.508Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/figma_rules.mdc:0-0
Timestamp: 2025-10-01T17:12:39.508Z
Learning: Applies to **/*.tsx : Apply column widths in tables using rem units

Applied to files:

  • services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-table.tsx
📚 Learning: 2025-08-21T14:59:36.874Z
Learnt from: CR
Repo: talecorp/lanserhof PR: 0
File: .cursorrules:0-0
Timestamp: 2025-08-21T14:59:36.874Z
Learning: Applies to app/**/*.{tsx,jsx} : Use dynamic imports for code splitting where appropriate

Applied to files:

  • services/platform/app/layout.tsx
📚 Learning: 2025-08-21T14:59:36.874Z
Learnt from: CR
Repo: talecorp/lanserhof PR: 0
File: .cursorrules:0-0
Timestamp: 2025-08-21T14:59:36.874Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use Vercel AI SDK only for AI features: import from 'ai' and 'openrouter/ai-sdk-provider'

Applied to files:

  • services/platform/app/layout.tsx
📚 Learning: 2025-07-19T15:30:00.886Z
Learnt from: CR
Repo: talecorp/poc PR: 0
File: .cursor/rules/core-rules.mdc:0-0
Timestamp: 2025-07-19T15:30:00.886Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Do not use direct OpenAI imports

Applied to files:

  • services/platform/app/layout.tsx
📚 Learning: 2025-08-21T15:01:09.405Z
Learnt from: CR
Repo: talecorp/lanserhof PR: 0
File: .cursor/rules/core-rules.mdc:0-0
Timestamp: 2025-08-21T15:01:09.405Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Avoid direct OpenAI imports

Applied to files:

  • services/platform/app/layout.tsx
📚 Learning: 2025-08-21T14:59:36.874Z
Learnt from: CR
Repo: talecorp/lanserhof PR: 0
File: .cursorrules:0-0
Timestamp: 2025-08-21T14:59:36.874Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Avoid Pages Router patterns in new code (App Router only)

Applied to files:

  • services/platform/app/layout.tsx
📚 Learning: 2025-07-03T08:43:49.346Z
Learnt from: CR
Repo: talecorp/poc PR: 0
File: .cursor/rules/next-best-practice.mdc:0-0
Timestamp: 2025-07-03T08:43:49.346Z
Learning: Applies to **/*.{tsx,jsx} : Use dynamic imports for code splitting

Applied to files:

  • services/platform/app/layout.tsx
📚 Learning: 2025-10-11T11:46:02.452Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursorrules:0-0
Timestamp: 2025-10-11T11:46:02.452Z
Learning: Applies to **/*.{ts,tsx,js} : Do not import OpenAI directly (e.g., `import OpenAI from 'openai'`)

Applied to files:

  • services/platform/app/layout.tsx
📚 Learning: 2025-08-21T14:59:36.874Z
Learnt from: CR
Repo: talecorp/lanserhof PR: 0
File: .cursorrules:0-0
Timestamp: 2025-08-21T14:59:36.874Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Do not import OpenAI SDK directly (e.g., `import OpenAI from 'openai'`)

Applied to files:

  • services/platform/app/layout.tsx
📚 Learning: 2025-10-11T11:46:02.452Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursorrules:0-0
Timestamp: 2025-10-11T11:46:02.452Z
Learning: Applies to **/*.{tsx,jsx} : Use dynamic imports for code splitting where appropriate

Applied to files:

  • services/platform/app/layout.tsx
📚 Learning: 2024-10-12T10:20:33.353Z
Learnt from: yannickmonney
Repo: talecorp/tale PR: 1320
File: core/next/src/utils/next/metadata/generate-default-metadata.ts:3-3
Timestamp: 2024-10-12T10:20:33.353Z
Learning: In the TypeScript file `core/next/src/utils/next/metadata/generate-default-metadata.ts`, the import path `'tale/core/base/utils/utils/i18n/get-global-translate'` with the duplicated `'utils'` segment is intentional and correct. This is the proper import path for the `getGlobalTranslate` function and should not be flagged as a typo in future code reviews.

Applied to files:

  • services/platform/app/layout.tsx
📚 Learning: 2025-07-19T15:29:09.401Z
Learnt from: CR
Repo: talecorp/poc PR: 0
File: .cursorrules:0-0
Timestamp: 2025-07-19T15:29:09.401Z
Learning: Applies to app/components/**/*.{js,jsx,ts,tsx} : Use Next.js Image component for all images.

Applied to files:

  • services/platform/app/layout.tsx
📚 Learning: 2025-12-15T14:01:55.275Z
Learnt from: larryro
Repo: tale-project/tale PR: 18
File: services/platform/convex/workflow/actions/conversation/helpers/update_conversations.ts:7-10
Timestamp: 2025-12-15T14:01:55.275Z
Learning: In Convex action helpers (services/platform/convex/workflow/actions/**/helpers/*.ts), using Record<string, unknown> for update parameters is acceptable when field validation is handled at the mutation level in Convex. This provides flexibility for dynamic field updates while keeping validation centralized at the mutation layer.

Applied to files:

  • services/platform/convex/member.ts
📚 Learning: 2025-10-03T11:34:20.628Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-10-03T11:34:20.628Z
Learning: Applies to convex/**/*.{ts,js} : Always use the new Convex function syntax (query/mutation/action with args/returns/handler)

Applied to files:

  • services/platform/convex/member.ts
📚 Learning: 2025-11-30T03:53:00.316Z
Learnt from: CR
Repo: tale-project/poc2 PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-11-30T03:53:00.316Z
Learning: Applies to convex/**/*.ts : Always use the new Convex function syntax with `query`, `mutation`, `internalQuery`, `internalMutation`, `action`, or `internalAction` with explicit `args`, `returns`, and `handler` properties

Applied to files:

  • services/platform/convex/member.ts
📚 Learning: 2025-10-03T11:34:20.628Z
Learnt from: CR
Repo: talecorp/poc2 PR: 0
File: .cursor/rules/convex_rules.mdc:0-0
Timestamp: 2025-10-03T11:34:20.628Z
Learning: Applies to convex/**/*.{ts,js} : Register public functions with query, mutation, and action; do not use these for sensitive internal logic

Applied to files:

  • services/platform/convex/member.ts
📚 Learning: 2024-10-31T07:10:23.361Z
Learnt from: Israeltheminer
Repo: talecorp/tale PR: 1536
File: apps/app/app/[locale]/(protected)/merchant/(dashboard)/(settings)/(organization-settings)/business-details/page.tsx:21-21
Timestamp: 2024-10-31T07:10:23.361Z
Learning: In `apps/app/app/[locale]/(protected)/merchant/(dashboard)/(settings)/(organization-settings)/business-details/page.tsx`, the `numberOfEmployees` field in `BusinessDetailsForm` is not a required form entry.

Applied to files:

  • services/platform/app/(app)/(auth)/sign-up/[[...sign-up]]/page.tsx
🧬 Code graph analysis (5)
services/platform/app/(app)/(auth)/log-in/[[...log-in]]/page.tsx (1)
services/platform/app/(app)/(auth)/components/auth-skeleton.tsx (1)
  • AuthFormSkeleton (52-84)
services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-table.tsx (2)
services/platform/components/ui/layout.tsx (1)
  • Stack (42-50)
services/platform/components/ui/table-date-cell.tsx (1)
  • TableTimestampCell (101-115)
services/platform/components/user-button.tsx (2)
services/platform/components/ui/dropdown-menu.tsx (1)
  • DropdownMenuTrigger (199-199)
services/platform/components/ui/skeleton.tsx (1)
  • Skeleton (3-13)
services/platform/convex/member.ts (1)
services/platform/convex/model/members/types.ts (3)
  • BetterAuthFindManyResult (62-66)
  • BetterAuthUser (11-20)
  • BetterAuthMember (25-31)
services/platform/app/(app)/(auth)/sign-up/[[...sign-up]]/page.tsx (1)
services/platform/app/(app)/(auth)/components/auth-skeleton.tsx (1)
  • AuthFormSkeleton (52-84)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build Docker Image
🔇 Additional comments (20)
services/platform/app/(app)/(auth)/log-in/[[...log-in]]/page.tsx (1)

84-87: LGTM!

The translation key update aligns with the PR objective to correct auth skeleton translation keys and mirrors the parallel change in the sign-up flow (signup.signupTitle). The login.loginTitle translation key is properly defined in services/platform/messages/en.json and is consistently used across both the skeleton fallback and the form component. The distinction between login.title (used for page metadata) and login.loginTitle (used for the form header) is appropriate since they serve different purposes.

services/platform/app/layout.tsx (1)

5-6: LGTM — ESLint disable for CSS side-effect import is appropriate.

CSS imports are a standard exception to import/no-unassigned-import. The inline disable works, though you could alternatively allow *.css files globally in your ESLint config if this pattern appears elsewhere:

// eslint.config.js
'import/no-unassigned-import': ['error', { allow: ['**/*.css'] }]
services/platform/app/(app)/(auth)/sign-up/[[...sign-up]]/page.tsx (1)

45-45: No action required—the translation keys are intentionally different for different purposes.

The skeleton fallback uses signup.signupTitle ("Create your account"), which matches the actual SignUpForm component that also uses signup.signupTitle. The metadata uses signup.title ("Create account") for the browser tab/page head, which is a separate concern from the UI title. There is no visual inconsistency or layout shift between the skeleton and loaded form since both display the same text.

services/platform/convex/model/threads/get_thread_messages_streaming.ts (1)

41-46: Verify exclusion of 'aborted' status is intentional.

The fix for Issue #184 is sound—excluding 'finished' messages prevents duplicates since they already come from listUIMessages. However, the change also excludes the 'aborted' status that was previously included.

Please confirm that aborted messages are correctly retrieved via listUIMessages and don't need to be included in the streaming sync.

services/platform/app/(app)/dashboard/[id]/chat/components/chat-header.tsx (1)

133-134: LGTM!

The simplified positioning removes the unnecessary calc() wrapper as noted in the PR description. The fixed offset of HISTORY_WIDTH pixels is cleaner and achieves the same result.

services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-table.tsx (2)

69-80: LGTM!

The logic correctly prevents duplicate display when displayName equals email. Using Stack with gap={0} and block-level spans ensures proper layout. This is a good UX improvement.


107-115: LGTM!

The header alignment and TableTimestampCell formatting are clean improvements.

services/platform/app/not-found.tsx (2)

1-15: LGTM!

Converting to a client component is necessary to use useAuth and useT hooks for the auth-aware rendering. The implementation correctly handles loading, authenticated, and unauthenticated states.


26-36: Consider handling potential auth check delay on initial render.

The loading skeleton provides a good placeholder, but on slow networks or during hydration, there might be a brief flash. The current implementation handles this gracefully with the skeleton, which is appropriate.

services/platform/app/(app)/dashboard/[id]/conversations/components/conversation-panel.tsx (1)

379-379: LGTM!

The padding adjustments (pt-2 and px-4) align with the broader UI refinements in this PR.

services/platform/app/(app)/dashboard/[id]/conversations/components/message.tsx (1)

37-44: Verify content doesn't touch bubble edges after removing padding.

The p-2 padding was removed from the message container. Ensure that the EmailPreview component or its content provides adequate internal spacing so text doesn't touch the rounded edges of the bubble.

services/platform/app/(app)/dashboard/[id]/chat/layout.tsx (1)

22-27: All call sites correctly include the required timestamp field.

Verification confirms that all places setting OptimisticMessage objects include the timestamp field. The two null assignments are properly typed and valid. The implementation is complete and correct.

services/platform/app/(app)/dashboard/[id]/settings/organization/hooks/use-update-member-display-name.ts (1)

5-33: LGTM — Clean optimistic update pattern with proper validation.

The hook correctly validates the display name before applying the optimistic update, and the cache update logic properly handles the case where the query result might be undefined or null.

One minor observation: organizationId is captured from params at hook instantiation time rather than at mutation invocation. This works correctly because the hook will be re-instantiated when navigating to a different organization route, but be mindful of this closure behavior if the hook's usage context changes.

services/platform/app/(app)/dashboard/[id]/settings/organization/components/member-edit-dialog.tsx (1)

132-139: LGTM — Original state passed correctly for change detection.

Passing the original member.role and member.displayName to handleUpdateMember enables accurate change detection without relying on form dirty state, which could be unreliable for initial values.

services/platform/components/user-button.tsx (1)

133-137: Good UX improvement — avoids duplicate email display.

Conditionally rendering the email only when it differs from the display name prevents visual redundancy when a user's display name is set to their email address.

services/platform/convex/member.ts (1)

35-51: LGTM — Formatting improvements only.

The multi-line formatting for query arguments improves readability without changing functionality.

services/platform/app/(app)/dashboard/[id]/chat/components/chat-interface.tsx (4)

329-374: Content-based deduplication may cause false positives.

Using the first 200 characters as a content key (lines 365-370) could incorrectly filter out distinct messages that happen to share the same opening text. While this addresses Issue #184, consider using a more robust deduplication strategy.

Consider including additional discriminators like order or _creationTime in the content key to reduce false positive risk:

       if (m.role === 'assistant' && m.text) {
-        const contentKey = m.text.substring(0, 200);
+        // Include order to distinguish messages with similar content
+        const contentKey = `${m.order}:${m.text.substring(0, 200)}`;
         if (seenAssistantContent.has(contentKey)) {
           return false;
         }

Alternatively, verify that the root cause of duplicate streaming/persisted messages is fully addressed at the source (the streaming hook or backend).


684-690: LGTM — Timestamp-based optimistic message tracking.

Adding optimisticTimestamp and propagating it through thread creation improves the accuracy of matching server messages to optimistic drafts, preventing the race condition where old messages could be incorrectly matched.

Also applies to: 715-720


871-883: LGTM — Correctly suppresses duplicate optimistic message.

Using hasMatchingServerMessage to conditionally render the draft message prevents the brief duplicate display during the window between server message arrival and state cleanup.


886-903: LGTM — Improved ThinkingAnimation visibility logic.

Explicitly checking streamingMessage?.status === 'streaming' ensures the indicator remains visible during tool state transitions when no text has been output yet. The comment clearly explains the rationale.

Comment thread services/platform/app/layout.tsx Outdated
Comment thread services/platform/components/user-button.tsx
Comment thread services/platform/convex/member.ts
The globals.css file was moved from app/(app)/ to app/ but the
date-range-picker.module.css reference wasn't updated.
- Move providers from app/(app)/providers to root providers/
- Update layout.tsx import to use @/providers/app-providers
- Extract duplicated message matching logic to findMatchingServerMessage helper
- Add server-side validation for displayName in updateMemberDisplayName mutation
  (trim, empty check, max 256 chars)
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.

1 participant