This commit is contained in:
TulkasOrome 2025-06-16 01:25:26 +00:00 committed by GitHub
commit e28c592325
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 21560 additions and 11892 deletions

View file

@ -187,5 +187,8 @@
"@angular-eslint/schematics:library": { "@angular-eslint/schematics:library": {
"setParserOptionsProject": true "setParserOptionsProject": true
} }
},
"cli": {
"analytics": false
} }
} }

29599
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
{ {
"name": "ngx-admin", "name": "identity-pulse",
"version": "11.0.0", "version": "11.0.0",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
@ -62,7 +62,6 @@
"ng2-completer": "^9.0.1", "ng2-completer": "^9.0.1",
"ng2-smart-table": "^1.6.0", "ng2-smart-table": "^1.6.0",
"ngx-echarts": "^4.2.2", "ngx-echarts": "^4.2.2",
"node-sass": "^4.14.1",
"normalize.css": "6.0.0", "normalize.css": "6.0.0",
"pace-js": "1.0.2", "pace-js": "1.0.2",
"roboto-fontface": "0.8.0", "roboto-fontface": "0.8.0",
@ -110,6 +109,7 @@
"npm-run-all": "4.0.2", "npm-run-all": "4.0.2",
"protractor": "~7.0.0", "protractor": "~7.0.0",
"rimraf": "2.6.1", "rimraf": "2.6.1",
"sass": "^1.89.0",
"stylelint": "7.13.0", "stylelint": "7.13.0",
"ts-node": "3.2.2", "ts-node": "3.2.2",
"tslint": "~6.1.0", "tslint": "~6.1.0",

View file

@ -1,11 +1,12 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { NbThemeService } from '@nebular/theme';
@Component({ @Component({
selector: 'ngx-footer', selector: 'ngx-footer',
styleUrls: ['./footer.component.scss'], styleUrls: ['./footer.component.scss'],
template: ` template: `
<span class="created-by"> <span class="created-by">
Created with by <b><a href="https://akveo.page.link/8V2f" target="_blank">Akveo</a></b> 2019 Powered by <b><a href="https://marketsoft.com.au" target="_blank">IdentityPulse</a></b> © 2025
</span> </span>
<div class="socials"> <div class="socials">
<a href="#" target="_blank" class="ion ion-social-github"></a> <a href="#" target="_blank" class="ion ion-social-github"></a>
@ -16,4 +17,5 @@ import { Component } from '@angular/core';
`, `,
}) })
export class FooterComponent { export class FooterComponent {
constructor(private themeService: NbThemeService) {}
} }

View file

@ -3,7 +3,7 @@
<a (click)="toggleSidebar()" href="#" class="sidebar-toggle"> <a (click)="toggleSidebar()" href="#" class="sidebar-toggle">
<nb-icon icon="menu-2-outline"></nb-icon> <nb-icon icon="menu-2-outline"></nb-icon>
</a> </a>
<a class="logo" href="#" (click)="navigateHome()">ngx-<span>admin</span></a> <a class="logo" href="#" (click)="navigateHome()">Identity<span>Pulse</span></a>
</div> </div>
<nb-select [selected]="currentTheme" (selectedChange)="changeTheme($event)" status="primary"> <nb-select [selected]="currentTheme" (selectedChange)="changeTheme($event)" status="primary">
<nb-option *ngFor="let theme of themes" [value]="theme.value"> {{ theme.name }}</nb-option> <nb-option *ngFor="let theme of themes" [value]="theme.value"> {{ theme.name }}</nb-option>

View file

@ -34,9 +34,13 @@ export class HeaderComponent implements OnInit, OnDestroy {
value: 'corporate', value: 'corporate',
name: 'Corporate', name: 'Corporate',
}, },
{
value: 'marketsoft',
name: 'Marketsoft',
},
]; ];
currentTheme = 'default'; currentTheme = 'marketsoft';
userMenu = [ { title: 'Profile' }, { title: 'Log out' } ]; userMenu = [ { title: 'Profile' }, { title: 'Log out' } ];

View file

@ -1,4 +1,6 @@
@import url('https://fonts.googleapis.com/css?family=Open+Sans:400,600,700&display=swap'); @import url('https://fonts.googleapis.com/css?family=Open+Sans:400,600,700&display=swap');
/* You can add global styles to this file, and also import other style files */
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap');
// themes - our custom or/and out of the box themes // themes - our custom or/and out of the box themes
@import 'themes'; @import 'themes';

View file

@ -0,0 +1,171 @@
import { NbJSThemeOptions, DEFAULT_THEME as baseTheme } from '@nebular/theme';
const baseThemeVariables = baseTheme.variables;
export const MARKETSOFT_THEME = {
name: 'marketsoft',
base: 'default',
variables: {
// Based on the Marketsoft brand colors from the provided brand guide
// Primary color - Marketsoft red
temperature: {
arcFill: ['#D6001C', '#D6001C', '#D6001C', '#D6001C', '#D6001C'],
arcEmpty: baseThemeVariables.bg2,
thumbBg: '#FFFFFF',
thumbBorder: '#D6001C',
},
// Override with Marketsoft brand colors
primary: '#D6001C', // Marketsoft red
success: '#2a2e40', // Marketsoft blue
info: '#2a2e40', // Marketsoft blue
warning: '#D6001C', // Marketsoft red
danger: '#D6001C', // Marketsoft red
// Background colors
bg3: '#f7f9fc',
bg4: '#edf1f7',
solar: {
gradientLeft: '#D6001C',
gradientRight: '#D6001C',
shadowColor: 'rgba(0, 0, 0, 0)',
secondSeriesFill: baseThemeVariables.bg2,
radius: ['70%', '90%'],
},
traffic: {
tooltipBg: baseThemeVariables.bg,
tooltipBorderColor: baseThemeVariables.border2,
tooltipExtraCss: 'border-radius: 10px; padding: 4px 16px;',
tooltipTextColor: baseThemeVariables.fgText,
tooltipFontWeight: 'normal',
yAxisSplitLine: baseThemeVariables.separator,
lineBg: '#D6001C',
lineShadowBlur: '0',
itemColor: '#D6001C',
itemBorderColor: '#D6001C',
itemEmphasisBorderColor: '#D6001C',
shadowLineDarkBg: 'rgba(0, 0, 0, 0)',
shadowLineShadow: 'rgba(0, 0, 0, 0)',
gradFrom: baseThemeVariables.bg,
gradTo: baseThemeVariables.bg,
},
electricity: {
tooltipBg: baseThemeVariables.bg,
tooltipLineColor: baseThemeVariables.fgText,
tooltipLineWidth: '0',
tooltipBorderColor: baseThemeVariables.border2,
tooltipExtraCss: 'border-radius: 10px; padding: 8px 24px;',
tooltipTextColor: baseThemeVariables.fgText,
tooltipFontWeight: 'normal',
axisLineColor: baseThemeVariables.border3,
xAxisTextColor: baseThemeVariables.fg,
yAxisSplitLine: baseThemeVariables.separator,
itemBorderColor: '#D6001C',
lineStyle: 'solid',
lineWidth: '4',
lineGradFrom: '#D6001C',
lineGradTo: '#D6001C',
lineShadow: 'rgba(0, 0, 0, 0)',
areaGradFrom: 'rgba(214, 0, 28, 0.2)',
areaGradTo: 'rgba(214, 0, 28, 0)',
shadowLineDarkBg: 'rgba(0, 0, 0, 0)',
},
bubbleMap: {
titleColor: baseThemeVariables.fgText,
areaColor: baseThemeVariables.bg4,
areaHoverColor: baseThemeVariables.fgHighlight,
areaBorderColor: baseThemeVariables.border5,
},
echarts: {
bg: baseThemeVariables.bg,
textColor: baseThemeVariables.fgText,
axisLineColor: baseThemeVariables.fgText,
splitLineColor: baseThemeVariables.separator,
itemHoverShadowColor: 'rgba(0, 0, 0, 0.5)',
tooltipBackgroundColor: '#D6001C',
areaOpacity: '0.7',
},
chartjs: {
axisLineColor: baseThemeVariables.separator,
textColor: baseThemeVariables.fgText,
},
// Additional styling for specific components
orders: {
tooltipBg: baseThemeVariables.bg,
tooltipLineColor: 'rgba(0, 0, 0, 0)',
tooltipLineWidth: '0',
tooltipBorderColor: baseThemeVariables.border2,
tooltipExtraCss: 'border-radius: 10px; padding: 8px 24px;',
tooltipTextColor: baseThemeVariables.fgText,
tooltipFontWeight: 'normal',
tooltipFontSize: '20',
axisLineColor: baseThemeVariables.border4,
axisFontSize: '16',
axisTextColor: baseThemeVariables.fg,
yAxisSplitLine: baseThemeVariables.separator,
itemBorderColor: '#D6001C',
lineStyle: 'solid',
lineWidth: '4',
// first line
firstAreaGradFrom: 'rgba(42, 46, 64, 0.2)',
firstAreaGradTo: 'rgba(42, 46, 64, 0)',
firstShadowLineDarkBg: 'rgba(0, 0, 0, 0)',
// second line
secondLineGradFrom: '#D6001C',
secondLineGradTo: '#D6001C',
secondAreaGradFrom: 'rgba(214, 0, 28, 0.2)',
secondAreaGradTo: 'rgba(214, 0, 28, 0)',
secondShadowLineDarkBg: 'rgba(0, 0, 0, 0)',
// third line
thirdLineGradFrom: '#2a2e40',
thirdLineGradTo: '#2a2e40',
thirdAreaGradFrom: 'rgba(42, 46, 64, 0.2)',
thirdAreaGradTo: 'rgba(42, 46, 64, 0)',
thirdShadowLineDarkBg: 'rgba(0, 0, 0, 0)',
},
// Setting up the Marketsoft specific colors for visuals
visitorsPieLegend: {
firstSection: '#D6001C',
secondSection: '#2a2e40',
},
earningPie: {
radius: ['65%', '100%'],
center: ['50%', '50%'],
fontSize: '22',
firstPieGradientLeft: '#D6001C',
firstPieGradientRight: '#D6001C',
firstPieShadowColor: 'rgba(0, 0, 0, 0)',
secondPieGradientLeft: '#2a2e40',
secondPieGradientRight: '#2a2e40',
secondPieShadowColor: 'rgba(0, 0, 0, 0)',
thirdPieGradientLeft: '#ffffff',
thirdPieGradientRight: '#ffffff',
thirdPieShadowColor: 'rgba(0, 0, 0, 0)',
},
},
} as NbJSThemeOptions;

