Skip to content

Commit 855dc8d

Browse files
committed
fix: resolve conflicts
2 parents a2adb96 + 24c9140 commit 855dc8d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1502
-403
lines changed
693 Bytes
Loading

jest/setup.ts

Lines changed: 59 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable max-classes-per-file */
22
import * as core from '@actions/core';
33
import '@shopify/flash-list/jestSetup';
4+
import {useMemo} from 'react';
45
import type * as RNAppLogs from 'react-native-app-logs';
56
import type {ReadDirItem} from 'react-native-fs';
67
import 'react-native-gesture-handler/jestSetup';
@@ -142,60 +143,70 @@ jest.mock('../modules/hybrid-app/src/NativeReactNativeHybridApp', () => ({
142143
clearOldDotAfterSignOut: jest.fn(),
143144
}));
144145

146+
const mockUseMemo = useMemo;
147+
145148
// Mock lazy asset loading to be synchronous in tests
146149
jest.mock('../src/hooks/useLazyAsset.ts', () => ({
147-
useMemoizedLazyAsset: jest.fn(() => {
148-
// Return a mock asset immediately to avoid async loading in tests
149-
const mockAsset = {
150-
src: 'mock-icon',
151-
testID: 'mock-asset',
152-
// Add common icon properties that tests might expect
153-
height: 20,
154-
width: 20,
155-
};
156-
157-
return {
158-
asset: mockAsset,
159-
isLoaded: true,
160-
isLoading: false,
161-
hasError: false,
162-
};
163-
}),
164-
useMemoizedLazyIllustrations: jest.fn((names: readonly string[]) => {
165-
// Return a Record with all requested illustration names
166-
const mockIllustrations: Record<string, unknown> = {};
167-
for (const name of names) {
168-
mockIllustrations[name] = {
169-
src: `mock-${name}`,
170-
testID: `mock-illustration-${name}`,
150+
useMemoizedLazyAsset: jest.fn((importFn) =>
151+
mockUseMemo(() => {
152+
// Return a mock asset immediately to avoid async loading in tests
153+
const mockAsset = {
154+
src: 'mock-icon',
155+
testID: 'mock-asset',
156+
// Add common icon properties that tests might expect
171157
height: 20,
172158
width: 20,
173159
};
174-
}
175-
return mockIllustrations;
176-
}),
177-
useMemoizedLazyExpensifyIcons: jest.fn((names: readonly string[]) => {
178-
// Return a Record with all requested icon names
179-
const mockIcons: Record<string, unknown> = {};
180-
for (const name of names) {
181-
mockIcons[name] = {
182-
src: `mock-${name}`,
183-
testID: `mock-expensify-icon-${name}`,
184-
height: 20,
185-
width: 20,
160+
161+
return {
162+
asset: mockAsset,
163+
isLoaded: true,
164+
isLoading: false,
165+
hasError: false,
186166
};
187-
}
188-
return mockIcons;
189-
}),
190-
default: jest.fn(() => {
191-
const mockAsset = {src: 'mock-icon', testID: 'mock-asset'};
192-
return {
193-
asset: mockAsset,
194-
isLoaded: true,
195-
isLoading: false,
196-
hasError: false,
197-
};
198-
}),
167+
}, [importFn]),
168+
),
169+
useMemoizedLazyIllustrations: jest.fn((names: readonly string[]) =>
170+
mockUseMemo(() => {
171+
// Return a Record with all requested illustration names
172+
const mockIllustrations: Record<string, unknown> = {};
173+
for (const name of names) {
174+
mockIllustrations[name] = {
175+
src: `mock-${name}`,
176+
testID: `mock-illustration-${name}`,
177+
height: 20,
178+
width: 20,
179+
};
180+
}
181+
return mockIllustrations;
182+
}, [names]),
183+
),
184+
useMemoizedLazyExpensifyIcons: jest.fn((names: readonly string[]) =>
185+
mockUseMemo(() => {
186+
// Return a Record with all requested icon names
187+
const mockIcons: Record<string, unknown> = {};
188+
for (const name of names) {
189+
mockIcons[name] = {
190+
src: `mock-${name}`,
191+
testID: `mock-expensify-icon-${name}`,
192+
height: 20,
193+
width: 20,
194+
};
195+
}
196+
return mockIcons;
197+
}, [names]),
198+
),
199+
default: jest.fn((importFn) =>
200+
mockUseMemo(() => {
201+
const mockAsset = {src: 'mock-icon', testID: 'mock-asset'};
202+
return {
203+
asset: mockAsset,
204+
isLoaded: true,
205+
isLoading: false,
206+
hasError: false,
207+
};
208+
}, [importFn]),
209+
),
199210
}));
200211

201212
// Mock icon loading functions to resolve immediately

src/ONYXKEYS.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,9 @@ const ONYXKEYS = {
713713

714714
/** Used for identifying user as admin of a domain */
715715
SHARED_NVP_PRIVATE_ADMIN_ACCESS: 'sharedNVP_private_admin_access_',
716+
717+
/** SAML login metadata for a domain */
718+
SAML_METADATA: 'saml_metadata_',
716719
},
717720

718721
/** List of Form ids */
@@ -1095,6 +1098,7 @@ type OnyxCollectionValuesMapping = {
10951098
[ONYXKEYS.COLLECTION.NVP_EXPENSIFY_ON_CARD_WAITLIST]: OnyxTypes.CardOnWaitlist;
10961099
[ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD]: OnyxTypes.IssueNewCard;
10971100
[ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_ADMIN_ACCESS]: boolean;
1101+
[ONYXKEYS.COLLECTION.SAML_METADATA]: OnyxTypes.SamlMetadata;
10981102
};
10991103

11001104
type OnyxValuesMapping = {

src/components/Button/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ type ButtonProps = Partial<ChildrenProps> & {
6666
onLayout?: (event: LayoutChangeEvent) => void;
6767

6868
/** A function that is called when the button is clicked on */
69-
onPress?: (event?: GestureResponderEvent | KeyboardEvent) => void;
69+
onPress?: (event?: GestureResponderEvent | KeyboardEvent) => void | Promise<void>;
7070

7171
/** A function that is called when the button is long pressed */
7272
onLongPress?: (event?: GestureResponderEvent) => void;

src/components/ButtonWithDropdownMenu/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ type DropdownOption<TValueType> = {
3535
iconFill?: string;
3636
interactive?: boolean;
3737
numberOfLinesTitle?: number;
38-
titleStyle?: ViewStyle;
38+
titleStyle?: StyleProp<TextStyle>;
3939
shouldCloseModalOnSelect?: boolean;
4040
description?: string;
4141
descriptionTextStyle?: StyleProp<TextStyle>;

src/components/Domain/CopyableTextField.tsx

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
import React from 'react';
1+
import React, {useState} from 'react';
2+
import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
23
import {View} from 'react-native';
34
import ActivityIndicator from '@components/ActivityIndicator';
5+
import Button from '@components/Button';
46
import CopyTextToClipboard from '@components/CopyTextToClipboard';
57
import Text from '@components/Text';
8+
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
9+
import useLocalize from '@hooks/useLocalize';
610
import useTheme from '@hooks/useTheme';
711
import useThemeStyles from '@hooks/useThemeStyles';
812

@@ -12,21 +16,55 @@ type CopyableTextFieldProps = {
1216

1317
/** Should an activity indicator be shown instead of the text and button */
1418
isLoading?: boolean;
19+
20+
/** Custom styles for the outer most View */
21+
style?: StyleProp<ViewStyle>;
22+
23+
/** Custom styles for the displayed text */
24+
textStyle?: StyleProp<TextStyle>;
25+
26+
/** Whether the text field should be expandable */
27+
shouldDisplayShowMoreButton?: boolean;
1528
};
1629

17-
function CopyableTextField({value, isLoading = false}: CopyableTextFieldProps) {
30+
function CopyableTextField({value, isLoading = false, style, textStyle, shouldDisplayShowMoreButton = false}: CopyableTextFieldProps) {
1831
const styles = useThemeStyles();
1932
const theme = useTheme();
33+
const {translate} = useLocalize();
34+
35+
const [expanded, setExpanded] = useState(false);
36+
const icons = useMemoizedLazyExpensifyIcons(['DownArrow', 'UpArrow'] as const);
37+
2038
return (
21-
<View style={[styles.qbdSetupLinkBox, styles.border, styles.flexRow, styles.gap2, styles.justifyContentCenter, styles.alignItemsCenter]}>
39+
<View style={[styles.qbdSetupLinkBox, styles.border, styles.gap4, styles.justifyContentCenter, styles.alignItemsCenter, style]}>
2240
{isLoading ? (
2341
<ActivityIndicator color={theme.text} />
2442
) : (
2543
<>
26-
<Text style={styles.copyableTextField}>{value ?? ''}</Text>
27-
<View style={[styles.reportActionContextMenuMiniButton, styles.overflowHidden, styles.buttonHoveredBG]}>
28-
<CopyTextToClipboard urlToCopy={value ?? ''} />
44+
<View style={[styles.w100, styles.flexRow, styles.gap2, styles.justifyContentBetween, styles.alignItemsCenter]}>
45+
<Text
46+
style={[styles.copyableTextField, textStyle]}
47+
numberOfLines={!shouldDisplayShowMoreButton || expanded ? undefined : 4}
48+
>
49+
{value ?? ''}
50+
</Text>
51+
<CopyTextToClipboard
52+
urlToCopy={value ?? ''}
53+
styles={styles.copyableTextFieldButton}
54+
iconStyles={styles.t0}
55+
shouldHaveActiveBackground
56+
shouldUseButtonBackground
57+
/>
2958
</View>
59+
{shouldDisplayShowMoreButton && (
60+
<Button
61+
small
62+
text={translate(expanded ? 'common.showLess' : 'common.showMore')}
63+
onPress={() => setExpanded((current) => !current)}
64+
shouldShowRightIcon
65+
iconRight={expanded ? icons.UpArrow : icons.DownArrow}
66+
/>
67+
)}
3068
</>
3169
)}
3270
</View>

src/components/Domain/DomainMenuItem.tsx

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
import React from 'react';
2-
import Icon from '@components/Icon';
3-
// eslint-disable-next-line no-restricted-imports
4-
import * as Expensicons from '@components/Icon/Expensicons';
1+
import React, {useMemo} from 'react';
52
import type {OfflineWithFeedbackProps} from '@components/OfflineWithFeedback';
63
import OfflineWithFeedback from '@components/OfflineWithFeedback';
74
import type {PopoverMenuItem} from '@components/PopoverMenu';
85
import {PressableWithoutFeedback} from '@components/Pressable';
96
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
107
import useLocalize from '@hooks/useLocalize';
11-
import useTheme from '@hooks/useTheme';
128
import useThemeStyles from '@hooks/useThemeStyles';
139
import Navigation from '@libs/Navigation/Navigation';
1410
import CONST from '@src/CONST';
@@ -44,27 +40,29 @@ type DomainItem = {
4440
} & Pick<OfflineWithFeedbackProps, 'pendingAction'>;
4541

4642
function DomainMenuItem({item, index}: DomainMenuItemProps) {
47-
const icons = useMemoizedLazyExpensifyIcons(['NewWindow'] as const);
43+
const icons = useMemoizedLazyExpensifyIcons(['Globe'] as const);
4844
const styles = useThemeStyles();
4945
const {translate} = useLocalize();
50-
const {isAdmin, isValidated} = item;
51-
const theme = useTheme();
46+
const {isAdmin, isValidated, action} = item;
5247

53-
const threeDotsMenuItems: PopoverMenuItem[] | undefined =
54-
!isValidated && isAdmin
55-
? [
56-
{
57-
icon: Expensicons.Globe,
58-
text: translate('domain.goToDomain'),
59-
onSelected: item.action,
60-
},
61-
{
62-
icon: Expensicons.Globe,
63-
text: translate('domain.verifyDomain.title'),
64-
onSelected: () => Navigation.navigate(ROUTES.WORKSPACES_VERIFY_DOMAIN.getRoute(item.accountID)),
65-
},
66-
]
67-
: undefined;
48+
const threeDotsMenuItems: PopoverMenuItem[] | undefined = useMemo(
49+
() =>
50+
isAdmin
51+
? [
52+
{
53+
icon: icons.Globe,
54+
text: translate('domain.goToDomain'),
55+
onSelected: action,
56+
},
57+
!isValidated && {
58+
icon: icons.Globe,
59+
text: translate('domain.verifyDomain.title'),
60+
onSelected: () => Navigation.navigate(ROUTES.WORKSPACES_VERIFY_DOMAIN.getRoute(item.accountID)),
61+
},
62+
].filter((menuItem) => !!menuItem)
63+
: undefined,
64+
[isAdmin, icons.Globe, translate, action, isValidated, item.accountID],
65+
);
6866

6967
return (
7068
<OfflineWithFeedback
@@ -76,7 +74,7 @@ function DomainMenuItem({item, index}: DomainMenuItemProps) {
7674
role={CONST.ROLE.BUTTON}
7775
accessibilityLabel="row"
7876
style={styles.mh5}
79-
onPress={item.action}
77+
onPress={action}
8078
disabled={!isAdmin}
8179
>
8280
{({hovered}) => (
@@ -85,23 +83,6 @@ function DomainMenuItem({item, index}: DomainMenuItemProps) {
8583
badgeText={isAdmin && !isValidated ? translate('domain.notVerified') : undefined}
8684
isHovered={hovered}
8785
menuItems={threeDotsMenuItems}
88-
rightIcon={
89-
isValidated ? (
90-
<Icon
91-
src={icons.NewWindow}
92-
fill={hovered ? theme.iconHovered : theme.icon}
93-
isButtonIcon
94-
/>
95-
) : (
96-
<Icon
97-
src={Expensicons.ArrowRight}
98-
fill={theme.icon}
99-
additionalStyles={[styles.alignSelfCenter, !hovered && styles.opacitySemiTransparent]}
100-
isButtonIcon
101-
medium
102-
/>
103-
)
104-
}
10586
/>
10687
)}
10788
</PressableWithoutFeedback>

0 commit comments

Comments
 (0)