Skip to content

Commit

Permalink
Merge pull request Expensify#33244 from kubabutkiewicz/ts-migration/I…
Browse files Browse the repository at this point in the history
…OUWaypoint/page

[TS migration] Migrate 'IOUWaypoint' page to TypeScript
  • Loading branch information
MonilBhavsar authored Feb 23, 2024
2 parents 539e269 + 1ff718c commit cd14830
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 163 deletions.
2 changes: 1 addition & 1 deletion src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,4 +546,4 @@ type Route = RouteIsPlainString extends true ? never : AllRoutes;

type HybridAppRoute = (typeof HYBRID_APP_ROUTES)[keyof typeof HYBRID_APP_ROUTES];

export type {Route, HybridAppRoute};
export type {Route, HybridAppRoute, AllRoutes};
10 changes: 5 additions & 5 deletions src/components/AddressSearch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ function AddressSearch(

const renderHeaderComponent = () => (
<>
{predefinedPlaces.length > 0 && (
{(predefinedPlaces?.length ?? 0) > 0 && (
<>
{/* This will show current location button in list if there are some recent destinations */}
{shouldShowCurrentLocationButton && (
Expand Down Expand Up @@ -339,7 +339,7 @@ function AddressSearch(
fetchDetails
suppressDefaultStyles
enablePoweredByContainer={false}
predefinedPlaces={predefinedPlaces}
predefinedPlaces={predefinedPlaces ?? undefined}
listEmptyComponent={listEmptyComponent}
listLoaderComponent={listLoader}
renderHeaderComponent={renderHeaderComponent}
Expand All @@ -348,7 +348,7 @@ function AddressSearch(
const subtitle = data.isPredefinedPlace ? data.description : data.structured_formatting.secondary_text;
return (
<View>
{title && <Text style={[styles.googleSearchText]}>{title}</Text>}
{!!title && <Text style={[styles.googleSearchText]}>{title}</Text>}
<Text style={[styles.textLabelSupporting]}>{subtitle}</Text>
</View>
);
Expand Down Expand Up @@ -398,10 +398,10 @@ function AddressSearch(
if (inputID) {
onInputChange?.(text);
} else {
onInputChange({street: text});
onInputChange?.({street: text});
}
// If the text is empty and we have no predefined places, we set displayListViewBorder to false to prevent UI flickering
if (!text && !predefinedPlaces.length) {
if (!text && !predefinedPlaces?.length) {
setDisplayListViewBorder(false);
}
},
Expand Down
6 changes: 4 additions & 2 deletions src/components/AddressSearch/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ type RenamedInputKeysProps = {
lat: string;
lng: string;
zipCode: string;
address?: string;
country?: string;
};

type OnPressProps = {
Expand Down Expand Up @@ -59,7 +61,7 @@ type AddressSearchProps = {
defaultValue?: string;

/** A callback function when the value of this field has changed */
onInputChange: (value: string | number | RenamedInputKeysProps | StreetValue, key?: string) => void;
onInputChange?: (value: string | number | RenamedInputKeysProps | StreetValue, key?: string) => void;

/** A callback function when an address has been auto-selected */
onPress?: (props: OnPressProps) => void;
Expand All @@ -74,7 +76,7 @@ type AddressSearchProps = {
canUseCurrentLocation?: boolean;

/** A list of predefined places that can be shown when the user isn't searching for something */
predefinedPlaces?: Place[];
predefinedPlaces?: Place[] | null;

/** A map of inputID key names */
renamedInputKeys: RenamedInputKeysProps;
Expand Down
11 changes: 7 additions & 4 deletions src/hooks/useLocationBias.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import {useMemo} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import type {UserLocation} from '@src/types/onyx';
import type {WaypointCollection} from '@src/types/onyx/Transaction';

/**
* Construct the rectangular boundary based on user location and waypoints
*/
export default function useLocationBias(allWaypoints: Record<string, {lng?: number; lat?: number}>, userLocation?: {latitude: number; longitude: number}) {
export default function useLocationBias(allWaypoints: WaypointCollection, userLocation?: OnyxEntry<UserLocation>) {
return useMemo(() => {
const hasFilledWaypointCount = Object.values(allWaypoints).some((waypoint) => Object.keys(waypoint).length > 0);
// If there are no filled wayPoints and if user's current location cannot be retrieved,
// it is futile to arrive at a biased location. Let's return
if (!hasFilledWaypointCount && userLocation === undefined) {
return null;
return undefined;
}

// Gather the longitudes and latitudes from filled waypoints.
Expand All @@ -29,8 +32,8 @@ export default function useLocationBias(allWaypoints: Record<string, {lng?: numb
// When no filled waypoints are available but the current location of the user is available,
// let us consider the current user's location to construct a rectangular bound
if (!hasFilledWaypointCount && userLocation !== undefined) {
longitudes.push(userLocation.longitude);
latitudes.push(userLocation.latitude);
longitudes.push(userLocation?.longitude ?? 0);
latitudes.push(userLocation?.latitude ?? 0);
}

// Extend the rectangular bound by 0.5 degree (roughly around 25-30 miles in US)
Expand Down
7 changes: 7 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,13 @@ type MoneyRequestNavigatorParamList = {
reportID: string;
backTo: string;
};
[SCREENS.MONEY_REQUEST.STEP_WAYPOINT]: {
iouType: ValueOf<typeof CONST.IOU.TYPE>;
reportID: string;
backTo: Routes | undefined;
action: ValueOf<typeof CONST.IOU.ACTION>;
pageIndex: string;
};
[SCREENS.MONEY_REQUEST.STEP_MERCHANT]: {
action: ValueOf<typeof CONST.IOU.ACTION>;
iouType: ValueOf<typeof CONST.IOU.TYPE>;
Expand Down
6 changes: 5 additions & 1 deletion src/libs/ValidationUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ function validateCardNumber(value: string): boolean {
/**
* Validating that this is a valid address (PO boxes are not allowed)
*/
function isValidAddress(value: string): boolean {
function isValidAddress(value: FormValue): boolean {
if (typeof value !== 'string') {
return false;
}

if (!CONST.REGEX.ANY_VALUE.test(value) || value.match(CONST.REGEX.EMOJIS)) {
return false;
}
Expand Down
12 changes: 7 additions & 5 deletions src/libs/actions/Transaction.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {isEqual} from 'lodash';
import lodashClone from 'lodash/clone';
import lodashHas from 'lodash/has';
import type {OnyxEntry} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import * as API from '@libs/API';
import type {GetRouteForDraftParams, GetRouteParams} from '@libs/API/parameters';
Expand Down Expand Up @@ -106,7 +107,7 @@ function saveWaypoint(transactionID: string, index: string, waypoint: RecentWayp
}
}

function removeWaypoint(transaction: Transaction, currentIndex: string, isDraft: boolean) {
function removeWaypoint(transaction: OnyxEntry<Transaction>, currentIndex: string, isDraft?: boolean) {
// Index comes from the route params and is a string
const index = Number(currentIndex);
const existingWaypoints = transaction?.comment?.waypoints ?? {};
Expand Down Expand Up @@ -134,9 +135,10 @@ function removeWaypoint(transaction: Transaction, currentIndex: string, isDraft:
// to remove nested keys while also preserving other object keys
// Doing a deep clone of the transaction to avoid mutating the original object and running into a cache issue when using Onyx.set
let newTransaction: Transaction = {
...transaction,
// eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
...(transaction as Transaction),
comment: {
...transaction.comment,
...transaction?.comment,
waypoints: reIndexedWaypoints,
},
// We want to reset the amount only for draft transactions (when creating the request).
Expand Down Expand Up @@ -164,10 +166,10 @@ function removeWaypoint(transaction: Transaction, currentIndex: string, isDraft:
};
}
if (isDraft) {
Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transaction.transactionID}`, newTransaction);
Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transaction?.transactionID}`, newTransaction);
return;
}
Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction.transactionID}`, newTransaction);
Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION}${transaction?.transactionID}`, newTransaction);
}

function getOnyxDataForRouteRequest(transactionID: string, isDraft = false): OnyxData {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,21 @@
import PropTypes from 'prop-types';
import type {StackScreenProps} from '@react-navigation/stack';
import React from 'react';
import {withOnyx} from 'react-native-onyx';
import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types';
import ONYXKEYS from '@src/ONYXKEYS';
import type SCREENS from '@src/SCREENS';
import IOURequestStepWaypoint from './request/step/IOURequestStepWaypoint';

const propTypes = {
/** The transactionID of this request */
transactionID: PropTypes.string,

/** Route params */
route: PropTypes.shape({
params: PropTypes.shape({
/** IOU type */
iouType: PropTypes.string,

/** Index of the waypoint being edited */
waypointIndex: PropTypes.string,
}),
}),
};

const defaultProps = {
transactionID: '',
route: {
params: {
iouType: '',
waypointIndex: '',
},
},
type MoneyRequestWaypointPageOnyxProps = {
transactionID: string | undefined;
};
type MoneyRequestWaypointPageProps = StackScreenProps<MoneyRequestNavigatorParamList, typeof SCREENS.MONEY_REQUEST.STEP_WAYPOINT> & MoneyRequestWaypointPageOnyxProps;

// This component is responsible for grabbing the transactionID from the IOU key
// You can't use Onyx props in the withOnyx mapping, so we need to set up and access the transactionID here, and then pass it down so that WaypointEditor can subscribe to the transaction.
function MoneyRequestWaypointPage({transactionID, route}) {
function MoneyRequestWaypointPage({transactionID = '', route}: MoneyRequestWaypointPageProps) {
return (
// @ts-expect-error TODO: Remove this once withFullTransactionOrNotFound(https://github.com/Expensify/App/issues/36123) is migrated to TypeScript.
<IOURequestStepWaypoint
// Put the transactionID into the route params so that WaypointEdit behaves the same when creating a new waypoint
// or editing an existing waypoint.
Expand All @@ -48,8 +30,7 @@ function MoneyRequestWaypointPage({transactionID, route}) {
}

MoneyRequestWaypointPage.displayName = 'MoneyRequestWaypointPage';
MoneyRequestWaypointPage.propTypes = propTypes;
MoneyRequestWaypointPage.defaultProps = defaultProps;
export default withOnyx({
transactionID: {key: ONYXKEYS.IOU, selector: (iou) => iou && iou.transactionID},

export default withOnyx<MoneyRequestWaypointPageProps, MoneyRequestWaypointPageOnyxProps>({
transactionID: {key: ONYXKEYS.IOU, selector: (iou) => iou?.transactionID},
})(MoneyRequestWaypointPage);
Loading

0 comments on commit cd14830

Please sign in to comment.