View file

@ -86,3 +86,67 @@ $nb-themes: nb-register-theme((
slide-out-shadow-color: 0 4px 14px 0 #8f9bb3, slide-out-shadow-color: 0 4px 14px 0 #8f9bb3,
slide-out-shadow-color-rtl: 0 4px 14px 0 #8f9bb3, slide-out-shadow-color-rtl: 0 4px 14px 0 #8f9bb3,
), dark, dark); ), dark, dark);
// Add the new Marketsoft theme
$nb-themes: nb-register-theme((
layout-padding-top: 2.25rem,
menu-item-icon-margin: 0 0.5rem 0 0,
card-height-tiny: 13.5rem,
card-height-small: 21.1875rem,
card-height-medium: 28.875rem,
card-height-large: 36.5625rem,
card-height-giant: 44.25rem,
card-margin-bottom: 1.875rem,
card-header-with-select-padding-top: 0.5rem,
card-header-with-select-padding-bottom: 0.5rem,
select-min-width: 6rem,
// Marketsoft brand colors
color-primary-100: #ffe2e5,
color-primary-200: #ffb2b9,
color-primary-300: #ff7e8c,
color-primary-400: #ff4d5f,
color-primary-500: #D6001C, // Main Marketsoft red
color-primary-600: #ad0017,
color-primary-700: #840012,
color-primary-800: #5b000c,
color-primary-900: #320007,
// Custom background for the Marketsoft theme
background-basic-color-1: #ffffff,
background-basic-color-2: #f7f9fc,
background-basic-color-3: #edf1f7,
background-basic-color-4: #e4e9f2,
// Text colors
text-basic-color: #2a2e40, // Marketsoft dark blue
text-primary-color: #D6001C, // Marketsoft red
// Override some menu colors
menu-item-hover-text-color: #D6001C,
menu-item-active-text-color: #D6001C,
menu-item-active-background-color: #ffe2e5,
menu-item-icon-color: #D6001C,
// Set the slide-out colors (sidebar)
slide-out-background: #ffffff,
slide-out-shadow-color: 0 4px 14px 0 rgba(214, 0, 28, 0.1),
slide-out-shadow-color-rtl: 0 4px 14px 0 rgba(214, 0, 28, 0.1),
// Button colors
button-filled-primary-background-color: #D6001C,
button-filled-primary-border-color: #D6001C,
button-filled-primary-hover-background-color: #ad0017,
button-filled-primary-hover-border-color: #ad0017,
// Border radius
card-border-radius: 0.375rem,
border-radius: 0.375rem,
// Typography settings - use Roboto as specified in the brand guide
font-family-primary: 'Roboto, sans-serif',
font-family-secondary: 'Roboto, sans-serif',
), marketsoft, default);

View file

@ -38,6 +38,7 @@ import { DEFAULT_THEME } from './styles/theme.default';
import { COSMIC_THEME } from './styles/theme.cosmic'; import { COSMIC_THEME } from './styles/theme.cosmic';
import { CORPORATE_THEME } from './styles/theme.corporate'; import { CORPORATE_THEME } from './styles/theme.corporate';
import { DARK_THEME } from './styles/theme.dark'; import { DARK_THEME } from './styles/theme.dark';
import { MARKETSOFT_THEME } from './styles/theme.marketsoft'; // Import the new theme
const NB_MODULES = [ const NB_MODULES = [
NbLayoutModule, NbLayoutModule,
@ -82,9 +83,9 @@ export class ThemeModule {
providers: [ providers: [
...NbThemeModule.forRoot( ...NbThemeModule.forRoot(
{ {
name: 'default', name: 'marketsoft', // Set marketsoft as the default theme
}, },
[ DEFAULT_THEME, COSMIC_THEME, CORPORATE_THEME, DARK_THEME ], [ DEFAULT_THEME, COSMIC_THEME, CORPORATE_THEME, DARK_THEME, MARKETSOFT_THEME ], // Add MARKETSOFT_THEME to the themes array
).providers, ).providers,
], ],
}; };

View file

@ -0,0 +1,33 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
import { NbCardModule, NbInputModule, NbButtonModule, NbIconModule } from '@nebular/theme';
import { ProfileComponent } from './profile/profile.component';
import { SettingsComponent } from './settings/settings.component';
@NgModule({
imports: [
CommonModule,
ReactiveFormsModule,
NbCardModule,
NbInputModule,
NbButtonModule,
NbIconModule,
RouterModule.forChild([
{
path: 'profile',
component: ProfileComponent,
},
{
path: 'settings',
component: SettingsComponent,
},
]),
],
declarations: [
ProfileComponent,
SettingsComponent,
],
})
export class AccountModule { }

View file

@ -0,0 +1,74 @@
<div class="row">
<div class="col-12">
<nb-card>
<nb-card-header>
<h5>Your Profile</h5>
</nb-card-header>
<nb-card-body>
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label class="label" for="firstName">First Name</label>
<input nbInput fullWidth id="firstName" formControlName="firstName" placeholder="First Name">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="label" for="lastName">Last Name</label>
<input nbInput fullWidth id="lastName" formControlName="lastName" placeholder="Last Name">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label class="label" for="email">Email</label>
<input nbInput fullWidth id="email" formControlName="email" placeholder="Email">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="label" for="phone">Phone</label>
<input nbInput fullWidth id="phone" formControlName="phone" placeholder="Phone Number">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label class="label" for="company">Company</label>
<input nbInput fullWidth id="company" formControlName="company" placeholder="Company">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="label" for="position">Position</label>
<input nbInput fullWidth id="position" formControlName="position" placeholder="Position">
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="form-group">
<label class="label" for="address">Address</label>
<input nbInput fullWidth id="address" formControlName="address" placeholder="Address">
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-12 text-center">
<button nbButton status="primary" [disabled]="profileForm.invalid">
<nb-icon icon="save-outline"></nb-icon> Update Profile
</button>
</div>
</div>
</form>
</nb-card-body>
</nb-card>
</div>
</div>

View file

@ -0,0 +1,9 @@
.form-group {
margin-bottom: 20px;
}
.label {
display: block;
margin-bottom: 8px;
font-weight: 500;
}

View file

@ -0,0 +1,32 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'ngx-profile',
templateUrl: './profile.component.html',
styleUrls: ['./profile.component.scss']
})
export class ProfileComponent implements OnInit {
profileForm: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
this.profileForm = this.fb.group({
firstName: ['John', Validators.required],
lastName: ['Doe', Validators.required],
email: ['john.doe@example.com', [Validators.required, Validators.email]],
company: ['Acme Corp', Validators.required],
position: ['Product Manager', Validators.required],
phone: ['+1 (555) 123-4567', Validators.required],
address: ['123 Main St, New York, NY 10001', Validators.required],
});
}
onSubmit() {
if (this.profileForm.valid) {
// Handle profile update logic
console.log('Profile updated:', this.profileForm.value);
}
}
}

View file

@ -0,0 +1,101 @@
<div class="row">
<div class="col-12">
<nb-card>
<nb-card-header>
<h5>Account Settings</h5>
</nb-card-header>
<nb-card-body>
<form [formGroup]="settingsForm" (ngSubmit)="onSubmit()">
<h6 class="section-title">Notifications</h6>
<div class="settings-section">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="emailNotifications" formControlName="emailNotifications">
<label class="custom-control-label" for="emailNotifications">Email Notifications</label>
</div>
<small class="form-text text-muted">Receive verification results and updates via email</small>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="smsNotifications" formControlName="smsNotifications">
<label class="custom-control-label" for="smsNotifications">SMS Notifications</label>
</div>
<small class="form-text text-muted">Receive verification results and updates via SMS</small>
</div>
</div>
</div>
</div>
<h6 class="section-title">Security</h6>
<div class="settings-section">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" id="twoFactorAuth" formControlName="twoFactorAuth">
<label class="custom-control-label" for="twoFactorAuth">Two-Factor Authentication</label>
</div>
<small class="form-text text-muted">Enable 2FA for additional security</small>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="dataRetention">Data Retention</label>
<select class="form-control" id="dataRetention" formControlName="dataRetention">
<option value="7days">7 Days</option>
<option value="30days">30 Days</option>
<option value="90days">90 Days</option>
<option value="1year">1 Year</option>
</select>
<small class="form-text text-muted">How long to keep your verification results</small>
</div>
</div>
</div>
</div>
<h6 class="section-title">Appearance</h6>
<div class="settings-section">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="theme">Theme</label>
<select class="form-control" id="theme" formControlName="theme">
<option value="default">Default</option>
<option value="dark">Dark</option>
<option value="cosmic">Cosmic</option>
<option value="corporate">Corporate</option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="language">Language</label>
<select class="form-control" id="language" formControlName="language">
<option value="en">English</option>
<option value="es">Spanish</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="zh">Chinese</option>
<option value="ja">Japanese</option>
</select>
</div>
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-12 text-center">
<button nbButton status="primary">
<nb-icon icon="save-outline"></nb-icon> Save Settings
</button>
</div>
</div>
</form>
</nb-card-body>
</nb-card>
</div>
</div>

View file

@ -0,0 +1,19 @@
.section-title {
margin-top: 20px;
margin-bottom: 10px;
font-weight: 600;
border-bottom: 1px solid #edf1f7;
padding-bottom: 8px;
}
.settings-section {
margin-bottom: 25px;
}
.form-group {
margin-bottom: 15px;
}
.custom-control-label {
cursor: pointer;
}

View file

@ -0,0 +1,31 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'ngx-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.scss']
})
export class SettingsComponent implements OnInit {
settingsForm: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
this.settingsForm = this.fb.group({
emailNotifications: [true],
smsNotifications: [false],
twoFactorAuth: [true],
dataRetention: ['30days'],
theme: ['default'],
language: ['en'],
});
}
onSubmit() {
if (this.settingsForm.valid) {
// Handle settings update logic
console.log('Settings updated:', this.settingsForm.value);
}
}
}

View file

