Feature/add global heat map to landing page (#1584)
* Add global heat map * Update changelog
This commit is contained in:
parent
fc8e23a9c8
commit
90a7a84ac5
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- Extended the landing page by a global heat map of subscribers
|
||||
|
||||
### Changed
|
||||
|
||||
- Improved the form of the import dividends dialog (disable while loading)
|
||||
|
@ -7,6 +7,7 @@ import { PropertyService } from '@ghostfolio/api/services/property/property.serv
|
||||
import { TagService } from '@ghostfolio/api/services/tag/tag.service';
|
||||
import {
|
||||
DEMO_USER_ID,
|
||||
PROPERTY_COUNTRIES_OF_SUBSCRIBERS,
|
||||
PROPERTY_IS_READ_ONLY_MODE,
|
||||
PROPERTY_SLACK_COMMUNITY_USERS,
|
||||
PROPERTY_STRIPE_CONFIG,
|
||||
@ -92,6 +93,10 @@ export class InfoService {
|
||||
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
|
||||
globalPermissions.push(permissions.enableSubscription);
|
||||
|
||||
info.countriesOfSubscribers =
|
||||
((await this.propertyService.getByKey(
|
||||
PROPERTY_COUNTRIES_OF_SUBSCRIBERS
|
||||
)) as string[]) ?? [];
|
||||
info.stripePublicKey = this.configurationService.get('STRIPE_PUBLIC_KEY');
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,8 @@ import svgMap from 'svgmap';
|
||||
styleUrls: ['./world-map-chart.component.scss']
|
||||
})
|
||||
export class WorldMapChartComponent implements OnChanges, OnDestroy, OnInit {
|
||||
@Input() baseCurrency: string;
|
||||
@Input() countries: { [code: string]: { name: string; value: number } };
|
||||
@Input() countries: { [code: string]: { name?: string; value: number } };
|
||||
@Input() format: string;
|
||||
@Input() isInPercent = false;
|
||||
|
||||
public isLoading = true;
|
||||
@ -71,7 +71,7 @@ export class WorldMapChartComponent implements OnChanges, OnDestroy, OnInit {
|
||||
applyData: 'value',
|
||||
data: {
|
||||
value: {
|
||||
format: this.isInPercent ? `{0}%` : `{0} ${this.baseCurrency}`
|
||||
format: this.format
|
||||
}
|
||||
},
|
||||
values: this.countries
|
||||
|
@ -13,10 +13,14 @@ import { Subject } from 'rxjs';
|
||||
templateUrl: './landing-page.html'
|
||||
})
|
||||
export class LandingPageComponent implements OnDestroy, OnInit {
|
||||
public countriesOfSubscribersMap: {
|
||||
[code: string]: { value: number };
|
||||
} = {};
|
||||
public currentYear = format(new Date(), 'yyyy');
|
||||
public demoAuthToken: string;
|
||||
public deviceType: string;
|
||||
public hasPermissionForStatistics: boolean;
|
||||
public hasPermissionForSubscription: boolean;
|
||||
public hasPermissionToCreateUser: boolean;
|
||||
public statistics: Statistics;
|
||||
public testimonials = [
|
||||
@ -48,13 +52,25 @@ export class LandingPageComponent implements OnDestroy, OnInit {
|
||||
private dataService: DataService,
|
||||
private deviceService: DeviceDetectorService
|
||||
) {
|
||||
const { globalPermissions, statistics } = this.dataService.fetchInfo();
|
||||
const { countriesOfSubscribers, globalPermissions, statistics } =
|
||||
this.dataService.fetchInfo();
|
||||
|
||||
for (const country of countriesOfSubscribers) {
|
||||
this.countriesOfSubscribersMap[country] = {
|
||||
value: 1
|
||||
};
|
||||
}
|
||||
|
||||
this.hasPermissionForStatistics = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.enableStatistics
|
||||
);
|
||||
|
||||
this.hasPermissionForSubscription = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.enableSubscription
|
||||
);
|
||||
|
||||
this.hasPermissionToCreateUser = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.createUserAccount
|
||||
|
@ -269,6 +269,21 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="hasPermissionForSubscription" class="row my-5">
|
||||
<div class="col-12">
|
||||
<h2 class="h4 text-center">
|
||||
Members from around the globe are using
|
||||
<a href="pricing"><strong>Ghostfolio Premium</strong></a>
|
||||
</h2>
|
||||
</div>
|
||||
<div class="col-md-8 customer-map-container offset-md-2">
|
||||
<gf-world-map-chart
|
||||
format="👻"
|
||||
[countries]="countriesOfSubscribersMap"
|
||||
></gf-world-map-chart>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row my-3">
|
||||
<div class="col-12">
|
||||
<h2 class="h4 mb-1 text-center">
|
||||
|
@ -3,7 +3,9 @@ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { GfWorldMapChartModule } from '@ghostfolio/client/components/world-map-chart/world-map-chart.module';
|
||||
import { GfLogoModule } from '@ghostfolio/ui/logo';
|
||||
import { GfPremiumIndicatorModule } from '@ghostfolio/ui/premium-indicator';
|
||||
import { GfValueModule } from '@ghostfolio/ui/value';
|
||||
|
||||
import { LandingPageRoutingModule } from './landing-page-routing.module';
|
||||
@ -14,7 +16,9 @@ import { LandingPageComponent } from './landing-page.component';
|
||||
imports: [
|
||||
CommonModule,
|
||||
GfLogoModule,
|
||||
GfPremiumIndicatorModule,
|
||||
GfValueModule,
|
||||
GfWorldMapChartModule,
|
||||
LandingPageRoutingModule,
|
||||
MatButtonModule,
|
||||
MatCardModule,
|
||||
|
@ -9,6 +9,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.customer-map-container {
|
||||
aspect-ratio: 16 / 9;
|
||||
}
|
||||
|
||||
.downloads {
|
||||
img {
|
||||
height: 2.5rem;
|
||||
|
@ -84,6 +84,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
|
||||
};
|
||||
|
||||
public user: User;
|
||||
public worldMapChartFormat: string;
|
||||
|
||||
private unsubscribeSubject = new Subject<void>();
|
||||
|
||||
@ -193,6 +194,11 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
|
||||
...tagFilters
|
||||
];
|
||||
|
||||
this.worldMapChartFormat =
|
||||
this.hasImpersonationId || this.user.settings.isRestrictedView
|
||||
? `{0}%`
|
||||
: `{0} ${this.user?.settings?.baseCurrency}`;
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
}
|
||||
});
|
||||
|
@ -257,8 +257,8 @@
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<gf-world-map-chart
|
||||
[baseCurrency]="user?.settings?.baseCurrency"
|
||||
[countries]="countries"
|
||||
[format]="worldMapChartFormat"
|
||||
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
|
||||
></gf-world-map-chart>
|
||||
<div class="row">
|
||||
|
@ -72,6 +72,7 @@ export const GATHER_HISTORICAL_MARKET_DATA_PROCESS_OPTIONS: JobOptions = {
|
||||
export const MAX_CHART_ITEMS = 365;
|
||||
|
||||
export const PROPERTY_BENCHMARKS = 'BENCHMARKS';
|
||||
export const PROPERTY_COUNTRIES_OF_SUBSCRIBERS = 'COUNTRIES_OF_SUBSCRIBERS';
|
||||
export const PROPERTY_COUPONS = 'COUPONS';
|
||||
export const PROPERTY_CURRENCIES = 'CURRENCIES';
|
||||
export const PROPERTY_IS_READ_ONLY_MODE = 'IS_READ_ONLY_MODE';
|
||||
|
@ -6,12 +6,12 @@ import { Subscription } from './subscription.interface';
|
||||
export interface InfoItem {
|
||||
baseCurrency: string;
|
||||
benchmarks: Partial<SymbolProfile>[];
|
||||
countriesOfSubscribers?: string[];
|
||||
currencies: string[];
|
||||
demoAuthToken: string;
|
||||
fearAndGreedDataSource?: string;
|
||||
globalPermissions: string[];
|
||||
isReadOnlyMode?: boolean;
|
||||
lastDataGathering?: Date;
|
||||
platforms: { id: string; name: string }[];
|
||||
statistics: Statistics;
|
||||
stripePublicKey?: string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user