Skip to content

Commit

Permalink
Merge pull request #34335 from rayane-djouah/Migrate-DistanceRequest-…
Browse files Browse the repository at this point in the history
…component-to-TypeScript

[TS migration] Migrate 'DistanceRequest' component to TypeScript
  • Loading branch information
AndrewGable authored Feb 15, 2024
2 parents bd69530 + c2d2808 commit 634f766
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 171 deletions.
7 changes: 1 addition & 6 deletions src/components/ConfirmedRoute.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,9 @@ import type IconAsset from '@src/types/utils/IconAsset';
import DistanceMapView from './DistanceMapView';
import * as Expensicons from './Icon/Expensicons';
import ImageSVG from './ImageSVG';
import type {WayPoint} from './MapView/MapViewTypes';
import PendingMapView from './MapView/PendingMapView';

type WayPoint = {
id: string;
coordinate: [number, number];
markerComponent: () => ReactNode;
};

type ConfirmedRoutePropsOnyxProps = {
/** Data about Mapbox token for calling Mapbox API */
mapboxAccessToken: OnyxEntry<MapboxAccessToken>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,77 +1,61 @@
import lodashGet from 'lodash/get';
import lodashIsNil from 'lodash/isNil';
import PropTypes from 'prop-types';
import React, {useMemo} from 'react';
import type {ReactNode} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import type {OnyxEntry} from 'react-native-onyx';
import Button from '@components/Button';
import DistanceMapView from '@components/DistanceMapView';
import * as Expensicons from '@components/Icon/Expensicons';
import ImageSVG from '@components/ImageSVG';
import transactionPropTypes from '@components/transactionPropTypes';
import type {WayPoint} from '@components/MapView/MapViewTypes';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import * as TransactionUtils from '@libs/TransactionUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {MapboxAccessToken} from '@src/types/onyx';
import type {WaypointCollection} from '@src/types/onyx/Transaction';
import type Transaction from '@src/types/onyx/Transaction';
import type IconAsset from '@src/types/utils/IconAsset';

const MAX_WAYPOINTS = 25;

const propTypes = {
type DistanceRequestFooterOnyxProps = {
/** Data about Mapbox token for calling Mapbox API */
mapboxAccessToken: OnyxEntry<MapboxAccessToken>;
};

type DistanceRequestFooterProps = DistanceRequestFooterOnyxProps & {
/** The waypoints for the distance request */
waypoints: PropTypes.objectOf(
PropTypes.shape({
lat: PropTypes.number,
lng: PropTypes.number,
address: PropTypes.string,
name: PropTypes.string,
}),
),
waypoints?: WaypointCollection;

/** Function to call when the user wants to add a new waypoint */
navigateToWaypointEditPage: PropTypes.func.isRequired,

/** Data about Mapbox token for calling Mapbox API */
mapboxAccessToken: PropTypes.shape({
/** Temporary token for Mapbox API */
token: PropTypes.string,

/** Time when the token will expire in ISO 8601 */
expiration: PropTypes.string,
}),
navigateToWaypointEditPage: (index: number) => void;

/** The transaction being interacted with */
transaction: transactionPropTypes,
transaction: OnyxEntry<Transaction>;
};

const defaultProps = {
waypoints: {},
mapboxAccessToken: {
token: '',
},
transaction: {},
};
function DistanceRequestFooter({waypoints, transaction, mapboxAccessToken, navigateToWaypointEditPage}) {
function DistanceRequestFooter({waypoints, transaction, mapboxAccessToken, navigateToWaypointEditPage}: DistanceRequestFooterProps) {
const theme = useTheme();
const styles = useThemeStyles();
const {translate} = useLocalize();

const numberOfWaypoints = _.size(waypoints);
const numberOfFilledWaypoints = _.size(_.filter(waypoints, (waypoint) => !_.isEmpty(waypoint)));
const numberOfWaypoints = Object.keys(waypoints ?? {}).length;
const numberOfFilledWaypoints = Object.values(waypoints ?? {}).filter((waypoint) => Object.keys(waypoint).length).length;
const lastWaypointIndex = numberOfWaypoints - 1;

const waypointMarkers = useMemo(
() =>
_.filter(
_.map(waypoints, (waypoint, key) => {
if (!waypoint || lodashIsNil(waypoint.lat) || lodashIsNil(waypoint.lng)) {
Object.entries(waypoints ?? {})
.map(([key, waypoint]) => {
if (!waypoint?.lat || !waypoint?.lng) {
return;
}

const index = TransactionUtils.getWaypointIndex(key);
let MarkerComponent;
let MarkerComponent: IconAsset;
if (index === 0) {
MarkerComponent = Expensicons.DotIndicatorUnfilled;
} else if (index === lastWaypointIndex) {
Expand All @@ -82,8 +66,8 @@ function DistanceRequestFooter({waypoints, transaction, mapboxAccessToken, navig

return {
id: `${waypoint.lng},${waypoint.lat},${index}`,
coordinate: [waypoint.lng, waypoint.lat],
markerComponent: () => (
coordinate: [waypoint.lng, waypoint.lat] as const,
markerComponent: (): ReactNode => (
<ImageSVG
src={MarkerComponent}
width={CONST.MAP_MARKER_SIZE}
Expand All @@ -92,9 +76,8 @@ function DistanceRequestFooter({waypoints, transaction, mapboxAccessToken, navig
/>
),
};
}),
(waypoint) => waypoint,
),
})
.filter((waypoint): waypoint is WayPoint => !!waypoint),
[waypoints, lastWaypointIndex, theme.icon],
);

Expand All @@ -105,7 +88,7 @@ function DistanceRequestFooter({waypoints, transaction, mapboxAccessToken, navig
<Button
small
icon={Expensicons.Plus}
onPress={() => navigateToWaypointEditPage(_.size(lodashGet(transaction, 'comment.waypoints', {})))}
onPress={() => navigateToWaypointEditPage(Object.keys(transaction?.comment?.waypoints ?? {}).length)}
text={translate('distance.addStop')}
isDisabled={numberOfWaypoints === MAX_WAYPOINTS}
innerStyles={[styles.ph10]}
Expand All @@ -114,14 +97,14 @@ function DistanceRequestFooter({waypoints, transaction, mapboxAccessToken, navig
)}
<View style={styles.mapViewContainer}>
<DistanceMapView
accessToken={mapboxAccessToken.token}
accessToken={mapboxAccessToken?.token ?? ''}
mapPadding={CONST.MAPBOX.PADDING}
pitchEnabled={false}
initialState={{
zoom: CONST.MAPBOX.DEFAULT_ZOOM,
location: lodashGet(waypointMarkers, [0, 'coordinate'], CONST.MAPBOX.DEFAULT_COORDINATE),
location: waypointMarkers?.[0]?.coordinate ?? (CONST.MAPBOX.DEFAULT_COORDINATE as [number, number]),
}}
directionCoordinates={lodashGet(transaction, 'routes.route0.geometry.coordinates', [])}
directionCoordinates={(transaction?.routes?.route0?.geometry?.coordinates as Array<[number, number]>) ?? []}
style={[styles.mapView, styles.mapEditView]}
waypoints={waypointMarkers}
styleURL={CONST.MAPBOX.STYLE_URL}
Expand All @@ -133,10 +116,8 @@ function DistanceRequestFooter({waypoints, transaction, mapboxAccessToken, navig
}

DistanceRequestFooter.displayName = 'DistanceRequestFooter';
DistanceRequestFooter.propTypes = propTypes;
DistanceRequestFooter.defaultProps = defaultProps;

export default withOnyx({
export default withOnyx<DistanceRequestFooterProps, DistanceRequestFooterOnyxProps>({
mapboxAccessToken: {
key: ONYXKEYS.MAPBOX_ACCESS_TOKEN,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,59 +1,41 @@
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React from 'react';
import _ from 'underscore';
import * as Expensicons from '@components/Icon/Expensicons';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
import useLocalize from '@hooks/useLocalize';
import useTheme from '@hooks/useTheme';
import type {TranslationPaths} from '@src/languages/types';
import type {WaypointCollection} from '@src/types/onyx/Transaction';

const propTypes = {
type DistanceRequestProps = {
/** The waypoints for the distance request */
waypoints: PropTypes.objectOf(
PropTypes.shape({
lat: PropTypes.number,
lng: PropTypes.number,
address: PropTypes.string,
name: PropTypes.string,
}),
),
waypoints?: WaypointCollection;

/** The index of the item */
item: PropTypes.string,
item?: string;

/** Function to call when the secondary interaction is triggered */
onSecondaryInteraction: PropTypes.func,
onSecondaryInteraction?: () => void;

/** Function to get the index of the item */
getIndex: PropTypes.func,
getIndex?: () => number;

/** Whether the item is active */
isActive: PropTypes.bool,
isActive?: boolean;

/** Function to call when the user clicks the item */
onPress: PropTypes.func,
onPress?: (index: number) => void;

/** Whether the item is disabled */
disabled: PropTypes.bool,
disabled?: boolean;
};

const defaultProps = {
waypoints: {},
item: '',
onSecondaryInteraction: () => {},
getIndex: () => {},
isActive: false,
onPress: () => {},
disabled: false,
};

function DistanceRequestRenderItem({waypoints, item, onSecondaryInteraction, getIndex, isActive, onPress, disabled}) {
function DistanceRequestRenderItem({waypoints, item = '', onSecondaryInteraction, getIndex, isActive = false, onPress = () => {}, disabled = false}: DistanceRequestProps) {
const theme = useTheme();
const {translate} = useLocalize();
const numberOfWaypoints = _.size(waypoints);
const numberOfWaypoints = Object.keys(waypoints ?? {}).length;
const lastWaypointIndex = numberOfWaypoints - 1;

const index = getIndex();
const index = getIndex?.() ?? -1;
let descriptionKey = 'distance.waypointDescription.';
let waypointIcon;
if (index === 0) {
Expand All @@ -67,12 +49,13 @@ function DistanceRequestRenderItem({waypoints, item, onSecondaryInteraction, get
waypointIcon = Expensicons.DotIndicator;
}

const waypoint = lodashGet(waypoints, [`waypoint${index}`], {});
const waypoint = waypoints?.[`waypoint${index}`] ?? {};
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
const title = waypoint.name || waypoint.address;

return (
<MenuItemWithTopDescription
description={translate(descriptionKey)}
description={translate(descriptionKey as TranslationPaths)}
title={title}
icon={Expensicons.DragHandles}
iconFill={theme.icon}
Expand All @@ -89,7 +72,5 @@ function DistanceRequestRenderItem({waypoints, item, onSecondaryInteraction, get
}

DistanceRequestRenderItem.displayName = 'DistanceRequestRenderItem';
DistanceRequestRenderItem.propTypes = propTypes;
DistanceRequestRenderItem.defaultProps = defaultProps;

export default DistanceRequestRenderItem;
Loading

0 comments on commit 634f766

Please sign in to comment.