Skip to content

Commit

Permalink
Merge branch 'Expensify:main' into krishna2323/issue/32291
Browse files Browse the repository at this point in the history
  • Loading branch information
Krishna2323 authored Feb 21, 2024
2 parents b26de03 + c1e73ec commit 4506b55
Show file tree
Hide file tree
Showing 131 changed files with 1,267 additions and 1,658 deletions.
4 changes: 2 additions & 2 deletions __mocks__/@react-native-community/netinfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import {NetInfoCellularGeneration, NetInfoStateType} from '@react-native-communi
import type {addEventListener, configure, fetch, NetInfoState, refresh, useNetInfo} from '@react-native-community/netinfo';

const defaultState: NetInfoState = {
type: NetInfoStateType.cellular,
type: NetInfoStateType?.cellular,
isConnected: true,
isInternetReachable: true,
details: {
isConnectionExpensive: true,
cellularGeneration: NetInfoCellularGeneration['3g'],
cellularGeneration: NetInfoCellularGeneration?.['3g'],
carrier: 'T-Mobile',
},
};
Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001044305
versionName "1.4.43-5"
versionCode 1001044309
versionName "1.4.43-9"
}

flavorDimensions "default"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: Manage devices
description: Control which devices can access your Expensify account
---
<div id="expensify-classic" markdown="1">

You can see which devices have been used to access your Expensify account and even remove devices that you no longer want to have access to your account.

{% include info.html %}
This process is currently not available from the mobile app and must be completed from the Expensify website.
{% include end-info.html %}

1. Hover over Settings and click **Account**.
2. Under Account Details, scroll down to the Device Management section.
3. Click **Device Management** to expand the section.
4. Review the devices that have access to your account. To remove access for a specific device, click **Revoke** next to it.

</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: Set notifications
description: Select your Expensify notification preferences
---
<div id="expensify-classic" markdown="1">

{% include info.html %}
This process is currently not available from the mobile app and must be completed from the Expensify website.
{% include end-info.html %}

