Skip to content

Commit 658bc2a

Browse files
[LWDM] feat(earn): add simulator deeplink (LIVE-36400) (#21089)
2 parents 8d05454 + 803c2db commit 658bc2a

8 files changed

Lines changed: 76 additions & 2 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"ledger-live-desktop": minor
3+
"live-mobile": minor
4+
---
5+
6+
Add earn/simulate deeplink to open the rewards simulator

apps/ledger-live-desktop/deeplinks-test-page.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ <h3>Discover</h3>
198198

199199
<h3>Earn</h3>
200200
<deeplink-button pathname="earn"></deeplink-button>
201+
<deeplink-button pathname="earn/deposit?cryptoAssetId=ethereum"></deeplink-button>
202+
<deeplink-button pathname="earn/simulate"></deeplink-button>
201203
<deeplink-button pathname="earn?action=stake"></deeplink-button>
202204
<deeplink-button pathname="earn?action=stake-account&accountId=1"></deeplink-button>
203205
<deeplink-button pathname="earn?action=get-funds&currencyId=ethereum"></deeplink-button>

apps/ledger-live-desktop/src/renderer/hooks/useDeeplinking/__tests__/parseDeepLink.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,19 @@ describe("parseDeepLink", () => {
130130
});
131131
});
132132

133+
it("creates earn simulate route", () => {
134+
const parsed = parseDeepLink("ledgerwallet://earn/simulate");
135+
const route = createRoute(parsed);
136+
137+
expect(route).toEqual({
138+
type: "earn",
139+
path: "simulate",
140+
cryptoAssetId: undefined,
141+
accountId: undefined,
142+
search: "",
143+
});
144+
});
145+
133146
it("creates borrow route", () => {
134147
const parsed = parseDeepLink("ledgerwallet://borrow?action=open");
135148
const route = createRoute(parsed);

apps/ledger-live-desktop/src/renderer/hooks/useDeeplinking/handlers/__tests__/earn.handler.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,27 @@ describe("earn.handler", () => {
8585
);
8686
});
8787

88+
it("navigates with simulate intent when path is simulate", () => {
89+
const context = createMockContext();
90+
91+
earnHandler(
92+
{
93+
type: "earn",
94+
path: "simulate",
95+
search: "?ref=campaign",
96+
},
97+
context,
98+
);
99+
100+
expect(context.navigate).toHaveBeenCalledWith(
101+
"/earn",
102+
{
103+
intent: "simulate",
104+
},
105+
"?ref=campaign",
106+
);
107+
});
108+
88109
it("navigates without deposit intent for other paths", () => {
89110
const context = createMockContext();
90111

apps/ledger-live-desktop/src/renderer/hooks/useDeeplinking/handlers/earn.handler.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export const earnHandler: DeeplinkHandler<"earn"> = (route, { navigate }) => {
1313
},
1414
search,
1515
);
16+
} else if (path === "simulate") {
17+
navigate("/earn", { intent: "simulate" }, search);
1618
} else {
1719
navigate("/earn", undefined, search);
1820
}

apps/ledger-live-desktop/src/renderer/screens/earn/index.test.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,29 @@ describe("Earn screen", () => {
147147
useLocationSpy.mockRestore();
148148
});
149149

150+
it("passes simulate intent params in inputs like mobile route params", () => {
151+
const useLocationSpy = jest.spyOn(require("react-router"), "useLocation").mockReturnValue({
152+
pathname: "/earn",
153+
search: "",
154+
hash: "",
155+
state: { intent: "simulate" },
156+
});
157+
158+
render(<Earn />, {
159+
initialState: withFlagOverrides({
160+
ptxEarnLiveApp: { enabled: true, params: { manifest_id: "earn-manifest-id" } },
161+
stakePrograms: { enabled: true, params: { list: [], redirects: {} } } as never,
162+
}),
163+
});
164+
165+
const lastCall = mockWebPlatformPlayer.mock.calls.at(-1)?.[0] as unknown as {
166+
inputs: Record<string, string | undefined>;
167+
};
168+
169+
expect(lastCall.inputs.intent).toBe("simulate");
170+
useLocationSpy.mockRestore();
171+
});
172+
150173
it("passes uiVersion v3 when earn upselling is enabled", () => {
151174
render(<Earn />, {
152175
initialState: withFlagOverrides({

apps/ledger-live-mobile/docs/deeplinks.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ When working on deeplinks, please update the **Wiki** accordingly.
117117

118118
`ledgerlive://earn?action=get-funds&currencyId=ethereum` will open buy drawer with specified currency
119119

120+
`ledgerlive://earn/simulate` (or `ledgerlive://earn?action=simulate`) will open the earn rewards simulator
121+
120122
- **_paytab_** 🠒 Pay Tab (when `lwmPayTab` is on)
121123

122124
`ledgerlive://paytab` opens the Pay tab.

apps/ledger-live-mobile/src/navigation/DeeplinksProvider.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,8 @@ export const DeeplinksProvider = ({
478478
* * @params ?currencyId: string
479479
* ie: "ledgerlive://earn?action=get-funds&currencyId=ethereum" will open buy drawer with currency
480480
*
481+
* ie: "ledgerlive://earn/simulate" will open the earn rewards simulator
482+
*
481483
*/
482484
[ScreenName.Earn]: "earn",
483485
},
@@ -787,14 +789,17 @@ export const DeeplinksProvider = ({
787789
searchParams.get("cryptoAssetId") || undefined,
788790
searchParams.get("accountId") || undefined,
789791
);
790-
// Handle deposit deeplink on earnLiveAppNavigator
791-
// Creating own search params for deposit deeplink
792792
url.pathname = "";
793793
url.searchParams.set("action", "deposit");
794794
url.searchParams.set("cryptoAssetId", validatedModal.cryptoAssetId ?? "");
795795
url.searchParams.set("accountId", validatedModal.accountId ?? "");
796796
return getStateFromPath(url.href?.split("://")[1], config);
797797
}
798+
if (pathname === "/simulate") {
799+
url.pathname = "";
800+
url.searchParams.set("action", "simulate");
801+
return getStateFromPath(url.href?.split("://")[1], config);
802+
}
798803
}
799804
if (hostname === "swap") {
800805
const swapParams = new URLSearchParams();

0 commit comments

Comments
 (0)