Skip to content

Commit c76a199

Browse files
authored
Merge pull request Expensify#89673 from Expensify/claude-fixSharedFeedAssignPermission
Allow card assignment on shared workspaces via linkedPolicyIDs
2 parents e72949f + 4d7d61c commit c76a199

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

src/hooks/useIsAllowedToIssueCompanyCard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ function useIsAllowedToIssueCompanyCard({policyID}: {policyID?: string}) {
2020
const selectedFeedData = selectedFeed && companyCards[selectedFeed];
2121
const [domain] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN}${selectedFeedData?.domainID}`);
2222

23-
if (selectedFeedData?.domainID === policy?.workspaceAccountID) {
23+
if (selectedFeedData?.domainID === policy?.workspaceAccountID || (policyID && selectedFeedData?.linkedPolicyIDs?.some((id) => id.toUpperCase() === policyID.toUpperCase()))) {
2424
return isPolicyAdmin;
2525
}
2626

tests/unit/hooks/useIsAllowedToIssueCompanyCard.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ const workspaceAccountID = 11111111;
1414

1515
const mockPolicy = {...createRandomPolicy(Number(mockPolicyID), CONST.POLICY.TYPE.TEAM, 'TestPolicy'), policyID: mockPolicyID, workspaceAccountID};
1616

17+
const linkedFeedDomainID = 22222222;
18+
1719
const mockedFeeds = {
1820
// eslint-disable-next-line @typescript-eslint/naming-convention
1921
'vcf#19475968': {
@@ -31,6 +33,15 @@ const mockedFeeds = {
3133
customFeedName: 'Custom feed name 1',
3234
feed: CONST.COMPANY_CARD.FEED_BANK_NAME.VISA,
3335
},
36+
// eslint-disable-next-line @typescript-eslint/naming-convention -- Feed keys use the `vcf#<id>` format from the backend
37+
'vcf#22222222': {
38+
liabilityType: 'personal',
39+
pending: false,
40+
domainID: linkedFeedDomainID,
41+
customFeedName: 'Linked feed',
42+
feed: CONST.COMPANY_CARD.FEED_BANK_NAME.VISA,
43+
linkedPolicyIDs: [mockPolicyID],
44+
},
3445
};
3546

3647
jest.mock('@hooks/useCardFeeds', () => ({
@@ -92,4 +103,22 @@ describe('useIsAllowedToIssueCompanyCard', () => {
92103
const {result} = renderHook(() => useIsAllowedToIssueCompanyCard({policyID: mockPolicyID}));
93104
expect(result?.current).toBe(false);
94105
});
106+
it('should return true if feed is shared via linkedPolicyIDs and user is admin', async () => {
107+
await Onyx.merge(`${ONYXKEYS.COLLECTION.LAST_SELECTED_FEED}${mockPolicy?.policyID}`, 'vcf#22222222');
108+
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${mockPolicy?.policyID}`, {
109+
role: CONST.POLICY.ROLE.ADMIN,
110+
});
111+
(useCardFeeds as jest.Mock).mockReturnValue([mockedFeeds, {status: 'loaded'}]);
112+
const {result} = renderHook(() => useIsAllowedToIssueCompanyCard({policyID: mockPolicyID}));
113+
expect(result?.current).toBe(true);
114+
});
115+
it('should return false if feed is shared via linkedPolicyIDs and user is not an admin', async () => {
116+
await Onyx.merge(`${ONYXKEYS.COLLECTION.LAST_SELECTED_FEED}${mockPolicy?.policyID}`, 'vcf#22222222');
117+
await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${mockPolicy?.policyID}`, {
118+
role: CONST.POLICY.ROLE.USER,
119+
});
120+
(useCardFeeds as jest.Mock).mockReturnValue([mockedFeeds, {status: 'loaded'}]);
121+
const {result} = renderHook(() => useIsAllowedToIssueCompanyCard({policyID: mockPolicyID}));
122+
expect(result?.current).toBe(false);
123+
});
95124
});

0 commit comments

Comments
 (0)