Skip to content

Commit b8424b9

Browse files
authored
Merge pull request Expensify#89983 from callstack-internal/perf/improve-useDelegateAccountID
[No QA] Remove usePersonalDetailsByEmail from useDelegateAccountID
2 parents 73ec4ca + 606492e commit b8424b9

2 files changed

Lines changed: 139 additions & 3 deletions

File tree

src/hooks/useDelegateAccountID.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
11
import {delegateEmailSelector} from '@selectors/Account';
2+
import type {OnyxEntry} from 'react-native-onyx';
23
import ONYXKEYS from '@src/ONYXKEYS';
4+
import type {PersonalDetailsList} from '@src/types/onyx';
35
import useOnyx from './useOnyx';
4-
import usePersonalDetailsByLogin from './usePersonalDetailsByLogin';
56

67
function useDelegateAccountID(): number | undefined {
78
const [delegateEmail] = useOnyx(ONYXKEYS.ACCOUNT, {selector: delegateEmailSelector});
8-
const personalDetailsByLogin = usePersonalDetailsByLogin();
9+
const lowerEmail = delegateEmail?.toLowerCase();
910

10-
return delegateEmail ? personalDetailsByLogin[delegateEmail.toLowerCase()]?.accountID : undefined;
11+
const [accountID] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {
12+
selector: (personalDetails: OnyxEntry<PersonalDetailsList>) => {
13+
if (!lowerEmail || !personalDetails) {
14+
return undefined;
15+
}
16+
for (const detail of Object.values(personalDetails)) {
17+
if (detail?.login?.toLowerCase() === lowerEmail) {
18+
return detail.accountID;
19+
}
20+
}
21+
return undefined;
22+
},
23+
});
24+
25+
return accountID;
1126
}
1227

1328
export default useDelegateAccountID;
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import {renderHook, waitFor} from '@testing-library/react-native';
2+
import Onyx from 'react-native-onyx';
3+
import useDelegateAccountID from '@hooks/useDelegateAccountID';
4+
import ONYXKEYS from '@src/ONYXKEYS';
5+
6+
const ACCOUNT_ID_ALICE = 1;
7+
const ACCOUNT_ID_BOB = 2;
8+
const ACCOUNT_ID_CAROL = 3;
9+
10+
describe('useDelegateAccountID', () => {
11+
beforeAll(() => {
12+
Onyx.init({keys: ONYXKEYS});
13+
});
14+
15+
beforeEach(async () => {
16+
await Onyx.clear();
17+
});
18+
19+
it('returns the accountID of the delegate when both account and personal details are set', async () => {
20+
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
21+
[ACCOUNT_ID_ALICE]: {accountID: ACCOUNT_ID_ALICE, login: 'alice@test.com'},
22+
[ACCOUNT_ID_BOB]: {accountID: ACCOUNT_ID_BOB, login: 'bob@test.com'},
23+
});
24+
await Onyx.merge(ONYXKEYS.ACCOUNT, {delegatedAccess: {delegate: 'bob@test.com'}});
25+
26+
const {result} = renderHook(() => useDelegateAccountID());
27+
28+
await waitFor(() => {
29+
expect(result.current).toBe(ACCOUNT_ID_BOB);
30+
});
31+
});
32+
33+
it('matches the delegate email case-insensitively', async () => {
34+
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
35+
[ACCOUNT_ID_ALICE]: {accountID: ACCOUNT_ID_ALICE, login: 'alice@test.com'},
36+
});
37+
await Onyx.merge(ONYXKEYS.ACCOUNT, {delegatedAccess: {delegate: 'ALICE@TEST.COM'}});
38+
39+
const {result} = renderHook(() => useDelegateAccountID());
40+
41+
await waitFor(() => {
42+
expect(result.current).toBe(ACCOUNT_ID_ALICE);
43+
});
44+
});
45+
46+
it('returns undefined when there is no delegate set on the account', async () => {
47+
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
48+
[ACCOUNT_ID_ALICE]: {accountID: ACCOUNT_ID_ALICE, login: 'alice@test.com'},
49+
});
50+
51+
const {result} = renderHook(() => useDelegateAccountID());
52+
53+
await waitFor(() => {
54+
expect(result.current).toBeUndefined();
55+
});
56+
});
57+
58+
it('returns undefined when the delegate email does not match any personal detail', async () => {
59+
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
60+
[ACCOUNT_ID_ALICE]: {accountID: ACCOUNT_ID_ALICE, login: 'alice@test.com'},
61+
});
62+
await Onyx.merge(ONYXKEYS.ACCOUNT, {delegatedAccess: {delegate: 'unknown@test.com'}});
63+
64+
const {result} = renderHook(() => useDelegateAccountID());
65+
66+
await waitFor(() => {
67+
expect(result.current).toBeUndefined();
68+
});
69+
});
70+
71+
it('returns undefined when personal details list is not set', async () => {
72+
await Onyx.merge(ONYXKEYS.ACCOUNT, {delegatedAccess: {delegate: 'bob@test.com'}});
73+
74+
const {result} = renderHook(() => useDelegateAccountID());
75+
76+
await waitFor(() => {
77+
expect(result.current).toBeUndefined();
78+
});
79+
});
80+
81+
it('updates when the delegate email changes', async () => {
82+
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
83+
[ACCOUNT_ID_ALICE]: {accountID: ACCOUNT_ID_ALICE, login: 'alice@test.com'},
84+
[ACCOUNT_ID_BOB]: {accountID: ACCOUNT_ID_BOB, login: 'bob@test.com'},
85+
});
86+
await Onyx.merge(ONYXKEYS.ACCOUNT, {delegatedAccess: {delegate: 'alice@test.com'}});
87+
88+
const {result} = renderHook(() => useDelegateAccountID());
89+
90+
await waitFor(() => {
91+
expect(result.current).toBe(ACCOUNT_ID_ALICE);
92+
});
93+
94+
await Onyx.merge(ONYXKEYS.ACCOUNT, {delegatedAccess: {delegate: 'bob@test.com'}});
95+
96+
await waitFor(() => {
97+
expect(result.current).toBe(ACCOUNT_ID_BOB);
98+
});
99+
});
100+
101+
it('updates when the matching personal detail is added later', async () => {
102+
await Onyx.merge(ONYXKEYS.ACCOUNT, {delegatedAccess: {delegate: 'carol@test.com'}});
103+
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
104+
[ACCOUNT_ID_ALICE]: {accountID: ACCOUNT_ID_ALICE, login: 'alice@test.com'},
105+
});
106+
107+
const {result} = renderHook(() => useDelegateAccountID());
108+
109+
await waitFor(() => {
110+
expect(result.current).toBeUndefined();
111+
});
112+
113+
await Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, {
114+
[ACCOUNT_ID_CAROL]: {accountID: ACCOUNT_ID_CAROL, login: 'carol@test.com'},
115+
});
116+
117+
await waitFor(() => {
118+
expect(result.current).toBe(ACCOUNT_ID_CAROL);
119+
});
120+
});
121+
});

0 commit comments

Comments
 (0)