Skip to content

Commit

Permalink
Merge pull request #4093 from Expensify/update-staging-from-main
Browse files Browse the repository at this point in the history
  • Loading branch information
OSBotify authored Jul 15, 2021
2 parents 6eb655d + 54b1165 commit 47395d2
Show file tree
Hide file tree
Showing 36 changed files with 267 additions and 145 deletions.
24 changes: 12 additions & 12 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Contributing to Expensify.cash
Welcome! Thanks for checking out Expensify.cash and for taking the time to contribute!
# Contributing to Expensify
Welcome! Thanks for checking out the new Expensify app and for taking the time to contribute!

## Getting Started
If you would like to become an Expensify.cash contributor, the first step is to read this document in it's entirety. The second step is to review the README guidelines [here](https://github.com/Expensify/Expensify.cash/blob/main/README.md) for a general overview of the code repository (i.e. how to run the app locally, testing, storage, etc). Please read both documents before asking questions, as it may be covered within the documentation.
If you would like to become an Expensify contributor, the first step is to read this document in its entirety. The second step is to review the README guidelines [here](https://github.com/Expensify/Expensify.cash/blob/main/README.md) for a general overview of the code repository (i.e. how to run the app locally, testing, storage, etc). Please read both documents before asking questions, as it may be covered within the documentation.

#### Test Accounts
You can create as many accounts as needed in order to test your changes directly from [new.expensify.com](https://new.expensify.com/). An initial account can be created when logging in for the first time, and additional accounts can be invited by entering a valid email or phone in the "Find or start a chat" input then tapping the avatar.
You can create as many accounts as needed in order to test your changes directly from [the app](https://new.expensify.com/). An initial account can be created when logging in for the first time, and additional accounts can be invited by entering a valid email or phone in the "Find or start a chat" input then tapping the avatar.

**Note**: When testing chat functionality in Expensify Cash please do this between accounts you or your fellow contributors own - **do not test chatting with Concierge**, as this diverts to our customer support team. Thank you.
**Note**: When testing chat functionality in the app please do this between accounts you or your fellow contributors own - **do not test chatting with Concierge**, as this diverts to our customer support team. Thank you.

## Code of Conduct
This project and everyone participating in it is governed by the Expensify [Code of Conduct](https://github.com/Expensify/Expensify.cash/blob/main/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [contributors@expensify.com](mailto:contributors@expensify.com).
Expand All @@ -24,21 +24,21 @@ If you are hired for an Upwork job and have any job-specific questions, please a
If you've found a vulnerability, please email security@expensify.com with the subject `Vulnerability Report` instead of creating an issue.

## Payment for Contributions
We hire and pay external contributors via Upwork.com. If you'd like to be paid for contributing, please create an Upwork account and apply for a job in the [Upwork issue list](https://www.upwork.com/ab/jobs/search/?q=Expensify%20React%20Native&sort=recency&user_location_match=2). Payment for your contributions will be made no less than 7 days after the pull request is merged to allow for regression testing. We hire one contributor for each Upwork job. New Expensify.cash contributors are limited to working on one job at a time, however experienced contributors may work on numerous jobs simultaneously. If you have not received payment after 8 days of the PR being deployed to production, please email contributors@expensify.com referencing the GH issue and your GH handle.
We hire and pay external contributors via Upwork.com. If you'd like to be paid for contributing, please create an Upwork account and apply for a job in the [Upwork issue list](https://www.upwork.com/ab/jobs/search/?q=Expensify%20React%20Native&sort=recency&user_location_match=2). Payment for your contributions will be made no less than 7 days after the pull request is merged to allow for regression testing. We hire one contributor for each Upwork job. New contributors are limited to working on one job at a time, however experienced contributors may work on numerous jobs simultaneously. If you have not received payment after 8 days of the PR being deployed to production, please email contributors@expensify.com referencing the GH issue and your GH handle.

## Finding Expensify.cash Jobs
There are two ways you can find an Expensify.cash job that you can contribute to:
## Finding Jobs
There are two ways you can find a job that you can contribute to:

#### Finding a job that Expensify posted
This is the most common scenario for contributors. The Expensify team posts Expensify.cash jobs to the Upwork job list [here](https://www.upwork.com/ab/jobs/search/?q=Expensify%20React%20Native&sort=recency&user_location_match=2). Each job in Upwork has a corresponding GitHub issue, which will include instructions to follow.
This is the most common scenario for contributors. The Expensify team posts new jobs to the Upwork job list [here](https://www.upwork.com/ab/jobs/search/?q=Expensify%20React%20Native&sort=recency&user_location_match=2). Each job in Upwork has a corresponding GitHub issue, which will include instructions to follow.

#### Proposing a job that Expensify hasn’t posted

In this scenario, it’s possible that you found a bug or enhancement that we haven’t posted to the [Upwork job list](https://www.upwork.com/ab/jobs/search/?q=Expensify%20React%20Native&sort=recency&user_location_match=2) or [Github repository](https://github.com/Expensify/Expensify.cash/issues?q=is%3Aissue). This is an opportunity to propose a job, and (optionally) a solution. If it's a valid job proposal, we will compensate you for the solution and give an additional bonus of $150 for proactively proposing the job. In this case, please take the following steps:

1. Check to ensure an issue does not already exist in the Expensify.cash Issue list or Upwork job list. Please use your best judgement to search for similar titles and issue descriptions.
1. Check to ensure an issue does not already exist in the New Expensify Issue list or Upwork job list. Please use your best judgement to search for similar titles and issue descriptions.
2. If your bug or enhancement matches an existing issue, please feel free to comment on that GitHub issue with your findings if you think it’ll help solve a problem.
3. If there is no existing issue or Upwork job, create a new GitHub issue in the Expensify.cash repo.
3. If there is no existing issue or Upwork job, create a new GitHub issue in the Expensify/App repo.
4. Make sure to fill out all the required information fields in the issue template.
5. Add the `AutoAssignerTriage` label to your issue.
6. Before starting your PR to solve the bug or enhancement that you are proposing, please add a comment on your issue with a solution proposal.
Expand All @@ -50,7 +50,7 @@ In this scenario, it’s possible that you found a bug or enhancement that we ha
>
>**Solution:** Start up time will perceptibly decrease by 1042ms if we prevent the unnecessary re-renders of this component.
## Working on Expensify.cash Jobs
## Working on Expensify Jobs
*Reminder: For technical guidance please refer to the [README](https://github.com/Expensify/Expensify.cash/blob/main/README.md)*.

#### Express interest for the job on Upwork.com
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<div align="center">
<a href="https://new.expensify.com">
<img src="https://raw.githubusercontent.com/Expensify/Expensify.cash/main/web/favicon.png" width="64" height="64" alt="Expensify.cash Icon">
<img src="https://raw.githubusercontent.com/Expensify/Expensify.cash/main/web/favicon.png" width="64" height="64" alt="New Expensify Icon">
</a>
<h1>
<a href="https://new.expensify.com">
new.expensify.com
New Expensify
</a>
</h1>
</div>
Expand All @@ -19,14 +19,14 @@
* [Deploying](#deploying)

#### Additional Reading
* [Contributing to Expensify.cash](./CONTRIBUTING.md)
* [Contributing to Expensify](./CONTRIBUTING.md)
* [Expensify Code of Conduct](./CODE_OF_CONDUCT.md)
* [Contributor License Agreement](./CLA.md)

----

# Local development
These instructions should get you set up ready to work on Expensify.cash 🙌
These instructions should get you set up ready to work on New Expensify 🙌

## Getting Started
1. Install `node` & `npm`: `brew install node`
Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001007802
versionName "1.0.78-2"
versionCode 1001007803
versionName "1.0.78-3"
}
splits {
abi {
Expand Down
2 changes: 1 addition & 1 deletion ios/ExpensifyCash/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.0.78.2</string>
<string>1.0.78.3</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
2 changes: 1 addition & 1 deletion ios/ExpensifyCashTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0.78.2</string>
<string>1.0.78.3</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": "expensify.cash",
"version": "1.0.78-2",
"version": "1.0.78-3",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "Expensify.cash is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Expand Down
1 change: 1 addition & 0 deletions src/components/AttachmentModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class AttachmentModal extends PureComponent {
textStyles={[styles.buttonConfirmText]}
text={this.props.translate('common.send')}
onPress={this.submitAndClose}
pressOnEnter
/>
)}
</Modal>
Expand Down
124 changes: 78 additions & 46 deletions src/components/Button.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import _ from 'underscore';
import React from 'react';
import React, {Component} from 'react';
import {Pressable, ActivityIndicator} from 'react-native';
import PropTypes from 'prop-types';
import {
Pressable, ActivityIndicator,
} from 'react-native';
import styles from '../styles/styles';
import themeColors from '../styles/themes/default';
import OpacityView from './OpacityView';
import Text from './Text';
import KeyboardShortcut from '../libs/KeyboardShortcut';

const propTypes = {
/** The text for the button label */
Expand All @@ -28,6 +27,9 @@ const propTypes = {
/** A function that is called when the button is clicked on */
onPress: PropTypes.func,

/** Call the onPress function when Enter key is pressed */
pressOnEnter: PropTypes.bool,

/** Additional styles to add after local styles */
style: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.object),
Expand Down Expand Up @@ -60,6 +62,7 @@ const defaultProps = {
small: false,
large: false,
onPress: () => {},
pressOnEnter: false,
style: [],
textStyles: [],
success: false,
Expand All @@ -69,66 +72,95 @@ const defaultProps = {
shouldRemoveLeftBorderRadius: false,
};

const Button = (props) => {
const additionalStyles = _.isArray(props.style) ? props.style : [props.style];
class Button extends Component {
constructor(props) {
super(props);
this.additionalStyles = _.isArray(this.props.style) ? this.props.style : [this.props.style];

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

componentDidMount() {
if (!this.props.pressOnEnter) {
return;
}

// Setup and attach keypress handler for pressing the button with Enter key
this.unsubscribe = KeyboardShortcut.subscribe('Enter', () => {
if (!this.props.isDisabled && !this.props.isLoading) {
this.props.onPress();
}
}, [], true);
}

function renderContent() {
const {ContentComponent} = props;
componentWillUnmount() {
// Cleanup event listeners
if (!this.unsubscribe) {
return;
}
this.unsubscribe();
}

renderContent() {
const {ContentComponent} = this.props;
if (ContentComponent) {
return <ContentComponent />;
}

return props.isLoading
return this.props.isLoading
? (
<ActivityIndicator color={themeColors.textReversed} />
) : (
<Text
selectable={false}
style={[
styles.buttonText,
props.small && styles.buttonSmallText,
props.large && styles.buttonLargeText,
props.success && styles.buttonSuccessText,
props.danger && styles.buttonDangerText,
...props.textStyles,
this.props.small && styles.buttonSmallText,
this.props.large && styles.buttonLargeText,
this.props.success && styles.buttonSuccessText,
this.props.danger && styles.buttonDangerText,
...this.props.textStyles,
]}
>
{props.text}
{this.props.text}
</Text>
);
}

return (
<Pressable
onPress={props.onPress}
disabled={props.isLoading || props.isDisabled}
style={[
...additionalStyles,
]}
>
{({pressed, hovered}) => (
<OpacityView
shouldDim={pressed}
style={[
styles.button,
props.small ? styles.buttonSmall : undefined,
props.large ? styles.buttonLarge : undefined,
props.success ? styles.buttonSuccess : undefined,
props.danger ? styles.buttonDanger : undefined,
(props.isDisabled && props.danger) ? styles.buttonDangerDisabled : undefined,
(props.isDisabled && !props.danger) ? styles.buttonDisable : undefined,
(props.success && hovered) ? styles.buttonSuccessHovered : undefined,
(props.danger && hovered) ? styles.buttonDangerHovered : undefined,
props.shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
props.shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
]}
>
{renderContent()}
</OpacityView>
)}
</Pressable>
);
};
render() {
return (
<Pressable
onPress={this.props.onPress}
disabled={this.props.isLoading || this.props.isDisabled}
style={[
this.props.isDisabled ? styles.cursorDisabled : {},
...this.additionalStyles,
]}
>
{({pressed, hovered}) => (
<OpacityView
shouldDim={pressed}
style={[
styles.button,
this.props.small ? styles.buttonSmall : undefined,
this.props.large ? styles.buttonLarge : undefined,
this.props.success ? styles.buttonSuccess : undefined,
this.props.danger ? styles.buttonDanger : undefined,
(this.props.isDisabled && this.props.danger) ? styles.buttonDangerDisabled : undefined,
(this.props.isDisabled && !this.props.danger) ? styles.buttonDisable : undefined,
(this.props.success && hovered) ? styles.buttonSuccessHovered : undefined,
(this.props.danger && hovered) ? styles.buttonDangerHovered : undefined,
this.props.shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
this.props.shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
]}
>
{this.renderContent()}
</OpacityView>
)}
</Pressable>
);
}
}

Button.propTypes = propTypes;
Button.defaultProps = defaultProps;
Expand Down
1 change: 1 addition & 0 deletions src/components/ConfirmModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const ConfirmModal = props => (
danger={props.danger}
style={[styles.mt4]}
onPress={props.onConfirm}
pressOnEnter
text={props.confirmText || props.translate('common.yes')}
/>
<Button
Expand Down
1 change: 1 addition & 0 deletions src/components/IOUConfirmationList.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ class IOUConfirmationList extends Component {
isLoading={this.props.iou.loading}
text={buttonText}
onPress={() => this.props.onConfirm(this.getSplits())}
pressOnEnter
/>
</FixedFooter>
</>
Expand Down
1 change: 1 addition & 0 deletions src/components/InvertedFlatList/index.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default forwardRef((props, ref) => (
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={ref}
initialNumToRender={20}

// Remove clipped subviews helps prevent avatars and attachments from eating up excess memory on Android. When
// we run out of memory images stop appearing without any warning.
Expand Down
11 changes: 9 additions & 2 deletions src/components/InvertedFlatList/index.ios.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import React, {forwardRef} from 'react';
import BaseInvertedFlatList from './BaseInvertedFlatList';

BaseInvertedFlatList.displayName = 'InvertedFlatList';
export default BaseInvertedFlatList;
export default forwardRef((props, ref) => (
<BaseInvertedFlatList
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={ref}
initialNumToRender={20}
/>
));
1 change: 1 addition & 0 deletions src/components/InvertedFlatList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class InvertedFlatList extends React.Component {
{...this.props}
ref={el => this.list = el}
shouldMeasureItems
initialNumToRender={25}
/>
);
}
Expand Down
Loading

0 comments on commit 47395d2

Please sign in to comment.