Skip to content

Commit 9e28cbe

Browse files
committed
Merge branch 'main' into remove-onyx-connect-in-Task-p1
2 parents fcf81fa + 4cdf916 commit 9e28cbe

63 files changed

Lines changed: 1661 additions & 186 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

config/webpack/webpack.common.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -189,19 +189,12 @@ const getCommonConfiguration = ({file = '.env', platform = 'web'}: Environment):
189189
*/
190190
exclude: [new RegExp(`node_modules/(?!(${includeModules})/).*|.native.js$`)],
191191
},
192-
193192
// We are importing this worker as a string by using asset/source otherwise it will default to loading via an HTTPS request later.
194193
// This causes issues if we have gone offline before the pdfjs web worker is set up as we won't be able to load it from the server.
195194
{
196-
// eslint-disable-next-line prefer-regex-literals
197195
test: new RegExp('node_modules/pdfjs-dist/build/pdf.worker.min.mjs'),
198196
type: 'asset/source',
199197
},
200-
{
201-
// eslint-disable-next-line prefer-regex-literals
202-
test: new RegExp('node_modules/pdfjs-dist/legacy/build/pdf.worker.min.mjs'),
203-
type: 'asset/source',
204-
},
205198

206199
// Rule for react-native-web-webview
207200
{

cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@
438438
"numberformat",
439439
"objc",
440440
"oblador",
441+
"OCBC",
441442
"octocat",
442443
"officedocument",
443444
"oldarch",

docs/articles/expensify-classic/bank-accounts-and-payments/bank-accounts/Connect-Personal-Bank-Account.md

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,35 @@ However, if you encounter an error during this process, you can close the pop-up
5252

5353
Some banks, such as Chase, may display masked or tokenized account numbers when connected via Plaid. This is a security feature implemented by the bank and does not indicate any setup error. As long as the connection was successful and you see your account listed in your **Wallet**, reimbursements should process correctly.
5454

55-
## Why can't I add my HSBC bank account details in Singapore?
56-
57-
You can. HSBC typically includes the **branch code** which is the final three digits of the Swift Code (HSBCSGS2XXX) in their "Account Number". If you see figures like "146172002492", please drop first 3 digit (146) which is the Branch Code.
55+
## I can't find all the details for my bank in Singapore that you require. Where can I find them?
56+
57+
Expensify requires many fields to add a Singaporean Business account (for paying out) or Personal account (for receiving into). The Name and Address fields are self-explanatory. The other fields are:
58+
59+
- Swift Code
60+
- Account Number
61+
- Clearing Code
62+
63+
The Swift code can generally be found by searching for your bank [here](https://wise.com/gb/swift-codes/countries). It always contains a capitalized alphanumerical string of characters that end in either XXX or the bank **Branch Code**. There is no requirement to use anything but the XXX head office option.
64+
65+
The Account Number can usually be found on your statement or in your online banking portal. For example, HSBC typically includes the **Branch Code** (the final three digits of the Swift Code, e.g. HSBCSGS2XXX → 146) in the **Account Number**. If you see figures like `146172002492`, drop the first 3 digits (`146`), which form the Branch Code, and use the remainder as the Account No.
66+
67+
The Clearing Code is made up of both the **Bank Code** and the **Branch Code** to form a full 7-digit Clearing Code. Some bank-specific help is outlined below:
68+
69+
- **UOB (Standard Accounts)** — Bank Code: 7375. Branch Code: first 3 digits of Account No. Account No: unchanged.
70+
Example: `9102031012` → Branch Code `030`, Clearing Code `7375030`, Account No `9102031012`.
71+
- **DBS** — Bank Code: 7171. Branch Code: first 3 digits of Account No. Account No: unchanged.
72+
Example: `0052312891` → Branch Code `005`, Clearing Code `7171005`.
73+
- **POSBank** — Bank Code: 7171. Branch Code: always `081`. Account No: unchanged.
74+
Example: `84102395` → Branch Code `081`, Clearing Code `7171081`.
75+
- **OCBC** — Bank Code: 7339. Branch Code: first 3 digits of Account No. Account No: drop the first 3 digits.
76+
Example: `5501089550` → Branch Code `550`, Clearing Code `7339550`, Account No `1089550`.
77+
- **HSBC (Corporate)** — Bank Code: 7232. Branch Code: first 3 digits of Account No. Account No: drop the first 3 digits.
78+
Example: `146172002492` → Branch Code `146`, Clearing Code `7232146`, Account No `172002492`.
79+
- **HSBC (Personal)** — Bank Code: 9548. Branch Code: first 3 digits of Account No. Account No: drop the first 3 digits.
80+
Example: `146123843293` → Branch Code `146`, Clearing Code `9548146`, Account No `123843293`.
81+
- **SBI** — Bank Code: 7791. Branch Code: first 3 digits of Account No. Account No: drop the first 3 digits.
82+
Example: `27767012518738` → Branch Code `277`, Clearing Code `7791277`, Account No `67012518738`.
83+
- **Standard Chartered** — Bank Code: 9496. Branch Code: `0` + first 2 digits of Account No. Account No: full 10 digits.
84+
Example: `1803645852` → Branch Code `018`, Clearing Code `9496018`, Account No `1803645852`.
5885

5986
</div>

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
"test:debug": "TZ=utc NODE_OPTIONS='--inspect-brk --experimental-vm-modules' jest --runInBand",
4747
"perf-test": "NODE_OPTIONS=--experimental-vm-modules npx reassure",
4848
"typecheck": "NODE_OPTIONS=--max_old_space_size=8192 tsc",
49-
"lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=245 --cache --cache-location=node_modules/.cache/eslint",
49+
"lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=243 --cache --cache-location=node_modules/.cache/eslint",
5050
"lint-changed": "NODE_OPTIONS=--max_old_space_size=8192 ./scripts/lintChanged.sh",
5151
"lint-watch": "npx eslint-watch --watch --changed",
5252
"shellcheck": "./scripts/shellCheck.sh",

src/ONYXKEYS.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,9 @@ const ONYXKEYS = {
466466

467467
NVP_PRIVATE_CANCELLATION_DETAILS: 'nvp_private_cancellationDetails',
468468

469+
/** Stores the information about duplicated workspace */
470+
DUPLICATE_WORKSPACE: 'duplicateWorkspace',
471+
469472
/** Stores the information about currently edited advanced approval workflow */
470473
APPROVAL_WORKFLOW: 'approvalWorkflow',
471474

@@ -683,6 +686,8 @@ const ONYXKEYS = {
683686
WORKSPACE_CATEGORY_FORM: 'workspaceCategoryForm',
684687
WORKSPACE_CONFIRMATION_FORM: 'workspaceConfirmationForm',
685688
WORKSPACE_CONFIRMATION_FORM_DRAFT: 'workspaceConfirmationFormDraft',
689+
WORKSPACE_DUPLICATE_FORM: 'workspaceDuplicateForm',
690+
WORKSPACE_DUPLICATE_FORM_DRAFT: 'workspaceDuplicateFormDraft',
686691
WORKSPACE_CATEGORY_FORM_DRAFT: 'workspaceCategoryFormDraft',
687692
WORKSPACE_CATEGORY_DESCRIPTION_HINT_FORM: 'workspaceCategoryDescriptionHintForm',
688693
WORKSPACE_CATEGORY_DESCRIPTION_HINT_FORM_DRAFT: 'workspaceCategoryDescriptionHintFormDraft',
@@ -889,6 +894,7 @@ type OnyxFormValuesMapping = {
889894
[ONYXKEYS.FORMS.WORKSPACE_SETTINGS_FORM]: FormTypes.WorkspaceSettingsForm;
890895
[ONYXKEYS.FORMS.WORKSPACE_CATEGORY_FORM]: FormTypes.WorkspaceCategoryForm;
891896
[ONYXKEYS.FORMS.WORKSPACE_CONFIRMATION_FORM]: FormTypes.WorkspaceConfirmationForm;
897+
[ONYXKEYS.FORMS.WORKSPACE_DUPLICATE_FORM]: FormTypes.WorkspaceDuplicateForm;
892898
[ONYXKEYS.FORMS.ONBOARDING_WORKSPACE_DETAILS_FORM]: FormTypes.WorkspaceConfirmationForm;
893899
[ONYXKEYS.FORMS.WORKSPACE_TAG_FORM]: FormTypes.WorkspaceTagForm;
894900
[ONYXKEYS.FORMS.WORKSPACE_TAX_CUSTOM_NAME]: FormTypes.WorkspaceTaxCustomName;
@@ -1190,6 +1196,7 @@ type OnyxValuesMapping = {
11901196
[ONYXKEYS.ADD_NEW_COMPANY_CARD]: OnyxTypes.AddNewCompanyCardFeed;
11911197
[ONYXKEYS.ASSIGN_CARD]: OnyxTypes.AssignCard;
11921198
[ONYXKEYS.MOBILE_SELECTION_MODE]: boolean;
1199+
[ONYXKEYS.DUPLICATE_WORKSPACE]: OnyxTypes.DuplicateWorkspace;
11931200
[ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL]: string;
11941201
[ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL]: string;
11951202
[ONYXKEYS.NVP_BILLING_FUND_ID]: number;

src/ROUTES.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1872,6 +1872,14 @@ const ROUTES = {
18721872
return getUrlWithBackToParam(`workspaces/${policyID}/per-diem`, backTo);
18731873
},
18741874
},
1875+
WORKSPACE_DUPLICATE: {
1876+
route: 'workspace/:policyID/duplicate',
1877+
getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`workspace/${policyID}/duplicate`, backTo),
1878+
},
1879+
WORKSPACE_DUPLICATE_SELECT_FEATURES: {
1880+
route: 'workspace/:policyID/duplicate/select-features',
1881+
getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`workspace/${policyID}/duplicate/select-features`, backTo),
1882+
},
18751883
WORKSPACE_RECEIPT_PARTNERS: {
18761884
route: 'workspaces/:policyID/receipt-partners',
18771885
getRoute: (policyID: string | undefined, backTo?: string) => {

src/SCREENS.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ const SCREENS = {
192192
REPORT_DETAILS: 'Report_Details',
193193
REPORT_CHANGE_WORKSPACE: 'ReportChangeWorkspace',
194194
WORKSPACE_CONFIRMATION: 'Workspace_Confirmation',
195+
WORKSPACE_DUPLICATE: 'Workspace_Duplicate',
195196
REPORT_SETTINGS: 'Report_Settings',
196197
REPORT_DESCRIPTION: 'Report_Description',
197198
PARTICIPANTS: 'Participants',
@@ -387,6 +388,7 @@ const SCREENS = {
387388
},
388389

389390
WORKSPACE_CONFIRMATION: {ROOT: 'Workspace_Confirmation_Root'},
391+
WORKSPACE_DUPLICATE: {ROOT: 'Workspace_Duplicate_Root', SELECT_FEATURES: 'Workspace_Duplicate_Select_Features'},
390392

391393
WORKSPACES_LIST: 'Workspaces_List',
392394

src/components/MoneyReportHeader.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import {getThreadReportIDsForTransactions, getTotalAmountForIOUReportPreviewButt
2727
import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
2828
import type {PlatformStackRouteProp} from '@libs/Navigation/PlatformStackNavigation/types';
2929
import type {ReportsSplitNavigatorParamList, SearchFullscreenNavigatorParamList, SearchReportParamList} from '@libs/Navigation/types';
30-
import {buildOptimisticNextStepForPreventSelfApprovalsEnabled} from '@libs/NextStepUtils';
30+
import {getReportNextStep} from '@libs/NextStepUtils';
3131
import {isSecondaryActionAPaymentOption, selectPaymentType} from '@libs/PaymentUtils';
3232
import type {KYCFlowEvent, TriggerKYCFlow} from '@libs/PaymentUtils';
3333
import {getConnectedIntegration, getValidConnectedIntegration} from '@libs/PolicyUtils';
@@ -40,7 +40,6 @@ import {
4040
getArchiveReason,
4141
getIntegrationExportIcon,
4242
getIntegrationNameFromExportMessage as getIntegrationNameFromExportMessageUtils,
43-
getNextApproverAccountID,
4443
getNonHeldAndFullAmount,
4544
getTransactionsWithReceipts,
4645
hasHeldExpenses as hasHeldExpensesReportUtils,
@@ -50,7 +49,6 @@ import {
5049
isExported as isExportedUtils,
5150
isInvoiceReport as isInvoiceReportUtil,
5251
isProcessingReport,
53-
isReportOwner,
5452
navigateOnDeleteExpense,
5553
navigateToDetailsPage,
5654
} from '@libs/ReportUtils';
@@ -363,12 +361,7 @@ function MoneyReportHeader({
363361
const shouldShowStatusBar =
364362
hasAllPendingRTERViolations || shouldShowBrokenConnectionViolation || hasOnlyHeldExpenses || hasScanningReceipt || isPayAtEndExpense || hasOnlyPendingTransactions || hasDuplicates;
365363

366-
// When prevent self-approval is enabled & the current user is submitter AND they're submitting to themselves, we need to show the optimistic next step
367-
// We should always show this optimistic message for policies with preventSelfApproval
368-
// to avoid any flicker during transitions between online/offline states
369-
const nextApproverAccountID = getNextApproverAccountID(moneyRequestReport);
370-
const isSubmitterSameAsNextApprover = isReportOwner(moneyRequestReport) && nextApproverAccountID === moneyRequestReport?.ownerAccountID;
371-
const optimisticNextStep = isSubmitterSameAsNextApprover && policy?.preventSelfApproval ? buildOptimisticNextStepForPreventSelfApprovalsEnabled() : nextStep;
364+
const optimisticNextStep = getReportNextStep(nextStep, moneyRequestReport, transactions, policy);
372365

373366
const shouldShowNextStep = isFromPaidPolicy && !isInvoiceReport && !shouldShowStatusBar;
374367
const {nonHeldAmount, fullAmount, hasValidNonHeldAmount} = getNonHeldAndFullAmount(moneyRequestReport, shouldShowPayButton);

src/components/PDFThumbnail/index.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
import 'core-js/proposals/promise-with-resolvers';
22
// eslint-disable-next-line import/extensions
33
import pdfWorkerSource from 'pdfjs-dist/build/pdf.worker.min.mjs';
4-
// eslint-disable-next-line import/extensions
5-
import pdfWorkerLegacySource from 'pdfjs-dist/legacy/build/pdf.worker.min.mjs';
64
import React, {useMemo, useState} from 'react';
75
import {View} from 'react-native';
86
import {Document, pdfjs, Thumbnail} from 'react-pdf';
97
import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
108
import useThemeStyles from '@hooks/useThemeStyles';
119
import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL';
12-
import {isMobileSafari, isModernSafari} from '@libs/Browser';
1310
import PDFThumbnailError from './PDFThumbnailError';
1411
import type PDFThumbnailProps from './types';
1512

16-
const shouldUseLegacyWorker = isMobileSafari() && !isModernSafari();
17-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
18-
const pdfWorker = shouldUseLegacyWorker ? pdfWorkerLegacySource : pdfWorkerSource;
19-
2013
if (!pdfjs.GlobalWorkerOptions.workerSrc) {
21-
pdfjs.GlobalWorkerOptions.workerSrc = URL.createObjectURL(new Blob([pdfWorker], {type: 'text/javascript'}));
14+
pdfjs.GlobalWorkerOptions.workerSrc = URL.createObjectURL(new Blob([pdfWorkerSource], {type: 'text/javascript'}));
2215
}
2316

2417
function PDFThumbnail({previewSourceURL, style, isAuthTokenRequired = false, enabled = true, onPassword, onLoadError, onLoadSuccess}: PDFThumbnailProps) {

src/components/PriorityModeController.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {isReportParticipant, isValidReport} from '@libs/ReportUtils';
99
import CONST from '@src/CONST';
1010
import ONYXKEYS from '@src/ONYXKEYS';
1111
import SCREENS from '@src/SCREENS';
12+
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
1213
import FocusModeNotification from './FocusModeNotification';
1314

1415
/**
@@ -25,13 +26,12 @@ import FocusModeNotification from './FocusModeNotification';
2526
export default function PriorityModeController() {
2627
const [accountID] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.accountID, canBeMissing: true});
2728
const [isLoadingReportData] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA, {canBeMissing: true});
28-
const [isInFocusMode] = useOnyx(ONYXKEYS.NVP_PRIORITY_MODE, {selector: (priorityMode) => priorityMode === CONST.PRIORITY_MODE.GSD, canBeMissing: true});
29-
const [hasTriedFocusMode] = useOnyx(ONYXKEYS.NVP_TRY_FOCUS_MODE, {canBeMissing: true});
29+
const [isInFocusMode, isInFocusModeMetadata] = useOnyx(ONYXKEYS.NVP_PRIORITY_MODE, {selector: (priorityMode) => priorityMode === CONST.PRIORITY_MODE.GSD, canBeMissing: true});
30+
const [hasTriedFocusMode, hasTriedFocusModeMetadata] = useOnyx(ONYXKEYS.NVP_TRY_FOCUS_MODE, {canBeMissing: true});
3031
const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true});
3132
const currentRouteName = useCurrentRouteName();
3233
const [shouldShowModal, setShouldShowModal] = useState(false);
3334
const closeModal = useCallback(() => setShouldShowModal(false), []);
34-
3535
const validReportCount = useMemo(() => {
3636
let count = 0;
3737
Object.values(allReports ?? {}).forEach((report) => {
@@ -50,10 +50,11 @@ export default function PriorityModeController() {
5050
// Listen for state changes and trigger the #focus mode when appropriate
5151
useEffect(() => {
5252
// Wait for Onyx state to fully load
53-
if (isLoadingReportData !== false || isInFocusMode === undefined || hasTriedFocusMode === undefined || !accountID) {
53+
if (isLoadingReportData !== false || !accountID || isLoadingOnyxValue(isInFocusModeMetadata, hasTriedFocusModeMetadata)) {
5454
return;
5555
}
5656

57+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
5758
if (hasSwitched.current || isInFocusMode || hasTriedFocusMode) {
5859
return;
5960
}
@@ -74,7 +75,7 @@ export default function PriorityModeController() {
7475
updateChatPriorityMode(CONST.PRIORITY_MODE.GSD, true);
7576
setShouldShowModal(true);
7677
hasSwitched.current = true;
77-
}, [accountID, currentRouteName, hasTriedFocusMode, isInFocusMode, isLoadingReportData, validReportCount]);
78+
}, [accountID, currentRouteName, hasTriedFocusMode, hasTriedFocusModeMetadata, isInFocusMode, isInFocusModeMetadata, isLoadingReportData, validReportCount]);
7879

7980
return shouldShowModal ? <FocusModeNotification onClose={closeModal} /> : null;
8081
}

0 commit comments

Comments
 (0)