@ -0,0 +1,119 @@
<div class="row">
<div class="col-12">
<nb-card>
<nb-card-header>
<h5>Supported Countries & Regions</h5>
</nb-card-header>
<nb-card-body>
<p class="subtitle">IdentityPulse provides comprehensive identity verification coverage across Asia-Pacific and expanding into the Middle East.</p>
</nb-card-body>
</nb-card>
</div>
</div>
<div class="row">
<div class="col-12">
<h6 class="section-title">Active Countries</h6>
</div>
<div class="col-lg-6 col-xl-4" *ngFor="let country of activeCountries">
<nb-card class="country-card" [class.active]="country.status === 'active'">
<nb-card-header>
<div class="country-header">
<div class="country-title">
<span class="flag">{{ country.flag }}</span>
<h6>{{ country.name }}</h6>
</div>
<nb-badge [text]="country.status" status="success"></nb-badge>
</div>
</nb-card-header>
<nb-card-body>
<div class="country-stats">
<div class="stat">
<span class="label">Coverage</span>
<span class="value">{{ country.coverage }}%</span>
</div>
<div class="stat">
<span class="label">Population</span>
<span class="value">{{ country.population }}</span>
</div>
<div class="stat">
<span class="label">Databases</span>
<span class="value">{{ country.databases }}</span>
</div>
<div class="stat">
<span class="label">Updates</span>
<span class="value">{{ country.updateFrequency }}</span>
</div>
</div>
<div class="features">
<h6>Available Features</h6>
<div class="feature-tags">
<span class="tag" *ngFor="let feature of country.features">{{ feature }}</span>
</div>
</div>
<div class="regulations">
<h6>Compliance</h6>
<div class="regulation-tags">
<span class="tag" *ngFor="let reg of country.regulations">{{ reg }}</span>
</div>
</div>
</nb-card-body>
<nb-card-footer>
<button nbButton fullWidth status="primary" routerLink="/pages/identity/manual-lookup"
[queryParams]="{country: country.name.toLowerCase().replace(' ', '-')}">
<nb-icon icon="search-outline"></nb-icon>
Verify in {{ country.name }}
</button>
</nb-card-footer>
</nb-card>
</div>
</div>
<div class="row" *ngIf="comingSoonCountries.length > 0">
<div class="col-12">
<h6 class="section-title">Coming Soon</h6>
</div>
<div class="col-lg-6 col-xl-4" *ngFor="let country of comingSoonCountries">
<nb-card class="country-card coming-soon">
<nb-card-header>
<div class="country-header">
<div class="country-title">
<span class="flag">{{ country.flag }}</span>
<h6>{{ country.name }}</h6>
</div>
<nb-badge text="coming soon" status="warning"></nb-badge>
</div>
</nb-card-header>
<nb-card-body>
<div class="country-stats">
<div class="stat">
<span class="label">Population</span>
<span class="value">{{ country.population }}</span>
</div>
</div>
<div class="features">
<h6>Planned Features</h6>
<div class="feature-tags">
<span class="tag" *ngFor="let feature of country.features">{{ feature }}</span>
</div>
</div>
<div class="regulations">
<h6>Target Compliance</h6>
<div class="regulation-tags">
<span class="tag" *ngFor="let reg of country.regulations">{{ reg }}</span>
</div>
</div>
</nb-card-body>
<nb-card-footer>
<button nbButton fullWidth status="basic" disabled>
<nb-icon icon="clock-outline"></nb-icon>
Coming Soon
</button>
</nb-card-footer>
</nb-card>
</div>
</div>

View file

@ -0,0 +1,108 @@
@import '../../@theme/styles/themes';
@include nb-install-component() {
.subtitle {
color: nb-theme(text-hint-color);
margin: 0;
}
.section-title {
margin: 2rem 0 1rem 0;
font-weight: 600;
color: nb-theme(text-basic-color);
}
.country-card {
height: 100%;
transition: all 0.3s ease;
&:hover:not(.coming-soon) {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
&.coming-soon {
opacity: 0.8;
}
.country-header {
display: flex;
justify-content: space-between;
align-items: center;
.country-title {
display: flex;
align-items: center;
gap: 0.75rem;
.flag {
font-size: 2rem;
}
h6 {
margin: 0;
font-weight: 600;
}
}
}
.country-stats {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
margin-bottom: 1.5rem;
padding: 1rem;
background: nb-theme(background-basic-color-2);
border-radius: nb-theme(card-border-radius);
.stat {
display: flex;
flex-direction: column;
.label {
font-size: 0.75rem;
color: nb-theme(text-hint-color);
margin-bottom: 0.25rem;
}
.value {
font-size: 1.25rem;
font-weight: 600;
color: nb-theme(text-basic-color);
}
}
}
.features,
.regulations {
margin-bottom: 1.5rem;
h6 {
font-size: 0.875rem;
font-weight: 600;
margin: 0 0 0.75rem 0;
color: nb-theme(text-basic-color);
}
.feature-tags,
.regulation-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
.tag {
display: inline-block;
padding: 0.25rem 0.75rem;
font-size: 0.75rem;
background: nb-theme(background-basic-color-3);
border-radius: 1rem;
color: nb-theme(text-hint-color);
}
}
}
nb-card-footer {
padding: 1rem;
}
}
}

View file

@ -0,0 +1,82 @@
import { Component } from '@angular/core';
interface Country {
name: string;
flag: string;
status: 'active' | 'coming-soon';
coverage: number;
population: string;
databases: number;
updateFrequency: string;
regulations: string[];
features: string[];
}
@Component({
selector: 'ngx-countries',
templateUrl: './countries.component.html',
styleUrls: ['./countries.component.scss']
})
export class CountriesComponent {
countries: Country[] = [
{
name: 'Australia',
flag: '🇦🇺',
status: 'active',
coverage: 95,
population: '25.7M',
databases: 5,
updateFrequency: 'Daily',
regulations: ['Privacy Act 1988', 'AML/CTF Act', 'CDR'],
features: ['Full KYC', 'Document Verification', 'Biometric Matching', 'Watchlist Screening']
},
{
name: 'Indonesia',
flag: '🇮🇩',
status: 'active',
coverage: 82,
population: '273.5M',
databases: 4,
updateFrequency: 'Weekly',
regulations: ['UU PDP', 'OJK Regulations'],
features: ['Identity Verification', 'Address Validation', 'Phone Verification', 'KTP Validation']
},
{
name: 'Malaysia',
flag: '🇲🇾',
status: 'active',
coverage: 78,
population: '32.4M',
databases: 3,
updateFrequency: 'Weekly',
regulations: ['PDPA 2010', 'AMLA'],
features: ['MyKad Verification', 'Address Check', 'Phone Validation', 'Business Registry']
},
{
name: 'Japan',
flag: '🇯🇵',
status: 'active',
coverage: 88,
population: '125.8M',
databases: 4,
updateFrequency: 'Daily',
regulations: ['APPI', 'FIEA'],
features: ['My Number Verification', 'Address Validation', 'Corporate Registry', 'AML Check']
},
{
name: 'Saudi Arabia',
flag: '🇸🇦',
status: 'coming-soon',
coverage: 0,
population: '34.8M',
databases: 0,
updateFrequency: 'TBD',
regulations: ['PDPL', 'SAMA Regulations'],
features: ['National ID Verification', 'Iqama Validation', 'Business Registry', 'AML Screening']
}
];
activeCountries = this.countries.filter(c => c.status === 'active');
comingSoonCountries = this.countries.filter(c => c.status === 'coming-soon');
}

View file

@ -0,0 +1,30 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import {
NbCardModule,
NbButtonModule,
NbIconModule,
NbBadgeModule
} from '@nebular/theme';
import { CountriesComponent } from './countries.component';
@NgModule({
imports: [
CommonModule,
RouterModule.forChild([
{
path: '',
component: CountriesComponent,
},
]),
NbCardModule,
NbButtonModule,
NbIconModule,
NbBadgeModule
],
declarations: [
CountriesComponent,
],
})
export class CountriesModule { }

View file

@ -0,0 +1,42 @@
<nb-card>
<nb-card-header>
<h6>Trusted by Industry Leaders</h6>
</nb-card-header>
<nb-card-body>
<div class="clients-grid">
<div class="client-card" *ngFor="let client of clients">
<div class="client-logo">
<div class="logo-placeholder">
{{ client.name }}
</div>
</div>
<div class="client-info">
<h6 class="client-name">{{ client.name }}</h6>
<span class="client-industry">{{ client.industry }}</span>
<p class="client-description">{{ client.description }}</p>
<div class="verification-count">
<nb-icon icon="checkmark-circle-2-outline" pack="eva"></nb-icon>
<span>{{ client.verifications }} verifications</span>
</div>
</div>
</div>
</div>
<div class="showcase-footer">
<div class="trust-metrics">
<div class="metric">
<span class="metric-value">50+</span>
<span class="metric-label">Enterprise Clients</span>
</div>
<div class="metric">
<span class="metric-value">15M+</span>
<span class="metric-label">Monthly Verifications</span>
</div>
<div class="metric">
<span class="metric-value">99.9%</span>
<span class="metric-label">Uptime SLA</span>
</div>
</div>
</div>
</nb-card-body>
</nb-card>

View file

@ -0,0 +1,137 @@
@import '../../../@theme/styles/themes';
@import 'bootstrap/scss/mixins/breakpoints';
@import '@nebular/theme/styles/global/breakpoints';
@include nb-install-component() {
nb-card {
height: 100%;
}
nb-card-header {
h6 {
margin: 0;
font-weight: 600;
}
}
.clients-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
margin-bottom: 2rem;
@include media-breakpoint-down(sm) {
grid-template-columns: 1fr;
}
}
.client-card {
display: flex;
align-items: center;
padding: 1rem;
border: 1px solid nb-theme(border-basic-color-3);
border-radius: nb-theme(card-border-radius);
transition: all 0.3s ease;
cursor: pointer;
&:hover {
border-color: nb-theme(color-primary-default);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
}
.client-logo {
flex-shrink: 0;
width: 60px;
height: 60px;
margin-right: 1rem;
.logo-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: nb-theme(background-basic-color-3);
border-radius: nb-theme(card-border-radius);
font-size: 0.625rem;
font-weight: 600;
text-align: center;
padding: 0.5rem;
color: nb-theme(text-hint-color);
}
}
.client-info {
flex: 1;
min-width: 0;
.client-name {
margin: 0 0 0.25rem 0;
font-size: 0.875rem;
font-weight: 600;
color: nb-theme(text-basic-color);
}
.client-industry {
display: inline-block;
font-size: 0.75rem;
color: nb-theme(text-hint-color);
margin-bottom: 0.5rem;
}
.client-description {
font-size: 0.75rem;
color: nb-theme(text-hint-color);
margin: 0 0 0.5rem 0;
display: none;
@include media-breakpoint-up(lg) {
display: block;
}
}
.verification-count {
display: flex;
align-items: center;
gap: 0.25rem;
font-size: 0.75rem;
color: nb-theme(color-success-default);
nb-icon {
font-size: 1rem;
}
}
}
.showcase-footer {
border-top: 1px solid nb-theme(border-basic-color-3);
padding-top: 1.5rem;
margin-top: 1rem;
}
.trust-metrics {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
text-align: center;
.metric {
display: flex;
flex-direction: column;
.metric-value {
font-size: 1.5rem;
font-weight: 700;
color: nb-theme(color-primary-default);
margin-bottom: 0.25rem;
}
.metric-label {
font-size: 0.75rem;
color: nb-theme(text-hint-color);
}
}
}
}

