feat: narrow Wealth Management app and Symphony host integration#44
feat: narrow Wealth Management app and Symphony host integration#44mistryvinay wants to merge 2 commits intomasterfrom
Conversation
- add the Wealth Management dashboard, contacts, and client detail flows with supporting data models, assets, and route updates - embed the Symphony client chat host with shared shell controls, theme bridging, unread notifications, and bootstrap improvements - add UI primitives, Tailwind/PostCSS setup, and test coverage for Wealth Management, chat integration, and theming
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Adds a new Wealth Management mini-app experience inside CleverDeal.React, including a client dashboard/contacts/client detail flow, plus an embedded Symphony chat integration with shared theming/notifications and supporting UI primitives + Tailwind/PostCSS setup.
Changes:
- Introduces the Wealth Management routes/pages and supporting data models + shell data.
- Adds Symphony chat embedding (shared chat + client chat host), notification tracking, and a theme ownership bridge.
- Adds Tailwind/PostCSS configuration and a small set of reusable UI primitives with accompanying tests.
Reviewed changes
Copilot reviewed 59 out of 68 changed files in this pull request and generated 12 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 config (content paths, theme extensions, preflight disabled). |
| AppExamples/CleverDeal.React/src/index.tsx | Adds lazy-loaded Wealth Management route + dev error filtering for ResizeObserver loop. |
| AppExamples/CleverDeal.React/src/Theme/symphonyThemeBridge.ts | Adds theme bridge to coordinate global vs route-owned Symphony themes. |
| AppExamples/CleverDeal.React/src/Theme/symphonyThemeBridge.test.ts | Unit tests for the Symphony theme bridge ownership behavior. |
| AppExamples/CleverDeal.React/src/Theme/ThemeProvider.tsx | Routes Symphony theme updates through the shared theme bridge. |
| AppExamples/CleverDeal.React/src/Theme/ThemeProvider.test.tsx | Tests ThemeProvider calls the theme bridge correctly. |
| AppExamples/CleverDeal.React/src/Models/WealthManagementData.ts | Adds Wealth Management data model types and constants. |
| AppExamples/CleverDeal.React/src/Data/wealthManagementShell.ts | Adds lightweight shell data for room/contact stream IDs + avatars. |
| AppExamples/CleverDeal.React/src/Data/wealthManagement.ts | Adds demo Wealth Management dataset (dashboard, clients, PDFs, etc.). |
| AppExamples/CleverDeal.React/src/Data/routes.ts | Adds “Wealth Management” entry for landing page tiles. |
| AppExamples/CleverDeal.React/src/Components/ui/utils.ts | Adds cn helper for className composition. |
| AppExamples/CleverDeal.React/src/Components/ui/tabs.tsx | Adds a Tabs UI primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/table.tsx | Adds Table UI primitives. |
| AppExamples/CleverDeal.React/src/Components/ui/sheet.tsx | Adds Sheet (drawer/modal-like) UI primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/separator.tsx | Adds Separator UI primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/scroll-area.tsx | Adds ScrollArea UI primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/resizable.tsx | Adds basic resizable panel group primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/menubar.tsx | Adds Menubar UI primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/input.tsx | Adds Input UI primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/dropdown-menu.tsx | Adds DropdownMenu UI primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/card.tsx | Adds Card UI primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/calendar.tsx | Adds Calendar UI primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/button.tsx | Adds Button UI primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/badge.tsx | Adds Badge UI primitive. |
| AppExamples/CleverDeal.React/src/Components/ui/avatar.tsx | Adds Avatar UI primitive with image/fallback handling. |
| AppExamples/CleverDeal.React/src/Components/ui/avatar.test.tsx | Tests Avatar fallback vs loaded state behavior. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/styles/wealthManagement.css | Adds Tailwind entry CSS for Wealth Management-only styling. |
| 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 | Adds client list (table + filters) and chat-launch integration. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/pages/ClientDetailPage.tsx | Adds client profile page with embedded client chat + document share flow. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/pages/ClientDetailPage.test.tsx | Tests client document share sequencing + error handling. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/index.ts | Exports WealthManagement module entrypoints. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/components/SymphonyMark.tsx | Adds Symphony logo mark component. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/components/SymphonyChatShell.tsx | Adds shared shell wrapper around embedded Symphony chat experiences. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/components/ChatLoadingOverlay.tsx | Adds loading overlay used during chat bootstrapping/masking. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/wealthSymphonyTheme.ts | Defines Wealth Symphony theme + ownership helpers + settle/reapply logic. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/wealthSymphonyTheme.test.ts | Tests Wealth theme payload/serialization + refresh behavior. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useSharedWealthChatController.ts | Adds shared chat bootstrap + stream switching controller with retries. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useSharedWealthChatController.test.tsx | Tests shared chat controller bootstrap/switch + retry behavior. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useSharedChatPresentationTransition.ts | Adds masking/refresh behavior when shared chat layout changes. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useSharedChatPresentationTransition.test.tsx | Tests masking/refresh behavior across mode/visibility transitions. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useEmbeddedClientChatHost.ts | Adds client chat host iframe URL + readiness/error message handling. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useEmbeddedClientChatHost.test.tsx | Tests host URL building + ready/error message filtering. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/useEcpSlot.ts | Adds hook to manage/cleanup a Symphony ECP slot container. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/symphonySdk.ts | Adds SDK service for script loading, rendering, stream switching, error recovery. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/symphonySdk.test.ts | Tests SDK service behaviors (init/render/openStream/error/reset). |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/symphonyNotifications.ts | Adds notification listener service (global + per-stream unread + debug). |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/chat/symphonyNotifications.test.ts | Tests notification baselines/fallback behavior + per-stream tracking. |
| AppExamples/CleverDeal.React/src/Components/WealthManagement/WealthManagement.test.tsx | Integration-style tests for Wealth Management flows and chat UI. |
| AppExamples/CleverDeal.React/src/Components/LandingPage/LandingPage.tsx | Adds enabled support for tiles and “Coming Soon” rendering logic. |
| AppExamples/CleverDeal.React/src/Components/CleverResearch/CleverResearch.scss | Scopes research modal styles under .research-modal. |
| AppExamples/CleverDeal.React/public/wealth-client-chat-host.html | Adds standalone host page that embeds Symphony and proxies share actions. |
| AppExamples/CleverDeal.React/public/index.html | Adds early “Script error” suppression for Symphony SDK iframe noise. |
| AppExamples/CleverDeal.React/postcss.config.js | Adds PostCSS plugins for Tailwind + autoprefixer. |
| AppExamples/CleverDeal.React/package.json | Adds dependencies/devDependencies for Wealth UI + Tailwind. |
| .vscode/settings.json | Adds Snyk VS Code configuration. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const WEALTH_DEBUG_STORAGE_KEY = 'wealthDebugTheme'; | ||
|
|
||
| function isWealthThemeDebugEnabled() { |
There was a problem hiding this comment.
isWealthThemeDebugEnabled and the storage key are duplicated here and in Theme/symphonyThemeBridge.ts. Consider centralizing this debug-flag logic in a shared helper to avoid drift between implementations.
| const WEALTH_DEBUG_STORAGE_KEY = 'wealthDebugTheme'; | |
| function isWealthThemeDebugEnabled() { | |
| export const WEALTH_DEBUG_STORAGE_KEY = 'wealthDebugTheme'; | |
| export function isWealthThemeDebugEnabled() { |
| const contacts = useMemo(() => wealthManagementData.contacts ?? [], []); | ||
|
|
||
| useEffect(() => symphonyNotifications.onStreamUnreadChange(setStreamUnreadCounts), []); | ||
| const filteredContacts = useMemo( |
There was a problem hiding this comment.
onStreamUnreadChange returns an unsubscribe function, but this effect doesn't return it, so the stream unread listener will stay registered after the page unmounts (leak + duplicate updates on remount). Return the cleanup function from useEffect.
| function debugDocumentShare(message: string, context?: Record<string, unknown>) { | ||
| if (context) { | ||
| console.debug(`[WealthClientShare] ${message}`, context); | ||
| return; | ||
| } | ||
|
|
||
| console.debug(`[WealthClientShare] ${message}`); | ||
| } |
There was a problem hiding this comment.
debugDocumentShare logs to console.debug unconditionally. If this runs in production it will add noisy logs for every host message / share action. Consider gating this behind the existing wealth debug flag (query/localStorage) or NODE_ENV !== 'production' like other debug helpers in this PR.
| export type ContactSegment = 'UHNW' | 'HNW' | 'Retail'; | ||
|
|
||
| export const SEGMENT_STYLES: Record<string, string> = { | ||
| UHNW: 'bg-rose-600 text-white', | ||
| HNW: 'bg-violet-600 text-white', | ||
| Retail: 'bg-slate-600 text-white', | ||
| }; |
There was a problem hiding this comment.
SEGMENT_STYLES is typed as Record<string, string>, which loses type-safety and allows invalid segment keys at compile time. Since ContactSegment is declared just above, use Record<ContactSegment, string> (and optionally export it as such) so additions/removals are type-checked.
| "@radix-ui/react-dialog": "^1.1.14", | ||
| "@radix-ui/react-dropdown-menu": "^2.1.15", | ||
| "@radix-ui/react-menubar": "^1.1.15", | ||
| "@radix-ui/react-scroll-area": "^1.2.10", |
There was a problem hiding this comment.
These Radix UI packages are added as dependencies but there are no imports/usages in src/ (at least in this PR). If they're not needed yet, remove them to avoid extra install/bundle surface; otherwise add the intended usage so the dependency is justified.
| "@radix-ui/react-dialog": "^1.1.14", | |
| "@radix-ui/react-dropdown-menu": "^2.1.15", | |
| "@radix-ui/react-menubar": "^1.1.15", | |
| "@radix-ui/react-scroll-area": "^1.2.10", |
.vscode/settings.json
Outdated
| "snyk.advanced.organization": "c9d28c43-bb57-4687-8398-f2cd3e94ab31", | ||
| "snyk.advanced.autoSelectOrganization": true |
There was a problem hiding this comment.
Committing workspace-specific .vscode/settings.json with a fixed Snyk organization ID makes the repo configuration developer/tooling-specific and may unintentionally expose internal identifiers. Consider removing this file from the PR and using documented setup steps (or .vscode/settings.json via local-only tooling) instead.
| "snyk.advanced.organization": "c9d28c43-bb57-4687-8398-f2cd3e94ab31", | |
| "snyk.advanced.autoSelectOrganization": true |
| window.addEventListener('error', function(e) { | ||
| if (e.message === 'Script error.' || e.message === 'Script error') { | ||
| e.stopImmediatePropagation(); | ||
| e.preventDefault(); | ||
| } | ||
| }, true); |
There was a problem hiding this comment.
This global capture listener suppresses all cross-origin "Script error" events for the entire app. That can mask real production issues from other third-party scripts and makes debugging harder. Consider scoping this suppression more narrowly (e.g., only when the Symphony embed is present, checking e.filename/e.target/known iframe, or gating behind a URL flag) rather than blanket suppression.
| window.addEventListener('error', function(e) { | |
| if (e.message === 'Script error.' || e.message === 'Script error') { | |
| e.stopImmediatePropagation(); | |
| e.preventDefault(); | |
| } | |
| }, true); | |
| (function () { | |
| // Only register this handler when the Symphony container is present, | |
| // and only suppress generic cross-origin-style "Script error" events. | |
| if (!document.getElementById('symphony-ecm')) { | |
| return; | |
| } | |
| window.addEventListener( | |
| 'error', | |
| function (e) { | |
| // Cross-origin "Script error" typically has an empty filename. | |
| if ( | |
| (e.message === 'Script error.' || e.message === 'Script error') && | |
| e.filename === '' | |
| ) { | |
| e.stopImmediatePropagation(); | |
| e.preventDefault(); | |
| } | |
| }, | |
| true | |
| ); | |
| })(); |
| }: { | ||
| title: string; | ||
| headerContent?: React.ReactNode; | ||
| bodyClassName?: string; | ||
| className?: string; | ||
| children: React.ReactNode; | ||
| }) { |
There was a problem hiding this comment.
This file references React.ReactNode in prop types, but React is not imported (only named hooks are imported from react). This will fail TypeScript compilation. Import type ReactNode (or type React) from react and use that instead.
| return ( | ||
| <> | ||
| <div className="fixed inset-0 z-50 bg-slate-950/50" onClick={() => setOpen(false)} /> | ||
| <div | ||
| className={cn( | ||
| 'fixed top-0 z-50 h-full w-[320px] border-slate-200 bg-white shadow-2xl', | ||
| side === 'left' ? 'left-0 border-r' : 'right-0 border-l', | ||
| className, | ||
| )} |
There was a problem hiding this comment.
SheetContent renders a modal-like surface but doesn't expose dialog semantics or keyboard handling (e.g., role="dialog", aria-modal, labelling, Escape-to-close) and doesn't manage focus when opened/closed. This will be difficult for keyboard/screen-reader users. Consider adding the appropriate ARIA attributes + focus management (or using an accessible dialog primitive).
| export function DropdownMenu({ children }: { children: ReactNode }) { | ||
| const [open, setOpen] = useState(false); | ||
| const ref = useRef<HTMLDivElement>(null); | ||
|
|
||
| useEffect(() => { | ||
| if (!open) return; | ||
|
|
||
| const handleClickOutside = (event: MouseEvent) => { | ||
| if (ref.current && !ref.current.contains(event.target as Node)) { | ||
| setOpen(false); | ||
| } | ||
| }; | ||
|
|
||
| document.addEventListener('mousedown', handleClickOutside); | ||
| return () => document.removeEventListener('mousedown', handleClickOutside); | ||
| }, [open]); | ||
|
|
||
| const value = useMemo(() => ({ open, setOpen }), [open]); | ||
|
|
||
| return ( | ||
| <MenuContext.Provider value={value}> | ||
| <div ref={ref} className="relative inline-flex"> | ||
| {children} | ||
| </div> | ||
| </MenuContext.Provider> | ||
| ); |
There was a problem hiding this comment.
This dropdown implementation is click-only: it doesn't apply menu ARIA roles, keyboard navigation (Arrow keys/Enter/Escape), or focus management when opening/closing. If this is meant as a shared UI primitive, consider adding those behaviors/attributes or using an accessible menu component.
|
DO NOT MERGE. |
|
Superseded by #45, which carries the same feature work on a fresh one-commit branch without the leaked workspace settings history. |
Summary
Validation