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

Support fiat input in dual currency field #3089

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8c1567b
feat: dual currency input supports fiat input
riccardobl Mar 16, 2024
87a8edc
feat: prefix dual currency input with main symbol, add currency to in…
riccardobl Mar 23, 2024
3bffba9
fix: amount in Satoshis -> amount in sats
riccardobl Apr 1, 2024
29c49b4
fix: attempt at making unit tests happy
riccardobl Apr 1, 2024
90512cf
Merge remote-tracking branch 'upstream/master' into fiatinput
pavanjoshi914 Apr 2, 2024
3f7f107
Merge remote-tracking branch 'upstream/master' into fiatinput
pavanjoshi914 Apr 2, 2024
96635c8
Merge branch 'fiatinput' of https://github.com/getAlby/lightning-brow…
pavanjoshi914 Apr 2, 2024
0394bb7
fix: fix some unit tests
riccardobl Apr 2, 2024
2eb1020
fix: dual currency input event wrapping
riccardobl Apr 3, 2024
5a214c9
fix: more unit tests fixing
riccardobl Apr 3, 2024
2e2e329
fix: currency toggle issue for default values, improve some naming
riccardobl Apr 10, 2024
ea1954f
fix: input value
riccardobl Apr 14, 2024
9cfa078
Merge remote-tracking branch 'upstream/master' into fiatinput
pavanjoshi914 Apr 18, 2024
278acaf
fix: naming, empty input, do not change component to uncontrolled whe…
riccardobl May 5, 2024
49bb31c
fix: fixes and improvements
riccardobl May 24, 2024
fd36df6
fix: light theme
riccardobl May 25, 2024
269f8a3
Merge remote-tracking branch 'upstream/master' into fiatinput
pavanjoshi914 May 30, 2024
5b75f43
fix: dualcurrency component test
pavanjoshi914 May 30, 2024
9ff8337
fix: clone target to avoid side-effects when changing value
riccardobl Jun 19, 2024
564f79e
fix: tests and implementation
riccardobl Jul 1, 2024
ba7cb69
Merge branch 'master' into fiatinput
bumi Jul 3, 2024
0cdba7b
fix: allow 4 decimals in fiat input and add some comments
riccardobl Jul 8, 2024
c49b925
fix: preset workaround
riccardobl Jul 14, 2024
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
9 changes: 3 additions & 6 deletions src/app/components/BudgetControl/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,22 @@ type Props = {
onRememberChange: ChangeEventHandler<HTMLInputElement>;
budget: string;
onBudgetChange: ChangeEventHandler<HTMLInputElement>;
fiatAmount: string;
disabled?: boolean;
showFiat?: boolean;
};

