-
+
+
-
-
+
+
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/src/app/pages/dashboard/dashboard.component.scss b/src/app/pages/dashboard/dashboard.component.scss
index 223bcbe6..4661181b 100644
--- a/src/app/pages/dashboard/dashboard.component.scss
+++ b/src/app/pages/dashboard/dashboard.component.scss
@@ -13,4 +13,4 @@
display: none;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/dashboard.component.ts b/src/app/pages/dashboard/dashboard.component.ts
index c359216a..00990f3f 100644
--- a/src/app/pages/dashboard/dashboard.component.ts
+++ b/src/app/pages/dashboard/dashboard.component.ts
@@ -1,10 +1,11 @@
-import {Component, OnDestroy} from '@angular/core';
+import { Component, OnDestroy } from '@angular/core';
import { NbThemeService } from '@nebular/theme';
-import { takeWhile } from 'rxjs/operators' ;
-import { SolarData } from '../../@core/data/solar';
+import { takeWhile } from 'rxjs/operators';
interface CardSettings {
title: string;
+ value: string;
+ unitOfMeasurement: string;
iconClass: string;
type: string;
}
@@ -18,35 +19,46 @@ export class DashboardComponent implements OnDestroy {
private alive = true;
- solarValue: number;
- lightCard: CardSettings = {
- title: 'Light',
- iconClass: 'nb-lightbulb',
+ // Key metrics for IdentityPulse
+ verificationCard: CardSettings = {
+ title: 'Total Verifications',
+ value: '1,247',
+ unitOfMeasurement: 'today',
+ iconClass: 'nb-checkmark-circle',
type: 'primary',
};
- rollerShadesCard: CardSettings = {
- title: 'Roller Shades',
- iconClass: 'nb-roller-shades',
+
+ matchRateCard: CardSettings = {
+ title: 'Average Match Rate',
+ value: '87.3',
+ unitOfMeasurement: '%',
+ iconClass: 'nb-bar-chart',
type: 'success',
};
- wirelessAudioCard: CardSettings = {
- title: 'Wireless Audio',
- iconClass: 'nb-audio',
+
+ countriesCard: CardSettings = {
+ title: 'Active Countries',
+ value: '4',
+ unitOfMeasurement: 'regions',
+ iconClass: 'nb-location',
type: 'info',
};
- coffeeMakerCard: CardSettings = {
- title: 'Coffee Maker',
- iconClass: 'nb-coffee-maker',
+
+ apiResponseCard: CardSettings = {
+ title: 'API Response Time',
+ value: '245',
+ unitOfMeasurement: 'ms',
+ iconClass: 'nb-gear',
type: 'warning',
};
- statusCards: string;
+ statusCards: CardSettings[];
commonStatusCardsSet: CardSettings[] = [
- this.lightCard,
- this.rollerShadesCard,
- this.wirelessAudioCard,
- this.coffeeMakerCard,
+ this.verificationCard,
+ this.matchRateCard,
+ this.countriesCard,
+ this.apiResponseCard,
];
statusCardsByThemes: {
@@ -54,46 +66,24 @@ export class DashboardComponent implements OnDestroy {
cosmic: CardSettings[];
corporate: CardSettings[];
dark: CardSettings[];
+ marketsoft: CardSettings[];
} = {
default: this.commonStatusCardsSet,
cosmic: this.commonStatusCardsSet,
- corporate: [
- {
- ...this.lightCard,
- type: 'warning',
- },
- {
- ...this.rollerShadesCard,
- type: 'primary',
- },
- {
- ...this.wirelessAudioCard,
- type: 'danger',
- },
- {
- ...this.coffeeMakerCard,
- type: 'info',
- },
- ],
+ corporate: this.commonStatusCardsSet,
dark: this.commonStatusCardsSet,
+ marketsoft: this.commonStatusCardsSet,
};
- constructor(private themeService: NbThemeService,
- private solarService: SolarData) {
+ constructor(private themeService: NbThemeService) {
this.themeService.getJsTheme()
.pipe(takeWhile(() => this.alive))
.subscribe(theme => {
this.statusCards = this.statusCardsByThemes[theme.name];
- });
-
- this.solarService.getSolarData()
- .pipe(takeWhile(() => this.alive))
- .subscribe((data) => {
- this.solarValue = data;
});
}
ngOnDestroy() {
this.alive = false;
}
-}
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/dashboard.module.ts b/src/app/pages/dashboard/dashboard.module.ts
index b938dd67..c3a4ff7e 100644
--- a/src/app/pages/dashboard/dashboard.module.ts
+++ b/src/app/pages/dashboard/dashboard.module.ts
@@ -9,6 +9,7 @@ import {
NbSelectModule,
NbListModule,
NbIconModule,
+ NbProgressBarModule,
} from '@nebular/theme';
import { NgxEchartsModule } from 'ngx-echarts';
@@ -31,6 +32,19 @@ import { TrafficComponent } from './traffic/traffic.component';
import { TrafficChartComponent } from './traffic/traffic-chart.component';
import { FormsModule } from '@angular/forms';
+// IdentityPulse components
+import { MetricCardComponent } from './metric-card/metric-card.component';
+import { CountryCoverageComponent } from './country-coverage/country-coverage.component';
+import { ClientShowcaseComponent } from './client-showcase/client-showcase.component';
+import { DataCentersMapComponent } from './data-centers-map/data-centers-map.component';
+import { RecentVerificationsComponent } from './recent-verifications/recent-verifications.component';
+import { PricingRegionsComponent } from './pricing-regions/pricing-regions.component';
+import { ComplianceSummaryComponent } from './compliance-summary/compliance-summary.component';
+import { DifferentiatorsComponent } from './differentiators/differentiators.component';
+
+// Note: ECharts is already available globally through ngx-echarts
+// The world map is registered by ngx-admin's theme module
+
@NgModule({
imports: [
FormsModule,
@@ -45,6 +59,7 @@ import { FormsModule } from '@angular/forms';
NbListModule,
NbIconModule,
NbButtonModule,
+ NbProgressBarModule,
NgxEchartsModule,
],
declarations: [
@@ -64,6 +79,15 @@ import { FormsModule } from '@angular/forms';
SolarComponent,
TrafficComponent,
TrafficChartComponent,
+ // IdentityPulse components
+ MetricCardComponent,
+ CountryCoverageComponent,
+ ClientShowcaseComponent,
+ DataCentersMapComponent,
+ RecentVerificationsComponent,
+ PricingRegionsComponent,
+ ComplianceSummaryComponent,
+ DifferentiatorsComponent,
],
})
-export class DashboardModule { }
+export class DashboardModule { }
\ No newline at end of file
diff --git a/src/app/pages/dashboard/data-centers-map/data-centers-map.component.html b/src/app/pages/dashboard/data-centers-map/data-centers-map.component.html
new file mode 100644
index 00000000..0ac9d8b1
--- /dev/null
+++ b/src/app/pages/dashboard/data-centers-map/data-centers-map.component.html
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+ {{ getCountryCount() }} Countries
+
+
+
+ {{ getTotalDatabases() }} Databases
+
+
+
+ {{ getOnlineCount() }} Online
+
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/dashboard/data-centers-map/data-centers-map.component.scss b/src/app/pages/dashboard/data-centers-map/data-centers-map.component.scss
new file mode 100644
index 00000000..58048907
--- /dev/null
+++ b/src/app/pages/dashboard/data-centers-map/data-centers-map.component.scss
@@ -0,0 +1,88 @@
+@import '../../../@theme/styles/themes';
+
+@include nb-install-component() {
+ nb-card {
+ height: 450px;
+ }
+
+ .header-container {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+
+ h6 {
+ margin: 0;
+ font-weight: 600;
+ }
+ }
+
+ .legend {
+ display: flex;
+ gap: 1rem;
+
+ .legend-item {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 0.875rem;
+ color: nb-theme(text-hint-color);
+
+ .dot {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+
+ &.online {
+ background-color: #00d68f;
+ }
+
+ &.maintenance {
+ background-color: #ffaa00;
+ }
+
+ &.offline {
+ background-color: #ff3d71;
+ }
+ }
+ }
+ }
+
+ nb-card-body {
+ position: relative;
+ padding: 0;
+ }
+
+ .map-container {
+ width: 100%;
+ height: 350px;
+ z-index: 1;
+ }
+
+ .map-stats {
+ position: absolute;
+ bottom: 1rem;
+ left: 1rem;
+ background: nb-theme(background-basic-color-1);
+ border: 1px solid nb-theme(border-basic-color-3);
+ border-radius: nb-theme(card-border-radius);
+ padding: 0.75rem 1rem;
+ display: flex;
+ gap: 1.5rem;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ z-index: 1000; // Ensure stats appear above the map
+
+ .stat {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 0.875rem;
+ color: nb-theme(text-basic-color);
+
+ nb-icon {
+ font-size: 1.25rem;
+ color: nb-theme(color-primary-default);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/data-centers-map/data-centers-map.component.ts b/src/app/pages/dashboard/data-centers-map/data-centers-map.component.ts
new file mode 100644
index 00000000..e9881bd9
--- /dev/null
+++ b/src/app/pages/dashboard/data-centers-map/data-centers-map.component.ts
@@ -0,0 +1,215 @@
+import { Component, OnDestroy, AfterViewInit } from '@angular/core';
+import { NbThemeService } from '@nebular/theme';
+import { Router } from '@angular/router';
+import { takeWhile } from 'rxjs/operators';
+
+declare const L: any;
+
+interface DataCenter {
+ name: string;
+ country: string;
+ city: string;
+ coordinates: [number, number];
+ status: 'online' | 'maintenance' | 'offline';
+ databases: number;
+ responseTime: number;
+}
+
+@Component({
+ selector: 'ngx-data-centers-map',
+ styleUrls: ['./data-centers-map.component.scss'],
+ templateUrl: './data-centers-map.component.html',
+})
+export class DataCentersMapComponent implements AfterViewInit, OnDestroy {
+
+ private alive = true;
+ private map: any;
+
+ dataCenters: DataCenter[] = [
+ {
+ name: 'Sydney DC1',
+ country: 'Australia',
+ city: 'Sydney',
+ coordinates: [-33.8688, 151.2093],
+ status: 'online',
+ databases: 3,
+ responseTime: 45
+ },
+ {
+ name: 'Melbourne DC2',
+ country: 'Australia',
+ city: 'Melbourne',
+ coordinates: [-37.8136, 144.9631],
+ status: 'online',
+ databases: 2,
+ responseTime: 52
+ },
+ {
+ name: 'Jakarta DC1',
+ country: 'Indonesia',
+ city: 'Jakarta',
+ coordinates: [-6.2088, 106.8456],
+ status: 'online',
+ databases: 4,
+ responseTime: 78
+ },
+ {
+ name: 'Kuala Lumpur DC1',
+ country: 'Malaysia',
+ city: 'Kuala Lumpur',
+ coordinates: [3.1390, 101.6869],
+ status: 'online',
+ databases: 2,
+ responseTime: 65
+ },
+ {
+ name: 'Tokyo DC1',
+ country: 'Japan',
+ city: 'Tokyo',
+ coordinates: [35.6762, 139.6503],
+ status: 'online',
+ databases: 3,
+ responseTime: 89
+ }
+ ];
+
+ constructor(
+ private theme: NbThemeService,
+ private router: Router
+ ) {}
+
+ ngAfterViewInit() {
+ // Wait for the view to be fully initialized
+ setTimeout(() => {
+ this.initMap();
+ }, 100);
+ }
+
+ initMap() {
+ // Initialize the map centered on Asia-Pacific region
+ this.map = L.map('map', {
+ center: [0, 120],
+ zoom: 4,
+ minZoom: 2,
+ maxZoom: 18,
+ maxBounds: [[-90, -180], [90, 180]],
+ maxBoundsViscosity: 1.0,
+ zoomControl: true,
+ attributionControl: false
+ });
+
+ // Add tile layer with a professional style
+ L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', {
+ maxZoom: 19,
+ subdomains: 'abcd',
+ noWrap: true // Prevent the world from repeating
+ }).addTo(this.map);
+
+ // Add markers for each data center
+ this.dataCenters.forEach(dc => {
+ const icon = this.createCustomIcon(dc.status);
+
+ const marker = L.marker(dc.coordinates, { icon })
+ .addTo(this.map)
+ .bindPopup(this.createPopupContent(dc));
+
+ // Add click event to navigate to identity lookup
+ marker.on('click', () => {
+ setTimeout(() => {
+ this.router.navigate(['/pages/identity/manual-lookup'], {
+ queryParams: { country: dc.country.toLowerCase() }
+ });
+ }, 1000);
+ });
+ });
+
+ // Fit map to show all markers
+ const group = new L.featureGroup(this.dataCenters.map(dc => L.marker(dc.coordinates)));
+ this.map.fitBounds(group.getBounds().pad(0.1));
+ }
+
+ createCustomIcon(status: string) {
+ const colors = {
+ online: '#00d68f',
+ maintenance: '#ffaa00',
+ offline: '#ff3d71'
+ };
+
+ const html = `
+
+ `;
+
+ return L.divIcon({
+ html: html,
+ className: 'custom-marker',
+ iconSize: [24, 24],
+ iconAnchor: [12, 12]
+ });
+ }
+
+ createPopupContent(dc: DataCenter): string {
+ const statusColors = {
+ online: '#00d68f',
+ maintenance: '#ffaa00',
+ offline: '#ff3d71'
+ };
+
+ return `
+
+
${dc.name}
+
+
City: ${dc.city}, ${dc.country}
+
Status: ${dc.status}
+
Databases: ${dc.databases}
+
Response Time: ${dc.responseTime}ms
+
+
+
+ Click to query this region →
+
+
+
+ `;
+ }
+
+ getTotalDatabases(): number {
+ return this.dataCenters.reduce((sum, dc) => sum + dc.databases, 0);
+ }
+
+ getOnlineCount(): number {
+ return this.dataCenters.filter(dc => dc.status === 'online').length;
+ }
+
+ getCountryCount(): number {
+ // Get unique countries
+ const uniqueCountries = new Set(this.dataCenters.map(dc => dc.country));
+ return uniqueCountries.size;
+ }
+
+ getStatusColor(status: string): string {
+ switch (status) {
+ case 'online':
+ return '#00d68f';
+ case 'maintenance':
+ return '#ffaa00';
+ case 'offline':
+ return '#ff3d71';
+ default:
+ return '#8f9bb3';
+ }
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ if (this.map) {
+ this.map.remove();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/differentiators/differentiators.component.html b/src/app/pages/dashboard/differentiators/differentiators.component.html
new file mode 100644
index 00000000..67d0d1aa
--- /dev/null
+++ b/src/app/pages/dashboard/differentiators/differentiators.component.html
@@ -0,0 +1,27 @@
+
+
+ Why IdentityPulse is Different
+
+
+
+
+
+
+
+
+
+
{{ item.title }}
+
{{ item.description }}
+
{{ item.metric }}
+
+
+
+
+
+
Experience the difference with a live demo
+
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/dashboard/differentiators/differentiators.component.scss b/src/app/pages/dashboard/differentiators/differentiators.component.scss
new file mode 100644
index 00000000..752197a1
--- /dev/null
+++ b/src/app/pages/dashboard/differentiators/differentiators.component.scss
@@ -0,0 +1,90 @@
+@import '../../../@theme/styles/themes';
+
+@include nb-install-component() {
+ nb-card-header h6 {
+ margin: 0;
+ font-weight: 600;
+ }
+
+ .differentiators-grid {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ margin-bottom: 1.5rem;
+ }
+
+ .differentiator {
+ display: flex;
+ gap: 1rem;
+ padding: 1rem;
+ border: 1px solid nb-theme(border-basic-color-3);
+ border-radius: nb-theme(card-border-radius);
+ transition: all 0.3s ease;
+
+ &:hover {
+ border-color: nb-theme(color-primary-default);
+ transform: translateX(4px);
+
+ .icon-wrapper {
+ background: nb-theme(color-primary-default);
+ color: white;
+ }
+ }
+
+ .icon-wrapper {
+ flex-shrink: 0;
+ width: 48px;
+ height: 48px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: nb-theme(background-basic-color-3);
+ border-radius: nb-theme(card-border-radius);
+ transition: all 0.3s ease;
+
+ nb-icon {
+ font-size: 1.5rem;
+ }
+ }
+
+ .content {
+ flex: 1;
+
+ .title {
+ margin: 0 0 0.25rem 0;
+ font-size: 0.875rem;
+ font-weight: 600;
+ color: nb-theme(text-basic-color);
+ }
+
+ .description {
+ margin: 0 0 0.5rem 0;
+ font-size: 0.75rem;
+ color: nb-theme(text-hint-color);
+ line-height: 1.4;
+ }
+
+ .metric {
+ display: inline-block;
+ font-size: 0.75rem;
+ font-weight: 600;
+ color: nb-theme(color-primary-default);
+ padding: 0.125rem 0.5rem;
+ background: nb-theme(color-primary-transparent-100);
+ border-radius: nb-theme(border-radius);
+ }
+ }
+ }
+
+ .cta-section {
+ text-align: center;
+ padding-top: 1rem;
+ border-top: 1px solid nb-theme(border-basic-color-3);
+
+ .cta-text {
+ margin: 0 0 1rem 0;
+ font-size: 0.875rem;
+ color: nb-theme(text-hint-color);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/differentiators/differentiators.component.ts b/src/app/pages/dashboard/differentiators/differentiators.component.ts
new file mode 100644
index 00000000..e7550328
--- /dev/null
+++ b/src/app/pages/dashboard/differentiators/differentiators.component.ts
@@ -0,0 +1,55 @@
+import { Component } from '@angular/core';
+
+interface Differentiator {
+ title: string;
+ description: string;
+ icon: string;
+ metric?: string;
+}
+
+@Component({
+ selector: 'ngx-differentiators',
+ styleUrls: ['./differentiators.component.scss'],
+ templateUrl: './differentiators.component.html',
+})
+export class DifferentiatorsComponent {
+
+ differentiators: Differentiator[] = [
+ {
+ title: 'Real-time Updates',
+ description: 'Direct integration with government and trusted sources for instant data updates',
+ icon: 'flash-outline',
+ metric: '< 5min latency'
+ },
+ {
+ title: 'Multi-Source Validation',
+ description: 'Cross-reference data from multiple authoritative sources for accuracy',
+ icon: 'layers-outline',
+ metric: '15+ sources'
+ },
+ {
+ title: 'AI-Powered Matching',
+ description: 'Advanced fuzzy matching algorithms handle name variations and typos',
+ icon: 'bulb-outline',
+ metric: '99.2% accuracy'
+ },
+ {
+ title: 'Regional Expertise',
+ description: 'Deep understanding of local naming conventions and data formats',
+ icon: 'globe-2-outline',
+ metric: '4 regions'
+ },
+ {
+ title: 'Elastic Infrastructure',
+ description: 'Built on Elasticsearch for lightning-fast queries at any scale',
+ icon: 'activity-outline',
+ metric: '< 250ms response'
+ },
+ {
+ title: 'Privacy by Design',
+ description: 'Zero data retention policy and end-to-end encryption',
+ icon: 'shield-outline',
+ metric: 'ISO 27001'
+ }
+ ];
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/metric-card/metric-card.component.scss b/src/app/pages/dashboard/metric-card/metric-card.component.scss
new file mode 100644
index 00000000..af3be796
--- /dev/null
+++ b/src/app/pages/dashboard/metric-card/metric-card.component.scss
@@ -0,0 +1,95 @@
+@import '../../../@theme/styles/themes';
+@import 'bootstrap/scss/mixins/breakpoints';
+@import '@nebular/theme/styles/global/breakpoints';
+
+@include nb-install-component() {
+ nb-card {
+ flex-direction: row;
+ align-items: center;
+ height: 6rem;
+ overflow: visible;
+
+ .icon-container {
+ height: 100%;
+ padding: 0.625rem;
+ }
+
+ .icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 5.75rem;
+ height: 4.75rem;
+ font-size: 3.75rem;
+ border-radius: nb-theme(card-border-radius);
+ transition: width 0.4s ease;
+ transform: translate3d(0, 0, 0);
+ -webkit-transform-style: preserve-3d;
+ -webkit-backface-visibility: hidden;
+ color: nb-theme(text-control-color);
+
+ @each $status in nb-get-statuses() {
+ &.status-#{$status} {
+ $left-color: nb-theme(button-hero-#{$status}-left-background-color);
+ $right-color: nb-theme(button-hero-#{$status}-right-background-color);
+ background-image: linear-gradient(to right, $left-color, $right-color);
+
+ &:hover {
+ $left-hover-color: nb-theme(button-hero-#{$status}-hover-left-background-color);
+ $right-hover-color: nb-theme(button-hero-#{$status}-hover-right-background-color);
+ background-image: linear-gradient(to right, $left-hover-color, $right-hover-color);
+ }
+ }
+ }
+ }
+
+ .details {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ height: 100%;
+ @include nb-ltr(padding, 0 0.5rem 0 0.75rem);
+ @include nb-rtl(padding, 0 0.75rem 0 0.5rem);
+ border-left: 1px solid transparent;
+ }
+
+ .title {
+ margin: 0;
+ font-weight: 600;
+ color: nb-theme(text-hint-color);
+ font-size: 0.875rem;
+ }
+
+ .status-value {
+ display: flex;
+ align-items: baseline;
+
+ .value {
+ margin: 0;
+ font-weight: 700;
+ color: nb-theme(text-basic-color);
+ font-size: 2rem;
+ }
+
+ .unit {
+ margin-left: 0.5rem;
+ color: nb-theme(text-hint-color);
+ font-size: 0.875rem;
+ }
+ }
+ }
+
+ @include media-breakpoint-down(sm) {
+ nb-card {
+ .icon {
+ width: 4rem;
+ height: 4rem;
+ font-size: 2.5rem;
+ }
+
+ .value {
+ font-size: 1.5rem;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/metric-card/metric-card.component.ts b/src/app/pages/dashboard/metric-card/metric-card.component.ts
new file mode 100644
index 00000000..19d12e01
--- /dev/null
+++ b/src/app/pages/dashboard/metric-card/metric-card.component.ts
@@ -0,0 +1,30 @@
+import { Component, Input } from '@angular/core';
+
+@Component({
+ selector: 'ngx-metric-card',
+ styleUrls: ['./metric-card.component.scss'],
+ template: `
+
+
+
+
+
{{ title }}
+
+ {{ value }}
+ {{ unitOfMeasurement }}
+
+
+
+ `,
+})
+export class MetricCardComponent {
+ @Input() title: string;
+ @Input() type: string;
+ @Input() value: string;
+ @Input() unitOfMeasurement: string;
+ @Input() iconClass: string;
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/pricing-regions/pricing-regions.component.html b/src/app/pages/dashboard/pricing-regions/pricing-regions.component.html
new file mode 100644
index 00000000..bca9b332
--- /dev/null
+++ b/src/app/pages/dashboard/pricing-regions/pricing-regions.component.html
@@ -0,0 +1,47 @@
+
+
+ Regional Pricing
+
+
+
+
+
+
+
+
+ {{ tier.currency }}
+ ${{ tier.basePrice }}
+ /month
+
+
+
+ Per verification:
+ ${{ tier.perVerification }}
+
+
+
+
+ {{ tier.volumeDiscount }}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/dashboard/pricing-regions/pricing-regions.component.scss b/src/app/pages/dashboard/pricing-regions/pricing-regions.component.scss
new file mode 100644
index 00000000..df57bf5a
--- /dev/null
+++ b/src/app/pages/dashboard/pricing-regions/pricing-regions.component.scss
@@ -0,0 +1,115 @@
+@import '../../../@theme/styles/themes';
+
+@include nb-install-component() {
+ nb-card-header h6 {
+ margin: 0;
+ font-weight: 600;
+ }
+
+ .pricing-tiers {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ margin-bottom: 1.5rem;
+ }
+
+ .tier {
+ padding: 1rem;
+ border: 1px solid nb-theme(border-basic-color-3);
+ border-radius: nb-theme(card-border-radius);
+ transition: all 0.3s ease;
+
+ &:hover {
+ border-color: nb-theme(color-primary-default);
+ transform: translateY(-2px);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ }
+
+ .tier-header {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ margin-bottom: 0.75rem;
+
+ .region-flag {
+ font-size: 1.5rem;
+ }
+
+ .region-name {
+ margin: 0;
+ font-weight: 600;
+ color: nb-theme(text-basic-color);
+ }
+ }
+
+ .pricing-details {
+ .base-price {
+ display: flex;
+ align-items: baseline;
+ margin-bottom: 0.5rem;
+
+ .currency {
+ font-size: 0.875rem;
+ color: nb-theme(text-hint-color);
+ margin-right: 0.25rem;
+ }
+
+ .price {
+ font-size: 1.5rem;
+ font-weight: 700;
+ color: nb-theme(color-primary-default);
+ }
+
+ .period {
+ font-size: 0.875rem;
+ color: nb-theme(text-hint-color);
+ margin-left: 0.25rem;
+ }
+ }
+
+ .per-verification,
+ .volume-discount {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ font-size: 0.875rem;
+ color: nb-theme(text-hint-color);
+ margin-bottom: 0.25rem;
+
+ nb-icon {
+ font-size: 1rem;
+ color: nb-theme(color-success-default);
+ }
+ }
+ }
+ }
+
+ .features {
+ margin-bottom: 1.5rem;
+
+ h6 {
+ margin: 0 0 0.75rem 0;
+ font-weight: 600;
+ color: nb-theme(text-basic-color);
+ }
+
+ ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+
+ li {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ margin-bottom: 0.5rem;
+ font-size: 0.875rem;
+ color: nb-theme(text-hint-color);
+
+ nb-icon {
+ font-size: 1.25rem;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/pricing-regions/pricing-regions.component.ts b/src/app/pages/dashboard/pricing-regions/pricing-regions.component.ts
new file mode 100644
index 00000000..a06c50a5
--- /dev/null
+++ b/src/app/pages/dashboard/pricing-regions/pricing-regions.component.ts
@@ -0,0 +1,52 @@
+import { Component } from '@angular/core';
+
+interface PricingTier {
+ region: string;
+ flag: string;
+ currency: string;
+ basePrice: number;
+ perVerification: number;
+ volumeDiscount: string;
+}
+
+@Component({
+ selector: 'ngx-pricing-regions',
+ styleUrls: ['./pricing-regions.component.scss'],
+ templateUrl: './pricing-regions.component.html',
+})
+export class PricingRegionsComponent {
+
+ pricingTiers: PricingTier[] = [
+ {
+ region: 'APAC',
+ flag: '🌏',
+ currency: 'USD',
+ basePrice: 299,
+ perVerification: 0.15,
+ volumeDiscount: '10% off 100k+'
+ },
+ {
+ region: 'MENA',
+ flag: '🌍',
+ currency: 'USD',
+ basePrice: 349,
+ perVerification: 0.18,
+ volumeDiscount: '15% off 150k+'
+ },
+ {
+ region: 'Europe',
+ flag: '🇪🇺',
+ currency: 'EUR',
+ basePrice: 279,
+ perVerification: 0.14,
+ volumeDiscount: '12% off 100k+'
+ }
+ ];
+
+ features = [
+ 'Real-time API access',
+ 'Batch processing',
+ '99.9% uptime SLA',
+ '24/7 support'
+ ];
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/recent-verifications/recent-verifications.component.html b/src/app/pages/dashboard/recent-verifications/recent-verifications.component.html
new file mode 100644
index 00000000..ef9fffa6
--- /dev/null
+++ b/src/app/pages/dashboard/recent-verifications/recent-verifications.component.html
@@ -0,0 +1,41 @@
+
+
+ Recent Verifications
+
+
+
+
+
+
+
+
+
+
+ {{ verification.type }}
+ {{ verification.id }}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/app/pages/dashboard/recent-verifications/recent-verifications.component.scss b/src/app/pages/dashboard/recent-verifications/recent-verifications.component.scss
new file mode 100644
index 00000000..aef415d9
--- /dev/null
+++ b/src/app/pages/dashboard/recent-verifications/recent-verifications.component.scss
@@ -0,0 +1,101 @@
+@import '../../../@theme/styles/themes';
+
+@include nb-install-component() {
+ nb-card {
+ height: 450px;
+ }
+
+ nb-card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ h6 {
+ margin: 0;
+ font-weight: 600;
+ }
+ }
+
+ nb-card-body {
+ padding: 0;
+ overflow-y: auto;
+ }
+
+ nb-list {
+ margin: 0;
+ }
+
+ nb-list-item {
+ padding: 0;
+ border: none;
+
+ &:hover {
+ background-color: nb-theme(background-basic-color-2);
+ }
+ }
+
+ .verification-item {
+ padding: 1rem;
+ border-bottom: 1px solid nb-theme(border-basic-color-3);
+ }
+
+ .verification-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 0.5rem;
+
+ .country-info {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+
+ .country-flag {
+ font-size: 1.25rem;
+ }
+
+ .country-name {
+ font-weight: 600;
+ color: nb-theme(text-basic-color);
+ }
+ }
+
+ .timestamp {
+ font-size: 0.75rem;
+ color: nb-theme(text-hint-color);
+ }
+ }
+
+ .verification-details {
+ .type-and-id {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 0.5rem;
+
+ .type {
+ font-size: 0.875rem;
+ color: nb-theme(text-hint-color);
+ }
+
+ .id {
+ font-size: 0.75rem;
+ color: nb-theme(text-hint-color);
+ font-family: monospace;
+ }
+ }
+
+ .score-and-status {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+
+ nb-progress-bar {
+ flex: 1;
+ }
+
+ nb-icon {
+ font-size: 1.25rem;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/recent-verifications/recent-verifications.component.ts b/src/app/pages/dashboard/recent-verifications/recent-verifications.component.ts
new file mode 100644
index 00000000..8550efdf
--- /dev/null
+++ b/src/app/pages/dashboard/recent-verifications/recent-verifications.component.ts
@@ -0,0 +1,126 @@
+import { Component, OnDestroy } from '@angular/core';
+import { takeWhile } from 'rxjs/operators';
+import { NbThemeService } from '@nebular/theme';
+
+interface Verification {
+ id: string;
+ country: string;
+ timestamp: Date;
+ matchScore: number;
+ status: 'verified' | 'partial' | 'failed';
+ type: string;
+}
+
+@Component({
+ selector: 'ngx-recent-verifications',
+ styleUrls: ['./recent-verifications.component.scss'],
+ templateUrl: './recent-verifications.component.html',
+})
+export class RecentVerificationsComponent implements OnDestroy {
+
+ private alive = true;
+
+ verifications: Verification[] = [
+ {
+ id: 'VER-2024-001',
+ country: 'Australia',
+ timestamp: new Date(Date.now() - 120000),
+ matchScore: 95,
+ status: 'verified',
+ type: 'Identity Check'
+ },
+ {
+ id: 'VER-2024-002',
+ country: 'Indonesia',
+ timestamp: new Date(Date.now() - 300000),
+ matchScore: 78,
+ status: 'partial',
+ type: 'Address Verification'
+ },
+ {
+ id: 'VER-2024-003',
+ country: 'Japan',
+ timestamp: new Date(Date.now() - 600000),
+ matchScore: 92,
+ status: 'verified',
+ type: 'Full KYC'
+ },
+ {
+ id: 'VER-2024-004',
+ country: 'Malaysia',
+ timestamp: new Date(Date.now() - 900000),
+ matchScore: 45,
+ status: 'failed',
+ type: 'Identity Check'
+ },
+ {
+ id: 'VER-2024-005',
+ country: 'Australia',
+ timestamp: new Date(Date.now() - 1200000),
+ matchScore: 88,
+ status: 'verified',
+ type: 'Document Verify'
+ },
+ {
+ id: 'VER-2024-006',
+ country: 'Indonesia',
+ timestamp: new Date(Date.now() - 1500000),
+ matchScore: 91,
+ status: 'verified',
+ type: 'Full KYC'
+ }
+ ];
+
+ constructor(private themeService: NbThemeService) {}
+
+ getStatusIcon(status: string): string {
+ switch (status) {
+ case 'verified':
+ return 'checkmark-circle-2-outline';
+ case 'partial':
+ return 'alert-triangle-outline';
+ case 'failed':
+ return 'close-circle-outline';
+ default:
+ return 'minus-circle-outline';
+ }
+ }
+
+ getStatusColor(status: string): string {
+ switch (status) {
+ case 'verified':
+ return 'success';
+ case 'partial':
+ return 'warning';
+ case 'failed':
+ return 'danger';
+ default:
+ return 'basic';
+ }
+ }
+
+ getCountryFlag(country: string): string {
+ const flags = {
+ 'Australia': '🇦🇺',
+ 'Indonesia': '🇮🇩',
+ 'Malaysia': '🇲🇾',
+ 'Japan': '🇯🇵'
+ };
+ return flags[country] || '🌏';
+ }
+
+ getTimeAgo(date: Date): string {
+ const seconds = Math.floor((new Date().getTime() - date.getTime()) / 1000);
+ if (seconds < 60) return 'just now';
+ const minutes = Math.floor(seconds / 60);
+ if (minutes < 60) return `${minutes}m ago`;
+ const hours = Math.floor(minutes / 60);
+ if (hours < 24) return `${hours}h ago`;
+ const days = Math.floor(hours / 24);
+ return `${days}d ago`;
+ }
+
+ ngOnDestroy() {
+ this.alive = false;
+ }
+}
\ No newline at end of file
diff --git a/src/app/pages/dashboard/status-card/status-card.component.ts b/src/app/pages/dashboard/status-card/status-card.component.ts
index 16276408..82068fe0 100644
--- a/src/app/pages/dashboard/status-card/status-card.component.ts
+++ b/src/app/pages/dashboard/status-card/status-card.component.ts
@@ -4,7 +4,7 @@ import { Component, Input } from '@angular/core';
selector: 'ngx-status-card',
styleUrls: ['./status-card.component.scss'],
template: `
-
+
@@ -13,14 +13,17 @@ import { Component, Input } from '@angular/core';
{{ title }}
-
{{ on ? 'ON' : 'OFF' }}
+
+ {{ value }}
+ {{ unitOfMeasurement }}
+
`,
})
export class StatusCardComponent {
-
@Input() title: string;
@Input() type: string;
- @Input() on = true;
-}
+ @Input() value: string;
+ @Input() unitOfMeasurement: string;
+}
\ No newline at end of file
diff --git a/src/app/pages/identity/identity.module.ts b/src/app/pages/identity/identity.module.ts
index ae6ad750..d9904951 100644
--- a/src/app/pages/identity/identity.module.ts
+++ b/src/app/pages/identity/identity.module.ts
@@ -9,7 +9,8 @@ import {
NbSelectModule,
NbSpinnerModule,
NbProgressBarModule,
- NbIconModule
+ NbIconModule,
+ NbListModule
} from '@nebular/theme';
import { ManualLookupComponent } from './manual-lookup/manual-lookup.component';
import { ResultsHistoryComponent } from './results-history/results-history.component';
@@ -34,7 +35,8 @@ import { ResultsHistoryComponent } from './results-history/results-history.compo
NbSelectModule,
NbSpinnerModule,
NbProgressBarModule,
- NbIconModule
+ NbIconModule,
+ NbListModule
],
declarations: [
ManualLookupComponent,
diff --git a/src/app/pages/identity/manual-lookup/manual-lookup.component.html b/src/app/pages/identity/manual-lookup/manual-lookup.component.html
index ada2805c..8b3400b6 100644
--- a/src/app/pages/identity/manual-lookup/manual-lookup.component.html
+++ b/src/app/pages/identity/manual-lookup/manual-lookup.component.html
@@ -1,76 +1,150 @@
-
+
Identity Verification - Manual Lookup