Initial BlackRoad OS Hub - Meta-CRM Platform
## Hub Layer - Connected_CRM__c: Manage multiple CRM instances - CRM_Product__c: CRM product templates ## Financial Advisor CRM - Client_Household__c: Unified household view - Financial_Account__c: IRA, brokerage, annuity tracking - Distribution_Request__c: Withdrawal workflows - Mortality_Event__c: Estate processing - Liquidity_Event__c: Business sales, large transfers - Compliance_Log__c: FINRA audit trail ## Components - BlackRoadHubController: Hub dashboard controller - FinancialAdvisorService: FA business logic - blackroadHubDashboard: Lightning Web Component - BlackRoad Hub app with all tabs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
.blackroad-header {
|
||||
background: linear-gradient(135deg, #000000 0%, #1a1a2e 100%);
|
||||
color: white;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.blackroad-header .slds-page-header__title {
|
||||
color: #F5A623;
|
||||
}
|
||||
|
||||
.blackroad-header .slds-page-header__meta-text {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 2.5rem;
|
||||
font-weight: bold;
|
||||
color: #F5A623;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.875rem;
|
||||
color: #706e6b;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
lightning-card {
|
||||
--slds-c-card-radius-border: 8px;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div class="slds-page-header blackroad-header">
|
||||
<div class="slds-page-header__row">
|
||||
<div class="slds-page-header__col-title">
|
||||
<div class="slds-media">
|
||||
<div class="slds-media__figure">
|
||||
<lightning-icon icon-name="custom:custom9" size="large"></lightning-icon>
|
||||
</div>
|
||||
<div class="slds-media__body">
|
||||
<h1 class="slds-page-header__title">BlackRoad OS Hub</h1>
|
||||
<p class="slds-page-header__meta-text">CRM Command Center</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stats Cards -->
|
||||
<div class="slds-grid slds-gutters slds-m-top_medium">
|
||||
<div class="slds-col slds-size_1-of-4">
|
||||
<lightning-card title="Connected CRMs" icon-name="standard:connected_apps">
|
||||
<div class="slds-p-horizontal_medium">
|
||||
<p class="stat-number">{stats.activeCRMs} / {stats.totalCRMs}</p>
|
||||
<p class="stat-label">Active</p>
|
||||
</div>
|
||||
</lightning-card>
|
||||
</div>
|
||||
<div class="slds-col slds-size_1-of-4">
|
||||
<lightning-card title="Total Households" icon-name="standard:household">
|
||||
<div class="slds-p-horizontal_medium">
|
||||
<p class="stat-number">{stats.totalHouseholds}</p>
|
||||
<p class="stat-label">Client Households</p>
|
||||
</div>
|
||||
</lightning-card>
|
||||
</div>
|
||||
<div class="slds-col slds-size_1-of-4">
|
||||
<lightning-card title="Total AUM" icon-name="standard:currency">
|
||||
<div class="slds-p-horizontal_medium">
|
||||
<p class="stat-number">{formattedAUM}</p>
|
||||
<p class="stat-label">Assets Under Management</p>
|
||||
</div>
|
||||
</lightning-card>
|
||||
</div>
|
||||
<div class="slds-col slds-size_1-of-4">
|
||||
<lightning-card title="Pending Actions" icon-name="standard:task">
|
||||
<div class="slds-p-horizontal_medium">
|
||||
<p class="stat-number">{totalPending}</p>
|
||||
<p class="stat-label">Distributions / Events</p>
|
||||
</div>
|
||||
</lightning-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Grid -->
|
||||
<div class="slds-grid slds-gutters slds-m-top_medium">
|
||||
<!-- Connected CRMs -->
|
||||
<div class="slds-col slds-size_1-of-2">
|
||||
<lightning-card title="Connected CRMs" icon-name="standard:connected_apps">
|
||||
<lightning-button slot="actions" label="Add CRM" onclick={handleAddCRM}></lightning-button>
|
||||
<template if:true={connectedCRMs}>
|
||||
<lightning-datatable
|
||||
key-field="Id"
|
||||
data={connectedCRMs}
|
||||
columns={crmColumns}
|
||||
hide-checkbox-column
|
||||
onrowaction={handleCRMAction}>
|
||||
</lightning-datatable>
|
||||
</template>
|
||||
<template if:false={connectedCRMs}>
|
||||
<div class="slds-p-around_medium slds-text-align_center">
|
||||
<p>No CRMs connected yet.</p>
|
||||
</div>
|
||||
</template>
|
||||
</lightning-card>
|
||||
</div>
|
||||
|
||||
<!-- CRM Products -->
|
||||
<div class="slds-col slds-size_1-of-2">
|
||||
<lightning-card title="CRM Products" icon-name="standard:product">
|
||||
<template if:true={crmProducts}>
|
||||
<ul class="slds-has-dividers_bottom-space">
|
||||
<template for:each={crmProducts} for:item="product">
|
||||
<li key={product.Id} class="slds-item slds-p-around_small">
|
||||
<div class="slds-grid slds-grid_vertical-align-center">
|
||||
<div class="slds-col slds-grow">
|
||||
<p class="slds-text-heading_small">{product.Name}</p>
|
||||
<p class="slds-text-body_small slds-text-color_weak">{product.Target_Vertical__c}</p>
|
||||
</div>
|
||||
<div class="slds-col">
|
||||
<lightning-badge label={product.Version__c}></lightning-badge>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</template>
|
||||
</lightning-card>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Households Needing Attention -->
|
||||
<div class="slds-m-top_medium">
|
||||
<lightning-card title="Households Needing Attention" icon-name="standard:warning">
|
||||
<template if:true={householdsNeedingAttention}>
|
||||
<lightning-datatable
|
||||
key-field="Id"
|
||||
data={householdsNeedingAttention}
|
||||
columns={householdColumns}
|
||||
hide-checkbox-column
|
||||
onrowaction={handleHouseholdAction}>
|
||||
</lightning-datatable>
|
||||
</template>
|
||||
</lightning-card>
|
||||
</div>
|
||||
|
||||
<!-- Recent Compliance Activity -->
|
||||
<div class="slds-m-top_medium">
|
||||
<lightning-card title="Recent Compliance Activity" icon-name="standard:logging">
|
||||
<template if:true={complianceLogs}>
|
||||
<lightning-datatable
|
||||
key-field="Id"
|
||||
data={complianceLogs}
|
||||
columns={logColumns}
|
||||
hide-checkbox-column>
|
||||
</lightning-datatable>
|
||||
</template>
|
||||
</lightning-card>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,179 @@
|
||||
import { LightningElement, wire, track } from 'lwc';
|
||||
import { NavigationMixin } from 'lightning/navigation';
|
||||
import getConnectedCRMs from '@salesforce/apex/BlackRoadHubController.getConnectedCRMs';
|
||||
import getCRMProducts from '@salesforce/apex/BlackRoadHubController.getCRMProducts';
|
||||
import getHubStats from '@salesforce/apex/BlackRoadHubController.getHubStats';
|
||||
import getHouseholdsNeedingAttention from '@salesforce/apex/BlackRoadHubController.getHouseholdsNeedingAttention';
|
||||
import getRecentComplianceLogs from '@salesforce/apex/BlackRoadHubController.getRecentComplianceLogs';
|
||||
import syncCRM from '@salesforce/apex/BlackRoadHubController.syncCRM';
|
||||
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
|
||||
|
||||
export default class BlackroadHubDashboard extends NavigationMixin(LightningElement) {
|
||||
@track stats = {};
|
||||
@track connectedCRMs = [];
|
||||
@track crmProducts = [];
|
||||
@track householdsNeedingAttention = [];
|
||||
@track complianceLogs = [];
|
||||
|
||||
crmColumns = [
|
||||
{ label: 'Name', fieldName: 'Name', type: 'text' },
|
||||
{ label: 'Type', fieldName: 'CRM_Type__c', type: 'text' },
|
||||
{ label: 'Status', fieldName: 'Status__c', type: 'text' },
|
||||
{ label: 'Vertical', fieldName: 'Vertical__c', type: 'text' },
|
||||
{ label: 'Records', fieldName: 'Record_Count__c', type: 'number' },
|
||||
{
|
||||
type: 'action',
|
||||
typeAttributes: { rowActions: [
|
||||
{ label: 'Sync', name: 'sync' },
|
||||
{ label: 'View', name: 'view' }
|
||||
]}
|
||||
}
|
||||
];
|
||||
|
||||
householdColumns = [
|
||||
{ label: 'Household', fieldName: 'Name', type: 'text' },
|
||||
{ label: 'AUM', fieldName: 'Total_AUM__c', type: 'currency' },
|
||||
{ label: 'Status', fieldName: 'Household_Status__c', type: 'text' },
|
||||
{ label: 'Next Review', fieldName: 'Next_Review_Date__c', type: 'date' },
|
||||
{
|
||||
type: 'action',
|
||||
typeAttributes: { rowActions: [
|
||||
{ label: 'View', name: 'view' },
|
||||
{ label: 'Schedule Review', name: 'schedule' }
|
||||
]}
|
||||
}
|
||||
];
|
||||
|
||||
logColumns = [
|
||||
{ label: 'Log #', fieldName: 'Name', type: 'text' },
|
||||
{ label: 'Type', fieldName: 'Log_Type__c', type: 'text' },
|
||||
{ label: 'Description', fieldName: 'Description__c', type: 'text' },
|
||||
{ label: 'Date', fieldName: 'CreatedDate', type: 'date' }
|
||||
];
|
||||
|
||||
@wire(getHubStats)
|
||||
wiredStats({ error, data }) {
|
||||
if (data) {
|
||||
this.stats = data;
|
||||
} else if (error) {
|
||||
console.error('Error loading stats:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@wire(getConnectedCRMs)
|
||||
wiredCRMs({ error, data }) {
|
||||
if (data) {
|
||||
this.connectedCRMs = data;
|
||||
} else if (error) {
|
||||
console.error('Error loading CRMs:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@wire(getCRMProducts)
|
||||
wiredProducts({ error, data }) {
|
||||
if (data) {
|
||||
this.crmProducts = data;
|
||||
} else if (error) {
|
||||
console.error('Error loading products:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@wire(getHouseholdsNeedingAttention)
|
||||
wiredHouseholds({ error, data }) {
|
||||
if (data) {
|
||||
this.householdsNeedingAttention = data;
|
||||
} else if (error) {
|
||||
console.error('Error loading households:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@wire(getRecentComplianceLogs, { recordLimit: 10 })
|
||||
wiredLogs({ error, data }) {
|
||||
if (data) {
|
||||
this.complianceLogs = data;
|
||||
} else if (error) {
|
||||
console.error('Error loading logs:', error);
|
||||
}
|
||||
}
|
||||
|
||||
get formattedAUM() {
|
||||
if (!this.stats.totalAUM) return '$0';
|
||||
return new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'USD',
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0
|
||||
}).format(this.stats.totalAUM);
|
||||
}
|
||||
|
||||
get totalPending() {
|
||||
return (this.stats.pendingDistributions || 0) +
|
||||
(this.stats.activeMortalityEvents || 0) +
|
||||
(this.stats.activeLiquidityEvents || 0);
|
||||
}
|
||||
|
||||
handleAddCRM() {
|
||||
this[NavigationMixin.Navigate]({
|
||||
type: 'standard__objectPage',
|
||||
attributes: {
|
||||
objectApiName: 'Connected_CRM__c',
|
||||
actionName: 'new'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleCRMAction(event) {
|
||||
const action = event.detail.action;
|
||||
const row = event.detail.row;
|
||||
|
||||
if (action.name === 'sync') {
|
||||
this.syncCRMInstance(row.Id);
|
||||
} else if (action.name === 'view') {
|
||||
this[NavigationMixin.Navigate]({
|
||||
type: 'standard__recordPage',
|
||||
attributes: {
|
||||
recordId: row.Id,
|
||||
objectApiName: 'Connected_CRM__c',
|
||||
actionName: 'view'
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleHouseholdAction(event) {
|
||||
const action = event.detail.action;
|
||||
const row = event.detail.row;
|
||||
|
||||
if (action.name === 'view') {
|
||||
this[NavigationMixin.Navigate]({
|
||||
type: 'standard__recordPage',
|
||||
attributes: {
|
||||
recordId: row.Id,
|
||||
objectApiName: 'Client_Household__c',
|
||||
actionName: 'view'
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async syncCRMInstance(crmId) {
|
||||
try {
|
||||
const result = await syncCRM({ crmId: crmId });
|
||||
this.dispatchEvent(
|
||||
new ShowToastEvent({
|
||||
title: 'Success',
|
||||
message: result,
|
||||
variant: 'success'
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
this.dispatchEvent(
|
||||
new ShowToastEvent({
|
||||
title: 'Error',
|
||||
message: error.body.message,
|
||||
variant: 'error'
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<apiVersion>59.0</apiVersion>
|
||||
<isExposed>true</isExposed>
|
||||
<masterLabel>BlackRoad Hub Dashboard</masterLabel>
|
||||
<description>Main dashboard for BlackRoad OS Hub - CRM Command Center</description>
|
||||
<targets>
|
||||
<target>lightning__AppPage</target>
|
||||
<target>lightning__HomePage</target>
|
||||
<target>lightning__Tab</target>
|
||||
</targets>
|
||||
</LightningComponentBundle>
|
||||
Reference in New Issue
Block a user