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

Migrate index.native.js to function component #24615

Merged
merged 38 commits into from
Feb 12, 2024
Merged
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
2a543a2
Updated variables and states (WIP)
kadiealexander Aug 16, 2023
0b36d7c
began updating lifecycle method to useEffect
kadiealexander Aug 16, 2023
3dcc675
Merge branch 'main' of github.com:Expensify/App into kadie-native-ind…
kadiealexander Aug 22, 2023
3834c8c
latest useEffect updates
kadiealexander Aug 29, 2023
67b1555
merge main
kadiealexander Oct 16, 2023
aa23f3a
Merge branch 'main' into kadie-native-index-update
kadiealexander Oct 16, 2023
00efb24
small errors found during testing
kadiealexander Oct 16, 2023
520b39d
trying to make lint happy
kadiealexander Oct 17, 2023
72f601d
Revert "small errors found during testing"
kadiealexander Oct 17, 2023
437ebeb
Revert "small errors found during testing"
kadiealexander Oct 17, 2023
3597be6
fix functions and run lint/prettier
kadiealexander Oct 17, 2023
6f892b6
merging with main
kadiealexander Oct 30, 2023
bffa142
Merge branch 'main' of github.com:Expensify/App into kadie-native-ind…
kadiealexander Oct 31, 2023
b010ede
ran prettier
kadiealexander Nov 7, 2023
c15f3d4
removed unnecessary PasswordResponses definition
kadiealexander Nov 7, 2023
968be38
merge main
kadiealexander Nov 13, 2023
cc5e2de
destructured props
kadiealexander Nov 27, 2023
8b5081d
destructured props
kadiealexander Nov 27, 2023
f842efc
updated arrow functions per comment
kadiealexander Nov 27, 2023
76c508e
updated arrow function for onSubmit per comment
kadiealexander Nov 27, 2023
e527f41
updated arrow function for onPasswordUpdated due to incorrect change
kadiealexander Nov 27, 2023
6bcfcdb
merging main and resolving conflicts
kadiealexander Nov 27, 2023
71d12f1
Merge branch 'main' of github.com:Expensify/App into kadie-native-ind…
kadiealexander Dec 11, 2023
7d8fbbe
merge with main and addressed reviewer comments
kadiealexander Dec 11, 2023
ee78ab6
fix lint issue
kadiealexander Dec 11, 2023
371b846
fix hook issue with previous commit
kadiealexander Dec 11, 2023
203e2ba
Update index.native.js
kadiealexander Dec 11, 2023
d20986f
Update index.native.js
kadiealexander Dec 11, 2023
29175df
Merge branch 'main' into kadie-native-index-update
kadiealexander Jan 8, 2024
0b0ed8c
fix lint error
kadiealexander Jan 11, 2024
9b4cf2e
fix lint error
kadiealexander Jan 11, 2024
9c38ea8
merging main
kadiealexander Jan 11, 2024
b42a4b2
fixing weird lint error
kadiealexander Jan 11, 2024
c9e5397
fixing lint error
kadiealexander Jan 11, 2024
4c08eb6
Update src/components/PDFView/index.native.js
kadiealexander Jan 17, 2024
798861b
merging main
kadiealexander Jan 19, 2024
347c1f5
Update src/components/PDFView/index.native.js
kadiealexander Jan 19, 2024
a74f76b
running prettier
kadiealexander Jan 19, 2024
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
201 changes: 90 additions & 111 deletions src/components/PDFView/index.native.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
import React, {Component} from 'react';
import React, {useCallback, useEffect, useState} from 'react';
import {View} from 'react-native';
import PDF from 'react-native-pdf';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import KeyboardAvoidingView from '@components/KeyboardAvoidingView';
import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
import Text from '@components/Text';
import withKeyboardState, {keyboardStatePropTypes} from '@components/withKeyboardState';
import withLocalize from '@components/withLocalize';
import withStyleUtils, {withStyleUtilsPropTypes} from '@components/withStyleUtils';
import withThemeStyles, {withThemeStylesPropTypes} from '@components/withThemeStyles';
import withWindowDimensions from '@components/withWindowDimensions';
import compose from '@libs/compose';
import useKeyboardState from '@hooks/useKeyboardState';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import CONST from '@src/CONST';
import PDFPasswordForm from './PDFPasswordForm';
import {defaultProps, propTypes as pdfViewPropTypes} from './pdfViewPropTypes';

const propTypes = {
...pdfViewPropTypes,
...keyboardStatePropTypes,
...withThemeStylesPropTypes,
...withStyleUtilsPropTypes,
};

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please undo this line break removal

