Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Global Offline Indicator #9895

Merged
merged 18 commits into from
Jul 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/components/OfflineIndicator.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import {withNetwork} from './OnyxProvider';
import networkPropTypes from './networkPropTypes';
import Icon from './Icon';
Expand All @@ -9,11 +10,15 @@ import Text from './Text';
import styles from '../styles/styles';
import compose from '../libs/compose';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
import withWindowDimensions from './withWindowDimensions';

const propTypes = {
/** Information about the network */
network: networkPropTypes.isRequired,

/** Is the window width narrow, like on a mobile device */
isSmallScreenWidth: PropTypes.bool.isRequired,

...withLocalizePropTypes,
};

Expand All @@ -24,7 +29,7 @@ const OfflineIndicator = (props) => {

return (
<View style={[
styles.chatItemComposeSecondaryRowOffset,
props.isSmallScreenWidth ? styles.offlineIndicatorMobile : styles.offlineIndicator,
styles.flexRow,
styles.alignItemsCenter]}
>
Expand All @@ -44,6 +49,7 @@ OfflineIndicator.propTypes = propTypes;
OfflineIndicator.displayName = 'OfflineIndicator';

export default compose(
withWindowDimensions,
withLocalize,
withNetwork(),
)(OfflineIndicator);
60 changes: 43 additions & 17 deletions src/components/ScreenWrapper.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import _ from 'underscore';
import React from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import {View, KeyboardAvoidingView} from 'react-native';
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
import {withOnyx} from 'react-native-onyx';
import styles from '../styles/styles';
Expand All @@ -15,6 +15,10 @@ import compose from '../libs/compose';
import ONYXKEYS from '../ONYXKEYS';
import CONST from '../CONST';
import withNavigation from './withNavigation';
import withWindowDimensions from './withWindowDimensions';
import OfflineIndicator from './OfflineIndicator';
import {withNetwork} from './OnyxProvider';
import networkPropTypes from './networkPropTypes';

const propTypes = {
/** Array of additional styles to add */
Expand All @@ -35,6 +39,13 @@ const propTypes = {
// Called when navigated Screen's transition is finished.
onTransitionEnd: PropTypes.func,

/** Is the window width narrow, like on a mobile device */
isSmallScreenWidth: PropTypes.bool.isRequired,

/** The behavior to pass to the KeyboardAvoidingView, requires some trial and error depending on the layout/devices used.
* Search 'switch(behavior)' in ./node_modules/react-native/Libraries/Components/Keyboard/KeyboardAvoidingView.js for more context */
keyboardAvoidingViewBehavior: PropTypes.oneOf(['padding', 'height', 'position']),

// react-navigation navigation object available to screen components
navigation: PropTypes.shape({
// Method to attach listener to Navigation state.
Expand All @@ -47,6 +58,9 @@ const propTypes = {
willAlertModalBecomeVisible: PropTypes.bool,
}),

/** Information about the network */
network: networkPropTypes.isRequired,

};

const defaultProps = {
Expand All @@ -58,6 +72,7 @@ const defaultProps = {
addListener: () => {},
},
modal: {},
keyboardAvoidingViewBehavior: 'padding',
};

class ScreenWrapper extends React.Component {
Expand Down Expand Up @@ -105,27 +120,36 @@ class ScreenWrapper extends React.Component {
paddingStyle.paddingTop = paddingTop;
}

if (this.props.includePaddingBottom) {
// We always need the safe area padding bottom if we're showing the offline indicator since it is bottom-docked.
if (this.props.includePaddingBottom || this.props.network.isOffline) {
paddingStyle.paddingBottom = paddingBottom;
}

return (
<View style={[
...this.props.style,
styles.flex1,
paddingStyle,
]}
<View
style={[
...this.props.style,
styles.flex1,
paddingStyle,
]}
>
<HeaderGap />
{// If props.children is a function, call it to provide the insets to the children.
_.isFunction(this.props.children)
? this.props.children({
insets,
didScreenTransitionEnd: this.state.didScreenTransitionEnd,
})
: this.props.children
}
<KeyboardShortcutsModal />
<KeyboardAvoidingView style={[styles.w100, styles.h100]} behavior={this.props.keyboardAvoidingViewBehavior}>
<HeaderGap />
{// If props.children is a function, call it to provide the insets to the children.
_.isFunction(this.props.children)
? this.props.children({
insets,
didScreenTransitionEnd: this.state.didScreenTransitionEnd,
})
: this.props.children
}
<KeyboardShortcutsModal />
{this.props.isSmallScreenWidth && this.props.network.isOffline && (
<View style={styles.chatItemComposeSecondaryRow}>
<OfflineIndicator />
</View>
)}
</KeyboardAvoidingView>
</View>
);
}}
Expand All @@ -139,9 +163,11 @@ ScreenWrapper.defaultProps = defaultProps;

export default compose(
withNavigation,
withWindowDimensions,
withOnyx({
modal: {
key: ONYXKEYS.MODAL,
},
}),
withNetwork(),
)(ScreenWrapper);
117 changes: 57 additions & 60 deletions src/pages/AddPersonalBankAccountPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import AddPlaidBankAccount from '../components/AddPlaidBankAccount';
import getPlaidOAuthReceivedRedirectURI from '../libs/getPlaidOAuthReceivedRedirectURI';
import compose from '../libs/compose';
import ONYXKEYS from '../ONYXKEYS';
import KeyboardAvoidingView from '../components/KeyboardAvoidingView';
import Text from '../components/Text';
import styles from '../styles/styles';
import Button from '../components/Button';
Expand Down Expand Up @@ -125,67 +124,65 @@ class AddPersonalBankAccountPage extends React.Component {

return (
<ScreenWrapper>
<KeyboardAvoidingView>
<HeaderWithCloseButton
title={this.props.translate('bankAccount.addBankAccount')}
onCloseButtonPress={Navigation.goBack}
shouldShowBackButton
onBackButtonPress={Navigation.goBack}
/>
{success ? (
<>
<Text style={[styles.formSuccess, styles.mh5]}>
{success}
</Text>
<View style={[styles.mh5, styles.mb5, styles.flex1, styles.justifyContentEnd]}>
<Button
success
text={this.props.translate('common.continue')}
onPress={() => Navigation.navigate(ROUTES.SETTINGS_PAYMENTS)}
/>
</View>
</>
) : (
<FormScrollView>
<View style={[styles.mh5, styles.mb5]}>
<AddPlaidBankAccount
onSelect={(params) => {
this.setState({
selectedPlaidBankAccount: params.selectedPlaidBankAccount,
});
}}
onExitPlaid={Navigation.goBack}
receivedRedirectURI={getPlaidOAuthReceivedRedirectURI()}
/>
{!_.isUndefined(this.state.selectedPlaidBankAccount) && (
<View style={[styles.mb5]}>
<TextInput
label={this.props.translate('addPersonalBankAccountPage.enterPassword')}
secureTextEntry
value={this.state.password}
autoCompleteType="password"
textContentType="password"
autoCapitalize="none"
autoFocus={canFocusInputOnScreenFocus()}
onChangeText={text => this.setState({password: text})}
errorText={this.getErrorText('password')}
hasError={this.getErrors().password}
/>
</View>
)}
</View>
<HeaderWithCloseButton
title={this.props.translate('bankAccount.addBankAccount')}
onCloseButtonPress={Navigation.goBack}
shouldShowBackButton
onBackButtonPress={Navigation.goBack}
/>
{success ? (
<>
<Text style={[styles.formSuccess, styles.mh5]}>
{success}
</Text>
<View style={[styles.mh5, styles.mb5, styles.flex1, styles.justifyContentEnd]}>
<Button
success
text={this.props.translate('common.continue')}
onPress={() => Navigation.navigate(ROUTES.SETTINGS_PAYMENTS)}
/>
</View>
</>
) : (
<FormScrollView>
<View style={[styles.mh5, styles.mb5]}>
<AddPlaidBankAccount
onSelect={(params) => {
this.setState({
selectedPlaidBankAccount: params.selectedPlaidBankAccount,
});
}}
onExitPlaid={Navigation.goBack}
receivedRedirectURI={getPlaidOAuthReceivedRedirectURI()}
/>
{!_.isUndefined(this.state.selectedPlaidBankAccount) && (
<FormAlertWithSubmitButton
isAlertVisible={Boolean(error)}
buttonText={this.props.translate('common.saveAndContinue')}
onSubmit={this.submit}
message={error}
isLoading={loading}
/>
<View style={[styles.mb5]}>
<TextInput
label={this.props.translate('addPersonalBankAccountPage.enterPassword')}
secureTextEntry
value={this.state.password}
autoCompleteType="password"
textContentType="password"
autoCapitalize="none"
autoFocus={canFocusInputOnScreenFocus()}
onChangeText={text => this.setState({password: text})}
errorText={this.getErrorText('password')}
hasError={this.getErrors().password}
/>
</View>
)}
</FormScrollView>
)}
</KeyboardAvoidingView>
</View>
{!_.isUndefined(this.state.selectedPlaidBankAccount) && (
<FormAlertWithSubmitButton
isAlertVisible={Boolean(error)}
buttonText={this.props.translate('common.saveAndContinue')}
onSubmit={this.submit}
message={error}
isLoading={loading}
/>
)}
</FormScrollView>
)}
</ScreenWrapper>
);
}
Expand Down
Loading