Browse Source

Initial setup

pull/3190/head
Thomas Kaul 1 year ago
parent
commit
ca0fb33176
  1. 33
      apps/api/src/app/portfolio/portfolio.service.ts
  2. 16
      apps/api/src/app/user/update-user-setting.dto.ts
  3. 26
      apps/api/src/app/user/user.service.ts
  4. 4
      apps/client/src/app/services/user/user.service.ts
  5. 1
      libs/common/src/lib/interfaces/user.interface.ts
  6. 10
      libs/common/src/lib/types/date-range.type.ts
  7. 67
      libs/ui/src/lib/assistant/assistant.component.ts
  8. 6
      libs/ui/src/lib/assistant/interfaces/interfaces.ts

33
apps/api/src/app/portfolio/portfolio.service.ts

@ -1178,6 +1178,7 @@ export class PortfolioService {
})
);
// TODO: Refactor to getInterval()?
const startDate = this.getStartDate(dateRange, portfolioStart);
const {
currentValueInBaseCurrency,
@ -1192,7 +1193,7 @@ export class PortfolioService {
netPerformancePercentageWithCurrencyEffect,
netPerformanceWithCurrencyEffect,
totalInvestment
} = await portfolioCalculator.getCurrentPositions(startDate);
} = await portfolioCalculator.getCurrentPositions(startDate); // TODO: Provide endDate
let currentNetPerformance = netPerformance;
@ -1452,6 +1453,8 @@ export class PortfolioService {
dateRange,
portfolioCalculator.getStartDate()
);
// TODO
const endDate = new Date();
const daysInMarket = differenceInDays(endDate, startDate) + 1;
const step = withDataDecimation
@ -1618,22 +1621,24 @@ export class PortfolioService {
}
private getStartDate(aDateRange: DateRange, portfolioStart: Date) {
let startDate = portfolioStart;
switch (aDateRange) {
case '1d':
portfolioStart = max([
portfolioStart,
startDate = max([
startDate,
subDays(new Date().setHours(0, 0, 0, 0), 1)
]);
break;
case 'mtd':
portfolioStart = max([
portfolioStart,
startDate = max([
startDate,
subDays(startOfMonth(new Date().setHours(0, 0, 0, 0)), 1)
]);
break;
case 'wtd':
portfolioStart = max([
portfolioStart,
startDate = max([
startDate,
subDays(
startOfWeek(new Date().setHours(0, 0, 0, 0), { weekStartsOn: 1 }),
1
@ -1641,26 +1646,26 @@ export class PortfolioService {
]);
break;
case 'ytd':
portfolioStart = max([
portfolioStart,
startDate = max([
startDate,
subDays(startOfYear(new Date().setHours(0, 0, 0, 0)), 1)
]);
break;
case '1y':
portfolioStart = max([
portfolioStart,
startDate = max([
startDate,
subYears(new Date().setHours(0, 0, 0, 0), 1)
]);
break;
case '5y':
portfolioStart = max([
portfolioStart,
startDate = max([
startDate,
subYears(new Date().setHours(0, 0, 0, 0), 5)
]);
break;
}
return portfolioStart;
return startDate;
}
private getStreaks({

16
apps/api/src/app/user/update-user-setting.dto.ts

@ -14,6 +14,7 @@ import {
IsOptional,
IsString
} from 'class-validator';
import { eachYearOfInterval, format } from 'date-fns';
export class UpdateUserSettingDto {
@IsNumber()
@ -32,7 +33,20 @@ export class UpdateUserSettingDto {
@IsOptional()
colorScheme?: ColorScheme;
@IsIn(<DateRange[]>['1d', '1y', '5y', 'max', 'mtd', 'wtd', 'ytd'])
@IsIn(<DateRange[]>[
'1d',
'1y',
'5y',
'max',
'mtd',
'wtd',
'ytd',
...eachYearOfInterval({ end: new Date(1900), start: new Date() }).map(
(date) => {
return format(date, 'yyyy');
}
)
])
@IsOptional()
dateRange?: DateRange;

26
apps/api/src/app/user/user.service.ts

@ -51,13 +51,22 @@ export class UserService {
{ Account, id, permissions, Settings, subscription }: UserWithSettings,
aLocale = locale
): Promise<IUser> {
const access = await this.prismaService.access.findMany({
include: {
User: true
},
orderBy: { alias: 'asc' },
where: { GranteeUser: { id } }
});
let [access, firstActivity, tags] = await Promise.all([
this.prismaService.access.findMany({
include: {
User: true
},
orderBy: { alias: 'asc' },
where: { GranteeUser: { id } }
}),
this.prismaService.order.findFirst({
orderBy: {
date: 'asc'
},
where: { userId: id }
}),
this.tagService.getByUser(id)
]);
let systemMessage: SystemMessage;
@ -69,8 +78,6 @@ export class UserService {
systemMessage = systemMessageProperty;
}
let tags = await this.tagService.getByUser(id);
if (
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
subscription.type === 'Basic'
@ -91,6 +98,7 @@ export class UserService {
};
}),
accounts: Account,
dateOfFirstActivity: firstActivity?.date ?? new Date(),
settings: {
...(<UserSettings>Settings.settings),
locale: (<UserSettings>Settings.settings)?.locale ?? aLocale

4
apps/client/src/app/services/user/user.service.ts

@ -82,6 +82,10 @@ export class UserService extends ObservableStore<UserStoreState> {
private fetchUser(): Observable<User> {
return this.http.get<any>('/api/v1/user').pipe(
map((user) => {
if (user.dateOfFirstActivity) {
user.dateOfFirstActivity = parseISO(user.dateOfFirstActivity);
}
if (user.settings?.retirementDate) {
user.settings.retirementDate = parseISO(user.settings.retirementDate);
}

1
libs/common/src/lib/interfaces/user.interface.ts

@ -13,6 +13,7 @@ export interface User {
id: string;
}[];
accounts: Account[];
dateOfFirstActivity: Date;
id: string;
permissions: string[];
settings: UserSettings;

10
libs/common/src/lib/types/date-range.type.ts

@ -1 +1,9 @@
export type DateRange = '1d' | '1y' | '5y' | 'max' | 'mtd' | 'wtd' | 'ytd';
export type DateRange =
| '1d'
| '1y'
| '5y'
| 'max'
| 'mtd'
| 'wtd'
| 'ytd'
| string; // '2024', '2023', '2022', etc.

67
libs/ui/src/lib/assistant/assistant.component.ts

@ -24,6 +24,7 @@ import {
import { FormBuilder, FormControl } from '@angular/forms';
import { MatMenuTrigger } from '@angular/material/menu';
import { Account, AssetClass } from '@prisma/client';
import { eachYearOfInterval, format } from 'date-fns';
import { EMPTY, Observable, Subject, lastValueFrom } from 'rxjs';
import {
catchError,
@ -35,7 +36,11 @@ import {
} from 'rxjs/operators';
import { AssistantListItemComponent } from './assistant-list-item/assistant-list-item.component';
import { ISearchResultItem, ISearchResults } from './interfaces/interfaces';
import {
IDateRangeOption,
ISearchResultItem,
ISearchResults
} from './interfaces/interfaces';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
@ -95,27 +100,7 @@ export class AssistantComponent implements OnChanges, OnDestroy, OnInit {
public accounts: Account[] = [];
public assetClasses: Filter[] = [];
public dateRangeFormControl = new FormControl<string>(undefined);
public readonly dateRangeOptions = [
{ label: $localize`Today`, value: '1d' },
{
label: $localize`Week to date` + ' (' + $localize`WTD` + ')',
value: 'wtd'
},
{
label: $localize`Month to date` + ' (' + $localize`MTD` + ')',
value: 'mtd'
},
{
label: $localize`Year to date` + ' (' + $localize`YTD` + ')',
value: 'ytd'
},
{ label: '1 ' + $localize`year` + ' (' + $localize`1Y` + ')', value: '1y' },
{
label: '5 ' + $localize`years` + ' (' + $localize`5Y` + ')',
value: '5y'
},
{ label: $localize`Max`, value: 'max' }
];
public dateRangeOptions: IDateRangeOption[] = [];
public filterForm = this.formBuilder.group({
account: new FormControl<string>(undefined),
assetClass: new FormControl<string>(undefined),
@ -199,6 +184,44 @@ export class AssistantComponent implements OnChanges, OnDestroy, OnInit {
}
public ngOnChanges() {
this.dateRangeOptions = [
{ label: $localize`Today`, value: '1d' },
{
label: $localize`Week to date` + ' (' + $localize`WTD` + ')',
value: 'wtd'
},
{
label: $localize`Month to date` + ' (' + $localize`MTD` + ')',
value: 'mtd'
},
{
label: $localize`Year to date` + ' (' + $localize`YTD` + ')',
value: 'ytd'
},
{
label: '1 ' + $localize`year` + ' (' + $localize`1Y` + ')',
value: '1y'
},
{
label: '5 ' + $localize`years` + ' (' + $localize`5Y` + ')',
value: '5y'
},
{ label: $localize`Max`, value: 'max' }
];
if (this.user?.settings?.isExperimentalFeatures) {
this.dateRangeOptions = this.dateRangeOptions.concat(
eachYearOfInterval({
end: new Date(),
start: this.user?.dateOfFirstActivity ?? new Date()
})
.map((date) => {
return { label: format(date, 'yyyy'), value: format(date, 'yyyy') };
})
.slice(0, -1)
);
}
this.dateRangeFormControl.setValue(this.user?.settings?.dateRange ?? null);
this.filterForm.setValue(

6
libs/ui/src/lib/assistant/interfaces/interfaces.ts

@ -1,4 +1,10 @@
import { UniqueAsset } from '@ghostfolio/common/interfaces';
import { DateRange } from '@ghostfolio/common/types';
export interface IDateRangeOption {
label: string;
value: DateRange;
}
export interface ISearchResultItem extends UniqueAsset {
assetSubClassString: string;

Loading…
Cancel
Save