Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Balances can now be displayed in the desired currency. #44

Merged
merged 6 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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