Skip to content

Commit

Permalink
Merge branch 'main' into fix-15289
Browse files Browse the repository at this point in the history
  • Loading branch information
allroundexperts committed Aug 4, 2023
2 parents edcc556 + f9d760f commit 74f8e0d
Show file tree
Hide file tree
Showing 56 changed files with 848 additions and 565 deletions.
1 change: 1 addition & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ This is a checklist for PR authors. Please make sure to complete all tasks and c
- [ ] If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
- [ ] If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like `Avatar` is modified, I verified that `Avatar` is working as expected in all cases)
- [ ] If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
- [ ] If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
- [ ] If a new page is added, I verified it's using the `ScrollView` component to make it scrollable when more elements are added to the page.
- [ ] If the `main` branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the `Test` steps.
- [ ] I have checked off every checkbox in the PR author checklist, including those that don't apply to this PR.
Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001034901
versionName "1.3.49-1"
versionCode 1001035000
versionName "1.3.50-0"
}

signingConfigs {
Expand Down
1 change: 1 addition & 0 deletions contributingGuides/REVIEWER_CHECKLIST.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
- [ ] If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
- [ ] If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like `Avatar` is modified, I verified that `Avatar` is working as expected in all cases)
- [ ] If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
- [ ] If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
- [ ] If a new page is added, I verified it's using the `ScrollView` component to make it scrollable when more elements are added to the page.
- [ ] If the `main` branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the `Test` steps.
- [ ] I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.
Expand Down
4 changes: 2 additions & 2 deletions ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.3.49</string>
<string>1.3.50</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
Expand All @@ -32,7 +32,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.3.49.1</string>
<string>1.3.50.0</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
4 changes: 2 additions & 2 deletions ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.3.49</string>
<string>1.3.50</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.3.49.1</string>
<string>1.3.50.0</string>
</dict>
</plist>
2 changes: 1 addition & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1234,4 +1234,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: bc8161c6bfffeec6e6eaf84be18de5041ddcacf6

