Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
nkdengineer committed Jun 27, 2024
2 parents edd9502 + 050641a commit a72b000
Show file tree
Hide file tree
Showing 119 changed files with 1,551 additions and 1,031 deletions.
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1009000200
versionName "9.0.2-0"
versionCode 1009000203
versionName "9.0.2-3"
// 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
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ Log in to QuickBooks Online and ensure all of your employees are setup as either
<li>Enter your Intuit login details to import your settings from QuickBooks Online to Expensify.</li>
</ol>

![The toggle location to enable accounting integrations like QuickBooks Online]({{site.url}}/assets/images/ExpensifyHelp-QBO-1.png){:width="100%"}

![How to enable accounting integrations like QuickBooks Online]({{site.url}}/assets/images/ExpensifyHelp-QBO-2.png){:width="100%"}

![The QuickBooks Online Connect button]({{site.url}}/assets/images/ExpensifyHelp-QBO-3.png){:width="100%"}

# Step 3: Configure import settings

The following steps help you determine how data will be imported from QuickBooks Online to Expensify.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ To set up your Xero connection, complete the 4 steps below.
<li>Enter your Xero login details to import your settings from Xero to Expensify.</li>
</ol>

![The toggle location to enable accounting integrations like QuickBooks Online]({{site.url}}/assets/images/ExpensifyHelp-Xero-1.png){:width="100%"}

![How to enable accounting integrations like QuickBooks Online]({{site.url}}/assets/images/ExpensifyHelp-Xero-2.png){:width="100%"}

![The QuickBooks Online Connect button]({{site.url}}/assets/images/ExpensifyHelp-Xero-3.png){:width="100%"}

# Step 2: Configure import settings

The following steps help you determine how data will be imported from Xero to Expensify.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ To approve an expense,
{% include info.html %}
Admins can modify an expense, if needed.
{% include end-info.html %}


![The approve button in an expense]({{site.url}}/assets/images/ExpensifyHelp_ApproveExpense_1.png){:width="100%"}

![The approve button when you click into the expense]({{site.url}}/assets/images/ExpensifyHelp_ApproveExpense_2.png){:width="100%"}

You’re now ready to pay the expense.

