From 40f0fec7df7b48cc0304a8e797c8c0a036d3fc86 Mon Sep 17 00:00:00 2001 From: Daniel Edwards Date: Tue, 7 Nov 2023 12:16:16 -0500 Subject: [PATCH 01/14] Add SVG --- assets/images/empty-state__attach-receipt.svg | 16 ++++++++++++++++ src/components/Icon/Expensicons.js | 2 ++ 2 files changed, 18 insertions(+) create mode 100644 assets/images/empty-state__attach-receipt.svg diff --git a/assets/images/empty-state__attach-receipt.svg b/assets/images/empty-state__attach-receipt.svg new file mode 100644 index 000000000000..6b50afbdbf0b --- /dev/null +++ b/assets/images/empty-state__attach-receipt.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js index a4aa6b13cb29..e5f4d158be1a 100644 --- a/src/components/Icon/Expensicons.js +++ b/src/components/Icon/Expensicons.js @@ -46,6 +46,7 @@ import DragAndDrop from '@assets/images/drag-and-drop.svg'; import DragHandles from '@assets/images/drag-handles.svg'; import Emoji from '@assets/images/emoji.svg'; import EmptyStateRoutePending from '@assets/images/emptystate__routepending.svg'; +import EmptyStateAttachReceipt from '@assets/images/empty-state__attach-receipt.svg'; import EReceiptIcon from '@assets/images/eReceiptIcon.svg'; import Exclamation from '@assets/images/exclamation.svg'; import Exit from '@assets/images/exit.svg'; @@ -176,6 +177,7 @@ export { EReceiptIcon, Emoji, EmptyStateRoutePending, + EmptyStateAttachReceipt, Exclamation, Exit, ExpensifyCard, From 561c3548eab0de370a61a4403a99dcbde28ebd81 Mon Sep 17 00:00:00 2001 From: Daniel Edwards Date: Tue, 7 Nov 2023 15:31:42 -0500 Subject: [PATCH 02/14] Adds ReceiptEmptyState Component --- src/components/ReceiptEmptyState.js | 47 +++++++++++++++++++++++++++++ src/styles/styles.ts | 5 +++ 2 files changed, 52 insertions(+) create mode 100644 src/components/ReceiptEmptyState.js diff --git a/src/components/ReceiptEmptyState.js b/src/components/ReceiptEmptyState.js new file mode 100644 index 000000000000..31edb4842389 --- /dev/null +++ b/src/components/ReceiptEmptyState.js @@ -0,0 +1,47 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { View } from 'react-native'; +import styles from '@styles/styles'; +import variables from '@styles/variables'; +import Icon from './Icon'; +import * as Expensicons from './Icon/Expensicons'; + +import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; + +const propTypes = { + /** Whether or not there is a violation error */ + hasError: PropTypes.bool, + + /** Callback to be called on onPress */ + onPress: PropTypes.func, +} + +const defaultProps = { + hasError: false, + onPress: undefined, +} + + +// Create a component with the above instructions: + +function ReceiptEmptyState({hasError, onPress}) { + return ( + + + + + + + ) +} + +ReceiptEmptyState.displayName = 'ReceiptEmptyState'; +ReceiptEmptyState.propTypes = propTypes; +ReceiptEmptyState.defaultProps = defaultProps; + +export default ReceiptEmptyState; diff --git a/src/styles/styles.ts b/src/styles/styles.ts index da5cc8e726fd..588dba090767 100644 --- a/src/styles/styles.ts +++ b/src/styles/styles.ts @@ -3837,6 +3837,11 @@ const styles = (theme: ThemeDefault) => maxWidth: 400, }, + moneyRequestAttachReceipt: { + backgroundColor: theme.appBG, + borderColor: theme.textSupporting, + }, + mapViewContainer: { ...flex.flex1, minHeight: 300, From d8ededb712fc3adad9133e63d845d0df33e7acca Mon Sep 17 00:00:00 2001 From: Daniel Edwards Date: Tue, 7 Nov 2023 15:32:24 -0500 Subject: [PATCH 03/14] Adds EmptyStateReceipt to MoneyRequestView --- src/components/ReportActionItem/MoneyRequestView.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index aa1813fa6e4d..97455f621421 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -37,6 +37,7 @@ import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import ReceiptEmptyState from '@components/ReceiptEmptyState'; import ReportActionItemImage from './ReportActionItemImage'; const propTypes = { @@ -175,6 +176,11 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should )} + {!hasReceipt && Permissions.canUseViolations() && ( + + Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT))} /> + + )} Date: Tue, 7 Nov 2023 15:45:32 -0500 Subject: [PATCH 04/14] prettier --- src/components/Icon/Expensicons.js | 2 +- src/components/ReceiptEmptyState.js | 19 ++++++++++--------- .../ReportActionItem/MoneyRequestView.js | 7 +++++-- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js index e5f4d158be1a..3d4f0edb1656 100644 --- a/src/components/Icon/Expensicons.js +++ b/src/components/Icon/Expensicons.js @@ -45,8 +45,8 @@ import Download from '@assets/images/download.svg'; import DragAndDrop from '@assets/images/drag-and-drop.svg'; import DragHandles from '@assets/images/drag-handles.svg'; import Emoji from '@assets/images/emoji.svg'; -import EmptyStateRoutePending from '@assets/images/emptystate__routepending.svg'; import EmptyStateAttachReceipt from '@assets/images/empty-state__attach-receipt.svg'; +import EmptyStateRoutePending from '@assets/images/emptystate__routepending.svg'; import EReceiptIcon from '@assets/images/eReceiptIcon.svg'; import Exclamation from '@assets/images/exclamation.svg'; import Exit from '@assets/images/exit.svg'; diff --git a/src/components/ReceiptEmptyState.js b/src/components/ReceiptEmptyState.js index 31edb4842389..f32083c650d9 100644 --- a/src/components/ReceiptEmptyState.js +++ b/src/components/ReceiptEmptyState.js @@ -1,11 +1,10 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { View } from 'react-native'; +import React from 'react'; +import {View} from 'react-native'; import styles from '@styles/styles'; import variables from '@styles/variables'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; - import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; const propTypes = { @@ -14,20 +13,22 @@ const propTypes = { /** Callback to be called on onPress */ onPress: PropTypes.func, -} +}; const defaultProps = { hasError: false, onPress: undefined, -} - +}; // Create a component with the above instructions: function ReceiptEmptyState({hasError, onPress}) { return ( - - + + - ) + ); } ReceiptEmptyState.displayName = 'ReceiptEmptyState'; diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index 97455f621421..a9ae4d85e426 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -8,6 +8,7 @@ import categoryPropTypes from '@components/categoryPropTypes'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import ReceiptEmptyState from '@components/ReceiptEmptyState'; import SpacerView from '@components/SpacerView'; import Switch from '@components/Switch'; import tagPropTypes from '@components/tagPropTypes'; @@ -37,7 +38,6 @@ import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import ReceiptEmptyState from '@components/ReceiptEmptyState'; import ReportActionItemImage from './ReportActionItemImage'; const propTypes = { @@ -178,7 +178,10 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should )} {!hasReceipt && Permissions.canUseViolations() && ( - Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT))} /> + Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT))} + /> )} From dfa86a01e17d73cb543f15d3eb31753c3e59a7b4 Mon Sep 17 00:00:00 2001 From: Daniel Edwards Date: Wed, 8 Nov 2023 10:48:29 -0500 Subject: [PATCH 05/14] Removed extra SVG and updated fill color --- src/components/ReceiptEmptyState.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/ReceiptEmptyState.js b/src/components/ReceiptEmptyState.js index f32083c650d9..01c1b8a484f5 100644 --- a/src/components/ReceiptEmptyState.js +++ b/src/components/ReceiptEmptyState.js @@ -33,9 +33,8 @@ function ReceiptEmptyState({hasError, onPress}) { src={Expensicons.EmptyStateAttachReceipt} width={variables.iconSizeUltraLarge} height={variables.iconSizeUltraLarge} - fill="#DC80E4" + fill="transparent" /> - ); From 3b7199be403bfc9ca5ea9f8fb65feeb7bc770fed Mon Sep 17 00:00:00 2001 From: Daniel Edwards Date: Thu, 9 Nov 2023 15:17:33 -0500 Subject: [PATCH 06/14] Update src/components/ReceiptEmptyState.js Co-authored-by: Carlos Alvarez --- src/components/ReceiptEmptyState.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReceiptEmptyState.js b/src/components/ReceiptEmptyState.js index 01c1b8a484f5..4275aa8739c0 100644 --- a/src/components/ReceiptEmptyState.js +++ b/src/components/ReceiptEmptyState.js @@ -8,7 +8,7 @@ import * as Expensicons from './Icon/Expensicons'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; const propTypes = { - /** Whether or not there is a violation error */ + /** Whether or not there is an error */ hasError: PropTypes.bool, /** Callback to be called on onPress */ From 3d11e236923525bd3887ff5e00c720cc32c51de2 Mon Sep 17 00:00:00 2001 From: Daniel Edwards Date: Thu, 9 Nov 2023 15:17:52 -0500 Subject: [PATCH 07/14] Update src/components/ReceiptEmptyState.js Co-authored-by: Carlos Alvarez --- src/components/ReceiptEmptyState.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReceiptEmptyState.js b/src/components/ReceiptEmptyState.js index 4275aa8739c0..e3e888cbf74b 100644 --- a/src/components/ReceiptEmptyState.js +++ b/src/components/ReceiptEmptyState.js @@ -17,7 +17,7 @@ const propTypes = { const defaultProps = { hasError: false, - onPress: undefined, + onPress: () => {}, }; // Create a component with the above instructions: From 162572c2f0a36b22207087b26c34c229f2f05e5b Mon Sep 17 00:00:00 2001 From: Daniel Edwards Date: Thu, 9 Nov 2023 15:25:36 -0500 Subject: [PATCH 08/14] Updates comment for component --- src/components/ReceiptEmptyState.js | 3 +-- src/components/ReportActionItem/MoneyRequestView.js | 10 ++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/components/ReceiptEmptyState.js b/src/components/ReceiptEmptyState.js index e3e888cbf74b..205dd83dd42d 100644 --- a/src/components/ReceiptEmptyState.js +++ b/src/components/ReceiptEmptyState.js @@ -20,8 +20,7 @@ const defaultProps = { onPress: () => {}, }; -// Create a component with the above instructions: - +// Returns an SVG icon indicating that the user should attach a receipt function ReceiptEmptyState({hasError, onPress}) { return ( )} {!hasReceipt && Permissions.canUseViolations() && ( - - Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT))} - /> - + Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT))} + /> )} Date: Fri, 10 Nov 2023 16:12:59 -0500 Subject: [PATCH 09/14] Moved styles to Pressable and centered SVG better --- src/components/ReceiptEmptyState.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/components/ReceiptEmptyState.js b/src/components/ReceiptEmptyState.js index 205dd83dd42d..134124017b83 100644 --- a/src/components/ReceiptEmptyState.js +++ b/src/components/ReceiptEmptyState.js @@ -1,6 +1,5 @@ import PropTypes from 'prop-types'; import React from 'react'; -import {View} from 'react-native'; import styles from '@styles/styles'; import variables from '@styles/variables'; import Icon from './Icon'; @@ -26,15 +25,14 @@ function ReceiptEmptyState({hasError, onPress}) { - - - + ); } From 876557576f3fc462700a79b26ffd21ca4861852f Mon Sep 17 00:00:00 2001 From: Daniel Edwards Date: Fri, 10 Nov 2023 16:15:52 -0500 Subject: [PATCH 10/14] Updated Accessibility prop --- src/components/ReceiptEmptyState.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReceiptEmptyState.js b/src/components/ReceiptEmptyState.js index 134124017b83..ef2f6a5b62e4 100644 --- a/src/components/ReceiptEmptyState.js +++ b/src/components/ReceiptEmptyState.js @@ -23,7 +23,7 @@ const defaultProps = { function ReceiptEmptyState({hasError, onPress}) { return ( From 633606e09b3b7809ae48938b8c853b145e923b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Mon, 13 Nov 2023 06:28:22 -0300 Subject: [PATCH 11/14] Rename file to TS --- src/components/{Badge.js => Badge.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/components/{Badge.js => Badge.tsx} (100%) diff --git a/src/components/Badge.js b/src/components/Badge.tsx similarity index 100% rename from src/components/Badge.js rename to src/components/Badge.tsx From fa04a3f7702418dc816397a78ba48c155cf0ac91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Mon, 13 Nov 2023 09:33:41 -0300 Subject: [PATCH 12/14] Migrate file to TS --- src/components/Badge.tsx | 62 ++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/src/components/Badge.tsx b/src/components/Badge.tsx index 49b330ae37b2..8a0fea75f99a 100644 --- a/src/components/Badge.tsx +++ b/src/components/Badge.tsx @@ -1,79 +1,67 @@ -import PropTypes from 'prop-types'; import React from 'react'; -import {View} from 'react-native'; +import {GestureResponderEvent, PressableStateCallbackType, StyleProp, TextStyle, View, ViewStyle} from 'react-native'; import styles from '@styles/styles'; import * as StyleUtils from '@styles/StyleUtils'; import CONST from '@src/CONST'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; import Text from './Text'; -const propTypes = { +type BadgeProps = { /** Is Success type */ - success: PropTypes.bool, + success?: boolean; /** Is Error type */ - error: PropTypes.bool, + error?: boolean; /** Whether badge is clickable */ - pressable: PropTypes.bool, + pressable?: boolean; /** Text to display in the Badge */ - text: PropTypes.string.isRequired, + text: string; /** Text to display in the Badge */ - environment: PropTypes.string, + environment?: string; /** Styles for Badge */ - // eslint-disable-next-line react/forbid-prop-types - badgeStyles: PropTypes.arrayOf(PropTypes.object), + badgeStyles?: StyleProp; /** Styles for Badge Text */ - // eslint-disable-next-line react/forbid-prop-types - textStyles: PropTypes.arrayOf(PropTypes.object), + textStyles?: StyleProp; /** Callback to be called on onPress */ - onPress: PropTypes.func, + onPress: (event?: GestureResponderEvent | KeyboardEvent) => void; }; -const defaultProps = { - success: false, - error: false, - pressable: false, - badgeStyles: [], - textStyles: [], - onPress: undefined, - environment: CONST.ENVIRONMENT.DEV, -}; +function Badge({success = false, error = false, pressable = false, text, environment = CONST.ENVIRONMENT.DEV, badgeStyles, textStyles, onPress = () => {}}: BadgeProps) { + const textColorStyles = success || error ? styles.textWhite : undefined; + const Wrapper = pressable ? PressableWithoutFeedback : View; -function Badge(props) { - const textStyles = props.success || props.error ? styles.textWhite : undefined; - const Wrapper = props.pressable ? PressableWithoutFeedback : View; - const wrapperStyles = ({pressed}) => [ + const wrapperStyles: (state: PressableStateCallbackType) => StyleProp = ({pressed}) => [ styles.badge, styles.ml2, - StyleUtils.getBadgeColorStyle(props.success, props.error, pressed, props.environment === CONST.ENVIRONMENT.ADHOC), - ...props.badgeStyles, + StyleUtils.getBadgeColorStyle(success, error, pressed, environment === CONST.ENVIRONMENT.ADHOC), + badgeStyles, ]; return ( - {props.text} + {text} ); } Badge.displayName = 'Badge'; -Badge.propTypes = propTypes; -Badge.defaultProps = defaultProps; + export default Badge; From 95d237b608b6bd9b5f50f9b9c221615602bbfaf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Mon, 13 Nov 2023 09:51:51 -0300 Subject: [PATCH 13/14] Add useCallback --- src/components/Badge.tsx | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/components/Badge.tsx b/src/components/Badge.tsx index 8a0fea75f99a..2ccd41575073 100644 --- a/src/components/Badge.tsx +++ b/src/components/Badge.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import {GestureResponderEvent, PressableStateCallbackType, StyleProp, TextStyle, View, ViewStyle} from 'react-native'; import styles from '@styles/styles'; import * as StyleUtils from '@styles/StyleUtils'; @@ -36,12 +36,10 @@ function Badge({success = false, error = false, pressable = false, text, environ const textColorStyles = success || error ? styles.textWhite : undefined; const Wrapper = pressable ? PressableWithoutFeedback : View; - const wrapperStyles: (state: PressableStateCallbackType) => StyleProp = ({pressed}) => [ - styles.badge, - styles.ml2, - StyleUtils.getBadgeColorStyle(success, error, pressed, environment === CONST.ENVIRONMENT.ADHOC), - badgeStyles, - ]; + const wrapperStyles: (state: PressableStateCallbackType) => StyleProp = useCallback( + ({pressed}) => [styles.badge, styles.ml2, StyleUtils.getBadgeColorStyle(success, error, pressed, environment === CONST.ENVIRONMENT.ADHOC), badgeStyles], + [success, error, environment, badgeStyles], + ); return ( Date: Wed, 15 Nov 2023 09:34:42 -0500 Subject: [PATCH 14/14] Updates from review --- src/components/ReportActionItem/MoneyRequestView.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js index d60ea2c59e03..9ff1e0761594 100644 --- a/src/components/ReportActionItem/MoneyRequestView.js +++ b/src/components/ReportActionItem/MoneyRequestView.js @@ -177,7 +177,7 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should )} - {!hasReceipt && Permissions.canUseViolations() && ( + {!hasReceipt && canEdit && !isSettled && Permissions.canUseViolations() && ( Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT))}