COCOAPODS: 1.11.3
COCOAPODS: 1.12.1
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
"version": "1.3.49-1",
"version": "1.3.50-0",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Expand Down
6 changes: 5 additions & 1 deletion src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ const CONST = {
DATE: {
MOMENT_FORMAT_STRING: 'YYYY-MM-DD',
SQL_DATE_TIME: 'YYYY-MM-DD HH:mm:ss',
FNS_FORMAT_STRING: 'yyyy-MM-dd',
UNIX_EPOCH: '1970-01-01 00:00:00.000',
MAX_DATE: '9999-12-31',
MIN_DATE: '0001-01-01',
Expand Down Expand Up @@ -1061,6 +1062,9 @@ const CONST = {
DELETE: 'delete',
},
AMOUNT_MAX_LENGTH: 10,
RECEIPT_STATE: {
SCANREADY: 'SCANREADY',
},
FILE_TYPES: {
HTML: 'html',
DOC: 'doc',
Expand Down Expand Up @@ -1148,7 +1152,7 @@ const CONST = {
REGEX: {
SPECIAL_CHARS_WITHOUT_NEWLINE: /((?!\n)[()-\s\t])/g,
DIGITS_AND_PLUS: /^\+?[0-9]*$/,
ALPHABETIC_CHARS_WITH_NUMBER: /^[a-zA-ZÀ-ÿ0-9 ]*$/,
ALPHABETIC_AND_LATIN_CHARS: /^[a-zA-ZÀ-ÿ ]*$/,
POSITIVE_INTEGER: /^\d+$/,
PO_BOX: /\b[P|p]?(OST|ost)?\.?\s*[O|o|0]?(ffice|FFICE)?\.?\s*[B|b][O|o|0]?[X|x]?\.?\s+[#]?(\d+)\b/,
ANY_VALUE: /^.+$/,
Expand Down
109 changes: 63 additions & 46 deletions src/components/AttachmentModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import lodashExtend from 'lodash/extend';
import _ from 'underscore';
import CONST from '../CONST';
import Modal from './Modal';
import useLocalize from '../hooks/useLocalize';
import AttachmentView from './AttachmentView';
import AttachmentCarousel from './AttachmentCarousel';
import styles from '../styles/styles';
Expand Down Expand Up @@ -105,6 +106,7 @@ function AttachmentModal(props) {
}
: undefined,
);
const {translate} = useLocalize();

const onCarouselAttachmentChange = props.onCarouselAttachmentChange;

Expand All @@ -130,11 +132,10 @@ function AttachmentModal(props) {
*/
const getModalType = useCallback(
(sourceURL, _file) =>
sourceURL && (Str.isPDF(sourceURL) || (_file && Str.isPDF(_file.name || props.translate('attachmentView.unknownFilename'))))
sourceURL && (Str.isPDF(sourceURL) || (_file && Str.isPDF(_file.name || translate('attachmentView.unknownFilename'))))
? CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE
: CONST.MODAL.MODAL_TYPE.CENTERED,
// eslint-disable-next-line react-hooks/exhaustive-deps
[props.translate],
[translate],
);

/**
Expand Down Expand Up @@ -182,57 +183,73 @@ function AttachmentModal(props) {
* @param {Object} _file
* @returns {Boolean}
*/
const isValidFile = useCallback(
(_file) => {
const {fileExtension} = FileUtils.splitExtensionFromFileName(lodashGet(_file, 'name', ''));
if (_.contains(CONST.API_ATTACHMENT_VALIDATIONS.UNALLOWED_EXTENSIONS, fileExtension.toLowerCase())) {
const invalidReason = 'attachmentPicker.notAllowedExtension';

setIsAttachmentInvalid(true);
setAttachmentInvalidReasonTitle('attachmentPicker.wrongFileType');
setAttachmentInvalidReason(invalidReason);
return false;
}
const isValidFile = useCallback((_file) => {
const {fileExtension} = FileUtils.splitExtensionFromFileName(lodashGet(_file, 'name', ''));
if (_.contains(CONST.API_ATTACHMENT_VALIDATIONS.UNALLOWED_EXTENSIONS, fileExtension.toLowerCase())) {
const invalidReason = 'attachmentPicker.notAllowedExtension';

setIsAttachmentInvalid(true);
setAttachmentInvalidReasonTitle('attachmentPicker.wrongFileType');
setAttachmentInvalidReason(invalidReason);
return false;
}

if (lodashGet(_file, 'size', 0) > CONST.API_ATTACHMENT_VALIDATIONS.MAX_SIZE) {
setIsAttachmentInvalid(true);
setAttachmentInvalidReasonTitle('attachmentPicker.attachmentTooLarge');
setAttachmentInvalidReason('attachmentPicker.sizeExceeded');
return false;
}
if (lodashGet(_file, 'size', 0) > CONST.API_ATTACHMENT_VALIDATIONS.MAX_SIZE) {
setIsAttachmentInvalid(true);
setAttachmentInvalidReasonTitle('attachmentPicker.attachmentTooLarge');
setAttachmentInvalidReason('attachmentPicker.sizeExceeded');
return false;
}

if (lodashGet(_file, 'size', 0) < CONST.API_ATTACHMENT_VALIDATIONS.MIN_SIZE) {
setIsAttachmentInvalid(true);
setAttachmentInvalidReasonTitle('attachmentPicker.attachmentTooSmall');
setAttachmentInvalidReason('attachmentPicker.sizeNotMet');
return false;
}
if (lodashGet(_file, 'size', 0) < CONST.API_ATTACHMENT_VALIDATIONS.MIN_SIZE) {
setIsAttachmentInvalid(true);
setAttachmentInvalidReasonTitle('attachmentPicker.attachmentTooSmall');
setAttachmentInvalidReason('attachmentPicker.sizeNotMet');
return false;
}

return true;
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[props.translate],
);
return true;
}, []);
/**
* @param {Object} _data
* @returns {Boolean}
*/
const isDirectoryCheck = useCallback((_data) => {
if (typeof _data.webkitGetAsEntry === 'function' && _data.webkitGetAsEntry().isDirectory) {
setIsAttachmentInvalid(true);
setAttachmentInvalidReasonTitle('attachmentPicker.attachmentError');
setAttachmentInvalidReason('attachmentPicker.folderNotAllowedMessage');
return false;
}
return true;
}, []);

/**
* @param {Object} _file
* @param {Object} _data
*/
const validateAndDisplayFileToUpload = useCallback(
(_file) => {
if (!_file) {
(_data) => {
if (!isDirectoryCheck(_data)) {
return;
}
let fileObject = _data;
if (typeof _data.getAsFile === 'function') {
fileObject = _data.getAsFile();
}
if (!fileObject) {
return;
}

if (!isValidFile(_file)) {
if (!isValidFile(fileObject)) {
return;
}

if (_file instanceof File) {
if (fileObject instanceof File) {
/**
* Cleaning file name, done here so that it covers all cases:
* upload, drag and drop, copy-paste
*/
let updatedFile = _file;
let updatedFile = fileObject;
const cleanName = FileUtils.cleanFileName(updatedFile.name);
if (updatedFile.name !== cleanName) {
updatedFile = new File([updatedFile], cleanName, {type: updatedFile.type});
Expand All @@ -244,14 +261,14 @@ function AttachmentModal(props) {
setFile(updatedFile);
setModalType(inputModalType);
} else {
const inputModalType = getModalType(_file.uri, _file);
const inputModalType = getModalType(fileObject.uri, fileObject);
setIsModalOpen(true);
setSource(_file.uri);
setFile(_file);
setSource(fileObject.uri);
setFile(fileObject);
setModalType(inputModalType);
}
},
[isValidFile, getModalType],
[isValidFile, getModalType, isDirectoryCheck],
);

/**
Expand Down Expand Up @@ -311,7 +328,7 @@ function AttachmentModal(props) {
>
{props.isSmallScreenWidth && <HeaderGap />}
<HeaderWithBackButton
title={props.headerTitle || props.translate('common.attachment')}
title={props.headerTitle || translate('common.attachment')}
shouldShowBorderBottom
shouldShowDownloadButton={props.allowDownload}
onDownloadButtonPress={() => downloadAttachment(source)}
Expand Down Expand Up @@ -350,7 +367,7 @@ function AttachmentModal(props) {
success
style={[styles.buttonConfirm, props.isSmallScreenWidth ? {} : styles.attachmentButtonBigScreen]}
textStyles={[styles.buttonConfirmText]}
text={props.translate('common.send')}
text={translate('common.send')}
onPress={submitAndClose}
disabled={isConfirmButtonDisabled}
pressOnEnter
Expand All @@ -362,12 +379,12 @@ function AttachmentModal(props) {
</Modal>

<ConfirmModal
title={attachmentInvalidReasonTitle ? props.translate(attachmentInvalidReasonTitle) : ''}
title={attachmentInvalidReasonTitle ? translate(attachmentInvalidReasonTitle) : ''}
onConfirm={closeConfirmModal}
onCancel={closeConfirmModal}
isVisible={isAttachmentInvalid}
prompt={attachmentInvalidReason ? props.translate(attachmentInvalidReason) : ''}
confirmText={props.translate('common.close')}
prompt={attachmentInvalidReason ? translate(attachmentInvalidReason) : ''}
confirmText={translate('common.close')}
shouldShowCancelButton={false}
/>

Expand Down
48 changes: 19 additions & 29 deletions src/components/FormSubmit/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,12 @@ import * as formSubmitPropTypes from './formSubmitPropTypes';
import CONST from '../../CONST';
import isEnterWhileComposition from '../../libs/KeyboardShortcut/isEnterWhileComposition';

// This is a wrapper component to handle the ENTER key press, and submit the form.
class FormSubmit extends React.Component {
constructor(props) {
super(props);

this.submitForm = this.submitForm.bind(this);
}

function FormSubmit({innerRef, children, onSubmit, style}) {
/**
* Calls the submit callback when ENTER is pressed on a form element.
* @param {Object} event
*/

submitForm(event) {
const submitForm = (event) => {
// ENTER is pressed with modifier key or during text composition, do not submit the form
if (event.shiftKey || event.key !== CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey || isEnterWhileComposition(event)) {
return;
Expand All @@ -28,36 +20,34 @@ class FormSubmit extends React.Component {

// ENTER is pressed on INPUT or SELECT element, call the submit callback.
if (tagName === 'INPUT' || tagName === 'SELECT') {
this.props.onSubmit();
onSubmit();
return;
}

// Pressing Enter on TEXTAREA element adds a new line. When `dataset.submitOnEnter` prop is passed, call the submit callback.
if (tagName === 'TEXTAREA' && lodashGet(event, 'target.dataset.submitOnEnter', 'false') === 'true') {
this.props.onSubmit();
onSubmit();
return;
}

// ENTER is pressed on checkbox element, call the submit callback.
if (lodashGet(event, 'target.role') === 'checkbox') {
this.props.onSubmit();
onSubmit();
}
}

render() {
return (
// React-native-web prevents event bubbling on TextInput for key presses
// https://github.com/necolas/react-native-web/blob/fa47f80d34ee6cde2536b2a2241e326f84b633c4/packages/react-native-web/src/exports/TextInput/index.js#L272
// Thus use capture phase.
<View
ref={this.props.innerRef}
onKeyDownCapture={this.submitForm}
style={this.props.style}
>
{this.props.children}
</View>
);
}
};

return (
// React-native-web prevents event bubbling on TextInput for key presses
// https://github.com/necolas/react-native-web/blob/fa47f80d34ee6cde2536b2a2241e326f84b633c4/packages/react-native-web/src/exports/TextInput/index.js#L272
// Thus use capture phase.
<View
ref={innerRef}
onKeyDownCapture={submitForm}
style={style}
>
{children}
</View>
);
}

FormSubmit.propTypes = formSubmitPropTypes.propTypes;
Expand Down
Loading

0 comments on commit 74f8e0d

Please sign in to comment.