Skip to content

Commit

Permalink
merge main.
Browse files Browse the repository at this point in the history
Signed-off-by: Krishna Gupta <belivethatkg@gmail.com>
  • Loading branch information
Krishna2323 committed Jul 4, 2024
2 parents 72a1986 + ecd93c0 commit 5158ef1
Show file tree
Hide file tree
Showing 14 changed files with 166 additions and 226 deletions.
1 change: 0 additions & 1 deletion src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5084,7 +5084,6 @@ const CONST = {
PAYMENT_CARD_CURRENCY: {
USD: 'USD',
AUD: 'AUD',
GBP: 'GBP',
NZD: 'NZD',
},

Expand Down
1 change: 1 addition & 0 deletions src/components/AddressForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ function AddressForm({
InputComponent={CountrySelector}
inputID={INPUT_IDS.COUNTRY}
value={country}
onValueChange={onAddressChanged}
shouldSaveDraft={shouldSaveDraft}
/>
</View>
Expand Down
30 changes: 22 additions & 8 deletions src/components/CountrySelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {useIsFocused} from '@react-navigation/native';
import React, {forwardRef, useEffect, useRef} from 'react';
import type {ForwardedRef} from 'react';
import type {View} from 'react-native';
import useGeographicalStateAndCountryFromRoute from '@hooks/useGeographicalStateAndCountryFromRoute';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
Expand Down Expand Up @@ -31,25 +32,38 @@ type CountrySelectorProps = {
function CountrySelector({errorText = '', value: countryCode, onInputChange = () => {}, onBlur}: CountrySelectorProps, ref: ForwardedRef<View>) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const {country: countryFromUrl} = useGeographicalStateAndCountryFromRoute();

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) {
// Check if the country selector was opened and no value was selected, triggering onBlur to display an error
if (isFocused && didOpenContrySelector.current) {
didOpenContrySelector.current = false;
if (!countryFromUrl) {
onBlur?.();
}
}

// If no country is selected from the URL, exit the effect early to avoid further processing.
if (!countryFromUrl) {
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);
// If a country is selected, invoke `onInputChange` to update the form and clear any validation errors related to the country selection.
if (onInputChange) {
onInputChange(countryFromUrl);
}

// Clears the `country` parameter from the URL to ensure the component country is driven by the parent component rather than URL parameters.
// This helps prevent issues where the component might not update correctly if the country is controlled by both the parent and the URL.
Navigation.setParams({country: undefined});

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [countryCode]);
}, [countryFromUrl, isFocused, onBlur]);

return (
<MenuItemWithTopDescription
Expand Down
4 changes: 2 additions & 2 deletions src/components/StateSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {CONST as COMMON_CONST} from 'expensify-common';
import React, {useEffect, useRef} from 'react';
import type {ForwardedRef} from 'react';
import type {View} from 'react-native';
import useGeographicalStateFromRoute from '@hooks/useGeographicalStateFromRoute';
import useGeographicalStateAndCountryFromRoute from '@hooks/useGeographicalStateAndCountryFromRoute';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
Expand Down Expand Up @@ -43,7 +43,7 @@ function StateSelector(
) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const stateFromUrl = useGeographicalStateFromRoute();
const {state: stateFromUrl} = useGeographicalStateAndCountryFromRoute();

const didOpenStateSelector = useRef(false);
const isFocused = useIsFocused();
Expand Down
27 changes: 27 additions & 0 deletions src/hooks/useGeographicalStateAndCountryFromRoute.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {useRoute} from '@react-navigation/native';
import {CONST as COMMON_CONST} from 'expensify-common';
import CONST from '@src/CONST';

type State = keyof typeof COMMON_CONST.STATES;
type Country = keyof typeof CONST.ALL_COUNTRIES;
type StateAndCountry = {state?: State; country?: Country};

/**
* Extracts the 'state' and 'country' query parameters from the route/ url and validates it against COMMON_CONST.STATES and CONST.ALL_COUNTRIES.
* Example 1: Url: https://new.expensify.com/settings/profile/address?state=MO Returns: state=MO
* Example 2: Url: https://new.expensify.com/settings/profile/address?state=ASDF Returns: state=undefined
* Example 3: Url: https://new.expensify.com/settings/profile/address Returns: state=undefined
* Example 4: Url: https://new.expensify.com/settings/profile/address?state=MO-hash-a12341 Returns: state=MO
* Similarly for country parameter.
*/
export default function useGeographicalStateAndCountryFromRoute(stateParamName = 'state', countryParamName = 'country'): StateAndCountry {
const routeParams = useRoute().params as Record<string, string>;

const stateFromUrlTemp = routeParams?.[stateParamName] as string | undefined;
const countryFromUrlTemp = routeParams?.[countryParamName] as string | undefined;

return {
state: COMMON_CONST.STATES[stateFromUrlTemp as State]?.stateISO,
country: Object.keys(CONST.ALL_COUNTRIES).find((country) => country === countryFromUrlTemp) as Country,
};
}
23 changes: 0 additions & 23 deletions src/hooks/useGeographicalStateFromRoute.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/hooks/useSubscriptionPossibleCostSavings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ const POSSIBLE_COST_SAVINGS = {
[CONST.POLICY.TYPE.TEAM]: 1400,
[CONST.POLICY.TYPE.CORPORATE]: 3000,
},
[CONST.PAYMENT_CARD_CURRENCY.GBP]: {
[CONST.POLICY.TYPE.TEAM]: 800,
[CONST.POLICY.TYPE.CORPORATE]: 1400,
},
[CONST.PAYMENT_CARD_CURRENCY.NZD]: {
[CONST.POLICY.TYPE.TEAM]: 1600,
[CONST.POLICY.TYPE.CORPORATE]: 3200,
Expand Down
10 changes: 0 additions & 10 deletions src/hooks/useSubscriptionPrice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,6 @@ const SUBSCRIPTION_PRICES = {
[CONST.SUBSCRIPTION.TYPE.PAYPERUSE]: 1400,
},
},
[CONST.PAYMENT_CARD_CURRENCY.GBP]: {
[CONST.POLICY.TYPE.CORPORATE]: {
[CONST.SUBSCRIPTION.TYPE.ANNUAL]: 700,
[CONST.SUBSCRIPTION.TYPE.PAYPERUSE]: 1400,
},
[CONST.POLICY.TYPE.TEAM]: {
[CONST.SUBSCRIPTION.TYPE.ANNUAL]: 400,
[CONST.SUBSCRIPTION.TYPE.PAYPERUSE]: 800,
},
},
[CONST.PAYMENT_CARD_CURRENCY.NZD]: {
[CONST.POLICY.TYPE.CORPORATE]: {
[CONST.SUBSCRIPTION.TYPE.ANNUAL]: 1600,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.SETTINGS.PROFILE.TIMEZONE_SELECT]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/TimezoneSelectPage').default,
[SCREENS.SETTINGS.PROFILE.LEGAL_NAME]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/PersonalDetails/LegalNamePage').default,
[SCREENS.SETTINGS.PROFILE.DATE_OF_BIRTH]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/PersonalDetails/DateOfBirthPage').default,
[SCREENS.SETTINGS.PROFILE.ADDRESS]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/PersonalDetails/AddressPage').default,
[SCREENS.SETTINGS.PROFILE.ADDRESS]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/PersonalDetails/PersonalAddressPage').default,
[SCREENS.SETTINGS.PROFILE.ADDRESS_COUNTRY]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/PersonalDetails/CountrySelectionPage').default,
[SCREENS.SETTINGS.PROFILE.ADDRESS_STATE]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/PersonalDetails/StateSelectionPage').default,
[SCREENS.SETTINGS.PROFILE.CONTACT_METHODS]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/Contacts/ContactMethodsPage').default,
Expand All @@ -197,7 +197,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.SETTINGS.APP_DOWNLOAD_LINKS]: () => require<ReactComponentModule>('../../../../pages/settings/AppDownloadLinks').default,
[SCREENS.SETTINGS.CONSOLE]: () => require<ReactComponentModule>('../../../../pages/settings/AboutPage/ConsolePage').default,
[SCREENS.SETTINGS.SHARE_LOG]: () => require<ReactComponentModule>('../../../../pages/settings/AboutPage/ShareLogPage').default,
[SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/PersonalDetails/AddressPage').default,
[SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/PersonalDetails/PersonalAddressPage').default,
[SCREENS.SETTINGS.WALLET.DOMAIN_CARD]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ExpensifyCardPage').default,
[SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ReportVirtualCardFraudPage').default,
[SCREENS.SETTINGS.WALLET.CARD_ACTIVATE]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ActivatePhysicalCardPage').default,
Expand Down
27 changes: 7 additions & 20 deletions src/libs/actions/PaymentMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type {
TransferWalletBalanceParams,
UpdateBillingCurrencyParams,
} from '@libs/API/parameters';
import {READ_COMMANDS, SIDE_EFFECT_REQUEST_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
import * as CardUtils from '@libs/CardUtils';
import Navigation from '@libs/Navigation/Navigation';
import CONST from '@src/CONST';
Expand Down Expand Up @@ -253,25 +253,12 @@ function addSubscriptionPaymentCard(cardData: {
},
];

if (currency === CONST.PAYMENT_CARD_CURRENCY.GBP) {
// eslint-disable-next-line rulesdir/no-api-side-effects-method
API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.ADD_PAYMENT_CARD_GBR, parameters, {optimisticData, successData, failureData}).then((response) => {
if (response?.jsonCode !== CONST.JSON_CODE.SUCCESS) {
return;
}
// TODO 3ds flow will be done as a part https://github.com/Expensify/App/issues/42432
// We will use this onyx key to open Modal and preview iframe. Potentially we can save the whole object which come from side effect
Onyx.set(ONYXKEYS.VERIFY_3DS_SUBSCRIPTION, (response as {authenticationLink: string}).authenticationLink);
});
} else {
// eslint-disable-next-line rulesdir/no-multiple-api-calls
API.write(WRITE_COMMANDS.ADD_PAYMENT_CARD, parameters, {
optimisticData,
successData,
failureData,
});
Navigation.goBack();
}
API.write(WRITE_COMMANDS.ADD_PAYMENT_CARD, parameters, {
optimisticData,
successData,
failureData,
});
Navigation.goBack();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,35 @@
import type {StackScreenProps} from '@react-navigation/stack';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import React, {useCallback, useEffect, useState} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import AddressForm from '@components/AddressForm';
import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import useGeographicalStateFromRoute from '@hooks/useGeographicalStateFromRoute';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@libs/Navigation/Navigation';
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import * as PersonalDetails from '@userActions/PersonalDetails';
import type {FormOnyxValues} from '@src/components/Form/types';
import CONST from '@src/CONST';
import type {Country} from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type SCREENS from '@src/SCREENS';
import type {PrivatePersonalDetails} from '@src/types/onyx';
import type {Address} from '@src/types/onyx/PrivatePersonalDetails';

type AddressPageOnyxProps = {
type AddressPageProps = {
/** User's private personal details */
privatePersonalDetails: OnyxEntry<PrivatePersonalDetails>;
address?: Address;
/** Whether app is loading */
isLoadingApp: OnyxEntry<boolean>;
/** Function to call when address form is submitted */
updateAddress: (values: FormOnyxValues<typeof ONYXKEYS.FORMS.HOME_ADDRESS_FORM>) => void;
/** Title of address page */
title: string;
};

type AddressPageProps = StackScreenProps<SettingsNavigatorParamList, typeof SCREENS.SETTINGS.PROFILE.ADDRESS> & AddressPageOnyxProps;

/**
* Submit form to update user's first and last legal name
* @param values - form input values
*/
function updateAddress(values: FormOnyxValues<typeof ONYXKEYS.FORMS.HOME_ADDRESS_FORM>) {
PersonalDetails.updateAddress(
values.addressLine1?.trim() ?? '',
values.addressLine2?.trim() ?? '',
values.city.trim(),
values.state.trim(),
values?.zipPostCode?.trim().toUpperCase() ?? '',
values.country,
);
}

function AddressPage({privatePersonalDetails, route, isLoadingApp = true}: AddressPageProps) {
function AddressPage({title, address, updateAddress, isLoadingApp = true}: AddressPageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const address = useMemo(() => privatePersonalDetails?.address, [privatePersonalDetails]);
const countryFromUrlTemp = route?.params?.country;

// Check if country is valid
const countryFromUrl = CONST.ALL_COUNTRIES[countryFromUrlTemp as keyof typeof CONST.ALL_COUNTRIES] ? countryFromUrlTemp : '';
const stateFromUrl = useGeographicalStateFromRoute();
const {street, street2} = address ?? {};
const [currentCountry, setCurrentCountry] = useState(address?.country);
const [street1, street2] = (address?.street ?? '').split('\n');
const [state, setState] = useState(address?.state);
const [city, setCity] = useState(address?.city);
const [zipcode, setZipcode] = useState(address?.zip);
Expand All @@ -67,7 +42,8 @@ function AddressPage({privatePersonalDetails, route, isLoadingApp = true}: Addre
setCurrentCountry(address.country);
setCity(address.city);
setZipcode(address.zip);
}, [address]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [address?.state, address?.country, address?.city, address?.zip]);

const handleAddressChange = useCallback((value: unknown, key: unknown) => {
const addressPart = value as string;
Expand Down Expand Up @@ -97,27 +73,13 @@ function AddressPage({privatePersonalDetails, route, isLoadingApp = true}: Addre
setZipcode(addressPart);
}, []);

useEffect(() => {
if (!countryFromUrl) {
return;
}
handleAddressChange(countryFromUrl, 'country');
}, [countryFromUrl, handleAddressChange]);

useEffect(() => {
if (!stateFromUrl) {
return;
}
handleAddressChange(stateFromUrl, 'state');
}, [handleAddressChange, stateFromUrl]);

return (
<ScreenWrapper
includeSafeAreaPaddingBottom={false}
testID={AddressPage.displayName}
>
<HeaderWithBackButton
title={translate('privatePersonalDetails.address')}
title={title}
shouldShowBackButton
onBackButtonPress={() => Navigation.goBack()}
/>
Expand All @@ -132,7 +94,7 @@ function AddressPage({privatePersonalDetails, route, isLoadingApp = true}: Addre
country={currentCountry}
onAddressChanged={handleAddressChange}
state={state}
street1={street1}
street1={street}
street2={street2}
zip={zipcode}
/>
Expand All @@ -143,11 +105,4 @@ function AddressPage({privatePersonalDetails, route, isLoadingApp = true}: Addre

AddressPage.displayName = 'AddressPage';

export default withOnyx<AddressPageProps, AddressPageOnyxProps>({
privatePersonalDetails: {
key: ONYXKEYS.PRIVATE_PERSONAL_DETAILS,
},
isLoadingApp: {
key: ONYXKEYS.IS_LOADING_APP,
},
})(AddressPage);
export default AddressPage;
Loading

0 comments on commit 5158ef1

Please sign in to comment.