From bf6a49f94c544a0d659c7631b7c9b8e2ed12a8bc Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Thu, 25 Feb 2021 20:49:26 -0800 Subject: [PATCH 01/45] update to use the new thumbnail --- src/libs/actions/PersonalDetails.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 20745e933a29..ff59140cd095 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -84,7 +84,7 @@ function getDisplayName(login, personalDetail) { function formatPersonalDetails(personalDetailsList) { return _.reduce(personalDetailsList, (finalObject, personalDetailsResponse, login) => { // Form the details into something that has all the data in an easy to use format. - const avatarURL = getAvatar(personalDetailsResponse, login); + const avatarURL = personalDetailsResponse.avatarThumbnail; const displayName = getDisplayName(login, personalDetailsResponse); return { ...finalObject, @@ -122,9 +122,7 @@ function fetch() { .then((data) => { const allPersonalDetails = formatPersonalDetails(data.personalDetailsList); Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, allPersonalDetails); - - const myPersonalDetails = allPersonalDetails[currentUserEmail] - || {avatarURL: getAvatar(undefined, currentUserEmail)}; + const myPersonalDetails = allPersonalDetails[currentUserEmail]; // Set my personal details so they can be easily accessed and subscribed to on their own key Onyx.merge(ONYXKEYS.MY_PERSONAL_DETAILS, myPersonalDetails); @@ -161,7 +159,7 @@ function getFromReportParticipants(reports) { if (report.participants.length > 0) { const avatars = _.map(report.participants, dmParticipant => ({ firstName: lodashGet(details, [dmParticipant, 'firstName'], ''), - avatar: lodashGet(details, [dmParticipant, 'avatar'], '') || getDefaultAvatar(dmParticipant), + avatar: lodashGet(details, [dmParticipant, 'avatarThumbnail'], ''), })) .sort((first, second) => first.firstName - second.firstName) .map(item => item.avatar); From bae67a982bb5e74399f07c389fb13ef9306e9223 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Thu, 25 Feb 2021 20:54:12 -0800 Subject: [PATCH 02/45] remove getAvatar method --- src/libs/actions/PersonalDetails.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index ff59140cd095..5323a49617ac 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -33,21 +33,6 @@ function getDefaultAvatar(login = '') { return `${CONST.CLOUDFRONT_URL}/images/avatars/avatar_${loginHashBucket}.png`; } -/** - * Returns the URL for a user's avatar and handles someone not having any avatar at all - * - * @param {Object} personalDetail - * @param {String} login - * @returns {String} - */ -function getAvatar(personalDetail, login) { - if (personalDetail && personalDetail.avatar) { - return personalDetail.avatar.replace(/&d=404$/, ''); - } - - return getDefaultAvatar(login); -} - /** * Returns the displayName for a user * From c37372ff9dc78ad3962ef33d0b7ecb6a3e41abc7 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Fri, 26 Mar 2021 01:05:39 +0530 Subject: [PATCH 03/45] new: Copy to clipboard functionality --- config/webpack/webpack.common.js | 1 + package-lock.json | 5 + package.json | 1 + src/CONST.js | 1 + src/libs/Clipboard/index.js | 52 +++++++ src/libs/Clipboard/index.native.js | 16 +++ .../home/report/ReportActionContextMenu.js | 30 +++- .../report/ReportActionContextMenuItem.js | 131 +++++++++++++----- src/pages/home/report/ReportActionItem.js | 6 +- .../getReportActionContextMenuItemStyles.js | 2 + 10 files changed, 202 insertions(+), 43 deletions(-) create mode 100644 src/libs/Clipboard/index.js create mode 100644 src/libs/Clipboard/index.native.js diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js index 6f52e4ea0a13..46c85ef524de 100644 --- a/config/webpack/webpack.common.js +++ b/config/webpack/webpack.common.js @@ -127,6 +127,7 @@ const webpackConfig = { alias: { 'react-native-config': 'react-web-config', 'react-native$': 'react-native-web', + '@react-native-community/clipboard': 'react-native-web', }, // React Native libraries may have web-specific module implementations that appear with the extension `.web.js` diff --git a/package-lock.json b/package-lock.json index 958e73b2af7d..90ab8198af1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3757,6 +3757,11 @@ "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-4.10.1.tgz", "integrity": "sha512-ael2f1onoPF3vF7YqHGWy7NnafzGu+yp88BbFbP0ydoCP2xGSUzmZVw0zakPTC040Id+JQ9WeFczujMkDy6jYQ==" }, + "@react-native-community/clipboard": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@react-native-community/clipboard/-/clipboard-1.5.1.tgz", + "integrity": "sha512-AHAmrkLEH5UtPaDiRqoULERHh3oNv7Dgs0bTC0hO5Z2GdNokAMPT5w8ci8aMcRemcwbtdHjxChgtjbeA38GBdA==" + }, "@react-native-community/eslint-config": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@react-native-community/eslint-config/-/eslint-config-2.0.0.tgz", diff --git a/package.json b/package.json index c93867846ed1..01849d3419ed 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@babel/preset-flow": "^7.12.13", "@react-native-community/async-storage": "^1.11.0", "@react-native-community/cli": "4.13.1", + "@react-native-community/clipboard": "^1.5.1", "@react-native-community/masked-view": "^0.1.10", "@react-native-community/netinfo": "^5.9.10", "@react-native-community/progress-bar-android": "^1.0.4", diff --git a/src/CONST.js b/src/CONST.js index 2888611097d3..087cf65b440c 100644 --- a/src/CONST.js +++ b/src/CONST.js @@ -9,6 +9,7 @@ const CONST = { DEFAULT: 'default', HOVERED: 'hovered', PRESSED: 'pressed', + COMPLETE: 'complete', }, CLOUDFRONT_URL, PDF_VIEWER_URL: '/pdf/web/viewer.html', diff --git a/src/libs/Clipboard/index.js b/src/libs/Clipboard/index.js new file mode 100644 index 000000000000..a97a857832fe --- /dev/null +++ b/src/libs/Clipboard/index.js @@ -0,0 +1,52 @@ +// on Web/desktop this import will be replaced with `react-native-web` so we have to import the named export; +import {Clipboard as base} from '@react-native-community/clipboard'; + + +class Clipboard extends base { + /** + * Enable copying the images on Web/Desktop + * + * @static + * @param {String} html + * @returns {Boolean} + * @memberof Clipboard + */ + static setImage(html) { + let success = false; + const body = document.body; + + if (body) { + // add the text to a hidden node + const node = document.createElement('div'); + node.contentEditable = true; + node.innerHTML = html; + node.style.opacity = '0'; + node.style.position = 'absolute'; + node.style.whiteSpace = 'pre-wrap'; + node.style.userSelect = 'auto'; + body.appendChild(node); + + // select the text + const selection = window.getSelection(); + selection.removeAllRanges(); + const range = document.createRange(); + range.selectNodeContents(node); + selection.addRange(range); + + // attempt to copy + try { + document.execCommand('copy'); + success = true; + // eslint-disable-next-line no-empty + } catch (e) {} + + // remove selection and node + selection.removeAllRanges(); + body.removeChild(node); + } + + return success; + } +} + +export default Clipboard; diff --git a/src/libs/Clipboard/index.native.js b/src/libs/Clipboard/index.native.js new file mode 100644 index 000000000000..34ee00452fc4 --- /dev/null +++ b/src/libs/Clipboard/index.native.js @@ -0,0 +1,16 @@ +import base from '@react-native-community/clipboard'; + +class Clipboard extends base { + /** + * Noop on native platforms + * + * @static + * @returns {Boolean} + * @memberof Clipboard + */ + static setImage() { + return null; + } +} + +export default Clipboard; diff --git a/src/pages/home/report/ReportActionContextMenu.js b/src/pages/home/report/ReportActionContextMenu.js index 80156f9443e3..a8a24e5e915a 100644 --- a/src/pages/home/report/ReportActionContextMenu.js +++ b/src/pages/home/report/ReportActionContextMenu.js @@ -1,11 +1,16 @@ +import _ from 'underscore'; import React from 'react'; import {View} from 'react-native'; +import Str from 'expensify-common/lib/str'; import PropTypes from 'prop-types'; +import lodashGet from 'lodash/get'; import { - Clipboard, LinkCopy, Mail, Pencil, Trashcan, + Clipboard as ClipboardIcon, LinkCopy, Mail, Pencil, Trashcan, Checkmark, } from '../../../components/Icon/Expensicons'; import getReportActionContextMenuStyles from '../../../styles/getReportActionContextMenuStyles'; import ReportActionContextMenuItem from './ReportActionContextMenuItem'; +import ReportActionPropTypes from './ReportActionPropTypes'; +import Clipboard from '../../../libs/Clipboard'; /** * A list of all the context actions in this menu. @@ -14,7 +19,20 @@ const CONTEXT_ACTIONS = [ // Copy to clipboard { text: 'Copy to Clipboard', - icon: Clipboard, + icon: ClipboardIcon, + successText: 'Copied!', + successIcon: Checkmark, + onPress: (action) => { + const lastMessage = _.last(lodashGet(action, 'message', null)); + const html = lodashGet(lastMessage, 'html', ''); + const isImage = lastMessage && /]+)\/>/gi.test(html); + if (isImage) { + Clipboard.setImage(html); + } else { + Clipboard.setString(action.message[0].text); + } + return true; + }, }, // Copy chat link @@ -47,9 +65,8 @@ const propTypes = { // eslint-disable-next-line react/no-unused-prop-types reportID: PropTypes.number.isRequired, - // The ID of the report action this context menu is attached to. - // eslint-disable-next-line react/no-unused-prop-types - reportActionID: PropTypes.number.isRequired, + // The report action this context menu is attached to. + reportAction: PropTypes.shape(ReportActionPropTypes).isRequired, // If true, this component will be a small, row-oriented menu that displays icons but not text. // If false, this component will be a larger, column-oriented menu that displays icons alongside text in each row. @@ -72,7 +89,10 @@ const ReportActionContextMenu = (props) => { Str.result(contextAction.onPress, props.reportAction)} key={contextAction.text} /> ))} diff --git a/src/pages/home/report/ReportActionContextMenuItem.js b/src/pages/home/report/ReportActionContextMenuItem.js index 6b60ce74d9f5..1702973711d1 100644 --- a/src/pages/home/report/ReportActionContextMenuItem.js +++ b/src/pages/home/report/ReportActionContextMenuItem.js @@ -1,4 +1,4 @@ -import React, {memo} from 'react'; +import React, {Component} from 'react'; import PropTypes from 'prop-types'; import {Pressable, Text} from 'react-native'; import Tooltip from '../../../components/Tooltip'; @@ -12,9 +12,15 @@ import styles from '../../../styles/styles'; * * @param {Boolean} [isHovered] * @param {Boolean} [isPressed] + * @param {Boolean} [isComplete] * @returns {String} */ -function getButtonState(isHovered = false, isPressed = false) { +function getButtonState(isHovered = false, isPressed = false, isComplete = false) { + // We force this one over other states + if (isComplete) { + return CONST.BUTTON_STATES.COMPLETE; + } + if (isPressed) { return CONST.BUTTON_STATES.PRESSED; } @@ -29,52 +35,107 @@ function getButtonState(isHovered = false, isPressed = false) { const propTypes = { icon: PropTypes.elementType.isRequired, text: PropTypes.string.isRequired, + successIcon: PropTypes.elementType, + successText: PropTypes.string, isMini: PropTypes.bool, + onPress: PropTypes.func.isRequired, }; const defaultProps = { isMini: false, + successIcon: null, + successText: '', }; -const ReportActionContextMenuItem = (props) => { - const {getButtonStyle, getIconFillColor} = getReportActionContextMenuItemStyles(props.isMini); - return ( - props.isMini - ? ( - - getButtonStyle(getButtonState(hovered, pressed))}> +class ReportActionContextMenuItem extends Component { + constructor(props) { + super(props); + this.state = { + hasRun: false, + }; + this.onPress = this.onPress.bind(this); + } + + /** + * Called on button press and mark the run + * + * @memberof ReportActionContextMenuItem + */ + onPress() { + const pressResult = this.props.onPress(); + if (!(pressResult instanceof Promise)) { + if (pressResult) { + this.setState({ + hasRun: true, + }); + } + return; + } + pressResult.then((result) => { + if (result) { + this.setState({ + hasRun: true, + }); + } + }); + } + + render() { + const {getButtonStyle, getIconFillColor} = getReportActionContextMenuItemStyles(this.props.isMini); + const icon = this.state.hasRun ? this.props.successIcon || this.props.icon : this.props.icon; + const text = this.state.hasRun ? this.props.successText || this.props.text : this.props.text; + return ( + this.props.isMini + ? ( + + getButtonStyle( + getButtonState(hovered, pressed, this.state.hasRun), + ) + } + > + {({hovered, pressed}) => ( + + )} + + + ) : ( + getButtonStyle( + getButtonState(hovered, pressed, this.state.hasRun), + ) + } + > {({hovered, pressed}) => ( - + <> + + + {text} + + )} - - ) : ( - getButtonStyle(getButtonState(hovered, pressed))}> - {({hovered, pressed}) => ( - <> - - - {props.text} - - - )} - - ) - ); -}; + ) + ); + } +} ReportActionContextMenuItem.propTypes = propTypes; ReportActionContextMenuItem.defaultProps = defaultProps; ReportActionContextMenuItem.displayName = 'ReportActionContextMenuItem'; -export default memo(ReportActionContextMenuItem); +export default ReportActionContextMenuItem; diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index a0d920a60185..ad67362eabfc 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -117,7 +117,7 @@ class ReportActionItem extends Component { )} > diff --git a/src/styles/getReportActionContextMenuItemStyles.js b/src/styles/getReportActionContextMenuItemStyles.js index c53ab29df6e6..949eb44c8c71 100644 --- a/src/styles/getReportActionContextMenuItemStyles.js +++ b/src/styles/getReportActionContextMenuItemStyles.js @@ -33,6 +33,8 @@ function getIconFillColor(buttonState = CONST.BUTTON_STATES.DEFAULT) { return themeColors.text; case CONST.BUTTON_STATES.PRESSED: return themeColors.heading; + case CONST.BUTTON_STATES.COMPLETE: + return themeColors.iconSuccessFill; case CONST.BUTTON_STATES.DEFAULT: default: return themeColors.icon; From 6aad46b6f3629f470cf877994e00c0b3b72319dc Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Thu, 25 Mar 2021 17:06:44 -0700 Subject: [PATCH 04/45] avatar changes --- src/libs/actions/PersonalDetails.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index dfc2d456e5a7..dab997942a48 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -61,6 +61,21 @@ function getDisplayName(login, personalDetail) { return (`${firstName} ${lastName}`).trim() || userLogin; } +/** + * Returns the URL for a user's avatar and handles someone not having any avatar at all + * + * @param {Object} personalDetail + * @param {String} login + * @returns {String} + */ +function getAvatar(personalDetail, login) { + if (personalDetail.avatarThumbnail) { + return personalDetail.avatarThumbnail; + } + + return getDefaultAvatar(login); +} + /** * Format personal details * @@ -70,8 +85,7 @@ function getDisplayName(login, personalDetail) { function formatPersonalDetails(personalDetailsList) { return _.reduce(personalDetailsList, (finalObject, personalDetailsResponse, login) => { // Form the details into something that has all the data in an easy to use format. - const avatarURL = personalDetailsResponse.avatarThumbnail; - //const avatar = getAvatar(personalDetailsResponse, login); + const avatar = getAvatar(personalDetailsResponse, login); const displayName = getDisplayName(login, personalDetailsResponse); const pronouns = lodashGet(personalDetailsResponse, 'pronouns', ''); const timezone = lodashGet(personalDetailsResponse, 'timeZone', CONST.DEFAULT_TIME_ZONE); From 81e0fe6d19b9e3b5b8d45d4abb9a1f6e546a885c Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Thu, 25 Mar 2021 20:15:41 -0700 Subject: [PATCH 05/45] use default --- src/libs/actions/PersonalDetails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index dab997942a48..7d1a5e806bdd 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -170,7 +170,7 @@ function getFromReportParticipants(reports) { if (report.participants.length > 0) { const avatars = _.map(report.participants, dmParticipant => ({ firstName: lodashGet(details, [dmParticipant, 'firstName'], ''), - avatar: lodashGet(details, [dmParticipant, 'avatarThumbnail'], ''), + avatar: lodashGet(details, [dmParticipant, 'avatarThumbnail'], '') || getDefaultAvatar(dmParticipant), })) .sort((first, second) => first.firstName - second.firstName) .map(item => item.avatar); From 3d4cb12a1d5f20a97b8f3efbaaa5f4d5c7cc1a98 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Thu, 25 Mar 2021 20:16:47 -0700 Subject: [PATCH 06/45] move back to original location --- src/libs/actions/PersonalDetails.js | 30 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 7d1a5e806bdd..88c777df1e41 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -34,6 +34,21 @@ function getDefaultAvatar(login = '') { return `${CONST.CLOUDFRONT_URL}/images/avatars/avatar_${loginHashBucket}.png`; } +/** + * Returns the URL for a user's avatar and handles someone not having any avatar at all + * + * @param {Object} personalDetail + * @param {String} login + * @returns {String} + */ +function getAvatar(personalDetail, login) { + if (personalDetail.avatarThumbnail) { + return personalDetail.avatarThumbnail; + } + + return getDefaultAvatar(login); +} + /** * Returns the displayName for a user * @@ -61,21 +76,6 @@ function getDisplayName(login, personalDetail) { return (`${firstName} ${lastName}`).trim() || userLogin; } -/** - * Returns the URL for a user's avatar and handles someone not having any avatar at all - * - * @param {Object} personalDetail - * @param {String} login - * @returns {String} - */ -function getAvatar(personalDetail, login) { - if (personalDetail.avatarThumbnail) { - return personalDetail.avatarThumbnail; - } - - return getDefaultAvatar(login); -} - /** * Format personal details * From d931a0875f49c6e69db5c1cb85a58b0f416a7755 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Thu, 25 Mar 2021 20:17:15 -0700 Subject: [PATCH 07/45] remove extra space --- src/libs/actions/PersonalDetails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 88c777df1e41..e83b89dc820b 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -170,7 +170,7 @@ function getFromReportParticipants(reports) { if (report.participants.length > 0) { const avatars = _.map(report.participants, dmParticipant => ({ firstName: lodashGet(details, [dmParticipant, 'firstName'], ''), - avatar: lodashGet(details, [dmParticipant, 'avatarThumbnail'], '') || getDefaultAvatar(dmParticipant), + avatar: lodashGet(details, [dmParticipant, 'avatarThumbnail'], '') || getDefaultAvatar(dmParticipant), })) .sort((first, second) => first.firstName - second.firstName) .map(item => item.avatar); From 9ee94de16737cf7d167ee7e60b60515008b677f9 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Thu, 25 Mar 2021 20:19:44 -0700 Subject: [PATCH 08/45] fix max-len --- src/libs/actions/PersonalDetails.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index e83b89dc820b..8c4f4b7e24c6 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -170,7 +170,8 @@ function getFromReportParticipants(reports) { if (report.participants.length > 0) { const avatars = _.map(report.participants, dmParticipant => ({ firstName: lodashGet(details, [dmParticipant, 'firstName'], ''), - avatar: lodashGet(details, [dmParticipant, 'avatarThumbnail'], '') || getDefaultAvatar(dmParticipant), + avatar: lodashGet(details, [dmParticipant, 'avatarThumbnail'], '') + || getDefaultAvatar(dmParticipant), })) .sort((first, second) => first.firstName - second.firstName) .map(item => item.avatar); From e31c1e73a1223b3ee09fc9310134aff105abb6ff Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Sat, 27 Mar 2021 02:14:06 +0530 Subject: [PATCH 09/45] refactor code --- src/libs/Clipboard/index.js | 51 +------------------ src/libs/Clipboard/index.native.js | 15 +----- .../home/report/ReportActionContextMenu.js | 14 +++-- .../report/ReportActionContextMenuItem.js | 33 ++++-------- src/pages/home/report/ReportActionItem.js | 2 +- 5 files changed, 24 insertions(+), 91 deletions(-) diff --git a/src/libs/Clipboard/index.js b/src/libs/Clipboard/index.js index a97a857832fe..8e93fe929adf 100644 --- a/src/libs/Clipboard/index.js +++ b/src/libs/Clipboard/index.js @@ -1,52 +1,5 @@ // on Web/desktop this import will be replaced with `react-native-web` so we have to import the named export; -import {Clipboard as base} from '@react-native-community/clipboard'; - - -class Clipboard extends base { - /** - * Enable copying the images on Web/Desktop - * - * @static - * @param {String} html - * @returns {Boolean} - * @memberof Clipboard - */ - static setImage(html) { - let success = false; - const body = document.body; - - if (body) { - // add the text to a hidden node - const node = document.createElement('div'); - node.contentEditable = true; - node.innerHTML = html; - node.style.opacity = '0'; - node.style.position = 'absolute'; - node.style.whiteSpace = 'pre-wrap'; - node.style.userSelect = 'auto'; - body.appendChild(node); - - // select the text - const selection = window.getSelection(); - selection.removeAllRanges(); - const range = document.createRange(); - range.selectNodeContents(node); - selection.addRange(range); - - // attempt to copy - try { - document.execCommand('copy'); - success = true; - // eslint-disable-next-line no-empty - } catch (e) {} - - // remove selection and node - selection.removeAllRanges(); - body.removeChild(node); - } - - return success; - } -} +// according to the `react-native-web`; +import {Clipboard} from '@react-native-community/clipboard'; export default Clipboard; diff --git a/src/libs/Clipboard/index.native.js b/src/libs/Clipboard/index.native.js index 34ee00452fc4..db249165a421 100644 --- a/src/libs/Clipboard/index.native.js +++ b/src/libs/Clipboard/index.native.js @@ -1,16 +1,3 @@ -import base from '@react-native-community/clipboard'; - -class Clipboard extends base { - /** - * Noop on native platforms - * - * @static - * @returns {Boolean} - * @memberof Clipboard - */ - static setImage() { - return null; - } -} +import Clipboard from '@react-native-community/clipboard'; export default Clipboard; diff --git a/src/pages/home/report/ReportActionContextMenu.js b/src/pages/home/report/ReportActionContextMenu.js index a8a24e5e915a..976f0c3f1599 100644 --- a/src/pages/home/report/ReportActionContextMenu.js +++ b/src/pages/home/report/ReportActionContextMenu.js @@ -1,7 +1,6 @@ import _ from 'underscore'; import React from 'react'; import {View} from 'react-native'; -import Str from 'expensify-common/lib/str'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import { @@ -22,13 +21,14 @@ const CONTEXT_ACTIONS = [ icon: ClipboardIcon, successText: 'Copied!', successIcon: Checkmark, + + // If return value is true, we switch the `text` and `icon` on + // `ReportActionContextMenuItem` with `successText` and `successIcon` onPress: (action) => { const lastMessage = _.last(lodashGet(action, 'message', null)); const html = lodashGet(lastMessage, 'html', ''); const isImage = lastMessage && /]+)\/>/gi.test(html); - if (isImage) { - Clipboard.setImage(html); - } else { + if (!isImage) { Clipboard.setString(action.message[0].text); } return true; @@ -39,24 +39,28 @@ const CONTEXT_ACTIONS = [ { text: 'Copy Link', icon: LinkCopy, + onPress: () => { }, }, // Mark as Unread { text: 'Mark as Unread', icon: Mail, + onPress: () => { }, }, // Edit Comment { text: 'Edit Comment', icon: Pencil, + onPress: () => { }, }, // Delete Comment { text: 'Delete Comment', icon: Trashcan, + onPress: () => { }, }, ]; @@ -92,7 +96,7 @@ const ReportActionContextMenu = (props) => { successIcon={contextAction.successIcon} successText={contextAction.successText} isMini={props.isMini} - onPress={() => Str.result(contextAction.onPress, props.reportAction)} + onPress={() => contextAction.onPress(props.reportAction)} key={contextAction.text} /> ))} diff --git a/src/pages/home/report/ReportActionContextMenuItem.js b/src/pages/home/report/ReportActionContextMenuItem.js index 1702973711d1..6847cea179dc 100644 --- a/src/pages/home/report/ReportActionContextMenuItem.js +++ b/src/pages/home/report/ReportActionContextMenuItem.js @@ -16,7 +16,6 @@ import styles from '../../../styles/styles'; * @returns {String} */ function getButtonState(isHovered = false, isPressed = false, isComplete = false) { - // We force this one over other states if (isComplete) { return CONST.BUTTON_STATES.COMPLETE; } @@ -51,7 +50,7 @@ class ReportActionContextMenuItem extends Component { constructor(props) { super(props); this.state = { - hasRun: false, + success: false, }; this.onPress = this.onPress.bind(this); } @@ -63,27 +62,17 @@ class ReportActionContextMenuItem extends Component { */ onPress() { const pressResult = this.props.onPress(); - if (!(pressResult instanceof Promise)) { - if (pressResult) { - this.setState({ - hasRun: true, - }); - } - return; + if (pressResult) { + this.setState({ + success: true, + }); } - pressResult.then((result) => { - if (result) { - this.setState({ - hasRun: true, - }); - } - }); } render() { const {getButtonStyle, getIconFillColor} = getReportActionContextMenuItemStyles(this.props.isMini); - const icon = this.state.hasRun ? this.props.successIcon || this.props.icon : this.props.icon; - const text = this.state.hasRun ? this.props.successText || this.props.text : this.props.text; + const icon = this.state.success ? this.props.successIcon || this.props.icon : this.props.icon; + const text = this.state.success ? this.props.successText || this.props.text : this.props.text; return ( this.props.isMini ? ( @@ -92,14 +81,14 @@ class ReportActionContextMenuItem extends Component { onPress={this.onPress} style={ ({hovered, pressed}) => getButtonStyle( - getButtonState(hovered, pressed, this.state.hasRun), + getButtonState(hovered, pressed, this.state.success), ) } > {({hovered, pressed}) => ( )} @@ -109,7 +98,7 @@ class ReportActionContextMenuItem extends Component { onPress={this.onPress} style={ ({hovered, pressed}) => getButtonStyle( - getButtonState(hovered, pressed, this.state.hasRun), + getButtonState(hovered, pressed, this.state.success), ) } > @@ -117,7 +106,7 @@ class ReportActionContextMenuItem extends Component { <> )} > From 64f7d3612b70054a46937fc9b119d32c8417057a Mon Sep 17 00:00:00 2001 From: maftalion Date: Fri, 26 Mar 2021 17:20:20 -0700 Subject: [PATCH 10/45] initial avatar setup --- src/CONST.js | 7 -- src/components/CreateMenu.js | 71 +++++--------------- src/pages/home/report/ReportActionCompose.js | 27 -------- src/pages/home/sidebar/SidebarScreen.js | 20 ------ src/pages/settings/ProfilePage.js | 48 ++++++++++++- 5 files changed, 62 insertions(+), 111 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 2888611097d3..27400900beec 100644 --- a/src/CONST.js +++ b/src/CONST.js @@ -69,13 +69,6 @@ const CONST = { ERROR: { API_OFFLINE: 'API is offline', }, - MENU_ITEM_KEYS: { - NEW_CHAT: 'NewChat', - NEW_GROUP: 'NewGroup', - REQUEST_MONEY: 'RequestMoney', - SPLIT_BILL: 'SplitBill', - ATTACHMENT_PICKER: 'AttachmentPicker', - }, NVP: { PAYPAL_ME_ADDRESS: 'expensify_payPalMeAddress', PRIORITY_MODE: 'priorityMode', diff --git a/src/components/CreateMenu.js b/src/components/CreateMenu.js index da57ef5dbf78..3e09d5e9542d 100644 --- a/src/components/CreateMenu.js +++ b/src/components/CreateMenu.js @@ -3,13 +3,8 @@ import {View} from 'react-native'; import PropTypes from 'prop-types'; import Popover from './Popover'; import styles from '../styles/styles'; -import { - ChatBubble, Users, Receipt, MoneyCircle, Paperclip, -} from './Icon/Expensicons'; -import ROUTES from '../ROUTES'; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; import CONST from '../CONST'; -import Navigation from '../libs/Navigation/Navigation'; import MenuItem from './MenuItem'; const propTypes = { @@ -23,63 +18,23 @@ const propTypes = { onItemSelected: PropTypes.func.isRequired, // Menu items to be rendered on the list - menuOptions: PropTypes.arrayOf( - PropTypes.oneOf(Object.values(CONST.MENU_ITEM_KEYS)), + menuItems: PropTypes.arrayOf( + PropTypes.shape({ + icon: PropTypes.func.isRequired, + text: PropTypes.string.isRequired, + onSelected: PropTypes.func.isRequired, + }), ).isRequired, - // Callback to fire when a AttachmentPicker item is selected - onAttachmentPickerSelected: PropTypes.func, - ...windowDimensionsPropTypes, }; - -const defaultProps = { - onAttachmentPickerSelected: () => {}, -}; - class CreateMenu extends PureComponent { constructor(props) { super(props); + this.onModalHide = () => { }; this.setOnModalHide = this.setOnModalHide.bind(this); this.resetOnModalHide = this.resetOnModalHide.bind(this); - this.onModalHide = () => {}; - - const MENU_ITEMS = { - [CONST.MENU_ITEM_KEYS.NEW_CHAT]: { - icon: ChatBubble, - text: 'New Chat', - onSelected: () => Navigation.navigate(ROUTES.NEW_CHAT), - }, - [CONST.MENU_ITEM_KEYS.NEW_GROUP]: { - icon: Users, - text: 'New Group', - onSelected: () => Navigation.navigate(ROUTES.NEW_GROUP), - }, - [CONST.MENU_ITEM_KEYS.REQUEST_MONEY]: { - icon: MoneyCircle, - text: 'Request Money', - onSelected: () => Navigation.navigate(ROUTES.NEW_CHAT), - }, - [CONST.MENU_ITEM_KEYS.SPLIT_BILL]: { - icon: Receipt, - text: 'Split Bill', - onSelected: () => Navigation.navigate(ROUTES.NEW_CHAT), - }, - [CONST.MENU_ITEM_KEYS.ATTACHMENT_PICKER]: { - icon: Paperclip, - text: 'Add Attachment', - onSelected: () => this.props.onAttachmentPickerSelected(), - }, - }; - - this.menuItemData = props.menuOptions.map(key => ({ - ...MENU_ITEMS[key], - onPress: () => { - props.onItemSelected(); - this.setOnModalHide(() => MENU_ITEMS[key].onSelected()); - }, - })); } /** @@ -109,12 +64,19 @@ class CreateMenu extends PureComponent { anchorPosition={styles.createMenuPosition} > - {this.menuItemData.map(({icon, text, onPress}) => ( + {this.props.menuItems.map(({ + icon, + text, + onSelected = () => {}, + }) => ( { + this.props.onItemSelected(); + this.setOnModalHide(onSelected); + }} /> ))} @@ -124,6 +86,5 @@ class CreateMenu extends PureComponent { } CreateMenu.propTypes = propTypes; -CreateMenu.defaultProps = defaultProps; CreateMenu.displayName = 'CreateMenu'; export default withWindowDimensions(CreateMenu); diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 87bfe26fae5a..bc1b4daa266a 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -224,33 +224,6 @@ class ReportActionCompose extends React.Component { > - this.setMenuVisibility(false)} - onAttachmentPickerSelected={() => { - setTimeout(() => { - openPicker({ - onPicked: (file) => { - displayFileInModal({file}); - }, - }); - }, 10); - }} - onItemSelected={() => this.setMenuVisibility(false)} - menuOptions={[CONST.MENU_ITEM_KEYS.ATTACHMENT_PICKER]} - - /** - * Temporarily hiding IOU Modal options while Modal is incomplete. Will - * be replaced by a beta flag once IOUConfirm is completed. - menuOptions={hasMultipleParticipants - ? [ - CONST.MENU_ITEM_KEYS.SPLIT_BILL, - CONST.MENU_ITEM_KEYS.ATTACHMENT_PICKER] - : [ - CONST.MENU_ITEM_KEYS.REQUEST_MONEY, - CONST.MENU_ITEM_KEYS.ATTACHMENT_PICKER]} - */ - /> )} diff --git a/src/pages/home/sidebar/SidebarScreen.js b/src/pages/home/sidebar/SidebarScreen.js index 3965e65c3abb..e6ed8c17e891 100644 --- a/src/pages/home/sidebar/SidebarScreen.js +++ b/src/pages/home/sidebar/SidebarScreen.js @@ -84,26 +84,6 @@ class SidebarScreen extends Component { onPress={this.toggleCreateMenu} /> - )} diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 1939a775de77..f2c7f4cda824 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -12,17 +12,19 @@ import moment from 'moment-timezone'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import Navigation from '../../libs/Navigation/Navigation'; import ScreenWrapper from '../../components/ScreenWrapper'; -import {setPersonalDetails} from '../../libs/actions/PersonalDetails'; +import { setPersonalDetails, setAvatar, getDefaultAvatar} from '../../libs/actions/PersonalDetails'; import ROUTES from '../../ROUTES'; import ONYXKEYS from '../../ONYXKEYS'; import CONST from '../../CONST'; import Avatar from '../../components/Avatar'; import styles from '../../styles/styles'; import Text from '../../components/Text'; -import {DownArrow} from '../../components/Icon/Expensicons'; +import {DownArrow, Download, Trashcan} from '../../components/Icon/Expensicons'; import Icon from '../../components/Icon'; import Checkbox from '../../components/Checkbox'; import themeColors from '../../styles/themes/default'; +import AttachmentPicker from '../../components/AttachmentPicker'; +import CreateMenu from '../../components/CreateMenu'; const propTypes = { /* Onyx Props */ @@ -93,6 +95,7 @@ class ProfilePage extends Component { selfSelectedPronouns: initialSelfSelectedPronouns, selectedTimezone: timezone.selected || CONST.DEFAULT_TIME_ZONE.selected, isAutomaticTimezone: timezone.automatic ?? CONST.DEFAULT_TIME_ZONE.automatic, + isEditPhotoMenuVisible: false, }; this.pronounDropdownValues = pronounsList.map(pronoun => ({value: pronoun, label: pronoun})); @@ -154,6 +157,47 @@ class ProfilePage extends Component { style={[styles.avatarLarge, styles.alignSelfCenter]} source={this.props.myPersonalDetails.avatar} /> + + {({openPicker}) => ( + <> + this.setState({isEditPhotoMenuVisible: true})} + > + Edit Photo + + this.setState({isEditPhotoMenuVisible: false})} + onItemSelected={() => this.setState({isEditPhotoMenuVisible: false})} + menuItems={[ + { + icon: Download, + text: 'Upload Photo', + onSelected: () => { + setTimeout(() => { + openPicker({ + onPicked: (file) => { + console.log(file) + setAvatar({file}); + }, + }); + }, 10); + }, + }, + { + icon: Trashcan, + text: 'Remove Photo', + onSelected: () => { + const uri = getDefaultAvatar(); + // setAvatar({ file }); + }, + }, + ]} + /> + + )} + Tell us about yourself, we would love to get to know you! From 6e591a3e1545bd0e56900d356d1a086dc3c3ec48 Mon Sep 17 00:00:00 2001 From: maftalion Date: Sun, 28 Mar 2021 15:54:39 -0700 Subject: [PATCH 11/45] refactor createmenu, add upload/delete avatar --- src/libs/actions/PersonalDetails.js | 16 +++++ src/pages/home/report/ReportActionCompose.js | 34 +++++++++- src/pages/home/sidebar/SidebarScreen.js | 29 +++++++++ src/pages/settings/ProfilePage.js | 67 ++++++++++++-------- 4 files changed, 117 insertions(+), 29 deletions(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 7c14f6f3fc98..36d0e26df083 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -227,6 +227,21 @@ function setAvatar(file) { }); } +/** + * Deletes the user's avatar image + * + * @param {String} [login] + */ +function deleteAvatar(login) { + const details = JSON.stringify({avatar: ''}); + API.PersonalDetails_Update({details}); + + // Set onyx value to default avatar + Onyx.merge(ONYXKEYS.MY_PERSONAL_DETAILS, { + avatar: getDefaultAvatar(login), + }); +} + // When the app reconnects from being offline, fetch all of the personal details NetworkConnection.onReconnect(fetch); @@ -237,4 +252,5 @@ export { getDefaultAvatar, setPersonalDetails, setAvatar, + deleteAvatar, }; diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index bc1b4daa266a..061b67c48880 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -9,7 +9,7 @@ import themeColors from '../../../styles/themes/default'; import TextInputFocusable from '../../../components/TextInputFocusable'; import ONYXKEYS from '../../../ONYXKEYS'; import Icon from '../../../components/Icon'; -import {Plus, Send} from '../../../components/Icon/Expensicons'; +import {Plus, Send, Paperclip} from '../../../components/Icon/Expensicons'; import AttachmentPicker from '../../../components/AttachmentPicker'; import {addAction, saveReportComment, broadcastUserIsTyping} from '../../../libs/actions/Report'; import ReportTypingIndicator from './ReportTypingIndicator'; @@ -17,7 +17,6 @@ import AttachmentModal from '../../../components/AttachmentModal'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; import compose from '../../../libs/compose'; import CreateMenu from '../../../components/CreateMenu'; -import CONST from '../../../CONST'; import Navigation from '../../../libs/Navigation/Navigation'; const propTypes = { @@ -224,6 +223,37 @@ class ReportActionCompose extends React.Component { > + this.setMenuVisibility(false)} + onItemSelected={() => this.setMenuVisibility(false)} + menuItems={[ + { + icon: Paperclip, + text: 'Upload Photo', + onSelected: () => { + setTimeout(() => { + openPicker({ + onPicked: file => displayFileInModal({file}), + }); + }, 10); + }, + }, + ]} + + /** + * Temporarily hiding IOU Modal options while Modal is incomplete. Will + * be replaced by a beta flag once IOUConfirm is completed. + menuOptions={hasMultipleParticipants + ? [ + CONST.MENU_ITEM_KEYS.SPLIT_BILL, + CONST.MENU_ITEM_KEYS.ATTACHMENT_PICKER] + : [ + CONST.MENU_ITEM_KEYS.REQUEST_MONEY, + CONST.MENU_ITEM_KEYS.ATTACHMENT_PICKER]} + */ + /> + )} diff --git a/src/pages/home/sidebar/SidebarScreen.js b/src/pages/home/sidebar/SidebarScreen.js index e6ed8c17e891..358159fbe22f 100644 --- a/src/pages/home/sidebar/SidebarScreen.js +++ b/src/pages/home/sidebar/SidebarScreen.js @@ -10,6 +10,7 @@ import ROUTES from '../../../ROUTES'; import Timing from '../../../libs/actions/Timing'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; import CONST from '../../../CONST'; +import {ChatBubble, Users} from '../../../components/Icon/Expensicons'; const propTypes = { // propTypes for withWindowDimensions @@ -84,6 +85,34 @@ class SidebarScreen extends Component { onPress={this.toggleCreateMenu} /> + Navigation.navigate(ROUTES.NEW_CHAT), + }, + { + icon: Users, + text: 'New Group', + onSelected: () => Navigation.navigate(ROUTES.NEW_GROUP), + }, + ]} + + /** + * Temporarily hiding IOU Modal options while Modal is incomplete. Will + * be replaced by a beta flag once IOUConfirm is completed. + menuOptions={[ + CONST.MENU_ITEM_KEYS.NEW_CHAT, + CONST.MENU_ITEM_KEYS.REQUEST_MONEY, + CONST.MENU_ITEM_KEYS.NEW_GROUP, + CONST.MENU_ITEM_KEYS.SPLIT_BILL, + ]} + */ + /> )} diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index f2c7f4cda824..58a706e65ab7 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -12,7 +12,7 @@ import moment from 'moment-timezone'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import Navigation from '../../libs/Navigation/Navigation'; import ScreenWrapper from '../../components/ScreenWrapper'; -import { setPersonalDetails, setAvatar, getDefaultAvatar} from '../../libs/actions/PersonalDetails'; +import { setPersonalDetails, setAvatar, deleteAvatar} from '../../libs/actions/PersonalDetails'; import ROUTES from '../../ROUTES'; import ONYXKEYS from '../../ONYXKEYS'; import CONST from '../../CONST'; @@ -101,6 +101,7 @@ class ProfilePage extends Component { this.pronounDropdownValues = pronounsList.map(pronoun => ({value: pronoun, label: pronoun})); this.updatePersonalDetails = this.updatePersonalDetails.bind(this); this.setAutomaticTimezone = this.setAutomaticTimezone.bind(this); + this.createMenuItems = this.createMenuItems.bind(this); } setAutomaticTimezone(isAutomaticTimezone) { @@ -131,6 +132,34 @@ class ProfilePage extends Component { }); } + createMenuItems(openPicker) { + const menuItems = [ + { + icon: Download, + text: 'Upload Photo', + onSelected: () => { + setTimeout(() => { + openPicker({ + onPicked: setAvatar, + }); + }, 10); + }, + }, + ]; + + // If current avatar isn't a default avatar, allow Remove Photo option + if (!this.props.myPersonalDetails.avatar.includes('/images/avatars/avatar')) { + menuItems.push({ + icon: Trashcan, + text: 'Remove Photo', + onSelected: () => { + deleteAvatar(this.props.myPersonalDetails.login); + }, + }); + } + return menuItems; + } + render() { // Determines if the pronouns/selected pronouns have changed const arePronounsUnchanged = this.props.myPersonalDetails.pronouns === this.state.pronouns @@ -161,39 +190,23 @@ class ProfilePage extends Component { {({openPicker}) => ( <> this.setState({isEditPhotoMenuVisible: true})} > - Edit Photo + + + + + Edit Photo + + + this.setState({isEditPhotoMenuVisible: false})} onItemSelected={() => this.setState({isEditPhotoMenuVisible: false})} - menuItems={[ - { - icon: Download, - text: 'Upload Photo', - onSelected: () => { - setTimeout(() => { - openPicker({ - onPicked: (file) => { - console.log(file) - setAvatar({file}); - }, - }); - }, 10); - }, - }, - { - icon: Trashcan, - text: 'Remove Photo', - onSelected: () => { - const uri = getDefaultAvatar(); - // setAvatar({ file }); - }, - }, - ]} + menuItems={this.createMenuItems(openPicker)} /> )} From 41ffe3acfc5437c8ef05f9ef3389fe7579cafa1a Mon Sep 17 00:00:00 2001 From: maftalion Date: Sun, 28 Mar 2021 15:56:23 -0700 Subject: [PATCH 12/45] lint --- src/components/CreateMenu.js | 1 - src/pages/settings/ProfilePage.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/CreateMenu.js b/src/components/CreateMenu.js index 3e09d5e9542d..5fd2d84484ea 100644 --- a/src/components/CreateMenu.js +++ b/src/components/CreateMenu.js @@ -4,7 +4,6 @@ import PropTypes from 'prop-types'; import Popover from './Popover'; import styles from '../styles/styles'; import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; -import CONST from '../CONST'; import MenuItem from './MenuItem'; const propTypes = { diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 58a706e65ab7..441d48e7d8e2 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -12,7 +12,7 @@ import moment from 'moment-timezone'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import Navigation from '../../libs/Navigation/Navigation'; import ScreenWrapper from '../../components/ScreenWrapper'; -import { setPersonalDetails, setAvatar, deleteAvatar} from '../../libs/actions/PersonalDetails'; +import {setPersonalDetails, setAvatar, deleteAvatar} from '../../libs/actions/PersonalDetails'; import ROUTES from '../../ROUTES'; import ONYXKEYS from '../../ONYXKEYS'; import CONST from '../../CONST'; From 69fa80fc8bfef9418400f1659db99682a4c2a589 Mon Sep 17 00:00:00 2001 From: maftalion Date: Mon, 29 Mar 2021 08:30:44 -0700 Subject: [PATCH 13/45] Add Upload icon --- assets/images/upload.svg | 11 +++++++++++ src/components/Icon/Expensicons.js | 2 ++ src/pages/settings/ProfilePage.js | 4 ++-- 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 assets/images/upload.svg diff --git a/assets/images/upload.svg b/assets/images/upload.svg new file mode 100644 index 000000000000..7760794acddf --- /dev/null +++ b/assets/images/upload.svg @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js index d06bd2620fb0..0c505936eb74 100644 --- a/src/components/Icon/Expensicons.js +++ b/src/components/Icon/Expensicons.js @@ -23,6 +23,7 @@ import Gear from '../../../assets/images/gear.svg'; import Wallet from '../../../assets/images/wallet.svg'; import Lock from '../../../assets/images/lock.svg'; import ArrowRight from '../../../assets/images/arrow-right.svg'; +import Upload from '../../../assets/images/upload.svg'; export { BackArrow, @@ -50,4 +51,5 @@ export { Wallet, Lock, ArrowRight, + Upload, }; diff --git a/src/pages/settings/ProfilePage.js b/src/pages/settings/ProfilePage.js index 441d48e7d8e2..dd8bd30ff643 100644 --- a/src/pages/settings/ProfilePage.js +++ b/src/pages/settings/ProfilePage.js @@ -19,7 +19,7 @@ import CONST from '../../CONST'; import Avatar from '../../components/Avatar'; import styles from '../../styles/styles'; import Text from '../../components/Text'; -import {DownArrow, Download, Trashcan} from '../../components/Icon/Expensicons'; +import {DownArrow, Upload, Trashcan} from '../../components/Icon/Expensicons'; import Icon from '../../components/Icon'; import Checkbox from '../../components/Checkbox'; import themeColors from '../../styles/themes/default'; @@ -135,7 +135,7 @@ class ProfilePage extends Component { createMenuItems(openPicker) { const menuItems = [ { - icon: Download, + icon: Upload, text: 'Upload Photo', onSelected: () => { setTimeout(() => { From ffd016efb5e1ea777b9f811a1b4c1f2862796189 Mon Sep 17 00:00:00 2001 From: maftalion Date: Mon, 29 Mar 2021 16:59:33 -0700 Subject: [PATCH 14/45] pr feedback fixes --- src/components/CreateMenu.js | 3 +-- src/libs/actions/PersonalDetails.js | 6 +++--- src/pages/home/report/ReportActionCompose.js | 1 - 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/CreateMenu.js b/src/components/CreateMenu.js index 5fd2d84484ea..0ce157eaf3a0 100644 --- a/src/components/CreateMenu.js +++ b/src/components/CreateMenu.js @@ -30,8 +30,7 @@ const propTypes = { class CreateMenu extends PureComponent { constructor(props) { super(props); - this.onModalHide = () => { }; - + this.onModalHide = () => {}; this.setOnModalHide = this.setOnModalHide.bind(this); this.resetOnModalHide = this.resetOnModalHide.bind(this); } diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 36d0e26df083..7c8fe24aabfc 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -230,11 +230,11 @@ function setAvatar(file) { /** * Deletes the user's avatar image * - * @param {String} [login] + * @param {String} login */ function deleteAvatar(login) { - const details = JSON.stringify({avatar: ''}); - API.PersonalDetails_Update({details}); + // We don't want to save default avatar on BE, just update to empty string + API.PersonalDetails_Update({details: JSON.stringify({avatar: ''})}); // Set onyx value to default avatar Onyx.merge(ONYXKEYS.MY_PERSONAL_DETAILS, { diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 061b67c48880..8289a8ea4c70 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -253,7 +253,6 @@ class ReportActionCompose extends React.Component { CONST.MENU_ITEM_KEYS.ATTACHMENT_PICKER]} */ /> - )} From 4a4481d12a60dc5dff6ab8b16cf410d8d916444a Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Tue, 30 Mar 2021 14:47:22 +0530 Subject: [PATCH 15/45] attachment check updated --- src/pages/home/report/ReportActionContextMenu.js | 12 ++++++++---- src/pages/home/report/ReportActionContextMenuItem.js | 3 +++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/pages/home/report/ReportActionContextMenu.js b/src/pages/home/report/ReportActionContextMenu.js index 976f0c3f1599..f19e0d5f55b4 100644 --- a/src/pages/home/report/ReportActionContextMenu.js +++ b/src/pages/home/report/ReportActionContextMenu.js @@ -23,13 +23,17 @@ const CONTEXT_ACTIONS = [ successIcon: Checkmark, // If return value is true, we switch the `text` and `icon` on - // `ReportActionContextMenuItem` with `successText` and `successIcon` + // `ReportActionContextMenuItem` with `successText` and `successIcon` which will fallback to + // the `text` and `icon` onPress: (action) => { const lastMessage = _.last(lodashGet(action, 'message', null)); const html = lodashGet(lastMessage, 'html', ''); - const isImage = lastMessage && /]+)\/>/gi.test(html); - if (!isImage) { - Clipboard.setString(action.message[0].text); + const text = lodashGet(lastMessage, 'text', ''); + const isAttachment = text === '[Attachment]'; + if (!isAttachment) { + Clipboard.setString(text); + } else { + Clipboard.setString(html); } return true; }, diff --git a/src/pages/home/report/ReportActionContextMenuItem.js b/src/pages/home/report/ReportActionContextMenuItem.js index 6847cea179dc..64622f0694eb 100644 --- a/src/pages/home/report/ReportActionContextMenuItem.js +++ b/src/pages/home/report/ReportActionContextMenuItem.js @@ -61,6 +61,9 @@ class ReportActionContextMenuItem extends Component { * @memberof ReportActionContextMenuItem */ onPress() { + if (this.state.success) { + return; + } const pressResult = this.props.onPress(); if (pressResult) { this.setState({ From 14c0fae093440141deea93b4d335d4861d89485a Mon Sep 17 00:00:00 2001 From: maftalion Date: Tue, 30 Mar 2021 23:52:03 -0700 Subject: [PATCH 16/45] update comment --- src/libs/actions/PersonalDetails.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 7c8fe24aabfc..eb9ee6f9a600 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -233,7 +233,8 @@ function setAvatar(file) { * @param {String} login */ function deleteAvatar(login) { - // We don't want to save default avatar on BE, just update to empty string + // We don't want to save the default avatar URL in the backend since we don't want to allow + // users the option of removing the default avatar, instead we'll save an empty string API.PersonalDetails_Update({details: JSON.stringify({avatar: ''})}); // Set onyx value to default avatar From bc24830ddca0432ae77ce2c297d82377ba99c5a1 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 31 Mar 2021 14:45:06 -1000 Subject: [PATCH 17/45] Fix maxParticipants text --- src/libs/OptionsListUtils.js | 4 ++-- src/pages/NewGroupPage.js | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 22209dbf3bdd..362167023f5a 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -410,11 +410,11 @@ function getSidebarOptions(reports, personalDetails, draftComments, activeReport * * @param {Boolean} hasSelectableOptions * @param {Boolean} hasUserToInvite - * @param {String} searchValue + * @param {String} [searchValue] * @param {Boolean} [maxParticipantsReached] * @return {String} */ -function getHeaderMessage(hasSelectableOptions, hasUserToInvite, searchValue, maxParticipantsReached = false) { +function getHeaderMessage(hasSelectableOptions, hasUserToInvite, searchValue = '', maxParticipantsReached = false) { if (maxParticipantsReached) { return CONST.MESSAGES.MAXIMUM_PARTICIPANTS_REACHED; } diff --git a/src/pages/NewGroupPage.js b/src/pages/NewGroupPage.js index 1bee4f70ba61..ff8dd7c6f06b 100644 --- a/src/pages/NewGroupPage.js +++ b/src/pages/NewGroupPage.js @@ -176,6 +176,7 @@ class NewGroupPage extends Component { const headerMessage = getHeaderMessage( this.state.personalDetails.length + this.state.recentReports.length !== 0, Boolean(this.state.userToInvite), + '', maxParticipantsReached, ); return ( From 346153c585e69644aea713a9aa23b8b25372957f Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 31 Mar 2021 14:58:59 -1000 Subject: [PATCH 18/45] fix sms domain --- src/libs/OptionsListUtils.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 362167023f5a..dacd0999757d 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -98,7 +98,9 @@ function createOption(personalDetailList, report, draftComments, activeReportID, return { text: report ? report.reportName : personalDetail.displayName, - alternateText: (showChatPreviewLine && lastMessageText) ? lastMessageText : personalDetail.login, + alternateText: (showChatPreviewLine && lastMessageText) + ? lastMessageText + : Str.removeSMSDomain(personalDetail.login), icons: report ? report.icons : [personalDetail.avatar], tooltipText, participantsList: personalDetailList, From a862c02ee042fe1f5b83ca26423406f91f1bf0dd Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 31 Mar 2021 15:31:36 -1000 Subject: [PATCH 19/45] use state.searchValue --- src/pages/NewGroupPage.js | 2 +- src/pages/SearchPage.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/NewGroupPage.js b/src/pages/NewGroupPage.js index ff8dd7c6f06b..3f7dc291be99 100644 --- a/src/pages/NewGroupPage.js +++ b/src/pages/NewGroupPage.js @@ -176,7 +176,7 @@ class NewGroupPage extends Component { const headerMessage = getHeaderMessage( this.state.personalDetails.length + this.state.recentReports.length !== 0, Boolean(this.state.userToInvite), - '', + this.state.searchValue, maxParticipantsReached, ); return ( diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js index 08be33ce2af5..d0f4b0492a46 100644 --- a/src/pages/SearchPage.js +++ b/src/pages/SearchPage.js @@ -133,6 +133,7 @@ class SearchPage extends Component { const headerMessage = getHeaderMessage( (this.state.recentReports.length + this.state.personalDetails.length) !== 0, Boolean(this.state.userToInvite), + this.state.searchValue, ); return ( From b6bae44da1814f4b8d0dd4c53cadfc4f0284fb40 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 31 Mar 2021 15:32:52 -1000 Subject: [PATCH 20/45] update optional param --- src/libs/OptionsListUtils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index dacd0999757d..977a7ed37c73 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -412,11 +412,11 @@ function getSidebarOptions(reports, personalDetails, draftComments, activeReport * * @param {Boolean} hasSelectableOptions * @param {Boolean} hasUserToInvite - * @param {String} [searchValue] + * @param {String} searchValue * @param {Boolean} [maxParticipantsReached] * @return {String} */ -function getHeaderMessage(hasSelectableOptions, hasUserToInvite, searchValue = '', maxParticipantsReached = false) { +function getHeaderMessage(hasSelectableOptions, hasUserToInvite, searchValue, maxParticipantsReached = false) { if (maxParticipantsReached) { return CONST.MESSAGES.MAXIMUM_PARTICIPANTS_REACHED; } From ca7491730dc0f9b4e9e06b9fa37712d0947f3a56 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 1 Apr 2021 11:34:29 +0800 Subject: [PATCH 21/45] Add WelcomeText component --- src/components/WelcomeText.js | 26 +++++++++++++++++++ src/pages/signin/LoginForm/LoginFormNarrow.js | 13 ++-------- src/pages/signin/LoginForm/LoginFormWide.js | 15 ++--------- 3 files changed, 30 insertions(+), 24 deletions(-) create mode 100644 src/components/WelcomeText.js diff --git a/src/components/WelcomeText.js b/src/components/WelcomeText.js new file mode 100644 index 000000000000..e41550d86c16 --- /dev/null +++ b/src/components/WelcomeText.js @@ -0,0 +1,26 @@ +import React from 'react'; +import {Text, View} from 'react-native'; +import styles from '../styles/styles'; +import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; + +const propTypes = { + ...windowDimensionsPropTypes, +}; + +const WelcomeText = props => ( + + + With Expensify.cash, chat and payments are the same thing. + + + Money talks. And now that chat and payments are in one place, it's also easy. + {' '} + Your payments get to you as fast as you can get your point across. + + +); + +WelcomeText.propTypes = propTypes; +WelcomeText.displayName = 'WelcomeText'; + +export default withWindowDimensions(WelcomeText); diff --git a/src/pages/signin/LoginForm/LoginFormNarrow.js b/src/pages/signin/LoginForm/LoginFormNarrow.js index 50b5c72341bd..61c3f8571f38 100644 --- a/src/pages/signin/LoginForm/LoginFormNarrow.js +++ b/src/pages/signin/LoginForm/LoginFormNarrow.js @@ -11,6 +11,7 @@ import ButtonWithLoader from '../../../components/ButtonWithLoader'; import {fetchAccountDetails} from '../../../libs/actions/Session'; import welcomeScreenshot from '../../../../assets/images/welcome-screenshot.png'; import ONYXKEYS from '../../../ONYXKEYS'; +import WelcomeText from '../../../components/WelcomeText'; const propTypes = { /* Onyx Props */ @@ -102,17 +103,7 @@ class LoginFormNarrow extends React.Component { source={welcomeScreenshot} /> - - - - With Expensify.cash, chat and payments are the same thing. - - - Money talks. And now that chat and payments are in one place, it's also easy. - {' '} - Your payments get to you as fast as you can get your point across. - - + ); } diff --git a/src/pages/signin/LoginForm/LoginFormWide.js b/src/pages/signin/LoginForm/LoginFormWide.js index 070c77c5c1b9..90620568e6ea 100644 --- a/src/pages/signin/LoginForm/LoginFormWide.js +++ b/src/pages/signin/LoginForm/LoginFormWide.js @@ -7,6 +7,7 @@ import {fetchAccountDetails} from '../../../libs/actions/Session'; import styles from '../../../styles/styles'; import ButtonWithLoader from '../../../components/ButtonWithLoader'; import ONYXKEYS from '../../../ONYXKEYS'; +import WelcomeText from '../../../components/WelcomeText'; const propTypes = { /* Onyx Props */ @@ -92,19 +93,7 @@ class LoginFormWide extends React.Component { )} - - - - - With Expensify.cash, chat and payments are the same thing. - - - Money talks. And now that chat and payments are in one place, it's also easy. - {' '} - Your payments get to you as fast as you can get your point across. - - - + ); } From ec68a00d0a25a79c432f239743c6b974a89f294c Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 1 Apr 2021 12:11:49 +0800 Subject: [PATCH 22/45] Remove windowDimensions from WelcomeText --- src/components/WelcomeText.js | 14 ++++---------- src/pages/signin/LoginForm/LoginFormWide.js | 4 +++- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/components/WelcomeText.js b/src/components/WelcomeText.js index e41550d86c16..ca722197521f 100644 --- a/src/components/WelcomeText.js +++ b/src/components/WelcomeText.js @@ -1,14 +1,9 @@ import React from 'react'; -import {Text, View} from 'react-native'; +import {Text} from 'react-native'; import styles from '../styles/styles'; -import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; - -const propTypes = { - ...windowDimensionsPropTypes, -}; const WelcomeText = props => ( - + <> With Expensify.cash, chat and payments are the same thing. @@ -17,10 +12,9 @@ const WelcomeText = props => ( {' '} Your payments get to you as fast as you can get your point across. - + ); -WelcomeText.propTypes = propTypes; WelcomeText.displayName = 'WelcomeText'; -export default withWindowDimensions(WelcomeText); +export default WelcomeText; diff --git a/src/pages/signin/LoginForm/LoginFormWide.js b/src/pages/signin/LoginForm/LoginFormWide.js index 90620568e6ea..90718d863d8f 100644 --- a/src/pages/signin/LoginForm/LoginFormWide.js +++ b/src/pages/signin/LoginForm/LoginFormWide.js @@ -93,7 +93,9 @@ class LoginFormWide extends React.Component { )} - + + + ); } From 1d3cd1769f44b89dd4b2833a2df43f72d8d4dff0 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 1 Apr 2021 12:14:10 +0800 Subject: [PATCH 23/45] Remove windowDimensions from WelcomeText --- src/components/WelcomeText.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/WelcomeText.js b/src/components/WelcomeText.js index ca722197521f..c0fffaa77a56 100644 --- a/src/components/WelcomeText.js +++ b/src/components/WelcomeText.js @@ -1,13 +1,22 @@ import React from 'react'; import {Text} from 'react-native'; +import PropTypes from 'prop-types'; import styles from '../styles/styles'; +const propTypes = { + isSmallText: PropTypes.bool, +}; + +const defaultProps = { + isSmallText: false, +}; + const WelcomeText = props => ( <> - + With Expensify.cash, chat and payments are the same thing. - + Money talks. And now that chat and payments are in one place, it's also easy. {' '} Your payments get to you as fast as you can get your point across. @@ -16,5 +25,7 @@ const WelcomeText = props => ( ); WelcomeText.displayName = 'WelcomeText'; +WelcomeText.propTypes = propTypes; +WelcomeText.defaultProps = defaultProps; export default WelcomeText; From 0d836781d126212abbc25746d303907a3ec02f72 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 1 Apr 2021 12:14:43 +0800 Subject: [PATCH 24/45] Use isSmallText --- src/pages/signin/LoginForm/LoginFormNarrow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/signin/LoginForm/LoginFormNarrow.js b/src/pages/signin/LoginForm/LoginFormNarrow.js index 61c3f8571f38..f135e6987175 100644 --- a/src/pages/signin/LoginForm/LoginFormNarrow.js +++ b/src/pages/signin/LoginForm/LoginFormNarrow.js @@ -103,7 +103,7 @@ class LoginFormNarrow extends React.Component { source={welcomeScreenshot} /> - + ); } From be72ad6c8536e19562b4b064b02723aa06e5e247 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 1 Apr 2021 13:15:56 +0800 Subject: [PATCH 25/45] Change to use convention --- src/components/WelcomeText.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/WelcomeText.js b/src/components/WelcomeText.js index c0fffaa77a56..2ccee7b079b5 100644 --- a/src/components/WelcomeText.js +++ b/src/components/WelcomeText.js @@ -4,19 +4,21 @@ import PropTypes from 'prop-types'; import styles from '../styles/styles'; const propTypes = { - isSmallText: PropTypes.bool, + + // Fontsize + textSize: PropTypes.oneOf(['default', 'large']), }; const defaultProps = { - isSmallText: false, + textSize: 'default', }; const WelcomeText = props => ( <> - + With Expensify.cash, chat and payments are the same thing. - + Money talks. And now that chat and payments are in one place, it's also easy. {' '} Your payments get to you as fast as you can get your point across. From 6b6bbb3fe0ae5ebc2e20e2a32ade278bcc119511 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 31 Mar 2021 23:29:12 -0700 Subject: [PATCH 26/45] Setup yaml validation script --- .../scripts/validateActionsAndWorkflows.sh | 16 ++++ package-lock.json | 87 +++++++++++++++++++ package.json | 2 + 3 files changed, 105 insertions(+) create mode 100755 .github/scripts/validateActionsAndWorkflows.sh diff --git a/.github/scripts/validateActionsAndWorkflows.sh b/.github/scripts/validateActionsAndWorkflows.sh new file mode 100755 index 000000000000..c77f6cd64fbe --- /dev/null +++ b/.github/scripts/validateActionsAndWorkflows.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# +# 1) Lints the yaml style +# 2) Validates the Github Actions and workflows using the json schemas provided by https://www.schemastore.org/json/ + +# Download the up-to-date json schemas for github actions and workflows +cd ./.github && mkdir ./tempSchemas || exit 1; +curl https://json.schemastore.org/github-action.json --output ./tempSchemas/github-action.json --silent +curl https://json.schemastore.org/github-workflow.json --output ./tempSchemas/github-workflow.json --silent + +# Validate the actions and workflows using the JSON schemas and ajv https://github.com/ajv-validator/ajv-cli +find ./actions/ -type f -name "*.yml" -print0 | xargs -I file ajv -s ./tempSchemas/github-action.json -d file --strict=false +find ./workflows/ -type f -name "*.yml" -print0 | xargs -I file ajv -s ./tempSchemas/github-workflow.json -d file --strict=false + +# Cleanup after ourselves and delete the schemas +rm -rf ./tempSchemas diff --git a/package-lock.json b/package-lock.json index 7f12bd92e1f0..a3225cdcd93d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5044,6 +5044,41 @@ "uri-js": "^4.2.2" } }, + "ajv-cli": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ajv-cli/-/ajv-cli-5.0.0.tgz", + "integrity": "sha512-LY4m6dUv44HTyhV+u2z5uX4EhPYTM38Iv1jdgDJJJCyOOuqB8KtZEGjPZ2T+sh5ZIJrXUfgErYx/j3gLd3+PlQ==", + "dev": true, + "requires": { + "ajv": "^8.0.0", + "fast-json-patch": "^2.0.0", + "glob": "^7.1.0", + "js-yaml": "^3.14.0", + "json-schema-migrate": "^2.0.0", + "json5": "^2.1.3", + "minimist": "^1.2.0" + }, + "dependencies": { + "ajv": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.0.2.tgz", + "integrity": "sha512-V0HGxJd0PiDF0ecHYIesTOqfd1gJguwQUOYfMfAWnRsWQEXfc5ifbUFhD3Wjc+O+y7VAqL+g07prq9gHQ/JOZQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, "ajv-errors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", @@ -11418,6 +11453,23 @@ } } }, + "fast-json-patch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.2.1.tgz", + "integrity": "sha512-4j5uBaTnsYAV5ebkidvxiLUYOwjQ+JSFljeqfTxCrH9bDmlCQaOJFS84oDJ2rAXZq2yskmk3ORfoP9DCwqFNig==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1" + }, + "dependencies": { + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + } + } + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -16808,6 +16860,35 @@ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, + "json-schema-migrate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/json-schema-migrate/-/json-schema-migrate-2.0.0.tgz", + "integrity": "sha512-r38SVTtojDRp4eD6WsCqiE0eNDt4v1WalBXb9cyZYw9ai5cGtBwzRNWjHzJl38w6TxFkXAIA7h+fyX3tnrAFhQ==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.0.2.tgz", + "integrity": "sha512-V0HGxJd0PiDF0ecHYIesTOqfd1gJguwQUOYfMfAWnRsWQEXfc5ifbUFhD3Wjc+O+y7VAqL+g07prq9gHQ/JOZQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -22094,6 +22175,12 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", diff --git a/package.json b/package.json index e798a62f8e2f..a0eeb5ce8a1b 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "detox-build": "detox build --configuration ios.sim.debug", "detox-test": "detox test --configuration ios.sim.debug", "gh-actions-build": "./.github/scripts/buildActions.sh", + "gh-actions-lint": "./.github/scripts/validateActionsAndWorkflows.sh", "analyze-packages": "ANALYZE_BUNDLE=true webpack --config config/webpack/webpack.prod.js" }, "dependencies": { @@ -99,6 +100,7 @@ "@testing-library/jest-native": "^3.4.2", "@testing-library/react-native": "^7.0.2", "@vercel/ncc": "^0.27.0", + "ajv-cli": "^5.0.0", "babel-eslint": "^10.1.0", "babel-jest": "^26.2.2", "babel-loader": "^8.1.0", From ee8b1f7323c5758b1a336b6d2faf9d5731b11f84 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 31 Mar 2021 23:48:36 -0700 Subject: [PATCH 27/45] Fix exit code propagation --- .github/scripts/validateActionsAndWorkflows.sh | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/scripts/validateActionsAndWorkflows.sh b/.github/scripts/validateActionsAndWorkflows.sh index c77f6cd64fbe..724c5bdd9bb5 100755 --- a/.github/scripts/validateActionsAndWorkflows.sh +++ b/.github/scripts/validateActionsAndWorkflows.sh @@ -3,14 +3,21 @@ # 1) Lints the yaml style # 2) Validates the Github Actions and workflows using the json schemas provided by https://www.schemastore.org/json/ +# Track exit codes so we can run a full lint, report errors, and exit with the correct code +declare EXIT_CODE=0 + # Download the up-to-date json schemas for github actions and workflows -cd ./.github && mkdir ./tempSchemas || exit 1; +cd ./.github && mkdir ./tempSchemas || exit 1 curl https://json.schemastore.org/github-action.json --output ./tempSchemas/github-action.json --silent curl https://json.schemastore.org/github-workflow.json --output ./tempSchemas/github-workflow.json --silent # Validate the actions and workflows using the JSON schemas and ajv https://github.com/ajv-validator/ajv-cli -find ./actions/ -type f -name "*.yml" -print0 | xargs -I file ajv -s ./tempSchemas/github-action.json -d file --strict=false -find ./workflows/ -type f -name "*.yml" -print0 | xargs -I file ajv -s ./tempSchemas/github-workflow.json -d file --strict=false +find ./actions/ -type f -name "*.yml" -print0 | xargs -0 -I file ajv -s ./tempSchemas/github-action.json -d file --strict=false || EXIT_CODE=1 +find ./workflows/ -type f -name "*.yml" -print0 | xargs -0 -I file ajv -s ./tempSchemas/github-workflow.json -d file --strict=false || EXIT_CODE=1 + +echo $EXIT_CODE # Cleanup after ourselves and delete the schemas rm -rf ./tempSchemas + +exit $EXIT_CODE From c4809e2d5cd3a91419322c30109640c3079d4e89 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 31 Mar 2021 23:49:30 -0700 Subject: [PATCH 28/45] Remove unnecessary echo --- .github/scripts/validateActionsAndWorkflows.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/scripts/validateActionsAndWorkflows.sh b/.github/scripts/validateActionsAndWorkflows.sh index 724c5bdd9bb5..2b51b73d7109 100755 --- a/.github/scripts/validateActionsAndWorkflows.sh +++ b/.github/scripts/validateActionsAndWorkflows.sh @@ -15,8 +15,6 @@ curl https://json.schemastore.org/github-workflow.json --output ./tempSchemas/gi find ./actions/ -type f -name "*.yml" -print0 | xargs -0 -I file ajv -s ./tempSchemas/github-action.json -d file --strict=false || EXIT_CODE=1 find ./workflows/ -type f -name "*.yml" -print0 | xargs -0 -I file ajv -s ./tempSchemas/github-workflow.json -d file --strict=false || EXIT_CODE=1 -echo $EXIT_CODE - # Cleanup after ourselves and delete the schemas rm -rf ./tempSchemas From 0a860023058fe2188dbc1df56213929a226c2e08 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Wed, 31 Mar 2021 23:59:43 -0700 Subject: [PATCH 29/45] Add github actions validation to Github Actions workflow (how meta) --- ...fyGithubActionBuilds.yml => validateGithubActions.yml} | 8 ++++++-- package.json | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) rename .github/workflows/{verifyGithubActionBuilds.yml => validateGithubActions.yml} (77%) diff --git a/.github/workflows/verifyGithubActionBuilds.yml b/.github/workflows/validateGithubActions.yml similarity index 77% rename from .github/workflows/verifyGithubActionBuilds.yml rename to .github/workflows/validateGithubActions.yml index 21fa3213259b..e6c8e0d04186 100644 --- a/.github/workflows/verifyGithubActionBuilds.yml +++ b/.github/workflows/validateGithubActions.yml @@ -1,4 +1,4 @@ -name: Verify Github Action Builds +name: Validate Github Actions on: pull_request: @@ -25,4 +25,8 @@ jobs: # Rebuild all the actions on this branch and check for a diff. Fail if there is one, # because that would be a sign that the PR author did not rebuild the Github Actions - - run: ./.github/scripts/verifyActions.sh + - name: Verify Javascript Action Builds + run: ./.github/scripts/verifyActions.sh + + - name: Validate actions and workflows + run: npm run gh-actions-validate diff --git a/package.json b/package.json index a0eeb5ce8a1b..e5683c871cf9 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "detox-build": "detox build --configuration ios.sim.debug", "detox-test": "detox test --configuration ios.sim.debug", "gh-actions-build": "./.github/scripts/buildActions.sh", - "gh-actions-lint": "./.github/scripts/validateActionsAndWorkflows.sh", + "gh-actions-validate": "./.github/scripts/validateActionsAndWorkflows.sh", "analyze-packages": "ANALYZE_BUNDLE=true webpack --config config/webpack/webpack.prod.js" }, "dependencies": { From c2895982ec799977a233f0cd84925e3246f46710 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Thu, 1 Apr 2021 00:04:17 -0700 Subject: [PATCH 30/45] Improve comment and add more early exits --- .github/scripts/validateActionsAndWorkflows.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/scripts/validateActionsAndWorkflows.sh b/.github/scripts/validateActionsAndWorkflows.sh index 2b51b73d7109..0ff92289b524 100755 --- a/.github/scripts/validateActionsAndWorkflows.sh +++ b/.github/scripts/validateActionsAndWorkflows.sh @@ -1,15 +1,14 @@ #!/bin/bash # -# 1) Lints the yaml style -# 2) Validates the Github Actions and workflows using the json schemas provided by https://www.schemastore.org/json/ +# Validates the Github Actions and workflows using the json schemas provided by https://www.schemastore.org/json/ -# Track exit codes so we can run a full lint, report errors, and exit with the correct code +# Track exit codes separately so we can run a full validation, report errors, and exit with the correct code declare EXIT_CODE=0 # Download the up-to-date json schemas for github actions and workflows cd ./.github && mkdir ./tempSchemas || exit 1 -curl https://json.schemastore.org/github-action.json --output ./tempSchemas/github-action.json --silent -curl https://json.schemastore.org/github-workflow.json --output ./tempSchemas/github-workflow.json --silent +curl https://json.schemastore.org/github-action.json --output ./tempSchemas/github-action.json --silent || exit 1 +curl https://json.schemastore.org/github-workflow.json --output ./tempSchemas/github-workflow.json --silent || exit 1 # Validate the actions and workflows using the JSON schemas and ajv https://github.com/ajv-validator/ajv-cli find ./actions/ -type f -name "*.yml" -print0 | xargs -0 -I file ajv -s ./tempSchemas/github-action.json -d file --strict=false || EXIT_CODE=1 From 1f64bb78482e5ed0548dffc3be0abfecc141b1fe Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Thu, 1 Apr 2021 10:20:46 -0700 Subject: [PATCH 31/45] add back check for personalDetail --- src/libs/actions/PersonalDetails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 8c4f4b7e24c6..0847e21cfb68 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -42,7 +42,7 @@ function getDefaultAvatar(login = '') { * @returns {String} */ function getAvatar(personalDetail, login) { - if (personalDetail.avatarThumbnail) { + if (personalDetail && personalDetail.avatarThumbnail) { return personalDetail.avatarThumbnail; } From eec30b71a224446e0c0018bf5e54d2586bec7f40 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Thu, 1 Apr 2021 08:20:10 -1000 Subject: [PATCH 32/45] Fix up dynamic background helpers --- src/components/MenuItem.js | 3 +-- src/pages/home/sidebar/OptionRow.js | 11 +++++----- src/styles/styles.js | 32 +++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js index ef6c0817b4b3..4fadcea2b606 100644 --- a/src/components/MenuItem.js +++ b/src/components/MenuItem.js @@ -5,7 +5,6 @@ import { import PropTypes from 'prop-types'; import styles from '../styles/styles'; -import themeColors from '../styles/themes/default'; import Icon from './Icon'; import {ArrowRight} from './Icon/Expensicons'; @@ -43,7 +42,7 @@ const MenuItem = ({ onPress={onPress} style={({hovered}) => ([ styles.createMenuItem, - hovered && {backgroundColor: themeColors.buttonHoveredBG}, + hovered && styles.hoveredButton, wrapperStyle, ])} > diff --git a/src/pages/home/sidebar/OptionRow.js b/src/pages/home/sidebar/OptionRow.js index c7d10c705714..185cd733bedf 100644 --- a/src/pages/home/sidebar/OptionRow.js +++ b/src/pages/home/sidebar/OptionRow.js @@ -7,7 +7,7 @@ import { View, StyleSheet, } from 'react-native'; -import styles, {getSecondAvatarStyle} from '../../../styles/styles'; +import styles, {getBackgroundAndBorder, getBackgroundColor} from '../../../styles/styles'; import {optionPropTypes} from './optionPropTypes'; import Icon from '../../../components/Icon'; import {Pencil, PinCircle, Checkmark} from '../../../components/Icon/Expensicons'; @@ -121,7 +121,7 @@ const OptionRow = ({ styles.justifyContentBetween, styles.sidebarLink, styles.sidebarLinkInner, - {backgroundColor}, + getBackgroundColor(backgroundColor), optionIsFocused ? styles.sidebarLinkActive : null, hovered && !optionIsFocused ? hoverStyle : null, ]} @@ -140,9 +140,10 @@ const OptionRow = ({ avatarImageURLs={option.icons} size={mode === 'compact' ? 'small' : 'default'} secondAvatarStyle={[ - getSecondAvatarStyle(backgroundColor), - optionIsFocused && getSecondAvatarStyle(focusedBackgroundColor), - hovered && !optionIsFocused && getSecondAvatarStyle(hoveredBackgroundColor), + getBackgroundAndBorder(backgroundColor), + optionIsFocused && getBackgroundAndBorder(focusedBackgroundColor), + hovered && !optionIsFocused + && getBackgroundAndBorder(hoveredBackgroundColor), ]} /> ) diff --git a/src/styles/styles.js b/src/styles/styles.js index 2ba713405aba..49e9e0bac154 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -788,6 +788,10 @@ const styles = { justifyContent: 'center', }, + hoveredButton: { + backgroundColor: themeColors.buttonHoveredBG, + }, + chatItemAttachButton: { alignItems: 'center', alignSelf: 'flex-end', @@ -1410,12 +1414,31 @@ function getZoomSizingStyle(isZoomed) { }; } -function getSecondAvatarStyle(parentBGColor) { +/** + * Returns a style with backgroundColor and borderColor set to the same color + * + * @param {String} backgroundColor + * @returns {Object} + */ +function getBackgroundAndBorder(backgroundColor) { return { - backgroundColor: parentBGColor, - borderColor: parentBGColor, + backgroundColor, + borderColor: backgroundColor, }; } + +/** + * Returns a style with the specified backgroundColor + * + * @param {String} backgroundColor + * @returns {Object} + */ +function getBackgroundColor(backgroundColor) { + return { + backgroundColor, + }; +} + export default styles; export { getSafeAreaPadding, @@ -1426,5 +1449,6 @@ export { getNavigationModalCardStyle, getZoomCursorStyle, getZoomSizingStyle, - getSecondAvatarStyle, + getBackgroundAndBorder, + getBackgroundColor, }; From 6a860189927eb7ce4410a14fb195cb038d0417f6 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Thu, 1 Apr 2021 08:57:52 -1000 Subject: [PATCH 33/45] Remove all inline styles --- src/components/FAB.js | 4 +- src/components/HeaderGap/index.desktop.js | 3 +- src/components/ImageView/index.native.js | 7 +- src/components/ImageWithSizeCalculation.js | 11 ++-- src/components/Modal/BaseModal.js | 18 ++++-- src/components/PDFView/index.native.js | 7 +- src/components/ScreenWrapper.js | 6 +- src/components/ThumbnailImage.js | 7 +- src/components/UnreadActionIndicator.js | 4 +- src/pages/home/sidebar/OptionRow.js | 10 +-- src/pages/iou/steps/IOUAmountPage.js | 2 +- src/styles/styles.js | 74 ++++++++++++++++++++-- 12 files changed, 108 insertions(+), 45 deletions(-) diff --git a/src/components/FAB.js b/src/components/FAB.js index 585641dbea69..6986c1144500 100644 --- a/src/components/FAB.js +++ b/src/components/FAB.js @@ -5,7 +5,7 @@ import { import PropTypes from 'prop-types'; import Icon from './Icon'; import {Plus} from './Icon/Expensicons'; -import styles from '../styles/styles'; +import styles, {getAnimatedFABStyle} from '../styles/styles'; import themeColors from '../styles/themes/default'; const AnimatedIcon = Animated.createAnimatedComponent(Icon); @@ -71,7 +71,7 @@ class FAB extends PureComponent { onPress={this.props.onPress} style={[ styles.floatingActionButton, - {transform: [{rotate}], backgroundColor}, + getAnimatedFABStyle(rotate, backgroundColor), ]} > diff --git a/src/components/HeaderGap/index.desktop.js b/src/components/HeaderGap/index.desktop.js index 16eeb157b6d5..12d9c773954a 100644 --- a/src/components/HeaderGap/index.desktop.js +++ b/src/components/HeaderGap/index.desktop.js @@ -1,8 +1,9 @@ import React, {PureComponent} from 'react'; import {View} from 'react-native'; +import styles from '../../styles/styles'; export default class HeaderGap extends PureComponent { render() { - return (); + return (); } } diff --git a/src/components/ImageView/index.native.js b/src/components/ImageView/index.native.js index b0610f8b5d28..78dd87b7ccdf 100644 --- a/src/components/ImageView/index.native.js +++ b/src/components/ImageView/index.native.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {View} from 'react-native'; import ImageZoom from 'react-native-image-pan-zoom'; import ImageWithSizeCalculation from '../ImageWithSizeCalculation'; -import styles from '../../styles/styles'; +import styles, {getWidthAndHeightStyle} from '../../styles/styles'; import variables from '../../styles/variables'; import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; @@ -47,10 +47,7 @@ class ImageView extends PureComponent { imageHeight={this.state.imageHeight} > { let imageWidth = width; diff --git a/src/components/ImageWithSizeCalculation.js b/src/components/ImageWithSizeCalculation.js index b874b55d0366..666ebbbef79f 100644 --- a/src/components/ImageWithSizeCalculation.js +++ b/src/components/ImageWithSizeCalculation.js @@ -1,6 +1,7 @@ import React, {PureComponent} from 'react'; import {Image} from 'react-native'; import PropTypes from 'prop-types'; +import styles from '../styles/styles'; const propTypes = { // Url for image to display @@ -69,11 +70,11 @@ class ImageWithSizeCalculation extends PureComponent { render() { return ( diff --git a/src/components/Modal/BaseModal.js b/src/components/Modal/BaseModal.js index e90b6b402741..1c9cd4acd557 100644 --- a/src/components/Modal/BaseModal.js +++ b/src/components/Modal/BaseModal.js @@ -4,7 +4,7 @@ import ReactNativeModal from 'react-native-modal'; import {SafeAreaInsetsContext} from 'react-native-safe-area-context'; import KeyboardShortcut from '../../libs/KeyboardShortcut'; -import styles, {getSafeAreaPadding} from '../../styles/styles'; +import styles, {getModalPaddingStyles, getSafeAreaPadding} from '../../styles/styles'; import themeColors from '../../styles/themes/default'; import {propTypes, defaultProps} from './ModalPropTypes'; import getModalStyles from '../../styles/getModalStyles'; @@ -102,17 +102,21 @@ class BaseModal extends PureComponent { paddingBottom: safeAreaPaddingBottom, } = getSafeAreaPadding(insets); + const modalPaddingStyles = getModalPaddingStyles({ + safeAreaPaddingTop, + safeAreaPaddingBottom, + shouldAddBottomSafeAreaPadding, + shouldAddTopSafeAreaPadding, + modalContainerStylePaddingTop: modalContainerStyle.paddingTop, + modalContainerStylePaddingBottom: modalContainerStyle.paddingBottom, + }); + return ( {this.props.children} diff --git a/src/components/PDFView/index.native.js b/src/components/PDFView/index.native.js index 682cc3d72025..1bb056446d9a 100644 --- a/src/components/PDFView/index.native.js +++ b/src/components/PDFView/index.native.js @@ -2,7 +2,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {View} from 'react-native'; import PDF from 'react-native-pdf'; -import styles from '../../styles/styles'; +import styles, {getWidthAndHeightStyle} from '../../styles/styles'; import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions'; const propTypes = { @@ -34,10 +34,7 @@ const PDFView = props => ( source={{uri: props.sourceURL}} style={[ styles.imageModalPDF, - { - width: props.windowWidth, - height: props.windowHeight, - }, + getWidthAndHeightStyle(props.windowWidth, props.windowHeight), ]} /> diff --git a/src/components/ScreenWrapper.js b/src/components/ScreenWrapper.js index ba732010220c..b1ea723537df 100644 --- a/src/components/ScreenWrapper.js +++ b/src/components/ScreenWrapper.js @@ -44,11 +44,11 @@ const ScreenWrapper = props => ( } return ( - {// If props.children is a function, call it to provide the insets to the children. diff --git a/src/components/ThumbnailImage.js b/src/components/ThumbnailImage.js index 142fe540d8b6..3ccd5f630f63 100644 --- a/src/components/ThumbnailImage.js +++ b/src/components/ThumbnailImage.js @@ -5,7 +5,7 @@ import {withOnyx} from 'react-native-onyx'; import ONYXKEYS from '../ONYXKEYS'; import ImageWithSizeCalculation from './ImageWithSizeCalculation'; import addAuthTokenToURL from '../libs/addAuthTokenToURL'; -import styles from '../styles/styles'; +import styles, {getWidthAndHeightStyle} from '../styles/styles'; const propTypes = { // Source URL for the preview image @@ -59,10 +59,7 @@ class ThumbnailImage extends PureComponent { return ( ( diff --git a/src/pages/home/sidebar/OptionRow.js b/src/pages/home/sidebar/OptionRow.js index 185cd733bedf..fe4b13b4875b 100644 --- a/src/pages/home/sidebar/OptionRow.js +++ b/src/pages/home/sidebar/OptionRow.js @@ -7,7 +7,7 @@ import { View, StyleSheet, } from 'react-native'; -import styles, {getBackgroundAndBorder, getBackgroundColor} from '../../../styles/styles'; +import styles, {getBackgroundAndBorderStyle, getBackgroundColorStyle} from '../../../styles/styles'; import {optionPropTypes} from './optionPropTypes'; import Icon from '../../../components/Icon'; import {Pencil, PinCircle, Checkmark} from '../../../components/Icon/Expensicons'; @@ -121,7 +121,7 @@ const OptionRow = ({ styles.justifyContentBetween, styles.sidebarLink, styles.sidebarLinkInner, - getBackgroundColor(backgroundColor), + getBackgroundColorStyle(backgroundColor), optionIsFocused ? styles.sidebarLinkActive : null, hovered && !optionIsFocused ? hoverStyle : null, ]} @@ -140,10 +140,10 @@ const OptionRow = ({ avatarImageURLs={option.icons} size={mode === 'compact' ? 'small' : 'default'} secondAvatarStyle={[ - getBackgroundAndBorder(backgroundColor), - optionIsFocused && getBackgroundAndBorder(focusedBackgroundColor), + getBackgroundAndBorderStyle(backgroundColor), + optionIsFocused && getBackgroundAndBorderStyle(focusedBackgroundColor), hovered && !optionIsFocused - && getBackgroundAndBorder(hoveredBackgroundColor), + && getBackgroundAndBorderStyle(hoveredBackgroundColor), ]} /> ) diff --git a/src/pages/iou/steps/IOUAmountPage.js b/src/pages/iou/steps/IOUAmountPage.js index 4d0c2e99d67e..8d32220eced4 100644 --- a/src/pages/iou/steps/IOUAmountPage.js +++ b/src/pages/iou/steps/IOUAmountPage.js @@ -96,7 +96,7 @@ class IOUAmountPage extends React.Component { textAlign="left" /> this.setState({textInputWidth: e.nativeEvent.layout.width})} > {this.props.amount} diff --git a/src/styles/styles.js b/src/styles/styles.js index 49e9e0bac154..22b13cd5e8db 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -252,6 +252,14 @@ const styles = { fontWeight: fontWeightBold, }, + headerGap: { + height: 12, + }, + + pushTextRight: { + left: 100000, + }, + reportOptions: { marginLeft: 8, }, @@ -1420,7 +1428,7 @@ function getZoomSizingStyle(isZoomed) { * @param {String} backgroundColor * @returns {Object} */ -function getBackgroundAndBorder(backgroundColor) { +function getBackgroundAndBorderStyle(backgroundColor) { return { backgroundColor, borderColor: backgroundColor, @@ -1433,12 +1441,66 @@ function getBackgroundAndBorder(backgroundColor) { * @param {String} backgroundColor * @returns {Object} */ -function getBackgroundColor(backgroundColor) { +function getBackgroundColorStyle(backgroundColor) { + return { + backgroundColor, + }; +} + +/** + * @param {Animated.Value} rotate + * @param {Animated.Value} backgroundColor + * @returns {Object} + */ +function getAnimatedFABStyle(rotate, backgroundColor) { return { + transform: [{rotate}], backgroundColor, }; } +/** + * @param {Number} width + * @param {Number} height + * @returns {Object} + */ +function getWidthAndHeightStyle(width, height) { + return { + width, + height, + }; +} + +/** + * @param {Number} opacity + * @returns {Object} + */ +function getOpacityStyle(opacity) { + return {opacity}; +} + +/** + * @param {Object} params + * @returns {Object} + */ +function getModalPaddingStyles({ + shouldAddBottomSafeAreaPadding, + shouldAddTopSafeAreaPadding, + safeAreaPaddingTop, + safeAreaPaddingBottom, + modalContainerStylePaddingTop, + modalContainerStylePaddingBottom, +}) { + return { + paddingTop: shouldAddTopSafeAreaPadding + ? (modalContainerStylePaddingTop || 0) + safeAreaPaddingTop + : modalContainerStylePaddingTop || 0, + paddingBottom: shouldAddBottomSafeAreaPadding + ? (modalContainerStylePaddingBottom || 0) + safeAreaPaddingBottom + : modalContainerStylePaddingBottom || 0, + }; +} + export default styles; export { getSafeAreaPadding, @@ -1449,6 +1511,10 @@ export { getNavigationModalCardStyle, getZoomCursorStyle, getZoomSizingStyle, - getBackgroundAndBorder, - getBackgroundColor, + getBackgroundAndBorderStyle, + getBackgroundColorStyle, + getAnimatedFABStyle, + getWidthAndHeightStyle, + getOpacityStyle, + getModalPaddingStyles, }; From 7a004f378d3d25999254e1408948f32c2041ffdd Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Thu, 1 Apr 2021 09:05:42 -1000 Subject: [PATCH 34/45] fix propTypes warnings --- src/pages/home/sidebar/OptionRow.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pages/home/sidebar/OptionRow.js b/src/pages/home/sidebar/OptionRow.js index fe4b13b4875b..860b23a45090 100644 --- a/src/pages/home/sidebar/OptionRow.js +++ b/src/pages/home/sidebar/OptionRow.js @@ -141,9 +141,12 @@ const OptionRow = ({ size={mode === 'compact' ? 'small' : 'default'} secondAvatarStyle={[ getBackgroundAndBorderStyle(backgroundColor), - optionIsFocused && getBackgroundAndBorderStyle(focusedBackgroundColor), + optionIsFocused + ? getBackgroundAndBorderStyle(focusedBackgroundColor) + : undefined, hovered && !optionIsFocused - && getBackgroundAndBorderStyle(hoveredBackgroundColor), + ? getBackgroundAndBorderStyle(hoveredBackgroundColor) + : undefined, ]} /> ) From 002e5c11bbfe7c5dbf6fd9e6fc377cd098eaa388 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Wed, 31 Mar 2021 15:03:21 +0530 Subject: [PATCH 35/45] refactor code --- config/webpack/webpack.common.js | 1 - src/libs/Clipboard/index.js | 5 ++--- src/libs/reportUtils.js | 17 ++++++++++++++++- .../home/report/ReportActionContextMenu.js | 13 ++++++------- .../home/report/ReportActionContextMenuItem.js | 17 +++++++++-------- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js index 46c85ef524de..6f52e4ea0a13 100644 --- a/config/webpack/webpack.common.js +++ b/config/webpack/webpack.common.js @@ -127,7 +127,6 @@ const webpackConfig = { alias: { 'react-native-config': 'react-web-config', 'react-native$': 'react-native-web', - '@react-native-community/clipboard': 'react-native-web', }, // React Native libraries may have web-specific module implementations that appear with the extension `.web.js` diff --git a/src/libs/Clipboard/index.js b/src/libs/Clipboard/index.js index 8e93fe929adf..808e75b765ee 100644 --- a/src/libs/Clipboard/index.js +++ b/src/libs/Clipboard/index.js @@ -1,5 +1,4 @@ -// on Web/desktop this import will be replaced with `react-native-web` so we have to import the named export; -// according to the `react-native-web`; -import {Clipboard} from '@react-native-community/clipboard'; +// on Web/desktop this import will be replaced with `react-native-web` +import {Clipboard} from 'react-native-web'; export default Clipboard; diff --git a/src/libs/reportUtils.js b/src/libs/reportUtils.js index 538076d6c183..0e09a063f1af 100644 --- a/src/libs/reportUtils.js +++ b/src/libs/reportUtils.js @@ -1,5 +1,6 @@ import _ from 'underscore'; import Str from 'expensify-common/lib/str'; +import lodashGet from 'lodash/get'; /** * Returns the concatenated title for the PrimaryLogins of a report @@ -11,7 +12,21 @@ function getReportParticipantsTitle(logins) { return _.map(logins, login => Str.removeSMSDomain(login)).join(', '); } +/** + * Check whether a report action is Attachment is not. + * + * @param {Object} reportAction action from a Report + * @returns {Boolean} + */ +function isReportActionAttachment(reportAction) { + if (_.has(reportAction, 'isAttachment')) { + return reportAction.isAttachment; + } + const lastMessage = _.last(lodashGet(reportAction, 'message', null)); + return lodashGet(lastMessage, 'text', '') === '[Attachment]'; +} + export { - // eslint-disable-next-line import/prefer-default-export getReportParticipantsTitle, + isReportActionAttachment, }; diff --git a/src/pages/home/report/ReportActionContextMenu.js b/src/pages/home/report/ReportActionContextMenu.js index f19e0d5f55b4..18c42d8f81e7 100644 --- a/src/pages/home/report/ReportActionContextMenu.js +++ b/src/pages/home/report/ReportActionContextMenu.js @@ -10,6 +10,7 @@ import getReportActionContextMenuStyles from '../../../styles/getReportActionCon import ReportActionContextMenuItem from './ReportActionContextMenuItem'; import ReportActionPropTypes from './ReportActionPropTypes'; import Clipboard from '../../../libs/Clipboard'; +import {isReportActionAttachment} from '../../../libs/reportUtils'; /** * A list of all the context actions in this menu. @@ -29,13 +30,11 @@ const CONTEXT_ACTIONS = [ const lastMessage = _.last(lodashGet(action, 'message', null)); const html = lodashGet(lastMessage, 'html', ''); const text = lodashGet(lastMessage, 'text', ''); - const isAttachment = text === '[Attachment]'; - if (!isAttachment) { + if (!isReportActionAttachment(action)) { Clipboard.setString(text); } else { Clipboard.setString(html); } - return true; }, }, @@ -43,28 +42,28 @@ const CONTEXT_ACTIONS = [ { text: 'Copy Link', icon: LinkCopy, - onPress: () => { }, + onPress: () => {}, }, // Mark as Unread { text: 'Mark as Unread', icon: Mail, - onPress: () => { }, + onPress: () => {}, }, // Edit Comment { text: 'Edit Comment', icon: Pencil, - onPress: () => { }, + onPress: () => {}, }, // Delete Comment { text: 'Delete Comment', icon: Trashcan, - onPress: () => { }, + onPress: () => {}, }, ]; diff --git a/src/pages/home/report/ReportActionContextMenuItem.js b/src/pages/home/report/ReportActionContextMenuItem.js index 64622f0694eb..1ce45419e983 100644 --- a/src/pages/home/report/ReportActionContextMenuItem.js +++ b/src/pages/home/report/ReportActionContextMenuItem.js @@ -52,20 +52,21 @@ class ReportActionContextMenuItem extends Component { this.state = { success: false, }; - this.onPress = this.onPress.bind(this); + this.triggerPressAndUpdateSuccess = this.triggerPressAndUpdateSuccess.bind(this); } /** * Called on button press and mark the run - * - * @memberof ReportActionContextMenuItem */ - onPress() { + triggerPressAndUpdateSuccess() { if (this.state.success) { return; } - const pressResult = this.props.onPress(); - if (pressResult) { + this.props.onPress(); + + // We only set the success state when we have icon or text to represent the success state + // We may want to replace this check by checking the Result from OnPress Callback in future. + if (this.props.successIcon || this.props.successText) { this.setState({ success: true, }); @@ -81,7 +82,7 @@ class ReportActionContextMenuItem extends Component { ? ( getButtonStyle( getButtonState(hovered, pressed, this.state.success), @@ -98,7 +99,7 @@ class ReportActionContextMenuItem extends Component { ) : ( getButtonStyle( getButtonState(hovered, pressed, this.state.success), From 4bf4a2ae8524e761fa3ba88a7b5691ed56dcc9bb Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Fri, 2 Apr 2021 01:50:55 +0530 Subject: [PATCH 36/45] removed [Attachment] manual checks --- src/libs/actions/Report.js | 3 ++- src/libs/reportUtils.js | 13 ++++--------- src/pages/home/report/ReportActionContextMenu.js | 13 ++++++++----- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 2bf879dacd4e..87323ccc073e 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -17,6 +17,7 @@ import Timing from './Timing'; import * as API from '../API'; import CONST from '../../CONST'; import Log from '../Log'; +import {isReportMessageAttachment} from '../reportUtils'; let currentUserEmail; let currentUserAccountID; @@ -376,7 +377,7 @@ function updateReportWithNewAction(reportID, reportAction) { // Add the action into Onyx reportActionsToMerge[reportAction.sequenceNumber] = { ...reportAction, - isAttachment: messageText === '[Attachment]', + isAttachment: isReportMessageAttachment(messageText), loading: false, }; diff --git a/src/libs/reportUtils.js b/src/libs/reportUtils.js index 0e09a063f1af..a8e5575059b4 100644 --- a/src/libs/reportUtils.js +++ b/src/libs/reportUtils.js @@ -1,6 +1,5 @@ import _ from 'underscore'; import Str from 'expensify-common/lib/str'; -import lodashGet from 'lodash/get'; /** * Returns the concatenated title for the PrimaryLogins of a report @@ -15,18 +14,14 @@ function getReportParticipantsTitle(logins) { /** * Check whether a report action is Attachment is not. * - * @param {Object} reportAction action from a Report + * @param {Object} reportMessageText report action's message as text * @returns {Boolean} */ -function isReportActionAttachment(reportAction) { - if (_.has(reportAction, 'isAttachment')) { - return reportAction.isAttachment; - } - const lastMessage = _.last(lodashGet(reportAction, 'message', null)); - return lodashGet(lastMessage, 'text', '') === '[Attachment]'; +function isReportMessageAttachment(reportMessageText) { + return reportMessageText === '[Attachment]'; } export { getReportParticipantsTitle, - isReportActionAttachment, + isReportMessageAttachment, }; diff --git a/src/pages/home/report/ReportActionContextMenu.js b/src/pages/home/report/ReportActionContextMenu.js index 18c42d8f81e7..e667ba5c65f9 100644 --- a/src/pages/home/report/ReportActionContextMenu.js +++ b/src/pages/home/report/ReportActionContextMenu.js @@ -10,7 +10,7 @@ import getReportActionContextMenuStyles from '../../../styles/getReportActionCon import ReportActionContextMenuItem from './ReportActionContextMenuItem'; import ReportActionPropTypes from './ReportActionPropTypes'; import Clipboard from '../../../libs/Clipboard'; -import {isReportActionAttachment} from '../../../libs/reportUtils'; +import {isReportMessageAttachment} from '../../../libs/reportUtils'; /** * A list of all the context actions in this menu. @@ -27,10 +27,13 @@ const CONTEXT_ACTIONS = [ // `ReportActionContextMenuItem` with `successText` and `successIcon` which will fallback to // the `text` and `icon` onPress: (action) => { - const lastMessage = _.last(lodashGet(action, 'message', null)); - const html = lodashGet(lastMessage, 'html', ''); - const text = lodashGet(lastMessage, 'text', ''); - if (!isReportActionAttachment(action)) { + const message = _.last(lodashGet(action, 'message', null)); + const html = lodashGet(message, 'html', ''); + const text = lodashGet(message, 'text', ''); + const isAttachment = _.has(action, 'isAttachment') + ? action.isAttachment + : isReportMessageAttachment(text); + if (!isAttachment) { Clipboard.setString(text); } else { Clipboard.setString(html); From e45001f3dff8ec12e8314a2a30774b8325b245f7 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Thu, 1 Apr 2021 14:52:10 -0700 Subject: [PATCH 37/45] Purposely commit incorrect value in Github Action --- .github/actions/bumpVersion/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/bumpVersion/action.yml b/.github/actions/bumpVersion/action.yml index 4118916bb768..d6a3bd8761e9 100644 --- a/.github/actions/bumpVersion/action.yml +++ b/.github/actions/bumpVersion/action.yml @@ -6,7 +6,7 @@ inputs: required: true SEMVER_LEVEL: description: Semantic Versioning Level - required: true + required: blarginfogigglenohip outputs: NEW_VERSION: description: The new semver version of the application, updated in the JS and native layers. From b67183c98440fec60c58e92c0845d70d6633e91c Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Thu, 1 Apr 2021 14:54:07 -0700 Subject: [PATCH 38/45] Purposely commit invalid key in github action --- .github/actions/bumpVersion/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/bumpVersion/action.yml b/.github/actions/bumpVersion/action.yml index d6a3bd8761e9..9b50e4cb5699 100644 --- a/.github/actions/bumpVersion/action.yml +++ b/.github/actions/bumpVersion/action.yml @@ -5,8 +5,8 @@ inputs: description: Auth token for Expensify.cash Github required: true SEMVER_LEVEL: - description: Semantic Versioning Level - required: blarginfogigglenohip + balshaefyaer: Semantic Versioning Level + required: true outputs: NEW_VERSION: description: The new semver version of the application, updated in the JS and native layers. From 286085e621abf86cf302e9193ae7e9029eb1cc3c Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Thu, 1 Apr 2021 16:18:53 -0700 Subject: [PATCH 39/45] Purposely commit invalid key in github workflow --- .github/actions/bumpVersion/action.yml | 2 +- .github/workflows/automerge.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/bumpVersion/action.yml b/.github/actions/bumpVersion/action.yml index 9b50e4cb5699..4118916bb768 100644 --- a/.github/actions/bumpVersion/action.yml +++ b/.github/actions/bumpVersion/action.yml @@ -5,7 +5,7 @@ inputs: description: Auth token for Expensify.cash Github required: true SEMVER_LEVEL: - balshaefyaer: Semantic Versioning Level + description: Semantic Versioning Level required: true outputs: NEW_VERSION: diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml index 098b00e26223..ab653766c70d 100644 --- a/.github/workflows/automerge.yml +++ b/.github/workflows/automerge.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest outputs: isMergeable: ${{ steps.isPullRequestMergeable.outputs.IS_MERGEABLE }} - steps: + balksraeb: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f with: ref: master From 9e33976b370cae4815763a2a06963b32ff55edac Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Thu, 1 Apr 2021 16:20:44 -0700 Subject: [PATCH 40/45] Purposely commit incorrect value in github workflow --- .github/workflows/automerge.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml index ab653766c70d..c434859c10a9 100644 --- a/.github/workflows/automerge.yml +++ b/.github/workflows/automerge.yml @@ -9,11 +9,11 @@ on: jobs: getPullRequestMergeability: - if: github.actor == 'OSBotify' && github.event.label.name == 'automerge' + if: lerueavhba runs-on: ubuntu-latest outputs: isMergeable: ${{ steps.isPullRequestMergeable.outputs.IS_MERGEABLE }} - balksraeb: + steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f with: ref: master From 80de9738de9fc379b7dace753e9912055c4210d5 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Thu, 1 Apr 2021 16:22:09 -0700 Subject: [PATCH 41/45] Reset everything back to normal --- .github/workflows/automerge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml index c434859c10a9..3304d37a2903 100644 --- a/.github/workflows/automerge.yml +++ b/.github/workflows/automerge.yml @@ -9,7 +9,7 @@ on: jobs: getPullRequestMergeability: - if: lerueavhba + if: github.actor == 'OSBotify' && github.event.label.name == 'automerge' runs-on: ubuntu-latest outputs: isMergeable: ${{ steps.isPullRequestMergeable.outputs.IS_MERGEABLE }} From b0217ba1d889a4a64970022bd6ef87c97a94c162 Mon Sep 17 00:00:00 2001 From: Rory Abraham Date: Thu, 1 Apr 2021 16:26:03 -0700 Subject: [PATCH 42/45] Nix extra space in automerge workflow --- .github/workflows/automerge.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml index 3304d37a2903..098b00e26223 100644 --- a/.github/workflows/automerge.yml +++ b/.github/workflows/automerge.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest outputs: isMergeable: ${{ steps.isPullRequestMergeable.outputs.IS_MERGEABLE }} - steps: + steps: - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f with: ref: master From 8edbf7985e02b878434747bd597bc317b2625dfd Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Fri, 2 Apr 2021 08:17:59 +0800 Subject: [PATCH 43/45] Remove unused, add missed prop --- src/pages/signin/LoginForm/LoginFormNarrow.js | 2 +- src/pages/signin/LoginForm/LoginFormWide.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/signin/LoginForm/LoginFormNarrow.js b/src/pages/signin/LoginForm/LoginFormNarrow.js index f135e6987175..61c3f8571f38 100644 --- a/src/pages/signin/LoginForm/LoginFormNarrow.js +++ b/src/pages/signin/LoginForm/LoginFormNarrow.js @@ -103,7 +103,7 @@ class LoginFormNarrow extends React.Component { source={welcomeScreenshot} /> - + ); } diff --git a/src/pages/signin/LoginForm/LoginFormWide.js b/src/pages/signin/LoginForm/LoginFormWide.js index 90718d863d8f..7eccb16bf25b 100644 --- a/src/pages/signin/LoginForm/LoginFormWide.js +++ b/src/pages/signin/LoginForm/LoginFormWide.js @@ -94,7 +94,7 @@ class LoginFormWide extends React.Component { )} - + ); From f0139c3398c590e44b71ed1c8a9f813a48aa9502 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 2 Apr 2021 18:27:02 +0000 Subject: [PATCH 44/45] Update version to 1.0.11-1 --- android/app/build.gradle | 4 ++-- ios/ExpensifyCash/Info.plist | 4 ++-- ios/ExpensifyCashTests/Info.plist | 4 ++-- package-lock.json | 2 +- package.json | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 329661226a4a..40aa09fc78b5 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -148,8 +148,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001001002 - versionName "1.0.10-2" + versionCode 1001001101 + versionName "1.0.11-1" } splits { abi { diff --git a/ios/ExpensifyCash/Info.plist b/ios/ExpensifyCash/Info.plist index b158052454db..10ff181ecc6b 100644 --- a/ios/ExpensifyCash/Info.plist +++ b/ios/ExpensifyCash/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0.10 + 1.0.11 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.0.10.2 + 1.0.11.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/ExpensifyCashTests/Info.plist b/ios/ExpensifyCashTests/Info.plist index 929c25e9d984..417378e40e79 100644 --- a/ios/ExpensifyCashTests/Info.plist +++ b/ios/ExpensifyCashTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.0.10 + 1.0.11 CFBundleSignature ???? CFBundleVersion - 1.0.10.2 + 1.0.11.1 diff --git a/package-lock.json b/package-lock.json index 94348b0cf3bf..1b0788872190 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "expensify.cash", - "version": "1.0.10-2", + "version": "1.0.11-1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 328e20e55f76..741de1a5ed72 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "expensify.cash", - "version": "1.0.10-2", + "version": "1.0.11-1", "author": "Expensify, Inc.", "homepage": "https://expensify.cash", "description": "Expensify.cash is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From ccf6c114aae11f9b58272d5b7e99a05575c79e27 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 2 Apr 2021 20:48:07 +0000 Subject: [PATCH 45/45] Update version to 1.0.11-2 --- android/app/build.gradle | 4 ++-- ios/ExpensifyCash/Info.plist | 2 +- ios/ExpensifyCashTests/Info.plist | 2 +- package-lock.json | 2 +- package.json | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 40aa09fc78b5..ec3b7aab2b8c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -148,8 +148,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001001101 - versionName "1.0.11-1" + versionCode 1001001102 + versionName "1.0.11-2" } splits { abi { diff --git a/ios/ExpensifyCash/Info.plist b/ios/ExpensifyCash/Info.plist index 10ff181ecc6b..168172f5ab4e 100644 --- a/ios/ExpensifyCash/Info.plist +++ b/ios/ExpensifyCash/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 1.0.11.1 + 1.0.11.2 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/ExpensifyCashTests/Info.plist b/ios/ExpensifyCashTests/Info.plist index 417378e40e79..3d0f7e02e0ac 100644 --- a/ios/ExpensifyCashTests/Info.plist +++ b/ios/ExpensifyCashTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.0.11.1 + 1.0.11.2 diff --git a/package-lock.json b/package-lock.json index 21d9c2682012..e21575a32000 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "expensify.cash", - "version": "1.0.11-1", + "version": "1.0.11-2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1de9f70d1acd..0400b50c2890 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "expensify.cash", - "version": "1.0.11-1", + "version": "1.0.11-2", "author": "Expensify, Inc.", "homepage": "https://expensify.cash", "description": "Expensify.cash is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",