diff --git a/CHANGELOG.md b/CHANGELOG.md index 33d51279d..72defa239 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Improved the create or update activity dialog’s asset sub class selector of the portfolio menu activities panel to update the options dynamically based on the selected asset class +- Randomized the minutes of the hourly data gathering cron job - Refactored the dialog footer component to standalone - Refactored the dialog header component to standalone - Refactored the landing page to standalone +- Refactored the pricing page to standalone - Refactored the register page to standalone - Migrated the login with access token dialog from `ngModel` to form control - Upgraded `@ionic/angular` from version `8.6.3` to `8.7.3` diff --git a/apps/api/src/services/cron/cron.service.ts b/apps/api/src/services/cron/cron.service.ts index b770aa2d7..88fcabce2 100644 --- a/apps/api/src/services/cron/cron.service.ts +++ b/apps/api/src/services/cron/cron.service.ts @@ -17,6 +17,7 @@ import { Cron, CronExpression } from '@nestjs/schedule'; @Injectable() export class CronService { + private static readonly EVERY_HOUR_AT_RANDOM_MINUTE = `${new Date().getMinutes()} * * * *`; private static readonly EVERY_SUNDAY_AT_LUNCH_TIME = '0 12 * * 0'; public constructor( @@ -28,8 +29,8 @@ export class CronService { private readonly userService: UserService ) {} - @Cron(CronExpression.EVERY_HOUR) - public async runEveryHour() { + @Cron(CronService.EVERY_HOUR_AT_RANDOM_MINUTE) + public async runEveryHourAtRandomMinute() { if (await this.isDataGatheringEnabled()) { await this.dataGatheringService.gather7Days(); } diff --git a/apps/client/src/app/app-routing.module.ts b/apps/client/src/app/app-routing.module.ts index dc1e92df5..9d5123d1b 100644 --- a/apps/client/src/app/app-routing.module.ts +++ b/apps/client/src/app/app-routing.module.ts @@ -106,9 +106,7 @@ const routes: Routes = [ { path: publicRoutes.pricing.path, loadChildren: () => - import('./pages/pricing/pricing-page.module').then( - (m) => m.PricingPageModule - ) + import('./pages/pricing/pricing-page.routes').then((m) => m.routes) }, { path: publicRoutes.public.path, diff --git a/apps/client/src/app/pages/pricing/pricing-page-routing.module.ts b/apps/client/src/app/pages/pricing/pricing-page-routing.module.ts deleted file mode 100644 index 5ba675184..000000000 --- a/apps/client/src/app/pages/pricing/pricing-page-routing.module.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { AuthGuard } from '@ghostfolio/client/core/auth.guard'; - -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; - -import { PricingPageComponent } from './pricing-page.component'; - -const routes: Routes = [ - { - canActivate: [AuthGuard], - component: PricingPageComponent, - path: '', - title: $localize`Pricing` - } -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class PricingPageRoutingModule {} diff --git a/apps/client/src/app/pages/pricing/pricing-page.component.ts b/apps/client/src/app/pages/pricing/pricing-page.component.ts index 5186aaadf..170d70914 100644 --- a/apps/client/src/app/pages/pricing/pricing-page.component.ts +++ b/apps/client/src/app/pages/pricing/pricing-page.component.ts @@ -5,10 +5,27 @@ import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { translate } from '@ghostfolio/ui/i18n'; +import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { + ChangeDetectorRef, + Component, + CUSTOM_ELEMENTS_SCHEMA, + OnDestroy, + OnInit +} from '@angular/core'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCardModule } from '@angular/material/card'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { RouterModule } from '@angular/router'; +import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; -import { checkmarkCircleOutline, checkmarkOutline } from 'ionicons/icons'; +import { + checkmarkCircleOutline, + checkmarkOutline, + informationCircleOutline +} from 'ionicons/icons'; import { StringValue } from 'ms'; import { StripeService } from 'ngx-stripe'; import { Subject } from 'rxjs'; @@ -16,12 +33,21 @@ import { catchError, switchMap, takeUntil } from 'rxjs/operators'; @Component({ host: { class: 'page' }, + imports: [ + CommonModule, + GfPremiumIndicatorComponent, + IonIcon, + MatButtonModule, + MatCardModule, + MatTooltipModule, + RouterModule + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-pricing-page', styleUrls: ['./pricing-page.scss'], - templateUrl: './pricing-page.html', - standalone: false + templateUrl: './pricing-page.html' }) -export class PricingPageComponent implements OnDestroy, OnInit { +export class GfPricingPageComponent implements OnDestroy, OnInit { public baseCurrency: string; public coupon: number; public couponId: string; @@ -56,7 +82,11 @@ export class PricingPageComponent implements OnDestroy, OnInit { private stripeService: StripeService, private userService: UserService ) { - addIcons({ checkmarkCircleOutline, checkmarkOutline }); + addIcons({ + checkmarkCircleOutline, + checkmarkOutline, + informationCircleOutline + }); } public ngOnInit() { diff --git a/apps/client/src/app/pages/pricing/pricing-page.module.ts b/apps/client/src/app/pages/pricing/pricing-page.module.ts deleted file mode 100644 index 3cfa09ade..000000000 --- a/apps/client/src/app/pages/pricing/pricing-page.module.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; - -import { CommonModule } from '@angular/common'; -import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; -import { MatButtonModule } from '@angular/material/button'; -import { MatCardModule } from '@angular/material/card'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { RouterModule } from '@angular/router'; -import { IonIcon } from '@ionic/angular/standalone'; - -import { PricingPageRoutingModule } from './pricing-page-routing.module'; -import { PricingPageComponent } from './pricing-page.component'; - -@NgModule({ - declarations: [PricingPageComponent], - imports: [ - CommonModule, - GfPremiumIndicatorComponent, - IonIcon, - MatButtonModule, - MatCardModule, - MatTooltipModule, - PricingPageRoutingModule, - RouterModule - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA] -}) -export class PricingPageModule {} diff --git a/apps/client/src/app/pages/pricing/pricing-page.routes.ts b/apps/client/src/app/pages/pricing/pricing-page.routes.ts new file mode 100644 index 000000000..a5b2c6639 --- /dev/null +++ b/apps/client/src/app/pages/pricing/pricing-page.routes.ts @@ -0,0 +1,14 @@ +import { AuthGuard } from '@ghostfolio/client/core/auth.guard'; + +import { Routes } from '@angular/router'; + +import { GfPricingPageComponent } from './pricing-page.component'; + +export const routes: Routes = [ + { + canActivate: [AuthGuard], + component: GfPricingPageComponent, + path: '', + title: $localize`Pricing` + } +];