Skip to content

Commit

Permalink
Merge pull request #53373 from Krishna2323/krishna2323/issue/fix2_49847
Browse files Browse the repository at this point in the history
  • Loading branch information
youssef-lr authored Dec 13, 2024
2 parents 10bfe9a + ebde15d commit 35c2a75
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 21 deletions.
2 changes: 2 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ const CONST = {
ANIMATION_GYROSCOPE_VALUE: 0.4,
ANIMATION_PAID_DURATION: 200,
ANIMATION_PAID_CHECKMARK_DELAY: 300,
ANIMATION_THUMBSUP_DURATION: 250,
ANIMATION_THUMBSUP_DELAY: 200,
ANIMATION_PAID_BUTTON_HIDE_DELAY: 1000,
BACKGROUND_IMAGE_TRANSITION_DURATION: 1000,
SCREEN_TRANSITION_END_TIMEOUT: 1000,
Expand Down
3 changes: 3 additions & 0 deletions src/components/ProcessMoneyReportHoldMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ function ProcessMoneyReportHoldMenu({

const onSubmit = (full: boolean) => {
if (isApprove) {
if (startAnimation) {
startAnimation();
}
IOU.approveMoneyRequest(moneyRequestReport, full);
if (!full && isLinkedTransactionHeld(Navigation.getTopmostReportActionId() ?? '-1', moneyRequestReport?.reportID ?? '')) {
Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(moneyRequestReport?.reportID ?? ''));
Expand Down
61 changes: 52 additions & 9 deletions src/components/ReportActionItem/ReportPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,18 +124,24 @@ function ReportPreview({
);

const [isPaidAnimationRunning, setIsPaidAnimationRunning] = useState(false);
const [isApprovedAnimationRunning, setIsApprovedAnimationRunning] = useState(false);
const [isHoldMenuVisible, setIsHoldMenuVisible] = useState(false);
const [requestType, setRequestType] = useState<ActionHandledType>();
const [paymentType, setPaymentType] = useState<PaymentMethodType>();

const getCanIOUBePaid = useCallback(
(onlyShowPayElsewhere = false) => IOU.canIOUBePaid(iouReport, chatReport, policy, allTransactions, onlyShowPayElsewhere),
(onlyShowPayElsewhere = false, shouldCheckApprovedState = true) =>
IOU.canIOUBePaid(iouReport, chatReport, policy, allTransactions, onlyShowPayElsewhere, undefined, undefined, shouldCheckApprovedState),
[iouReport, chatReport, policy, allTransactions],
);

const canIOUBePaid = useMemo(() => getCanIOUBePaid(), [getCanIOUBePaid]);
const canIOUBePaidAndApproved = useMemo(() => getCanIOUBePaid(false, false), [getCanIOUBePaid]);
const onlyShowPayElsewhere = useMemo(() => !canIOUBePaid && getCanIOUBePaid(true), [canIOUBePaid, getCanIOUBePaid]);
const shouldShowPayButton = isPaidAnimationRunning || canIOUBePaid || onlyShowPayElsewhere;
const shouldShowApproveButton = useMemo(() => IOU.canApproveIOU(iouReport, policy), [iouReport, policy]) || isApprovedAnimationRunning;

const shouldDisableApproveButton = shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport);

const {nonHeldAmount, fullAmount, hasValidNonHeldAmount} = ReportUtils.getNonHeldAndFullAmount(iouReport, shouldShowPayButton);
const hasOnlyHeldExpenses = ReportUtils.hasOnlyHeldExpenses(iouReport?.reportID ?? '');
Expand All @@ -151,12 +157,18 @@ function ReportPreview({
}));
const checkMarkScale = useSharedValue(iouSettled ? 1 : 0);

const isApproved = ReportUtils.isReportApproved(iouReport, action);
const thumbsUpScale = useSharedValue(isApproved ? 1 : 0);
const thumbsUpStyle = useAnimatedStyle(() => ({
...styles.defaultCheckmarkWrapper,
transform: [{scale: thumbsUpScale.get()}],
}));

const moneyRequestComment = action?.childLastMoneyRequestComment ?? '';
const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport);
const isInvoiceRoom = ReportUtils.isInvoiceRoom(chatReport);
const isOpenExpenseReport = isPolicyExpenseChat && ReportUtils.isOpenExpenseReport(iouReport);

const isApproved = ReportUtils.isReportApproved(iouReport, action);
const canAllowSettlement = ReportUtils.hasUpdatedTotal(iouReport, policy);
const numberOfRequests = allTransactions.length;
const transactionsWithReceipts = ReportUtils.getTransactionsWithReceipts(iouReportID);
Expand Down Expand Up @@ -207,11 +219,19 @@ function ReportPreview({
const {isDelegateAccessRestricted} = useDelegateUserDetails();
const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);

const stopAnimation = useCallback(() => setIsPaidAnimationRunning(false), []);
const stopAnimation = useCallback(() => {
setIsPaidAnimationRunning(false);
setIsApprovedAnimationRunning(false);
}, []);
const startAnimation = useCallback(() => {
setIsPaidAnimationRunning(true);
HapticFeedback.longPress();
}, []);
const startApprovedAnimation = useCallback(() => {
setIsApprovedAnimationRunning(true);
HapticFeedback.longPress();
}, []);

const confirmPayment = useCallback(
(type: PaymentMethodType | undefined, payAsBusiness?: boolean) => {
if (!type) {
Expand Down Expand Up @@ -243,6 +263,8 @@ function ReportPreview({
} else if (ReportUtils.hasHeldExpenses(iouReport?.reportID)) {
setIsHoldMenuVisible(true);
} else {
setIsApprovedAnimationRunning(true);
HapticFeedback.longPress();
IOU.approveMoneyRequest(iouReport, true);
}
};
Expand Down Expand Up @@ -340,9 +362,6 @@ function ReportPreview({
]);

const bankAccountRoute = ReportUtils.getBankAccountRoute(chatReport);
const shouldShowApproveButton = useMemo(() => IOU.canApproveIOU(iouReport, policy), [iouReport, policy]);

const shouldDisableApproveButton = shouldShowApproveButton && !ReportUtils.isAllowedToApproveExpenseReport(iouReport);

const shouldShowSettlementButton = (shouldShowPayButton || shouldShowApproveButton) && !showRTERViolationMessage && !shouldShowBrokenConnectionViolation;

Expand Down Expand Up @@ -427,7 +446,7 @@ function ReportPreview({
const shouldShowExportIntegrationButton = !shouldShowPayButton && !shouldShowSubmitButton && connectedIntegration && isAdmin && ReportUtils.canBeExported(iouReport);

useEffect(() => {
if (!isPaidAnimationRunning) {
if (!isPaidAnimationRunning || isApprovedAnimationRunning) {
return;
}

Expand All @@ -448,6 +467,14 @@ function ReportPreview({
checkMarkScale.set(isPaidAnimationRunning ? withDelay(CONST.ANIMATION_PAID_CHECKMARK_DELAY, withSpring(1, {duration: CONST.ANIMATION_PAID_DURATION})) : 1);
}, [isPaidAnimationRunning, iouSettled, checkMarkScale]);

useEffect(() => {
if (!isApproved) {
return;
}

thumbsUpScale.set(isApprovedAnimationRunning ? withDelay(CONST.ANIMATION_THUMBSUP_DELAY, withSpring(1, {duration: CONST.ANIMATION_THUMBSUP_DURATION})) : 1);
}, [isApproved, isApprovedAnimationRunning, thumbsUpScale]);

const openReportFromPreview = useCallback(() => {
Performance.markStart(CONST.TIMING.OPEN_REPORT_FROM_PREVIEW);
Timing.start(CONST.TIMING.OPEN_REPORT_FROM_PREVIEW);
Expand Down Expand Up @@ -483,7 +510,7 @@ function ReportPreview({
<View style={styles.expenseAndReportPreviewTextContainer}>
<View style={styles.flexRow}>
<Animated.View style={[styles.flex1, styles.flexRow, styles.alignItemsCenter, previewMessageStyle]}>
<Text style={[styles.textLabelSupporting, styles.lh16]}>{previewMessage}</Text>
<Text style={[styles.textLabelSupporting, styles.lh20]}>{previewMessage}</Text>
</Animated.View>
{shouldShowRBR && (
<Icon
Expand All @@ -510,6 +537,14 @@ function ReportPreview({
/>
</Animated.View>
)}
{isApproved && (
<Animated.View style={thumbsUpStyle}>
<Icon
src={Expensicons.ThumbsUp}
fill={theme.icon}
/>
</Animated.View>
)}
</View>
</View>
{shouldShowSubtitle && !!supportText && (
Expand Down Expand Up @@ -537,6 +572,8 @@ function ReportPreview({
shouldUseSuccessStyle={!hasHeldExpenses}
onlyShowPayElsewhere={onlyShowPayElsewhere}
isPaidAnimationRunning={isPaidAnimationRunning}
isApprovedAnimationRunning={isApprovedAnimationRunning}
canIOUBePaid={canIOUBePaidAndApproved || isPaidAnimationRunning}
onAnimationFinish={stopAnimation}
formattedAmount={getSettlementAmount() ?? ''}
currency={iouReport?.currency}
Expand Down Expand Up @@ -604,7 +641,13 @@ function ReportPreview({
chatReport={chatReport}
moneyRequestReport={iouReport}
transactionCount={numberOfRequests}
startAnimation={startAnimation}
startAnimation={() => {
if (requestType === CONST.IOU.REPORT_ACTION_TYPE.APPROVE) {
startApprovedAnimation();
} else {
startAnimation();
}
}}
/>
)}
</OfflineWithFeedback>
Expand Down
52 changes: 41 additions & 11 deletions src/components/SettlementButton/AnimatedSettlementButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,18 @@ import type SettlementButtonProps from './types';
type AnimatedSettlementButtonProps = SettlementButtonProps & {
isPaidAnimationRunning: boolean;
onAnimationFinish: () => void;
isApprovedAnimationRunning: boolean;
canIOUBePaid: boolean;
};

function AnimatedSettlementButton({isPaidAnimationRunning, onAnimationFinish, isDisabled, ...settlementButtonProps}: AnimatedSettlementButtonProps) {
function AnimatedSettlementButton({
isPaidAnimationRunning,
onAnimationFinish,
isApprovedAnimationRunning,
isDisabled,
canIOUBePaid,
...settlementButtonProps
}: AnimatedSettlementButtonProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const buttonScale = useSharedValue(1);
Expand All @@ -38,12 +47,13 @@ function AnimatedSettlementButton({isPaidAnimationRunning, onAnimationFinish, is
overflow: 'hidden',
marginTop: buttonMarginTop.get(),
}));
const buttonDisabledStyle = isPaidAnimationRunning
? {
opacity: 1,
...styles.cursorDefault,
}
: undefined;
const buttonDisabledStyle =
isPaidAnimationRunning || isApprovedAnimationRunning
? {
opacity: 1,
...styles.cursorDefault,
}
: undefined;

const resetAnimation = useCallback(() => {
buttonScale.set(1);
Expand All @@ -55,7 +65,7 @@ function AnimatedSettlementButton({isPaidAnimationRunning, onAnimationFinish, is
}, [buttonScale, buttonOpacity, paymentCompleteTextScale, paymentCompleteTextOpacity, height, buttonMarginTop, styles.expenseAndReportPreviewTextButtonContainer.gap]);

useEffect(() => {
if (!isPaidAnimationRunning) {
if (!isApprovedAnimationRunning && !isPaidAnimationRunning) {
resetAnimation();
return;
}
Expand All @@ -65,15 +75,30 @@ function AnimatedSettlementButton({isPaidAnimationRunning, onAnimationFinish, is

// Wait for the above animation + 1s delay before hiding the component
const totalDelay = CONST.ANIMATION_PAID_DURATION + CONST.ANIMATION_PAID_BUTTON_HIDE_DELAY;
const willShowPaymentButton = canIOUBePaid && isApprovedAnimationRunning;
height.set(
withDelay(
totalDelay,
withTiming(0, {duration: CONST.ANIMATION_PAID_DURATION}, () => runOnJS(onAnimationFinish)()),
withTiming(willShowPaymentButton ? variables.componentSizeNormal : 0, {duration: CONST.ANIMATION_PAID_DURATION}, () => runOnJS(onAnimationFinish)()),
),
);
buttonMarginTop.set(withDelay(totalDelay, withTiming(willShowPaymentButton ? styles.expenseAndReportPreviewTextButtonContainer.gap : 0, {duration: CONST.ANIMATION_PAID_DURATION})));
buttonMarginTop.set(withDelay(totalDelay, withTiming(0, {duration: CONST.ANIMATION_PAID_DURATION})));
paymentCompleteTextOpacity.set(withDelay(totalDelay, withTiming(0, {duration: CONST.ANIMATION_PAID_DURATION})));
}, [isPaidAnimationRunning, onAnimationFinish, buttonOpacity, buttonScale, height, paymentCompleteTextOpacity, paymentCompleteTextScale, buttonMarginTop, resetAnimation]);
}, [
isPaidAnimationRunning,
isApprovedAnimationRunning,
onAnimationFinish,
buttonOpacity,
buttonScale,
height,
paymentCompleteTextOpacity,
paymentCompleteTextScale,
buttonMarginTop,
resetAnimation,
canIOUBePaid,
styles.expenseAndReportPreviewTextButtonContainer.gap,
]);

return (
<Animated.View style={containerStyles}>
Expand All @@ -82,11 +107,16 @@ function AnimatedSettlementButton({isPaidAnimationRunning, onAnimationFinish, is
<Text style={[styles.buttonMediumText]}>{translate('iou.paymentComplete')}</Text>
</Animated.View>
)}
{isApprovedAnimationRunning && (
<Animated.View style={paymentCompleteTextStyles}>
<Text style={[styles.buttonMediumText]}>{translate('iou.approved')}</Text>
</Animated.View>
)}
<Animated.View style={buttonStyles}>
<SettlementButton
// eslint-disable-next-line react/jsx-props-no-spreading
{...settlementButtonProps}
isDisabled={isPaidAnimationRunning || isDisabled}
isDisabled={isPaidAnimationRunning || isApprovedAnimationRunning || isDisabled}
disabledStyle={buttonDisabledStyle}
/>
</Animated.View>
Expand Down
3 changes: 2 additions & 1 deletion src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7134,6 +7134,7 @@ function canIOUBePaid(
onlyShowPayElsewhere = false,
chatReportRNVP?: OnyxTypes.ReportNameValuePairs,
invoiceReceiverPolicy?: SearchPolicy,
shouldCheckApprovedState = true,
) {
const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(chatReport);
const reportNameValuePairs = chatReportRNVP ?? ReportUtils.getReportNameValuePairs(chatReport?.reportID);
Expand Down Expand Up @@ -7188,7 +7189,7 @@ function canIOUBePaid(
reimbursableSpend !== 0 &&
!isChatReportArchived &&
!isAutoReimbursable &&
!shouldBeApproved &&
(!shouldBeApproved || !shouldCheckApprovedState) &&
!isPayAtEndExpenseReport
);
}
Expand Down

0 comments on commit 35c2a75

Please sign in to comment.