View file

@ -0,0 +1,79 @@
import { Component, OnDestroy } from '@angular/core';
import { NbThemeService } from '@nebular/theme';
import { takeWhile } from 'rxjs/operators';
interface Client {
name: string;
logo: string;
industry: string;
description: string;
verifications: string;
}
@Component({
selector: 'ngx-client-showcase',
styleUrls: ['./client-showcase.component.scss'],
templateUrl: './client-showcase.component.html',
})
export class ClientShowcaseComponent implements OnDestroy {
private alive = true;
currentTheme: string;
clients: Client[] = [
{
name: 'LexisNexis',
logo: 'assets/images/clients/lexisnexis.png',
industry: 'Risk Solutions',
description: 'Global leader in legal and business information',
verifications: '2.3M+'
},
{
name: 'Data Zoo',
logo: 'assets/images/clients/datazoo.png',
industry: 'Identity Verification',
description: 'Identity verification and fraud prevention',
verifications: '1.8M+'
},
{
name: 'Commonwealth Bank',
logo: 'assets/images/clients/cba.png',
industry: 'Banking',
description: 'Australia\'s leading financial institution',
verifications: '3.1M+'
},
{
name: 'Westpac',
logo: 'assets/images/clients/westpac.png',
industry: 'Banking',
description: 'Major Australian bank and financial services',
verifications: '2.7M+'
},
{
name: 'Telstra',
logo: 'assets/images/clients/telstra.png',
industry: 'Telecommunications',
description: 'Australia\'s largest telecommunications company',
verifications: '1.5M+'
},
{
name: 'ANZ Bank',
logo: 'assets/images/clients/anz.png',
industry: 'Banking',
description: 'Leading bank across Australia and New Zealand',
verifications: '2.4M+'
}
];
constructor(private themeService: NbThemeService) {
this.themeService.getJsTheme()
.pipe(takeWhile(() => this.alive))
.subscribe(theme => {
this.currentTheme = theme.name;
});
}
ngOnDestroy() {
this.alive = false;
}
}

View file

@ -0,0 +1,40 @@
<nb-card>
<nb-card-header>
<h6>Compliance & Data Residency</h6>
</nb-card-header>
<nb-card-body>
<div class="compliance-list">
<div class="compliance-item" *ngFor="let item of complianceItems">
<div class="item-header">
<span class="region">{{ item.region }}</span>
<nb-icon
[icon]="getStatusIcon(item.status)"
[status]="getStatusColor(item.status)"
pack="eva">
</nb-icon>
</div>
<div class="regulations">
<span class="regulation" *ngFor="let reg of item.regulations">
{{ reg }}
</span>
</div>
<div class="hosting-model">
<nb-icon icon="hard-drive-outline" pack="eva"></nb-icon>
<span>{{ item.hostingModel }}</span>
</div>
</div>
</div>
<div class="certifications">
<h6>Certifications</h6>
<div class="cert-badges">
<div class="badge" *ngFor="let cert of certifications">
<nb-icon [icon]="cert.icon" pack="eva" status="primary"></nb-icon>
<span>{{ cert.name }}</span>
</div>
</div>
</div>
</nb-card-body>
</nb-card>

View file

@ -0,0 +1,92 @@
@import '../../../@theme/styles/themes';
@include nb-install-component() {
nb-card-header h6 {
margin: 0;
font-weight: 600;
}
.compliance-list {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 1.5rem;
}
.compliance-item {
padding: 1rem;
border: 1px solid nb-theme(border-basic-color-3);
border-radius: nb-theme(card-border-radius);
.item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
.region {
font-weight: 600;
color: nb-theme(text-basic-color);
}
nb-icon {
font-size: 1.25rem;
}
}
.regulations {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 0.75rem;
.regulation {
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
background: nb-theme(background-basic-color-3);
border-radius: nb-theme(border-radius);
color: nb-theme(text-hint-color);
}
}
.hosting-model {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.875rem;
color: nb-theme(text-hint-color);
nb-icon {
font-size: 1rem;
}
}
}
.certifications {
h6 {
margin: 0 0 0.75rem 0;
font-weight: 600;
color: nb-theme(text-basic-color);
}
.cert-badges {
display: flex;
flex-direction: column;
gap: 0.5rem;
.badge {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
background: nb-theme(background-basic-color-2);
border-radius: nb-theme(card-border-radius);
font-size: 0.875rem;
nb-icon {
font-size: 1.25rem;
}
}
}
}
}

View file

@ -0,0 +1,75 @@
import { Component } from '@angular/core';
interface ComplianceItem {
region: string;
regulations: string[];
status: 'compliant' | 'in-progress' | 'planned';
hostingModel: string;
}
@Component({
selector: 'ngx-compliance-summary',
styleUrls: ['./compliance-summary.component.scss'],
templateUrl: './compliance-summary.component.html',
})
export class ComplianceSummaryComponent {
complianceItems: ComplianceItem[] = [
{
region: 'Australia',
regulations: ['Privacy Act 1988', 'AML/CTF Act', 'CDR'],
status: 'compliant',
hostingModel: 'Local data residency'
},
{
region: 'Indonesia',
regulations: ['UU PDP', 'OJK Regulations'],
status: 'compliant',
hostingModel: 'Local data center'
},
{
region: 'Malaysia',
regulations: ['PDPA 2010', 'AMLA'],
status: 'compliant',
hostingModel: 'Regional hosting'
},
{
region: 'Japan',
regulations: ['APPI', 'FIEA'],
status: 'compliant',
hostingModel: 'Local data residency'
}
];
certifications = [
{ name: 'ISO 27001', icon: 'shield-outline' },
{ name: 'SOC 2 Type II', icon: 'lock-outline' },
{ name: 'GDPR Ready', icon: 'checkmark-square-outline' }
];
getStatusColor(status: string): string {
switch (status) {
case 'compliant':
return 'success';
case 'in-progress':
return 'warning';
case 'planned':
return 'info';
default:
return 'basic';
}
}
getStatusIcon(status: string): string {
switch (status) {
case 'compliant':
return 'checkmark-circle-2-outline';
case 'in-progress':
return 'sync-outline';
case 'planned':
return 'calendar-outline';
default:
return 'minus-circle-outline';
}
}
}

View file

@ -0,0 +1,44 @@
<nb-card size="large">
<nb-card-header>
<span>Country Coverage & Availability</span>
<nb-select [(selected)]="selectedRegion" class="region-select">
<nb-option value="all">All Regions</nb-option>
<nb-option value="apac">APAC</nb-option>
<nb-option value="mena">MENA</nb-option>
<nb-option value="europe">Europe</nb-option>
</nb-select>
</nb-card-header>
<nb-card-body>
<div class="country-list">
<div class="country-item" *ngFor="let country of countries">
<div class="country-header">
<div class="country-info">
<h6 class="country-name">{{ country.name }}</h6>
<nb-icon
[icon]="getStatusIcon(country.status)"
[status]="getStatusColor(country.status)"
pack="eva">
</nb-icon>
</div>
<div class="country-stats">
<span class="records">{{ country.records }} records</span>
<span class="update-freq">{{ country.updateFrequency }} updates</span>
</div>
</div>
<div class="coverage-section">
<div class="coverage-header">
<span class="coverage-label">Coverage</span>
<span class="coverage-value">{{ country.coverage }}%</span>
</div>
<nb-progress-bar
[value]="country.coverage"
[status]="getCoverageStatus(country.coverage)"
size="tiny">
</nb-progress-bar>
</div>
</div>
</div>
</nb-card-body>
</nb-card>

View file

@ -0,0 +1,117 @@
@import '../../../@theme/styles/themes';
@import 'bootstrap/scss/mixins/breakpoints';
@import '@nebular/theme/styles/global/breakpoints';
@include nb-install-component() {
nb-card-header {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: nb-theme(card-header-with-select-padding-top);
padding-bottom: nb-theme(card-header-with-select-padding-bottom);
}
.region-select {
margin-left: auto;
min-width: 8rem;
}
.country-list {
max-height: 400px;
overflow-y: auto;
padding-right: 0.5rem;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: nb-theme(background-basic-color-2);
}
&::-webkit-scrollbar-thumb {
background: nb-theme(background-basic-color-4);
border-radius: 3px;
}
}
.country-item {
padding: 1rem;
border: 1px solid nb-theme(border-basic-color-3);
border-radius: nb-theme(card-border-radius);
margin-bottom: 1rem;
transition: all 0.3s ease;
&:hover {
border-color: nb-theme(color-primary-default);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
&:last-child {
margin-bottom: 0;
}
}
.country-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 0.75rem;
}
.country-info {
display: flex;
align-items: center;
gap: 0.5rem;
.country-name {
margin: 0;
font-weight: 600;
color: nb-theme(text-basic-color);
}
nb-icon {
font-size: 1.25rem;
}
}
.country-stats {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 0.25rem;
span {
font-size: 0.875rem;
color: nb-theme(text-hint-color);
}
}
.coverage-section {
.coverage-header {
display: flex;
justify-content: space-between;
margin-bottom: 0.5rem;
.coverage-label {
font-size: 0.875rem;
color: nb-theme(text-hint-color);
}
.coverage-value {
font-weight: 600;
color: nb-theme(text-basic-color);
}
}
nb-progress-bar {
height: 0.5rem;
}
}
@include media-breakpoint-down(sm) {
.country-stats {
display: none;
}
}
}

View file

