Bugfix/fix state handling of currency selector component (#2795) (#3429)

* Fix state handling of currency selector component

* Update changelog
pull/3445/head
Eduardo Marinho 9 months ago committed by GitHub
parent b12ac1fe84
commit 60ef46accf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Fixed an issue with the initial annual interest rate in the _FIRE_ calculator - Fixed an issue with the initial annual interest rate in the _FIRE_ calculator
- Fixed the state handling in the currency selector
## 2.83.0 - 2024-05-30 ## 2.83.0 - 2024-05-30

@ -8,7 +8,6 @@ import { ghostfolioScraperApiSymbolPrefix } from '@ghostfolio/common/config';
import { DATE_FORMAT } from '@ghostfolio/common/helper'; import { DATE_FORMAT } from '@ghostfolio/common/helper';
import { import {
AdminMarketDataDetails, AdminMarketDataDetails,
Currency,
UniqueAsset UniqueAsset
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { translate } from '@ghostfolio/ui/i18n'; import { translate } from '@ghostfolio/ui/i18n';
@ -73,7 +72,7 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
public countries: { public countries: {
[code: string]: { name: string; value: number }; [code: string]: { name: string; value: number };
}; };
public currencies: Currency[] = []; public currencies: string[] = [];
public ghostfolioScraperApiSymbolPrefix = ghostfolioScraperApiSymbolPrefix; public ghostfolioScraperApiSymbolPrefix = ghostfolioScraperApiSymbolPrefix;
public isBenchmark = false; public isBenchmark = false;
public marketDataDetails: MarketData[] = []; public marketDataDetails: MarketData[] = [];
@ -102,10 +101,7 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
const { benchmarks, currencies } = this.dataService.fetchInfo(); const { benchmarks, currencies } = this.dataService.fetchInfo();
this.benchmarks = benchmarks; this.benchmarks = benchmarks;
this.currencies = currencies.map((currency) => ({ this.currencies = currencies;
label: currency,
value: currency
}));
this.initialize(); this.initialize();
} }
@ -293,9 +289,7 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
assetClass: this.assetProfileForm.get('assetClass').value, assetClass: this.assetProfileForm.get('assetClass').value,
assetSubClass: this.assetProfileForm.get('assetSubClass').value, assetSubClass: this.assetProfileForm.get('assetSubClass').value,
comment: this.assetProfileForm.get('comment').value || null, comment: this.assetProfileForm.get('comment').value || null,
currency: (<Currency>( currency: this.assetProfileForm.get('currency').value,
(<unknown>this.assetProfileForm.get('currency').value)
))?.value,
name: this.assetProfileForm.get('name').value, name: this.assetProfileForm.get('name').value,
url: this.assetProfileForm.get('url').value || null url: this.assetProfileForm.get('url').value || null
}; };
@ -343,8 +337,7 @@ export class AssetProfileDialog implements OnDestroy, OnInit {
' ' + ' ' +
price + price +
' ' + ' ' +
(<Currency>(<unknown>this.assetProfileForm.get('currency').value)) this.assetProfileForm.get('currency').value
?.value
); );
}); });
} }

