Skip to content

Commit e945abb

Browse files
authored
Merge pull request #23061 from Expensify/Rory-WorkspacePage
Implement animated WorkspacesListPage and LoungeAccessPage
2 parents 0fec944 + b9581dc commit e945abb

23 files changed

+201
-162
lines changed

assets/animations/ExpensifyLounge.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

assets/animations/WorkspacePlanet.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

src/CONST.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2542,9 +2542,6 @@ const CONST = {
25422542
ADJUSTABLE: 'adjustable',
25432543
IMAGE: 'image',
25442544
},
2545-
SETTINGS_LOUNGE_ACCESS: {
2546-
HEADER_IMAGE_ASPECT_RATIO: 0.64,
2547-
},
25482545
TRANSLATION_KEYS: {
25492546
ATTACHMENT: 'common.attachment',
25502547
},

src/SCREENS.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ export default {
1111
TRANSITION_BETWEEN_APPS: 'TransitionBetweenApps',
1212
SETTINGS: {
1313
PREFERENCES: 'Settings_Preferences',
14+
WORKSPACES: 'Settings_Workspaces',
1415
},
1516
};

src/components/Avatar.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import * as Expensicons from './Icon/Expensicons';
1111
import Image from './Image';
1212
import styles from '../styles/styles';
1313
import * as ReportUtils from '../libs/ReportUtils';
14-
import useOnNetworkReconnect from '../hooks/useOnNetworkReconnect';
14+
import useNetwork from '../hooks/useNetwork';
1515