@ -0,0 +1,101 @@
import { Component, OnDestroy } from '@angular/core';
import { NbThemeService } from '@nebular/theme';
import { takeWhile } from 'rxjs/operators';
interface CountryData {
name: string;
coverage: number;
records: string;
updateFrequency: string;
status: 'active' | 'coming-soon' | 'limited';
}
@Component({
selector: 'ngx-country-coverage',
styleUrls: ['./country-coverage.component.scss'],
templateUrl: './country-coverage.component.html',
})
export class CountryCoverageComponent implements OnDestroy {
private alive = true;
countries: CountryData[] = [
{
name: 'Australia',
coverage: 95,
records: '25.6M',
updateFrequency: 'Daily',
status: 'active'
},
{
name: 'Indonesia',
coverage: 82,
records: '180.2M',
updateFrequency: 'Weekly',
status: 'active'
},
{
name: 'Malaysia',
coverage: 78,
records: '28.4M',
updateFrequency: 'Weekly',
status: 'active'
},
{
name: 'Japan',
coverage: 88,
records: '126.8M',
updateFrequency: 'Daily',
status: 'active'
},
];
selectedRegion = 'all';
regions = ['all', 'apac', 'mena', 'europe'];
currentTheme: string;
constructor(private themeService: NbThemeService) {
this.themeService.getJsTheme()
.pipe(takeWhile(() => this.alive))
.subscribe(theme => {
this.currentTheme = theme.name;
});
}
ngOnDestroy() {
this.alive = false;
}
getStatusIcon(status: string): string {
switch (status) {
case 'active':
return 'checkmark-circle-2-outline';
case 'coming-soon':
return 'clock-outline';
case 'limited':
return 'alert-triangle-outline';
default:
return 'minus-circle-outline';
}
}
getStatusColor(status: string): string {
switch (status) {
case 'active':
return 'success';
case 'coming-soon':
return 'warning';
case 'limited':
return 'danger';
default:
return 'basic';
}
}
getCoverageStatus(coverage: number): string {
if (coverage >= 80) return 'success';
if (coverage >= 60) return 'warning';
return 'danger';
}
}

View file

@ -1,42 +1,45 @@
<div class="row"> <div class="row">
<div class="col-xxxl-3 col-md-6" *ngFor="let statusCard of statusCards"> <div class="col-xxxl-3 col-md-6" *ngFor="let statusCard of statusCards">
<ngx-status-card [title]="statusCard.title" [type]="statusCard.type"> <ngx-metric-card
<i [ngClass]="statusCard.iconClass"></i> [title]="statusCard.title"
</ngx-status-card> [type]="statusCard.type"
[value]="statusCard.value"
[unitOfMeasurement]="statusCard.unitOfMeasurement"
[iconClass]="statusCard.iconClass">
</ngx-metric-card>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xxxl-3 col-xxl-4 col-lg-5 col-md-6"> <div class="col-xxxl-6 col-xxl-7 col-lg-7 col-md-12">
<ngx-temperature></ngx-temperature> <ngx-country-coverage></ngx-country-coverage>
</div> </div>
<div class="col-xxxl-9 col-xxl-8 col-lg-7 col-md-6"> <div class="col-xxxl-6 col-xxl-5 col-lg-5 col-md-12">
<ngx-electricity></ngx-electricity> <ngx-client-showcase></ngx-client-showcase>
</div>
</div>
<div class="row mt-4">
<div class="col-xxxl-8 col-xl-12">
<ngx-data-centers-map></ngx-data-centers-map>
</div>
<div class="col-xxxl-4 col-xxl-4 col-lg-5 col-md-6">
<ngx-recent-verifications></ngx-recent-verifications>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xxxl-9 col-xl-12"> <div class="col-xxxl-4 col-xxl-4 col-lg-4 col-md-6">
<ngx-rooms></ngx-rooms> <ngx-pricing-regions></ngx-pricing-regions>
</div> </div>
<div class="col-xxxl-3 col-xxl-4 col-lg-7 col-md-6"> <div class="col-xxxl-4 col-xxl-4 col-lg-4 col-md-6">
<ngx-contacts></ngx-contacts> <ngx-compliance-summary></ngx-compliance-summary>
</div> </div>
<div class="col-xxxl-3 col-xxl-4 col-lg-5 col-md-6"> <div class="col-xxxl-4 col-xxl-4 col-lg-4 col-md-12">
<ngx-solar [chartValue]="solarValue"></ngx-solar> <ngx-differentiators></ngx-differentiators>
<ngx-kitten></ngx-kitten>
</div>
<div class="col-xxxl-3 col-xxl-4 col-md-5">
<ngx-traffic></ngx-traffic>
<ngx-weather></ngx-weather>
</div>
<div class="col-xxxl-6 col-xxl-12 col-md-7">
<ngx-security-cameras></ngx-security-cameras>
</div> </div>
</div> </div>

View file

@ -1,10 +1,11 @@
import {Component, OnDestroy} from '@angular/core'; import { Component, OnDestroy } from '@angular/core';
import { NbThemeService } from '@nebular/theme'; import { NbThemeService } from '@nebular/theme';
import { takeWhile } from 'rxjs/operators' ; import { takeWhile } from 'rxjs/operators';
import { SolarData } from '../../@core/data/solar';
interface CardSettings { interface CardSettings {
title: string; title: string;
value: string;
unitOfMeasurement: string;
iconClass: string; iconClass: string;
type: string; type: string;
} }
@ -18,35 +19,46 @@ export class DashboardComponent implements OnDestroy {
private alive = true; private alive = true;
solarValue: number; // Key metrics for IdentityPulse
lightCard: CardSettings = { verificationCard: CardSettings = {
title: 'Light', title: 'Total Verifications',
iconClass: 'nb-lightbulb', value: '1,247',
unitOfMeasurement: 'today',
iconClass: 'nb-checkmark-circle',
type: 'primary', type: 'primary',
}; };
rollerShadesCard: CardSettings = {
title: 'Roller Shades', matchRateCard: CardSettings = {
iconClass: 'nb-roller-shades', title: 'Average Match Rate',
value: '87.3',
unitOfMeasurement: '%',
iconClass: 'nb-bar-chart',
type: 'success', type: 'success',
}; };
wirelessAudioCard: CardSettings = {
title: 'Wireless Audio', countriesCard: CardSettings = {
iconClass: 'nb-audio', title: 'Active Countries',
value: '4',
unitOfMeasurement: 'regions',
iconClass: 'nb-location',
type: 'info', type: 'info',
}; };
coffeeMakerCard: CardSettings = {
title: 'Coffee Maker', apiResponseCard: CardSettings = {
iconClass: 'nb-coffee-maker', title: 'API Response Time',
value: '245',
unitOfMeasurement: 'ms',
iconClass: 'nb-gear',
type: 'warning', type: 'warning',
}; };
statusCards: string; statusCards: CardSettings[];
commonStatusCardsSet: CardSettings[] = [ commonStatusCardsSet: CardSettings[] = [
this.lightCard, this.verificationCard,
this.rollerShadesCard, this.matchRateCard,
this.wirelessAudioCard, this.countriesCard,
this.coffeeMakerCard, this.apiResponseCard,
]; ];
statusCardsByThemes: { statusCardsByThemes: {
@ -54,42 +66,20 @@ export class DashboardComponent implements OnDestroy {
cosmic: CardSettings[]; cosmic: CardSettings[];
corporate: CardSettings[]; corporate: CardSettings[];
dark: CardSettings[]; dark: CardSettings[];
marketsoft: CardSettings[];
} = { } = {
default: this.commonStatusCardsSet, default: this.commonStatusCardsSet,
cosmic: this.commonStatusCardsSet, cosmic: this.commonStatusCardsSet,
corporate: [ corporate: this.commonStatusCardsSet,
{
...this.lightCard,
type: 'warning',
},
{
...this.rollerShadesCard,
type: 'primary',
},
{
...this.wirelessAudioCard,
type: 'danger',
},
{
...this.coffeeMakerCard,
type: 'info',
},
],
dark: this.commonStatusCardsSet, dark: this.commonStatusCardsSet,
marketsoft: this.commonStatusCardsSet,
}; };
constructor(private themeService: NbThemeService, constructor(private themeService: NbThemeService) {
private solarService: SolarData) {
this.themeService.getJsTheme() this.themeService.getJsTheme()
.pipe(takeWhile(() => this.alive)) .pipe(takeWhile(() => this.alive))
.subscribe(theme => { .subscribe(theme => {
this.statusCards = this.statusCardsByThemes[theme.name]; this.statusCards = this.statusCardsByThemes[theme.name];
});
this.solarService.getSolarData()
.pipe(takeWhile(() => this.alive))
.subscribe((data) => {
this.solarValue = data;
}); });
} }

View file

@ -9,6 +9,7 @@ import {
NbSelectModule, NbSelectModule,
NbListModule, NbListModule,
NbIconModule, NbIconModule,
NbProgressBarModule,
} from '@nebular/theme'; } from '@nebular/theme';
import { NgxEchartsModule } from 'ngx-echarts'; import { NgxEchartsModule } from 'ngx-echarts';
@ -31,6 +32,19 @@ import { TrafficComponent } from './traffic/traffic.component';
import { TrafficChartComponent } from './traffic/traffic-chart.component'; import { TrafficChartComponent } from './traffic/traffic-chart.component';
import { FormsModule } from '@angular/forms'; 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({ @NgModule({
imports: [ imports: [
FormsModule, FormsModule,
@ -45,6 +59,7 @@ import { FormsModule } from '@angular/forms';
NbListModule, NbListModule,
NbIconModule, NbIconModule,
NbButtonModule, NbButtonModule,
NbProgressBarModule,
NgxEchartsModule, NgxEchartsModule,
], ],
declarations: [ declarations: [
@ -64,6 +79,15 @@ import { FormsModule } from '@angular/forms';
SolarComponent, SolarComponent,
TrafficComponent, TrafficComponent,
TrafficChartComponent, TrafficChartComponent,
// IdentityPulse components
MetricCardComponent,
CountryCoverageComponent,
ClientShowcaseComponent,
DataCentersMapComponent,
RecentVerificationsComponent,
PricingRegionsComponent,
ComplianceSummaryComponent,
DifferentiatorsComponent,
], ],
}) })
export class DashboardModule { } export class DashboardModule { }

View file

@ -0,0 +1,38 @@
<nb-card>
<nb-card-header>
<div class="header-container">
<h6>Global Identity Verification Coverage</h6>
<div class="legend">
<span class="legend-item">
<span class="dot online"></span>
Online
</span>
<span class="legend-item">
<span class="dot maintenance"></span>
Maintenance
</span>
<span class="legend-item">
<span class="dot offline"></span>
Offline
</span>
</div>
</div>
</nb-card-header>
<nb-card-body>
<div id="map" class="map-container"></div>
<div class="map-stats">
<div class="stat">
<nb-icon icon="globe-2-outline" pack="eva"></nb-icon>
<span>{{ getCountryCount() }} Countries</span>
</div>
<div class="stat">
<nb-icon icon="hard-drive-outline" pack="eva"></nb-icon>
<span>{{ getTotalDatabases() }} Databases</span>
</div>
<div class="stat">
<nb-icon icon="activity-outline" pack="eva"></nb-icon>
<span>{{ getOnlineCount() }} Online</span>
</div>
</div>
</nb-card-body>
</nb-card>

View file

@ -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);
}
}
}
}

