Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow detaching receipts from transactions #26219

Merged
merged 44 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
6a458b7
Allow zIndex to be overridden
Beamanator Aug 29, 2023
c2aa62f
Allow overriding some modal styles from HeaderWithBackButton
Beamanator Aug 29, 2023
bfe6348
New attachment view header component
Beamanator Aug 29, 2023
9373871
Forgot to commit new style var
Beamanator Aug 29, 2023
73ba5b6
Finish transaction-get logic
Beamanator Aug 29, 2023
fe01307
Add optimistic and failure data
Beamanator Aug 29, 2023
c0f1198
Fixing up some lint errors
Beamanator Aug 29, 2023
e46307c
Navigate user back to receipt report after detaching
Beamanator Aug 29, 2023
802af8d
Add translations
Beamanator Aug 29, 2023
6491074
lint & prettify
Beamanator Aug 29, 2023
6283fa6
Merge branch 'main' of github.com:Expensify/App into beaman-addContex…
Beamanator Aug 30, 2023
dc50e8a
Merge branch 'main' of github.com:Expensify/App into beaman-addContex…
Beamanator Sep 1, 2023
776513e
Prop types fixes
Beamanator Sep 1, 2023
b46f19a
Merge branch 'main' of github.com:Expensify/App into beaman-addContex…
Beamanator Sep 19, 2023
d089863
Fix types
Beamanator Sep 19, 2023
b11ffb7
Merge branch 'main' of github.com:Expensify/App into beaman-addContex…
Beamanator Sep 20, 2023
f3087ee
Remove old version of custom header
Beamanator Sep 20, 2023
7c83e8c
Revert a few style updates
Beamanator Sep 20, 2023
eaa6671
Revert unused var
Beamanator Sep 20, 2023
ca054cf
Connect detachReceipt with transactionID
Beamanator Sep 20, 2023
0ae84f4
Merge branch 'main' of github.com:Expensify/App into beaman-addContex…
Beamanator Sep 21, 2023
cf3979a
Fix up logic
Beamanator Sep 21, 2023
64a4f68
revert a few old changes
Beamanator Sep 21, 2023
1c73f1f
move function to IOU.js
Gonals Sep 27, 2023
7aed7bc
hide if smartscanning
Gonals Sep 27, 2023
28bc51e
remove extras
Gonals Sep 27, 2023
8d6af6f
Better handle optimistic data
Gonals Sep 28, 2023
cc7ff5a
remove debug lines
Gonals Sep 28, 2023
22e636c
lint
Gonals Sep 28, 2023
9495751
Merge branch 'main' into beaman-addContextMenuForReceipts
Gonals Sep 28, 2023
9c3bff6
add confirm modal
Gonals Sep 28, 2023
a6de27f
hooks stuff
Gonals Sep 28, 2023
99fe73d
Merge branch 'main' into beaman-addContextMenuForReceipts
Gonals Oct 3, 2023
f0d73af
bunch of comments
Gonals Oct 3, 2023
b592c3c
remove unneded params
Gonals Oct 4, 2023
086fbd7
conflicts
Gonals Oct 4, 2023
b8ecb24
more conflicts
Gonals Oct 4, 2023
2902371
conflicts
Gonals Oct 9, 2023
4de580d
conflicts
Gonals Oct 9, 2023
0a52427
conflicts
Gonals Oct 10, 2023
dbce3ec
remove extra export
Gonals Oct 10, 2023
c3e4a26
fix confirm modal on ios
luacmartins Oct 11, 2023
bd019dd
Merge branch 'main' into beaman-addContextMenuForReceipts
luacmartins Oct 11, 2023
b976628
resolve conflicts
luacmartins Oct 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 62 additions & 13 deletions src/components/AttachmentModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -97,6 +103,7 @@ const defaultProps = {
allowDownload: false,
headerTitle: null,
report: {},
transaction: {},
onModalShow: () => {},
onModalHide: () => {},
onCarouselAttachmentChange: () => {},
Expand All @@ -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('');
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -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 (
<>
Expand Down Expand Up @@ -442,18 +469,30 @@ function AttachmentModal(props) {
)}
</SafeAreaConsumer>
)}
{isAttachmentReceipt ? (
<ConfirmModal
title={translate('receipt.deleteReceipt')}
isVisible={isDeleteReceiptConfirmModalVisible}
onConfirm={deleteAndCloseModal}
onCancel={closeConfirmModal}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fyi, if there are 2 Modals in a screen, we have to handle onClose callback on each Modal properly #31256 (comment). Otherwise, it will cause an issue here #30045

prompt={translate('receipt.deleteConfirmation')}
confirmText={translate('common.delete')}
cancelText={translate('common.cancel')}
danger
/>
) : (
<ConfirmModal
title={attachmentInvalidReasonTitle ? translate(attachmentInvalidReasonTitle) : ''}
onConfirm={closeConfirmModal}
onCancel={closeConfirmModal}
isVisible={isAttachmentInvalid}
prompt={attachmentInvalidReason ? translate(attachmentInvalidReason) : ''}
confirmText={translate('common.close')}
shouldShowCancelButton={false}
/>
)}
</Modal>

<ConfirmModal
title={attachmentInvalidReasonTitle ? translate(attachmentInvalidReasonTitle) : ''}
onConfirm={closeConfirmModal}
onCancel={closeConfirmModal}
isVisible={isAttachmentInvalid}
prompt={attachmentInvalidReason ? translate(attachmentInvalidReason) : ''}
confirmText={translate('common.close')}
shouldShowCancelButton={false}
/>

{props.children &&
props.children({
displayFileInModal: validateAndDisplayFileToUpload,
Expand All @@ -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'}`,
},
Expand Down
2 changes: 2 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
2 changes: 2 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
24 changes: 24 additions & 0 deletions src/libs/actions/IOU.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -2663,5 +2686,6 @@ export {
navigateToNextPage,
updateDistanceRequest,
replaceReceipt,
detachReceipt,
getIOUReportID,
};
Loading