diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index 1cc12fca24ae..b8bfb4c36122 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -31,11 +31,14 @@ import useWindowDimensions from '../hooks/useWindowDimensions'; import Navigation from '../libs/Navigation/Navigation'; import ROUTES from '../ROUTES'; import useNativeDriver from '../libs/useNativeDriver'; -import * as ReportUtils from '../libs/ReportUtils'; import * as ReportActionsUtils from '../libs/ReportActionsUtils'; +import * as ReportUtils from '../libs/ReportUtils'; import ONYXKEYS from '../ONYXKEYS'; import * as Policy from '../libs/actions/Policy'; import useNetwork from '../hooks/useNetwork'; +import * as IOU from '../libs/actions/IOU'; +import transactionPropTypes from './transactionPropTypes'; +import * as TransactionUtils from '../libs/TransactionUtils'; /** * Modal render prop component that exposes modal launching triggers that can be used @@ -79,6 +82,9 @@ const propTypes = { /** The report that has this attachment */ report: reportPropTypes, + /** The transaction associated with the receipt attachment, if any */ + transaction: transactionPropTypes, + ...withLocalizePropTypes, ...windowDimensionsPropTypes, @@ -97,6 +103,7 @@ const defaultProps = { allowDownload: false, headerTitle: null, report: {}, + transaction: {}, onModalShow: () => {}, onModalHide: () => {}, onCarouselAttachmentChange: () => {}, @@ -108,6 +115,7 @@ function AttachmentModal(props) { const [isModalOpen, setIsModalOpen] = useState(props.defaultOpen); const [shouldLoadAttachment, setShouldLoadAttachment] = useState(false); const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false); + const [isDeleteReceiptConfirmModalVisible, setIsDeleteReceiptConfirmModalVisible] = useState(false); const [isAuthTokenRequired, setIsAuthTokenRequired] = useState(props.isAuthTokenRequired); const [isAttachmentReceipt, setIsAttachmentReceipt] = useState(false); const [attachmentInvalidReasonTitle, setAttachmentInvalidReasonTitle] = useState(''); @@ -205,12 +213,22 @@ function AttachmentModal(props) { }, [isModalOpen, isConfirmButtonDisabled, props.onConfirm, file, source]); /** - * Close the confirm modal. + * Close the confirm modals. */ const closeConfirmModal = useCallback(() => { setIsAttachmentInvalid(false); + setIsDeleteReceiptConfirmModalVisible(false); }, []); + /** + * Detach the receipt and close the modal. + */ + const deleteAndCloseModal = useCallback(() => { + IOU.detachReceipt(props.transaction.transactionID, props.report.reportID); + setIsDeleteReceiptConfirmModalVisible(false); + Navigation.dismissModal(props.report.reportID); + }, [props.transaction, props.report]); + /** * @param {Object} _file * @returns {Boolean} @@ -358,9 +376,18 @@ function AttachmentModal(props) { text: props.translate('common.download'), onSelected: () => downloadAttachment(source), }); + if (TransactionUtils.hasReceipt(props.transaction) && !TransactionUtils.isReceiptBeingScanned(props.transaction)) { + menuItems.push({ + icon: Expensicons.Trashcan, + text: props.translate('receipt.deleteReceipt'), + onSelected: () => { + setIsDeleteReceiptConfirmModalVisible(true); + }, + }); + } return menuItems; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isAttachmentReceipt, props.parentReport, props.parentReportActions, props.policy]); + }, [isAttachmentReceipt, props.parentReport, props.parentReportActions, props.policy, props.transaction]); return ( <> @@ -442,18 +469,30 @@ function AttachmentModal(props) { )} )} + {isAttachmentReceipt ? ( + + ) : ( + + )} - - {props.children && props.children({ displayFileInModal: validateAndDisplayFileToUpload, @@ -470,6 +509,16 @@ export default compose( withWindowDimensions, withLocalize, withOnyx({ + transaction: { + key: ({report}) => { + if (!report) { + return undefined; + } + const parentReportAction = ReportActionsUtils.getReportAction(report.parentReportID, report.parentReportActionID); + const transactionID = lodashGet(parentReportAction, ['originalMessage', 'IOUTransactionID'], 0); + return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; + }, + }, parentReport: { key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report ? report.parentReportID : '0'}`, }, diff --git a/src/languages/en.ts b/src/languages/en.ts index 85e897db58ec..1128e364eb94 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -506,6 +506,8 @@ export default { flash: 'flash', shutter: 'shutter', gallery: 'gallery', + deleteReceipt: 'Delete receipt', + deleteConfirmation: 'Are you sure you want to delete this receipt?', addReceipt: 'Add receipt', }, iou: { diff --git a/src/languages/es.ts b/src/languages/es.ts index 548c2caa3721..cc7e94d6e520 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -498,6 +498,8 @@ export default { flash: 'flash', shutter: 'obturador', gallery: 'galería', + deleteReceipt: 'Eliminar recibo', + deleteConfirmation: '¿Estás seguro de que quieres borrar este recibo?', addReceipt: 'Añadir recibo', }, iou: { diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 68e782010982..bc6ee9be4e0b 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -2431,6 +2431,29 @@ function payMoneyRequest(paymentType, chatReport, iouReport) { Navigation.dismissModal(chatReport.reportID); } +function detachReceipt(transactionID) { + const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] || {}; + const newTransaction = {...transaction, filename: '', receipt: {}}; + + const optimisticData = [ + { + onyxMethod: Onyx.METHOD.SET, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, + value: newTransaction, + }, + ]; + + const failureData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, + value: transaction, + }, + ]; + + API.write('DetachReceipt', {transactionID}, {optimisticData, failureData}); +} + /** * @param {String} transactionID * @param {Object} receipt @@ -2663,5 +2686,6 @@ export { navigateToNextPage, updateDistanceRequest, replaceReceipt, + detachReceipt, getIOUReportID, };