Skip to content

Commit

Permalink
✨ Add option for setting a default target currency (#1210)
Browse files Browse the repository at this point in the history
* ✨ Add option for setting a default target currency

* Added new test case

* Simplify code

---------

Co-authored-by: Oliver Schwendener <[email protected]>
  • Loading branch information
peterphmikkelsen and oliverschwendener authored Sep 24, 2024
1 parent 30f4e00 commit 5cbca27
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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);
Expand All @@ -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");
Expand All @@ -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", () => {
Expand Down Expand Up @@ -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" });
});
});
});
28 changes: 22 additions & 6 deletions src/main/Extensions/CurrencyConversion/CurrencyConversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class CurrencyConversion implements Extension {

private readonly defaultSettings = {
currencies: ["usd", "chf", "eur"],
defaultTargetCurrency: "eur",
};

private rates: Rates;
Expand All @@ -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) {
Expand All @@ -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 });

Expand All @@ -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()}`,
},
];
}
Expand Down Expand Up @@ -107,13 +111,15 @@ 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",
},
"de-CH": {
extensionName: "Währungsumrechnung",
currencies: "Währungen",
defaultTargetCurrency: "Standard-Zielwährung",
selectCurrencies: "Währungen wählen",
copyToClipboard: "In Zwischenablage kopieren",
currencyConversion: "Währungsumrechnung",
Expand All @@ -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> {
Expand All @@ -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"),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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")}>
Expand All @@ -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>
);
Expand Down

0 comments on commit 5cbca27

Please sign in to comment.