1616
const propTypes = {
1717
/** Source for the avatar. Can be a URL or an icon. */
@@ -64,7 +64,7 @@ const defaultProps = {
6464
function Avatar(props) {
6565
const [imageError, setImageError] = useState(false);
6666

67-
useOnNetworkReconnect(() => setImageError(false));
67+
useNetwork({onReconnect: () => setImageError(false)});
6868

6969
if (!props.source) {
7070
return null;

src/components/FeatureList.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import _ from 'underscore';
2+
import React from 'react';
3+
import {View} from 'react-native';
4+
import PropTypes from 'prop-types';
5+
import menuItemPropTypes from './menuItemPropTypes';
6+
import MenuItem from './MenuItem';
7+
import styles from '../styles/styles';
8+
import useLocalize from '../hooks/useLocalize';
9+
import Text from './Text';
10+
11+
const propTypes = {
12+
/** A list of menuItems representing the feature list. */
13+
menuItems: PropTypes.arrayOf(PropTypes.shape({...menuItemPropTypes, translationKey: PropTypes.string})).isRequired,
14+
15+
/** A headline translation key to show above the feature list. */
16+
headline: PropTypes.string.isRequired,
17+
18+
/** A description translation key to show below the headline and above the feature list. */
19+
description: PropTypes.string.isRequired,
20+
};
21+
22+
function FeatureList({menuItems, headline, description}) {
23+
const {translate} = useLocalize();
24+
return (
25+
<>
26+
<View style={[styles.w100, styles.ph5, styles.pb5]}>
27+
<Text
28+
style={[styles.textHeadline, styles.preWrap, styles.mb2]}
29+
numberOfLines={2}
30+
>
31+
{translate(headline)}
32+
</Text>
33+
<Text style={styles.baseFontStyle}>{translate(description)}</Text>
34+
</View>
35+
{_.map(menuItems, ({translationKey, icon}) => (
36+
<MenuItem
37+
key={translationKey}
38+
title={translate(translationKey)}
39+
icon={icon}
40+
iconWidth={60}
41+
iconHeight={60}
42+
iconStyles={[styles.mr3, styles.ml3]}
43+
interactive={false}
44+
/>
45+
))}
46+
</>
47+
);
48+
}
49+
50+
FeatureList.propTypes = propTypes;
51+
FeatureList.displayName = 'FeatureList';
52+
53+
export default FeatureList;

src/components/IllustratedHeaderPageLayout.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import _ from 'underscore';
12
import React from 'react';
23
import PropTypes from 'prop-types';
34
import {ScrollView, View} from 'react-native';
@@ -9,35 +10,45 @@ import styles from '../styles/styles';
910
import themeColors from '../styles/themes/default';
1011
import * as StyleUtils from '../styles/StyleUtils';
1112
import useWindowDimensions from '../hooks/useWindowDimensions';
13+
import FixedFooter from './FixedFooter';
1214

1315
const propTypes = {
1416
...headerWithBackButtonPropTypes,
1517

1618
/** Children to display in the lower half of the page (below the header section w/ an animation) */
1719
children: PropTypes.node.isRequired,
1820

19-
/** The background color to apply in the upper half of the screen. */
20-
backgroundColor: PropTypes.string.isRequired,
21-
2221
/** The illustration to display in the header. Can be either an SVG component or a JSON object representing a Lottie animation. */
2322
illustration: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,
23+
24+
/** The background color to apply in the upper half of the screen. */
25+
backgroundColor: PropTypes.string,
26+
27+
/** A fixed footer to display at the bottom of the page. */
28+
footer: PropTypes.node,
29+
};
30+
31+
const defaultProps = {
32+
backgroundColor: themeColors.appBG,
33+
footer: null,
2434
};
2535

26-
function IllustratedHeaderPageLayout({backgroundColor, children, illustration, ...propsToPassToHeader}) {
36+
function IllustratedHeaderPageLayout({backgroundColor, children, illustration, footer, ...propsToPassToHeader}) {
2737
const {windowHeight} = useWindowDimensions();
2838
return (
2939
<ScreenWrapper
3040
style={[StyleUtils.getBackgroundColorStyle(backgroundColor)]}
3141
shouldEnablePickerAvoiding={false}
3242
includeSafeAreaPaddingBottom={false}
43+
offlineIndicatorStyle={[StyleUtils.getBackgroundColorStyle(themeColors.appBG)]}
3344
>
3445
{({safeAreaPaddingBottomStyle}) => (
3546
<>
3647
<HeaderWithBackButton
3748
// eslint-disable-next-line react/jsx-props-no-spreading
3849
{...propsToPassToHeader}
39-
titleColor={themeColors.iconColorfulBackground}
40-
iconFill={themeColors.iconColorfulBackground}
50+
titleColor={backgroundColor === themeColors.appBG ? undefined : themeColors.textColorfulBackground}
51+
iconFill={backgroundColor === themeColors.appBG ? undefined : themeColors.iconColorfulBackground}
4152
/>
4253
<View style={[styles.flex1, StyleUtils.getBackgroundColorStyle(themeColors.appBG)]}>
4354
<ScrollView
@@ -55,6 +66,7 @@ function IllustratedHeaderPageLayout({backgroundColor, children, illustration, .
5566
</View>
5667
<View style={[styles.pt5]}>{children}</View>
5768
</ScrollView>
69+
{!_.isNull(footer) && <FixedFooter>{footer}</FixedFooter>}
5870
</View>
5971
</>
6072
)}
@@ -63,6 +75,7 @@ function IllustratedHeaderPageLayout({backgroundColor, children, illustration, .
6375
}
6476

6577
IllustratedHeaderPageLayout.propTypes = propTypes;
78+
IllustratedHeaderPageLayout.defaultProps = defaultProps;
6679
IllustratedHeaderPageLayout.displayName = 'IllustratedHeaderPageLayout';
6780

6881
export default IllustratedHeaderPageLayout;

src/components/LottieAnimations.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import ExpensifyLounge from '../../assets/animations/ExpensifyLounge.json';
12
import Fireworks from '../../assets/animations/Fireworks.json';
23
import Hands from '../../assets/animations/Hands.json';
34
import PreferencesDJ from '../../assets/animations/PreferencesDJ.json';
45
import ReviewingBankInfo from '../../assets/animations/ReviewingBankInfo.json';
6+
import WorkspacePlanet from '../../assets/animations/WorkspacePlanet.json';
57

6-
export {Fireworks, Hands, PreferencesDJ, ReviewingBankInfo};
8+
export {ExpensifyLounge, Fireworks, Hands, PreferencesDJ, ReviewingBankInfo, WorkspacePlanet};

src/components/MagicCodeInput.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import TextInput from './TextInput';
1111
import FormHelpMessage from './FormHelpMessage';
1212
import {withNetwork} from './OnyxProvider';
1313
import networkPropTypes from './networkPropTypes';
14-
import useOnNetworkReconnect from '../hooks/useOnNetworkReconnect';
14+
import useNetwork from '../hooks/useNetwork';
1515
import * as Browser from '../libs/Browser';
1616

1717
const propTypes = {
@@ -142,7 +142,7 @@ function MagicCodeInput(props) {
142142
props.onFulfill(props.value);
143143
};
144144

145-
useOnNetworkReconnect(validateAndSubmit);
145+
useNetwork({onReconnect: validateAndSubmit});
146146

147147
useEffect(() => {
148148
validateAndSubmit();

src/components/MenuItem.js

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,14 @@ import colors from '../styles/colors';
1818
import MultipleAvatars from './MultipleAvatars';
1919
import * as defaultWorkspaceAvatars from './Icon/WorkspaceDefaultAvatars';
2020
import PressableWithSecondaryInteraction from './PressableWithSecondaryInteraction';
21-
import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
2221
import * as DeviceCapabilities from '../libs/DeviceCapabilities';
2322
import ControlSelection from '../libs/ControlSelection';
2423
import variables from '../styles/variables';
2524
import * as Session from '../libs/actions/Session';
2625
import Hoverable from './Hoverable';
26+
import useWindowDimensions from '../hooks/useWindowDimensions';
2727

28-
const propTypes = {
29-
...menuItemPropTypes,
30-
...windowDimensionsPropTypes,
31-
};
28+
const propTypes = menuItemPropTypes;
3229

3330
const defaultProps = {
3431
badgeText: undefined,
@@ -76,7 +73,9 @@ const defaultProps = {
7673
shouldGreyOutWhenDisabled: true,
7774
};
7875

79-
function MenuItem(props) {
76+
const MenuItem = React.forwardRef((props, ref) => {
77+
const {isSmallScreenWidth} = useWindowDimensions();
78+
8079
const isDeleted = _.contains(props.style, styles.offlineFeedback.deleted);
8180
const descriptionVerticalMargin = props.shouldShowDescriptionOnTop ? styles.mb1 : styles.mt1;
8281
const titleTextStyle = StyleUtils.combineStyles(
@@ -118,7 +117,7 @@ function MenuItem(props) {
118117

119118
props.onPress(e);
120119
}, props.isAnonymousAction)}
121-
onPressIn={() => props.shouldBlockSelection && props.isSmallScreenWidth && DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()}
120+
onPressIn={() => props.shouldBlockSelection && isSmallScreenWidth && DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()}
122121
onPressOut={ControlSelection.unblock}
123122
onSecondaryInteraction={props.onSecondaryInteraction}
124123
style={({pressed}) => [
@@ -130,7 +129,7 @@ function MenuItem(props) {
130129
props.shouldGreyOutWhenDisabled && props.disabled && styles.buttonOpacityDisabled,
131130
]}
132131
disabled={props.disabled}
133-
ref={props.forwardedRef}
132+
ref={ref}
134133
accessibilityRole={CONST.ACCESSIBILITY_ROLE.MENUITEM}
135134
accessibilityLabel={props.title}
136135
>
@@ -301,20 +300,10 @@ function MenuItem(props) {
301300
)}
302301
</Hoverable>
303302
);
304-
}
303+
});
305304

306305
MenuItem.propTypes = propTypes;
306+
MenuItem.defaultProps = defaultProps;
307307
MenuItem.displayName = 'MenuItem';
308308

309-
const MenuItemWithWindowDimensions = withWindowDimensions(
310-
React.forwardRef((props, ref) => (
311-
<MenuItem
312-
// eslint-disable-next-line react/jsx-props-no-spreading
313-
{...props}
314-
forwardedRef={ref}
315-
/>
316-
)),
317-
);
318-
MenuItemWithWindowDimensions.defaultProps = defaultProps;
319-
320-
export default MenuItemWithWindowDimensions;
309+
export default MenuItem;

0 commit comments

Comments
 (0)