View file

@ -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 = `
<div style="
background-color: ${colors[status]};
width: 24px;
height: 24px;
border-radius: 50%;
border: 3px solid white;
box-shadow: 0 2px 4px rgba(0,0,0,0.3);
"></div>
`;
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 `
<div style="padding: 10px; min-width: 200px;">
<h6 style="margin: 0 0 10px 0; font-weight: 600;">${dc.name}</h6>
<div style="font-size: 14px; line-height: 1.6;">
<div><strong>City:</strong> ${dc.city}, ${dc.country}</div>
<div><strong>Status:</strong> <span style="color: ${statusColors[dc.status]}; font-weight: 600;">${dc.status}</span></div>
<div><strong>Databases:</strong> ${dc.databases}</div>
<div><strong>Response Time:</strong> ${dc.responseTime}ms</div>
</div>
<div style="margin-top: 10px; padding-top: 10px; border-top: 1px solid #e4e9f2; text-align: center;">
<span style="color: #0095ff; font-size: 12px; cursor: pointer;">
<strong>Click to query this region </strong>
</span>
</div>
</div>
`;
}
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();
}
}
}

View file

@ -0,0 +1,27 @@
<nb-card>
<nb-card-header>
<h6>Why IdentityPulse is Different</h6>
</nb-card-header>
<nb-card-body>
<div class="differentiators-grid">
<div class="differentiator" *ngFor="let item of differentiators">
<div class="icon-wrapper">
<nb-icon [icon]="item.icon" pack="eva"></nb-icon>
</div>
<div class="content">
<h6 class="title">{{ item.title }}</h6>
<p class="description">{{ item.description }}</p>
<span class="metric" *ngIf="item.metric">{{ item.metric }}</span>
</div>
</div>
</div>
<div class="cta-section">
<p class="cta-text">Experience the difference with a live demo</p>
<button nbButton status="primary" fullWidth>
Schedule Demo
</button>
</div>
</nb-card-body>
</nb-card>

View file

@ -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);
}
}
}

View file

@ -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'
}
];
}

View file

@ -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;
}
}
}
}

View file

@ -0,0 +1,30 @@
import { Component, Input } from '@angular/core';
@Component({
selector: 'ngx-metric-card',
styleUrls: ['./metric-card.component.scss'],
template: `
<nb-card>
<div class="icon-container">
<div class="icon status-{{ type }}">
<i [ngClass]="iconClass"></i>
</div>
</div>
<div class="details">
<div class="title">{{ title }}</div>
<div class="status-value">
<span class="value">{{ value }}</span>
<span class="unit">{{ unitOfMeasurement }}</span>
</div>
</div>
</nb-card>
`,
})
export class MetricCardComponent {
@Input() title: string;
@Input() type: string;
@Input() value: string;
@Input() unitOfMeasurement: string;
@Input() iconClass: string;
}

View file

@ -0,0 +1,47 @@
<nb-card>
<nb-card-header>
<h6>Regional Pricing</h6>
</nb-card-header>
<nb-card-body>
<div class="pricing-tiers">
<div class="tier" *ngFor="let tier of pricingTiers">
<div class="tier-header">
<span class="region-flag">{{ tier.flag }}</span>
<h6 class="region-name">{{ tier.region }}</h6>
</div>
<div class="pricing-details">
<div class="base-price">
<span class="currency">{{ tier.currency }}</span>
<span class="price">${{ tier.basePrice }}</span>
<span class="period">/month</span>
</div>
<div class="per-verification">
<span class="label">Per verification:</span>
<span class="value">${{ tier.perVerification }}</span>
</div>
<div class="volume-discount">
<nb-icon icon="pricetags-outline" pack="eva"></nb-icon>
<span>{{ tier.volumeDiscount }}</span>
</div>
</div>
</div>
</div>
<div class="features">
<h6>All plans include:</h6>
<ul>
<li *ngFor="let feature of features">
<nb-icon icon="checkmark-outline" pack="eva" status="success"></nb-icon>
{{ feature }}
</li>
</ul>
</div>
<button nbButton fullWidth status="primary">
Contact Sales
</button>
</nb-card-body>
</nb-card>

View file

@ -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;
}
}
}
}
}

View file

@ -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'
];
}

View file

@ -0,0 +1,41 @@
<nb-card>
<nb-card-header>
<h6>Recent Verifications</h6>
<button nbButton ghost size="tiny" status="primary">View All</button>
</nb-card-header>
<nb-card-body>
<nb-list>
<nb-list-item *ngFor="let verification of verifications">
<div class="verification-item">
<div class="verification-header">
<div class="country-info">
<span class="country-flag">{{ getCountryFlag(verification.country) }}</span>
<span class="country-name">{{ verification.country }}</span>
</div>
<span class="timestamp">{{ getTimeAgo(verification.timestamp) }}</span>
</div>
<div class="verification-details">
<div class="type-and-id">
<span class="type">{{ verification.type }}</span>
<span class="id">{{ verification.id }}</span>
</div>
<div class="score-and-status">
<nb-progress-bar
[value]="verification.matchScore"
[status]="getStatusColor(verification.status)"
size="tiny"
[displayValue]="true">
</nb-progress-bar>
<nb-icon
[icon]="getStatusIcon(verification.status)"
[status]="getStatusColor(verification.status)"
pack="eva">
</nb-icon>
</div>
</div>
</div>
</nb-list-item>
</nb-list>
</nb-card-body>
</nb-card>

View file

@ -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;
}
}
}
}

View file

@ -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;
}
}

View file

@ -4,7 +4,7 @@ import { Component, Input } from '@angular/core';
selector: 'ngx-status-card', selector: 'ngx-status-card',
styleUrls: ['./status-card.component.scss'], styleUrls: ['./status-card.component.scss'],
template: ` template: `
<nb-card (click)="on = !on" [ngClass]="{'off': !on}"> <nb-card>
<div class="icon-container"> <div class="icon-container">
<div class="icon status-{{ type }}"> <div class="icon status-{{ type }}">
<ng-content></ng-content> <ng-content></ng-content>
@ -13,14 +13,17 @@ import { Component, Input } from '@angular/core';
<div class="details"> <div class="details">
<div class="title h5">{{ title }}</div> <div class="title h5">{{ title }}</div>
<div class="status paragraph-2">{{ on ? 'ON' : 'OFF' }}</div> <div class="status-value">
<span class="value h2">{{ value }}</span>
<span class="unit">{{ unitOfMeasurement }}</span>
</div>
</div> </div>
</nb-card> </nb-card>
`, `,
}) })
export class StatusCardComponent { export class StatusCardComponent {
@Input() title: string; @Input() title: string;
@Input() type: string; @Input() type: string;
@Input() on = true; @Input() value: string;
@Input() unitOfMeasurement: string;
} }

View file

@ -0,0 +1,46 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
import {
NbCardModule,
NbButtonModule,
NbInputModule,
NbSelectModule,
NbSpinnerModule,
NbProgressBarModule,
NbIconModule,
NbListModule
} from '@nebular/theme';
import { ManualLookupComponent } from './manual-lookup/manual-lookup.component';
import { ResultsHistoryComponent } from './results-history/results-history.component';
@NgModule({
imports: [
CommonModule,
ReactiveFormsModule,
RouterModule.forChild([
{
path: 'manual-lookup',
component: ManualLookupComponent,
},
{
path: 'results-history',
component: ResultsHistoryComponent,
},
]),
NbCardModule,
NbButtonModule,
NbInputModule,
NbSelectModule,
NbSpinnerModule,
NbProgressBarModule,
NbIconModule,
NbListModule
],
declarations: [
ManualLookupComponent,
ResultsHistoryComponent,
],
})
export class IdentityModule { }

View file

