Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set workspace address when attempting to Book Travel #46333

Merged
merged 34 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
87c12ef
rm padding for nested lists
rushatgabhane Jul 26, 2024
4edafe6
Merge branch 'main' of github.com:rushatgabhane/exfy into margin
rushatgabhane Jul 26, 2024
306d765
use h3 heading
rushatgabhane Jul 26, 2024
d11b1e9
navigate to company address if not present
rushatgabhane Jul 26, 2024
6581442
Revert "use h3 heading"
rushatgabhane Jul 26, 2024
e4ffa8a
Revert "rm padding for nested lists"
rushatgabhane Jul 26, 2024
548c4fa
undo unrelated commits
rushatgabhane Jul 26, 2024
0e6502a
undo unrelated commits
rushatgabhane Jul 26, 2024
d3e3498
get policy from onyx and show loading indicator
rushatgabhane Jul 26, 2024
186354a
show error message for cta
rushatgabhane Jul 27, 2024
1c0c1ef
add generic error for travel
rushatgabhane Jul 27, 2024
19b0e29
handle error in open travel dot
rushatgabhane Jul 27, 2024
cf750a6
null checks for promise response
rushatgabhane Jul 27, 2024
a773eb6
null checks for promise response
rushatgabhane Jul 27, 2024
cd7e464
set error message if failed to open travel dot
rushatgabhane Jul 27, 2024
3167b61
reject if unable to generate spotnana token
rushatgabhane Jul 27, 2024
e94ef7c
show error message if error in spotnana token while accepting terms
rushatgabhane Jul 27, 2024
458ecb7
Merge branch 'Expensify:main' into travel-address
rushatgabhane Jul 28, 2024
643a76e
fix type
rushatgabhane Jul 29, 2024
8e1ef1c
Merge branch 'main' into travel-address
rushatgabhane Jul 29, 2024
4bd56f7
Merge branch 'main' of github.com:rushatgabhane/exfy into travel-address
rushatgabhane Jul 29, 2024
ba72d49
add test account key
rushatgabhane Jul 29, 2024
a80e443
connect to test account key and use it for building travel dot url
rushatgabhane Jul 29, 2024
4c663df
rm unused code
rushatgabhane Jul 29, 2024
9d395c6
cleanup
rushatgabhane Jul 29, 2024
ddd0558
undo async url changes
rushatgabhane Jul 30, 2024
e8e5868
throw err for async to be caught
rushatgabhane Jul 30, 2024
aa023c2
throw err for async to be caught
rushatgabhane Jul 30, 2024
76b5379
catch err
rushatgabhane Jul 30, 2024
152b577
catch err
rushatgabhane Jul 30, 2024
4d6011f
Merge branch 'main' into travel-address
rushatgabhane Jul 31, 2024
90ba0ff
log warning
rushatgabhane Aug 2, 2024
f54c790
log warning
rushatgabhane Aug 2, 2024
6b8cfa5
change warn msg
rushatgabhane Aug 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/components/FeatureList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ 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 Down Expand Up @@ -56,6 +57,9 @@ 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};
};
Expand All @@ -65,10 +69,11 @@ function FeatureList({
subtitle = '',
ctaText = '',
ctaAccessibilityLabel = '',
onCtaPress,
onCtaPress = () => {},
secondaryButtonText = '',
secondaryButtonAccessibilityLabel = '',
onSecondaryButtonPress,
onSecondaryButtonPress = () => {},
ctaErrorMessage,
menuItems,
illustration,
illustrationStyle,
Expand Down Expand Up @@ -120,6 +125,12 @@ function FeatureList({
large
/>
)}
{ctaErrorMessage && (
<DotIndicatorMessage
messages={{error: ctaErrorMessage}}
type="error"
/>
)}
<Button
text={ctaText}
onPress={onCtaPress}
Expand Down
4 changes: 3 additions & 1 deletion src/components/ReportActionItem/MoneyRequestView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,9 @@ function MoneyRequestView({
icon={Expensicons.Suitcase}
iconRight={Expensicons.NewWindow}
shouldShowRightIcon
onPress={() => Link.openTravelDotLink(activePolicyID, CONST.TRIP_ID_PATH(tripID))}
onPress={() => {
Link.openTravelDotLink(activePolicyID, CONST.TRIP_ID_PATH(tripID));
}}
/>
)}
{shouldShowBillable && (
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2029,6 +2029,7 @@ export default {
trip: 'Trip',
tripSummary: 'Trip summary',
departs: 'Departs',
errorMessage: 'Something went wrong. Please try again later.',
},
workspace: {
common: {
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2064,6 +2064,7 @@ export default {
trip: 'Viaje',
tripSummary: 'Resumen del viaje',
departs: 'Sale',
errorMessage: 'Ha ocurrido un error. Por favor, inténtalo mas tarde.',
},
workspace: {
common: {
Expand Down
24 changes: 1 addition & 23 deletions src/libs/Environment/Environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,6 @@ const OLDDOT_ENVIRONMENT_URLS = {
[CONST.ENVIRONMENT.ADHOC]: CONST.STAGING_EXPENSIFY_URL,
};

const TRAVELDOT_ENVIRONMENT_URLS: Record<string, string> = {
[CONST.ENVIRONMENT.DEV]: CONST.STAGING_TRAVEL_DOT_URL,
[CONST.ENVIRONMENT.STAGING]: CONST.STAGING_TRAVEL_DOT_URL,
[CONST.ENVIRONMENT.PRODUCTION]: CONST.TRAVEL_DOT_URL,
[CONST.ENVIRONMENT.ADHOC]: CONST.STAGING_TRAVEL_DOT_URL,
};

const SPOTNANA_ENVIRONMENT_TMC_ID: Record<string, string> = {
[CONST.ENVIRONMENT.DEV]: CONST.STAGING_SPOTNANA_TMC_ID,
[CONST.ENVIRONMENT.STAGING]: CONST.STAGING_SPOTNANA_TMC_ID,
[CONST.ENVIRONMENT.PRODUCTION]: CONST.SPOTNANA_TMC_ID,
[CONST.ENVIRONMENT.ADHOC]: CONST.STAGING_SPOTNANA_TMC_ID,
};

/**
* Are we running the app in development?
*/
Expand Down Expand Up @@ -68,12 +54,4 @@ function getOldDotEnvironmentURL(): Promise<string> {
return getEnvironment().then((environment) => OLDDOT_ENVIRONMENT_URLS[environment]);
}

function getTravelDotEnvironmentURL(): Promise<string> {
return getEnvironment().then((environment) => TRAVELDOT_ENVIRONMENT_URLS[environment]);
}

function getSpotnanaEnvironmentTMCID(): Promise<string> {
return getEnvironment().then((environment) => SPOTNANA_ENVIRONMENT_TMC_ID[environment]);
}

export {getEnvironment, isInternalTestBuild, isDevelopment, isProduction, getEnvironmentURL, getOldDotEnvironmentURL, getTravelDotEnvironmentURL, getSpotnanaEnvironmentTMCID};
export {getEnvironment, isInternalTestBuild, isDevelopment, isProduction, getEnvironmentURL, getOldDotEnvironmentURL};
56 changes: 39 additions & 17 deletions src/libs/actions/Link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ Onyx.connect({
},
});

let isTravelTestAccount = false;
Onyx.connect({
key: ONYXKEYS.NVP_TRAVEL_SETTINGS,
callback: (value) => {
isTravelTestAccount = value?.testAccount ?? false;
},
});

function buildOldDotURL(url: string, shortLivedAuthToken?: string): Promise<string> {
const hasHashParams = url.indexOf('#') !== -1;
const hasURLParams = url.indexOf('?') !== -1;
Expand Down Expand Up @@ -70,17 +78,18 @@ function openOldDotLink(url: string) {
);
}

function buildTravelDotURL(spotnanaToken?: string, postLoginPath?: string): Promise<string> {
return Promise.all([Environment.getTravelDotEnvironmentURL(), Environment.getSpotnanaEnvironmentTMCID()]).then(([environmentURL, tmcID]) => {
const authCode = spotnanaToken ? `authCode=${spotnanaToken}` : '';
const redirectURL = postLoginPath ? `redirectUrl=${Url.addLeadingForwardSlash(postLoginPath)}` : '';
const tmcIDParam = `tmcId=${tmcID}`;
function buildTravelDotURL(spotnanaToken: string, postLoginPath?: string): string {
const environmentURL = isTravelTestAccount ? CONST.STAGING_TRAVEL_DOT_URL : CONST.TRAVEL_DOT_URL;
const tmcID = isTravelTestAccount ? CONST.STAGING_SPOTNANA_TMC_ID : CONST.SPOTNANA_TMC_ID;

const paramsArray = [authCode, tmcIDParam, redirectURL];
const params = paramsArray.filter(Boolean).join('&');
const travelDotDomain = Url.addTrailingForwardSlash(environmentURL);
return `${travelDotDomain}auth/code?${params}`;
});
const authCode = `authCode=${spotnanaToken}`;
const tmcIDParam = `tmcId=${tmcID}`;
const redirectURL = postLoginPath ? `redirectUrl=${Url.addLeadingForwardSlash(postLoginPath)}` : '';

const paramsArray = [authCode, tmcIDParam, redirectURL];
const params = paramsArray.filter(Boolean).join('&');
const travelDotDomain = Url.addTrailingForwardSlash(environmentURL);
return `${travelDotDomain}auth/code?${params}`;
}

/**
Expand All @@ -95,13 +104,26 @@ function openTravelDotLink(policyID: OnyxEntry<string>, postLoginPath?: string)
policyID,
};

asyncOpenURL(
// eslint-disable-next-line rulesdir/no-api-side-effects-method
API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.GENERATE_SPOTNANA_TOKEN, parameters, {})
.then((response) => (response?.spotnanaToken ? buildTravelDotURL(response.spotnanaToken, postLoginPath) : buildTravelDotURL()))
.catch(() => buildTravelDotURL()),
(travelDotURL) => travelDotURL,
);
return new Promise((_, reject) => {
const error = new Error('Failed to generate spotnana token.');

asyncOpenURL(
// eslint-disable-next-line rulesdir/no-api-side-effects-method
API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.GENERATE_SPOTNANA_TOKEN, parameters, {})
.then((response) => {
if (!response?.spotnanaToken) {
reject(error);
throw error;
}
return buildTravelDotURL(response.spotnanaToken, postLoginPath);
})
.catch(() => {
reject(error);
throw error;
}),
(travelDotURL) => travelDotURL ?? '',
);
});
}

function getInternalNewExpensifyPath(href: string) {
Expand Down
26 changes: 19 additions & 7 deletions src/libs/actions/Travel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,26 @@ function acceptSpotnanaTerms() {
},
},
];
const error = new Error('Failed to generate spotnana token.');

asyncOpenURL(
// eslint-disable-next-line rulesdir/no-api-side-effects-method
API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.ACCEPT_SPOTNANA_TERMS, null, {optimisticData})
.then((response) => (response?.spotnanaToken ? buildTravelDotURL(response.spotnanaToken) : buildTravelDotURL()))
.catch(() => buildTravelDotURL()),
(travelDotURL) => travelDotURL,
);
return new Promise((_, reject) => {
asyncOpenURL(
// eslint-disable-next-line rulesdir/no-api-side-effects-method
API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.ACCEPT_SPOTNANA_TERMS, null, {optimisticData})
.then((response) => {
if (!response?.spotnanaToken) {
reject(error);
throw error;
}
return buildTravelDotURL(response.spotnanaToken);
})
.catch(() => {
reject(error);
throw error;
}),
(travelDotURL) => travelDotURL ?? '',
);
});
}

// eslint-disable-next-line import/prefer-default-export
Expand Down
11 changes: 8 additions & 3 deletions src/libs/asyncOpenURL/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import {Linking} from 'react-native';
import Log from '@libs/Log';
import type AsyncOpenURL from './types';

const asyncOpenURL: AsyncOpenURL = (promise, url) => {
if (!url) {
return;
}

promise.then((params) => {
Linking.openURL(typeof url === 'string' ? url : url(params));
});
promise
.then((params) => {
Linking.openURL(typeof url === 'string' ? url : url(params));
})
.catch(() => {
Log.warn('[asyncOpenURL] error occured while opening URL', {url});
});
};

export default asyncOpenURL;
16 changes: 12 additions & 4 deletions src/libs/asyncOpenURL/index.website.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {Linking} from 'react-native';
import Log from '@libs/Log';
import type AsyncOpenURL from './types';

/**
Expand All @@ -13,9 +14,13 @@ const asyncOpenURL: AsyncOpenURL = (promise, url, shouldSkipCustomSafariLogic) =
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);

if (!isSafari || shouldSkipCustomSafariLogic) {
promise.then((params) => {
Linking.openURL(typeof url === 'string' ? url : url(params));
});
promise
.then((params) => {
Linking.openURL(typeof url === 'string' ? url : url(params));
})
.catch(() => {
Log.warn('[asyncOpenURL] error occured while opening URL', {url});
});
} else {
const windowRef = window.open();
promise
Expand All @@ -25,7 +30,10 @@ const asyncOpenURL: AsyncOpenURL = (promise, url, shouldSkipCustomSafariLogic) =
}
windowRef.location = typeof url === 'string' ? url : url(params);
})
.catch(() => windowRef?.close());
.catch(() => {
windowRef?.close();
Log.warn('[asyncOpenURL] error occured while opening URL', {url});
});
}
};

Expand Down
24 changes: 22 additions & 2 deletions src/pages/Travel/ManageTrips.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import React, {useState} from 'react';
import {Linking, View} from 'react-native';
import {useOnyx} from 'react-native-onyx';
import type {FeatureListItem} from '@components/FeatureList';
import FeatureList from '@components/FeatureList';
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import * as Illustrations from '@components/Icon/Illustrations';
import ScrollView from '@components/ScrollView';
import useLocalize from '@hooks/useLocalize';
Expand All @@ -14,6 +15,7 @@ import * as Link from '@userActions/Link';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import {isEmptyObject} from '@src/types/utils/EmptyObject';

const tripsFeatures: FeatureListItem[] = [
{
Expand All @@ -32,8 +34,16 @@ function ManageTrips() {
const {translate} = useLocalize();
const [travelSettings] = useOnyx(ONYXKEYS.NVP_TRAVEL_SETTINGS);
const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID);
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${activePolicyID}`);

const [ctaErrorMessage, setCtaErrorMessage] = useState('');

if (isEmptyObject(policy)) {
return <FullScreenLoadingIndicator />;
}

const hasAcceptedTravelTerms = travelSettings?.hasAcceptedTerms;
const hasPolicyAddress = !isEmptyObject(policy?.address);

const navigateToBookTravelDemo = () => {
Linking.openURL(CONST.BOOK_TRAVEL_DEMO_URL);
Expand All @@ -49,12 +59,22 @@ function ManageTrips() {
ctaText={translate('travel.bookTravel')}
ctaAccessibilityLabel={translate('travel.bookTravel')}
onCtaPress={() => {
if (!hasPolicyAddress) {
Navigation.navigate(ROUTES.WORKSPACE_PROFILE_ADDRESS.getRoute(activePolicyID ?? '-1'));
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not using backTo while calling getRoute caused #47069

}
if (!hasAcceptedTravelTerms) {
Navigation.navigate(ROUTES.TRAVEL_TCS);
return;
}
Link.openTravelDotLink(activePolicyID);
if (ctaErrorMessage) {
setCtaErrorMessage('');
}
Link.openTravelDotLink(activePolicyID)?.catch(() => {
setCtaErrorMessage(translate('travel.errorMessage'));
});
}}
ctaErrorMessage={ctaErrorMessage}
illustration={Illustrations.EmptyStateTravel}
illustrationStyle={[styles.mv4, styles.tripIllustrationSize]}
secondaryButtonText={translate('travel.bookDemo')}
Expand Down
19 changes: 10 additions & 9 deletions src/pages/Travel/TravelTerms.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ function TravelTerms() {
const {translate} = useLocalize();
const {canUseSpotnanaTravel} = usePermissions();
const [hasAcceptedTravelTerms, setHasAcceptedTravelTerms] = useState(false);
const [error, setError] = useState(false);

const errorMessage = error ? translate('travel.termsAndConditions.error') : '';
const [errorMessage, setErrorMessage] = useState('');

const toggleTravelTerms = () => {
setHasAcceptedTravelTerms(!hasAcceptedTravelTerms);
Expand All @@ -34,7 +32,7 @@ function TravelTerms() {
return;
}

setError(false);
setErrorMessage('');
}, [hasAcceptedTravelTerms]);

const AgreeToTheLabel = useCallback(
Expand Down Expand Up @@ -86,16 +84,19 @@ function TravelTerms() {
isDisabled={!hasAcceptedTravelTerms}
onSubmit={() => {
if (!hasAcceptedTravelTerms) {
setError(true);
setErrorMessage(translate('travel.termsAndConditions.error'));
return;
}
if (errorMessage) {
setErrorMessage('');
}

Travel.acceptSpotnanaTerms();
setError(false);
Navigation.goBack();
Travel.acceptSpotnanaTerms()
.then(() => Navigation.goBack())
.catch(() => setErrorMessage(translate('travel.errorMessage')));
}}
message={errorMessage}
isAlertVisible={error || !!errorMessage}
isAlertVisible={!!errorMessage}
containerStyles={[styles.mh0, styles.mt5]}
/>
</ScrollView>
Expand Down
3 changes: 3 additions & 0 deletions src/types/onyx/TravelSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ type TravelSettings = {

/** Whether the user has completed the travel terms and conditions checkbox */
hasAcceptedTerms: boolean;

/** Whether the user is setup for staging travelDot */
testAccount?: boolean;
};

/** Model of workspace travel information to connect with Spotnana */
Expand Down
Loading