@ -2,7 +2,6 @@ import { CreateAccountDto } from '@ghostfolio/api/app/account/create-account.dto
import { UpdateAccountDto } from '@ghostfolio/api/app/account/update-account.dto'; import { UpdateAccountDto } from '@ghostfolio/api/app/account/update-account.dto';
import { DataService } from '@ghostfolio/client/services/data.service'; import { DataService } from '@ghostfolio/client/services/data.service';
import { validateObjectForForm } from '@ghostfolio/client/util/form.util'; import { validateObjectForForm } from '@ghostfolio/client/util/form.util';
import { Currency } from '@ghostfolio/common/interfaces';
import { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
@ -33,7 +32,7 @@ import { CreateOrUpdateAccountDialogParams } from './interfaces/interfaces';
}) })
export class CreateOrUpdateAccountDialog implements OnDestroy { export class CreateOrUpdateAccountDialog implements OnDestroy {
public accountForm: FormGroup; public accountForm: FormGroup;
public currencies: Currency[] = []; public currencies: string[] = [];
public filteredPlatforms: Observable<Platform[]>; public filteredPlatforms: Observable<Platform[]>;
public platforms: Platform[]; public platforms: Platform[];
@ -49,10 +48,7 @@ export class CreateOrUpdateAccountDialog implements OnDestroy {
public ngOnInit() { public ngOnInit() {
const { currencies, platforms } = this.dataService.fetchInfo(); const { currencies, platforms } = this.dataService.fetchInfo();
this.currencies = currencies.map((currency) => ({ this.currencies = currencies;
label: currency,
value: currency
}));
this.platforms = platforms; this.platforms = platforms;
this.accountForm = this.formBuilder.group({ this.accountForm = this.formBuilder.group({
@ -107,7 +103,7 @@ export class CreateOrUpdateAccountDialog implements OnDestroy {
const account: CreateAccountDto | UpdateAccountDto = { const account: CreateAccountDto | UpdateAccountDto = {
balance: this.accountForm.get('balance').value, balance: this.accountForm.get('balance').value,
comment: this.accountForm.get('comment').value || null, comment: this.accountForm.get('comment').value || null,
currency: this.accountForm.get('currency').value?.value, currency: this.accountForm.get('currency').value,
id: this.accountForm.get('accountId').value, id: this.accountForm.get('accountId').value,
isExcluded: this.accountForm.get('isExcluded').value, isExcluded: this.accountForm.get('isExcluded').value,
name: this.accountForm.get('name').value, name: this.accountForm.get('name').value,

@ -1,4 +0,0 @@
export interface Currency {
label: string;
value: string;
}

@ -11,7 +11,6 @@ import type { BenchmarkMarketDataDetails } from './benchmark-market-data-details
import type { BenchmarkProperty } from './benchmark-property.interface'; import type { BenchmarkProperty } from './benchmark-property.interface';
import type { Benchmark } from './benchmark.interface'; import type { Benchmark } from './benchmark.interface';
import type { Coupon } from './coupon.interface'; import type { Coupon } from './coupon.interface';
import type { Currency } from './currency.interface';
import type { DataProviderInfo } from './data-provider-info.interface'; import type { DataProviderInfo } from './data-provider-info.interface';
import type { EnhancedSymbolProfile } from './enhanced-symbol-profile.interface'; import type { EnhancedSymbolProfile } from './enhanced-symbol-profile.interface';
import type { Export } from './export.interface'; import type { Export } from './export.interface';
@ -66,7 +65,6 @@ export {
BenchmarkProperty, BenchmarkProperty,
BenchmarkResponse, BenchmarkResponse,
Coupon, Coupon,
Currency,
DataProviderInfo, DataProviderInfo,
EnhancedSymbolProfile, EnhancedSymbolProfile,
Export, Export,

@ -8,12 +8,11 @@
<mat-autocomplete <mat-autocomplete
#currencyAutocomplete="matAutocomplete" #currencyAutocomplete="matAutocomplete"
[displayWith]="displayFn"
(optionSelected)="onUpdateCurrency($event)" (optionSelected)="onUpdateCurrency($event)"
> >
@for (currencyItem of filteredCurrencies; track currencyItem) { @for (currency of filteredCurrencies; track currency) {
<mat-option class="line-height-1" [value]="currencyItem"> <mat-option class="line-height-1" [value]="currency">
{{ currencyItem.label }} {{ currency }}
</mat-option> </mat-option>
} }
</mat-autocomplete> </mat-autocomplete>

@ -1,4 +1,3 @@
import { Currency } from '@ghostfolio/common/interfaces';
import { AbstractMatFormField } from '@ghostfolio/ui/shared/abstract-mat-form-field'; import { AbstractMatFormField } from '@ghostfolio/ui/shared/abstract-mat-form-field';
import { FocusMonitor } from '@angular/cdk/a11y'; import { FocusMonitor } from '@angular/cdk/a11y';
@ -59,10 +58,10 @@ import { map, startWith, takeUntil } from 'rxjs/operators';
templateUrl: 'currency-selector.component.html' templateUrl: 'currency-selector.component.html'
}) })
export class GfCurrencySelectorComponent export class GfCurrencySelectorComponent
extends AbstractMatFormField<Currency> extends AbstractMatFormField<string>
implements OnInit, OnDestroy implements OnInit, OnDestroy
{ {
@Input() private currencies: Currency[] = []; @Input() private currencies: string[] = [];
@Input() private formControlName: string; @Input() private formControlName: string;
@ViewChild(MatInput) private input: MatInput; @ViewChild(MatInput) private input: MatInput;
@ -71,7 +70,7 @@ export class GfCurrencySelectorComponent
public currencyAutocomplete: MatAutocomplete; public currencyAutocomplete: MatAutocomplete;
public control = new FormControl(); public control = new FormControl();
public filteredCurrencies: Currency[] = []; public filteredCurrencies: string[] = [];
private unsubscribeSubject = new Subject<void>(); private unsubscribeSubject = new Subject<void>();
@ -98,7 +97,7 @@ export class GfCurrencySelectorComponent
const control = formGroup.get(this.formControlName); const control = formGroup.get(this.formControlName);
if (control) { if (control) {
this.value = this.currencies.find(({ value }) => { this.value = this.currencies.find((value) => {
return value === control.value; return value === control.value;
}); });
} }
@ -107,8 +106,8 @@ export class GfCurrencySelectorComponent
this.control.valueChanges this.control.valueChanges
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => { .subscribe(() => {
if (super.value?.value) { if (super.value) {
super.value.value = null; super.value = null;
} }
}); });
@ -125,10 +124,6 @@ export class GfCurrencySelectorComponent
}); });
} }
public displayFn(currency: Currency) {
return currency?.label ?? '';
}
public get empty() { public get empty() {
return this.input?.empty; return this.input?.empty;
} }
@ -146,17 +141,12 @@ export class GfCurrencySelectorComponent
} }
public onUpdateCurrency(event: MatAutocompleteSelectedEvent) { public onUpdateCurrency(event: MatAutocompleteSelectedEvent) {
super.value = { super.value = event.option.value;
label: event.option.value.label,
value: event.option.value.value
} as Currency;
} }
public set value(value: Currency) { public set value(value: string) {
const newValue = this.control.setValue(value);
typeof value === 'object' && value !== null ? { ...value } : value; super.value = value;
this.control.setValue(newValue);
super.value = newValue;
} }
public ngOnDestroy() { public ngOnDestroy() {
@ -166,21 +156,16 @@ export class GfCurrencySelectorComponent
this.unsubscribeSubject.complete(); this.unsubscribeSubject.complete();
} }
private filter(value: Currency | string) { private filter(value: string) {
const filterValue = const filterValue = value?.toLowerCase();
typeof value === 'string'
? value?.toLowerCase()
: value?.value.toLowerCase();
return this.currencies.filter((currency) => { return this.currencies.filter((currency) => {
return currency.value.toLowerCase().startsWith(filterValue); return currency.toLowerCase().startsWith(filterValue);
}); });
} }
private validateRequired() { private validateRequired() {
const requiredCheck = super.required const requiredCheck = super.required ? !super.value : false;
? !super.value?.label || !super.value?.value
: false;
if (requiredCheck) { if (requiredCheck) {
this.ngControl.control.setErrors({ invalidData: true }); this.ngControl.control.setErrors({ invalidData: true });

Loading…
Cancel
Save