Feature/set public stripe key dynamically (#216)
* Set public Stripe key dynamically * Update changelog
This commit is contained in:
parent
39a76f7f40
commit
51fbc538ca
@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Improved the styling of the current pricing plan
|
||||
- Improved the styling of the transaction type badge
|
||||
- Set the public _Stripe_ key dynamically
|
||||
- Upgraded `angular-material-css-vars` from version `2.0.0` to `2.1.0`
|
||||
|
||||
### Fixed
|
||||
|
@ -20,6 +20,7 @@ export class InfoService {
|
||||
) {}
|
||||
|
||||
public async get(): Promise<InfoItem> {
|
||||
const info: Partial<InfoItem> = {};
|
||||
const platforms = await this.prisma.platform.findMany({
|
||||
orderBy: { name: 'asc' },
|
||||
select: { id: true, name: true }
|
||||
@ -41,9 +42,12 @@ export class InfoService {
|
||||
|
||||
if (this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION')) {
|
||||
globalPermissions.push(permissions.enableSubscription);
|
||||
|
||||
info.stripePublicKey = this.configurationService.get('STRIPE_PUBLIC_KEY');
|
||||
}
|
||||
|
||||
return {
|
||||
...info,
|
||||
globalPermissions,
|
||||
platforms,
|
||||
currencies: Object.values(Currency),
|
||||
|
@ -30,6 +30,7 @@ export class ConfigurationService {
|
||||
REDIS_HOST: str({ default: 'localhost' }),
|
||||
REDIS_PORT: port({ default: 6379 }),
|
||||
ROOT_URL: str({ default: 'http://localhost:4200' }),
|
||||
STRIPE_PUBLIC_KEY: str({ default: '' }),
|
||||
STRIPE_SECRET_KEY: str({ default: '' }),
|
||||
WEB_AUTH_RP_ID: host({ default: 'localhost' })
|
||||
});
|
||||
|
@ -20,6 +20,7 @@ export interface Environment extends CleanedEnvAccessors {
|
||||
REDIS_HOST: string;
|
||||
REDIS_PORT: number;
|
||||
ROOT_URL: string;
|
||||
STRIPE_PUBLIC_KEY: string;
|
||||
STRIPE_SECRET_KEY: string;
|
||||
WEB_AUTH_RP_ID: string;
|
||||
}
|
||||
|
@ -56,13 +56,6 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
public ngOnInit() {
|
||||
this.deviceType = this.deviceService.getDeviceInfo().deviceType;
|
||||
|
||||
this.dataService
|
||||
.fetchInfo()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe((info) => {
|
||||
this.info = info;
|
||||
});
|
||||
|
||||
this.router.events
|
||||
.pipe(filter((event) => event instanceof NavigationEnd))
|
||||
.subscribe(() => {
|
||||
@ -70,6 +63,8 @@ export class AppComponent implements OnDestroy, OnInit {
|
||||
const urlSegmentGroup = urlTree.root.children[PRIMARY_OUTLET];
|
||||
const urlSegments = urlSegmentGroup.segments;
|
||||
this.currentRoute = urlSegments[0].path;
|
||||
|
||||
this.info = this.dataService.fetchInfo();
|
||||
});
|
||||
|
||||
this.userService.stateChanged
|
||||
|
@ -15,7 +15,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MaterialCssVarsModule } from 'angular-material-css-vars';
|
||||
import { MarkdownModule } from 'ngx-markdown';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
import { NgxStripeModule } from 'ngx-stripe';
|
||||
import { NgxStripeModule, STRIPE_PUBLISHABLE_KEY } from 'ngx-stripe';
|
||||
|
||||
import { environment } from '../environments/environment';
|
||||
import { CustomDateAdapter } from './adapter/custom-date-adapter';
|
||||
@ -27,6 +27,10 @@ import { authInterceptorProviders } from './core/auth.interceptor';
|
||||
import { httpResponseInterceptorProviders } from './core/http-response.interceptor';
|
||||
import { LanguageService } from './core/language.service';
|
||||
|
||||
export function NgxStripeFactory(): string {
|
||||
return environment.stripePublicKey;
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent],
|
||||
imports: [
|
||||
@ -57,7 +61,11 @@ import { LanguageService } from './core/language.service';
|
||||
useClass: CustomDateAdapter,
|
||||
deps: [LanguageService, MAT_DATE_LOCALE, Platform]
|
||||
},
|
||||
{ provide: MAT_DATE_FORMATS, useValue: DateFormats }
|
||||
{ provide: MAT_DATE_FORMATS, useValue: DateFormats },
|
||||
{
|
||||
provide: STRIPE_PUBLISHABLE_KEY,
|
||||
useFactory: NgxStripeFactory
|
||||
}
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
@ -39,19 +39,13 @@ export class AboutPageComponent implements OnDestroy, OnInit {
|
||||
* Initializes the controller
|
||||
*/
|
||||
public ngOnInit() {
|
||||
this.dataService
|
||||
.fetchInfo()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(({ globalPermissions, statistics }) => {
|
||||
this.hasPermissionForStatistics = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.enableStatistics
|
||||
);
|
||||
const { globalPermissions, statistics } = this.dataService.fetchInfo();
|
||||
this.hasPermissionForStatistics = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.enableStatistics
|
||||
);
|
||||
|
||||
this.statistics = statistics;
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
this.statistics = statistics;
|
||||
|
||||
this.userService.stateChanged
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
|
@ -54,24 +54,19 @@ export class AccountPageComponent implements OnDestroy, OnInit {
|
||||
private userService: UserService,
|
||||
public webAuthnService: WebAuthnService
|
||||
) {
|
||||
this.dataService
|
||||
.fetchInfo()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(({ currencies, globalPermissions, subscriptions }) => {
|
||||
this.coupon = subscriptions?.[0]?.coupon;
|
||||
this.couponId = subscriptions?.[0]?.couponId;
|
||||
this.currencies = currencies;
|
||||
const { currencies, globalPermissions, subscriptions } =
|
||||
this.dataService.fetchInfo();
|
||||
this.coupon = subscriptions?.[0]?.coupon;
|
||||
this.couponId = subscriptions?.[0]?.couponId;
|
||||
this.currencies = currencies;
|
||||
|
||||
this.hasPermissionForSubscription = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.enableSubscription
|
||||
);
|
||||
this.hasPermissionForSubscription = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.enableSubscription
|
||||
);
|
||||
|
||||
this.price = subscriptions?.[0]?.price;
|
||||
this.priceId = subscriptions?.[0]?.priceId;
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
this.price = subscriptions?.[0]?.price;
|
||||
this.priceId = subscriptions?.[0]?.priceId;
|
||||
|
||||
this.userService.stateChanged
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
|
@ -8,7 +8,6 @@ import {
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { Currency } from '@prisma/client';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
import { DataService } from '../../../services/data.service';
|
||||
import { CreateOrUpdateAccountDialogParams } from './interfaces/interfaces';
|
||||
@ -34,15 +33,10 @@ export class CreateOrUpdateAccountDialog implements OnDestroy {
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.dataService
|
||||
.fetchInfo()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(({ currencies, platforms }) => {
|
||||
this.currencies = currencies;
|
||||
this.platforms = platforms;
|
||||
const { currencies, platforms } = this.dataService.fetchInfo();
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
this.currencies = currencies;
|
||||
this.platforms = platforms;
|
||||
}
|
||||
|
||||
public onCancel(): void {
|
||||
|
@ -3,10 +3,8 @@ import { Router } from '@angular/router';
|
||||
import { LineChartItem } from '@ghostfolio/client/components/line-chart/interfaces/line-chart.interface';
|
||||
import { DataService } from '@ghostfolio/client/services/data.service';
|
||||
import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service';
|
||||
import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service';
|
||||
import { format } from 'date-fns';
|
||||
import { Subject } from 'rxjs';
|
||||
import { takeUntil } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'gf-landing-page',
|
||||
@ -34,16 +32,11 @@ export class LandingPageComponent implements OnDestroy, OnInit {
|
||||
* Initializes the controller
|
||||
*/
|
||||
public ngOnInit() {
|
||||
this.dataService
|
||||
.fetchInfo()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(({ demoAuthToken }) => {
|
||||
this.demoAuthToken = demoAuthToken;
|
||||
const { demoAuthToken } = this.dataService.fetchInfo();
|
||||
|
||||
this.initializeLineChart();
|
||||
this.demoAuthToken = demoAuthToken;
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
this.initializeLineChart();
|
||||
}
|
||||
|
||||
public initializeLineChart() {
|
||||
|
@ -28,15 +28,10 @@ export class PricingPageComponent implements OnDestroy, OnInit {
|
||||
private dataService: DataService,
|
||||
private userService: UserService
|
||||
) {
|
||||
this.dataService
|
||||
.fetchInfo()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(({ subscriptions }) => {
|
||||
this.coupon = this.price = subscriptions?.[0]?.coupon;
|
||||
this.price = subscriptions?.[0]?.price;
|
||||
const { subscriptions } = this.dataService.fetchInfo();
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
this.coupon = this.price = subscriptions?.[0]?.coupon;
|
||||
this.price = subscriptions?.[0]?.price;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,18 +41,13 @@ export class RegisterPageComponent implements OnDestroy, OnInit {
|
||||
* Initializes the controller
|
||||
*/
|
||||
public ngOnInit() {
|
||||
this.dataService
|
||||
.fetchInfo()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(({ demoAuthToken, globalPermissions }) => {
|
||||
this.demoAuthToken = demoAuthToken;
|
||||
this.hasPermissionForSocialLogin = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.enableSocialLogin
|
||||
);
|
||||
const { demoAuthToken, globalPermissions } = this.dataService.fetchInfo();
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
this.demoAuthToken = demoAuthToken;
|
||||
this.hasPermissionForSocialLogin = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.enableSocialLogin
|
||||
);
|
||||
}
|
||||
|
||||
public async createAccount() {
|
||||
|
@ -50,15 +50,10 @@ export class CreateOrUpdateTransactionDialog implements OnDestroy {
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.dataService
|
||||
.fetchInfo()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(({ currencies, platforms }) => {
|
||||
this.currencies = currencies;
|
||||
this.platforms = platforms;
|
||||
const { currencies, platforms } = this.dataService.fetchInfo();
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
this.currencies = currencies;
|
||||
this.platforms = platforms;
|
||||
|
||||
this.filteredLookupItems = this.searchSymbolCtrl.valueChanges.pipe(
|
||||
startWith(''),
|
||||
|
@ -10,7 +10,6 @@ import { UserService } from '@ghostfolio/client/services/user/user.service';
|
||||
import { User } from '@ghostfolio/common/interfaces';
|
||||
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
|
||||
import { Order as OrderModel } from '@prisma/client';
|
||||
import { environment } from 'apps/client/src/environments/environment';
|
||||
import { format, parseISO } from 'date-fns';
|
||||
import { DeviceDetectorService } from 'ngx-device-detector';
|
||||
import { EMPTY, Subject, Subscription } from 'rxjs';
|
||||
@ -72,17 +71,12 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
|
||||
* Initializes the controller
|
||||
*/
|
||||
public ngOnInit() {
|
||||
this.dataService
|
||||
.fetchInfo()
|
||||
.pipe(takeUntil(this.unsubscribeSubject))
|
||||
.subscribe(({ globalPermissions }) => {
|
||||
this.hasPermissionToImportOrders = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.enableImport
|
||||
);
|
||||
const { globalPermissions } = this.dataService.fetchInfo();
|
||||
|
||||
this.changeDetectorRef.markForCheck();
|
||||
});
|
||||
this.hasPermissionToImportOrders = hasPermission(
|
||||
globalPermissions,
|
||||
permissions.enableImport
|
||||
);
|
||||
|
||||
this.deviceType = this.deviceService.getDeviceInfo().deviceType;
|
||||
|
||||
|
@ -29,6 +29,7 @@ import { permissions } from '@ghostfolio/common/permissions';
|
||||
import { Order as OrderModel } from '@prisma/client';
|
||||
import { Account as AccountModel } from '@prisma/client';
|
||||
import { parseISO } from 'date-fns';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@ -92,21 +93,16 @@ export class DataService {
|
||||
return this.http.get<Export>('/api/export');
|
||||
}
|
||||
|
||||
public fetchInfo() {
|
||||
return this.http.get<InfoItem>('/api/info').pipe(
|
||||
map((data) => {
|
||||
if (
|
||||
this.settingsStorageService.getSetting('utm_source') ===
|
||||
'trusted-web-activity'
|
||||
) {
|
||||
data.globalPermissions = data.globalPermissions.filter(
|
||||
(permission) => permission !== permissions.enableSubscription
|
||||
);
|
||||
}
|
||||
public fetchInfo(): InfoItem {
|
||||
const info = cloneDeep((window as any).info);
|
||||
|
||||
return data;
|
||||
})
|
||||
);
|
||||
if (window.localStorage.getItem('utm_source') === 'trusted-web-activity') {
|
||||
info.globalPermissions = info.globalPermissions.filter(
|
||||
(permission) => permission !== permissions.enableSubscription
|
||||
);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public fetchSymbolItem(aSymbol: string) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
export const environment = {
|
||||
lastPublish: '{BUILD_TIMESTAMP}',
|
||||
production: true,
|
||||
stripePublicKey: '{STRIPE_PUBLIC_KEY}',
|
||||
stripePublicKey: '',
|
||||
version: `v${require('../../../../package.json').version}`
|
||||
};
|
||||
|
@ -1,16 +1,33 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { LOCALE_ID } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { InfoItem } from '@ghostfolio/common/interfaces';
|
||||
import { permissions } from '@ghostfolio/common/permissions';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
(async () => {
|
||||
const response = await fetch('/api/info');
|
||||
const info: InfoItem = await response.json();
|
||||
|
||||
platformBrowserDynamic()
|
||||
.bootstrapModule(AppModule, {
|
||||
providers: [{ provide: LOCALE_ID, useValue: 'de-CH' }]
|
||||
})
|
||||
.catch((err) => console.error(err));
|
||||
if (window.localStorage.getItem('utm_source') === 'trusted-web-activity') {
|
||||
info.globalPermissions = info.globalPermissions.filter(
|
||||
(permission) => permission !== permissions.enableSubscription
|
||||
);
|
||||
}
|
||||
|
||||
(window as any).info = info;
|
||||
|
||||
environment.stripePublicKey = info.stripePublicKey;
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic()
|
||||
.bootstrapModule(AppModule, {
|
||||
providers: [{ provide: LOCALE_ID, useValue: 'de-CH' }]
|
||||
})
|
||||
.catch((err) => console.error(err));
|
||||
})();
|
||||
|
@ -14,5 +14,6 @@ export interface InfoItem {
|
||||
};
|
||||
platforms: { id: string; name: string }[];
|
||||
statistics: Statistics;
|
||||
stripePublicKey?: string;
|
||||
subscriptions: Subscription[];
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ const buildTimestamp = `${formatWithTwoDigits(
|
||||
)}:${formatWithTwoDigits(now.getMinutes())}`;
|
||||
|
||||
try {
|
||||
let changedFiles = replace.sync({
|
||||
const changedFiles = replace.sync({
|
||||
files: './dist/apps/client/main.*.js',
|
||||
from: /{BUILD_TIMESTAMP}/g,
|
||||
to: buildTimestamp,
|
||||
@ -24,14 +24,6 @@ try {
|
||||
});
|
||||
console.log('Build version set: ' + buildTimestamp);
|
||||
console.log(changedFiles);
|
||||
|
||||
changedFiles = replace.sync({
|
||||
files: './dist/apps/client/main.*.js',
|
||||
from: /{STRIPE_PUBLIC_KEY}/g,
|
||||
to: process.env.STRIPE_PUBLIC_KEY ?? '',
|
||||
allowEmptyPaths: false
|
||||
});
|
||||
console.log(changedFiles);
|
||||
} catch (error) {
|
||||
console.error('Error occurred:', error);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user