Skip to content

feat: narrow Wealth Management app and Symphony host integration#45

Open
mistryvinay wants to merge 3 commits intomasterfrom
wealth-management-clean-pr
Open

feat: narrow Wealth Management app and Symphony host integration#45
mistryvinay wants to merge 3 commits intomasterfrom
wealth-management-clean-pr

Conversation

@mistryvinay
Copy link
Copy Markdown
Collaborator

@mistryvinay mistryvinay commented Mar 23, 2026

Summary

  • move the Wealth Management feature into a single clean PR branch with one commit
  • keep the Wealth Management dashboard, contacts, client detail, Symphony shared chat, embedded client host, theme bridge, notification wiring, and Wealth-scoped UI primitives together in this replacement branch
  • include the follow-up fixes already applied after review: centralized debug logging, unread listener cleanup, stronger segment typing, and accessible Wealth-specific menu and sheet behavior

Validation

  • npm test -- --runInBand --watch=false
  • npm run build

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 23, 2026

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

Project Deployment Actions Updated (UTC)
clever-deal Ready Ready Preview, Comment Mar 24, 2026 4:42pm

Copy link
Copy Markdown

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 narrowed, self-contained Wealth Management mini-app in CleverDeal.React, including a dedicated /wealth-management/* route, Tailwind-scoped UI primitives, and a more robust Symphony embed/theme/unread-notification integration.

Changes:

  • Adds the Wealth Management mini-app (dashboard, contacts, client detail, shared + embedded chat shells, and UI primitives) behind a lazy-loaded route.
  • Centralizes Symphony theme updates via a shared symphonyThemeBridge with ownership semantics + tests.
  • Implements Symphony embed operational hardening: SDK wrapper, unread notification service, layout/theme re-apply logic, and an embedded client chat host page.

Reviewed changes

Copilot reviewed 53 out of 63 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
AppExamples/CleverDeal.React/tsconfig.json Updates TS include/exclude patterns for the React app.
AppExamples/CleverDeal.React/tailwind.config.js Adds Tailwind configuration scoped to src with Preflight disabled.
AppExamples/CleverDeal.React/src/index.tsx Adds lazy-loaded /wealth-management/* route and dev error filtering.
AppExamples/CleverDeal.React/src/Theme/symphonyThemeBridge.ts Adds theme bridge to coordinate global vs route-owned Symphony theme updates.
AppExamples/CleverDeal.React/src/Theme/symphonyThemeBridge.test.ts Tests theme ownership + restore behavior for the theme bridge.
AppExamples/CleverDeal.React/src/Theme/ThemeProvider.tsx Routes Symphony theme updates through the new theme bridge.
AppExamples/CleverDeal.React/src/Theme/ThemeProvider.test.tsx Tests that ThemeProvider uses the theme bridge.
AppExamples/CleverDeal.React/src/Data/routes.ts Extends route metadata to support “enabled/coming soon” entries (incl. Wealth Management).
AppExamples/CleverDeal.React/src/Components/WealthManagement/ui/utils.ts Adds cn utility for class merging.
AppExamples/CleverDeal.React/src/Components/WealthManagement/ui/table.tsx Adds Wealth-scoped table primitives.
AppExamples/CleverDeal.React/src/Components/WealthManagement/ui/sheet.tsx Adds accessible sheet/drawer primitive for Wealth UI.
AppExamples/CleverDeal.React/src/Components/WealthManagement/ui/dropdown-menu.tsx Adds accessible dropdown menu primitives for Wealth UI.
AppExamples/CleverDeal.React/src/Components/WealthManagement/ui/card.tsx Adds Wealth card primitives.
AppExamples/CleverDeal.React/src/Components/WealthManagement/ui/calendar.tsx Adds Wealth calendar component.
AppExamples/CleverDeal.React/src/Components/WealthManagement/ui/button.tsx Adds Wealth button primitive with variants/sizes.
AppExamples/CleverDeal.React/src/Components/WealthManagement/ui/badge.tsx Adds Wealth badge primitive with variants.
AppExamples/CleverDeal.React/src/Components/WealthManagement/ui/avatar.tsx Adds Wealth avatar primitives with load/fallback state handling.
AppExamples/CleverDeal.React/src/Components/WealthManagement/ui/avatar.test.tsx Tests avatar fallback behavior for load/error.
AppExamples/CleverDeal.React/src/Components/WealthManagement/styles/wealthManagement.css Adds Tailwind components/utilities stylesheet scoped to Wealth app.
AppExamples/CleverDeal.React/src/Components/WealthManagement/pages/ModulePlaceholderPage.tsx Adds placeholder page for future Wealth modules.
AppExamples/CleverDeal.React/src/Components/WealthManagement/pages/ContactsPage.tsx Implements Wealth contacts list with filters, KPIs, and unread indicators.
AppExamples/CleverDeal.React/src/Components/WealthManagement/pages/ClientDetailPage.tsx Implements client profile page with embedded client chat host + document sharing flow.
AppExamples/CleverDeal.React/src/Components/WealthManagement/pages/ClientDetailPage.test.tsx Tests document-share request tracking and stale-message handling.
AppExamples/CleverDeal.React/src/Components/WealthManagement/models/WealthManagementData.ts Adds typed Wealth data model (contacts, dashboard, activity, etc.).
AppExamples/CleverDeal.React/src/Components/WealthManagement/index.ts Adds module entrypoint exports for lazy loading.
AppExamples/CleverDeal.React/src/Components/WealthManagement/data/wealthManagementShell.ts Adds shell data used for embedded-client chat mapping.
AppExamples/CleverDeal.React/src/Components/WealthManagement/data/wealthManagement.ts Adds Wealth demo dataset (contacts, dashboard, PDF data URI, etc.).
AppExamples/CleverDeal.React/src/Components/WealthManagement/components/SymphonyMark.tsx Adds Symphony mark asset component for Wealth UI.
AppExamples/CleverDeal.React/src/Components/WealthManagement/components/SymphonyChatShell.tsx Adds shared/embedded chat shell for page/drawer contexts.
AppExamples/CleverDeal.React/src/Components/WealthManagement/components/ChatLoadingOverlay.tsx Adds loading overlay for chat readiness/masking states.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/wealthSymphonyTheme.ts Defines Wealth-specific Symphony theme + render options + reapply helpers.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/wealthSymphonyTheme.test.ts Tests Wealth theme tokens and refresh behavior.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/wealthDebug.ts Adds Wealth debug-flag utilities + centralized debug logger.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useSharedWealthChatController.ts Adds controller for shared chat bootstrap + stream switching + retries.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useSharedWealthChatController.test.tsx Tests shared chat bootstrap, switching, and retry behavior.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useSharedChatPresentationTransition.ts Adds masking + layout-settle logic to refresh theme after UI transitions.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useSharedChatPresentationTransition.test.tsx Tests masking/refresh sequencing for transitions and visibility changes.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useEmbeddedClientChatHost.ts Adds hook to build host URL, track readiness, and clear unread on ready.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useEmbeddedClientChatHost.test.tsx Tests URL building, message filtering by origin/source, and stale-stream handling.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useEcpSlot.ts Adds slot hook to track ECP readiness/errors and cleanup container on unmount.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/symphonySdk.ts Adds SDK service wrapper for script init, render, openStream, and iframe readiness tracking.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/symphonySdk.test.ts Tests SDK wrapper rendering semantics, iframe readiness, and error reset behavior.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/symphonyNotifications.ts Adds notification service for unread counts, per-stream tracking, debug snapshotting, and retries.
AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/symphonyNotifications.test.ts Tests unread counting, baseline behavior, per-stream clearing, and retry init.
AppExamples/CleverDeal.React/src/Components/WealthManagement/WealthManagement.test.tsx Integration-style tests for Wealth routes, chat drawer/page behavior, and notifications UI.
AppExamples/CleverDeal.React/src/Components/LandingPage/LandingPage.tsx Updates tile enablement logic to use enabled flag when provided.
AppExamples/CleverDeal.React/src/Components/CleverResearch/CleverResearch.scss Scopes selectors under .research-modal to avoid style leakage.
AppExamples/CleverDeal.React/public/wealth-client-chat-host.html Adds same-origin host page that embeds Symphony and mediates document-share actions via postMessage.
AppExamples/CleverDeal.React/public/index.html Adds early error listener intended to suppress cross-origin “Script error.” from Symphony iframe.
AppExamples/CleverDeal.React/postcss.config.js Adds PostCSS config to enable Tailwind + Autoprefixer.
AppExamples/CleverDeal.React/package.json Adds Tailwind/PostCSS toolchain deps and @tanstack/react-table.
.gitignore Ignores .vscode directory.

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

Comment on lines +35 to +41
if (!document.getElementById('symphony-ecm')) {
return;
}

window.addEventListener(
'error',
function (e) {
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The guard if (!document.getElementById('symphony-ecm')) return; runs in the <head> before the <body> is parsed, so it will always early-return and the error listener won’t be registered. This means cross-origin "Script error." events from the Symphony iframe will still reach CRA’s overlay.

Fix by registering the listener unconditionally, or by moving the element-presence check into the handler (check at error time rather than at script-eval time).

Suggested change
if (!document.getElementById('symphony-ecm')) {
return;
}
window.addEventListener(
'error',
function (e) {
window.addEventListener(
'error',
function (e) {
if (!document.getElementById('symphony-ecm')) {
return;
}

Copilot uses AI. Check for mistakes.
Comment on lines 23 to +29
"include": [
"src"
"src/**/*"
],
"exclude": [
"build",
"src/**/*.test.ts",
"src/**/*.test.tsx"
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

tsconfig.json now excludes src/**/*.test.ts(x), which prevents TypeScript type-checking of the newly added test suite during npm run build / IDE TS checks. If the intention is only to avoid emitting tests, consider keeping tests included (since noEmit is already set) or adding a separate tsconfig.test.json for Jest rather than excluding them entirely.

Copilot uses AI. Check for mistakes.
@Yannick-Malins
Copy link
Copy Markdown
Contributor

if you look at your yarn lockfile, you're introducing dependencies on artefacts in repo.symphony.com , which shouldn't be necessary for an external project like this. that's why vercel can'y build it

Copy link
Copy Markdown

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 54 out of 64 changed files in this pull request and generated 3 comments.


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

Comment on lines +35 to +38
if (!document.getElementById('symphony-ecm')) {
return;
}

Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

The guard if (!document.getElementById('symphony-ecm')) return; runs while the script is executing in <head>, before the <div id="symphony-ecm"> in <body> has been parsed. As a result, the error listener is never registered and cross-origin "Script error." events will not be suppressed as intended. Consider removing the DOM check entirely, or deferring this setup until after DOMContentLoaded (or by placing the script after the symphony-ecm element).

Suggested change
if (!document.getElementById('symphony-ecm')) {
return;
}

Copilot uses AI. Check for mistakes.
Comment on lines +32 to +38
const query = new URLSearchParams(window.location.search);
const ecpOrigin = query.get('ecpOrigin') || DEFAULT_ORIGIN;
const partnerId = query.get('partnerId');
const mode = query.get('mode') || 'light';
const theme = query.get('theme');
const podUrl = 'https://' + ecpOrigin;
const initialStreamId = query.get('streamId');
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

ecpOrigin is taken directly from the query string and used to construct podUrl/iframe URLs (e.g. https://${ecpOrigin}/embed/index.html). This allows embedding arbitrary remote origins and is effectively a client-side SSRF / script-inclusion vector if this page is reachable with attacker-controlled params. Please validate ecpOrigin against a strict allowlist (e.g. the known Symphony pods) before using it, and fall back to DEFAULT_ORIGIN when invalid.

Copilot uses AI. Check for mistakes.
Comment on lines +88 to +92
const handleClickOutside = (event: MouseEvent) => {
if (wrapperRef.current && !wrapperRef.current.contains(event.target as Node)) {
setOpen(false);
}
};
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

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

When the menu closes via an outside click, focus is not restored to the trigger element. This can leave keyboard/screen-reader users without a clear focus target after dismissal. Consider calling triggerRef.current?.focus() when closing from handleClickOutside (and similarly for any other non-item close paths).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants