diff --git a/assets/images/emptystate__routepending.svg b/assets/images/emptystate__routepending.svg index 90f3296d37d6..aba08554d02f 100644 --- a/assets/images/emptystate__routepending.svg +++ b/assets/images/emptystate__routepending.svg @@ -1 +1,18 @@ - \ No newline at end of file + + + + + + + + + diff --git a/src/components/BlockingViews/BlockingView.tsx b/src/components/BlockingViews/BlockingView.tsx index e5717de4a64f..066aa42237a7 100644 --- a/src/components/BlockingViews/BlockingView.tsx +++ b/src/components/BlockingViews/BlockingView.tsx @@ -1,6 +1,6 @@ import type {ImageContentFit} from 'expo-image'; import React, {useMemo} from 'react'; -import type {ImageSourcePropType, StyleProp, ViewStyle, WebStyle} from 'react-native'; +import type {ImageSourcePropType, StyleProp, TextStyle, ViewStyle, WebStyle} from 'react-native'; import {View} from 'react-native'; import type {SvgProps} from 'react-native-svg'; import type {MergeExclusive} from 'type-fest'; @@ -23,6 +23,9 @@ type BaseBlockingViewProps = { /** Subtitle message below the title */ subtitle?: string; + /** The style of the subtitle message */ + subtitleStyle?: StyleProp; + /** Link message below the subtitle */ linkKey?: TranslationPaths; @@ -79,6 +82,7 @@ function BlockingView({ iconColor, title, subtitle = '', + subtitleStyle, linkKey = 'notFound.goBackHome', shouldShowLink = false, iconWidth = variables.iconSizeSuperLarge, @@ -98,7 +102,7 @@ function BlockingView({ () => ( <> {shouldShowLink ? ( @@ -111,7 +115,7 @@ function BlockingView({ ) : null} ), - [styles, subtitle, shouldShowLink, linkKey, onLinkPress, translate], + [styles, subtitle, shouldShowLink, linkKey, onLinkPress, translate, subtitleStyle], ); const subtitleContent = useMemo(() => { diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx index d9cbbc8f248f..745535f3f03f 100644 --- a/src/components/ConfirmedRoute.tsx +++ b/src/components/ConfirmedRoute.tsx @@ -3,6 +3,7 @@ import type {ReactNode} from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import useNetwork from '@hooks/useNetwork'; +import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -27,17 +28,28 @@ type ConfirmedRouteProps = ConfirmedRoutePropsOnyxProps & { /** Transaction that stores the distance expense data */ transaction: OnyxEntry; + /** Whether the size of the route pending icon is smaller. */ + isSmallerIcon?: boolean; + + /** Whether it should have border radius */ + shouldHaveBorderRadius?: boolean; + + /** Whether it should display the Mapbox map only when the route/coordinates exist otherwise + * it will display pending map icon */ + requireRouteToDisplayMap?: boolean; + /** Whether the map is interactable or not */ interactive?: boolean; }; -function ConfirmedRoute({mapboxAccessToken, transaction, interactive}: ConfirmedRouteProps) { +function ConfirmedRoute({mapboxAccessToken, transaction, isSmallerIcon, shouldHaveBorderRadius = true, requireRouteToDisplayMap = false, interactive}: ConfirmedRouteProps) { const {isOffline} = useNetwork(); const {route0: route} = transaction?.routes ?? {}; const waypoints = transaction?.comment?.waypoints ?? {}; const coordinates = route?.geometry?.coordinates ?? []; const theme = useTheme(); const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); const getMarkerComponent = useCallback( (icon: IconAsset): ReactNode => ( @@ -90,7 +102,9 @@ function ConfirmedRoute({mapboxAccessToken, transaction, interactive}: Confirmed return MapboxToken.stop; }, []); - return !isOffline && Boolean(mapboxAccessToken?.token) ? ( + const shouldDisplayMap = !requireRouteToDisplayMap || !!coordinates.length; + + return !isOffline && Boolean(mapboxAccessToken?.token) && shouldDisplayMap ? ( } - style={[styles.mapView, styles.br4]} + style={[styles.mapView, shouldHaveBorderRadius && styles.br4]} waypoints={waypointMarkers} styleURL={CONST.MAPBOX.STYLE_URL} /> ) : ( - + ); } diff --git a/src/components/DistanceMapView/index.android.tsx b/src/components/DistanceMapView/index.android.tsx index 168a480c6100..629b05d7bccf 100644 --- a/src/components/DistanceMapView/index.android.tsx +++ b/src/components/DistanceMapView/index.android.tsx @@ -5,6 +5,7 @@ import * as Expensicons from '@components/Icon/Expensicons'; import MapView from '@components/MapView'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import type DistanceMapViewProps from './types'; @@ -13,6 +14,7 @@ function DistanceMapView({overlayStyle, ...rest}: DistanceMapViewProps) { const [isMapReady, setIsMapReady] = useState(false); const {isOffline} = useNetwork(); const {translate} = useLocalize(); + const theme = useTheme(); return ( <> @@ -33,6 +35,7 @@ function DistanceMapView({overlayStyle, ...rest}: DistanceMapViewProps) { title={translate('distance.mapPending.title')} subtitle={isOffline ? translate('distance.mapPending.subtitle') : translate('distance.mapPending.onlineSubtitle')} shouldShowLink={false} + iconColor={theme.border} /> )} diff --git a/src/components/MapView/MapViewTypes.ts b/src/components/MapView/MapViewTypes.ts index 40934308b0e1..41170694c9d2 100644 --- a/src/components/MapView/MapViewTypes.ts +++ b/src/components/MapView/MapViewTypes.ts @@ -38,6 +38,9 @@ type PendingMapViewProps = { /** Style applied to PendingMapView */ style?: StyleProp; + + /** Whether the size of the route pending icon is smaller. */ + isSmallerIcon?: boolean; }; // Initial state of the map diff --git a/src/components/MapView/PendingMapView.tsx b/src/components/MapView/PendingMapView.tsx index 32bf42a14b10..cc9829517154 100644 --- a/src/components/MapView/PendingMapView.tsx +++ b/src/components/MapView/PendingMapView.tsx @@ -4,28 +4,34 @@ import {View} from 'react-native'; import BlockingView from '@components/BlockingViews/BlockingView'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; +import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; import type {PendingMapViewProps} from './MapViewTypes'; -function PendingMapView({title = '', subtitle = '', style}: PendingMapViewProps) { +function PendingMapView({title = '', subtitle = '', style, isSmallerIcon = false}: PendingMapViewProps) { const hasTextContent = !_.isEmpty(title) || !_.isEmpty(subtitle); const styles = useThemeStyles(); + const theme = useTheme(); + const iconSize = isSmallerIcon ? variables.iconSizeSuperLarge : variables.iconSizeUltraLarge; return ( {hasTextContent ? ( ) : ( )} diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index 3331572ab625..94839ed1c961 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -3,7 +3,6 @@ import truncate from 'lodash/truncate'; import React, {useMemo} from 'react'; import {View} from 'react-native'; import type {GestureResponderEvent} from 'react-native'; -import ConfirmedRoute from '@components/ConfirmedRoute'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import {ReceiptScan} from '@components/Icon/Expensicons'; @@ -124,10 +123,7 @@ function MoneyRequestPreviewContent({ merchantOrDescription = description || ''; } - const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(transaction)] : []; - - const hasPendingWaypoints = transaction?.pendingFields?.waypoints; - const showMapAsImage = isDistanceRequest && hasPendingWaypoints; + const receiptImages = hasReceipt ? [{...ReceiptUtils.getThumbnailAndImageURIs(transaction), transaction}] : []; const getSettledMessage = (): string => { if (isCardTransaction) { @@ -254,15 +250,7 @@ function MoneyRequestPreviewContent({ !onPreviewPressed ? [styles.moneyRequestPreviewBox, containerStyles] : {}, ]} > - {showMapAsImage && ( - - - - )} - {!showMapAsImage && hasReceipt && ( + {hasReceipt && ( ); - const shouldShowMapOrReceipt = showMapAsImage || hasReceipt; const isReceiptAllowed = !isPaidReport && !isInvoice; const shouldShowReceiptEmptyState = isReceiptAllowed && !hasReceipt && !isApproved && !isSettled && (canEditReceipt || isAdmin || isApprover) && (canEditReceipt || ReportUtils.isPaidGroupPolicy(report)); @@ -330,7 +326,7 @@ function MoneyRequestView({ const receiptViolations = transactionViolations?.filter((violation) => receiptViolationNames.includes(violation.name)).map((violation) => ViolationsUtils.getViolationTranslation(violation, translate)) ?? []; const shouldShowNotesViolations = !isReceiptBeingScanned && canUseViolations && ReportUtils.isPaidGroupPolicy(report); - const shouldShowReceiptHeader = isReceiptAllowed && (shouldShowReceiptEmptyState || shouldShowMapOrReceipt) && canUseViolations && ReportUtils.isPaidGroupPolicy(report); + const shouldShowReceiptHeader = isReceiptAllowed && (shouldShowReceiptEmptyState || hasReceipt) && canUseViolations && ReportUtils.isPaidGroupPolicy(report); const errors = { ...(transaction?.errorFields?.route ?? transaction?.errors), @@ -347,7 +343,7 @@ function MoneyRequestView({ shouldShowAuditMessage={Boolean(shouldShowNotesViolations && didRceiptScanSucceed)} /> )} - {(shouldShowMapOrReceipt || errors) && ( + {(hasReceipt || errors) && ( - {shouldShowMapOrReceipt && ( + {hasReceipt && ( - {showMapAsImage ? ( - - ) : ( - - )} + )} @@ -400,7 +389,7 @@ function MoneyRequestView({ } /> )} - {!shouldShowReceiptEmptyState && !shouldShowMapOrReceipt && } + {!shouldShowReceiptEmptyState && !hasReceipt && } {shouldShowNotesViolations && } + + + ); + } + const attachmentModalSource = tryResolveUrlFromApiRoot(image ?? ''); const thumbnailSource = tryResolveUrlFromApiRoot(thumbnail ?? ''); const isEReceipt = transaction && TransactionUtils.hasEReceipt(transaction); - const isDistanceRequest = Boolean(transaction && TransactionUtils.isDistanceRequest(transaction)); let propsObj: ReceiptImageProps; diff --git a/src/components/ReportActionItem/ReportActionItemImages.tsx b/src/components/ReportActionItem/ReportActionItemImages.tsx index 5e3a26d3a870..f27596556c53 100644 --- a/src/components/ReportActionItem/ReportActionItemImages.tsx +++ b/src/components/ReportActionItem/ReportActionItemImages.tsx @@ -85,6 +85,7 @@ function ReportActionItemImages({images, size, total, isHovered = false}: Report transaction={transaction} isThumbnail={isThumbnail} isSingleImage={numberOfShownImages === 1} + shouldMapHaveBorderRadius={false} /> ); diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index be3b104018db..f30dd59168c8 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -141,7 +141,7 @@ function ReportPreview({ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const hasErrors = hasMissingSmartscanFields || (canUseViolations && ReportUtils.hasViolations(iouReportID, transactionViolations)) || ReportUtils.hasActionsWithErrors(iouReportID); const lastThreeTransactionsWithReceipts = transactionsWithReceipts.slice(-3); - const lastThreeReceipts = lastThreeTransactionsWithReceipts.map((transaction) => ReceiptUtils.getThumbnailAndImageURIs(transaction)); + const lastThreeReceipts = lastThreeTransactionsWithReceipts.map((transaction) => ({...ReceiptUtils.getThumbnailAndImageURIs(transaction), transaction})); const showRTERViolationMessage = numberOfRequests === 1 && TransactionUtils.hasPendingUI(allTransactions[0], TransactionUtils.getTransactionViolations(allTransactions[0]?.transactionID ?? '', transactionViolations)); diff --git a/src/styles/index.ts b/src/styles/index.ts index 9980a96f64ae..166123d136b9 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -4453,7 +4453,7 @@ const styles = (theme: ThemeColors) => }, mapPendingView: { - backgroundColor: theme.highlightBG, + backgroundColor: theme.hoverComponentBG, ...flex.flex1, borderRadius: variables.componentBorderRadiusLarge, }, diff --git a/src/styles/variables.ts b/src/styles/variables.ts index 6f1cac46d729..b45f37a811f3 100644 --- a/src/styles/variables.ts +++ b/src/styles/variables.ts @@ -82,7 +82,7 @@ export default { iconSizeXLarge: 28, iconSizeExtraLarge: 40, iconSizeSuperLarge: 60, - iconSizeUltraLarge: 120, + iconSizeUltraLarge: 80, iconBottomBar: 24, sidebarAvatarSize: 28, iconHeader: 48,