Skip to content

Commit

Permalink
Merge branch 'main' into fix-focus-when-editing-message
Browse files Browse the repository at this point in the history
  • Loading branch information
mateuuszzzzz committed Feb 5, 2025
2 parents ca36e87 + 81bdb03 commit 7058ee0
Show file tree
Hide file tree
Showing 17 changed files with 207 additions and 238 deletions.
2 changes: 1 addition & 1 deletion Mobile-Expensify
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1009009408
versionName "9.0.94-8"
versionCode 1009009410
versionName "9.0.94-10"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>9.0.94.8</string>
<string>9.0.94.10</string>
<key>FullStory</key>
<dict>
<key>OrgId</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>9.0.94.8</string>
<string>9.0.94.10</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>9.0.94</string>
<key>CFBundleVersion</key>
<string>9.0.94.8</string>
<string>9.0.94.10</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
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.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
"version": "9.0.94-8",
"version": "9.0.94-10",
"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
120 changes: 120 additions & 0 deletions src/components/BookTravelButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import {Str} from 'expensify-common';
import React, {useCallback, useContext, useState} from 'react';
import {NativeModules} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import useLocalize from '@hooks/useLocalize';
import usePolicy from '@hooks/usePolicy';
import useThemeStyles from '@hooks/useThemeStyles';
import {openTravelDotLink} from '@libs/actions/Link';
import {cleanupTravelProvisioningSession} from '@libs/actions/Travel';
import Log from '@libs/Log';
import Navigation from '@libs/Navigation/Navigation';
import {getAdminsPrivateEmailDomains} from '@libs/PolicyUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import Button from './Button';
import CustomStatusBarAndBackgroundContext from './CustomStatusBarAndBackground/CustomStatusBarAndBackgroundContext';
import DotIndicatorMessage from './DotIndicatorMessage';

type BookTravelButtonProps = {
text: string;
};

const navigateToAcceptTerms = (domain: string) => {
// Remove the previous provision session infromation if any is cached.
cleanupTravelProvisioningSession();
Navigation.navigate(ROUTES.TRAVEL_TCS.getRoute(domain));
};

function BookTravelButton({text}: BookTravelButtonProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
const policy = usePolicy(activePolicyID);
const [errorMessage, setErrorMessage] = useState('');
const [travelSettings] = useOnyx(ONYXKEYS.NVP_TRAVEL_SETTINGS);
const [account] = useOnyx(ONYXKEYS.ACCOUNT);
const primaryLogin = account?.primaryLogin;
const {setRootStatusBarEnabled} = useContext(CustomStatusBarAndBackgroundContext);

// Flag indicating whether NewDot was launched exclusively for Travel,
// e.g., when the user selects "Trips" from the Expensify Classic menu in HybridApp.
const [wasNewDotLaunchedJustForTravel] = useOnyx(ONYXKEYS.IS_SINGLE_NEW_DOT_ENTRY);

const bookATrip = useCallback(() => {
setErrorMessage('');

// The primary login of the user is where Spotnana sends the emails with booking confirmations, itinerary etc. It can't be a phone number.
if (!primaryLogin || Str.isSMSLogin(primaryLogin)) {
setErrorMessage(translate('travel.phoneError'));
return;
}

// Spotnana requires an address anytime an entity is created for a policy
if (isEmptyObject(policy?.address)) {
Navigation.navigate(ROUTES.WORKSPACE_PROFILE_ADDRESS.getRoute(policy?.id, Navigation.getActiveRoute()));
return;
}

const isPolicyProvisioned = policy?.travelSettings?.spotnanaCompanyID ?? policy?.travelSettings?.associatedTravelDomainAccountID;
if (policy?.travelSettings?.hasAcceptedTerms ?? (travelSettings?.hasAcceptedTerms && isPolicyProvisioned)) {
openTravelDotLink(policy?.id)
?.then(() => {
// When a user selects "Trips" in the Expensify Classic menu, the HybridApp opens the ManageTrips page in NewDot.
// The wasNewDotLaunchedJustForTravel flag indicates if NewDot was launched solely for this purpose.
if (!NativeModules.HybridAppModule || !wasNewDotLaunchedJustForTravel) {
return;
}

// Close NewDot if it was opened only for Travel, as its purpose is now fulfilled.
Log.info('[HybridApp] Returning to OldDot after opening TravelDot');
NativeModules.HybridAppModule.closeReactNativeApp(false, false);
setRootStatusBarEnabled(false);
})
?.catch(() => {
setErrorMessage(translate('travel.errorMessage'));
});
} else if (isPolicyProvisioned) {
navigateToAcceptTerms(CONST.TRAVEL.DEFAULT_DOMAIN);
} else {
// Determine the domain to associate with the workspace during provisioning in Spotnana.
// - If all admins share the same private domain, the workspace is tied to it automatically.
// - If admins have multiple private domains, the user must select one.
// - Public domains are not allowed; an error page is shown in that case.
const adminDomains = getAdminsPrivateEmailDomains(policy);
if (adminDomains.length === 0) {
Navigation.navigate(ROUTES.TRAVEL_PUBLIC_DOMAIN_ERROR);
} else if (adminDomains.length === 1) {
navigateToAcceptTerms(adminDomains.at(0) ?? CONST.TRAVEL.DEFAULT_DOMAIN);
} else {
Navigation.navigate(ROUTES.TRAVEL_DOMAIN_SELECTOR);
}
}
}, [policy, wasNewDotLaunchedJustForTravel, travelSettings, translate, primaryLogin, setRootStatusBarEnabled]);

return (
<>
{!!errorMessage && (
<DotIndicatorMessage
style={styles.mb1}
messages={{error: errorMessage}}
type="error"
/>
)}
<Button
text={text}
onPress={bookATrip}
accessibilityLabel={translate('travel.bookTravel')}
style={styles.w100}
success
large
/>
</>
);
}

BookTravelButton.displayName = 'BookTravelButton';

export default BookTravelButton;
4 changes: 3 additions & 1 deletion src/components/EmptyStateComponent/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function EmptyStateComponent({
title,
titleStyles,
subtitle,
children,
headerStyles,
headerContentStyles,
lottieWebViewStyles,
Expand Down Expand Up @@ -99,7 +100,8 @@ function EmptyStateComponent({
<View style={[styles.emptyStateHeader(headerMediaType === CONST.EMPTY_STATE_MEDIA.ILLUSTRATION), headerStyles]}>{HeaderComponent}</View>
<View style={shouldUseNarrowLayout ? styles.p5 : styles.p8}>
<Text style={[styles.textAlignCenter, styles.textHeadlineH1, styles.mb2, titleStyles]}>{title}</Text>
{typeof subtitle === 'string' ? <Text style={[styles.textAlignCenter, styles.textSupporting, styles.textNormal]}>{subtitle}</Text> : subtitle}
<Text style={[styles.textAlignCenter, styles.textSupporting, styles.textNormal]}>{subtitle}</Text>
{children}
<View style={[styles.gap2, styles.mt5, !shouldUseNarrowLayout ? styles.flexRow : undefined]}>
{buttons?.map(({buttonText, buttonAction, success, icon, isDisabled}, index) => (
<View
Expand Down
3 changes: 2 additions & 1 deletion src/components/EmptyStateComponent/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ type SharedProps<T> = {
SkeletonComponent: ValidSkeletons;
title: string;
titleStyles?: StyleProp<TextStyle>;
subtitle: string | React.ReactNode;
subtitle?: string;
children?: React.ReactNode;
buttons?: Button[];
containerStyles?: StyleProp<ViewStyle>;
headerStyles?: StyleProp<ViewStyle>;
Expand Down
55 changes: 15 additions & 40 deletions src/components/FeatureList.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import type {ReactNode} from 'react';
import {View} from 'react-native';
import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
import useLocalize from '@hooks/useLocalize';
Expand All @@ -7,7 +8,6 @@ import variables from '@styles/variables';
import type {TranslationPaths} from '@src/languages/types';
import type IconAsset from '@src/types/utils/IconAsset';
import Button from './Button';
import DotIndicatorMessage from './DotIndicatorMessage';
import type DotLottieAnimation from './LottieAnimations/types';
import MenuItem from './MenuItem';
import Section from './Section';
Expand All @@ -33,15 +33,6 @@ type FeatureListProps = {
/** Action to call on cta button press */
onCtaPress?: () => void;

/** Text of the secondary button button */
secondaryButtonText?: string;

/** Accessibility label for the secondary button */
secondaryButtonAccessibilityLabel?: string;

/** Action to call on secondary button press */
onSecondaryButtonPress?: () => void;

/** A list of menuItems representing the feature list. */
menuItems: FeatureListItem[];

Expand All @@ -60,30 +51,27 @@ type FeatureListProps = {
/** The style used for the title */
titleStyles?: StyleProp<TextStyle>;

/** The error message to display for the CTA button */
ctaErrorMessage?: string;

/** Padding for content on large screens */
contentPaddingOnLargeScreens?: {padding: number};

/** Custom content to display in the footer */
footer?: ReactNode;
};

function FeatureList({
title,
subtitle = '',
ctaText = '',
ctaAccessibilityLabel = '',
onCtaPress = () => {},
secondaryButtonText = '',
secondaryButtonAccessibilityLabel = '',
onSecondaryButtonPress = () => {},
ctaErrorMessage,
ctaText,
ctaAccessibilityLabel,
onCtaPress,
menuItems,
illustration,
illustrationStyle,
illustrationBackgroundColor,
illustrationContainerStyle,
titleStyles,
contentPaddingOnLargeScreens,
footer,
}: FeatureListProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
Expand Down Expand Up @@ -122,30 +110,17 @@ function FeatureList({
</View>
))}
</View>
{!!secondaryButtonText && (
{!!ctaText && (
<Button
text={secondaryButtonText}
onPress={onSecondaryButtonPress}
accessibilityLabel={secondaryButtonAccessibilityLabel}
style={[styles.w100, styles.mb3]}
text={ctaText}
onPress={onCtaPress}
accessibilityLabel={ctaAccessibilityLabel}
style={styles.w100}
success
large
/>
)}
{!!ctaErrorMessage && (
<DotIndicatorMessage
style={styles.mb1}
messages={{error: ctaErrorMessage}}
type="error"
/>
)}
<Button
text={ctaText}
onPress={onCtaPress}
accessibilityLabel={ctaAccessibilityLabel}
style={styles.w100}
success
large
/>
{!!footer && footer}
</View>
</Section>
);
Expand Down
Loading

0 comments on commit 7058ee0

Please sign in to comment.