Skip to content

Create a generic <Chat /> component, and use it for account appeal#12360

Open
sebastianekstrom wants to merge 7 commits into
mainfrom
feature/chat-attachment
Open

Create a generic <Chat /> component, and use it for account appeal#12360
sebastianekstrom wants to merge 7 commits into
mainfrom
feature/chat-attachment

Conversation

@sebastianekstrom

@sebastianekstrom sebastianekstrom commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR will do a somewhat huge refactor of the current appeal chat. However it's not launched to anyone yet so no risk of regression. Changes made are:

  • Refactor everything into a generic <Chat /> component
  • Add animations
  • Add the ability to upload attachments
  • Add the ability to cancel attachment uploads
  • If the tab is not focused and you have an unread message show (X) in the tab bar
  • If you are on other parts of the dashboard, show an unread badge for Finance in the nav
  • Lots more

Full demo

demoooooo.mov

Summary by cubic

Adds a reusable Chat for account appeals with attachments, drag-and-drop, unread indicators, and a new empty state to start conversations. Migrates the appeal case UI to this component, launches the new flow, and improves uploads, scrolling, polling, and line-break rendering in messages.

  • New Features

    • Chat with grouped bubbles, avatars, image/file previews, smooth animations, line-break preserving text, custom message rendering, drag-and-drop overlay, and an empty state.
    • File attachments: drag-and-drop, progress, type/size/limit checks, and cancellation; supports images, video, PDF, CSV/TXT, DOC(X), XLS(X).
    • Unread indicators (tab title when unfocused and a Finance nav dot), decision notices, and auto-refresh of Account page on approval.
  • Refactors

    • Replaced the appeal case UI with Chat via an adapter; replies can include optional file_ids; initial appeal uses a minimum length with a counter.
    • Uploads are abortable and integrated with the composer; improved scrolling with stick-to-bottom, programmatic control, and auto-scroll on send.
    • useAppealCase polling is visibility-aware with adjustable intervals and stops when the thread is closed.

Written for commit 706a75a. Summary will update on new commits.

Review in cubic

@sebastianekstrom sebastianekstrom requested a review from a team as a code owner June 12, 2026 10:33
@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
orbit Ready Ready Preview, Comment Jun 12, 2026 2:02pm
polar Ready Ready Preview, Comment Jun 12, 2026 2:02pm
polar-sandbox Ready Ready Preview, Comment Jun 12, 2026 2:02pm
polar-test Ready Ready Preview, Comment Jun 12, 2026 2:02pm

Request Review

@sebastianekstrom sebastianekstrom changed the title Add <Chat /> for account appeal Create a generic <Chat /> component, and use it for account appeal Jun 12, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

3 issues found across 31 files

Confidence score: 3/5

  • In clients/apps/web/src/components/FileUpload/Upload.ts, a cancel/finalize race can still emit success, so canceled uploads may appear completed and leave UI/state inconsistent; gate success emission on final canceled state (or re-check abort signal) before merging.
  • In clients/apps/web/src/components/Organization/HumanReviewCase/useUnreadTitleBadge.ts, initializing from the current unread count instead of the persisted seen baseline can suppress real unread indicators when the tab mounts unfocused, causing users to miss messages; restore initialization from persisted seen state and add a mount/unfocused regression test.
  • In clients/apps/web/src/components/Chat/MessageThread.tsx, per-message attachments.filter introduces O(messages×attachments) render work that can degrade thread performance as data grows; pre-group attachments by messageId once per render and use constant-time lookup.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="clients/apps/web/src/components/Chat/MessageThread.tsx">

<violation number="1" location="clients/apps/web/src/components/Chat/MessageThread.tsx:73">
P2: Per-message `attachments.filter` creates quadratic render cost. Pre-group attachments by `messageId` once per render and do O(1) lookup per bubble.</violation>
</file>

<file name="clients/apps/web/src/components/Organization/HumanReviewCase/useUnreadTitleBadge.ts">

<violation number="1" location="clients/apps/web/src/components/Organization/HumanReviewCase/useUnreadTitleBadge.ts:10">
P2: Unread title badge baseline uses current count instead of persisted seen count, hiding existing unread messages when mounted while tab is unfocused.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

<ChatBubble
key={message.id}
message={message}
attachments={attachments.filter(

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.

P2: Per-message attachments.filter creates quadratic render cost. Pre-group attachments by messageId once per render and do O(1) lookup per bubble.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At clients/apps/web/src/components/Chat/MessageThread.tsx, line 73:

<comment>Per-message `attachments.filter` creates quadratic render cost. Pre-group attachments by `messageId` once per render and do O(1) lookup per bubble.</comment>

<file context>
@@ -0,0 +1,86 @@
+            <ChatBubble
+              key={message.id}
+              message={message}
+              attachments={attachments.filter(
+                (attachment) => attachment.messageId === message.id,
+              )}
</file context>

Comment thread clients/apps/web/src/components/FileUpload/Upload.ts
messages: schemas['SupportCaseMessage'][] | undefined,
) => {
const count = (messages ?? []).filter(isNotifiable).length
const seenCountRef = useRef(count)

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.

P2: Unread title badge baseline uses current count instead of persisted seen count, hiding existing unread messages when mounted while tab is unfocused.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At clients/apps/web/src/components/Organization/HumanReviewCase/useUnreadTitleBadge.ts, line 10:

<comment>Unread title badge baseline uses current count instead of persisted seen count, hiding existing unread messages when mounted while tab is unfocused.</comment>

<file context>
@@ -0,0 +1,53 @@
+  messages: schemas['SupportCaseMessage'][] | undefined,
+) => {
+  const count = (messages ?? []).filter(isNotifiable).length
+  const seenCountRef = useRef(count)
+  const latestCountRef = useRef(count)
+  const baseTitleRef = useRef<string | null>(null)
</file context>

// Gates the merchant-facing human-review case flow shown after a denied
// appeal. Hardcoded off until the dedicated flow is finished.
const NEW_CASE_FLOW_ENABLED = false
const NEW_CASE_FLOW_ENABLED = true

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Will revert this before merging

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Preview Environment
URL: https://polar-preview-vm.taildbff7b.ts.net/pr-12360
API: https://polar-preview-vm.taildbff7b.ts.net/pr-12360/v1/
Logs: backend
SHA: 706a75afa0fad9a8f1ec8aeb9ab1977199d0b554

@github-actions

Copy link
Copy Markdown
Contributor

OpenAPI Changes

No changes detected in the OpenAPI schema.

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

0 issues found across 3 files (changes from recent commits).

Requires human review: Auto-approval blocked by 2 unresolved issues from previous reviews.

Re-trigger cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

0 issues found across 1 file (changes from recent commits).

Requires human review: Auto-approval blocked by 2 unresolved issues from previous reviews.

Re-trigger cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

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.

0 issues found across 3 files (changes from recent commits).

Requires human review: Auto-approval blocked by 2 unresolved issues from previous reviews.

Re-trigger cubic

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