Skip to content

Commit

Permalink
Merge branch 'Expensify:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
dharmik authored Apr 21, 2022
2 parents 0c44dd4 + f27934b commit 422672e
Show file tree
Hide file tree
Showing 47 changed files with 328 additions and 169 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cherryPick.yml
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ jobs:

- name: 'Announces a CP failure in the #announce Slack room'
uses: 8398a7/action-slack@v3
if: ${{ failure() }}
if: ${{ failure() || !fromJSON(steps.isPullRequestMergeable.outputs.IS_MERGEABLE) }}
with:
status: custom
custom_payload: |
Expand Down
4 changes: 4 additions & 0 deletions .well-known/apple-app-site-association
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
{
"/": "/partners/plaid/oauth_ios",
"comment": "Plaid setup"
},
{
"/": "/statements/*",
"comment": "Wallet statements"
}
]
}
Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001015501
versionName "1.1.55-1"
versionCode 1001015600
versionName "1.1.56-0"
}
splits {
abi {
Expand Down
2 changes: 2 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
<data android:scheme="https" android:host="new.expensify.com" android:pathPrefix="/bank-account"/>
<data android:scheme="https" android:host="new.expensify.com" android:pathPrefix="/iou"/>
<data android:scheme="https" android:host="new.expensify.com" android:pathPrefix="/enable-payments"/>
<data android:scheme="https" android:host="new.expensify.com" android:pathPrefix="/statements"/>

<!-- Staging URLs -->
<data android:scheme="https" android:host="staging.new.expensify.com" android:pathPrefix="/r"/>
Expand All @@ -78,6 +79,7 @@
<data android:scheme="https" android:host="staging.new.expensify.com" android:pathPrefix="/bank-account"/>
<data android:scheme="https" android:host="staging.new.expensify.com" android:pathPrefix="/iou"/>
<data android:scheme="https" android:host="staging.new.expensify.com" android:pathPrefix="/enable-payments"/>
<data android:scheme="https" android:host="staging.new.expensify.com" android:pathPrefix="/statements"/>
</intent-filter>
</activity>

Expand Down
4 changes: 2 additions & 2 deletions ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.1.55</string>
<string>1.1.56</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
Expand All @@ -30,7 +30,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.1.55.1</string>
<string>1.1.56.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.1.55</string>
<string>1.1.56</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.1.55.1</string>
<string>1.1.56.0</string>
</dict>
</plist>
2 changes: 1 addition & 1 deletion 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.1.55-1",
"version": "1.1.56-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
26 changes: 22 additions & 4 deletions src/CONST.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,12 +311,34 @@ const CONST = {
GSD: 'gsd',
DEFAULT: 'default',
},
JSON_CODE: {
SUCCESS: 200,
NOT_AUTHENTICATED: 407,
EXP_ERROR: 666,
},
ERROR: {
XHR_FAILED: 'xhrFailed',
API_OFFLINE: 'session.offlineMessageRetry',
UNKNOWN_ERROR: 'Unknown error',
REQUEST_CANCELLED: 'AbortError',
FAILED_TO_FETCH: 'Failed to fetch',
ENSURE_BUGBOT: 'ENSURE_BUGBOT',
NETWORK_REQUEST_FAILED: 'Network request failed',
SAFARI_DOCUMENT_LOAD_ABORTED: 'cancelled',
FIREFOX_DOCUMENT_LOAD_ABORTED: 'NetworkError when attempting to fetch resource.',
IOS_NETWORK_CONNECTION_LOST: 'The network connection was lost.',
IOS_NETWORK_CONNECTION_LOST_RUSSIAN: 'Сетевое соединение потеряно.',
IOS_NETWORK_CONNECTION_LOST_SWEDISH: 'Nätverksanslutningen förlorades.',
IOS_LOAD_FAILED: 'Load failed',
SAFARI_CANNOT_PARSE_RESPONSE: 'cannot parse response',
GATEWAY_TIMEOUT: 'Gateway Timeout',
EXPENSIFY_SERVICE_INTERRUPTED: 'Expensify service interrupted',
},
ERROR_TYPE: {
SOCKET: 'Expensify\\Auth\\Error\\Socket',
},
ERROR_TITLE: {
SOCKET: 'Issue connecting to database',
},
NETWORK: {
METHOD: {
Expand All @@ -326,10 +348,6 @@ const CONST = {
PROCESS_REQUEST_DELAY_MS: 1000,
MAX_PENDING_TIME_MS: 10 * 1000,
},
JSON_CODE: {
SUCCESS: 200,
NOT_AUTHENTICATED: 407,
},
NVP: {
IS_FIRST_TIME_NEW_EXPENSIFY_USER: 'isFirstTimeNewExpensifyUser',
BLOCKED_FROM_CONCIERGE: 'private_blockedFromConcierge',
Expand Down
37 changes: 24 additions & 13 deletions src/components/CheckboxWithLabel.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,10 @@ import * as FormUtils from '../libs/FormUtils';

const propTypes = {
/** Whether the checkbox is checked */
isChecked: PropTypes.bool.isRequired,
isChecked: PropTypes.bool,

/** Called when the checkbox or label is pressed */
onPress: PropTypes.func.isRequired,

/** Called when the checkbox or label is pressed */
onChange: PropTypes.func,
onInputChange: PropTypes.func.isRequired,

/** Container styles */
style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
Expand All @@ -33,6 +30,12 @@ const propTypes = {
/** Indicates that the input is being used with the Form component */
isFormInput: PropTypes.bool,

/** The default value for the checkbox */
defaultValue: PropTypes.bool,

/** React ref being forwarded to the Checkbox input */
forwardedRef: PropTypes.func,

/**
* The ID used to uniquely identify the input
*
Expand All @@ -46,24 +49,29 @@ const propTypes = {
};

const defaultProps = {
onChange: () => {},
isFormInput: false,
inputID: undefined,
style: [],
label: undefined,
LabelComponent: undefined,
errorText: '',
shouldSaveDraft: false,
isChecked: false,
defaultValue: false,
forwardedRef: () => {},
};

const CheckboxWithLabel = React.forwardRef((props, ref) => {
const CheckboxWithLabel = (props) => {
const LabelComponent = props.LabelComponent;
const defaultStyles = [styles.flexRow, styles.alignItemsCenter];
const wrapperStyles = _.isArray(props.style) ? [...defaultStyles, ...props.style] : [...defaultStyles, props.style];

// We keep track of the checkbox "state" in a local variable so that this component has an uncontrolled input interface
let isChecked = props.defaultValue ? props.defaultValue : props.isChecked;

function toggleCheckbox() {
props.onPress(!props.isChecked);
props.onChange(!props.isChecked);
props.onInputChange(!isChecked);
isChecked = !isChecked;
}

if (!props.label && !LabelComponent) {
Expand All @@ -73,11 +81,11 @@ const CheckboxWithLabel = React.forwardRef((props, ref) => {
<>
<View style={wrapperStyles}>
<Checkbox
isChecked={props.isChecked}
isChecked={isChecked}
onPress={toggleCheckbox}
label={props.label}
hasError={Boolean(props.errorText)}
forwardedRef={ref}
forwardedRef={props.forwardedRef}
isFormInput={props.isFormInput}
inputID={props.inputID}
shouldSaveDraft={props.shouldSaveDraft}
Expand Down Expand Up @@ -107,10 +115,13 @@ const CheckboxWithLabel = React.forwardRef((props, ref) => {
</InlineErrorText>
</>
);
});
};

CheckboxWithLabel.propTypes = propTypes;
CheckboxWithLabel.defaultProps = defaultProps;
CheckboxWithLabel.displayName = 'CheckboxWithLabel';

export default CheckboxWithLabel;
export default React.forwardRef((props, ref) => (
// eslint-disable-next-line react/jsx-props-no-spreading
<CheckboxWithLabel {...props} forwardedRef={ref} />
));
6 changes: 5 additions & 1 deletion src/components/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ class Form extends React.Component {
// We clone the child passing down all form props
const inputID = child.props.inputID;
const defaultValue = this.props.draftValues[inputID] || child.props.defaultValue;
this.inputValues[inputID] = defaultValue;

// We want to initialize the input value if it's undefined
if (_.isUndefined(this.inputValues[inputID])) {
this.inputValues[inputID] = defaultValue;
}

return React.cloneElement(child, {
ref: node => this.inputRefs[inputID] = node,
Expand Down
3 changes: 2 additions & 1 deletion src/components/FormAlertWithSubmitButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const propTypes = {
buttonText: PropTypes.string.isRequired,

/** Callback fired when the "fix the errors" link is pressed */
onFixTheErrorsLinkPressed: PropTypes.func.isRequired,
onFixTheErrorsLinkPressed: PropTypes.func,

/** Error message to display above button */
message: PropTypes.string,
Expand All @@ -49,6 +49,7 @@ const defaultProps = {
isMessageHtml: false,
containerStyles: [],
isLoading: false,
onFixTheErrorsLinkPressed: () => {},
};

const FormAlertWithSubmitButton = (props) => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/Picker/BasePicker/basePickerStyles/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import CONST from '../../../../CONST';
import getBrowser from '../../../../libs/getBrowser';
import * as Browser from '../../../../libs/Browser';
import styles from '../../../../styles/styles';

const pickerStylesWeb = () => {
if (CONST.BROWSER.FIREFOX === getBrowser()) {
if (CONST.BROWSER.FIREFOX === Browser.getBrowser()) {
return {
textIndent: -2,
};
Expand Down
4 changes: 2 additions & 2 deletions src/components/Picker/BasePicker/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class BasePicker extends React.Component {
super(props);

this.state = {
selectedValue: this.props.value || this.props.defaultValue,
selectedValue: this.props.defaultValue,
};

this.updateSelectedValueAndExecuteOnChange = this.updateSelectedValueAndExecuteOnChange.bind(this);
Expand All @@ -31,7 +31,7 @@ class BasePicker extends React.Component {
style={this.props.size === 'normal' ? basePickerStyles(this.props.disabled, hasError, this.props.focused) : styles.pickerSmall}
useNativeAndroidPickerStyle={false}
placeholder={this.props.placeholder}
value={this.state.selectedValue}
value={this.props.value || this.state.selectedValue}
Icon={() => this.props.icon(this.props.size)}
disabled={this.props.disabled}
fixAndroidTouchableBug
Expand Down
2 changes: 1 addition & 1 deletion src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ export default {
closeAccountSuccess: 'Cuenta cerrada exitosamente',
closeAccountActionRequired: 'Parece que necesitas completar algunas acciones antes de cerrar tu cuenta. Mira la guía',
closeAccountTryAgainAfter: 'e intenta nuevamente',
enterDefaultContact: 'Introduce tu método de contacto predeterminado',
enterDefaultContact: 'Tu método de contacto predeterminado',
defaultContact: 'Método de contacto predeterminado:',
okayGotIt: 'Ok, entendido',
closeAccountError: 'No se pudo cerrar tu cuenta',
Expand Down
11 changes: 11 additions & 0 deletions src/libs/Browser/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function getBrowser() {
return '';
}

function isMobile() {
return '';
}
export {
getBrowser,
isMobile,
};
18 changes: 12 additions & 6 deletions src/libs/getBrowser/index.web.js → src/libs/Browser/index.web.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,20 @@ function getBrowser() {
}

match = match[1] ? match[1] : navigator.appName;
return match;
return match ? match.toLowerCase() : CONST.BROWSER.OTHER;
}

/**
* Get the Browser name
* @returns {String}
* Whether the platform is a mobile browser.
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
*
* @returns {Boolean}
*/
export default () => {
const browser = getBrowser();
return browser ? browser.toLowerCase() : CONST.BROWSER.OTHER;
function isMobile() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Silk|Opera Mini/i.test(navigator.userAgent);
}

export {
getBrowser,
isMobile,
};
19 changes: 19 additions & 0 deletions src/libs/Errors/HttpsError.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Custom error class useful for re-throwing fetch errors with status code or valid error responses with status 200 but non 200 jsonCode
*/
export default class HttpsError extends Error {
constructor({
message,
status = '',
type = '',
title = '',
jsonCode = '',
}) {
super(message);
this.name = 'HttpsError';
this.status = status;
this.title = title;
this.type = type;
this.jsonCode = jsonCode;
}
}
18 changes: 17 additions & 1 deletion src/libs/HttpUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import _ from 'underscore';
import CONFIG from '../CONFIG';
import CONST from '../CONST';
import ONYXKEYS from '../ONYXKEYS';
import HttpsError from './Errors/HttpsError';

let shouldUseSecureStaging = false;
Onyx.connect({
Expand Down Expand Up @@ -32,10 +33,25 @@ function processHTTPRequest(url, method = 'get', body = null, canCancel = true)
})
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
throw new HttpsError({
message: response.statusText,
status: response.status,
});
}

return response.json();
})
.then((response) => {
// Auth is down or timed out while making a request
if (response.jsonCode === CONST.JSON_CODE.EXP_ERROR && response.title === CONST.ERROR_TITLE.SOCKET && response.type === CONST.ERROR_TYPE.SOCKET) {
throw new HttpsError({
message: CONST.ERROR.EXPENSIFY_SERVICE_INTERRUPTED,
type: CONST.ERROR_TYPE.SOCKET,
title: CONST.ERROR_TITLE.SOCKET,
jsonCode: CONST.JSON_CODE.EXP_ERROR,
});
}
return response;
});
}

Expand Down
Loading

0 comments on commit 422672e

Please sign in to comment.