Skip to content

Commit

Permalink
Merge pull request #18715 from 0xmiroslav/issue-18706-split-amount-io…
Browse files Browse the repository at this point in the history
…u-preview

show individual split amount on Bill Split IOU Previews
  • Loading branch information
mountiny authored May 14, 2023
2 parents 9b48b8e + f9b9377 commit 148517a
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 55 deletions.
4 changes: 2 additions & 2 deletions src/components/MoneyRequestConfirmationList.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class MoneyRequestConfirmationList extends Component {
* @returns {Array}
*/
getParticipantsWithAmount(participants) {
const iouAmount = IOUUtils.calculateAmount(participants, this.props.iouAmount);
const iouAmount = IOUUtils.calculateAmount(participants.length, this.props.iouAmount);
return OptionsListUtils.getIOUConfirmationOptionsFromParticipants(participants, CurrencyUtils.convertToDisplayString(iouAmount, this.props.iou.selectedCurrencyCode));
}

Expand Down Expand Up @@ -168,7 +168,7 @@ class MoneyRequestConfirmationList extends Component {
const formattedUnselectedParticipants = this.getParticipantsWithoutAmount(unselectedParticipants);
const formattedParticipants = _.union(formattedSelectedParticipants, formattedUnselectedParticipants);

const myIOUAmount = IOUUtils.calculateAmount(selectedParticipants, this.props.iouAmount, true);
const myIOUAmount = IOUUtils.calculateAmount(selectedParticipants.length, this.props.iouAmount, true);
const formattedMyPersonalDetails = OptionsListUtils.getIOUConfirmationOptionsFromMyPersonalDetail(
this.props.currentUserPersonalDetails,
CurrencyUtils.convertToDisplayString(myIOUAmount, this.props.iou.selectedCurrencyCode),
Expand Down
83 changes: 46 additions & 37 deletions src/components/Pressable/GenericPressable/BaseGenericPressable.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,45 +63,54 @@ const GenericPressable = forwardRef((props, ref) => {
return props.disabled || shouldBeDisabledByScreenReader;
}, [isScreenReaderActive, enableInScreenReaderStates, props.disabled]);

const onLongPressHandler = useCallback((event) => {
if (isDisabled) {
return;
}
if (!onLongPress) {
return;
}
if (shouldUseHapticsOnLongPress) {
HapticFeedback.longPress();
}
if (ref && ref.current) {
ref.current.blur();
}
onLongPress(event);

Accessibility.moveAccessibilityFocus(nextFocusRef);
}, [shouldUseHapticsOnLongPress, onLongPress, nextFocusRef, ref, isDisabled]);

const onPressHandler = useCallback((event) => {
if (isDisabled) {
return;
}
if (shouldUseHapticsOnPress) {
HapticFeedback.press();
}
if (ref && ref.current) {
ref.current.blur();
}
onPress(event);
const onLongPressHandler = useCallback(
(event) => {
if (isDisabled) {
return;
}
if (!onLongPress) {
return;
}
if (shouldUseHapticsOnLongPress) {
HapticFeedback.longPress();
}
if (ref && ref.current) {
ref.current.blur();
}
onLongPress(event);

Accessibility.moveAccessibilityFocus(nextFocusRef);
},
[shouldUseHapticsOnLongPress, onLongPress, nextFocusRef, ref, isDisabled],
);

Accessibility.moveAccessibilityFocus(nextFocusRef);
}, [shouldUseHapticsOnPress, onPress, nextFocusRef, ref, isDisabled]);
const onPressHandler = useCallback(
(event) => {
if (isDisabled) {
return;
}
if (shouldUseHapticsOnPress) {
HapticFeedback.press();
}
if (ref && ref.current) {
ref.current.blur();
}
onPress(event);

Accessibility.moveAccessibilityFocus(nextFocusRef);
},
[shouldUseHapticsOnPress, onPress, nextFocusRef, ref, isDisabled],
);

const onKeyPressHandler = useCallback((event) => {
if (event.key !== 'Enter') {
return;
}
onPressHandler(event);
}, [onPressHandler]);
const onKeyPressHandler = useCallback(
(event) => {
if (event.key !== 'Enter') {
return;
}
onPressHandler(event);
},
[onPressHandler],
);

useEffect(() => {
if (!keyboardShortcut) {
Expand Down
21 changes: 16 additions & 5 deletions src/components/ReportActionItem/IOUPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes
import {showContextMenuForReport} from '../ShowContextMenuContext';
import * as OptionsListUtils from '../../libs/OptionsListUtils';
import * as CurrencyUtils from '../../libs/CurrencyUtils';
import * as IOUUtils from '../../libs/IOUUtils';
import * as ReportUtils from '../../libs/ReportUtils';

const propTypes = {
Expand Down Expand Up @@ -225,11 +226,21 @@ const IOUPreview = (props) => {
)}
</View>

{!isCurrentUserManager && props.shouldShowPendingConversionMessage && (
<Text style={[styles.textLabel, styles.colorMuted]}>{props.translate('iou.pendingConversionMessage')}</Text>
)}

<Text style={[styles.colorMuted]}>{Str.htmlDecode(lodashGet(props.action, 'originalMessage.comment', ''))}</Text>
<View style={[styles.flexRow]}>
<View style={[styles.flex1]}>
{!isCurrentUserManager && props.shouldShowPendingConversionMessage && (
<Text style={[styles.textLabel, styles.colorMuted]}>{props.translate('iou.pendingConversionMessage')}</Text>
)}
<Text style={[styles.colorMuted]}>{Str.htmlDecode(lodashGet(props.action, 'originalMessage.comment', ''))}</Text>
</View>
{props.isBillSplit && !_.isEmpty(participantEmails) && (
<Text style={[styles.textLabel, styles.colorMuted, styles.ml1]}>
{props.translate('iou.amountEach', {
amount: CurrencyUtils.convertToDisplayString(IOUUtils.calculateAmount(participantEmails.length - 1, requestAmount), requestCurrency),
})}
</Text>
)}
</View>
</View>
</OfflineWithFeedback>
</View>
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ export default {
settlePaypalMe: 'Pay with PayPal.me',
requestAmount: ({amount}) => `request ${amount}`,
splitAmount: ({amount}) => `split ${amount}`,
amountEach: ({amount}) => `${amount} each`,
payerOwesAmount: ({payer, amount}) => `${payer} owes ${amount}`,
payerSettled: ({amount}) => `settled up ${amount}`,
noReimbursableExpenses: 'This report has an invalid amount',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ export default {
settlePaypalMe: 'Pagar con PayPal.me',
requestAmount: ({amount}) => `solicitar ${amount}`,
splitAmount: ({amount}) => `dividir ${amount}`,
amountEach: ({amount}) => `${amount} cada uno`,
payerOwesAmount: ({payer, amount}) => `${payer} debe ${amount}`,
payerSettled: ({amount}) => `pagado ${amount}`,
noReimbursableExpenses: 'El monto de este informe es inválido',
Expand Down
6 changes: 3 additions & 3 deletions src/libs/IOUUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import CONST from '../CONST';
/**
* Calculates the amount per user given a list of participants
*
* @param {Array} participants - List of logins for the participants in the chat. It should not include the current user's login.
* @param {Number} numberOfParticipants - Number of participants in the chat. It should not include the current user.
* @param {Number} total - IOU total amount in the smallest units of the currency
* @param {Boolean} isDefaultUser - Whether we are calculating the amount for the current user
* @returns {Number}
*/
function calculateAmount(participants, total, isDefaultUser = false) {
const totalParticipants = participants.length + 1;
function calculateAmount(numberOfParticipants, total, isDefaultUser = false) {
const totalParticipants = numberOfParticipants + 1;
const amountPerPerson = Math.round(total / totalParticipants);
let finalAmount = amountPerPerson;
if (isDefaultUser) {
Expand Down
4 changes: 2 additions & 2 deletions src/libs/actions/IOU.js
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,8 @@ function createSplitsAndOnyxData(participants, currentUserLogin, amount, comment
}

// Loop through participants creating individual chats, iouReports and reportActionIDs as needed
const splitAmount = IOUUtils.calculateAmount(participants, amount, false);
const splits = [{email: currentUserEmail, amount: IOUUtils.calculateAmount(participants, amount, true)}];
const splitAmount = IOUUtils.calculateAmount(participants.length, amount, false);
const splits = [{email: currentUserEmail, amount: IOUUtils.calculateAmount(participants.length, amount, true)}];

const hasMultipleParticipants = participants.length > 1;
_.each(participants, (participant) => {
Expand Down
12 changes: 6 additions & 6 deletions tests/unit/IOUUtilsTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,20 +137,20 @@ describe('IOUUtils', () => {

test('103 JPY split among 3 participants including the default user should be [35, 34, 34]', () => {
const participants = ['tonystark@expensify.com', 'reedrichards@expensify.com'];
expect(IOUUtils.calculateAmount(participants, 103, true)).toBe(35);
expect(IOUUtils.calculateAmount(participants, 103)).toBe(34);
expect(IOUUtils.calculateAmount(participants.length, 103, true)).toBe(35);
expect(IOUUtils.calculateAmount(participants.length, 103)).toBe(34);
});

test('10 AFN split among 4 participants including the default user should be [1, 3, 3, 3]', () => {
const participants = ['tonystark@expensify.com', 'reedrichards@expensify.com', 'suestorm@expensify.com'];
expect(IOUUtils.calculateAmount(participants, 10, true)).toBe(1);
expect(IOUUtils.calculateAmount(participants, 10)).toBe(3);
expect(IOUUtils.calculateAmount(participants.length, 10, true)).toBe(1);
expect(IOUUtils.calculateAmount(participants.length, 10)).toBe(3);
});

test('0.02 USD split among 4 participants including the default user should be [-1, 1, 1, 1]', () => {
const participants = ['tonystark@expensify.com', 'reedrichards@expensify.com', 'suestorm@expensify.com'];
expect(IOUUtils.calculateAmount(participants, 2, true)).toBe(-1);
expect(IOUUtils.calculateAmount(participants, 2)).toBe(1);
expect(IOUUtils.calculateAmount(participants.length, 2, true)).toBe(-1);
expect(IOUUtils.calculateAmount(participants.length, 2)).toBe(1);
});
});
});

0 comments on commit 148517a

Please sign in to comment.