Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 72 additions & 70 deletions src/app/analytics/dashboard-widget/dashboard-widget.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -580,102 +580,104 @@
border-color: rgb(255 255 255 / 4%);
}

.leaflet-map-element {
filter: invert(100%) hue-rotate(180deg) brightness(95%) contrast(90%);
}

.leaflet-custom-popup {
.leaflet-popup-content-wrapper {
background: rgb(30 30 30 / 85%);
border-color: rgb(255 255 255 / 8%);
box-shadow:
0 10px 25px -5px rgb(0 0 0 / 40%),
0 8px 10px -6px rgb(0 0 0 / 40%);
::ng-deep {
Comment thread
JaySoni1 marked this conversation as resolved.
.leaflet-tile-pane {
filter: invert(100%) hue-rotate(180deg) brightness(95%) contrast(90%);
}

.leaflet-popup-tip {
background: rgb(30 30 30 / 85%);
border-color: rgb(255 255 255 / 8%);
}
.leaflet-custom-popup {
.leaflet-popup-content-wrapper {
background: rgb(30 30 30 / 85%);
border-color: rgb(255 255 255 / 8%);
box-shadow:
0 10px 25px -5px rgb(0 0 0 / 40%),
0 8px 10px -6px rgb(0 0 0 / 40%);
}

.map-tooltip {
.tooltip-header {
.tooltip-icon {
color: #38bdf8;
.leaflet-popup-tip {
background: rgb(30 30 30 / 85%);
border-color: rgb(255 255 255 / 8%);
}

.map-tooltip {
.tooltip-header {
.tooltip-icon {
color: #38bdf8;
}

.tooltip-title {
color: #f8fafc;
}

.tooltip-subtitle {
color: #94a3b8;
}
}

.tooltip-title {
color: #f8fafc;
.tooltip-divider {
background: rgb(255 255 255 / 8%);
}

.tooltip-subtitle {
color: #94a3b8;
.tooltip-row {
.tooltip-label {
color: #94a3b8;
}

.tooltip-value {
color: #e2e8f0;
}
}
}
}

.tooltip-divider {
background: rgb(255 255 255 / 8%);
.custom-map-pin {
.pin-pulse {
background: rgb(56 189 248 / 24%);
}

.tooltip-row {
.tooltip-label {
color: #94a3b8;
&:hover {
.pin-svg {
filter: drop-shadow(0 3px 6px rgb(56 189 248 / 45%));
}
}

.tooltip-value {
color: #e2e8f0;
&.active {
.pin-pulse {
background: rgb(249 115 22 / 30%);
}
}
}
}

.custom-map-pin {
.pin-pulse {
background: rgb(56 189 248 / 24%);
}

&:hover {
.pin-svg {
filter: drop-shadow(0 3px 6px rgb(56 189 248 / 45%));
.custom-marker-cluster {
.cluster-inner {
background: rgb(56 189 248 / 20%);
border-color: rgb(56 189 248 / 40%);
box-shadow: 0 4px 14px rgb(56 189 248 / 35%);

span {
background: #38bdf8;
color: #0f172a !important;
border: 2px solid #fff;
outline: 2px solid rgb(56 189 248 / 60%);
font-weight: 800;
}
}
}

&.active {
.pin-pulse {
background: rgb(249 115 22 / 30%);
}
.custom-leaflet-tooltip {
background: rgb(30 30 30 / 90%) !important;
border-color: rgb(255 255 255 / 8%) !important;
color: #e2e8f0 !important;
box-shadow: 0 4px 10px rgb(0 0 0 / 30%) !important;
}
}

.custom-marker-cluster {
.cluster-inner {
background: rgb(56 189 248 / 20%);
border-color: rgb(56 189 248 / 40%);
box-shadow: 0 4px 14px rgb(56 189 248 / 35%);

span {
background: #38bdf8;
color: #0f172a !important;
border: 2px solid #fff;
outline: 2px solid rgb(56 189 248 / 60%);
font-weight: 800;
}
.leaflet-tooltip.custom-tooltip-card {
background: #1e293b !important;
border-color: rgb(255 255 255 / 12%) !important;
box-shadow: 0 10px 25px -5px rgb(0 0 0 / 50%) !important;
}
}

.custom-leaflet-tooltip {
background: rgb(30 30 30 / 90%) !important;
border-color: rgb(255 255 255 / 8%) !important;
color: #e2e8f0 !important;
box-shadow: 0 4px 10px rgb(0 0 0 / 30%) !important;
}

.leaflet-tooltip.custom-tooltip-card {
background: #1e293b !important;
border-color: rgb(255 255 255 / 12%) !important;
box-shadow: 0 10px 25px -5px rgb(0 0 0 / 50%) !important;
}

.map-empty-state {
background-color: #1a1a1a;
color: #94a3b8;
Expand Down
41 changes: 31 additions & 10 deletions src/app/analytics/dashboard-widget/dashboard-widget.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,22 +288,25 @@ export class DashboardWidgetComponent implements AfterViewInit, OnChanges, OnDes
const savingsVal = pin.savings ? pin.savings.toLocaleString('en-US') : '0';
const collectedVal = pin.collected ? pin.collected.toLocaleString('en-US') : '0';

const safeOfficeName = this.escapeHtml(pin.officeName);
const safeCountry = this.escapeHtml(pin.country);

const popupHtml = `
<div class="map-tooltip">
<div class="tooltip-header">
<i class="fa fa-globe tooltip-icon"></i>
<div class="tooltip-title-container">
<span class="tooltip-title">${pin.officeName}</span>
<span class="tooltip-title">${safeOfficeName}</span>
<span class="tooltip-subtitle">
${flagUrl ? `<img src="${flagUrl}" class="tooltip-flag" width="16" height="12" />` : ''}
${pin.country || ''}
${safeCountry}
</span>
</div>
</div>
<div class="tooltip-divider"></div>
<div class="tooltip-row">
<span class="tooltip-label">${countryLabel}:</span>
<span class="tooltip-value">${pin.country || ''}</span>
<span class="tooltip-value">${safeCountry}</span>
</div>
<div class="tooltip-row">
<span class="tooltip-label">${activeClientsLabel}:</span>
Expand Down Expand Up @@ -351,7 +354,7 @@ export class DashboardWidgetComponent implements AfterViewInit, OnChanges, OnDes
marker.closeTooltip();
});

marker.on('click', (e: any) => {
marker.on('click', (e: L.LeafletMouseEvent) => {
if (e && e.originalEvent) {
L.DomEvent.stopPropagation(e.originalEvent);
}
Expand Down Expand Up @@ -398,14 +401,22 @@ export class DashboardWidgetComponent implements AfterViewInit, OnChanges, OnDes
});

if (this.selectedOfficeId !== null && this.markersMap.has(this.selectedOfficeId) && this.map) {
const marker = this.markersMap.get(this.selectedOfficeId);
const targetOfficeId = this.selectedOfficeId;
const marker = this.markersMap.get(targetOfficeId);
if (marker) {
setTimeout(() => {
if (this.map && marker) {
marker.openPopup();
this.map.panTo(marker.getLatLng());
const showMarkerPopup = () => {
if (this.selectedOfficeId !== targetOfficeId || !this.map || !marker) {
return;
}
}, 50);
marker.openPopup();
this.map.panTo(marker.getLatLng());
};

if (this.markerClusterGroup) {
this.markerClusterGroup.zoomToShowLayer(marker, showMarkerPopup);
} else {
setTimeout(showMarkerPopup, 50);
}
}
}
}
Expand All @@ -426,6 +437,16 @@ export class DashboardWidgetComponent implements AfterViewInit, OnChanges, OnDes
* - Percent adapters: format as 12.3%
* - Default: plain integer
*/
private escapeHtml(text?: string | null): string {
if (!text) return '';
return text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}

formatMetricValue(widgetId: string, value?: number): string {
if (value === undefined || value === null) {
return '—';
Expand Down
13 changes: 10 additions & 3 deletions src/app/analytics/services/analytics-data-source.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1164,8 +1164,13 @@ export class AnalyticsDataSourceService {
};
}

private normalizeOfficeId(officeId: number): number {
const id = Math.abs(Math.floor(Number(officeId)));
return Number.isSafeInteger(id) && id > 0 ? id : 1;
Comment thread
JaySoni1 marked this conversation as resolved.
}

private getOfficeClients(officeId: number, filters: AnalyticsFilters): number {
const safeId = Math.abs(Number(officeId)) || 1;
const safeId = this.normalizeOfficeId(officeId);
const base = ((safeId * 149) % 300) + 150;
const scale = filters.productId ? 0.25 : 1.0;
return Math.max(50, Math.floor(base * scale));
Expand All @@ -1178,14 +1183,16 @@ export class AnalyticsDataSourceService {

private getOfficeSavings(officeId: number, filters: AnalyticsFilters): number {
const clients = this.getOfficeClients(officeId, filters);
const basePerClient = ((officeId * 73) % 500) + 800;
const safeId = this.normalizeOfficeId(officeId);
const basePerClient = ((safeId * 73) % 500) + 800;
const productScale = filters.productId ? 0.4 : 1.0;
return Math.floor(clients * basePerClient * productScale);
}

private getOfficeCollected(officeId: number, filters: AnalyticsFilters): number {
const loansCount = this.getOfficeLoans(officeId, filters);
const avgLoanSize = ((officeId * 41) % 1000) + 1500;
const safeId = this.normalizeOfficeId(officeId);
const avgLoanSize = ((safeId * 41) % 1000) + 1500;
const basePortfolio = loansCount * avgLoanSize;

let periodScale = 0.08;
Expand Down
Loading