Repository navigation
Add Scan to Split Bill and implement IOU action startSplitBill
#28710
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
Merged
Merged
Changes from all commits
Commits
Show all changes
41 commits
Select commit
Hold shift + click to select a range
d03ead5
Display 'Split' bill button in Scan flow
6231e7c
Hide $0 amounts in Split Bill
60ffec4
Add IOU action startSplitBillRequest
facfd16
Hide split amount if it's O
ec7610d
Add receipt status text in SplitBillDetailsPage
057fc00
Allow editing merchant and date when creating split bill
7361985
Fix navigation to newly created chat
04ec01c
Show TabSelector when using Split Bill from workspace chat
1404029
Display receipt in SplitBillDetailsPage
fbdf93d
Cleanup
9fd07bc
Fix splitting bill with unkown users
66c0ae2
Merge branch 'main' into youssef_startSplitBill
a51725a
Cleanup
3820323
Add JSDocs
51fbbf6
Remove created and merchant
6f8b808
Only display scan status when receipt is being scanned
19e5994
Cleanup
a1b79b0
Fix GH actions
2af470b
Sve policy expense chat reportID in splits array
53f28f3
Create optimistic details of participants if needed
98bd046
Merge branch 'main' into youssef_startSplitBill
027cc04
Show amount in split details page once it's created
23e5e2b
Show SmartScan fields in ReadOnly split details page
9b2b942
Rename receiptSource to receiptFilename
424132f
Add null check
2f99094
Bug fix
66616b4
Merge branch 'main' into youssef_startSplitBill
ceb1872
Apply suggestions from code review
10d24d0
Merge branch 'main' into youssef_startSplitBill
5c47140
Hide showMore button when there are no more fields to display
4083b0c
Merge branch 'main' into youssef_startSplitBill
e6de6c5
Fix navigation to split chat report
a5d29ba
Remove unnecessary param
92c9a42
Reverse changes in TransactionUtils
6c8f574
Apply suggestions from code review
5f7656b
Tidy up code
5527d4c
Add error to split chat created action on failure
3a7504e
Merge branch 'youssef_startSplitBill' of github.com:Expensify/App int…
25f0a2a
fix lint
ab6a140
Add comment
993f0ce
Save splits optimistically in the transaction comment
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -114,8 +114,8 @@ const propTypes = { | |
| /** File path of the receipt */ | ||
| receiptPath: PropTypes.string, | ||
|
|
||
| /** File source of the receipt */ | ||
| receiptSource: PropTypes.string, | ||
| /** File name of the receipt */ | ||
| receiptFilename: PropTypes.string, | ||
|
|
||
| /** List styles for OptionsSelector */ | ||
| listStyles: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), | ||
|
|
@@ -141,6 +141,9 @@ const propTypes = { | |
| /** Whether the money request is a distance request */ | ||
| isDistanceRequest: PropTypes.bool, | ||
|
|
||
| /** Whether the receipt associated with this report is being scanned */ | ||
| isScanning: PropTypes.bool, | ||
|
|
||
| /** A flag for verifying that the current report is a sub-report of a workspace chat */ | ||
| isPolicyExpenseChat: PropTypes.bool, | ||
|
|
||
|
|
@@ -171,14 +174,15 @@ const defaultProps = { | |
| reportID: '', | ||
| ...withCurrentUserPersonalDetailsDefaultProps, | ||
| receiptPath: '', | ||
| receiptSource: '', | ||
| receiptFilename: '', | ||
| listStyles: [], | ||
| policyCategories: {}, | ||
| policyTags: {}, | ||
| transactionID: '', | ||
| transaction: {}, | ||
| mileageRate: {unit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES, rate: 0, currency: 'USD'}, | ||
| isDistanceRequest: false, | ||
| isScanning: false, | ||
| isPolicyExpenseChat: false, | ||
| }; | ||
|
|
||
|
|
@@ -188,9 +192,6 @@ function MoneyRequestConfirmationList(props) { | |
| const {onSendMoney, onConfirm, onSelectParticipant, transaction} = props; | ||
| const {translate, toLocaleDigit} = useLocalize(); | ||
|
|
||
| // A flag and a toggler for showing the rest of the form fields | ||
| const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); | ||
| const shouldShowAllFields = props.isDistanceRequest || shouldExpandFields; | ||
| const isTypeRequest = props.iouType === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST; | ||
|
|
||
| const {unit, rate, currency} = props.mileageRate; | ||
|
|
@@ -201,6 +202,14 @@ function MoneyRequestConfirmationList(props) { | |
| const shouldShowCategories = | ||
| props.isPolicyExpenseChat && Permissions.canUseCategories(props.betas) && (props.iouCategory || OptionsListUtils.hasEnabledOptions(_.values(props.policyCategories))); | ||
|
|
||
| // A flag for showing SmartScan fields: date, merchant, and amount, only when we don't have a receiptPath (e.g. manual request) | ||
| // or in the split details page which is ReadOnly | ||
| const shouldShowSmartScanFields = (!props.receiptPath || props.isReadOnly) && !props.isScanning; | ||
|
|
||
| // A flag and a toggler for showing the rest of the form fields | ||
| const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); | ||
| const shouldShowAllFields = props.isDistanceRequest || shouldExpandFields || !shouldShowSmartScanFields; | ||
|
|
||
| // Fetches the first tag list of the policy | ||
| const policyTag = PolicyUtils.getTag(props.policyTags); | ||
| const policyTagList = lodashGet(policyTag, 'tags', {}); | ||
|
|
@@ -245,7 +254,10 @@ function MoneyRequestConfirmationList(props) { | |
| const getParticipantsWithAmount = useCallback( | ||
| (participantsList) => { | ||
| const iouAmount = IOUUtils.calculateAmount(participantsList.length, props.iouAmount, props.iouCurrencyCode); | ||
| return OptionsListUtils.getIOUConfirmationOptionsFromParticipants(participantsList, CurrencyUtils.convertToDisplayString(iouAmount, props.iouCurrencyCode)); | ||
| return OptionsListUtils.getIOUConfirmationOptionsFromParticipants( | ||
| participantsList, | ||
| props.iouAmount > 0 ? CurrencyUtils.convertToDisplayString(iouAmount, props.iouCurrencyCode) : '', | ||
| ); | ||
| }, | ||
| [props.iouAmount, props.iouCurrencyCode], | ||
| ); | ||
|
|
@@ -254,7 +266,9 @@ function MoneyRequestConfirmationList(props) { | |
|
|
||
| const splitOrRequestOptions = useMemo(() => { | ||
| let text; | ||
| if (props.receiptPath || isDistanceRequestWithoutRoute) { | ||
| if (props.receiptPath && props.hasMultipleParticipants && props.iouAmount === 0) { | ||
| text = translate('iou.split'); | ||
| } else if (props.receiptPath || isDistanceRequestWithoutRoute) { | ||
| text = translate('iou.request'); | ||
| } else { | ||
| const translationKey = props.hasMultipleParticipants ? 'iou.splitAmount' : 'iou.requestAmount'; | ||
|
|
@@ -266,7 +280,7 @@ function MoneyRequestConfirmationList(props) { | |
| value: props.hasMultipleParticipants ? CONST.IOU.MONEY_REQUEST_TYPE.SPLIT : CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, | ||
| }, | ||
| ]; | ||
| }, [props.hasMultipleParticipants, props.receiptPath, translate, formattedAmount, isDistanceRequestWithoutRoute]); | ||
| }, [props.hasMultipleParticipants, props.iouAmount, props.receiptPath, translate, formattedAmount, isDistanceRequestWithoutRoute]); | ||
|
|
||
| const selectedParticipants = useMemo(() => _.filter(props.selectedParticipants, (participant) => participant.selected), [props.selectedParticipants]); | ||
| const payeePersonalDetails = useMemo(() => props.payeePersonalDetails || props.currentUserPersonalDetails, [props.payeePersonalDetails, props.currentUserPersonalDetails]); | ||
|
|
@@ -290,7 +304,7 @@ function MoneyRequestConfirmationList(props) { | |
| const myIOUAmount = IOUUtils.calculateAmount(selectedParticipants.length, props.iouAmount, props.iouCurrencyCode, true); | ||
| const formattedPayeeOption = OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail( | ||
| payeePersonalDetails, | ||
| CurrencyUtils.convertToDisplayString(myIOUAmount, props.iouCurrencyCode), | ||
| props.iouAmount > 0 ? CurrencyUtils.convertToDisplayString(myIOUAmount, props.iouCurrencyCode) : '', | ||
| ); | ||
|
|
||
| sections.push( | ||
|
|
@@ -459,6 +473,9 @@ function MoneyRequestConfirmationList(props) { | |
| ); | ||
| }, [confirm, props.bankAccountRoute, props.iouCurrencyCode, props.iouType, props.isReadOnly, props.policyID, selectedParticipants, splitOrRequestOptions, translate, formError]); | ||
|
|
||
| const {image: receiptImage, thumbnail: receiptThumbnail} = | ||
| props.receiptPath && props.receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(props.receiptPath, props.receiptFilename) : {}; | ||
|
|
||
| return ( | ||
| <OptionsSelector | ||
| sections={optionSelectorSections} | ||
|
|
@@ -483,12 +500,17 @@ function MoneyRequestConfirmationList(props) { | |
| <ConfirmedRoute transactionID={props.transactionID} /> | ||
| </View> | ||
| )} | ||
| {!_.isEmpty(props.receiptPath) ? ( | ||
| {(receiptImage || receiptThumbnail) && ( | ||
| <Image | ||
| style={styles.moneyRequestImage} | ||
| source={{uri: ReceiptUtils.getThumbnailAndImageURIs(props.receiptPath, props.receiptSource).image}} | ||
| source={{uri: receiptThumbnail || receiptImage}} | ||
| // AuthToken is required when retrieving the image from the server | ||
| // but we don't need it to load the blob:// or file:// image when starting a money request / split bill | ||
| // So if we have a thumbnail, it means we're retrieving the image from the server | ||
| isAuthTokenRequired={!_.isEmpty(receiptThumbnail)} | ||
|
youssef-lr marked this conversation as resolved.
Resolved
|
||
| /> | ||
| ) : ( | ||
| )} | ||
| {shouldShowSmartScanFields && ( | ||
| <MenuItemWithTopDescription | ||
| shouldShowRightIcon={!props.isReadOnly && !props.isDistanceRequest} | ||
| title={formattedAmount} | ||
|
|
@@ -527,16 +549,18 @@ function MoneyRequestConfirmationList(props) { | |
| )} | ||
| {shouldShowAllFields && ( | ||
| <> | ||
| <MenuItemWithTopDescription | ||
| shouldShowRightIcon={!props.isReadOnly && isTypeRequest} | ||
| title={props.iouCreated || format(new Date(), CONST.DATE.FNS_FORMAT_STRING)} | ||
| description={translate('common.date')} | ||
| style={[styles.moneyRequestMenuItem]} | ||
| titleStyle={styles.flex1} | ||
| onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_DATE.getRoute(props.iouType, props.reportID))} | ||
| disabled={didConfirm || props.isReadOnly || !isTypeRequest} | ||
| /> | ||
| {props.isDistanceRequest ? ( | ||
| {shouldShowSmartScanFields && ( | ||
| <MenuItemWithTopDescription | ||
| shouldShowRightIcon={!props.isReadOnly && isTypeRequest} | ||
| title={props.iouCreated || format(new Date(), CONST.DATE.FNS_FORMAT_STRING)} | ||
| description={translate('common.date')} | ||
| style={[styles.moneyRequestMenuItem]} | ||
| titleStyle={styles.flex1} | ||
| onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_DATE.getRoute(props.iouType, props.reportID))} | ||
| disabled={didConfirm || props.isReadOnly} | ||
| /> | ||
| )} | ||
| {props.isDistanceRequest && ( | ||
| <MenuItemWithTopDescription | ||
| shouldShowRightIcon={!props.isReadOnly && isTypeRequest} | ||
| title={props.iouMerchant} | ||
|
|
@@ -546,15 +570,16 @@ function MoneyRequestConfirmationList(props) { | |
| onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_DISTANCE.getRoute(props.iouType, props.reportID))} | ||
| disabled={didConfirm || props.isReadOnly || !isTypeRequest} | ||
| /> | ||
| ) : ( | ||
| )} | ||
| {shouldShowSmartScanFields && ( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Coming from #29374. We should hide |
||
| <MenuItemWithTopDescription | ||
| shouldShowRightIcon={!props.isReadOnly && isTypeRequest} | ||
| title={props.iouMerchant} | ||
| description={translate('common.merchant')} | ||
| style={[styles.moneyRequestMenuItem]} | ||
| titleStyle={styles.flex1} | ||
| onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_MERCHANT.getRoute(props.iouType, props.reportID))} | ||
| disabled={didConfirm || props.isReadOnly || !isTypeRequest} | ||
| disabled={didConfirm || props.isReadOnly} | ||
| /> | ||
| )} | ||
| {shouldShowCategories && ( | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.