@ -0,0 +1,258 @@
<div class="row">
<div class="col-12 col-lg-8">
<nb-card>
<nb-card-header>
<h5>Identity Verification - Manual Lookup</h5>
</nb-card-header>
<nb-card-body>
<form [formGroup]="identityForm" (ngSubmit)="onSubmit()">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="firstName" class="label">First Name *</label>
<input nbInput
fullWidth
id="firstName"
formControlName="firstName"
placeholder="Enter first name"
status="basic"
[status]="identityForm.get('firstName').invalid && identityForm.get('firstName').touched ? 'danger' : 'basic'">
<span class="error-message" *ngIf="identityForm.get('firstName').invalid && identityForm.get('firstName').touched">
First name is required
</span>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="lastName" class="label">Last Name *</label>
<input nbInput
fullWidth
id="lastName"
formControlName="lastName"
placeholder="Enter last name"
[status]="identityForm.get('lastName').invalid && identityForm.get('lastName').touched ? 'danger' : 'basic'">
<span class="error-message" *ngIf="identityForm.get('lastName').invalid && identityForm.get('lastName').touched">
Last name is required
</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="dateOfBirth" class="label">Date of Birth *</label>
<input nbInput
fullWidth
id="dateOfBirth"
type="date"
formControlName="dateOfBirth"
placeholder="YYYY-MM-DD"
[status]="identityForm.get('dateOfBirth').invalid && identityForm.get('dateOfBirth').touched ? 'danger' : 'basic'">
<span class="error-message" *ngIf="identityForm.get('dateOfBirth').invalid && identityForm.get('dateOfBirth').touched">
Date of birth is required
</span>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="country" class="label">Country *</label>
<nb-select fullWidth
id="country"
formControlName="country"
placeholder="Select Country"
[status]="identityForm.get('country').invalid && identityForm.get('country').touched ? 'danger' : 'basic'">
<nb-option value="australia">Australia</nb-option>
<nb-option value="indonesia">Indonesia</nb-option>
<nb-option value="japan">Japan</nb-option>
<nb-option value="malaysia">Malaysia</nb-option>
</nb-select>
<span class="error-message" *ngIf="identityForm.get('country').invalid && identityForm.get('country').touched">
Please select a country
</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="identificationNumber" class="label">ID Number</label>
<input nbInput
fullWidth
id="identificationNumber"
formControlName="identificationNumber"
placeholder="Enter identification number"
status="basic">
<span class="hint-text">Optional: National ID, Passport, or Driver's License</span>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="email" class="label">Email</label>
<input nbInput
fullWidth
id="email"
type="email"
formControlName="email"
placeholder="Enter email address"
[status]="identityForm.get('email').invalid && identityForm.get('email').touched ? 'danger' : 'basic'">
<span class="error-message" *ngIf="identityForm.get('email').invalid && identityForm.get('email').touched">
Please enter a valid email
</span>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="phone" class="label">Phone Number</label>
<input nbInput
fullWidth
id="phone"
formControlName="phone"
placeholder="Enter phone number"
status="basic">
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="address" class="label">Address</label>
<input nbInput
fullWidth
id="address"
formControlName="address"
placeholder="Enter address"
status="basic">
</div>
</div>
</div>
<div class="row mt-4">
<div class="col-12">
<button nbButton
fullWidth
status="primary"
size="large"
[disabled]="identityForm.invalid || isSubmitting"
[nbSpinner]="isSubmitting"
nbSpinnerStatus="primary"
nbSpinnerSize="small">
<nb-icon icon="search-outline" *ngIf="!isSubmitting"></nb-icon>
{{ isSubmitting ? 'Verifying...' : 'Verify Identity' }}
</button>
</div>
</div>
</form>
</nb-card-body>
</nb-card>
</div>
<div class="col-12 col-lg-4">
<nb-card *ngIf="!result" class="info-card">
<nb-card-header>
<h6>Verification Tips</h6>
</nb-card-header>
<nb-card-body>
<nb-list>
<nb-list-item>
<nb-icon icon="checkmark-circle-outline" status="success"></nb-icon>
<span>Use full legal names as they appear on official documents</span>
</nb-list-item>
<nb-list-item>
<nb-icon icon="checkmark-circle-outline" status="success"></nb-icon>
<span>Ensure date format is YYYY-MM-DD</span>
</nb-list-item>
<nb-list-item>
<nb-icon icon="checkmark-circle-outline" status="success"></nb-icon>
<span>Include middle names if available</span>
</nb-list-item>
<nb-list-item>
<nb-icon icon="checkmark-circle-outline" status="success"></nb-icon>
<span>Double-check spelling and formatting</span>
</nb-list-item>
</nb-list>
</nb-card-body>
</nb-card>
<nb-card *ngIf="result" class="result-card">
<nb-card-header>
<h6>Verification Results</h6>
</nb-card-header>
<nb-card-body>
<div class="match-result">
<h6>Overall Match Confidence</h6>
<nb-progress-bar [value]="result.overallMatch"
[status]="getMatchStatus(result.overallMatch)"
[displayValue]="true"
size="large">
</nb-progress-bar>
</div>
<div class="field-matches mt-4">
<h6>Field-level Match Breakdown</h6>
<div class="field-match-item">
<div class="match-header">
<span>Name</span>
<span class="match-value">{{ result.fieldMatches.name }}%</span>
</div>
<nb-progress-bar [value]="result.fieldMatches.name"
size="tiny"
[status]="getMatchStatus(result.fieldMatches.name)">
</nb-progress-bar>
</div>
<div class="field-match-item">
<div class="match-header">
<span>Date of Birth</span>
<span class="match-value">{{ result.fieldMatches.dateOfBirth }}%</span>
</div>
<nb-progress-bar [value]="result.fieldMatches.dateOfBirth"
size="tiny"
[status]="getMatchStatus(result.fieldMatches.dateOfBirth)">
</nb-progress-bar>
</div>
<div class="field-match-item">
<div class="match-header">
<span>Address</span>
<span class="match-value">{{ result.fieldMatches.address }}%</span>
</div>
<nb-progress-bar [value]="result.fieldMatches.address"
size="tiny"
[status]="getMatchStatus(result.fieldMatches.address)">
</nb-progress-bar>
</div>
<div class="field-match-item">
<div class="match-header">
<span>Identification</span>
<span class="match-value">{{ result.fieldMatches.identification }}%</span>
</div>
<nb-progress-bar [value]="result.fieldMatches.identification"
size="tiny"
[status]="getMatchStatus(result.fieldMatches.identification)">
</nb-progress-bar>
</div>
</div>
<div class="action-buttons">
<button nbButton fullWidth status="info" size="medium">
<nb-icon icon="download-outline"></nb-icon>
Download Report
</button>
<button nbButton fullWidth status="basic" size="medium" (click)="resetForm()">
<nb-icon icon="refresh-outline"></nb-icon>
New Verification
</button>
</div>
</nb-card-body>
</nb-card>
</div>
</div>

View file

@ -0,0 +1,108 @@
@import '../../../@theme/styles/themes';
@include nb-install-component() {
.form-group {
margin-bottom: 1.5rem;
.label {
display: block;
margin-bottom: 0.5rem;
font-weight: 600;
color: nb-theme(text-basic-color);
font-size: 0.875rem;
}
.error-message {
display: block;
margin-top: 0.25rem;
font-size: 0.75rem;
color: nb-theme(color-danger-default);
}
.hint-text {
display: block;
margin-top: 0.25rem;
font-size: 0.75rem;
color: nb-theme(text-hint-color);
}
}
.info-card {
nb-list {
margin: 0;
}
nb-list-item {
display: flex;
align-items: flex-start;
gap: 0.75rem;
padding: 0.75rem 0;
border: none;
nb-icon {
flex-shrink: 0;
font-size: 1.25rem;
margin-top: 0.125rem;
}
span {
font-size: 0.875rem;
color: nb-theme(text-hint-color);
line-height: 1.5;
}
}
}
.result-card {
.match-result {
margin-bottom: 2rem;
padding: 1rem;
background: nb-theme(background-basic-color-2);
border-radius: nb-theme(card-border-radius);
h6 {
margin: 0 0 1rem 0;
font-weight: 600;
color: nb-theme(text-basic-color);
}
}
.field-matches {
h6 {
margin: 0 0 1rem 0;
font-weight: 600;
color: nb-theme(text-basic-color);
}
.field-match-item {
margin-bottom: 1rem;
.match-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
span {
font-size: 0.875rem;
color: nb-theme(text-hint-color);
}
.match-value {
font-weight: 600;
color: nb-theme(text-basic-color);
}
}
}
}
.action-buttons {
display: flex;
flex-direction: column;
gap: 0.75rem;
margin-top: 2rem;
padding-top: 1.5rem;
border-top: 1px solid nb-theme(border-basic-color-3);
}
}
}

View file

@ -0,0 +1,76 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'ngx-manual-lookup',
templateUrl: './manual-lookup.component.html',
styleUrls: ['./manual-lookup.component.scss']
})
export class ManualLookupComponent implements OnInit {
identityForm: FormGroup;
isSubmitting = false;
result = null;
constructor(
private fb: FormBuilder,
private route: ActivatedRoute
) {
this.identityForm = this.fb.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
dateOfBirth: ['', Validators.required],
country: ['', Validators.required],
identificationNumber: [''],
email: ['', Validators.email],
phone: [''],
address: [''],
});
}
ngOnInit(): void {
// Check if country is passed as query parameter
this.route.queryParams.subscribe(params => {
if (params['country']) {
this.identityForm.patchValue({
country: params['country']
});
}
});
}
onSubmit() {
if (this.identityForm.valid) {
this.isSubmitting = true;
// Simulate API call
setTimeout(() => {
this.isSubmitting = false;
this.result = {
overallMatch: 85,
fieldMatches: {
name: 90,
dateOfBirth: 100,
address: 70,
identification: 80
}
};
}, 2000);
} else {
// Mark all fields as touched to show validation errors
Object.keys(this.identityForm.controls).forEach(key => {
this.identityForm.get(key).markAsTouched();
});
}
}
resetForm() {
this.identityForm.reset();
this.result = null;
}
getMatchStatus(score: number): string {
if (score >= 80) return 'success';
if (score >= 60) return 'warning';
return 'danger';
}
}

View file

@ -0,0 +1,40 @@
<nb-card>
<nb-card-header>
<h5>Verification Results History</h5>
</nb-card-header>
<nb-card-body>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Date/Time</th>
<th>Country</th>
<th>Match Score</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let lookup of recentLookups">
<td>{{ lookup.date }}</td>
<td>{{ lookup.country }}</td>
<td>
<nb-progress-bar [value]="lookup.score" size="tiny" [status]="getStatusClass(lookup.status)" [displayValue]="true"></nb-progress-bar>
</td>
<td>
<span class="badge badge-{{ getStatusClass(lookup.status) }}">{{ lookup.status }}</span>
</td>
<td>
<button nbButton ghost size="small" status="info" title="View Details">
<nb-icon icon="eye-outline"></nb-icon>
</button>
<button nbButton ghost size="small" status="primary" title="Download Report">
<nb-icon icon="download-outline"></nb-icon>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</nb-card-body>
</nb-card>

View file

@ -0,0 +1,23 @@
button {
margin-right: 5px;
}
.badge {
padding: 0.4rem 0.6rem;
}
.badge-success {
background-color: #00d68f;
}
.badge-warning {
background-color: #ffaa00;
}
.badge-danger {
background-color: #ff3d71;
}
.badge-info {
background-color: #0095ff;
}

View file

@ -0,0 +1,37 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'ngx-results-history',
templateUrl: './results-history.component.html',
styleUrls: ['./results-history.component.scss']
})
export class ResultsHistoryComponent implements OnInit {
// Sample data for demonstration
recentLookups = [
{ date: '2025-05-19 10:30', country: 'Australia', score: 95, status: 'Verified' },
{ date: '2025-05-19 09:15', country: 'Indonesia', score: 82, status: 'Verified' },
{ date: '2025-05-18 16:45', country: 'Malaysia', score: 60, status: 'Partial Match' },
{ date: '2025-05-18 14:20', country: 'Japan', score: 42, status: 'No Match' },
{ date: '2025-05-17 11:30', country: 'Australia', score: 88, status: 'Verified' },
{ date: '2025-05-17 09:45', country: 'Indonesia', score: 76, status: 'Verified' },
];
constructor() { }
ngOnInit(): void {
}
getStatusClass(status: string): string {
switch (status) {
case 'Verified':
return 'success';
case 'Partial Match':
return 'warning';
case 'No Match':
return 'danger';
default:
return 'info';
}
}
}

View file

@ -21,5 +21,4 @@ const routes: Routes = [
imports: [RouterModule.forChild(routes)], imports: [RouterModule.forChild(routes)],
exports: [RouterModule], exports: [RouterModule],
}) })
export class MiscellaneousRoutingModule { export class MiscellaneousRoutingModule { }
}

