Skip to content

refactor(livechat): migrate remaining modules to TypeScript#41559

Draft
tassoevan wants to merge 14 commits into
developfrom
refactor/livechat-js
Draft

refactor(livechat): migrate remaining modules to TypeScript#41559
tassoevan wants to merge 14 commits into
developfrom
refactor/livechat-js

Conversation

@tassoevan

@tassoevan tassoevan commented Jul 24, 2026

Copy link
Copy Markdown
Member

Proposed changes (including videos or screenshots)

Finishes migrating the @rocket.chat/livechat package to TypeScript and does some related cleanup along the way. This is a refactor — no end-user behavior changes are intended.

TypeScript conversion (the remaining .js modules under packages/livechat/src — the tree is now 100% .ts/.tsx):

  • routes/Chat (component + container)
  • lib modules: main, room, threads, triggers, uiKit
  • components/Sound, components/uiKit index, and components/Messages (Message, MessageList)

Along the way, a few StoreState fields that these modules use at runtime but weren't typed were added, and a handful of latent bugs surfaced by the type checker were fixed (and called out in the individual commits).

Component refactors:

  • App and TriggerMessage converted from class components (withTranslation HOC) to function components using hooks. App now gates the routed screens on i18n.isInitialized, so translation-consuming routes no longer mount before i18next finishes initializing.

Tooling / build:

  • Typecheck now runs against tsconfig.json (tsc --noEmit) instead of a duplicate tsconfig.typecheck.json.
  • The repo-root postcss.config.js (only consumed by livechat) is scoped into the package, and postcss-css-variables is dropped — every browser in livechat's browserslist supports CSS custom properties natively, which also removes the "variable … used without a fallback" build warnings.
  • Storybook: fixed a node:stream unhandled-scheme build failure by normalizing node: specifiers in the webpack config, and added a reusable storeDecorator that feeds arbitrary store state to stories via StoreContext.

Issue(s)

N/A

Steps to test or reproduce

yarn workspace @rocket.chat/livechat typecheck
yarn workspace @rocket.chat/livechat eslint
yarn workspace @rocket.chat/livechat build
yarn workspace @rocket.chat/livechat build-storybook

All pass locally.

Further comments

Draft while the changes are reviewed. A changeset can be added if this should surface in release notes; happy to split into smaller PRs if that eases review.

Review in cubic

tassoevan and others added 7 commits July 24, 2026 15:38
Drop the separate tsconfig.typecheck.json and point the `typecheck`
script at the package's tsconfig.json with `--noEmit`. The extra config
only added skipLibCheck (already in the shared base config) and noEmit
(now passed as a CLI flag), so it was redundant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Convert the Chat route's component and container modules from JS to TS.

Add @types/emoji-mart (pinned to ~3.0.14 to match emoji-mart@3; the v5
line is a deprecated stub) so the lazy-loaded Picker and its onSelect
EmojiData are properly typed. The real types surfaced that `native`
only exists on BaseEmoji, so the emoji-select handler now narrows before
reading it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Convert main, room, threads, triggers and uiKit under src/lib from JS to
TS. Add the store fields these modules use at runtime but that were
missing from StoreState (config.settings.clearLocalStorageWhenChatEnded,
config.settings.agentHiddenInfo, parentMessages, triggersRecords) and
widen `room` to allow `servedBy` and `null`.

Message payloads stay `any`, matching the store's existing convention,
and the strongly-typed SDK calls (config, loadMessages, message,
sendUiInteraction) are cast at the boundary since their REST-derived
param types are stricter than the loose runtime usage.

A few latent bugs surfaced by the type checker were fixed and flagged
(trigger record key `id` -> `_id`, always-false `_isValid` comparison,
`MODAL_ClOSE` typo); the no-op async `filter` in normalizeMessages was
left as-is behind a FIXME to avoid changing message normalization.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Type the Sound component's props and audio ref. Drop the `type` attribute
from the <audio> element (it is only meaningful on <source>, so the
browser ignored it) to satisfy the JSX types.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…cript

Convert the two remaining JS modules under components/Messages (Message
and MessageList) to TSX. Message payloads stay `any`, matching the
store's convention.

Declare the props that sibling components already forward via spread but
did not type: `quoted` on Image/FileAttachment and `use` on
TypingIndicator. `avatarResolver` is passed with a `() => undefined`
fallback where those components type it as required (they have the same
runtime default).

The original passed `inverse={me}` to MessageTime, which only reads
`inverted` — so it was a no-op; dropped rather than enabling the
timestamp styling, to keep rendering identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the repo-root postcss.config.js into packages/livechat (its only
consumer) so it no longer acts as a global default for other PostCSS
consumers. Drop the postcss-css-variables plugin (and dependency): all
browsers in livechat's browserslist support CSS custom properties
natively, so build-time var() fallbacks are unnecessary. This also
removes the "variable ... is undefined and used without a fallback"
warnings emitted for third-party CSS during the build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dionisio-bot

dionisio-bot Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot

changeset-bot Bot commented Jul 24, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 4652436

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2732b545-f48f-4280-986c-677d6140fbc4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@codecov

codecov Bot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 68.71%. Comparing base (6dc66fb) to head (4652436).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #41559      +/-   ##
===========================================
+ Coverage    68.69%   68.71%   +0.01%     
===========================================
  Files         4139     4139              
  Lines       159112   159112              
  Branches     27917    27910       -7     
===========================================
+ Hits        109300   109328      +28     
+ Misses       44666    44641      -25     
+ Partials      5146     5143       -3     
Flag Coverage Δ
e2e 58.81% <ø> (-0.02%) ⬇️
e2e-api 45.89% <ø> (+0.27%) ⬆️
unit 70.65% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

tassoevan and others added 6 commits July 26, 2026 19:32
Storybook's preview build failed with "Reading from node:stream is not
handled by plugins". The config already stubs core modules via
resolve.fallback (stream: false), but that only matches the bare
specifier -- webpack 5 treats the node:-prefixed form as an unhandled
URI scheme. Strip the node: prefix in webpackFinal so those imports
(reached through the preact react-dom/server shim) hit the existing
fallbacks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the withTranslation class component with a function component
using useTranslation/useContext/useRef, and simplify the container to
useStore(), dropping the now-unused agent/unread/theme/formatAgent/ref
plumbing. Stories updated to the new handleChatStartClick prop.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Switch SwitchDepartment to the useStore() hook (dropping the manual
useContext(StoreContext) and the now-unneeded StoreState casts) and make
its route `path` prop optional. Update the story to inject config
(departments) and loading through the shared storeDecorator instead of
passing props the component ignores.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reference the exported RegisterProps type directly instead of deriving it
via ComponentProps<typeof Register>.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hoist the form values into a named LeaveMessageFormValues type and pass
it to useForm, which lets the submit handler drop the
`as unknown as JSXInternal.GenericEventHandler` cast. Make the route
`path` optional and reference LeaveMessageProps directly in the story.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ponent

Merge the GDPRAgreement component/container/index into one function
component that uses useTranslation and useStore, dropping the
withTranslation HOC. Behavior is unchanged: the container never passed
`instructions`, so the Trans fallback was always rendered. Story now
references GDPRAgreementProps and drops the props the component ignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tassoevan
tassoevan force-pushed the refactor/livechat-js branch from 92af50f to 2e1682a Compare July 26, 2026 22:37
…onent

Merge the ChatFinished component/container/index into one function
component that uses useTranslation and useStore (dropping the
withTranslation HOC and the separate container). Behavior is unchanged.
Story now injects the finished-conversation messages through the shared
storeDecorator instead of passing props the component no longer takes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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