Add option for setting a default target currency (#1210)

*  Add option for setting a default target currency

* Added new test case

* Simplify code

---------

Co-authored-by: Oliver Schwendener <oliver.schwendener@proton.me>
This commit is contained in:
Peter Mikkelsen 2024-09-24 08:06:25 +02:00 committed by GitHub
parent 30f4e00cae
commit 5cbca27034
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 66 additions and 7 deletions

View File

@ -1,4 +1,5 @@
import type { AssetPathResolver } from "@Core/AssetPathResolver";
import type { SettingsManager } from "@Core/SettingsManager";
import { describe, expect, it, vi } from "vitest";
import { CurrencyConversion } from "./CurrencyConversion";
import type { Rates } from "./Rates";
@ -9,10 +10,12 @@ describe(CurrencyConversion, () => {
expectedResult,
userInput,
rates,
defaultTarget,
}: {
expectedResult: string;
userInput: string;
rates: Rates;
defaultTarget?: string;
}) => {
const imageFilePath = "/path/to/image";
const getExtensionAssetPathMock = vi.fn().mockReturnValue(imageFilePath);
@ -22,12 +25,19 @@ describe(CurrencyConversion, () => {
getModuleAssetPath: () => null,
};
const currencyConversion = new CurrencyConversion(null, null, assetPathResolver);
const getValueMock = vi.fn().mockReturnValue(defaultTarget);
const settingsManager = <SettingsManager>{
getValue: (k, d, s) => getValueMock(k, d, s),
};
const currencyConversion = new CurrencyConversion(settingsManager, null, assetPathResolver);
currencyConversion["rates"] = rates;
const actual = currencyConversion.getInstantSearchResultItems(userInput);
expect(actual.length).toEqual(1);
expect(actual[0].name).toEqual(expectedResult);
expect(actual[0].image).toEqual({ url: `file://${imageFilePath}` });
expect(getExtensionAssetPathMock).toHaveBeenCalledWith(currencyConversion.id, "currency-conversion.png");
@ -38,7 +48,9 @@ describe(CurrencyConversion, () => {
currencyConversion["rates"] = { chf: { usd: 2 } };
expect(currencyConversion.getInstantSearchResultItems("1")).toEqual([]);
expect(currencyConversion.getInstantSearchResultItems("1 CHF to")).toEqual([]);
expect(currencyConversion.getInstantSearchResultItems("1 CHF to USD else")).toEqual([]);
});
it("should return empty array when first part in user input is not numerical", () => {
@ -77,8 +89,15 @@ describe(CurrencyConversion, () => {
it("should convert currencies based on the rates when user input matches expected pattern", () => {
const rates: Rates = { chf: { usd: 2, eur: 0.5 } };
testSuccessfulConversion({ expectedResult: "2.00 USD", userInput: " 1 CHF to USD ", rates });
testSuccessfulConversion({ expectedResult: "2.00 USD", userInput: "1 CHF to USD", rates });
testSuccessfulConversion({ expectedResult: "0.50 EUR", userInput: "1 CHF in EUR", rates });
});
it("should convert currencies to default currency when user input matches expected pattern", () => {
const rates: Rates = { chf: { usd: 2, eur: 0.5 } };
testSuccessfulConversion({ expectedResult: "2.00 USD", userInput: "1 CHF", rates, defaultTarget: "usd" });
});
});
});

View File

@ -26,6 +26,7 @@ export class CurrencyConversion implements Extension {
private readonly defaultSettings = {
currencies: ["usd", "chf", "eur"],
defaultTargetCurrency: "eur",
};
private rates: Rates;
@ -42,11 +43,14 @@ export class CurrencyConversion implements Extension {
const parts = searchTerm.trim().split(" ");
const validators = [
() => parts.length === 4,
() => parts.length === 2 || parts.length === 4,
() => !isNaN(Number(parts[0])),
() => Object.keys(this.rates).includes(parts[1].toLowerCase()),
() => ["in", "to"].includes(parts[2].toLowerCase()),
() => Object.keys(this.rates[parts[1].toLowerCase()]).includes(parts[3].toLowerCase()),
() => parts.length === 2 || (parts.length === 4 && ["in", "to"].includes(parts[2].toLowerCase())),
() =>
Object.keys(this.rates[parts[1].toLowerCase()]).includes(
parts.length === 4 ? parts[3].toLowerCase() : this.getDefaultTargetCurrency(),
),
];
for (const validator of validators) {
@ -57,7 +61,7 @@ export class CurrencyConversion implements Extension {
const value = Number(parts[0]);
const base = parts[1];
const target = parts[3];
const target = parts.length === 4 ? parts[3].toLowerCase() : this.getDefaultTargetCurrency();
const conversionResult = convert({ value, base, target, rates: this.rates });
@ -78,7 +82,7 @@ export class CurrencyConversion implements Extension {
},
id: `currency-conversion:instant-result`,
image: this.getImage(),
name: `${conversionResult.result.toFixed(2)} ${parts[3].toUpperCase()}`,
name: `${conversionResult.result.toFixed(2)} ${target.toUpperCase()}`,
},
];
}
@ -107,6 +111,7 @@ export class CurrencyConversion implements Extension {
"en-US": {
extensionName: "Currency Conversion",
currencies: "Currencies",
defaultTargetCurrency: "Default Target Currency",
selectCurrencies: "Select currencies",
copyToClipboard: "Copy to clipboard",
currencyConversion: "Currency Conversion",
@ -114,6 +119,7 @@ export class CurrencyConversion implements Extension {
"de-CH": {
extensionName: "Währungsumrechnung",
currencies: "Währungen",
defaultTargetCurrency: "Standard-Zielwährung",
selectCurrencies: "Währungen wählen",
copyToClipboard: "In Zwischenablage kopieren",
currencyConversion: "Währungsumrechnung",
@ -122,7 +128,10 @@ export class CurrencyConversion implements Extension {
}
public getSettingKeysTriggeringRescan(): string[] {
return [getExtensionSettingKey(this.id, "currencies")];
return [
getExtensionSettingKey(this.id, "currencies"),
getExtensionSettingKey(this.id, "defaultTargetCurrency"),
];
}
private async setRates(): Promise<void> {
@ -143,4 +152,11 @@ export class CurrencyConversion implements Extension {
this.rates[currency] = responseJson[currency];
}
private getDefaultTargetCurrency(): string {
return this.settingsManager.getValue<string>(
getExtensionSettingKey(this.id, "defaultTargetCurrency"),
this.getSettingDefaultValue<string>("defaultTargetCurrency"),
);
}
}

View File

@ -14,6 +14,11 @@ export const CurrencyConversionSettings = () => {
key: "currencies",
});
const { value: defaultTargetCurrency, updateValue: setDefaultTargetCurrency } = useExtensionSetting<string>({
extensionId: "CurrencyConversion",
key: "defaultTargetCurrency",
});
return (
<SettingGroupList>
<SettingGroup title={t("extensionName")}>
@ -35,6 +40,25 @@ export const CurrencyConversionSettings = () => {
</Dropdown>
}
/>
<Setting
label={t("defaultTargetCurrency")}
control={
<Dropdown
selectedOptions={[defaultTargetCurrency]}
value={defaultTargetCurrency.toUpperCase()}
placeholder={t("selectDefaultTargetCurrency")}
onOptionSelect={(_, { optionValue }) =>
optionValue && setDefaultTargetCurrency(optionValue)
}
>
{currencies.map((currency) => (
<Option key={currency} value={currency}>
{`${currency.toUpperCase()}`}
</Option>
))}
</Dropdown>
}
/>
</SettingGroup>
</SettingGroupList>
);