function BudgetControl({
remember,
onRememberChange,
budget,
onBudgetChange,
fiatAmount,
disabled = false,
showFiat = false,
}: Props) {
const { t } = useTranslation("components", {
keyPrefix: "budget_control",
});

const { t: tCommon } = useTranslation("common");

return (
<div className="mb-4">
<div className={`flex items-center`}>
Expand Down Expand Up @@ -60,12 +58,11 @@ function BudgetControl({

<div>
<DualCurrencyField
showFiat={showFiat}
autoFocus
fiatValue={fiatAmount}
id="budget"
min={0}
label={t("budget.label")}
placeholder={tCommon("sats", { count: 0 })}
value={budget}
onChange={onBudgetChange}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/PaymentSummary/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jest.mock("~/common/lib/api", () => {
return {
...original,
getSettings: jest.fn(() => Promise.resolve(mockSettings)),
getCurrencyRate: jest.fn(() => Promise.resolve({ rate: 11 })),
getCurrencyRate: jest.fn(() => 11),
};
});

Expand Down
58 changes: 48 additions & 10 deletions src/app/components/SitePreferences/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ import { settingsFixture as mockSettings } from "~/../tests/fixtures/settings";
import type { Props } from "./index";
import SitePreferences from "./index";

const mockGetFiatValue = jest.fn(() => Promise.resolve("$1,22"));
const mockGetFormattedFiat = jest.fn(() => "$1,22");
const mockGetFormattedInCurrency = jest.fn((v, curr) => v + " " + curr);

jest.mock("~/app/context/SettingsContext", () => ({
useSettings: () => ({
settings: mockSettings,
isLoading: false,
updateSetting: jest.fn(),
getFormattedFiat: mockGetFiatValue,
getFormattedFiat: mockGetFormattedFiat,
getFormattedNumber: jest.fn(),
getFormattedSats: jest.fn(),
getCurrencyRate: jest.fn(() => 1),
getCurrencySymbol: jest.fn(() => "₿"),
getFormattedInCurrency: mockGetFormattedInCurrency,
}),
}));

Expand Down Expand Up @@ -53,7 +57,7 @@ describe("SitePreferences", () => {

await renderComponent();

expect(mockGetFiatValue).not.toHaveBeenCalled();
expect(mockGetFormattedFiat).not.toHaveBeenCalled();

const settingsButton = await screen.getByRole("button");

Expand All @@ -66,25 +70,59 @@ describe("SitePreferences", () => {
name: "Save",
});

const checkDualInputValues = (values: Array<[number, string]>) => {
for (let i = 0; i < values.length; i++) {
expect(mockGetFormattedInCurrency).toHaveBeenNthCalledWith(
i + 1,
...values[i]
);
}
expect(mockGetFormattedInCurrency).toHaveBeenCalledTimes(values.length);
};

const checkDualInputValue = (v: number, n: number) => {
for (let i = 1; i <= n * 2; i += 2) {
expect(mockGetFormattedInCurrency).toHaveBeenNthCalledWith(i, v, "BTC");
expect(mockGetFormattedInCurrency).toHaveBeenNthCalledWith(
i + 1,
v,
"USD"
);
}
expect(mockGetFormattedInCurrency).toHaveBeenCalledTimes(n * 2);
};

// update fiat value when modal is open
expect(mockGetFiatValue).toHaveBeenCalledWith(
defaultProps.allowance.totalBudget.toString()
);
expect(mockGetFiatValue).toHaveBeenCalledTimes(1);
checkDualInputValue(defaultProps.allowance.totalBudget, 2);

await act(async () => {
await user.clear(screen.getByLabelText("One-click payments budget"));
mockGetFormattedInCurrency.mockClear();
await user.type(
screen.getByLabelText("One-click payments budget"),
"250"
);
});

// update fiat value
expect(screen.getByLabelText("One-click payments budget")).toHaveValue(250);

// update fiat value
expect(mockGetFiatValue).toHaveBeenCalledWith("250");
expect(mockGetFiatValue).toHaveBeenCalledTimes(4); // plus 3 times for each input value 2, 5, 0
checkDualInputValues([
[2, "BTC"],
[2, "USD"],
[2, "BTC"],
[2, "USD"],
[25, "BTC"],
[25, "USD"],
[25, "BTC"],
[25, "USD"],
[250, "BTC"],
[250, "USD"],
[250, "BTC"],
[250, "USD"],
[250, "BTC"],
[250, "USD"],
]);

await act(async () => {
await user.click(saveButton);
Expand Down
21 changes: 2 additions & 19 deletions src/app/components/SitePreferences/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,12 @@ export type Props = {
};

function SitePreferences({ launcherType, allowance, onEdit, onDelete }: Props) {
const {
isLoading: isLoadingSettings,
settings,
getFormattedFiat,
} = useSettings();
const { isLoading: isLoadingSettings, settings } = useSettings();
const showFiat = !isLoadingSettings && settings.showFiat;
const { account } = useAccount();
const [modalIsOpen, setIsOpen] = useState(false);
const [budget, setBudget] = useState("");
const [lnurlAuth, setLnurlAuth] = useState(false);
const [fiatAmount, setFiatAmount] = useState("");

const [originalPermissions, setOriginalPermissions] = useState<
Permission[] | null
Expand Down Expand Up @@ -83,17 +78,6 @@ function SitePreferences({ launcherType, allowance, onEdit, onDelete }: Props) {
fetchPermissions();
}, [account?.id, allowance.id]);

useEffect(() => {
if (budget !== "" && showFiat) {
const getFiat = async () => {
const res = await getFormattedFiat(budget);
setFiatAmount(res);
};

getFiat();
}
}, [budget, showFiat, getFormattedFiat]);

function openModal() {
setBudget(allowance.totalBudget.toString());
setLnurlAuth(allowance.lnurlAuth);
Expand Down Expand Up @@ -238,10 +222,9 @@ function SitePreferences({ launcherType, allowance, onEdit, onDelete }: Props) {
label={t("new_budget.label")}
min={0}
autoFocus
placeholder={tCommon("sats", { count: 0 })}
value={budget}
hint={t("hint")}
fiatValue={fiatAmount}
showFiat={showFiat}
onChange={(e) => setBudget(e.target.value)}
/>
</div>
Expand Down
23 changes: 20 additions & 3 deletions src/app/components/form/DualCurrencyField/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
import { render, screen } from "@testing-library/react";
import { render, screen, waitFor } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import { settingsFixture as mockSettings } from "~/../tests/fixtures/settings";

import type { Props } from "./index";
import DualCurrencyField from "./index";

const props: Props = {
fiatValue: "$10.00",
showFiat: true,
label: "Amount",
};
jest.mock("~/app/context/SettingsContext", () => ({
useSettings: () => ({
settings: mockSettings,
isLoading: false,
updateSetting: jest.fn(),
getFormattedFiat: jest.fn(() => "$10.00"),
getFormattedNumber: jest.fn(),
getFormattedSats: jest.fn(),
getCurrencyRate: jest.fn(() => 1),
getCurrencySymbol: jest.fn(() => "₿"),
getFormattedInCurrency: jest.fn(() => "$10.00"),
}),
}));

describe("DualCurrencyField", () => {
test("render", async () => {
Expand All @@ -20,6 +34,9 @@ describe("DualCurrencyField", () => {
const input = screen.getByLabelText("Amount");

expect(input).toBeInTheDocument();
expect(await screen.getByText("~$10.00")).toBeInTheDocument();

await waitFor(() => {
expect(screen.getByText("~$10.00")).toBeInTheDocument();
});
});
});
Loading
Loading