Skip to content

Commit 266b7fb

Browse files
committed
chore: review fixes
1 parent 5c90260 commit 266b7fb

File tree

8 files changed

+56
-88
lines changed

8 files changed

+56
-88
lines changed

apps/ledger-live-mobile/src/families/canton/PendingTransferProposals/PendingTransferProposalsDetails.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export function View({
120120
</Text>
121121
</Flex>
122122

123-
{!isExpired && timeRemaining && (
123+
{!isExpired && !!timeRemaining && (
124124
<Flex mb={8}>
125125
<Text variant="paragraph" color="neutral.c70" mb={2}>
126126
{t("canton.pendingTransactions.expiresIn")}

apps/ledger-live-mobile/src/families/canton/PendingTransferProposals/__tests__/test-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ export const createProcessedProposal = (
7979
overrides: Partial<ProcessedProposal> = {},
8080
): ProcessedProposal => {
8181
const futureMicros = (Date.now() + 3600000) * 1000;
82-
const expiresAt = new Date(futureMicros / 1000);
82+
const expiresAt = overrides.expiresAt ?? new Date(futureMicros / 1000);
8383
const day = new Date(expiresAt);
84-
day.setUTCHours(0, 0, 0, 0);
84+
day.setHours(0, 0, 0, 0);
8585
return {
8686
contractId: "contract-1",
8787
sender: "sender-xpub",

apps/ledger-live-mobile/src/families/canton/PendingTransferProposals/__tests__/transferProposals.test.ts

Lines changed: 44 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,15 @@
1-
/* eslint-disable @typescript-eslint/consistent-type-assertions */
21
import { BigNumber } from "bignumber.js";
32
import {
43
processTransferProposals,
54
groupByDay,
65
isValidRestoreModalState,
76
INSTRUCTION_TYPE_MAP,
87
} from "../utils/transferProposals";
9-
import type { ProcessedProposal, RawTransferProposal } from "../types";
8+
import type { RawTransferProposal } from "../types";
9+
import { ACCOUNT_XPUB, createRawProposal, createProcessedProposal } from "./test-utils";
1010

11-
const ACCOUNT_XPUB = "account-xpub";
1211
const OTHER_XPUB = "other-xpub";
1312

14-
const buildRawProposal = (overrides: {
15-
contract_id: string;
16-
sender: string;
17-
receiver: string;
18-
expires_at_micros?: number;
19-
memo?: string;
20-
}) => ({
21-
amount: "1000000",
22-
instrument_id: "instrument-1",
23-
instrument_admin: "",
24-
update_id: "",
25-
expires_at_micros: Date.now() * 1000 + 3600000000,
26-
memo: "",
27-
...overrides,
28-
});
29-
3013
describe("processTransferProposals", () => {
3114
it("should return empty incoming and outgoing arrays when given no proposals", () => {
3215
const result = processTransferProposals([], ACCOUNT_XPUB);
@@ -35,12 +18,7 @@ describe("processTransferProposals", () => {
3518
});
3619

3720
it("should classify a proposal as incoming when sender differs from accountXpub", () => {
38-
const raw = buildRawProposal({
39-
contract_id: "contract-1",
40-
sender: OTHER_XPUB,
41-
receiver: ACCOUNT_XPUB,
42-
});
43-
21+
const raw = createRawProposal("contract-1", OTHER_XPUB, ACCOUNT_XPUB);
4422
const { incoming, outgoing } = processTransferProposals([raw], ACCOUNT_XPUB);
4523

4624
expect(incoming).toHaveLength(1);
@@ -49,12 +27,7 @@ describe("processTransferProposals", () => {
4927
});
5028

5129
it("should classify a proposal as outgoing when sender matches accountXpub", () => {
52-
const raw = buildRawProposal({
53-
contract_id: "contract-2",
54-
sender: ACCOUNT_XPUB,
55-
receiver: OTHER_XPUB,
56-
});
57-
30+
const raw = createRawProposal("contract-2", ACCOUNT_XPUB, OTHER_XPUB);
5831
const { incoming, outgoing } = processTransferProposals([raw], ACCOUNT_XPUB);
5932

6033
expect(outgoing).toHaveLength(1);
@@ -64,9 +37,9 @@ describe("processTransferProposals", () => {
6437

6538
it("should correctly split a mixed list into incoming and outgoing", () => {
6639
const proposals = [
67-
buildRawProposal({ contract_id: "in-1", sender: OTHER_XPUB, receiver: ACCOUNT_XPUB }),
68-
buildRawProposal({ contract_id: "out-1", sender: ACCOUNT_XPUB, receiver: OTHER_XPUB }),
69-
buildRawProposal({ contract_id: "in-2", sender: OTHER_XPUB, receiver: ACCOUNT_XPUB }),
40+
createRawProposal("in-1", OTHER_XPUB, ACCOUNT_XPUB),
41+
createRawProposal("out-1", ACCOUNT_XPUB, OTHER_XPUB),
42+
createRawProposal("in-2", OTHER_XPUB, ACCOUNT_XPUB),
7043
];
7144

7245
const { incoming, outgoing } = processTransferProposals(proposals, ACCOUNT_XPUB);
@@ -77,10 +50,7 @@ describe("processTransferProposals", () => {
7750

7851
it("should mark a proposal as expired when its expiry timestamp is in the past", () => {
7952
const pastMicros = (Date.now() - 10000) * 1000;
80-
const raw = buildRawProposal({
81-
contract_id: "expired-1",
82-
sender: OTHER_XPUB,
83-
receiver: ACCOUNT_XPUB,
53+
const raw = createRawProposal("expired-1", OTHER_XPUB, ACCOUNT_XPUB, {
8454
expires_at_micros: pastMicros,
8555
});
8656

@@ -91,10 +61,7 @@ describe("processTransferProposals", () => {
9161

9262
it("should mark a proposal as not expired when its expiry timestamp is in the future", () => {
9363
const futureMicros = (Date.now() + 3600000) * 1000;
94-
const raw = buildRawProposal({
95-
contract_id: "active-1",
96-
sender: OTHER_XPUB,
97-
receiver: ACCOUNT_XPUB,
64+
const raw = createRawProposal("active-1", OTHER_XPUB, ACCOUNT_XPUB, {
9865
expires_at_micros: futureMicros,
9966
});
10067

@@ -105,10 +72,7 @@ describe("processTransferProposals", () => {
10572

10673
it("should correctly map raw field names to the ProcessedProposal shape", () => {
10774
const futureMicros = (Date.now() + 3600000) * 1000;
108-
const raw = buildRawProposal({
109-
contract_id: "contract-map",
110-
sender: OTHER_XPUB,
111-
receiver: ACCOUNT_XPUB,
75+
const raw = createRawProposal("contract-map", OTHER_XPUB, ACCOUNT_XPUB, {
11276
expires_at_micros: futureMicros,
11377
memo: "test memo",
11478
});
@@ -127,14 +91,9 @@ describe("processTransferProposals", () => {
12791
});
12892

12993
it("should default memo to an empty string when it is null or undefined", () => {
130-
const raw = {
131-
...buildRawProposal({
132-
contract_id: "no-memo",
133-
sender: OTHER_XPUB,
134-
receiver: ACCOUNT_XPUB,
135-
}),
94+
const raw = createRawProposal("no-memo", OTHER_XPUB, ACCOUNT_XPUB, {
13695
memo: undefined,
137-
};
96+
});
13897

13998
const { incoming } = processTransferProposals(
14099
[raw as unknown as RawTransferProposal],
@@ -146,33 +105,20 @@ describe("processTransferProposals", () => {
146105
});
147106

148107
describe("groupByDay", () => {
149-
const makeProposal = (contractId: string, expiresAt: Date): ProcessedProposal => {
150-
const day = new Date(expiresAt);
151-
day.setUTCHours(0, 0, 0, 0);
152-
return {
153-
contractId,
154-
sender: OTHER_XPUB,
155-
receiver: ACCOUNT_XPUB,
156-
amount: new BigNumber("1000000"),
157-
instrumentId: "instrument-1",
158-
memo: "",
159-
expiresAtMicros: expiresAt.getTime() * 1000,
160-
isExpired: false,
161-
isIncoming: true,
162-
expiresAt,
163-
day,
164-
};
165-
};
166-
167108
it("should return an empty array when given no proposals", () => {
168109
expect(groupByDay([])).toEqual([]);
169110
});
170111

171112
it("should return a single group for proposals that all expire on the same day", () => {
172-
const date = new Date("2025-06-15T10:00:00Z");
173113
const proposals = [
174-
makeProposal("contract-1", date),
175-
makeProposal("contract-2", new Date("2025-06-15T14:00:00Z")),
114+
createProcessedProposal({
115+
contractId: "contract-1",
116+
expiresAt: new Date("2025-06-15T10:00:00Z"),
117+
}),
118+
createProcessedProposal({
119+
contractId: "contract-2",
120+
expiresAt: new Date("2025-06-15T14:00:00Z"),
121+
}),
176122
];
177123

178124
const result = groupByDay(proposals);
@@ -182,19 +128,33 @@ describe("groupByDay", () => {
182128
});
183129

184130
it("should return multiple groups for proposals that expire on different days", () => {
185-
const day1 = new Date("2025-06-15T10:00:00Z");
186-
const day2 = new Date("2025-06-16T10:00:00Z");
187-
const proposals = [makeProposal("contract-1", day1), makeProposal("contract-2", day2)];
131+
const proposals = [
132+
createProcessedProposal({
133+
contractId: "contract-1",
134+
expiresAt: new Date("2025-06-15T10:00:00Z"),
135+
}),
136+
createProcessedProposal({
137+
contractId: "contract-2",
138+
expiresAt: new Date("2025-06-16T10:00:00Z"),
139+
}),
140+
];
188141

189142
const result = groupByDay(proposals);
190143

191144
expect(result).toHaveLength(2);
192145
});
193146

194147
it("should sort day groups in descending order so the latest day appears first", () => {
195-
const earlier = new Date("2025-06-14T10:00:00Z");
196-
const later = new Date("2025-06-16T10:00:00Z");
197-
const proposals = [makeProposal("contract-old", earlier), makeProposal("contract-new", later)];
148+
const proposals = [
149+
createProcessedProposal({
150+
contractId: "contract-old",
151+
expiresAt: new Date("2025-06-14T10:00:00Z"),
152+
}),
153+
createProcessedProposal({
154+
contractId: "contract-new",
155+
expiresAt: new Date("2025-06-16T10:00:00Z"),
156+
}),
157+
];
198158

199159
const result = groupByDay(proposals);
200160

@@ -235,6 +195,10 @@ describe("isValidRestoreModalState", () => {
235195
it("should return false when contractId is not a string", () => {
236196
expect(isValidRestoreModalState({ action: "accept", contractId: 123 })).toBe(false);
237197
});
198+
199+
it("should return false for prototype-chain property names like toString", () => {
200+
expect(isValidRestoreModalState({ action: "toString", contractId: "contract-1" })).toBe(false);
201+
});
238202
});
239203

240204
describe("INSTRUCTION_TYPE_MAP", () => {

apps/ledger-live-mobile/src/families/canton/PendingTransferProposals/__tests__/usePendingTransferProposalsDetailsViewModel.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ import { act, renderHook } from "@tests/test-renderer";
22
import { usePendingTransferProposalsDetailsViewModel } from "../usePendingTransferProposalsDetailsViewModel";
33
import { createCantonAccount, createProcessedProposal } from "./test-utils";
44

5+
jest.mock("@react-native-clipboard/clipboard", () => ({
6+
setString: jest.fn(),
7+
}));
8+
59
describe("usePendingTransferProposalsDetailsViewModel", () => {
610
const account = createCantonAccount();
711
const onOpenModal = jest.fn();

apps/ledger-live-mobile/src/families/canton/PendingTransferProposals/components/ProposalRow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export function View({
6464
<Text variant="small" color="neutral.c70" mr={2}>
6565
{formattedTime}
6666
</Text>
67-
{!isExpired && timeRemaining && (
67+
{!isExpired && !!timeRemaining && (
6868
<Text variant="small" color="neutral.c70">
6969
{timeRemaining}
7070
</Text>

apps/ledger-live-mobile/src/families/canton/PendingTransferProposals/components/useProposalRowViewModel.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useTimeRemaining } from "@ledgerhq/live-common/families/canton/react";
22
import type { Unit } from "@ledgerhq/types-cryptoassets";
33
import { Account } from "@ledgerhq/types-live";
4-
import { BigNumber } from "bignumber.js";
4+
import type { BigNumber } from "bignumber.js";
55
import { useCallback } from "react";
66
import { hoursAndMinutesOptionsSelector } from "~/components/DateFormat/FormatDate";
77
import { useSelector } from "~/context/hooks";

apps/ledger-live-mobile/src/families/canton/PendingTransferProposals/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BigNumber } from "bignumber.js";
1+
import type { BigNumber } from "bignumber.js";
22

33
export type TransferProposalAction = "accept" | "reject" | "withdraw";
44

apps/ledger-live-mobile/src/families/canton/PendingTransferProposals/utils/transferProposals.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const INSTRUCTION_TYPE_MAP: Record<TransferProposalAction, TransferInstru
1616

1717
const startOfDay = (date: Date): Date => {
1818
const d = new Date(date);
19-
d.setUTCHours(0, 0, 0, 0);
19+
d.setHours(0, 0, 0, 0);
2020
return d;
2121
};
2222

@@ -90,5 +90,5 @@ export const isValidRestoreModalState = (value: unknown): value is RestoreModalS
9090
if (typeof value !== "object" || value === null) return false;
9191
if (!("action" in value) || !("contractId" in value)) return false;
9292
if (typeof value.action !== "string" || typeof value.contractId !== "string") return false;
93-
return value.action in INSTRUCTION_TYPE_MAP;
93+
return Object.prototype.hasOwnProperty.call(INSTRUCTION_TYPE_MAP, value.action);
9494
};

0 commit comments

Comments
 (0)