Skip to content

Commit

Permalink
Merge branch 'main' into @chrispader/prevent-simultaneous-calls-to-Ge…
Browse files Browse the repository at this point in the history
…tMissingOnyxMessages
  • Loading branch information
chrispader committed Apr 2, 2024
2 parents 67f322e + ee5ab95 commit cd48514
Show file tree
Hide file tree
Showing 52 changed files with 937 additions and 301 deletions.
4 changes: 4 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# Every PR gets a review from an internal Expensify engineer
* @Expensify/pullerbear

# Assign the Design team to review changes to our styles & assets
src/styles/ @Expensify/design @Expensify/pullerbear
assets/ @Expensify/design @Expensify/pullerbear
7 changes: 7 additions & 0 deletions android/app/src/main/java/com/expensify/chat/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate

import com.oblador.performance.RNPerformance

class MainActivity : ReactActivity() {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
Expand Down Expand Up @@ -82,4 +84,9 @@ class MainActivity : ReactActivity() {
KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event)
return super.onKeyUp(keyCode, event)
}

override fun onStart() {
super.onStart()
RNPerformance.getInstance().mark("appCreationEnd", false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.modules.i18nmanager.I18nUtil
import com.facebook.soloader.SoLoader
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.oblador.performance.RNPerformance
import expo.modules.ApplicationLifecycleDispatcher
import expo.modules.ReactNativeHostWrapper

Expand Down Expand Up @@ -42,6 +43,8 @@ class MainApplication : MultiDexApplication(), ReactApplication {
override fun onCreate() {
super.onCreate()

RNPerformance.getInstance().mark("appCreationStart", false);

if (isOnfidoProcess()) {
return
}
Expand Down
6 changes: 6 additions & 0 deletions docs/redirects.csv
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ https://help.expensify.com/articles/expensify-classic/settings/Merge-Accounts,ht
https://help.expensify.com/articles/expensify-classic/settings/Preferences,https://help.expensify.com/expensify-classic/hubs/settings/account-settings
https://help.expensify.com/articles/expensify-classic/getting-started/support/Your-Expensify-Account-Manager,https://use.expensify.com/support
https://help.expensify.com/articles/expensify-classic/settings/Copilot,https://help.expensify.com/expensify-classic/hubs/copilots-and-delegates/
https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/reports/Currency,https://help.expensify.com/articles/expensify-classic/reports/Currency
https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/reports/Report-Fields-And-Titles,https://help.expensify.com/articles/expensify-classic/workspaces/reports/Report-Fields-And-Titles
https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/reports/Scheduled-Submit,https://help.expensify.com/articles/expensify-classic/workspaces/reports/Scheduled-Submit
https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Categories,https://help.expensify.com/articles/expensify-classic/workspaces/Categori
https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Expenses,https://help.expensify.com/expensify-classic/hubs/expenses/
https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Per-Diem,https://help.expensify.com/articles/expensify-classic/expenses/Per-Diem-Expenses
https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Budgets,https://help.expensify.com/articles/expensify-classic/workspaces/Budgets
https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Reimbursement,https://help.expensify.com/articles/expensify-classic/send-payments/Reimbursing-Reports
https://help.expensify.com/articles/expensify-classic/workspace-and-domain-settings/Tags,https://help.expensify.com/articles/expensify-classic/workspaces/Tags
2 changes: 2 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1827,6 +1827,8 @@ const CONST = {
RECEIPT: 'receipt',
DISTANCE: 'distance',
TAG: 'tag',
TAX_RATE: 'taxRate',
TAX_AMOUNT: 'taxAmount',
},
FOOTER: {
EXPENSE_MANAGEMENT_URL: `${USE_EXPENSIFY_URL}/expense-management`,
Expand Down
2 changes: 2 additions & 0 deletions src/Expensify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import NavigationRoot from './libs/Navigation/NavigationRoot';
import NetworkConnection from './libs/NetworkConnection';
import PushNotification from './libs/Notification/PushNotification';
import './libs/Notification/PushNotification/subscribePushNotification';
import Performance from './libs/Performance';
import StartupTimer from './libs/StartupTimer';
// This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection
import './libs/UnreadIndicatorUpdater';
Expand Down Expand Up @@ -130,6 +131,7 @@ function Expensify({

const onSplashHide = useCallback(() => {
setIsSplashHidden(true);
Performance.markEnd(CONST.TIMING.SIDEBAR_LOADED);
}, []);

useLayoutEffect(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -632,7 +632,7 @@ type OnyxValuesMapping = {
[ONYXKEYS.RECENTLY_USED_REPORT_FIELDS]: OnyxTypes.RecentlyUsedReportFields;
[ONYXKEYS.UPDATE_REQUIRED]: boolean;
[ONYXKEYS.PLAID_CURRENT_EVENT]: string;
[ONYXKEYS.LOGS]: Record<number, OnyxTypes.Log>;
[ONYXKEYS.LOGS]: OnyxTypes.CapturedLogs;
[ONYXKEYS.SHOULD_STORE_LOGS]: boolean;
[ONYXKEYS.CACHED_PDF_PATHS]: Record<string, string>;
[ONYXKEYS.POLICY_OWNERSHIP_CHANGE_CHECKS]: Record<string, OnyxTypes.PolicyOwnershipChangeChecks>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React from 'react';
import {Alert} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import Button from '@components/Button';
import Switch from '@components/Switch';
import TestToolRow from '@components/TestToolRow';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as Console from '@libs/actions/Console';
import {parseStringifiedMessages} from '@libs/Console';
import ONYXKEYS from '@src/ONYXKEYS';
import type {CapturedLogs, Log} from '@src/types/onyx';

type BaseClientSideLoggingToolMenuOnyxProps = {
/** Logs captured on the current device */
capturedLogs: OnyxEntry<CapturedLogs>;

/** Whether or not logs should be stored */
shouldStoreLogs: OnyxEntry<boolean>;
};

type BaseClientSideLoggingToolProps = {
/** Locally created file */
file?: {path: string; newFileName: string; size: number};
/** Action to run when pressing Share button */
onShareLogs?: () => void;
/** Action to run when disabling the switch */
onDisableLogging: (logs: Log[]) => void;
/** Action to run when enabling logging */
onEnableLogging?: () => void;
} & BaseClientSideLoggingToolMenuOnyxProps;

function BaseClientSideLoggingToolMenu({shouldStoreLogs, capturedLogs, file, onShareLogs, onDisableLogging, onEnableLogging}: BaseClientSideLoggingToolProps) {
const {translate} = useLocalize();

const onToggle = () => {
if (!shouldStoreLogs) {
Console.setShouldStoreLogs(true);

if (onEnableLogging) {
onEnableLogging();
}

return;
}

if (!capturedLogs) {
Alert.alert(translate('initialSettingsPage.troubleshoot.noLogsToShare'));
Console.disableLoggingAndFlushLogs();
return;
}

const logs = Object.values(capturedLogs);
const logsWithParsedMessages = parseStringifiedMessages(logs);

onDisableLogging(logsWithParsedMessages);
Console.disableLoggingAndFlushLogs();
};
const styles = useThemeStyles();
return (
<>
<TestToolRow title={translate('initialSettingsPage.troubleshoot.clientSideLogging')}>
<Switch
accessibilityLabel={translate('initialSettingsPage.troubleshoot.clientSideLogging')}
isOn={!!shouldStoreLogs}
onToggle={onToggle}
/>
</TestToolRow>
{!!file && (
<>
<Text style={[styles.textLabelSupporting, styles.mb4]}>{`path: ${file.path}`}</Text>
<TestToolRow title={translate('initialSettingsPage.debugConsole.logs')}>
<Button
small
text={translate('common.share')}
onPress={onShareLogs}
/>
</TestToolRow>
</>
)}
</>
);
}

BaseClientSideLoggingToolMenu.displayName = 'BaseClientSideLoggingToolMenu';

export default withOnyx<BaseClientSideLoggingToolProps, BaseClientSideLoggingToolMenuOnyxProps>({
capturedLogs: {
key: ONYXKEYS.LOGS,
},
shouldStoreLogs: {
key: ONYXKEYS.SHOULD_STORE_LOGS,
},
})(BaseClientSideLoggingToolMenu);
47 changes: 47 additions & 0 deletions src/components/ClientSideLoggingToolMenu/index.android.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, {useState} from 'react';
import RNFetchBlob from 'react-native-blob-util';
import Share from 'react-native-share';
import type {Log} from '@libs/Console';
import localFileCreate from '@libs/localFileCreate';
import BaseClientSideLoggingToolMenu from './BaseClientSideLoggingToolMenu';

function ClientSideLoggingToolMenu() {
const [file, setFile] = useState<{path: string; newFileName: string; size: number}>();

const createAndSaveFile = (logs: Log[]) => {
localFileCreate('logs', JSON.stringify(logs, null, 2)).then((localFile) => {
RNFetchBlob.MediaCollection.copyToMediaStore(
{
name: localFile.newFileName,
parentFolder: '',
mimeType: 'text/plain',
},
'Download',
localFile.path,
);
setFile(localFile);
});
};

const shareLogs = () => {
if (!file) {
return;
}
Share.open({
url: `file://${file.path}`,
});
};

return (
<BaseClientSideLoggingToolMenu
file={file}
onEnableLogging={() => setFile(undefined)}
onDisableLogging={createAndSaveFile}
onShareLogs={shareLogs}
/>
);
}

ClientSideLoggingToolMenu.displayName = 'ClientSideLoggingToolMenu';

export default ClientSideLoggingToolMenu;
37 changes: 37 additions & 0 deletions src/components/ClientSideLoggingToolMenu/index.ios.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, {useState} from 'react';
import Share from 'react-native-share';
import type {Log} from '@libs/Console';
import localFileCreate from '@libs/localFileCreate';
import BaseClientSideLoggingToolMenu from './BaseClientSideLoggingToolMenu';

function ClientSideLoggingToolMenu() {
const [file, setFile] = useState<{path: string; newFileName: string; size: number}>();

const createFile = (logs: Log[]) => {
localFileCreate('logs', JSON.stringify(logs, null, 2)).then((localFile) => {
setFile(localFile);
});
};

const shareLogs = () => {
if (!file) {
return;
}
Share.open({
url: `file://${file.path}`,
});
};

return (
<BaseClientSideLoggingToolMenu
file={file}
onEnableLogging={() => setFile(undefined)}
onDisableLogging={createFile}
onShareLogs={shareLogs}
/>
);
}

ClientSideLoggingToolMenu.displayName = 'ClientSideLoggingToolMenu';

export default ClientSideLoggingToolMenu;
16 changes: 16 additions & 0 deletions src/components/ClientSideLoggingToolMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import type {Log} from '@libs/Console';
import localFileDownload from '@libs/localFileDownload';
import BaseClientSideLoggingToolMenu from './BaseClientSideLoggingToolMenu';

function ClientSideLoggingToolMenu() {
const downloadFile = (logs: Log[]) => {
localFileDownload('logs', JSON.stringify(logs, null, 2));
};

return <BaseClientSideLoggingToolMenu onDisableLogging={downloadFile} />;
}

ClientSideLoggingToolMenu.displayName = 'ClientSideLoggingToolMenu';

export default ClientSideLoggingToolMenu;
29 changes: 24 additions & 5 deletions src/components/MoneyTemporaryForRefactorRequestConfirmationList.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import useLocalize from '@hooks/useLocalize';
import usePermissions from '@hooks/usePermissions';
import usePrevious from '@hooks/usePrevious';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import compose from '@libs/compose';
Expand All @@ -21,6 +22,7 @@ import * as MoneyRequestUtils from '@libs/MoneyRequestUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as OptionsListUtils from '@libs/OptionsListUtils';
import * as PolicyUtils from '@libs/PolicyUtils';
import {isTaxPolicyEnabled} from '@libs/PolicyUtils';
import * as ReceiptUtils from '@libs/ReceiptUtils';
import * as ReportUtils from '@libs/ReportUtils';
import playSound, {SOUNDS} from '@libs/Sound';
Expand Down Expand Up @@ -204,6 +206,11 @@ const defaultProps = {
isPolicyExpenseChat: false,
};

const getTaxAmount = (transaction, defaultTaxValue) => {
const percentage = (transaction.taxRate ? transaction.taxRate.data.value : defaultTaxValue) || '';
return TransactionUtils.calculateTaxAmount(percentage, transaction.amount);
};

function MoneyTemporaryForRefactorRequestConfirmationList({
bankAccountRoute,
canModifyParticipants,
Expand Down Expand Up @@ -277,7 +284,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({
const shouldShowTags = useMemo(() => isPolicyExpenseChat && OptionsListUtils.hasEnabledTags(policyTagLists), [isPolicyExpenseChat, policyTagLists]);

// A flag for showing tax rate
const shouldShowTax = isPolicyExpenseChat && policy && lodashGet(policy, 'tax.trackingEnabled', policy.isTaxTrackingEnabled);
const shouldShowTax = isTaxPolicyEnabled(isPolicyExpenseChat, policy);

// A flag for showing the billable field
const shouldShowBillable = !lodashGet(policy, 'disabledFields.defaultBillable', true);
Expand All @@ -292,9 +299,9 @@ function MoneyTemporaryForRefactorRequestConfirmationList({
);
const formattedTaxAmount = CurrencyUtils.convertToDisplayString(transaction.taxAmount, iouCurrencyCode);

const defaultTaxKey = taxRates.defaultExternalID;
const defaultTaxName = (defaultTaxKey && `${taxRates.taxes[defaultTaxKey].name} (${taxRates.taxes[defaultTaxKey].value}) • ${translate('common.default')}`) || '';
const taxRateTitle = (transaction.taxRate && transaction.taxRate.text) || defaultTaxName;
const taxRateTitle = TransactionUtils.getDefaultTaxName(taxRates, transaction);

const previousTransactionAmount = usePrevious(transaction.amount);

const isFocused = useIsFocused();
const [formError, setFormError] = useState('');
Expand Down Expand Up @@ -362,6 +369,18 @@ function MoneyTemporaryForRefactorRequestConfirmationList({
IOU.setMoneyRequestAmount_temporaryForRefactor(transaction.transactionID, amount, currency);
}, [shouldCalculateDistanceAmount, distance, rate, unit, transaction, currency]);

// Calculate and set tax amount in transaction draft
useEffect(() => {
const taxAmount = getTaxAmount(transaction, taxRates.defaultValue);
const amountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(Number.parseFloat(taxAmount));

if (transaction.taxAmount && previousTransactionAmount === transaction.amount) {
return IOU.setMoneyRequestTaxAmount(transaction.transactionID, transaction.taxAmount, true);
}

IOU.setMoneyRequestTaxAmount(transaction.transactionID, amountInSmallestCurrencyUnits, true);
}, [taxRates.defaultValue, transaction, previousTransactionAmount]);

/**
* Returns the participants with amount
* @param {Array} participants
Expand Down Expand Up @@ -855,7 +874,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({
key={`${taxRates.name}${formattedTaxAmount}`}
shouldShowRightIcon={!isReadOnly}
title={formattedTaxAmount}
description={taxRates.name}
description={translate('iou.taxAmount')}
style={[styles.moneyRequestMenuItem]}
titleStyle={styles.flex1}
onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_TAX_AMOUNT.getRoute(iouType, transaction.transactionID, reportID, Navigation.getActiveRouteWithoutParams()))}
Expand Down
Loading

0 comments on commit cd48514

Please sign in to comment.