Skip to content

Commit

Permalink
Balances can now be displayed in the desired currency. (#44)
Browse files Browse the repository at this point in the history
* A Turkish language file has been added. Additionally, hardcoded values in some files have been made compatible with translations, and incorrect values have been corrected.

* Balances are now displayed in your desired currency. Users can select their preferred currency from Settings > General > Currencies. The language file has been updated.

* Tests fixed.

* update version

Signed-off-by: Ruben <rubdeivis@gmail.com>

---------

Signed-off-by: Ruben <rubdeivis@gmail.com>
Co-authored-by: Ruben <rubdeivis@gmail.com>
  • Loading branch information
egemenkus and rubenguc authored Oct 24, 2023
1 parent f57ab63 commit f44c1e2
Show file tree
Hide file tree
Showing 19 changed files with 179 additions and 31 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "kuma-wallet",
"displayName": "Kuma Wallet",
"version": "0.3.9",
"version": "0.3.10",
"description": "Kuma a cross-chain wallet that offers seamless management and transfer of assets between EVM and WASM chains.",
"author": "Blockcoders Engineering <hello@blockcoders.io>",
"license": "MIT",
Expand Down
4 changes: 2 additions & 2 deletions src/constants/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ export const COINGECKO_ASSET_MAP: { [key: string]: string } = {
ldot: "liquid-staking-dot",
hdx: "hydradx",
ausd: "acala-dollar",
matic:"matic-network",
eth:"ethereum",
usdt: "tether",
ibtc: "interbtc",
intr: "Interlay",
pha: "pha",
unq: "unq",
vdot: "voucher-dot",

astr: "astar",

xcdot: "polkadot",
xchdx: "hydradx",
xcausd: "acala-dollar",
Expand Down
3 changes: 2 additions & 1 deletion src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@
"title": "General",
"languages": "Languages",
"manage_networks": "Manage networks",
"show_testnets": "Show testnets"
"show_testnets": "Show testnets",
"currencies": "Currencies"
},
"advanced_settings": {
"title": "Advanced"
Expand Down
3 changes: 2 additions & 1 deletion src/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@
"title": "General",
"languages": "Idiomas",
"manage_networks": "Administrar redes",
"show_testnets": "Mostrar redes de prueba"
"show_testnets": "Mostrar redes de prueba",
"currencies": "Monedas"
},
"advanced_settings": {
"title": "Avanzado"
Expand Down
3 changes: 2 additions & 1 deletion src/i18n/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@
"title": "Generale",
"languages": "Lingue",
"manage_networks": "Gestire le reti",
"show_testnets": "Mostrare le testnets"
"show_testnets": "Mostrare le testnets",
"currencies": "Valute"
},
"advanced_settings": {
"title": "Avanzate"
Expand Down
3 changes: 2 additions & 1 deletion src/i18n/jp.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@
"title": "一般",
"languages": "言語",
"manage_networks": "ネットワーク管理",
"show_testnets": "テストネットを表示"
"show_testnets": "テストネットを表示",
"currencies": "通貨"
},
"advanced_settings": {
"title": "高度な設定"
Expand Down
3 changes: 2 additions & 1 deletion src/i18n/tr.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@
"title": "Genel",
"languages": "Diller",
"manage_networks": "Ağları yönet",
"show_testnets": "Test ağlarını göster"
"show_testnets": "Test ağlarını göster",
"currencies": "Para Birimi Dönüşümü"
},
"advanced_settings": {
"title": "Gelişmiş"
Expand Down
10 changes: 10 additions & 0 deletions src/pages/balance/components/TotalBalance.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { fireEvent, render, waitFor } from "@testing-library/react";
import { I18nextProvider } from "react-i18next";
import { TotalBalance } from "./TotalBalance";
import { act } from "react-dom/test-utils";
import {CHAINS} from "@src/constants/chains";
import {AccountType} from "@src/accounts/types";

const renderComponent = () => {
return render(
Expand All @@ -25,6 +27,14 @@ describe("TotalBalance", () => {
},
],
},
loadAssets: vi.fn(),
}),
useNetworkContext: () => ({
state: {
selectedChain: CHAINS[0].chains[3],
type: AccountType.EVM,
api: null
},
}),
useAccountContext: () => ({
state: {
Expand Down
23 changes: 16 additions & 7 deletions src/pages/balance/components/TotalBalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import {
BsEyeFill,
} from "react-icons/bs";
import { useTranslation } from "react-i18next";
import { formatAmountWithDecimals } from "@src/utils/assets";
import { formatAmountWithDecimals,getCurrencyInfo } from "@src/utils/assets";
import { useNavigate } from "react-router-dom";
import { SEND, RECEIVE } from "@src/routes/paths";
import { useAccountContext, useAssetContext } from "@src/providers";
import {useAccountContext, useAssetContext, useNetworkContext} from "@src/providers";
import { Button } from "@src/components/common";

interface TotalBalanceProps {
Expand All @@ -24,6 +24,7 @@ export const TotalBalance: FC<TotalBalanceProps> = () => {
const [isEditing, setIsEditing] = useState(false);
const [accountName, setAccountName] = useState("");
const [showBalance, setShowBalance] = useState(true);
const [currencyLogo, setCurrencyLogo] = useState("$");

const {
state: { selectedAccount },
Expand All @@ -32,12 +33,17 @@ export const TotalBalance: FC<TotalBalanceProps> = () => {

const {
state: { assets },
loadAssets,
} = useAssetContext();
const {
state: { api, selectedChain },
} = useNetworkContext();

const totalBalance = assets.reduce(
(total, item) => total + (item.amount || 0),
0
);
const updateAllAssets = async () => {
loadAssets({api, selectedAccount, selectedChain});
}

const totalBalance = assets.reduce((total, item) => total + (item.amount || 0), 0);

const update = async () => {
setIsEditing(false);
Expand All @@ -55,6 +61,9 @@ export const TotalBalance: FC<TotalBalanceProps> = () => {
if (selectedAccount?.value?.name) {
setAccountName(selectedAccount.value.name);
}

setCurrencyLogo(getCurrencyInfo().logo);
updateAllAssets();
}, [selectedAccount]);

return (
Expand Down Expand Up @@ -82,7 +91,7 @@ export const TotalBalance: FC<TotalBalanceProps> = () => {
</div>
<div className="flex mb-4 gap-2 items-center justify-center">
<div className="flex gap-2 items-center">
<p className="text-2xl">$</p>
<p className="text-2xl">{currencyLogo}</p>
<p className="text-5xl" data-testid="balance">
{showBalance ? (formatAmountWithDecimals(totalBalance, 5) || "0") : "***"}
</p>
Expand Down
14 changes: 12 additions & 2 deletions src/pages/settings/General.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,25 @@ const getGeneralSettings = vi.fn().mockReturnValue([
{},
],
},
{
name:SettingKey.CURRENCY,
isCurrencyArray : () => true,
value: [
{
symbol: "usd",
name:"US Dollar ($)",
},
{},
],
},
{
name: SettingKey.SHOW_TESTNETS,
value: false,
},
{
name: SettingKey.MANAGE_NETWORKS,
},
] as Setting[]);
] as unknown as Setting[]);
const updateSetting = vi.fn();
const navigate = vi.fn();

Expand All @@ -52,7 +63,6 @@ describe("General", () => {
Extension.updateSetting = updateSetting;

const { getByTestId } = renderComponent();

await waitFor(() => {
expect(getByTestId("language-select")).toBeDefined();
}, {
Expand Down
41 changes: 41 additions & 0 deletions src/pages/settings/General.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Extension from "@src/Extension";
import { useToast } from "@src/hooks";
import Setting from "@src/storage/entities/settings/Setting";
import {
Currency,
Language,
SettingKey,
SettingType,
Expand All @@ -27,6 +28,7 @@ export const General = () => {
const [isLoading, setIsLoading] = useState(true);
const [settings, setSettings] = useState([] as Setting[]);
const [selectedLanguage, setSelectedLanguage] = useState("");
const [selectedCurrency, setSelectedCurrency] = useState("");
const [showTestnets, setShowTestnets] = useState(false);
const { showErrorToast } = useToast();

Expand All @@ -41,12 +43,15 @@ export const General = () => {
setSettings(settings);
const laguagesSetting = getSettingByName(settings, SettingKey.LANGUAGES)
?.value as Language[];
const currenciesSetting = getSettingByName(settings,SettingKey.CURRENCY)?.value as Currency[];

const showTestnetsSetting = getSettingByName(
settings,
SettingKey.SHOW_TESTNETS
)?.value as boolean;
setSelectedLanguage(getSelectedLanguage(laguagesSetting));
setShowTestnets(showTestnetsSetting);
setSelectedCurrency(getSelectedCurrency(currenciesSetting));
} catch (error) {
setSettings([]);
captureError(error);
Expand All @@ -68,6 +73,13 @@ export const General = () => {
return selectedLanguage?.lang || "en";
};

const getSelectedCurrency = (currencies: Currency[]) => {
const selectedCurrency = currencies.find(
(currency) => currency.symbol === localStorage.getItem("currency")
);
return selectedCurrency?.symbol || "usd";
}

const saveLanguage = async (language: string) => {
try {
await localStorage.setItem("language", language || "en");
Expand All @@ -80,6 +92,16 @@ export const General = () => {
}
};

const saveCurrency = async (currency: string) => {
try {
localStorage.setItem("currency", currency || "usd");
setSelectedCurrency(currency);
} catch (error) {
captureError(error);
showErrorToast(tCommon("failed_to_update_setting"));
}
}

const changeShowTestnets = async () => {
try {
const showTestnetsSetting = settings.find(
Expand Down Expand Up @@ -136,6 +158,25 @@ export const General = () => {
</select>
</div>
);
case SettingKey.CURRENCY:
return (
<div key={index} className="flex flex-col gap-2">
<p className="text-lg font-medium">{t("currencies")}</p>
<select
data-testid="currency-select"
className="text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 bg-gray-700 border-gray-600 placeholder-gray-400 text-white"
onChange={(e)=> saveCurrency(e.target.value)}
value={selectedCurrency}
>
{setting.isCurrencyArray() &&
(setting.value as Currency[]).map((option,index)=> (
<option key={index} value={option.symbol}>
{`${option.name}`}
</option>
))}
</select>
</div>
);
case SettingKey.MANAGE_NETWORKS:
return (
<div
Expand Down
23 changes: 23 additions & 0 deletions src/storage/entities/settings/CurrencySetting.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import CurrencySetting from "./CurrencySetting";
import {CURRENCIES} from "@utils/constants";
import {expect} from "vitest";

describe("CurrencySettings",()=>{
beforeAll(()=>{
vi.mock("./Settings.ts",()=> {
class Setting {}

return {
default:Setting,
};
});
});
it("should get default currency",()=>{
const result = CurrencySetting.getDefault();
expect(result).toEqual(CURRENCIES[0]);
})
it("should get all languages",()=>{
const result = CurrencySetting.getCurrencies();
expect(result).toEqual(CURRENCIES);
})
})
12 changes: 12 additions & 0 deletions src/storage/entities/settings/CurrencySetting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {CURRENCIES} from "@src/utils/constants";
import Setting from "./Setting";

export default class CurrencySetting extends Setting {
static getDefault() {
return CURRENCIES[0];
}

static getCurrencies() {
return CURRENCIES;
}
}
4 changes: 4 additions & 0 deletions src/storage/entities/settings/Setting.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,8 @@ describe("Setting", () => {
const setting = new Setting("test", [{ lang: "test" }] as SettingValue);
expect(setting.isLanguageArray()).toBeTruthy();
});
it("should return currency array", () => {
const setting = new Setting("test", [{ symbol: "test" }] as SettingValue);
expect(setting.isCurrencyArray()).toBeTruthy();
});
});
9 changes: 8 additions & 1 deletion src/storage/entities/settings/Setting.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Language, SettingValue } from "./types";
import { Language, SettingValue, Currency } from "./types";

export default class Setting {
value: SettingValue;
Expand Down Expand Up @@ -38,4 +38,11 @@ export default class Setting {
return lang.length > 0 && lang[0].lang !== undefined;
}
}

isCurrencyArray() {
if (this.isObject()) {
const currencies = this.value as Currency[];
return currencies.length > 0 && currencies[0].symbol !== undefined;
}
}
}
3 changes: 3 additions & 0 deletions src/storage/entities/settings/Settings.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import BaseEntity from "../BaseEntity";
import LanguageSetting from "./LanguageSetting";
import CurrencySetting from "./CurrencySetting";
import Setting from "./Setting";
import { SettingKey, SettingType, SettingValue } from "./types";

Expand All @@ -25,6 +26,8 @@ export default class Settings extends BaseEntity {
SettingKey.LANGUAGES,
LanguageSetting.getSupportedLanguages()
);
settings.addToGeneral(SettingKey.CURRENCY,
CurrencySetting.getCurrencies());
// this setting does not have a value (the true is just a placeholder)
settings.addToGeneral(SettingKey.MANAGE_NETWORKS, true);
settings.addToGeneral(SettingKey.SHOW_TESTNETS, false);
Expand Down
Loading

0 comments on commit f44c1e2

Please sign in to comment.