Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 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
8477fa7
Merge branch 'master' into fiatinput
pavanjoshi914 Oct 3, 2024
b711eff
test(ConfirmPayment): mock getFormattedInCurrency to fix tests
Dunsin-cyber Jun 8, 2025
df3abc9
Merge branch 'master' into riccardobl-fiatinput
Dunsin-cyber Jun 8, 2025
94a527f
fix: reduce unnecessary re-renders in input field and update test file
Dunsin-cyber Jun 11, 2025
9f913f6
test: adjust expected call count for mockGetFormattedInCurrency to ma…
Dunsin-cyber Jun 11, 2025
e51f018
Translated using Weblate (German)
weblate Jun 3, 2025
2e036b2
Translated using Weblate (Spanish)
weblate Jun 3, 2025
12fe08b
feat: add metadata to transactions
pavanjoshi914 Jun 6, 2025
cfa4135
chore: type correct
pavanjoshi914 Jun 10, 2025
1dc5528
chore: variable name
pavanjoshi914 Jun 11, 2025
52a6f1b
chore: new design
pavanjoshi914 Jun 12, 2025
fe96c35
fix: tests
pavanjoshi914 Jun 12, 2025
48f40a2
Translated using Weblate (German)
weblate Jun 14, 2025
5134e09
Merge branch 'master' into riccardobl-fiatinput
Dunsin-cyber Jun 17, 2025
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
63 changes: 53 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,14 +70,34 @@ 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(2);
};

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

await act(async () => {
await user.clear(screen.getByLabelText("One-click payments budget"));
mockGetFormattedInCurrency.mockClear();
await user.type(
screen.getByLabelText("One-click payments budget"),
"250"
Expand All @@ -82,9 +106,28 @@ describe("SitePreferences", () => {

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"],
[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