feat: narrow Wealth Management app and Symphony host integration#45
feat: narrow Wealth Management app and Symphony host integration#45mistryvinay wants to merge 3 commits intomasterfrom
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
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
symphonyThemeBridgewith 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.
| if (!document.getElementById('symphony-ecm')) { | ||
| return; | ||
| } | ||
|
|
||
| window.addEventListener( | ||
| 'error', | ||
| function (e) { |
There was a problem hiding this comment.
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).
| if (!document.getElementById('symphony-ecm')) { | |
| return; | |
| } | |
| window.addEventListener( | |
| 'error', | |
| function (e) { | |
| window.addEventListener( | |
| 'error', | |
| function (e) { | |
| if (!document.getElementById('symphony-ecm')) { | |
| return; | |
| } |
| "include": [ | ||
| "src" | ||
| "src/**/*" | ||
| ], | ||
| "exclude": [ | ||
| "build", | ||
| "src/**/*.test.ts", | ||
| "src/**/*.test.tsx" |
There was a problem hiding this comment.
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.
|
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 |
There was a problem hiding this comment.
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.
| if (!document.getElementById('symphony-ecm')) { | ||
| return; | ||
| } | ||
|
|
There was a problem hiding this comment.
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).
| if (!document.getElementById('symphony-ecm')) { | |
| return; | |
| } |
| 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'); |
There was a problem hiding this comment.
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.
| const handleClickOutside = (event: MouseEvent) => { | ||
| if (wrapperRef.current && !wrapperRef.current.contains(event.target as Node)) { | ||
| setOpen(false); | ||
| } | ||
| }; |
There was a problem hiding this comment.
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).
Summary
Validation