From 204c7360c3e345ad2084d827f6bf095fc3aeb27f Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Tue, 5 Apr 2022 21:02:07 +0200 Subject: [PATCH] Feature/prepare for localized date format (#803) * Support localized date and number format * Update changelog --- CHANGELOG.md | 6 +++ .../interfaces/user-settings.interface.ts | 1 + .../src/app/user/update-user-setting.dto.ts | 6 ++- apps/api/src/app/user/user.controller.ts | 18 ++++---- apps/api/src/app/user/user.service.ts | 21 +++++---- apps/client/src/app/adapter/date-formats.ts | 12 +++-- .../admin-market-data-detail.component.ts | 12 +++-- .../admin-market-data.component.ts | 25 ++++++++--- .../admin-market-data/admin-market-data.html | 1 + .../admin-overview.component.ts | 2 - .../portfolio-performance.component.ts | 7 ++- .../pages/account/account-page.component.ts | 32 ++++++++++++- .../src/app/pages/account/account-page.html | 25 +++++++++++ .../app/pages/account/account-page.module.ts | 2 + apps/client/src/main.ts | 3 +- libs/common/src/lib/config.ts | 3 +- libs/common/src/lib/helper.ts | 45 ++++++++++++++++++- .../activities-table.component.ts | 6 ++- libs/ui/src/lib/value/value.component.ts | 17 ++++--- 19 files changed, 193 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e584bb04..1c918a903 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Added support for localization (date and number format) in user settings + ## 1.131.1 - 04.04.2022 ### Fixed diff --git a/apps/api/src/app/user/interfaces/user-settings.interface.ts b/apps/api/src/app/user/interfaces/user-settings.interface.ts index fb4b2af35..ef3b03f1b 100644 --- a/apps/api/src/app/user/interfaces/user-settings.interface.ts +++ b/apps/api/src/app/user/interfaces/user-settings.interface.ts @@ -1,5 +1,6 @@ export interface UserSettings { emergencyFund?: number; + locale?: string; isNewCalculationEngine?: boolean; isRestrictedView?: boolean; } diff --git a/apps/api/src/app/user/update-user-setting.dto.ts b/apps/api/src/app/user/update-user-setting.dto.ts index 5af2f5f8d..eaa41464a 100644 --- a/apps/api/src/app/user/update-user-setting.dto.ts +++ b/apps/api/src/app/user/update-user-setting.dto.ts @@ -1,4 +1,4 @@ -import { IsBoolean, IsNumber, IsOptional } from 'class-validator'; +import { IsBoolean, IsNumber, IsOptional, IsString } from 'class-validator'; export class UpdateUserSettingDto { @IsNumber() @@ -12,4 +12,8 @@ export class UpdateUserSettingDto { @IsBoolean() @IsOptional() isRestrictedView?: boolean; + + @IsString() + @IsOptional() + locale?: string; } diff --git a/apps/api/src/app/user/user.controller.ts b/apps/api/src/app/user/user.controller.ts index 97cf25b6e..5bd14cfaa 100644 --- a/apps/api/src/app/user/user.controller.ts +++ b/apps/api/src/app/user/user.controller.ts @@ -2,17 +2,14 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration.ser import { PropertyService } from '@ghostfolio/api/services/property/property.service'; import { PROPERTY_IS_READ_ONLY_MODE } from '@ghostfolio/common/config'; import { User } from '@ghostfolio/common/interfaces'; -import { - hasPermission, - hasRole, - permissions -} from '@ghostfolio/common/permissions'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import type { RequestWithUser } from '@ghostfolio/common/types'; import { Body, Controller, Delete, Get, + Headers, HttpException, Inject, Param, @@ -63,8 +60,13 @@ export class UserController { @Get() @UseGuards(AuthGuard('jwt')) - public async getUser(@Param('id') id: string): Promise<User> { - return this.userService.getUser(this.request.user); + public async getUser( + @Headers('accept-language') acceptLanguage: string + ): Promise<User> { + return this.userService.getUser( + this.request.user, + acceptLanguage?.split(',')?.[0] + ); } @Post() @@ -118,7 +120,7 @@ export class UserController { }; for (const key in userSettings) { - if (userSettings[key] === false) { + if (userSettings[key] === false || userSettings[key] === null) { delete userSettings[key]; } } diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 43b3b52c7..a4e9267ef 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -33,14 +33,17 @@ export class UserService { private readonly subscriptionService: SubscriptionService ) {} - public async getUser({ - Account, - alias, - id, - permissions, - Settings, - subscription - }: UserWithSettings): Promise<IUser> { + public async getUser( + { + Account, + alias, + id, + permissions, + Settings, + subscription + }: UserWithSettings, + aLocale = locale + ): Promise<IUser> { const access = await this.prismaService.access.findMany({ include: { User: true @@ -63,8 +66,8 @@ export class UserService { accounts: Account, settings: { ...(<UserSettings>Settings.settings), - locale, baseCurrency: Settings?.currency ?? UserService.DEFAULT_CURRENCY, + locale: (<UserSettings>Settings.settings).locale ?? aLocale, viewMode: Settings?.viewMode ?? ViewMode.DEFAULT } }; diff --git a/apps/client/src/app/adapter/date-formats.ts b/apps/client/src/app/adapter/date-formats.ts index 554f7c76e..fdf32bef8 100644 --- a/apps/client/src/app/adapter/date-formats.ts +++ b/apps/client/src/app/adapter/date-formats.ts @@ -1,16 +1,14 @@ -import { - DEFAULT_DATE_FORMAT, - DEFAULT_DATE_FORMAT_MONTH_YEAR -} from '@ghostfolio/common/config'; +import { DEFAULT_DATE_FORMAT_MONTH_YEAR } from '@ghostfolio/common/config'; +import { getDateFormatString } from '@ghostfolio/common/helper'; export const DateFormats = { display: { - dateInput: DEFAULT_DATE_FORMAT, + dateInput: getDateFormatString(), monthYearLabel: DEFAULT_DATE_FORMAT_MONTH_YEAR, - dateA11yLabel: DEFAULT_DATE_FORMAT, + dateA11yLabel: getDateFormatString(), monthYearA11yLabel: DEFAULT_DATE_FORMAT_MONTH_YEAR }, parse: { - dateInput: DEFAULT_DATE_FORMAT + dateInput: getDateFormatString() } }; diff --git a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.ts b/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.ts index 9f935cb91..f28253b90 100644 --- a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.ts +++ b/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.ts @@ -8,8 +8,11 @@ import { Output } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { DEFAULT_DATE_FORMAT } from '@ghostfolio/common/config'; -import { DATE_FORMAT } from '@ghostfolio/common/helper'; +import { + DATE_FORMAT, + getDateFormatString, + getLocale +} from '@ghostfolio/common/helper'; import { LineChartItem } from '@ghostfolio/ui/line-chart/interfaces/line-chart.interface'; import { DataSource, MarketData } from '@prisma/client'; import { @@ -35,13 +38,14 @@ import { MarketDataDetailDialog } from './market-data-detail-dialog/market-data- export class AdminMarketDataDetailComponent implements OnChanges, OnInit { @Input() dataSource: DataSource; @Input() dateOfFirstActivity: string; + @Input() locale = getLocale(); @Input() marketData: MarketData[]; @Input() symbol: string; @Output() marketDataChanged = new EventEmitter<boolean>(); public days = Array(31); - public defaultDateFormat = DEFAULT_DATE_FORMAT; + public defaultDateFormat: string; public deviceType: string; public historicalDataItems: LineChartItem[]; public marketDataByMonth: { @@ -62,6 +66,8 @@ export class AdminMarketDataDetailComponent implements OnChanges, OnInit { public ngOnInit() {} public ngOnChanges() { + this.defaultDateFormat = getDateFormatString(this.locale); + this.historicalDataItems = this.marketData.map((marketDataItem) => { return { date: format(marketDataItem.date, DATE_FORMAT), diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts index a2900ae6b..2229a3609 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts @@ -7,8 +7,9 @@ import { } from '@angular/core'; import { AdminService } from '@ghostfolio/client/services/admin.service'; import { DataService } from '@ghostfolio/client/services/data.service'; -import { DEFAULT_DATE_FORMAT } from '@ghostfolio/common/config'; -import { UniqueAsset } from '@ghostfolio/common/interfaces'; +import { UserService } from '@ghostfolio/client/services/user/user.service'; +import { getDateFormatString } from '@ghostfolio/common/helper'; +import { UniqueAsset, User } from '@ghostfolio/common/interfaces'; import { AdminMarketDataItem } from '@ghostfolio/common/interfaces/admin-market-data.interface'; import { DataSource, MarketData } from '@prisma/client'; import { Subject } from 'rxjs'; @@ -23,9 +24,10 @@ import { takeUntil } from 'rxjs/operators'; export class AdminMarketDataComponent implements OnDestroy, OnInit { public currentDataSource: DataSource; public currentSymbol: string; - public defaultDateFormat = DEFAULT_DATE_FORMAT; + public defaultDateFormat: string; public marketData: AdminMarketDataItem[] = []; public marketDataDetails: MarketData[] = []; + public user: User; private unsubscribeSubject = new Subject<void>(); @@ -35,8 +37,21 @@ export class AdminMarketDataComponent implements OnDestroy, OnInit { public constructor( private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, - private dataService: DataService - ) {} + private dataService: DataService, + private userService: UserService + ) { + this.userService.stateChanged + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((state) => { + if (state?.user) { + this.user = state.user; + + this.defaultDateFormat = getDateFormatString( + this.user.settings.locale + ); + } + }); + } /** * Initializes the controller diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.html b/apps/client/src/app/components/admin-market-data/admin-market-data.html index 7638d6110..725c75e22 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.html +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.html @@ -65,6 +65,7 @@ <gf-admin-market-data-detail [dataSource]="item.dataSource" [dateOfFirstActivity]="item.date" + [locale]="user?.settings?.locale" [marketData]="marketDataDetails" [symbol]="item.symbol" (marketDataChanged)="onMarketDataChanged($event)" diff --git a/apps/client/src/app/components/admin-overview/admin-overview.component.ts b/apps/client/src/app/components/admin-overview/admin-overview.component.ts index 013633c00..f115c4ca9 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.component.ts +++ b/apps/client/src/app/components/admin-overview/admin-overview.component.ts @@ -5,7 +5,6 @@ import { CacheService } from '@ghostfolio/client/services/cache.service'; import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { - DEFAULT_DATE_FORMAT, PROPERTY_COUPONS, PROPERTY_CURRENCIES, PROPERTY_IS_READ_ONLY_MODE, @@ -35,7 +34,6 @@ export class AdminOverviewComponent implements OnDestroy, OnInit { public customCurrencies: string[]; public dataGatheringInProgress: boolean; public dataGatheringProgress: number; - public defaultDateFormat = DEFAULT_DATE_FORMAT; public exchangeRates: { label1: string; label2: string; value: number }[]; public hasPermissionForSubscription: boolean; public hasPermissionForSystemMessage: boolean; diff --git a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts index a2607b585..f1daa7e72 100644 --- a/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts +++ b/apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts @@ -7,6 +7,10 @@ import { OnInit, ViewChild } from '@angular/core'; +import { + getNumberFormatDecimal, + getNumberFormatGroup +} from '@ghostfolio/common/helper'; import { PortfolioPerformance, ResponseError @@ -50,13 +54,14 @@ export class PortfolioPerformanceComponent implements OnChanges, OnInit { this.unit = this.baseCurrency; new CountUp('value', this.performance?.currentValue, { + decimal: getNumberFormatDecimal(this.locale), decimalPlaces: this.deviceType === 'mobile' && this.performance?.currentValue >= 100000 ? 0 : 2, duration: 1, - separator: `'` + separator: getNumberFormatGroup(this.locale) }).start(); } else if (this.performance?.currentValue === null) { this.unit = '%'; diff --git a/apps/client/src/app/pages/account/account-page.component.ts b/apps/client/src/app/pages/account/account-page.component.ts index 8352dc35e..072d91482 100644 --- a/apps/client/src/app/pages/account/account-page.component.ts +++ b/apps/client/src/app/pages/account/account-page.component.ts @@ -20,9 +20,11 @@ import { CreateAccessDto } from '@ghostfolio/api/app/access/create-access.dto'; import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; -import { DEFAULT_DATE_FORMAT, baseCurrency } from '@ghostfolio/common/config'; +import { baseCurrency } from '@ghostfolio/common/config'; +import { getDateFormatString } from '@ghostfolio/common/helper'; import { Access, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { uniq } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; import { StripeService } from 'ngx-stripe'; import { EMPTY, Subject } from 'rxjs'; @@ -45,13 +47,14 @@ export class AccountPageComponent implements OnDestroy, OnInit { public coupon: number; public couponId: string; public currencies: string[] = []; - public defaultDateFormat = DEFAULT_DATE_FORMAT; + public defaultDateFormat: string; public deviceType: string; public hasPermissionForSubscription: boolean; public hasPermissionToCreateAccess: boolean; public hasPermissionToDeleteAccess: boolean; public hasPermissionToUpdateViewMode: boolean; public hasPermissionToUpdateUserSettings: boolean; + public locales = ['de', 'de-CH', 'en-GB', 'en-US']; public price: number; public priceId: string; public snackBarRef: MatSnackBarRef<TextOnlySnackBar>; @@ -101,6 +104,10 @@ export class AccountPageComponent implements OnDestroy, OnInit { if (state?.user) { this.user = state.user; + this.defaultDateFormat = getDateFormatString( + this.user.settings.locale + ); + this.hasPermissionToCreateAccess = hasPermission( this.user.permissions, permissions.createAccess @@ -121,6 +128,9 @@ export class AccountPageComponent implements OnDestroy, OnInit { permissions.updateViewMode ); + this.locales.push(this.user.settings.locale); + this.locales = uniq(this.locales.sort()); + this.changeDetectorRef.markForCheck(); } }); @@ -143,6 +153,24 @@ export class AccountPageComponent implements OnDestroy, OnInit { this.update(); } + public onChangeUserSetting(aKey: string, aValue: string) { + this.dataService + .putUserSetting({ [aKey]: aValue }) + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe(() => { + this.userService.remove(); + + this.userService + .get() + .pipe(takeUntil(this.unsubscribeSubject)) + .subscribe((user) => { + this.user = user; + + this.changeDetectorRef.markForCheck(); + }); + }); + } + public onChangeUserSettings(aKey: string, aValue: string) { const settings = { ...this.user.settings, [aKey]: aValue }; diff --git a/apps/client/src/app/pages/account/account-page.html b/apps/client/src/app/pages/account/account-page.html index 47f8a3714..96cc04d16 100644 --- a/apps/client/src/app/pages/account/account-page.html +++ b/apps/client/src/app/pages/account/account-page.html @@ -111,6 +111,31 @@ </mat-form-field> </div> </div> + <div class="align-items-center d-flex mb-2"> + <div class="pr-1 w-50"> + <div i18n>Locale</div> + <div class="hint-text text-muted" i18n> + Date and number format + </div> + </div> + <div class="pl-1 w-50"> + <mat-form-field appearance="outline" class="w-100"> + <mat-select + name="locale" + [disabled]="!hasPermissionToUpdateUserSettings" + [value]="user.settings.locale" + (selectionChange)="onChangeUserSetting('locale', $event.value)" + > + <mat-option [value]="null"></mat-option> + <mat-option + *ngFor="let locale of locales" + [value]="locale" + >{{ locale }}</mat-option + > + </mat-select> + </mat-form-field> + </div> + </div> <div class="d-flex"> <div class="align-items-center d-flex pr-1 pt-1 w-50" i18n> View Mode diff --git a/apps/client/src/app/pages/account/account-page.module.ts b/apps/client/src/app/pages/account/account-page.module.ts index cf0f52a03..d583e47cd 100644 --- a/apps/client/src/app/pages/account/account-page.module.ts +++ b/apps/client/src/app/pages/account/account-page.module.ts @@ -10,6 +10,7 @@ import { MatSelectModule } from '@angular/material/select'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { RouterModule } from '@angular/router'; import { GfPortfolioAccessTableModule } from '@ghostfolio/client/components/access-table/access-table.module'; +import { GfValueModule } from '@ghostfolio/ui/value'; import { AccountPageRoutingModule } from './account-page-routing.module'; import { AccountPageComponent } from './account-page.component'; @@ -24,6 +25,7 @@ import { GfCreateOrUpdateAccessDialogModule } from './create-or-update-access-di FormsModule, GfCreateOrUpdateAccessDialogModule, GfPortfolioAccessTableModule, + GfValueModule, MatButtonModule, MatCardModule, MatDialogModule, diff --git a/apps/client/src/main.ts b/apps/client/src/main.ts index 54e4b175a..915236117 100644 --- a/apps/client/src/main.ts +++ b/apps/client/src/main.ts @@ -1,6 +1,7 @@ import { enableProdMode } from '@angular/core'; import { LOCALE_ID } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { locale } from '@ghostfolio/common/config'; import { InfoItem } from '@ghostfolio/common/interfaces'; import { permissions } from '@ghostfolio/common/permissions'; @@ -27,7 +28,7 @@ import { environment } from './environments/environment'; platformBrowserDynamic() .bootstrapModule(AppModule, { - providers: [{ provide: LOCALE_ID, useValue: 'de-CH' }] + providers: [{ provide: LOCALE_ID, useValue: locale }] }) .catch((error) => console.error(error)); })(); diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 535fa2ef3..133dbeef6 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -19,7 +19,7 @@ export const ghostfolioCashSymbol = `${ghostfolioScraperApiSymbolPrefix}CASH`; export const ghostfolioFearAndGreedIndexDataSource = DataSource.RAKUTEN; export const ghostfolioFearAndGreedIndexSymbol = `${ghostfolioScraperApiSymbolPrefix}FEAR_AND_GREED_INDEX`; -export const locale = 'de-CH'; +export const locale = 'en-US'; export const primaryColorHex = '#36cfcc'; export const primaryColorRgb = { @@ -44,7 +44,6 @@ export const warnColorRgb = { export const ASSET_SUB_CLASS_EMERGENCY_FUND = 'EMERGENCY_FUND'; -export const DEFAULT_DATE_FORMAT = 'dd.MM.yyyy'; export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy'; export const PROPERTY_COUPONS = 'COUPONS'; diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index e337493c7..2e45d40cd 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -2,7 +2,7 @@ import * as currencies from '@dinero.js/currencies'; import { DataSource } from '@prisma/client'; import { getDate, getMonth, getYear, parse, subDays } from 'date-fns'; -import { ghostfolioScraperApiSymbolPrefix } from './config'; +import { ghostfolioScraperApiSymbolPrefix, locale } from './config'; export function capitalize(aString: string) { return aString.charAt(0).toUpperCase() + aString.slice(1).toLowerCase(); @@ -44,6 +44,49 @@ export function getCssVariable(aCssVariable: string) { ); } +export function getDateFormatString(aLocale?: string) { + const formatObject = new Intl.DateTimeFormat(aLocale).formatToParts( + new Date() + ); + + return formatObject + .map((object) => { + switch (object.type) { + case 'day': + return 'dd'; + case 'month': + return 'MM'; + case 'year': + return 'yyyy'; + default: + return object.value; + } + }) + .join(''); +} + +export function getLocale() { + return navigator.languages?.length + ? navigator.languages[0] + : navigator.language ?? locale; +} + +export function getNumberFormatDecimal(aLocale?: string) { + const formatObject = new Intl.NumberFormat(aLocale).formatToParts(9999.99); + + return formatObject.find((object) => { + return object.type === 'decimal'; + }).value; +} + +export function getNumberFormatGroup(aLocale?: string) { + const formatObject = new Intl.NumberFormat(aLocale).formatToParts(9999.99); + + return formatObject.find((object) => { + return object.type === 'group'; + }).value; +} + export function getTextColor() { const cssVariable = getCssVariable( window.matchMedia('(prefers-color-scheme: dark)').matches diff --git a/libs/ui/src/lib/activities-table/activities-table.component.ts b/libs/ui/src/lib/activities-table/activities-table.component.ts index b8d8b0597..52bc841ff 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.ts +++ b/libs/ui/src/lib/activities-table/activities-table.component.ts @@ -20,7 +20,7 @@ import { MatSort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; import { Router } from '@angular/router'; import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; -import { DEFAULT_DATE_FORMAT } from '@ghostfolio/common/config'; +import { getDateFormatString } from '@ghostfolio/common/helper'; import { UniqueAsset } from '@ghostfolio/common/interfaces'; import { OrderWithAccount } from '@ghostfolio/common/types'; import Big from 'big.js'; @@ -63,7 +63,7 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy { @ViewChild(MatSort) sort: MatSort; public dataSource: MatTableDataSource<Activity> = new MatTableDataSource(); - public defaultDateFormat = DEFAULT_DATE_FORMAT; + public defaultDateFormat: string; public displayedColumns = []; public endOfToday = endOfToday(); public filters$: Subject<string[]> = new BehaviorSubject([]); @@ -153,6 +153,8 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy { this.isLoading = true; + this.defaultDateFormat = getDateFormatString(this.locale); + if (this.activities) { this.dataSource = new MatTableDataSource(this.activities); this.dataSource.filterPredicate = (data, filter) => { diff --git a/libs/ui/src/lib/value/value.component.ts b/libs/ui/src/lib/value/value.component.ts index daa8d72bc..08fdb413e 100644 --- a/libs/ui/src/lib/value/value.component.ts +++ b/libs/ui/src/lib/value/value.component.ts @@ -4,8 +4,8 @@ import { Input, OnChanges } from '@angular/core'; -import { DEFAULT_DATE_FORMAT, locale } from '@ghostfolio/common/config'; -import { format, isDate, parseISO } from 'date-fns'; +import { getLocale } from '@ghostfolio/common/helper'; +import { isDate, parseISO } from 'date-fns'; import { isNumber } from 'lodash'; @Component({ @@ -21,7 +21,7 @@ export class ValueComponent implements OnChanges { @Input() isCurrency = false; @Input() isPercent = false; @Input() label = ''; - @Input() locale = locale; + @Input() locale = getLocale(); @Input() position = ''; @Input() precision: number | undefined; @Input() size: 'large' | 'medium' | 'small' = 'small'; @@ -102,10 +102,13 @@ export class ValueComponent implements OnChanges { try { if (isDate(parseISO(this.value))) { - this.formattedValue = format( - new Date(<string>this.value), - DEFAULT_DATE_FORMAT - ); + this.formattedValue = new Date( + <string>this.value + ).toLocaleDateString(this.locale, { + day: '2-digit', + month: '2-digit', + year: 'numeric' + }); } } catch { this.formattedValue = this.value;