1. Hover over Settings and click **Account**.
2. Click the **Preferences** tab on the left.
3. Scroll down to the Contact Preferences section.
4. Select the checkbox for the types of notifications you wish to receive.
</div>
1 change: 1 addition & 0 deletions docs/redirects.csv
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ https://help.expensify.com/articles/expensify-classic/getting-started/Employees,
https://help.expensify.com/articles/expensify-classic/getting-started/Using-The-App,https://help.expensify.com/articles/expensify-classic/getting-started/Join-your-company's-workspace
https://help.expensify.com/articles/expensify-classic/getting-started/support/Expensify-Support,https://use.expensify.com/support
https://help.expensify.com/articles/expensify-classic/getting-started/Plan-Types,https://use.expensify.com/
https://help.expensify.com/articles/new-expensify/payments/Referral-Program,https://help.expensify.com/articles/expensify-classic/get-paid-back/Referral-Program
2 changes: 1 addition & 1 deletion ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.4.43.5</string>
<string>1.4.43.9</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.4.43.5</string>
<string>1.4.43.9</string>
</dict>
</plist>
2 changes: 1 addition & 1 deletion ios/NotificationServiceExtension/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<key>CFBundleShortVersionString</key>
<string>1.4.43</string>
<key>CFBundleVersion</key>
<string>1.4.43.5</string>
<string>1.4.43.9</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module.exports = {
`<rootDir>/?(*.)+(spec|test).${testFileExtension}`,
],
transform: {
'^.+\\.jsx?$': 'babel-jest',
'^.+\\.[jt]sx?$': 'babel-jest',
'^.+\\.svg?$': 'jest-transformer-svg',
},
transformIgnorePatterns: ['<rootDir>/node_modules/(?!react-native)/'],
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
"version": "1.4.43-5",
"version": "1.4.43-9",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Expand Down Expand Up @@ -50,8 +50,8 @@
"analyze-packages": "ANALYZE_BUNDLE=true webpack --config config/webpack/webpack.common.js --env envFile=.env.production",
"symbolicate:android": "npx metro-symbolicate android/app/build/generated/sourcemaps/react/release/index.android.bundle.map",
"symbolicate:ios": "npx metro-symbolicate main.jsbundle.map",
"test:e2e": "ts-node tests/e2e/testRunner.js --development --skipCheckout --skipInstallDeps --buildMode none",
"test:e2e:dev": "ts-node tests/e2e/testRunner.js --development --skipCheckout --config ./config.dev.js --buildMode skip --skipInstallDeps",
"test:e2e": "ts-node tests/e2e/testRunner.js --config ./config.local.ts",
"test:e2e:dev": "ts-node tests/e2e/testRunner.js --config ./config.dev.js",
"gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh",
"workflow-test": "./workflow_tests/scripts/runWorkflowTests.sh",
"workflow-test:generate": "ts-node workflow_tests/utils/preGenerateTest.js",
Expand Down
32 changes: 18 additions & 14 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,28 +84,28 @@ const ROUTES = {
SETTINGS_APP_DOWNLOAD_LINKS: 'settings/about/app-download-links',
SETTINGS_WALLET: 'settings/wallet',
SETTINGS_WALLET_DOMAINCARD: {
route: '/settings/wallet/card/:domain',
getRoute: (domain: string) => `/settings/wallet/card/${domain}` as const,
route: 'settings/wallet/card/:domain',
getRoute: (domain: string) => `settings/wallet/card/${domain}` as const,
},
SETTINGS_REPORT_FRAUD: {
route: '/settings/wallet/card/:domain/report-virtual-fraud',
getRoute: (domain: string) => `/settings/wallet/card/${domain}/report-virtual-fraud` as const,
route: 'settings/wallet/card/:domain/report-virtual-fraud',
getRoute: (domain: string) => `settings/wallet/card/${domain}/report-virtual-fraud` as const,
},
SETTINGS_WALLET_CARD_GET_PHYSICAL_NAME: {
route: '/settings/wallet/card/:domain/get-physical/name',
getRoute: (domain: string) => `/settings/wallet/card/${domain}/get-physical/name` as const,
route: 'settings/wallet/card/:domain/get-physical/name',
getRoute: (domain: string) => `settings/wallet/card/${domain}/get-physical/name` as const,
},
SETTINGS_WALLET_CARD_GET_PHYSICAL_PHONE: {
route: '/settings/wallet/card/:domain/get-physical/phone',
getRoute: (domain: string) => `/settings/wallet/card/${domain}/get-physical/phone` as const,
route: 'settings/wallet/card/:domain/get-physical/phone',
getRoute: (domain: string) => `settings/wallet/card/${domain}/get-physical/phone` as const,
},
SETTINGS_WALLET_CARD_GET_PHYSICAL_ADDRESS: {
route: '/settings/wallet/card/:domain/get-physical/address',
getRoute: (domain: string) => `/settings/wallet/card/${domain}/get-physical/address` as const,
route: 'settings/wallet/card/:domain/get-physical/address',
getRoute: (domain: string) => `settings/wallet/card/${domain}/get-physical/address` as const,
},
SETTINGS_WALLET_CARD_GET_PHYSICAL_CONFIRM: {
route: '/settings/wallet/card/:domain/get-physical/confirm',
getRoute: (domain: string) => `/settings/wallet/card/${domain}/get-physical/confirm` as const,
route: 'settings/wallet/card/:domain/get-physical/confirm',
getRoute: (domain: string) => `settings/wallet/card/${domain}/get-physical/confirm` as const,
},
SETTINGS_ADD_DEBIT_CARD: 'settings/wallet/add-debit-card',
SETTINGS_ADD_BANK_ACCOUNT: 'settings/wallet/add-bank-account',
Expand All @@ -117,8 +117,8 @@ const ROUTES = {
SETTINGS_WALLET_TRANSFER_BALANCE: 'settings/wallet/transfer-balance',
SETTINGS_WALLET_CHOOSE_TRANSFER_ACCOUNT: 'settings/wallet/choose-transfer-account',
SETTINGS_WALLET_REPORT_CARD_LOST_OR_DAMAGED: {
route: '/settings/wallet/card/:domain/report-card-lost-or-damaged',
getRoute: (domain: string) => `/settings/wallet/card/${domain}/report-card-lost-or-damaged` as const,
route: 'settings/wallet/card/:domain/report-card-lost-or-damaged',
getRoute: (domain: string) => `settings/wallet/card/${domain}/report-card-lost-or-damaged` as const,
},
SETTINGS_WALLET_CARD_ACTIVATE: {
route: 'settings/wallet/card/:domain/activate',
Expand Down Expand Up @@ -219,6 +219,10 @@ const ROUTES = {
route: 'r/:reportID/settings/who-can-post',
getRoute: (reportID: string) => `r/${reportID}/settings/who-can-post` as const,
},
REPORT_SETTINGS_VISIBILITY: {
route: 'r/:reportID/settings/visibility',
getRoute: (reportID: string) => `r/${reportID}/settings/visibility` as const,
},
SPLIT_BILL_DETAILS: {
route: 'r/:reportID/split/:reportActionID',
getRoute: (reportID: string, reportActionID: string) => `r/${reportID}/split/${reportActionID}` as const,
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ const SCREENS = {
ROOM_NAME: 'Report_Settings_Room_Name',
NOTIFICATION_PREFERENCES: 'Report_Settings_Notification_Preferences',
WRITE_CAPABILITY: 'Report_Settings_Write_Capability',
VISIBILITY: 'Report_Settings_Visibility',
},

NEW_TASK: {
Expand Down
19 changes: 17 additions & 2 deletions src/components/CountrySelector.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, {forwardRef, useEffect} from 'react';
import {useIsFocused} from '@react-navigation/native';
import React, {forwardRef, useEffect, useRef} from 'react';
import type {ForwardedRef} from 'react';
import {View} from 'react-native';
import useLocalize from '@hooks/useLocalize';
Expand All @@ -23,15 +24,28 @@ type CountrySelectorProps = {
/** inputID used by the Form component */
// eslint-disable-next-line react/no-unused-prop-types
inputID: string;

/** Callback to call when the picker modal is dismissed */
onBlur?: () => void;
};

function CountrySelector({errorText = '', value: countryCode, onInputChange}: CountrySelectorProps, ref: ForwardedRef<View>) {
function CountrySelector({errorText = '', value: countryCode, onInputChange, onBlur}: CountrySelectorProps, ref: ForwardedRef<View>) {
const styles = useThemeStyles();
const {translate} = useLocalize();

const title = countryCode ? translate(`allCountries.${countryCode}`) : '';
const countryTitleDescStyle = title.length === 0 ? styles.textNormal : null;

const didOpenContrySelector = useRef(false);
const isFocused = useIsFocused();
useEffect(() => {
if (!isFocused || !didOpenContrySelector.current) {
return;
}
didOpenContrySelector.current = false;
onBlur?.();
}, [isFocused, onBlur]);

useEffect(() => {
// This will cause the form to revalidate and remove any error related to country name
onInputChange(countryCode);
Expand All @@ -48,6 +62,7 @@ function CountrySelector({errorText = '', value: countryCode, onInputChange}: Co
description={translate('common.country')}
onPress={() => {
const activeRoute = Navigation.getActiveRouteWithoutParams();
didOpenContrySelector.current = true;
Navigation.navigate(ROUTES.SETTINGS_ADDRESS_COUNTRY.getRoute(countryCode ?? '', activeRoute));
}}
/>
Expand Down
2 changes: 2 additions & 0 deletions src/components/DatePicker/CalendarPicker/YearPickerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton';
import Modal from '@components/Modal';
import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/RadioListItem';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -79,6 +80,7 @@ function YearPickerModal({isVisible, years, currentYear = new Date().getFullYear
showScrollIndicator
shouldStopPropagation
shouldUseDynamicMaxToRenderPerBatch
ListItem={RadioListItem}
/>
</ScreenWrapper>
</Modal>
Expand Down
19 changes: 12 additions & 7 deletions src/components/DistanceRequest/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Report, Transaction} from '@src/types/onyx';
import type {WaypointCollection} from '@src/types/onyx/Transaction';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import DistanceRequestFooter from './DistanceRequestFooter';
import DistanceRequestRenderItem from './DistanceRequestRenderItem';

Expand Down Expand Up @@ -176,7 +177,7 @@ function DistanceRequest({transactionID = '', report, transaction, route, isEdit
);
};

const getError = () => {
const getError = useCallback(() => {
// Get route error if available else show the invalid number of waypoints error.
if (hasRouteError) {
return ErrorUtils.getLatestErrorField((transaction ?? {}) as Transaction, 'route');
Expand All @@ -186,8 +187,12 @@ function DistanceRequest({transactionID = '', report, transaction, route, isEdit
// eslint-disable-next-line @typescript-eslint/naming-convention
return {0: 'iou.error.atLeastTwoDifferentWaypoints'};
}
return {};
};

if (Object.keys(validatedWaypoints).length < Object.keys(waypoints).length) {
// eslint-disable-next-line @typescript-eslint/naming-convention
return {0: translate('iou.error.duplicateWaypointsErrorMessage')};
}
}, [translate, transaction, hasRouteError, validatedWaypoints, waypoints]);

const updateWaypoints = useCallback(
({data}: DraggableListData<string>) => {
Expand All @@ -211,7 +216,7 @@ function DistanceRequest({transactionID = '', report, transaction, route, isEdit

const submitWaypoints = useCallback(() => {
// If there is any error or loading state, don't let user go to next page.
if (Object.keys(validatedWaypoints).length < 2 || hasRouteError || isLoadingRoute || (isLoading && !isOffline)) {
if (!isEmptyObject(getError()) || isLoadingRoute || (isLoading && !isOffline)) {
setHasError(true);
return;
}
Expand All @@ -221,7 +226,7 @@ function DistanceRequest({transactionID = '', report, transaction, route, isEdit
}

onSubmit(waypoints);
}, [onSubmit, setHasError, hasRouteError, isLoadingRoute, isLoading, validatedWaypoints, waypoints, isEditingNewRequest, isEditingRequest, isOffline]);
}, [onSubmit, setHasError, getError, isLoadingRoute, isLoading, waypoints, isEditingNewRequest, isEditingRequest, isOffline]);

const content = (
<>
Expand Down Expand Up @@ -254,10 +259,10 @@ function DistanceRequest({transactionID = '', report, transaction, route, isEdit
</View>
<View style={[styles.w100, styles.pt2]}>
{/* Show error message if there is route error or there are less than 2 routes and user has tried submitting, */}
{((hasError && Object.keys(validatedWaypoints).length < 2) || hasRouteError) && (
{((hasError && !isEmptyObject(getError())) || hasRouteError) && (
<DotIndicatorMessage
style={[styles.mh4, styles.mv3]}
messages={getError()}
messages={getError() ?? {}}
type="error"
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ function AnchorRenderer({tnode, style, key}: AnchorRendererProps) {
// eslint-disable-next-line react/jsx-props-no-multi-spaces
target={htmlAttribs.target || '_blank'}
rel={htmlAttribs.rel || 'noopener noreferrer'}
style={[parentStyle, styles.textUnderlinePositionUnder, styles.textDecorationSkipInkNone, style]}
style={[style, parentStyle, styles.textUnderlinePositionUnder, styles.textDecorationSkipInkNone]}
key={key}
// Only pass the press handler for internal links. For public links or whitelisted internal links fallback to default link handling
onPress={internalNewExpensifyPath || internalExpensifyPath ? () => Link.openLink(attrHref, environmentURL, isAttachment) : undefined}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import Text from '@components/Text';
import UserDetailsTooltip from '@components/UserDetailsTooltip';
import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
Expand All @@ -27,7 +26,6 @@ type MentionUserRendererProps = WithCurrentUserPersonalDetailsProps & CustomRend
function MentionUserRenderer({style, tnode, TDefaultRenderer, currentUserPersonalDetails, ...defaultRendererProps}: MentionUserRendererProps) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {translate} = useLocalize();
const htmlAttribAccountID = tnode.attributes.accountid;
const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT;

Expand All @@ -39,7 +37,7 @@ function MentionUserRenderer({style, tnode, TDefaultRenderer, currentUserPersona
const user = personalDetails[htmlAttribAccountID];
accountID = parseInt(htmlAttribAccountID, 10);
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
displayNameOrLogin = LocalePhoneNumber.formatPhoneNumber(user?.login ?? '') || user?.displayName || translate('common.hidden');
displayNameOrLogin = PersonalDetailsUtils.getDisplayNameOrDefault(user, LocalePhoneNumber.formatPhoneNumber(user?.login ?? ''));
navigationRoute = ROUTES.PROFILE.getRoute(htmlAttribAccountID);
} else if ('data' in tnode && !isEmptyObject(tnode.data)) {
// We need to remove the LTR unicode and leading @ from data as it is not part of the login
Expand Down
5 changes: 4 additions & 1 deletion src/components/Image/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import React, {useEffect, useMemo} from 'react';
import {Image as RNImage} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import useNetwork from '@hooks/useNetwork';
import ONYXKEYS from '@src/ONYXKEYS';
import {defaultProps, imagePropTypes} from './imagePropTypes';
import RESIZE_MODES from './resizeModes';

function Image(props) {
const {source: propsSource, isAuthTokenRequired, onLoad, session} = props;
const {isOffline} = useNetwork();

/**
* Check if the image source is a URL - if so the `encryptedAuthToken` is appended
* to the source.
Expand Down Expand Up @@ -39,7 +42,7 @@ function Image(props) {
RNImage.getSize(source.uri, (width, height) => {
onLoad({nativeEvent: {width, height}});
});
}, [onLoad, source]);
}, [onLoad, source, isOffline]);

// Omit the props which the underlying RNImage won't use
const forwardedProps = _.omit(props, ['source', 'onLoad', 'session', 'isAuthTokenRequired']);
Expand Down
Loading

0 comments on commit 4506b55

Please sign in to comment.