Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 0 additions & 2 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1494,8 +1494,6 @@ const CONST = {
WARM: 'warm',
REPORT_ACTION_ITEM_LAYOUT_DEBOUNCE_TIME: 1500,
SHOW_LOADING_SPINNER_DEBOUNCE_TIME: 250,
SKELETON_FADE_DURATION: 300,
SKELETON_SLIDE_DURATION: 1200,
TEST_TOOLS_MODAL_THROTTLE_TIME: 800,
TOOLTIP_SENSE: 1000,
TRIE_INITIALIZATION: 'trie_initialization',
Expand Down
85 changes: 50 additions & 35 deletions src/components/LoadingBar.tsx
Original file line number Diff line number Diff line change
@@ -1,68 +1,83 @@
import React, {useEffect} from 'react';
import {View} from 'react-native';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import Animated, {cancelAnimation, Easing, useAnimatedStyle, useSharedValue, withDelay, withRepeat, withSequence, withTiming} from 'react-native-reanimated';
import useThemeStyles from '@hooks/useThemeStyles';
import colors from '@styles/theme/colors';
import CONST from '@src/CONST';

type LoadingBarProps = {
// Whether to show the loading bar
// Whether or not to show the loading bar
shouldShow: boolean;
};

function LoadingBar({shouldShow}: LoadingBarProps) {
const left = useSharedValue(-30);
const left = useSharedValue(0);
const width = useSharedValue(0);
const opacity = useSharedValue(0);
const isAnimating = useSharedValue(false);
const styles = useThemeStyles();

useEffect(() => {
if (shouldShow && !isAnimating.get()) {
isAnimating.set(true);
opacity.set(withTiming(1, {duration: CONST.TIMING.SKELETON_FADE_DURATION}));
if (shouldShow) {
// eslint-disable-next-line react-compiler/react-compiler
left.set(0);
width.set(0);
opacity.set(withTiming(1, {duration: CONST.ANIMATED_PROGRESS_BAR_OPACITY_DURATION}));

left.set(
withTiming(100, {duration: CONST.TIMING.SKELETON_SLIDE_DURATION}, () => {
requestAnimationFrame(() => {
if (shouldShow) {
left.set(-30);
left.set(withTiming(100, {duration: CONST.TIMING.SKELETON_SLIDE_DURATION}));
} else {
opacity.set(
withTiming(0, {duration: CONST.TIMING.SKELETON_FADE_DURATION}, () => {
isAnimating.set(false);
}),
);
}
});
}),
withDelay(
CONST.ANIMATED_PROGRESS_BAR_DELAY,
withRepeat(
withSequence(
withTiming(0, {duration: 0}),
withTiming(0, {duration: CONST.ANIMATED_PROGRESS_BAR_DURATION, easing: Easing.bezier(0.65, 0, 0.35, 1)}),
withTiming(100, {duration: CONST.ANIMATED_PROGRESS_BAR_DURATION, easing: Easing.bezier(0.65, 0, 0.35, 1)}),
),
-1,
false,
),
),
);

width.set(
withDelay(
CONST.ANIMATED_PROGRESS_BAR_DELAY,
withRepeat(
withSequence(
withTiming(0, {duration: 0}),
withTiming(100, {duration: CONST.ANIMATED_PROGRESS_BAR_DURATION, easing: Easing.bezier(0.65, 0, 0.35, 1)}),
withTiming(0, {duration: CONST.ANIMATED_PROGRESS_BAR_DURATION, easing: Easing.bezier(0.65, 0, 0.35, 1)}),
),
-1,
false,
),
),
);
} else if (!shouldShow) {
} else {
opacity.set(
withTiming(0, {duration: CONST.TIMING.SKELETON_FADE_DURATION}, () => {
isAnimating.set(false);
withTiming(0, {duration: CONST.ANIMATED_PROGRESS_BAR_OPACITY_DURATION}, () => {
cancelAnimation(left);
cancelAnimation(width);
}),
);
}
// we want to update only when shouldShow changes
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, [shouldShow]);

const barStyle = useAnimatedStyle(() => ({
const animatedIndicatorStyle = useAnimatedStyle(() => ({
left: `${left.get()}%`,
width: '30%',
height: '100%',
backgroundColor: colors.green,
width: `${width.get()}%`,
}));

const animatedContainerStyle = useAnimatedStyle(() => ({
opacity: opacity.get(),
borderRadius: 2,
}));

return (
<View style={[styles.progressBarWrapper]}>
<Animated.View style={barStyle} />
</View>
<Animated.View style={[styles.progressBarWrapper, animatedContainerStyle]}>
<Animated.View style={[styles.progressBar, animatedIndicatorStyle]} />
</Animated.View>
);
}

LoadingBar.displayName = 'LoadingBar';
LoadingBar.displayName = 'ProgressBar';

export default LoadingBar;
3 changes: 3 additions & 0 deletions src/components/MoneyReportHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import DelegateNoAccessModal from './DelegateNoAccessModal';
import HeaderWithBackButton from './HeaderWithBackButton';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import LoadingBar from './LoadingBar';
import MoneyReportHeaderStatusBar from './MoneyReportHeaderStatusBar';
import type {MoneyRequestHeaderStatusBarProps} from './MoneyRequestHeaderStatusBar';
import MoneyRequestHeaderStatusBar from './MoneyRequestHeaderStatusBar';
Expand Down Expand Up @@ -234,6 +235,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea
const isMoreContentShown = shouldShowNextStep || shouldShowStatusBar || (shouldShowAnyButton && shouldUseNarrowLayout);
const {isDelegateAccessRestricted} = useDelegateUserDetails();
const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false);
const [isLoadingReportData] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA);

const isReportInRHP = route.name === SCREENS.SEARCH.REPORT_RHP;
const shouldDisplaySearchRouter = !isReportInRHP || isSmallScreenWidth;
Expand Down Expand Up @@ -528,6 +530,7 @@ function MoneyReportHeader({policy, report: moneyRequestReport, transactionThrea
)}
</View>
)}
<LoadingBar shouldShow={(isLoadingReportData && shouldUseNarrowLayout) ?? false} />
{isHoldMenuVisible && requestType !== undefined && (
<ProcessMoneyReportHoldMenu
nonHeldAmount={!hasOnlyHeldExpenses && hasValidNonHeldAmount ? nonHeldAmount : undefined}
Expand Down
3 changes: 3 additions & 0 deletions src/components/MoneyRequestHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import Button from './Button';
import HeaderWithBackButton from './HeaderWithBackButton';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import LoadingBar from './LoadingBar';
import type {MoneyRequestHeaderStatusBarProps} from './MoneyRequestHeaderStatusBar';
import MoneyRequestHeaderStatusBar from './MoneyRequestHeaderStatusBar';

Expand Down Expand Up @@ -67,6 +68,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
const transactionViolations = useTransactionViolations(transaction?.transactionID);

const [dismissedHoldUseExplanation, dismissedHoldUseExplanationResult] = useOnyx(ONYXKEYS.NVP_DISMISSED_HOLD_USE_EXPLANATION, {initialValue: true});
const [isLoadingReportData] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA);
const isLoadingHoldUseExplained = isLoadingOnyxValue(dismissedHoldUseExplanationResult);
const styles = useThemeStyles();
const theme = useTheme();
Expand Down Expand Up @@ -212,6 +214,7 @@ function MoneyRequestHeader({report, parentReportAction, policy, onBackButtonPre
/>
</View>
)}
<LoadingBar shouldShow={(isLoadingReportData && shouldUseNarrowLayout) ?? false} />
</View>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ function SkeletonViewLines({numberOfRows, shouldAnimate = true}: SkeletonViewLin
height={CONST.CHAT_SKELETON_VIEW.HEIGHT_FOR_ROW_COUNT[numberOfRows]}
backgroundColor={theme.skeletonLHNIn}
foregroundColor={theme.skeletonLHNOut}
speed={3}
style={styles.mr5}
>
<Circle
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import DateUtils from '@libs/DateUtils';
import DebugUtils from '@libs/DebugUtils';
import {canUseTouchScreen} from '@libs/DeviceCapabilities';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {DebugParamList} from '@libs/Navigation/types';
import {rand64} from '@libs/NumberUtils';
import * as NumberUtils from '@libs/NumberUtils';
import ReportActionItem from '@pages/home/report/ReportActionItem';
import Debug from '@userActions/Debug';
import CONST from '@src/CONST';
Expand All @@ -32,7 +32,7 @@ const getInitialReportAction = (reportID: string, session: OnyxEntry<Session>, p
DebugUtils.stringifyJSON({
actionName: CONST.REPORT.ACTIONS.TYPE.ADD_COMMENT,
reportID,
reportActionID: rand64(),
reportActionID: NumberUtils.rand64(),
created: DateUtils.getDBTime(),
actorAccountID: session?.accountID,
avatar: (session?.accountID && personalDetailsList?.[session.accountID]?.avatar) ?? '',
Expand Down Expand Up @@ -78,7 +78,7 @@ function DebugReportActionCreatePage({
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
shouldEnableKeyboardAvoidingView={false}
shouldEnableMinHeight={canUseTouchScreen()}
shouldEnableMinHeight={DeviceCapabilities.canUseTouchScreen()}
testID={DebugReportActionCreatePage.displayName}
>
{({safeAreaPaddingBottomStyle}) => (
Expand Down Expand Up @@ -107,6 +107,7 @@ function DebugReportActionCreatePage({
<ReportActionItem
action={JSON.parse(draftReportAction.replaceAll('\n', '')) as ReportAction}
report={{reportID}}
reportActions={[]}
parentReportAction={undefined}
displayAsGroup={false}
isMostRecentIOUReportAction={false}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function DebugReportActionPreview({reportAction, reportID}: DebugReportActionPre
<ReportActionItem
action={reportAction ?? ({} as ReportAction)}
report={report ?? ({} as Report)}
reportActions={[]}
parentReportAction={undefined}
displayAsGroup={false}
isMostRecentIOUReportAction={false}
Expand Down
8 changes: 4 additions & 4 deletions src/pages/TransactionDuplicate/DuplicateTransactionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {useOnyx} from 'react-native-onyx';
import useThemeStyles from '@hooks/useThemeStyles';
import {getOriginalMessage, getReportAction, isMoneyRequestAction} from '@libs/ReportActionsUtils';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import ReportActionItem from '@pages/home/report/ReportActionItem';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Transaction} from '@src/types/onyx';

Expand All @@ -21,7 +20,7 @@ function DuplicateTransactionItem(props: DuplicateTransactionItemProps) {

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/non-nullable-type-assertion-style
const action = Object.values(reportActions ?? {})?.find((reportAction) => {
const IOUTransactionID = isMoneyRequestAction(reportAction) ? getOriginalMessage(reportAction)?.IOUTransactionID : CONST.DEFAULT_NUMBER_ID;
const IOUTransactionID = ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction)?.IOUTransactionID : -1;
return IOUTransactionID === props.transaction?.transactionID;
});

Expand All @@ -34,8 +33,9 @@ function DuplicateTransactionItem(props: DuplicateTransactionItemProps) {
<ReportActionItem
action={action}
report={report}
parentReportAction={getReportAction(report?.parentReportID, report?.parentReportActionID)}
parentReportAction={ReportActionsUtils.getReportAction(report?.parentReportID ?? '', report?.parentReportActionID ?? '')}
index={props.index}
reportActions={Object.values(reportActions ?? {})}
displayAsGroup={false}
shouldDisplayNewMarker={false}
isMostRecentIOUReportAction={false}
Expand Down
3 changes: 3 additions & 0 deletions src/pages/home/HeaderView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import ConfirmModal from '@components/ConfirmModal';
import DisplayNames from '@components/DisplayNames';
import Icon from '@components/Icon';
import {BackArrow, CalendarSolid, DotIndicator, FallbackAvatar} from '@components/Icon/Expensicons';
import LoadingBar from '@components/LoadingBar';
import MultipleAvatars from '@components/MultipleAvatars';
import OfflineWithFeedback from '@components/OfflineWithFeedback';
import ParentNavigationSubtitle from '@components/ParentNavigationSubtitle';
Expand Down Expand Up @@ -106,6 +107,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
const [parentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(report?.parentReportID) ?? getNonEmptyStringOnyxID(report?.reportID)}`);
const policy = usePolicy(report?.policyID);
const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST);
const [isLoadingReportData] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA);
const [firstDayFreeTrial] = useOnyx(ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL);
const [lastDayFreeTrial] = useOnyx(ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL);
const [account] = useOnyx(ONYXKEYS.ACCOUNT);
Expand Down Expand Up @@ -392,6 +394,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked,
</View>
</View>
)}
<LoadingBar shouldShow={(isLoadingReportData && shouldUseNarrowLayout) ?? false} />
</View>
{shouldShowEarlyDiscountBanner && (
<EarlyDiscountBanner
Expand Down
2 changes: 1 addition & 1 deletion src/pages/home/ReportScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
<ReportActionsView
report={report}
reportActions={reportActions}
reportMetadata={reportMetadata}
isLoadingInitialReportActions={reportMetadata?.isLoadingInitialReportActions}
hasNewerActions={hasNewerActions}
hasOlderActions={hasOlderActions}
parentReportAction={parentReportAction}
Expand Down
5 changes: 5 additions & 0 deletions src/pages/home/report/PureReportActionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ type PureReportActionItemProps = {
/** The transaction thread report associated with the report for this action, if any */
transactionThreadReport?: OnyxEntry<OnyxTypes.Report>;

/** Array of report actions for the report for this action */
// eslint-disable-next-line react/no-unused-prop-types
reportActions: OnyxTypes.ReportAction[];

/** Report action belonging to the report's parent */
parentReportAction: OnyxEntry<OnyxTypes.ReportAction>;

Expand Down Expand Up @@ -1298,6 +1302,7 @@ export default memo(PureReportActionItem, (prevProps, nextProps) => {
prevProps.linkedReportActionID === nextProps.linkedReportActionID &&
lodashIsEqual(prevProps.report?.fieldList, nextProps.report?.fieldList) &&
lodashIsEqual(prevProps.transactionThreadReport, nextProps.transactionThreadReport) &&
lodashIsEqual(prevProps.reportActions, nextProps.reportActions) &&
lodashIsEqual(prevParentReportAction, nextParentReportAction) &&
prevProps.draftMessage === nextProps.draftMessage &&
prevProps.iouReport?.reportID === nextProps.iouReport?.reportID &&
Expand Down
5 changes: 5 additions & 0 deletions src/pages/home/report/ReportActionItemParentAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ type ReportActionItemParentActionProps = {
/** The transaction thread report associated with the current report, if any */
transactionThreadReport: OnyxEntry<OnyxTypes.Report>;

/** Array of report actions for this report */
reportActions: OnyxTypes.ReportAction[];

/** Report actions belonging to the report's parent */
parentReportAction: OnyxEntry<OnyxTypes.ReportAction>;

Expand All @@ -52,6 +55,7 @@ type ReportActionItemParentActionProps = {
function ReportActionItemParentAction({
report,
transactionThreadReport,
reportActions,
parentReportAction,
index = 0,
shouldHideThreadDividerLine = false,
Expand Down Expand Up @@ -140,6 +144,7 @@ function ReportActionItemParentAction({
}
parentReportAction={parentReportAction}
report={ancestor.report}
reportActions={reportActions}
transactionThreadReport={transactionThreadReport}
action={ancestor.reportAction}
displayAsGroup={false}
Expand Down
3 changes: 2 additions & 1 deletion src/pages/home/report/ReportActionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,6 @@ function ReportActionsList({
}, [report.reportID]);

const prevUnreadMarkerReportActionID = useRef<string | null>(null);

/**
* Whether a message is NOT from the active user and it was received while the user was offline.
*/
Expand Down Expand Up @@ -622,6 +621,7 @@ function ReportActionsList({
({item: reportAction, index}: ListRenderItemInfo<OnyxTypes.ReportAction>) => (
<ReportActionsListItemRenderer
reportAction={reportAction}
reportActions={sortedReportActions}
parentReportAction={parentReportAction}
parentReportActionForTransactionThread={parentReportActionForTransactionThread}
index={index}
Expand All @@ -647,6 +647,7 @@ function ReportActionsList({
mostRecentIOUReportActionID,
shouldHideThreadDividerLine,
parentReportAction,
sortedReportActions,
transactionThreadReport,
parentReportActionForTransactionThread,
shouldUseThreadDividerLine,
Expand Down
6 changes: 6 additions & 0 deletions src/pages/home/report/ReportActionsListItemRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ type ReportActionsListItemRendererProps = {
/** All the data of the action item */
reportAction: ReportAction;

/** Array of report actions for the report */
reportActions: ReportAction[];

/** The report's parentReportAction */
parentReportAction: OnyxEntry<ReportAction>;

Expand Down Expand Up @@ -53,6 +56,7 @@ type ReportActionsListItemRendererProps = {

function ReportActionsListItemRenderer({
reportAction,
reportActions = [],
parentReportAction,
index,
report,
Expand Down Expand Up @@ -148,6 +152,7 @@ function ReportActionsListItemRenderer({
parentReportAction={parentReportAction}
reportID={report.reportID}
report={report}
reportActions={reportActions}
transactionThreadReport={transactionThreadReport}
index={index}
isFirstVisibleReportAction={isFirstVisibleReportAction}
Expand All @@ -164,6 +169,7 @@ function ReportActionsListItemRenderer({
transactionThreadReport={transactionThreadReport}
parentReportActionForTransactionThread={parentReportActionForTransactionThread}
action={action}
reportActions={reportActions}
linkedReportActionID={linkedReportActionID}
displayAsGroup={displayAsGroup}
shouldDisplayNewMarker={shouldDisplayNewMarker}
Expand Down
Loading