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/Badge.js b/src/components/Badge.js
deleted file mode 100644
index 49b330ae37b2..000000000000
--- a/src/components/Badge.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import {View} 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 = {
- /** Is Success type */
- success: PropTypes.bool,
-
- /** Is Error type */
- error: PropTypes.bool,
-
- /** Whether badge is clickable */
- pressable: PropTypes.bool,
-
- /** Text to display in the Badge */
- text: PropTypes.string.isRequired,
-
- /** Text to display in the Badge */
- environment: PropTypes.string,
-
- /** Styles for Badge */
- // eslint-disable-next-line react/forbid-prop-types
- badgeStyles: PropTypes.arrayOf(PropTypes.object),
-
- /** Styles for Badge Text */
- // eslint-disable-next-line react/forbid-prop-types
- textStyles: PropTypes.arrayOf(PropTypes.object),
-
- /** Callback to be called on onPress */
- onPress: PropTypes.func,
-};
-
-const defaultProps = {
- success: false,
- error: false,
- pressable: false,
- badgeStyles: [],
- textStyles: [],
- onPress: undefined,
- environment: CONST.ENVIRONMENT.DEV,
-};
-
-function Badge(props) {
- const textStyles = props.success || props.error ? styles.textWhite : undefined;
- const Wrapper = props.pressable ? PressableWithoutFeedback : View;
- const wrapperStyles = ({pressed}) => [
- styles.badge,
- styles.ml2,
- StyleUtils.getBadgeColorStyle(props.success, props.error, pressed, props.environment === CONST.ENVIRONMENT.ADHOC),
- ...props.badgeStyles,
- ];
-
- return (
-
-
- {props.text}
-
-
- );
-}
-
-Badge.displayName = 'Badge';
-Badge.propTypes = propTypes;
-Badge.defaultProps = defaultProps;
-export default Badge;
diff --git a/src/components/Badge.tsx b/src/components/Badge.tsx
new file mode 100644
index 000000000000..2ccd41575073
--- /dev/null
+++ b/src/components/Badge.tsx
@@ -0,0 +1,65 @@
+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';
+import CONST from '@src/CONST';
+import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
+import Text from './Text';
+
+type BadgeProps = {
+ /** Is Success type */
+ success?: boolean;
+
+ /** Is Error type */
+ error?: boolean;
+
+ /** Whether badge is clickable */
+ pressable?: boolean;
+
+ /** Text to display in the Badge */
+ text: string;
+
+ /** Text to display in the Badge */
+ environment?: string;
+
+ /** Styles for Badge */
+ badgeStyles?: StyleProp;
+
+ /** Styles for Badge Text */
+ textStyles?: StyleProp;
+
+ /** Callback to be called on onPress */
+ onPress: (event?: GestureResponderEvent | KeyboardEvent) => void;
+};
+
+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;
+
+ 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 (
+
+
+ {text}
+
+
+ );
+}
+
+Badge.displayName = 'Badge';
+
+export default Badge;
diff --git a/src/components/Icon/Expensicons.ts b/src/components/Icon/Expensicons.ts
index a4aa6b13cb29..3d4f0edb1656 100644
--- a/src/components/Icon/Expensicons.ts
+++ b/src/components/Icon/Expensicons.ts
@@ -45,6 +45,7 @@ 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 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';
@@ -176,6 +177,7 @@ export {
EReceiptIcon,
Emoji,
EmptyStateRoutePending,
+ EmptyStateAttachReceipt,
Exclamation,
Exit,
ExpensifyCard,
diff --git a/src/components/ReceiptEmptyState.js b/src/components/ReceiptEmptyState.js
new file mode 100644
index 000000000000..ef2f6a5b62e4
--- /dev/null
+++ b/src/components/ReceiptEmptyState.js
@@ -0,0 +1,44 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+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 an error */
+ hasError: PropTypes.bool,
+
+ /** Callback to be called on onPress */
+ onPress: PropTypes.func,
+};
+
+const defaultProps = {
+ hasError: false,
+ onPress: () => {},
+};
+
+// Returns an SVG icon indicating that the user should attach a receipt
+function ReceiptEmptyState({hasError, onPress}) {
+ return (
+
+
+
+ );
+}
+
+ReceiptEmptyState.displayName = 'ReceiptEmptyState';
+ReceiptEmptyState.propTypes = propTypes;
+ReceiptEmptyState.defaultProps = defaultProps;
+
+export default ReceiptEmptyState;
diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js
index f1fc51bd2be8..5b9a1b2212c7 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';
@@ -172,6 +173,12 @@ function MoneyRequestView({report, parentReport, policyCategories, shouldShowHor
)}
+ {!hasReceipt && canEdit && !isSettled && Permissions.canUseViolations() && (
+ Navigation.navigate(ROUTES.EDIT_REQUEST.getRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT))}
+ />
+ )}
maxWidth: 400,
},
+ moneyRequestAttachReceipt: {
+ backgroundColor: theme.appBG,
+ borderColor: theme.textSupporting,
+ },
+
mapViewContainer: {
...flex.flex1,
minHeight: 300,