Skip to content

Commit

Permalink
Merge pull request #40386 from Expensify/youssef_uneven_splits_2
Browse files Browse the repository at this point in the history
  • Loading branch information
youssef-lr authored May 7, 2024
2 parents 7c774bd + c9021df commit 5259776
Show file tree
Hide file tree
Showing 23 changed files with 650 additions and 249 deletions.
5 changes: 5 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,11 @@ const CONST = {
URL: 'url',
},

INPUT_AUTOGROW_DIRECTION: {
LEFT: 'left',
RIGHT: 'right',
},

YOUR_LOCATION_TEXT: 'Your Location',

ATTACHMENT_MESSAGE_TEXT: '[Attachment]',
Expand Down
21 changes: 18 additions & 3 deletions src/components/AmountTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ type AmountTextInputProps = {
/** Style for the container */
touchableInputWrapperStyle?: StyleProp<ViewStyle>;

/** Whether to disable keyboard */
disableKeyboard?: boolean;

/** Function to call to handle key presses in the text input */
onKeyPress?: (event: NativeSyntheticEvent<KeyboardEvent>) => void;

Expand All @@ -36,22 +39,34 @@ type AmountTextInputProps = {
} & Pick<BaseTextInputProps, 'autoFocus'>;

function AmountTextInput(
{formattedAmount, onChangeAmount, placeholder, selection, onSelectionChange, style, touchableInputWrapperStyle, onKeyPress, containerStyle, ...rest}: AmountTextInputProps,
{
formattedAmount,
onChangeAmount,
placeholder,
selection,
onSelectionChange,
style,
touchableInputWrapperStyle,
onKeyPress,
containerStyle,
disableKeyboard = true,
...rest
}: AmountTextInputProps,
ref: ForwardedRef<BaseTextInputRef>,
) {
return (
<TextInput
disableKeyboard
autoGrow
hideFocusedState
shouldInterceptSwipe
disableKeyboard={disableKeyboard}
inputStyle={style}
textInputContainerStyles={containerStyle}
onChangeText={onChangeAmount}
ref={ref}
value={formattedAmount}
placeholder={placeholder}
inputMode={CONST.INPUT_MODE.NUMERIC}
inputMode={CONST.INPUT_MODE.DECIMAL}
blurOnSubmit={false}
selection={selection}
onSelectionChange={onSelectionChange}
Expand Down
56 changes: 47 additions & 9 deletions src/components/MoneyRequestAmountInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ type MoneyRequestAmountInputProps = {
/** Whether to hide the currency symbol */
hideCurrencySymbol?: boolean;

/** Whether to disable native keyboard on mobile */
disableKeyboard?: boolean;

/** Style for the prefix */
prefixStyle?: StyleProp<TextStyle>;

Expand All @@ -62,6 +65,11 @@ type MoneyRequestAmountInputProps = {

/** Style for the touchable input wrapper */
touchableInputWrapperStyle?: StyleProp<ViewStyle>;

/** Whether we want to format the display amount on blur */
formatAmountOnBlur?: boolean;

maxLength?: number;
};

type Selection = {
Expand All @@ -88,6 +96,9 @@ function MoneyRequestAmountInput(
hideCurrencySymbol = false,
shouldUpdateSelection = true,
moneyRequestAmountInputRef,
disableKeyboard = true,
formatAmountOnBlur,
maxLength,
...props
}: MoneyRequestAmountInputProps,
forwardedRef: ForwardedRef<BaseTextInputRef>,
Expand Down Expand Up @@ -117,9 +128,12 @@ function MoneyRequestAmountInput(
// Remove spaces from the newAmount value because Safari on iOS adds spaces when pasting a copied value
// More info: https://github.com/Expensify/App/issues/16974
const newAmountWithoutSpaces = MoneyRequestUtils.stripSpacesFromAmount(newAmount);
const finalAmount = newAmountWithoutSpaces.includes('.')
? MoneyRequestUtils.stripCommaFromAmount(newAmountWithoutSpaces)
: MoneyRequestUtils.replaceCommasWithPeriod(newAmountWithoutSpaces);
// Use a shallow copy of selection to trigger setSelection
// More info: https://github.com/Expensify/App/issues/16385
if (!MoneyRequestUtils.validateAmount(newAmountWithoutSpaces, decimals)) {
if (!MoneyRequestUtils.validateAmount(finalAmount, decimals)) {
setSelection((prevSelection) => ({...prevSelection}));
return;
}
Expand All @@ -128,7 +142,7 @@ function MoneyRequestAmountInput(

let hasSelectionBeenSet = false;
setCurrentAmount((prevAmount) => {
const strippedAmount = MoneyRequestUtils.stripCommaFromAmount(newAmountWithoutSpaces);
const strippedAmount = MoneyRequestUtils.stripCommaFromAmount(finalAmount);
const isForwardDelete = prevAmount.length > strippedAmount.length && forwardDeletePressedRef.current;
if (!hasSelectionBeenSet) {
hasSelectionBeenSet = true;
Expand Down Expand Up @@ -160,15 +174,21 @@ function MoneyRequestAmountInput(
}));

useEffect(() => {
if (!currency || typeof amount !== 'number') {
if (!currency || typeof amount !== 'number' || (formatAmountOnBlur && textInput.current?.isFocused())) {
return;
}
const frontendAmount = amount ? CurrencyUtils.convertToFrontendAmount(amount).toString() : '';
const frontendAmount = formatAmountOnBlur ? CurrencyUtils.convertToDisplayStringWithoutCurrency(amount, currency) : CurrencyUtils.convertToFrontendAmount(amount).toString();
setCurrentAmount(frontendAmount);
setSelection({
start: frontendAmount.length,
end: frontendAmount.length,
});

// Only update selection if the amount prop was changed from the outside and is not the same as the current amount we just computed
// In the line below the currentAmount is not immediately updated, it should still hold the previous value.
if (frontendAmount !== currentAmount) {
setSelection({
start: frontendAmount.length,
end: frontendAmount.length,
});
}

// we want to re-initialize the state only when the amount changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [amount]);
Expand Down Expand Up @@ -204,13 +224,30 @@ function MoneyRequestAmountInput(
forwardDeletePressedRef.current = key === 'delete' || ((operatingSystem === CONST.OS.MAC_OS || operatingSystem === CONST.OS.IOS) && nativeEvent?.ctrlKey && key === 'd');
};

const formatAmount = useCallback(() => {
if (!formatAmountOnBlur) {
return;
}
const formattedAmount = CurrencyUtils.convertToDisplayStringWithoutCurrency(amount, currency);
if (maxLength && formattedAmount.length > maxLength) {
return;
}
setCurrentAmount(formattedAmount);
setSelection({
start: formattedAmount.length,
end: formattedAmount.length,
});
}, [amount, currency, formatAmountOnBlur, maxLength]);

const formattedAmount = MoneyRequestUtils.replaceAllDigits(currentAmount, toLocaleDigit);

return (
<TextInputWithCurrencySymbol
disableKeyboard={disableKeyboard}
formattedAmount={formattedAmount}
onChangeAmount={setNewAmount}
onCurrencyButtonPress={onCurrencyButtonPress}
onBlur={formatAmount}
placeholder={numberFormat(0)}
ref={(ref) => {
if (typeof forwardedRef === 'function') {
Expand Down Expand Up @@ -241,11 +278,12 @@ function MoneyRequestAmountInput(
prefixStyle={props.prefixStyle}
prefixContainerStyle={props.prefixContainerStyle}
touchableInputWrapperStyle={props.touchableInputWrapperStyle}
maxLength={maxLength}
/>
);
}

MoneyRequestAmountInput.displayName = 'MoneyRequestAmountInput';

export default React.forwardRef(MoneyRequestAmountInput);
export type {CurrentMoney, MoneyRequestAmountInputRef};
export type {CurrentMoney, MoneyRequestAmountInputProps, MoneyRequestAmountInputRef};
Loading

0 comments on commit 5259776

Please sign in to comment.