View file

@ -2,9 +2,7 @@ import { Component } from '@angular/core';
@Component({ @Component({
selector: 'ngx-miscellaneous', selector: 'ngx-miscellaneous',
template: ` template: `<router-outlet></router-outlet>`,
<router-outlet></router-outlet>
`,
}) })
export class MiscellaneousComponent { export class MiscellaneousComponent {
} }

View file

@ -1,16 +1,19 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { NbButtonModule, NbCardModule } from '@nebular/theme'; import { CommonModule } from '@angular/common';
import { ThemeModule } from '../../@theme/theme.module'; import { ThemeModule } from '../../@theme/theme.module';
import { NbCardModule, NbButtonModule, NbIconModule } from '@nebular/theme';
import { MiscellaneousRoutingModule } from './miscellaneous-routing.module'; import { MiscellaneousRoutingModule } from './miscellaneous-routing.module';
import { MiscellaneousComponent } from './miscellaneous.component'; import { MiscellaneousComponent } from './miscellaneous.component';
import { NotFoundComponent } from './not-found/not-found.component'; import { NotFoundComponent } from './not-found/not-found.component';
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule,
ThemeModule, ThemeModule,
NbCardModule, NbCardModule,
NbButtonModule, NbButtonModule,
NbIconModule,
MiscellaneousRoutingModule, MiscellaneousRoutingModule,
], ],
declarations: [ declarations: [

View file

@ -2,245 +2,41 @@ import { NbMenuItem } from '@nebular/theme';
export const MENU_ITEMS: NbMenuItem[] = [ export const MENU_ITEMS: NbMenuItem[] = [
{ {
title: 'E-commerce', title: 'Dashboard',
icon: 'shopping-cart-outline', icon: 'home-outline',
link: '/pages/dashboard', link: '/pages/dashboard',
home: true, home: true,
}, },
{ {
title: 'IoT Dashboard', title: 'Identity Verification',
icon: 'home-outline', icon: 'person-outline',
link: '/pages/iot-dashboard',
},
{
title: 'FEATURES',
group: true,
},
{
title: 'Layout',
icon: 'layout-outline',
children: [ children: [
{ {
title: 'Stepper', title: 'Manual Lookup',
link: '/pages/layout/stepper', link: '/pages/identity/manual-lookup',
}, },
{ {
title: 'List', title: 'Results History',
link: '/pages/layout/list', link: '/pages/identity/results-history',
},
{
title: 'Infinite List',
link: '/pages/layout/infinite-list',
},
{
title: 'Accordion',
link: '/pages/layout/accordion',
},
{
title: 'Tabs',
pathMatch: 'prefix',
link: '/pages/layout/tabs',
}, },
], ],
}, },
{ {
title: 'Forms', title: 'Countries',
icon: 'edit-2-outline', icon: 'globe-outline',
children: [ link: '/pages/countries',
{
title: 'Form Inputs',
link: '/pages/forms/inputs',
},
{
title: 'Form Layouts',
link: '/pages/forms/layouts',
},
{
title: 'Buttons',
link: '/pages/forms/buttons',
},
{
title: 'Datepicker',
link: '/pages/forms/datepicker',
},
],
}, },
{ {
title: 'UI Features', title: 'Account',
icon: 'keypad-outline', icon: 'settings-outline',
link: '/pages/ui-features',
children: [ children: [
{ {
title: 'Grid', title: 'Profile',
link: '/pages/ui-features/grid', link: '/pages/account/profile',
}, },
{ {
title: 'Icons', title: 'Settings',
link: '/pages/ui-features/icons', link: '/pages/account/settings',
},
{
title: 'Typography',
link: '/pages/ui-features/typography',
},
{
title: 'Animated Searches',
link: '/pages/ui-features/search-fields',
},
],
},
{
title: 'Modal & Overlays',
icon: 'browser-outline',
children: [
{
title: 'Dialog',
link: '/pages/modal-overlays/dialog',
},
{
title: 'Window',
link: '/pages/modal-overlays/window',
},
{
title: 'Popover',
link: '/pages/modal-overlays/popover',
},
{
title: 'Toastr',
link: '/pages/modal-overlays/toastr',
},
{
title: 'Tooltip',
link: '/pages/modal-overlays/tooltip',
},
],
},
{
title: 'Extra Components',
icon: 'message-circle-outline',
children: [
{
title: 'Calendar',
link: '/pages/extra-components/calendar',
},
{
title: 'Progress Bar',
link: '/pages/extra-components/progress-bar',
},
{
title: 'Spinner',
link: '/pages/extra-components/spinner',
},
{
title: 'Alert',
link: '/pages/extra-components/alert',
},
{
title: 'Calendar Kit',
link: '/pages/extra-components/calendar-kit',
},
{
title: 'Chat',
link: '/pages/extra-components/chat',
},
],
},
{
title: 'Maps',
icon: 'map-outline',
children: [
{
title: 'Google Maps',
link: '/pages/maps/gmaps',
},
{
title: 'Leaflet Maps',
link: '/pages/maps/leaflet',
},
{
title: 'Bubble Maps',
link: '/pages/maps/bubble',
},
{
title: 'Search Maps',
link: '/pages/maps/searchmap',
},
],
},
{
title: 'Charts',
icon: 'pie-chart-outline',
children: [
{
title: 'Echarts',
link: '/pages/charts/echarts',
},
{
title: 'Charts.js',
link: '/pages/charts/chartjs',
},
{
title: 'D3',
link: '/pages/charts/d3',
},
],
},
{
title: 'Editors',
icon: 'text-outline',
children: [
{
title: 'TinyMCE',
link: '/pages/editors/tinymce',
},
{
title: 'CKEditor',
link: '/pages/editors/ckeditor',
},
],
},
{
title: 'Tables & Data',
icon: 'grid-outline',
children: [
{
title: 'Smart Table',
link: '/pages/tables/smart-table',
},
{
title: 'Tree Grid',
link: '/pages/tables/tree-grid',
},
],
},
{
title: 'Miscellaneous',
icon: 'shuffle-2-outline',
children: [
{
title: '404',
link: '/pages/miscellaneous/404',
},
],
},
{
title: 'Auth',
icon: 'lock-outline',
children: [
{
title: 'Login',
link: '/auth/login',
},
{
title: 'Register',
link: '/auth/register',
},
{
title: 'Request Password',
link: '/auth/request-password',
},
{
title: 'Reset Password',
link: '/auth/reset-password',
}, },
], ],
}, },

View file

@ -3,7 +3,6 @@ import { NgModule } from '@angular/core';
import { PagesComponent } from './pages.component'; import { PagesComponent } from './pages.component';
import { DashboardComponent } from './dashboard/dashboard.component'; import { DashboardComponent } from './dashboard/dashboard.component';
import { ECommerceComponent } from './e-commerce/e-commerce.component';
import { NotFoundComponent } from './miscellaneous/not-found/not-found.component'; import { NotFoundComponent } from './miscellaneous/not-found/not-found.component';
const routes: Routes = [{ const routes: Routes = [{
@ -12,61 +11,22 @@ const routes: Routes = [{
children: [ children: [
{ {
path: 'dashboard', path: 'dashboard',
component: ECommerceComponent,
},
{
path: 'iot-dashboard',
component: DashboardComponent, component: DashboardComponent,
}, },
{ {
path: 'layout', path: 'identity',
loadChildren: () => import('./layout/layout.module') loadChildren: () => import('./identity/identity.module')
.then(m => m.LayoutModule), .then(m => m.IdentityModule),
}, },
{ {
path: 'forms', path: 'countries',
loadChildren: () => import('./forms/forms.module') loadChildren: () => import('./countries/countries.module')
.then(m => m.FormsModule), .then(m => m.CountriesModule),
}, },
{ {
path: 'ui-features', path: 'account',
loadChildren: () => import('./ui-features/ui-features.module') loadChildren: () => import('./account/account.module')
.then(m => m.UiFeaturesModule), .then(m => m.AccountModule),
},
{
path: 'modal-overlays',
loadChildren: () => import('./modal-overlays/modal-overlays.module')
.then(m => m.ModalOverlaysModule),
},
{
path: 'extra-components',
loadChildren: () => import('./extra-components/extra-components.module')
.then(m => m.ExtraComponentsModule),
},
{
path: 'maps',
loadChildren: () => import('./maps/maps.module')
.then(m => m.MapsModule),
},
{
path: 'charts',
loadChildren: () => import('./charts/charts.module')
.then(m => m.ChartsModule),
},
{
path: 'editors',
loadChildren: () => import('./editors/editors.module')
.then(m => m.EditorsModule),
},
{
path: 'tables',
loadChildren: () => import('./tables/tables.module')
.then(m => m.TablesModule),
},
{
path: 'miscellaneous',
loadChildren: () => import('./miscellaneous/miscellaneous.module')
.then(m => m.MiscellaneousModule),
}, },
{ {
path: '', path: '',

View file

@ -4,9 +4,8 @@ import { NbMenuModule } from '@nebular/theme';
import { ThemeModule } from '../@theme/theme.module'; import { ThemeModule } from '../@theme/theme.module';
import { PagesComponent } from './pages.component'; import { PagesComponent } from './pages.component';
import { DashboardModule } from './dashboard/dashboard.module'; import { DashboardModule } from './dashboard/dashboard.module';
import { ECommerceModule } from './e-commerce/e-commerce.module';
import { PagesRoutingModule } from './pages-routing.module';
import { MiscellaneousModule } from './miscellaneous/miscellaneous.module'; import { MiscellaneousModule } from './miscellaneous/miscellaneous.module';
import { PagesRoutingModule } from './pages-routing.module';
@NgModule({ @NgModule({
imports: [ imports: [
@ -14,7 +13,6 @@ import { MiscellaneousModule } from './miscellaneous/miscellaneous.module';
ThemeModule, ThemeModule,
NbMenuModule, NbMenuModule,
DashboardModule, DashboardModule,
ECommerceModule,
MiscellaneousModule, MiscellaneousModule,
], ],
declarations: [ declarations: [

View file

@ -2,14 +2,15 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>ngx-admin Demo Application</title> <title>IdentityPulse - Identity Verification Platform</title>
<base href="/"> <base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="favicon.png"> <link rel="icon" type="image/png" href="favicon.png">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<script defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCpVhQiwAllg1RAFaxMWSpQruuGARy0Y1k&libraries=places"></script> <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
</head> </head>
<body> <body>
<ngx-app>Loading...</ngx-app> <ngx-app>Loading...</ngx-app>