Expand All @@ -36,41 +32,24 @@ const propTypes = {
* so that PDFPasswordForm doesn't bounce when react-native-pdf/PDF
* is (temporarily) rendered.
*/
class PDFView extends Component {
constructor(props) {
super(props);
this.state = {
shouldRequestPassword: false,
shouldAttemptPDFLoad: true,
shouldShowLoadingIndicator: true,
isPasswordInvalid: false,
failedToLoadPDF: false,
successToLoadPDF: false,
password: '',
};
this.initiatePasswordChallenge = this.initiatePasswordChallenge.bind(this);
this.attemptPDFLoadWithPassword = this.attemptPDFLoadWithPassword.bind(this);
this.finishPDFLoad = this.finishPDFLoad.bind(this);
this.handleFailureToLoadPDF = this.handleFailureToLoadPDF.bind(this);
}

componentDidUpdate() {
this.props.onToggleKeyboard(this.props.isKeyboardShown);
}

handleFailureToLoadPDF(error) {
if (error.message.match(/password/i)) {
this.initiatePasswordChallenge();
return;
}

this.setState({
failedToLoadPDF: true,
shouldAttemptPDFLoad: false,
shouldRequestPassword: false,
shouldShowLoadingIndicator: false,
});
}
function PDFView({onToggleKeyboard, onLoadComplete, fileName, onPress, isFocused, onScaleChanged, sourceURL, errorLabelStyles}) {
const [shouldRequestPassword, setShouldRequestPassword] = useState(false);
const [shouldAttemptPDFLoad, setShouldAttemptPDFLoad] = useState(true);
const [shouldShowLoadingIndicator, setShouldShowLoadingIndicator] = useState(true);
const [isPasswordInvalid, setIsPasswordInvalid] = useState(false);
const [failedToLoadPDF, setFailedToLoadPDF] = useState(false);
const [successToLoadPDF, setSuccessToLoadPDF] = useState(false);
const [password, setPassword] = useState('');
const {windowWidth, windowHeight, isSmallScreenWidth} = useWindowDimensions();
const {translate} = useLocalize();
const themeStyles = useThemeStyles();
const {isKeyboardShown} = useKeyboardState();
const StyleUtils = useStyleUtils();

useEffect(() => {
onToggleKeyboard(isKeyboardShown);
});

/**
* Initiate password challenge if message received from react-native-pdf/PDF
Expand All @@ -80,124 +59,124 @@ class PDFView extends Component {
* Note that the message doesn't specify whether the password is simply empty or
* invalid.
*/
initiatePasswordChallenge() {
this.setState({shouldShowLoadingIndicator: false});

const initiatePasswordChallenge = useCallback(() => {
setShouldShowLoadingIndicator(false);

// Render password form, and don't render PDF and loading indicator.
this.setState({
kadiealexander marked this conversation as resolved.
Show resolved Hide resolved
shouldRequestPassword: true,
shouldAttemptPDFLoad: false,
});
setShouldRequestPassword(true);
setShouldAttemptPDFLoad(false);

// The message provided by react-native-pdf doesn't indicate whether this
// is an initial password request or if the password is invalid. So we just assume
kadiealexander marked this conversation as resolved.
Show resolved Hide resolved
// that if a password was already entered then it's an invalid password error.
if (this.state.password) {
this.setState({isPasswordInvalid: true});
if (password) {
setIsPasswordInvalid(true);
}
}
}, [password]);

const handleFailureToLoadPDF = (error) => {
if (error.message.match(/password/i)) {
initiatePasswordChallenge();
return;
}
setFailedToLoadPDF(true);
setShouldShowLoadingIndicator(false);
setShouldRequestPassword(false);
setShouldAttemptPDFLoad(false);
};

/**
* When the password is submitted via PDFPasswordForm, save the password
* in state and attempt to load the PDF. Also show the loading indicator
* since react-native-pdf/PDF will need to reload the PDF.
*
* @param {String} password Password submitted via PDFPasswordForm
* @param {String} pdfPassword Password submitted via PDFPasswordForm
*/
attemptPDFLoadWithPassword(password) {
const attemptPDFLoadWithPassword = (pdfPassword) => {
// Render react-native-pdf/PDF so that it can validate the password.
// Note that at this point in the password challenge, shouldRequestPassword is true.
// Thus react-native-pdf/PDF will be rendered - but not visible.
this.setState({
password,
shouldAttemptPDFLoad: true,
shouldShowLoadingIndicator: true,
});
}

setPassword(pdfPassword);
setShouldAttemptPDFLoad(true);
setShouldShowLoadingIndicator(true);
};
/**
* After the PDF is successfully loaded hide PDFPasswordForm and the loading
* indicator.
*/
finishPDFLoad() {
this.setState({
shouldRequestPassword: false,
shouldShowLoadingIndicator: false,
successToLoadPDF: true,
});
this.props.onLoadComplete();
}
const finishPDFLoad = () => {
setShouldRequestPassword(false);
setShouldShowLoadingIndicator(false);
setSuccessToLoadPDF(true);
onLoadComplete();
};

renderPDFView() {
const pdfStyles = [this.props.themeStyles.imageModalPDF, this.props.StyleUtils.getWidthAndHeightStyle(this.props.windowWidth, this.props.windowHeight)];
function renderPDFView() {
const pdfStyles = [themeStyles.imageModalPDF, StyleUtils.getWidthAndHeightStyle(windowWidth, windowHeight)];

// If we haven't yet successfully validated the password and loaded the PDF,
// then we need to hide the react-native-pdf/PDF component so that PDFPasswordForm
// is positioned nicely. We're specifically hiding it because we still need to render
// the PDF component so that it can validate the password.
if (this.state.shouldRequestPassword) {
pdfStyles.push(this.props.themeStyles.invisible);
if (shouldRequestPassword) {
pdfStyles.push(themeStyles.invisible);
}

const containerStyles =
this.state.shouldRequestPassword && this.props.isSmallScreenWidth
? [this.props.themeStyles.w100, this.props.themeStyles.flex1]
: [this.props.themeStyles.alignItemsCenter, this.props.themeStyles.flex1];
const containerStyles = shouldRequestPassword && isSmallScreenWidth ? [themeStyles.w100, themeStyles.flex1] : [themeStyles.alignItemsCenter, themeStyles.flex1];

return (
<View style={containerStyles}>
{this.state.failedToLoadPDF && (
<View style={[this.props.themeStyles.flex1, this.props.themeStyles.justifyContentCenter]}>
<Text style={this.props.errorLabelStyles}>{this.props.translate('attachmentView.failedToLoadPDF')}</Text>
{failedToLoadPDF && (
<View style={[themeStyles.flex1, themeStyles.justifyContentCenter]}>
<Text style={errorLabelStyles}>{translate('attachmentView.failedToLoadPDF')}</Text>
</View>
)}
{this.state.shouldAttemptPDFLoad && (
{shouldAttemptPDFLoad && (
<PDF
fitPolicy={0}
trustAllCerts={false}
renderActivityIndicator={() => <FullScreenLoadingIndicator />}
source={{uri: this.props.sourceURL}}
source={{uri: sourceURL}}
style={pdfStyles}
onError={this.handleFailureToLoadPDF}
password={this.state.password}
onLoadComplete={this.finishPDFLoad}
onPageSingleTap={this.props.onPress}
onScaleChanged={this.props.onScaleChanged}
onError={handleFailureToLoadPDF}
password={password}
onLoadComplete={finishPDFLoad}
onPageSingleTap={onPress}
onScaleChanged={onScaleChanged}
/>
)}

{this.state.shouldRequestPassword && (
<KeyboardAvoidingView style={this.props.themeStyles.flex1}>
{shouldRequestPassword && (
<KeyboardAvoidingView style={themeStyles.flex1}>
<PDFPasswordForm
isFocused={this.props.isFocused}
onSubmit={this.attemptPDFLoadWithPassword}
onPasswordUpdated={() => this.setState({isPasswordInvalid: false})}
isPasswordInvalid={this.state.isPasswordInvalid}
shouldShowLoadingIndicator={this.state.shouldShowLoadingIndicator}
isFocused={isFocused}
onSubmit={attemptPDFLoadWithPassword}
onPasswordUpdated={() => setIsPasswordInvalid(false)}
isPasswordInvalid={isPasswordInvalid}
shouldShowLoadingIndicator={shouldShowLoadingIndicator}
/>
</KeyboardAvoidingView>
)}
</View>
);
}

render() {
return this.props.onPress && !this.state.successToLoadPDF ? (
<PressableWithoutFeedback
onPress={this.props.onPress}
style={[this.props.themeStyles.flex1, this.props.themeStyles.flexRow, this.props.themeStyles.alignSelfStretch]}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
accessibilityLabel={this.props.fileName || this.props.translate('attachmentView.unknownFilename')}
>
{this.renderPDFView()}
</PressableWithoutFeedback>
) : (
this.renderPDFView()
);
}
return onPress && !successToLoadPDF ? (
<PressableWithoutFeedback
onPress={onPress}
style={[themeStyles.flex1, themeStyles.flexRow, themeStyles.alignSelfStretch]}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON}
accessibilityLabel={fileName || translate('attachmentView.unknownFilename')}
kadiealexander marked this conversation as resolved.
Show resolved Hide resolved
>
{renderPDFView()}
</PressableWithoutFeedback>
) : (
renderPDFView()
);
}

PDFView.displayName = 'PDFView';
kadiealexander marked this conversation as resolved.
Show resolved Hide resolved
PDFView.propTypes = propTypes;
PDFView.defaultProps = defaultProps;

export default compose(withWindowDimensions, withKeyboardState, withLocalize, withThemeStyles, withStyleUtils)(PDFView);
export default PDFView;
Loading