# Hold an expense
Expand Down
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>9.0.2.0</string>
<string>9.0.2.3</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.2.0</string>
<string>9.0.2.3</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.2</string>
<key>CFBundleVersion</key>
<string>9.0.2.0</string>
<string>9.0.2.3</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.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
"version": "9.0.2-0",
"version": "9.0.2-3",
"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 @@ -36,7 +36,7 @@
"android-build-e2edelta": "bundle exec fastlane android build_e2edelta",
"test": "TZ=utc NODE_OPTIONS=--experimental-vm-modules jest",
"typecheck": "tsc",
"lint": "eslint . --max-warnings=0 --cache --cache-location=node_modules/.cache/eslint",
"lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=0 --cache --cache-location=node_modules/.cache/eslint",
"lint-changed": "eslint --fix $(git diff --diff-filter=AM --name-only main -- \"*.js\" \"*.ts\" \"*.tsx\")",
"lint-watch": "npx eslint-watch --watch --changed",
"shellcheck": "./scripts/shellCheck.sh",
Expand Down
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,7 @@ const CONST = {
ONFIDO_TERMS_OF_SERVICE_URL: 'https://onfido.com/terms-of-service/',
LIST_OF_RESTRICTED_BUSINESSES: 'https://community.expensify.com/discussion/6191/list-of-restricted-businesses',
TRAVEL_TERMS_URL: `${USE_EXPENSIFY_URL}/travelterms`,
PRICING: `https://www.expensify.com/pricing`,

// Use Environment.getEnvironmentURL to get the complete URL with port number
DEV_NEW_EXPENSIFY_URL: 'https://dev.new.expensify.com:',
Expand Down
13 changes: 10 additions & 3 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@ const ONYXKEYS = {
// Paths of PDF file that has been cached during one session
CACHED_PDF_PATHS: 'cachedPDFPaths',

/** Stores iframe link to verify 3DS flow for subscription */
VERIFY_3DS_SUBSCRIPTION: 'verify3dsSubscription',

/** Holds the checks used while transferring the ownership of the workspace */
POLICY_OWNERSHIP_CHANGE_CHECKS: 'policyOwnershipChangeChecks',

Expand Down Expand Up @@ -405,8 +408,8 @@ const ONYXKEYS = {

/** List of Form ids */
FORMS: {
ADD_DEBIT_CARD_FORM: 'addDebitCardForm',
ADD_DEBIT_CARD_FORM_DRAFT: 'addDebitCardFormDraft',
ADD_PAYMENT_CARD_FORM: 'addPaymentCardForm',
ADD_PAYMENT_CARD_FORM_DRAFT: 'addPaymentCardFormDraft',
WORKSPACE_SETTINGS_FORM: 'workspaceSettingsForm',
WORKSPACE_CATEGORY_FORM: 'workspaceCategoryForm',
WORKSPACE_CATEGORY_FORM_DRAFT: 'workspaceCategoryFormDraft',
Expand Down Expand Up @@ -475,6 +478,8 @@ const ONYXKEYS = {
SETTINGS_STATUS_SET_CLEAR_AFTER_FORM_DRAFT: 'settingsStatusSetClearAfterFormDraft',
SETTINGS_STATUS_CLEAR_DATE_FORM: 'settingsStatusClearDateForm',
SETTINGS_STATUS_CLEAR_DATE_FORM_DRAFT: 'settingsStatusClearDateFormDraft',
CHANGE_BILLING_CURRENCY_FORM: 'changeBillingCurrencyForm',
CHANGE_BILLING_CURRENCY_FORM_DRAFT: 'changeBillingCurrencyFormDraft',
PRIVATE_NOTES_FORM: 'privateNotesForm',
PRIVATE_NOTES_FORM_DRAFT: 'privateNotesFormDraft',
I_KNOW_A_TEACHER_FORM: 'iKnowTeacherForm',
Expand Down Expand Up @@ -517,7 +522,7 @@ const ONYXKEYS = {
type AllOnyxKeys = DeepValueOf<typeof ONYXKEYS>;

type OnyxFormValuesMapping = {
[ONYXKEYS.FORMS.ADD_DEBIT_CARD_FORM]: FormTypes.AddDebitCardForm;
[ONYXKEYS.FORMS.ADD_PAYMENT_CARD_FORM]: FormTypes.AddPaymentCardForm;
[ONYXKEYS.FORMS.WORKSPACE_SETTINGS_FORM]: FormTypes.WorkspaceSettingsForm;
[ONYXKEYS.FORMS.WORKSPACE_CATEGORY_FORM]: FormTypes.WorkspaceCategoryForm;
[ONYXKEYS.FORMS.WORKSPACE_TAG_FORM]: FormTypes.WorkspaceTagForm;
Expand Down Expand Up @@ -549,6 +554,7 @@ type OnyxFormValuesMapping = {
[ONYXKEYS.FORMS.WAYPOINT_FORM]: FormTypes.WaypointForm;
[ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM]: FormTypes.SettingsStatusSetForm;
[ONYXKEYS.FORMS.SETTINGS_STATUS_CLEAR_DATE_FORM]: FormTypes.SettingsStatusClearDateForm;
[ONYXKEYS.FORMS.CHANGE_BILLING_CURRENCY_FORM]: FormTypes.ChangeBillingCurrencyForm;
[ONYXKEYS.FORMS.SETTINGS_STATUS_SET_CLEAR_AFTER_FORM]: FormTypes.SettingsStatusSetClearAfterForm;
[ONYXKEYS.FORMS.PRIVATE_NOTES_FORM]: FormTypes.PrivateNotesForm;
[ONYXKEYS.FORMS.I_KNOW_A_TEACHER_FORM]: FormTypes.IKnowTeacherForm;
Expand Down Expand Up @@ -704,6 +710,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.IS_CHECKING_PUBLIC_ROOM]: boolean;
[ONYXKEYS.MY_DOMAIN_SECURITY_GROUPS]: Record<string, string>;
[ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID]: string;
[ONYXKEYS.VERIFY_3DS_SUBSCRIPTION]: string;
[ONYXKEYS.PREFERRED_THEME]: ValueOf<typeof CONST.THEME>;
[ONYXKEYS.MAPBOX_ACCESS_TOKEN]: OnyxTypes.MapboxAccessToken;
[ONYXKEYS.ONYX_UPDATES_FROM_SERVER]: OnyxTypes.OnyxUpdatesFromServer;
Expand Down
3 changes: 3 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ const ROUTES = {
WORKSPACE_SWITCHER: 'workspace-switcher',
SETTINGS: 'settings',
SETTINGS_PROFILE: 'settings/profile',
SETTINGS_CHANGE_CURRENCY: 'settings/add-payment-card/change-currency',
SETTINGS_SHARE_CODE: 'settings/shareCode',
SETTINGS_DISPLAY_NAME: 'settings/profile/display-name',
SETTINGS_TIMEZONE: 'settings/profile/timezone',
Expand All @@ -107,6 +108,8 @@ const ROUTES = {
getRoute: (canChangeSize: 0 | 1) => `settings/subscription/subscription-size?canChangeSize=${canChangeSize}` as const,
},
SETTINGS_SUBSCRIPTION_ADD_PAYMENT_CARD: 'settings/subscription/add-payment-card',
SETTINGS_SUBSCRIPTION_CHANGE_BILLING_CURRENCY: 'settings/subscription/change-billing-currency',
SETTINGS_SUBSCRIPTION_CHANGE_PAYMENT_CURRENCY: 'settings/subscription/add-payment-card/change-payment-currency',
SETTINGS_SUBSCRIPTION_DISABLE_AUTO_RENEW_SURVEY: 'settings/subscription/disable-auto-renew-survey',
SETTINGS_PRIORITY_MODE: 'settings/preferences/priority-mode',
SETTINGS_LANGUAGE: 'settings/preferences/language',
Expand Down
3 changes: 3 additions & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const SCREENS = {
SAVE_THE_WORLD: 'Settings_TeachersUnite',
APP_DOWNLOAD_LINKS: 'Settings_App_Download_Links',
ADD_DEBIT_CARD: 'Settings_Add_Debit_Card',
ADD_PAYMENT_CARD_CHANGE_CURRENCY: 'Settings_Add_Payment_Card_Change_Currency',
ADD_BANK_ACCOUNT: 'Settings_Add_Bank_Account',
CLOSE: 'Settings_Close',
TWO_FACTOR_AUTH: 'Settings_TwoFactorAuth',
Expand Down Expand Up @@ -104,6 +105,8 @@ const SCREENS = {
SIZE: 'Settings_Subscription_Size',
ADD_PAYMENT_CARD: 'Settings_Subscription_Add_Payment_Card',
DISABLE_AUTO_RENEW_SURVEY: 'Settings_Subscription_DisableAutoRenewSurvey',
CHANGE_BILLING_CURRENCY: 'Settings_Subscription_Change_Billing_Currency',
CHANGE_PAYMENT_CURRENCY: 'Settings_Subscription_Change_Payment_Currency',
},
},
SAVE_THE_WORLD: {
Expand Down
142 changes: 142 additions & 0 deletions src/components/AddPaymentCard/PaymentCardChangeCurrencyForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import React, {useCallback, useMemo, useState} from 'react';
import {View} from 'react-native';
import type {ValueOf} from 'type-fest';
import FormProvider from '@components/Form/FormProvider';
import InputWrapper from '@components/Form/InputWrapper';
import type {FormInputErrors, FormOnyxValues} from '@components/Form/types';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/RadioListItem';
import TextInput from '@components/TextInput';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ValidationUtils from '@libs/ValidationUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import INPUT_IDS from '@src/types/form/ChangeBillingCurrencyForm';
import PaymentCardCurrencyHeader from './PaymentCardCurrencyHeader';
import PaymentCardCurrencyModal from './PaymentCardCurrencyModal';

type PaymentCardFormProps = {
initialCurrency?: ValueOf<typeof CONST.CURRENCY>;
isSecurityCodeRequired?: boolean;
changeBillingCurrency: (currency?: ValueOf<typeof CONST.CURRENCY>, values?: FormOnyxValues<typeof ONYXKEYS.FORMS.CHANGE_BILLING_CURRENCY_FORM>) => void;
};

const REQUIRED_FIELDS = [INPUT_IDS.SECURITY_CODE];

function PaymentCardChangeCurrencyForm({changeBillingCurrency, isSecurityCodeRequired, initialCurrency}: PaymentCardFormProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();

const [isCurrencyModalVisible, setIsCurrencyModalVisible] = useState(false);
const [currency, setCurrency] = useState<ValueOf<typeof CONST.CURRENCY>>(initialCurrency ?? CONST.CURRENCY.USD);

const validate = (values: FormOnyxValues<typeof ONYXKEYS.FORMS.CHANGE_BILLING_CURRENCY_FORM>): FormInputErrors<typeof ONYXKEYS.FORMS.CHANGE_BILLING_CURRENCY_FORM> => {
const errors = ValidationUtils.getFieldRequiredErrors(values, REQUIRED_FIELDS);

if (values.securityCode && !ValidationUtils.isValidSecurityCode(values.securityCode)) {
errors.securityCode = translate('addPaymentCardPage.error.securityCode');
}

return errors;
};

const {sections} = useMemo(
() => ({
sections: [
{
data: (Object.keys(CONST.CURRENCY) as Array<ValueOf<typeof CONST.CURRENCY>>).map((currencyItem) => ({
text: currencyItem,
value: currencyItem,
keyForList: currencyItem,
isSelected: currencyItem === currency,
})),
},
],
}),
[currency],
);

const showCurrenciesModal = useCallback(() => {
setIsCurrencyModalVisible(true);
}, []);

const changeCurrency = useCallback((selectedCurrency: ValueOf<typeof CONST.CURRENCY>) => {
setCurrency(selectedCurrency);
setIsCurrencyModalVisible(false);
}, []);

const selectCurrency = useCallback(
(selectedCurrency: ValueOf<typeof CONST.CURRENCY>) => {
setCurrency(selectedCurrency);
changeBillingCurrency(selectedCurrency);
},
[changeBillingCurrency],
);

if (isSecurityCodeRequired) {
return (
<FormProvider
formID={ONYXKEYS.FORMS.CHANGE_BILLING_CURRENCY_FORM}
validate={validate}
onSubmit={(values) => changeBillingCurrency(currency, values)}
submitButtonText={translate('common.save')}
scrollContextEnabled
style={[styles.mh5, styles.flexGrow1]}
>
<PaymentCardCurrencyHeader />
<>
<View style={[styles.mt5, styles.mhn5]}>
<MenuItemWithTopDescription
shouldShowRightIcon
title={currency}
descriptionTextStyle={styles.textNormal}
description={translate('common.currency')}
onPress={showCurrenciesModal}
/>
</View>
<InputWrapper
InputComponent={TextInput}
inputID={INPUT_IDS.SECURITY_CODE}
label={translate('addDebitCardPage.cvv')}
aria-label={translate('addDebitCardPage.cvv')}
role={CONST.ROLE.PRESENTATION}
maxLength={4}
containerStyles={[styles.mt5]}
inputMode={CONST.INPUT_MODE.NUMERIC}
/>
</>
<PaymentCardCurrencyModal
isVisible={isCurrencyModalVisible}
currencies={Object.keys(CONST.CURRENCY) as Array<ValueOf<typeof CONST.CURRENCY>>}
currentCurrency={currency}
onCurrencyChange={changeCurrency}
onClose={() => setIsCurrencyModalVisible(false)}
/>
</FormProvider>
);
}

return (
<View style={[styles.mh5, styles.flexGrow1]}>
<SelectionList
headerContent={<PaymentCardCurrencyHeader isSectionList />}
initiallyFocusedOptionKey={currency}
containerStyle={[styles.mhn5]}
sections={sections}
onSelectRow={(option) => {
selectCurrency(option.value);
}}
showScrollIndicator
shouldStopPropagation
shouldUseDynamicMaxToRenderPerBatch
ListItem={RadioListItem}
/>
</View>
);
}

PaymentCardChangeCurrencyForm.displayName = 'PaymentCardChangeCurrencyForm';

export default PaymentCardChangeCurrencyForm;
28 changes: 28 additions & 0 deletions src/components/AddPaymentCard/PaymentCardCurrencyHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import {View} from 'react-native';
import Text from '@components/Text';
import TextLink from '@components/TextLink';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';

function PaymentCardCurrencyHeader({isSectionList}: {isSectionList?: boolean}) {
const styles = useThemeStyles();
const {translate} = useLocalize();
return (
<View style={[isSectionList && styles.mh5]}>
<Text style={[styles.mt3, isSectionList && styles.mb5]}>
{`${translate('billingCurrency.note')}`}{' '}
<TextLink
style={styles.link}
href={CONST.PRICING}
>{`${translate('billingCurrency.noteLink')}`}</TextLink>{' '}
{`${translate('billingCurrency.noteDetails')}`}
</Text>
</View>
);
}

PaymentCardCurrencyHeader.displayName = 'PaymentCardCurrencyHeader';

export default PaymentCardCurrencyHeader;
Loading

0 comments on commit a72b000

Please sign in to comment.