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/user.service.ts b/apps/api/src/app/user/user.service.ts index 43b3b52c7..b85f226a4 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -63,7 +63,7 @@ export class UserService { accounts: Account, settings: { ...(Settings.settings), - locale, + locale: (Settings.settings).locale ?? locale, baseCurrency: Settings?.currency ?? UserService.DEFAULT_CURRENCY, 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.html b/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.html index 7264be84d..02b8934d9 100644 --- a/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.html +++ b/apps/client/src/app/components/admin-market-data-detail/admin-market-data-detail.component.html @@ -25,7 +25,7 @@ }" [title]=" (itemByMonth.key + '-' + (i + 1 < 10 ? '0' + (i + 1) : i + 1) - | date: defaultDateFormat) ?? '' + | date: dateFormat) ?? '' " (click)=" onOpenMarketDataDetail({ 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..d182e6375 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,7 @@ 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 } from '@ghostfolio/common/helper'; import { LineChartItem } from '@ghostfolio/ui/line-chart/interfaces/line-chart.interface'; import { DataSource, MarketData } from '@prisma/client'; import { @@ -40,8 +39,8 @@ export class AdminMarketDataDetailComponent implements OnChanges, OnInit { @Output() marketDataChanged = new EventEmitter(); + public dateFormat = getDateFormatString(); public days = Array(31); - public defaultDateFormat = DEFAULT_DATE_FORMAT; public deviceType: string; public historicalDataItems: LineChartItem[]; public marketDataByMonth: { 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..8368b6f9c 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,8 @@ 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 { 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 +23,9 @@ import { takeUntil } from 'rxjs/operators'; export class AdminMarketDataComponent implements OnDestroy, OnInit { public currentDataSource: DataSource; public currentSymbol: string; - public defaultDateFormat = DEFAULT_DATE_FORMAT; public marketData: AdminMarketDataItem[] = []; public marketDataDetails: MarketData[] = []; + public user: User; private unsubscribeSubject = new Subject(); @@ -35,8 +35,17 @@ 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; + } + }); + } /** * 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..874b01767 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 @@ -21,7 +21,10 @@ {{ item.symbol }} {{ item.dataSource }} - {{ (item.date | date: defaultDateFormat) ?? '' }} + {{ item.activityCount }} {{ item.marketDataItemCount }} diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.module.ts b/apps/client/src/app/components/admin-market-data/admin-market-data.module.ts index 1a3432fff..d9b87a80d 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.module.ts +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.module.ts @@ -3,6 +3,7 @@ import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatMenuModule } from '@angular/material/menu'; import { GfAdminMarketDataDetailModule } from '@ghostfolio/client/components/admin-market-data-detail/admin-market-data-detail.module'; +import { GfValueModule } from '@ghostfolio/ui/value'; import { AdminMarketDataComponent } from './admin-market-data.component'; @@ -11,6 +12,7 @@ import { AdminMarketDataComponent } from './admin-market-data.component'; imports: [ CommonModule, GfAdminMarketDataDetailModule, + GfValueModule, MatButtonModule, MatMenuModule ], 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/pages/account/account-page.component.ts b/apps/client/src/app/pages/account/account-page.component.ts index 8352dc35e..440ba178d 100644 --- a/apps/client/src/app/pages/account/account-page.component.ts +++ b/apps/client/src/app/pages/account/account-page.component.ts @@ -20,7 +20,7 @@ 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 { Access, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { DeviceDetectorService } from 'ngx-device-detector'; @@ -45,7 +45,6 @@ export class AccountPageComponent implements OnDestroy, OnInit { public coupon: number; public couponId: string; public currencies: string[] = []; - public defaultDateFormat = DEFAULT_DATE_FORMAT; public deviceType: string; public hasPermissionForSubscription: boolean; public hasPermissionToCreateAccess: boolean; diff --git a/apps/client/src/app/pages/account/account-page.html b/apps/client/src/app/pages/account/account-page.html index 47f8a3714..40b81627d 100644 --- a/apps/client/src/app/pages/account/account-page.html +++ b/apps/client/src/app/pages/account/account-page.html @@ -24,8 +24,12 @@ >
- Valid until {{ user?.subscription?.expiresAt | date: - defaultDateFormat }} + Valid until +
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/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 535fa2ef3..ebe35342e 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -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..bb6f6e94d 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,33 @@ 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 getTextColor() { const cssVariable = getCssVariable( window.matchMedia('(prefers-color-scheme: dark)').matches diff --git a/libs/ui/src/lib/activities-table/activities-table.component.html b/libs/ui/src/lib/activities-table/activities-table.component.html index cbcb7da9c..01cfdbdf5 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.html +++ b/libs/ui/src/lib/activities-table/activities-table.component.html @@ -71,7 +71,7 @@
- {{ element.date | date: defaultDateFormat }} +
Total 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..cf27e387d 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,6 @@ 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 { UniqueAsset } from '@ghostfolio/common/interfaces'; import { OrderWithAccount } from '@ghostfolio/common/types'; import Big from 'big.js'; @@ -63,7 +62,6 @@ export class ActivitiesTableComponent implements OnChanges, OnDestroy { @ViewChild(MatSort) sort: MatSort; public dataSource: MatTableDataSource = new MatTableDataSource(); - public defaultDateFormat = DEFAULT_DATE_FORMAT; public displayedColumns = []; public endOfToday = endOfToday(); public filters$: Subject = new BehaviorSubject([]); 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(this.value), - DEFAULT_DATE_FORMAT - ); + this.formattedValue = new Date( + this.value + ).toLocaleDateString(this.locale, { + day: '2-digit', + month: '2-digit', + year: 'numeric' + }); } } catch { this.formattedValue = this.value;