diff --git a/.github/actions/javascript/awaitStagingDeploys/awaitStagingDeploys.ts b/.github/actions/javascript/awaitStagingDeploys/awaitStagingDeploys.ts index 7de78e257dc4..26947193cd80 100644 --- a/.github/actions/javascript/awaitStagingDeploys/awaitStagingDeploys.ts +++ b/.github/actions/javascript/awaitStagingDeploys/awaitStagingDeploys.ts @@ -8,6 +8,7 @@ import {promiseDoWhile} from '@github/libs/promiseWhile'; type CurrentStagingDeploys = Awaited>['data']['workflow_runs']; function run() { + console.info('[awaitStagingDeploys] POLL RATE', CONST.POLL_RATE); console.info('[awaitStagingDeploys] run()'); console.info('[awaitStagingDeploys] getStringInput', getStringInput); console.info('[awaitStagingDeploys] GitHubUtils', GitHubUtils); diff --git a/.github/actions/javascript/awaitStagingDeploys/index.js b/.github/actions/javascript/awaitStagingDeploys/index.js index d84c6df1a0d3..c91313520673 100644 --- a/.github/actions/javascript/awaitStagingDeploys/index.js +++ b/.github/actions/javascript/awaitStagingDeploys/index.js @@ -12131,6 +12131,7 @@ const CONST_1 = __importDefault(__nccwpck_require__(9873)); const GithubUtils_1 = __importDefault(__nccwpck_require__(9296)); const promiseWhile_1 = __nccwpck_require__(9438); function run() { + console.info('[awaitStagingDeploys] POLL RATE', CONST_1.default.POLL_RATE); console.info('[awaitStagingDeploys] run()'); console.info('[awaitStagingDeploys] getStringInput', ActionUtils_1.getStringInput); console.info('[awaitStagingDeploys] GitHubUtils', GithubUtils_1.default); @@ -12742,7 +12743,12 @@ function promiseWhile(condition, action) { resolve(); return; } - Promise.resolve(actionResult).then(loop).catch(reject); + Promise.resolve(actionResult) + .then(() => { + // Set a timeout to delay the next loop iteration + setTimeout(loop, 1000); // 1000 ms delay + }) + .catch(reject); } }; loop(); diff --git a/.github/libs/promiseWhile.ts b/.github/libs/promiseWhile.ts index 01c061096d64..401b6ee2e18a 100644 --- a/.github/libs/promiseWhile.ts +++ b/.github/libs/promiseWhile.ts @@ -19,7 +19,12 @@ function promiseWhile(condition: () => boolean, action: (() => Promise) | return; } - Promise.resolve(actionResult).then(loop).catch(reject); + Promise.resolve(actionResult) + .then(() => { + // Set a timeout to delay the next loop iteration + setTimeout(loop, 1000); // 1000 ms delay + }) + .catch(reject); } }; loop(); diff --git a/android/app/build.gradle b/android/app/build.gradle index dca58eeb96ca..d5afad11a9fa 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001046602 - versionName "1.4.66-2" + versionCode 1001046700 + versionName "1.4.67-0" // 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" diff --git a/assets/images/arrow-right.svg b/assets/images/arrow-right.svg index df13c75ca414..8d2ded92e791 100644 --- a/assets/images/arrow-right.svg +++ b/assets/images/arrow-right.svg @@ -1 +1,10 @@ - \ No newline at end of file + + + + + + diff --git a/assets/images/back-left.svg b/assets/images/back-left.svg index 51164100ff59..2ddd554e9720 100644 --- a/assets/images/back-left.svg +++ b/assets/images/back-left.svg @@ -1 +1,10 @@ - \ No newline at end of file + + + + + + diff --git a/assets/images/tax.svg b/assets/images/coins.svg similarity index 100% rename from assets/images/tax.svg rename to assets/images/coins.svg diff --git a/assets/images/play.svg b/assets/images/play.svg index cb781459e44e..5f7e14969529 100644 --- a/assets/images/play.svg +++ b/assets/images/play.svg @@ -1 +1,6 @@ - \ No newline at end of file + + + + + diff --git a/assets/images/receipt-scan.svg b/assets/images/receipt-scan.svg new file mode 100644 index 000000000000..ecdf3cf2e115 --- /dev/null +++ b/assets/images/receipt-scan.svg @@ -0,0 +1,14 @@ + + + + + + + diff --git a/config/webpack/webpack.dev.ts b/config/webpack/webpack.dev.ts index 8f32a2d95c99..7a196da6b691 100644 --- a/config/webpack/webpack.dev.ts +++ b/config/webpack/webpack.dev.ts @@ -21,16 +21,12 @@ const getConfiguration = (environment: Environment): Promise => process.env.USE_WEB_PROXY === 'false' ? {} : { - proxy: { - // eslint-disable-next-line @typescript-eslint/naming-convention - '/api': 'http://[::1]:9000', - // eslint-disable-next-line @typescript-eslint/naming-convention - '/staging': 'http://[::1]:9000', - // eslint-disable-next-line @typescript-eslint/naming-convention - '/chat-attachments': 'http://[::1]:9000', - // eslint-disable-next-line @typescript-eslint/naming-convention - '/receipts': 'http://[::1]:9000', - }, + proxy: [ + { + context: ['/api', '/staging', '/chat-attachments', '/receipts'], + target: 'http://[::1]:9000', + }, + ], }; const baseConfig = getCommonConfiguration(environment); diff --git a/docs/articles/expensify-classic/copilots-and-delegates/Approval-Workflows.md b/docs/articles/expensify-classic/copilots-and-delegates/Approval-Workflows.md deleted file mode 100644 index 4c64ab1cefe4..000000000000 --- a/docs/articles/expensify-classic/copilots-and-delegates/Approval-Workflows.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: Managing employees and reports > Approval workflows -description: Set up the workflow that your employees reports should flow through. ---- - - -# About -## Overview - - -This document explains how to manage employee expense reports and approval workflows in Expensify. - - -### Approval workflow modes - - -#### Submit and close -- This is a workflow where no approval occurs in Expensify. -- *What happens after submission?* The report state becomes Closed and is available to view by the member set in Submit reports to and any Workspace Admins. -- *Who should use this workflow?* This mode should be used where you don't require approvals in Expensify. - - -#### Submit and approve -- *Submit and approve* is a workflow where all reports are submitted to a single member for approval. New policies have Submit and Approve enabled by default. -- *What happens after submission?* The report state becomes Processing and it will be sent to the member indicated in Submit reports to for approval. When the member approves the report, the state will become Approved. -- *Who should use this workflow?* This mode should be used where the same person is responsible for approving all reports for your organization. If submitters have different approvers or multiple levels of approval are required, then you will need to use Advance Approval. - - -#### Advanced Approval -- This approval mode is used to handle more complex workflows, including: - - *Multiple levels of approval.* This is for companies that require more than one person to approve a report before it can be reimbursed. The most common scenario is when an employee needs to submit to their manager, and their manager needs to approve and forward that report to their finance department for final approval. - - *Varying approval workflows.* For example, if a company has Team A submitting reports to Manager A, and Team B to Manager B, use Advanced Approval. Group Workspace Admins can also set amount thresholds in the case that a report needs to go to a different approver based on the amount. -- *What happens after submission?* After the report is submitted, it will follow the set approval chain. The report state will be Processing until it is Final Approved. We have provided examples of how to set this up below. -- *Who should use this workflow?* Organizations with complex workflows or 2+ levels of approval. This could be based on manager approvals or where reports over a certain size require additional approvals. -- *For further automation:* use Concierge auto-approval for reports. You can set specific rules and guidelines in your Group Workspace for your team's expenses; if all expenses are below the Manual Approval Threshold and adhere to all the rules, then we will automatically approve these reports on behalf of the approver right after they are submitted. - - -### How to set an approval workflow - -- Step-by-step instructions on how to set this up at the Workspace level [here](link-to-instructions). - -# Deep Dive - -### Setting multiple levels of approval -- 'Submits to' is different than 'Approves to'. - - *Submits to* - is the person you are sending your reports to for 1st level approval - - *Approves to* - is the person you are sending the reports you've approved for higher-level approval -- In the example below, a report needs to be approved by multiple managers: *Submitter > Manager > Director > Finance/Accountant* - - *Submitter (aka. Employee):* This is the person listed under the member column of the People page. - - *First Approver (Manager):* This is the person listed under the Submits to column of the People Page. - - *Second Approver (Director):* This is the person listed as 'Approves to' in the Settings of the First Approver. - - *Final Approver (Finance/Accountant):* This is the person listed as the 'Approves to' in the Settings of the Second Approver. -- This is what this setup looks like in the Workspace Members table. - - Bryan submits his reports to Jim for 1st level approval. -![Screenshot showing the People section of the workspace]({{site.url}}/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_1.png){:width="100%"} - - - All of the reports Jim approves are submitted to Kevin. Kevin is the 'approves to' in Jim's Settings. -![Screenshot of Policy Member Editor]({{site.url}}/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_2.png){:width="100%"} - - - All of the reports Kevin approves are submitted to Lucy. Lucy is the 'approves to' in Kevin's Settings. -![Screenshot of Policy Member Editor Approves to]({{site.url}}/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_3.png){:width="100%"} - - - - Lucy is the final approver, so she doesn't submit her reports to anyone for review. -![Screenshot of Policy Member Editor Final Approver]({{site.url}}/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_4.png){:width="100%"} - - -- The final outcome: The member in the Submits To line is different than the person noted as the Approves To. -### Adding additional approver levels -- You can also set a specific approver for Reports Totals in Settings. -![Screenshot of Policy Member Editor Approves to]({{site.url}}/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_5.png){:width="100%"} - -- An example: The submitter's manager can approve any report up to a certain limit, let's say $500, and forward it to accounting. However, if a report is over that $500 limit, it has to be also approved by the department head before being forwarded to accounting. -- To configure, click on Edit Settings next to the approving manager's email address and set the "If Report Total is Over" and "Then Approves to" fields. -![Screenshot of Workspace Member Settings]({{site.url}}/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_6.png){:width="100%"} -![Screenshot of Policy Member Editor Configure]({{site.url}}/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_7.png){:width="100%"} - - -### Setting category approvals -- If your expense reports should be reviewed by an additional approver based on specific categories or tags selected on the expenses within the report, set up category approvers and tag approvers. -- Category approvers can be set in the Category settings for each Workspace -- Tag approvers can be set in the Tag settings for each Workspace - - -#### Category approver -- A category approver is a member who is added to the approval workflow for any reports in your Expensify Workspace that contain expenses with a specific category. -- For example: Your HR director Jim may need to approve any relocation expenses submitted by employees. Set Jim up as the category approver for your Relocation category, then any reports containing Relocation expenses will first be routed to Jim before continuing through the approval workflow. -- Adding category approvers - - To add a category approver in your Workspace: - - Navigate to *Settings > Policies > Group > [Workspace Name] > Categories* - - Click *"Edit Settings"* next to the category that requires the additional approver - - Select an approver and click *"Save"* - - -#### Tag approver -- A tag approver is a member who is added to the approval workflow for any reports in your Expensify Workspace that contain expenses with a specific tag. -- For example: If employees must tag project-based expenses with the corresponding project tag. Pam, the project manager is set as the project approver for that project, then any reports containing expenses with that project tag will first be routed to Pam for approval before continuing through the approval workflow. -- Please note: Tag approvers are only supported for a single level of tags, not for multi-level tags. The order in which the report is sent to tag approvers relies on the date of the expense. -- Adding tag approvers - - To add a tag approver in your Workspace: - - Navigate to *Settings > Policies > Group > [Workspace Name] > Tags* - - Click in the "Approver" column next to the tag that requires an additional approver - - -Category and Tag approvers are inserted at the beginning of the approval workflow already set on the People page. This means the workflow will look something like: * *Submitter > Category Approver(s) > Tag Approver(s) > Submits To > Previous approver's Approves To.* - - -### Workflow enforcement -- If you want to ensure your employees cannot override the workflow you set - enable workflow enforcement. As a Workspace Admin, you can choose to enforce your approval workflow by going to Settings > Workspaces > Group > [Workspace Name] > People > Approval Mode. When enabled (which is the default setting for a new workspace), submitters and approvers must adhere to the set approval workflow (recommended). This setting does not apply to Workspace Admins, who are free to submit outside of this workflow diff --git a/docs/articles/new-expensify/chat/Expensify-Chat-For-Conference-Attendees.md b/docs/articles/new-expensify/chat/Expensify-Chat-For-Conference-Attendees.md deleted file mode 100644 index 30eeb4158902..000000000000 --- a/docs/articles/new-expensify/chat/Expensify-Chat-For-Conference-Attendees.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -title: Expensify Chat for Conference Attendees -description: Best Practices for Conference Attendees -redirect_from: articles/other/Expensify-Chat-For-Conference-Attendees/ ---- - -# Overview -Expensify Chat is the best way to meet and network with other event attendees. No more hunting down your contacts by walking the floor or trying to find someone in crowds at a party. Instead, you can use Expensify Chat to network and collaborate with others throughout the conference. - -To help get you set up for a great event, we’ve created a guide to help you get the most out of using Expensify Chat at the event you’re attending. - -# Getting Started -We’ve rounded up some resources to get you set up on Expensify Chat and ready to start connecting with your fellow attendees: - -- [How to get set up and start using Expensify Chat](https://help.expensify.com/articles/other/Everything-About-Chat#how-to-use-chat-in-expensify) -- [How to format text in Expensify Chat](https://help.expensify.com/articles/other/Everything-About-Chat#how-to-format-text) -- [How to flag content and/or users for moderation](https://help.expensify.com/articles/other/Everything-About-Chat#flagging-content-as-offensive) - -# Chat Best Practices -To get the most out of your experience at your conference and engage people in a meaningful conversation that will fulfill your goals instead of turning people off, here are some tips on what to do and not to do as an event attendee using Expensify Chat: - -**Do:** -- Chat about non-business topics like where the best coffee is around the event, what great lunch options are available, or where the parties are happening that night! -- Share pictures of your travel before the event to hype everyone up, during the event if you met that person you’ve been meaning to see for years, or a fun pic from a party. -- Try to create fun groups with your fellow attendees around common interests like touring a local sight, going for a morning run, or trying a famous restaurant. - -**Don't:** -- Pitch your services in public rooms like #social or speaking session rooms. -- Start a first message with a stranger with a sales pitch. -- Discuss controversial topics such as politics, religion, or anything you wouldn’t say on a first date. -- In general just remember that you are still here for business, your profile is public, and you’re representing yourself & company, so do not say anything you wouldn’t feel comfortable sharing in a business setting. - -**Pro-Tips:** -Get active in Chat early and often by having real conversations around thought leadership or non-business discussions to stand out from the crowd! Also if you’re in a session and are afraid to ask a question, just ask in the chat room to make sure you can discuss it with the speaker after the session ends. - -By following these tips you’ll ensure that your messages will not be [flagged for moderation](https://help.expensify.com/articles/other/Everything-About-Chat#flagging-content-as-offensive) and you will not mess it up for the rest of us. diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index cda215581cff..4d2e7ba3b992 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.4.66 + 1.4.67 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.66.2 + 1.4.67.0 FullStory OrgId diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 43728a764228..952fbeddd75e 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.4.66 + 1.4.67 CFBundleSignature ???? CFBundleVersion - 1.4.66.2 + 1.4.67.0 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index 5d52107c99bf..d6920d746496 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -11,9 +11,9 @@ CFBundleName $(PRODUCT_NAME) CFBundleShortVersionString - 1.4.66 + 1.4.67 CFBundleVersion - 1.4.66.2 + 1.4.67.0 NSExtension NSExtensionPointIdentifier diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 16616b0b7723..0398bd3b1324 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1380,10 +1380,25 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - react-native-quick-sqlite (8.0.0-beta.2): - - React - - React-callinvoker + - react-native-quick-sqlite (8.0.6): + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen - React-Core + - React-debug + - React-Fabric + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga - react-native-release-profiler (0.1.6): - glog - hermes-engine @@ -2062,7 +2077,6 @@ DEPENDENCIES: - ExpoImageManipulator (from `../node_modules/expo-image-manipulator/ios`) - ExpoModulesCore (from `../node_modules/expo-modules-core`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - - "fullstory_react-native (from `../node_modules/@fullstory/react-native`)" - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - libevent (~> 2.1.12) @@ -2500,7 +2514,7 @@ SPEC CHECKSUMS: react-native-pdf: cd256a00b9d65cb1008dcca2792d7bfb8874838d react-native-performance: 1aa5960d005159f4ab20be15b44714b53b44e075 react-native-plaid-link-sdk: 93870f8cd1de8e0acca5cb5020188bdc94e15db6 - react-native-quick-sqlite: bcc7a7a250a40222f18913a97cd356bf82d0a6c4 + react-native-quick-sqlite: f7b9f578b8b3b608dc742240b0103faae5b61f63 react-native-release-profiler: 42fc8e09b4f6f9b7d14cc5a15c72165e871c0918 react-native-render-html: 96c979fe7452a0a41559685d2f83b12b93edac8c react-native-safe-area-context: e8bdd57d9f8d34cc336f0ee6acb30712a8454446 @@ -2558,8 +2572,8 @@ SPEC CHECKSUMS: SDWebImageWebPCoder: af09429398d99d524cae2fe00f6f0f6e491ed102 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 - VisionCamera: 3033e0dd5272d46e97bcb406adea4ae0e6907abf - Yoga: 1b901a6d6eeba4e8a2e8f308f708691cdb5db312 + VisionCamera: 8c5c9c50b3d76018782a823cee2f0b8b628c8604 + Yoga: 64cd2a583ead952b0315d5135bf39e053ae9be70 PODFILE CHECKSUM: a25a81f2b50270f0c0bd0aff2e2ebe4d0b4ec06d diff --git a/package-lock.json b/package-lock.json index 9c645b6cbe94..47737d0223d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.66-2", + "version": "1.4.67-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.66-2", + "version": "1.4.67-0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -108,7 +108,7 @@ "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#da50d2c5c54e268499047f9cc98b8df4196c1ddf", "react-native-plaid-link-sdk": "11.5.0", "react-native-qrcode-svg": "^6.2.0", - "react-native-quick-sqlite": "^8.0.0-beta.2", + "react-native-quick-sqlite": "git+https://github.com/margelo/react-native-quick-sqlite#abc91857d4b3efb2020ec43abd2a508563b64316", "react-native-reanimated": "^3.7.2", "react-native-release-profiler": "^0.1.6", "react-native-render-html": "6.3.1", @@ -241,8 +241,8 @@ "wait-port": "^0.2.9", "webpack": "^5.76.0", "webpack-bundle-analyzer": "^4.5.0", - "webpack-cli": "^4.10.0", - "webpack-dev-server": "^4.9.3", + "webpack-cli": "^5.0.4", + "webpack-dev-server": "^5.0.4", "webpack-merge": "^5.8.0", "yaml": "^2.2.1" }, @@ -7092,9 +7092,10 @@ "license": "MIT" }, "node_modules/@leichtgewicht/ip-codec": { - "version": "2.0.4", - "dev": true, - "license": "MIT" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true }, "node_modules/@lwc/eslint-plugin-lwc": { "version": "1.7.2", @@ -12174,9 +12175,10 @@ } }, "node_modules/@types/bonjour": { - "version": "3.5.10", + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -12213,9 +12215,10 @@ } }, "node_modules/@types/connect-history-api-fallback": { - "version": "1.3.5", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", "dev": true, - "license": "MIT", "dependencies": { "@types/express-serve-static-core": "*", "@types/node": "*" @@ -12283,22 +12286,25 @@ "license": "MIT" }, "node_modules/@types/express": { - "version": "4.17.13", - "license": "MIT", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", + "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.30", - "license": "MIT", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "dependencies": { "@types/node": "*", "@types/qs": "*", - "@types/range-parser": "*" + "@types/range-parser": "*", + "@types/send": "*" } }, "node_modules/@types/fs-extra": { @@ -12358,6 +12364,11 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==" + }, "node_modules/@types/http-proxy": { "version": "1.17.9", "dev": true, @@ -12469,8 +12480,9 @@ "integrity": "sha512-H9VZ9YqE+H28FQVchC83RCs5xQ2J7mAAv6qdDEaWmXEVl3OpdH+xfrSUzQ1lp7U7oSTRZ0RvW08ASPJsYBi7Cw==" }, "node_modules/@types/mime": { - "version": "3.0.1", - "license": "MIT" + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==" }, "node_modules/@types/minimatch": { "version": "3.0.5", @@ -12489,6 +12501,15 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", @@ -12615,9 +12636,10 @@ } }, "node_modules/@types/retry": { - "version": "0.12.0", - "dev": true, - "license": "MIT" + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "dev": true }, "node_modules/@types/scheduler": { "version": "0.16.2", @@ -12627,20 +12649,32 @@ "version": "7.5.4", "license": "MIT" }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "node_modules/@types/serve-index": { - "version": "1.9.1", + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", "dev": true, - "license": "MIT", "dependencies": { "@types/express": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.0", - "license": "MIT", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dependencies": { - "@types/mime": "*", - "@types/node": "*" + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" } }, "node_modules/@types/setimmediate": { @@ -12649,9 +12683,10 @@ "license": "MIT" }, "node_modules/@types/sockjs": { - "version": "0.3.33", + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -12705,9 +12740,10 @@ } }, "node_modules/@types/ws": { - "version": "8.5.3", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -13549,31 +13585,42 @@ "license": "MIT" }, "node_modules/@webpack-cli/configtest": { - "version": "1.2.0", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", "dev": true, - "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, "peerDependencies": { - "webpack": "4.x.x || 5.x.x", - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" } }, "node_modules/@webpack-cli/info": { - "version": "1.5.0", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", "dev": true, - "license": "MIT", - "dependencies": { - "envinfo": "^7.7.3" + "engines": { + "node": ">=14.15.0" }, "peerDependencies": { - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" } }, "node_modules/@webpack-cli/serve": { - "version": "1.7.0", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", "dev": true, - "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, "peerDependencies": { - "webpack-cli": "4.x.x" + "webpack": "5.x.x", + "webpack-cli": "5.x.x" }, "peerDependenciesMeta": { "webpack-dev-server": { @@ -15531,21 +15578,15 @@ "license": "MIT" }, "node_modules/bonjour-service": { - "version": "1.0.13", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", "dev": true, - "license": "MIT", "dependencies": { - "array-flatten": "^2.1.2", - "dns-equal": "^1.0.0", "fast-deep-equal": "^3.1.3", "multicast-dns": "^7.2.5" } }, - "node_modules/bonjour-service/node_modules/array-flatten": { - "version": "2.1.2", - "dev": true, - "license": "MIT" - }, "node_modules/boolbase": { "version": "1.0.0", "license": "ISC" @@ -15961,6 +16002,21 @@ "version": "1.0.3", "license": "MIT" }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bytes": { "version": "3.0.0", "license": "MIT", @@ -17874,6 +17930,22 @@ "node": ">=0.10.0" } }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dev": true, + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/default-browser-id": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", @@ -17889,6 +17961,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/default-browser/node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/default-gateway": { "version": "6.0.3", "dev": true, @@ -18305,15 +18389,11 @@ "license": "MIT", "optional": true }, - "node_modules/dns-equal": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/dns-packet": { - "version": "5.4.0", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", "dev": true, - "license": "MIT", "dependencies": { "@leichtgewicht/ip-codec": "^2.0.1" }, @@ -23050,11 +23130,12 @@ } }, "node_modules/interpret": { - "version": "2.2.0", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, "node_modules/invariant": { @@ -23384,6 +23465,39 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -23453,6 +23567,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "license": "MIT", @@ -26748,6 +26874,16 @@ "language-subtag-registry": "~0.3.2" } }, + "node_modules/launch-editor": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", + "dev": true, + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, "node_modules/lazy-cache": { "version": "1.0.4", "license": "MIT", @@ -28401,8 +28537,9 @@ }, "node_modules/multicast-dns": { "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, - "license": "MIT", "dependencies": { "dns-packet": "^5.2.2", "thunky": "^1.0.2" @@ -29477,15 +29614,20 @@ } }, "node_modules/p-retry": { - "version": "4.6.2", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", + "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", "dev": true, - "license": "MIT", "dependencies": { - "@types/retry": "0.12.0", + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", "retry": "^0.13.1" }, "engines": { - "node": ">=8" + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-try": { @@ -31432,7 +31574,9 @@ } }, "node_modules/react-native-quick-sqlite": { - "version": "8.0.0-beta.2", + "version": "8.0.6", + "resolved": "git+ssh://git@github.com/margelo/react-native-quick-sqlite.git#abc91857d4b3efb2020ec43abd2a508563b64316", + "integrity": "sha512-/tBM6Oh8ye3d+hIhURRA9hlBausKqQmscgyt4ZcKluPjBti0bgLb0cyL8Gyd0cbCakaVgym25VyGjaeicV/01A==", "license": "MIT", "peerDependencies": { "react": "*", @@ -32653,14 +32797,15 @@ } }, "node_modules/rechoir": { - "version": "0.7.1", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, - "license": "MIT", "dependencies": { - "resolve": "^1.9.0" + "resolve": "^1.20.0" }, "engines": { - "node": ">= 0.10" + "node": ">= 10.13.0" } }, "node_modules/redent": { @@ -33050,8 +33195,9 @@ }, "node_modules/retry": { "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4" } @@ -33116,6 +33262,18 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-node": { "version": "1.0.0", "dev": true, @@ -33298,10 +33456,12 @@ "license": "MIT" }, "node_modules/selfsigned": { - "version": "2.0.1", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, - "license": "MIT", "dependencies": { + "@types/node-forge": "^1.3.0", "node-forge": "^1" }, "engines": { @@ -35310,8 +35470,9 @@ }, "node_modules/thunky": { "version": "1.1.0", - "dev": true, - "license": "MIT" + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true }, "node_modules/time-analytics-webpack-plugin": { "version": "0.1.17", @@ -36933,43 +37094,42 @@ } }, "node_modules/webpack-cli": { - "version": "4.10.0", + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", "dev": true, - "license": "MIT", "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.2.0", - "@webpack-cli/info": "^1.5.0", - "@webpack-cli/serve": "^1.7.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", "colorette": "^2.0.14", - "commander": "^7.0.0", + "commander": "^10.0.1", "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", "webpack-merge": "^5.7.3" }, "bin": { "webpack-cli": "bin/cli.js" }, "engines": { - "node": ">=10.13.0" + "node": ">=14.15.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "4.x.x || 5.x.x" + "webpack": "5.x.x" }, "peerDependenciesMeta": { "@webpack-cli/generators": { "optional": true }, - "@webpack-cli/migrate": { - "optional": true - }, "webpack-bundle-analyzer": { "optional": true }, @@ -36984,11 +37144,12 @@ "license": "MIT" }, "node_modules/webpack-cli/node_modules/commander": { - "version": "7.2.0", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true, - "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=14" } }, "node_modules/webpack-dev-middleware": { @@ -37069,54 +37230,59 @@ } }, "node_modules/webpack-dev-server": { - "version": "4.10.0", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz", + "integrity": "sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA==", "dev": true, - "license": "MIT", "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.1", + "@types/bonjour": "^3.5.13", + "@types/connect-history-api-fallback": "^1.5.4", + "@types/express": "^4.17.21", + "@types/serve-index": "^1.9.4", + "@types/serve-static": "^1.15.5", + "@types/sockjs": "^0.3.36", + "@types/ws": "^8.5.10", "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", + "bonjour-service": "^1.2.1", + "chokidar": "^3.6.0", "colorette": "^2.0.10", "compression": "^1.7.4", "connect-history-api-fallback": "^2.0.0", "default-gateway": "^6.0.3", "express": "^4.17.3", "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", + "html-entities": "^2.4.0", "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.0.1", + "ipaddr.js": "^2.1.0", + "launch-editor": "^2.6.1", + "open": "^10.0.3", + "p-retry": "^6.2.0", + "rimraf": "^5.0.5", + "schema-utils": "^4.2.0", + "selfsigned": "^2.4.1", "serve-index": "^1.9.1", "sockjs": "^0.3.24", "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.4.2" + "webpack-dev-middleware": "^7.1.0", + "ws": "^8.16.0" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" + "webpack": "^5.0.0" }, "peerDependenciesMeta": { + "webpack": { + "optional": true + }, "webpack-cli": { "optional": true } @@ -37124,8 +37290,9 @@ }, "node_modules/webpack-dev-server/node_modules/ajv-keywords": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, - "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -37133,10 +37300,54 @@ "ajv": "^8.8.2" } }, + "node_modules/webpack-dev-server/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/webpack-dev-server/node_modules/colorette": { "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", "dev": true, - "license": "MIT" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/glob": { + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/webpack-dev-server/node_modules/ipaddr.js": { "version": "2.1.0", @@ -37146,21 +37357,86 @@ "node": ">= 10" } }, - "node_modules/webpack-dev-server/node_modules/memfs": { - "version": "3.5.3", + "node_modules/webpack-dev-server/node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", "dev": true, - "license": "Unlicense", "dependencies": { - "fs-monkey": "^1.0.4" + "is-inside-container": "^1.0.0" }, "engines": { - "node": ">= 4.0.0" + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webpack-dev-server/node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/webpack-dev-server/node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dev": true, + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/webpack-dev-server/node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/webpack-dev-server/node_modules/schema-utils": { "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dev": true, - "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", @@ -37176,25 +37452,32 @@ } }, "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { - "version": "5.3.3", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz", + "integrity": "sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA==", "dev": true, - "license": "MIT", "dependencies": { "colorette": "^2.0.10", - "memfs": "^3.4.3", + "memfs": "^4.6.0", "mime-types": "^2.1.31", + "on-finished": "^2.4.1", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } } }, "node_modules/webpack-hot-middleware": { diff --git a/package.json b/package.json index 2860b3c1d3a9..b01a03dc109f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.66-2", + "version": "1.4.67-0", "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.", @@ -160,7 +160,7 @@ "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#da50d2c5c54e268499047f9cc98b8df4196c1ddf", "react-native-plaid-link-sdk": "11.5.0", "react-native-qrcode-svg": "^6.2.0", - "react-native-quick-sqlite": "^8.0.0-beta.2", + "react-native-quick-sqlite": "git+https://github.com/margelo/react-native-quick-sqlite#abc91857d4b3efb2020ec43abd2a508563b64316", "react-native-reanimated": "^3.7.2", "react-native-release-profiler": "^0.1.6", "react-native-render-html": "6.3.1", @@ -293,8 +293,8 @@ "wait-port": "^0.2.9", "webpack": "^5.76.0", "webpack-bundle-analyzer": "^4.5.0", - "webpack-cli": "^4.10.0", - "webpack-dev-server": "^4.9.3", + "webpack-cli": "^5.0.4", + "webpack-dev-server": "^5.0.4", "webpack-merge": "^5.8.0", "yaml": "^2.2.1" }, diff --git a/patches/react-native-quick-sqlite+8.0.0-beta.2.patch b/patches/react-native-quick-sqlite+8.0.0-beta.2.patch deleted file mode 100644 index b5810c903873..000000000000 --- a/patches/react-native-quick-sqlite+8.0.0-beta.2.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/node_modules/react-native-quick-sqlite/android/build.gradle b/node_modules/react-native-quick-sqlite/android/build.gradle -index 323d34e..c2d0c44 100644 ---- a/node_modules/react-native-quick-sqlite/android/build.gradle -+++ b/node_modules/react-native-quick-sqlite/android/build.gradle -@@ -90,7 +90,6 @@ android { - externalNativeBuild { - cmake { - cppFlags "-O2", "-fexceptions", "-frtti", "-std=c++1y", "-DONANDROID" -- abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' - arguments '-DANDROID_STL=c++_shared', - "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}", - "-DSQLITE_FLAGS='${SQLITE_FLAGS ? SQLITE_FLAGS : ''}'" diff --git a/src/CONST.ts b/src/CONST.ts index e160b4e24627..83690d5e9a85 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4,8 +4,10 @@ import dateSubtract from 'date-fns/sub'; import Config from 'react-native-config'; import * as KeyCommand from 'react-native-key-command'; import type {ValueOf} from 'type-fest'; +import BankAccount from './libs/models/BankAccount'; import * as Url from './libs/Url'; import SCREENS from './SCREENS'; +import type PlaidBankAccount from './types/onyx/PlaidBankAccount'; import type {Unit} from './types/onyx/Policy'; type RateAndUnit = { @@ -53,6 +55,7 @@ const chatTypes = { POLICY_ROOM: 'policyRoom', POLICY_EXPENSE_CHAT: 'policyExpenseChat', SELF_DM: 'selfDM', + INVOICE: 'invoice', } as const; // Explicit type annotation is required @@ -76,8 +79,13 @@ const CONST = { // Note: Group and Self-DM excluded as these are not tied to a Workspace WORKSPACE_ROOM_TYPES: [chatTypes.POLICY_ADMINS, chatTypes.POLICY_ANNOUNCE, chatTypes.DOMAIN_ALL, chatTypes.POLICY_ROOM, chatTypes.POLICY_EXPENSE_CHAT], ANDROID_PACKAGE_NAME, - ANIMATED_HIGHLIGHT_DELAY: 500, - ANIMATED_HIGHLIGHT_DURATION: 500, + WORKSPACE_ENABLE_FEATURE_REDIRECT_DELAY: 100, + ANIMATED_HIGHLIGHT_ENTRY_DELAY: 50, + ANIMATED_HIGHLIGHT_ENTRY_DURATION: 300, + ANIMATED_HIGHLIGHT_START_DELAY: 10, + ANIMATED_HIGHLIGHT_START_DURATION: 300, + ANIMATED_HIGHLIGHT_END_DELAY: 800, + ANIMATED_HIGHLIGHT_END_DURATION: 2000, ANIMATED_TRANSITION: 300, ANIMATED_TRANSITION_FROM_VALUE: 100, ANIMATION_IN_TIMING: 100, @@ -798,6 +806,7 @@ const CONST = { EXPENSE: 'expense', IOU: 'iou', TASK: 'task', + INVOICE: 'invoice', }, CHAT_TYPE: chatTypes, WORKSPACE_CHAT_ROOMS: { @@ -841,6 +850,16 @@ const CONST = { OWNER_EMAIL_FAKE: '__FAKE__', OWNER_ACCOUNT_ID_FAKE: 0, DEFAULT_REPORT_NAME: 'Chat Report', + PERMISSIONS: { + READ: 'read', + WRITE: 'write', + SHARE: 'share', + OWN: 'own', + }, + INVOICE_RECEIVER_TYPE: { + INDIVIDUAL: 'individual', + BUSINESS: 'policy', + }, }, NEXT_STEP: { FINISHED: 'Finished!', @@ -1371,6 +1390,13 @@ const CONST = { ERROR: 'ERROR', EXIT: 'EXIT', }, + DEFAULT_DATA: { + bankName: '', + plaidAccessToken: '', + bankAccounts: [] as PlaidBankAccount[], + isLoading: false, + errors: {}, + }, }, ONFIDO: { @@ -1449,6 +1475,7 @@ const CONST = { PAY: 'pay', SPLIT: 'split', REQUEST: 'request', + INVOICE: 'invoice', SUBMIT: 'submit', TRACK: 'track', }, @@ -3942,31 +3969,43 @@ const CONST = { DEBUG: 'DEBUG', }, }, - REIMBURSEMENT_ACCOUNT_SUBSTEP_INDEX: { - BANK_ACCOUNT: { - ACCOUNT_NUMBERS: 0, - }, - PERSONAL_INFO: { - LEGAL_NAME: 0, - DATE_OF_BIRTH: 1, - SSN: 2, - ADDRESS: 3, - }, - BUSINESS_INFO: { - BUSINESS_NAME: 0, - TAX_ID_NUMBER: 1, - COMPANY_WEBSITE: 2, - PHONE_NUMBER: 3, - COMPANY_ADDRESS: 4, - COMPANY_TYPE: 5, - INCORPORATION_DATE: 6, - INCORPORATION_STATE: 7, - }, - UBO: { - LEGAL_NAME: 0, - DATE_OF_BIRTH: 1, - SSN: 2, - ADDRESS: 3, + REIMBURSEMENT_ACCOUNT: { + DEFAULT_DATA: { + achData: { + state: BankAccount.STATE.SETUP, + }, + isLoading: false, + errorFields: {}, + errors: {}, + maxAttemptsReached: false, + shouldShowResetModal: false, + }, + SUBSTEP_INDEX: { + BANK_ACCOUNT: { + ACCOUNT_NUMBERS: 0, + }, + PERSONAL_INFO: { + LEGAL_NAME: 0, + DATE_OF_BIRTH: 1, + SSN: 2, + ADDRESS: 3, + }, + BUSINESS_INFO: { + BUSINESS_NAME: 0, + TAX_ID_NUMBER: 1, + COMPANY_WEBSITE: 2, + PHONE_NUMBER: 3, + COMPANY_ADDRESS: 4, + COMPANY_TYPE: 5, + INCORPORATION_DATE: 6, + INCORPORATION_STATE: 7, + }, + UBO: { + LEGAL_NAME: 0, + DATE_OF_BIRTH: 1, + SSN: 2, + ADDRESS: 3, + }, }, }, CURRENCY_TO_DEFAULT_MILEAGE_RATE: JSON.parse(`{ diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 095fdafd0e6d..1a27d691e2ef 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -358,6 +358,9 @@ const ONYXKEYS = { /** This is deprecated, but needed for a migration, so we still need to include it here so that it will be initialized in Onyx.init */ DEPRECATED_POLICY_MEMBER_LIST: 'policyMemberList_', + + // Search Page related + SNAPSHOT: 'snapshot_', }, /** List of Form ids */ @@ -561,6 +564,7 @@ type OnyxCollectionValuesMapping = { [ONYXKEYS.COLLECTION.NEXT_STEP]: OnyxTypes.ReportNextStep; [ONYXKEYS.COLLECTION.POLICY_JOIN_MEMBER]: OnyxTypes.PolicyJoinMember; [ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS]: OnyxTypes.PolicyConnectionSyncProgress; + [ONYXKEYS.COLLECTION.SNAPSHOT]: OnyxTypes.SearchResults; }; type OnyxValuesMapping = { diff --git a/src/components/Avatar.tsx b/src/components/Avatar.tsx index 99183a1e6ba7..bf48894beaab 100644 --- a/src/components/Avatar.tsx +++ b/src/components/Avatar.tsx @@ -7,7 +7,6 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ReportUtils from '@libs/ReportUtils'; import type {AvatarSource} from '@libs/UserUtils'; -import * as UserUtils from '@libs/UserUtils'; import type {AvatarSizeName} from '@styles/utils'; import CONST from '@src/CONST'; import type {AvatarType} from '@src/types/onyx/OnyxCommon'; @@ -50,13 +49,10 @@ type AvatarProps = { /** Owner of the avatar. If user, displayName. If workspace, policy name */ name?: string; - - /** Optional account id if it's user avatar */ - accountID?: number; }; function Avatar({ - source: originalSource, + source, imageStyles, iconAdditionalStyles, containerStyles, @@ -66,7 +62,6 @@ function Avatar({ fallbackIconTestID = '', type = CONST.ICON_TYPE_AVATAR, name = '', - accountID, }: AvatarProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -77,17 +72,16 @@ function Avatar({ useEffect(() => { setImageError(false); - }, [originalSource]); + }, [source]); const isWorkspace = type === CONST.ICON_TYPE_WORKSPACE; - const iconSize = StyleUtils.getAvatarSize(size); + const imageStyle: StyleProp = [StyleUtils.getAvatarStyle(size), imageStyles, styles.noBorderRadius]; const iconStyle = imageStyles ? [StyleUtils.getAvatarStyle(size), styles.bgTransparent, imageStyles] : undefined; // We pass the color styles down to the SVG for the workspace and fallback avatar. - const source = isWorkspace ? originalSource : UserUtils.getAvatar(originalSource, accountID); - const useFallBackAvatar = imageError || !source || source === Expensicons.FallbackAvatar; + const useFallBackAvatar = imageError || source === Expensicons.FallbackAvatar || !source; const fallbackAvatar = isWorkspace ? ReportUtils.getDefaultWorkspaceAvatar(name) : fallbackIcon || Expensicons.FallbackAvatar; const fallbackAvatarTestID = isWorkspace ? ReportUtils.getDefaultWorkspaceAvatarTestID(name) : fallbackIconTestID || 'SvgFallbackAvatar Icon'; const avatarSource = useFallBackAvatar ? fallbackAvatar : source; diff --git a/src/components/AvatarWithDisplayName.tsx b/src/components/AvatarWithDisplayName.tsx index c7a4ece0de97..8942bf97a7dd 100644 --- a/src/components/AvatarWithDisplayName.tsx +++ b/src/components/AvatarWithDisplayName.tsx @@ -60,7 +60,8 @@ function AvatarWithDisplayName({ const title = ReportUtils.getReportName(report); const subtitle = ReportUtils.getChatRoomSubtitle(report); const parentNavigationSubtitleData = ReportUtils.getParentNavigationSubtitle(report); - const isMoneyRequestOrReport = ReportUtils.isMoneyRequestReport(report) || ReportUtils.isMoneyRequest(report) || ReportUtils.isTrackExpenseReport(report); + const isMoneyRequestOrReport = + ReportUtils.isMoneyRequestReport(report) || ReportUtils.isMoneyRequest(report) || ReportUtils.isTrackExpenseReport(report) || ReportUtils.isInvoiceReport(report); const icons = ReportUtils.getIcons(report, personalDetails, null, '', -1, policy); const ownerPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(report?.ownerAccountID ? [report.ownerAccountID] : [], personalDetails); const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(Object.values(ownerPersonalDetails) as PersonalDetails[], false); diff --git a/src/components/AvatarWithIndicator.tsx b/src/components/AvatarWithIndicator.tsx index 1bf18afb70ff..42b91b3d2d71 100644 --- a/src/components/AvatarWithIndicator.tsx +++ b/src/components/AvatarWithIndicator.tsx @@ -11,10 +11,7 @@ import Tooltip from './Tooltip'; type AvatarWithIndicatorProps = { /** URL for the avatar */ - source?: UserUtils.AvatarSource; - - /** account id if it's user avatar */ - accountID?: number; + source: UserUtils.AvatarSource; /** To show a tooltip on hover */ tooltipText?: string; @@ -26,7 +23,7 @@ type AvatarWithIndicatorProps = { isLoading?: boolean; }; -function AvatarWithIndicator({source, accountID, tooltipText = '', fallbackIcon = Expensicons.FallbackAvatar, isLoading = true}: AvatarWithIndicatorProps) { +function AvatarWithIndicator({source, tooltipText = '', fallbackIcon = Expensicons.FallbackAvatar, isLoading = true}: AvatarWithIndicatorProps) { const styles = useThemeStyles(); return ( @@ -38,7 +35,7 @@ function AvatarWithIndicator({source, accountID, tooltipText = '', fallbackIcon <> diff --git a/src/components/Banner.tsx b/src/components/Banner.tsx index a46b37c986ba..72dc53cceb39 100644 --- a/src/components/Banner.tsx +++ b/src/components/Banner.tsx @@ -7,6 +7,7 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import getButtonState from '@libs/getButtonState'; import CONST from '@src/CONST'; +import type IconAsset from '@src/types/utils/IconAsset'; import Hoverable from './Hoverable'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; @@ -17,7 +18,13 @@ import Tooltip from './Tooltip'; type BannerProps = { /** Text to display in the banner. */ - text: string; + text?: string; + + /** Content to display in the banner. */ + content?: React.ReactNode; + + /** The icon asset to display to the left of the text */ + icon?: IconAsset | null; /** Should this component render the left-aligned exclamation icon? */ shouldShowIcon?: boolean; @@ -41,7 +48,18 @@ type BannerProps = { textStyles?: StyleProp; }; -function Banner({text, onClose, onPress, containerStyles, textStyles, shouldRenderHTML = false, shouldShowIcon = false, shouldShowCloseButton = false}: BannerProps) { +function Banner({ + text, + content, + icon = Expensicons.Exclamation, + onClose, + onPress, + containerStyles, + textStyles, + shouldRenderHTML = false, + shouldShowIcon = false, + shouldShowCloseButton = false, +}: BannerProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -65,15 +83,17 @@ function Banner({text, onClose, onPress, containerStyles, textStyles, shouldRend ]} > - {shouldShowIcon && ( + {shouldShowIcon && icon && ( )} - {shouldRenderHTML ? ( + {content && content} + + {shouldRenderHTML && text ? ( ) : ( {}, opti false, optionItem.isPinned, !!optionItem.isUnread, - [], - false, - () => {}, - false, - optionItem.transactionThreadReportID, ); }; diff --git a/src/components/LHNOptionsList/OptionRowLHNData.tsx b/src/components/LHNOptionsList/OptionRowLHNData.tsx index 1d6cc636f939..c80017c39a3d 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.tsx +++ b/src/components/LHNOptionsList/OptionRowLHNData.tsx @@ -27,7 +27,6 @@ function OptionRowLHNData({ lastReportActionTransaction = {}, transactionViolations, canUseViolations, - transactionThreadReport, ...propsToForward }: OptionRowLHNDataProps) { const reportID = propsToForward.reportID; @@ -48,7 +47,6 @@ function OptionRowLHNData({ policy, parentReportAction, hasViolations: !!shouldDisplayViolations, - transactionThreadReport, }); if (deepEqual(item, optionItemRef.current)) { return optionItemRef.current; @@ -72,7 +70,6 @@ function OptionRowLHNData({ transactionViolations, canUseViolations, receiptTransactions, - transactionThreadReport, ]); return ( diff --git a/src/components/LHNOptionsList/types.ts b/src/components/LHNOptionsList/types.ts index 79b5f5ad3889..0f0c921747b4 100644 --- a/src/components/LHNOptionsList/types.ts +++ b/src/components/LHNOptionsList/types.ts @@ -74,9 +74,6 @@ type OptionRowLHNDataProps = { /** The full data of the report */ fullReport: OnyxEntry; - /** The transaction thread report associated with the current report – applicable only for one-transaction money reports */ - transactionThreadReport: OnyxEntry; - /** The policy which the user has access to and which the report could be tied to */ policy?: OnyxEntry; diff --git a/src/components/Modal/BaseModal.tsx b/src/components/Modal/BaseModal.tsx index 2448f65a75f4..38701389f78b 100644 --- a/src/components/Modal/BaseModal.tsx +++ b/src/components/Modal/BaseModal.tsx @@ -46,6 +46,7 @@ function BaseModal( onBackdropPress, shouldEnableNewFocusManagement = false, restoreFocusType, + shouldUseModalPaddingStyle = true, }: BaseModalProps, ref: React.ForwardedRef, ) { @@ -173,21 +174,26 @@ function BaseModal( paddingRight: safeAreaPaddingRight, } = StyleUtils.getSafeAreaPadding(safeAreaInsets); - const modalPaddingStyles = StyleUtils.getModalPaddingStyles({ - safeAreaPaddingTop, - safeAreaPaddingBottom, - safeAreaPaddingLeft, - safeAreaPaddingRight, - shouldAddBottomSafeAreaMargin, - shouldAddTopSafeAreaMargin, - shouldAddBottomSafeAreaPadding: !keyboardStateContextValue?.isKeyboardShown && shouldAddBottomSafeAreaPadding, - shouldAddTopSafeAreaPadding, - modalContainerStyleMarginTop: modalContainerStyle.marginTop, - modalContainerStyleMarginBottom: modalContainerStyle.marginBottom, - modalContainerStylePaddingTop: modalContainerStyle.paddingTop, - modalContainerStylePaddingBottom: modalContainerStyle.paddingBottom, - insets: safeAreaInsets, - }); + const modalPaddingStyles = shouldUseModalPaddingStyle + ? StyleUtils.getModalPaddingStyles({ + safeAreaPaddingTop, + safeAreaPaddingBottom, + safeAreaPaddingLeft, + safeAreaPaddingRight, + shouldAddBottomSafeAreaMargin, + shouldAddTopSafeAreaMargin, + shouldAddBottomSafeAreaPadding: !keyboardStateContextValue?.isKeyboardShown && shouldAddBottomSafeAreaPadding, + shouldAddTopSafeAreaPadding, + modalContainerStyleMarginTop: modalContainerStyle.marginTop, + modalContainerStyleMarginBottom: modalContainerStyle.marginBottom, + modalContainerStylePaddingTop: modalContainerStyle.paddingTop, + modalContainerStylePaddingBottom: modalContainerStyle.paddingBottom, + insets: safeAreaInsets, + }) + : { + paddingLeft: safeAreaPaddingLeft ?? 0, + paddingRight: safeAreaPaddingRight ?? 0, + }; return ( // this is a workaround for modal not being visible on the new arch in some cases diff --git a/src/components/Modal/types.ts b/src/components/Modal/types.ts index 6111987e9c8d..bb17f2b4846f 100644 --- a/src/components/Modal/types.ts +++ b/src/components/Modal/types.ts @@ -77,6 +77,9 @@ type BaseModalProps = Partial & { /** How to re-focus after the modal is dismissed */ restoreFocusType?: ValueOf; + + /** Should we apply padding style in modal itself. If this value is false, we will handle it in ScreenWrapper */ + shouldUseModalPaddingStyle?: boolean; }; export default BaseModalProps; diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx index 9ad5c8b090eb..5db2839654a0 100644 --- a/src/components/MoneyRequestHeader.tsx +++ b/src/components/MoneyRequestHeader.tsx @@ -108,12 +108,8 @@ function MoneyRequestHeader({ if (isOnHold) { IOU.unholdRequest(iouTransactionID, report?.reportID); } else { - if (!policy?.type) { - return; - } - const activeRoute = encodeURIComponent(Navigation.getActiveRouteWithoutParams()); - Navigation.navigate(ROUTES.MONEY_REQUEST_HOLD_REASON.getRoute(policy.type, iouTransactionID, report?.reportID, activeRoute)); + Navigation.navigate(ROUTES.MONEY_REQUEST_HOLD_REASON.getRoute(policy?.type ?? CONST.POLICY.TYPE.PERSONAL, iouTransactionID, report?.reportID, activeRoute)); } }; diff --git a/src/components/MultipleAvatars.tsx b/src/components/MultipleAvatars.tsx index 31d3d35af58d..dedaba500a9c 100644 --- a/src/components/MultipleAvatars.tsx +++ b/src/components/MultipleAvatars.tsx @@ -158,7 +158,6 @@ function MultipleAvatars({ name={icons[0].name} type={icons[0].type} fallbackIcon={icons[0].fallbackIcon} - accountID={icons[0].id} /> @@ -208,7 +207,6 @@ function MultipleAvatars({ name={icon.name} type={icon.type} fallbackIcon={icon.fallbackIcon} - accountID={icon.id} /> diff --git a/src/components/PDFView/pdfViewPropTypes.js b/src/components/PDFView/pdfViewPropTypes.js deleted file mode 100644 index 546f9b1a8933..000000000000 --- a/src/components/PDFView/pdfViewPropTypes.js +++ /dev/null @@ -1,51 +0,0 @@ -import PropTypes from 'prop-types'; -import {withThemeStylesPropTypes} from '@components/withThemeStyles'; -import {windowDimensionsPropTypes} from '@components/withWindowDimensions'; -import stylePropTypes from '@styles/stylePropTypes'; - -const propTypes = { - /** URL to full-sized image */ - sourceURL: PropTypes.string, - - /** PDF file name */ - fileName: PropTypes.string, - - /** Additional style props */ - style: stylePropTypes, - - /** Notify parent that the keyboard has opened or closed */ - onToggleKeyboard: PropTypes.func, - - /** Handles press events like toggling attachment arrows natively */ - onPress: PropTypes.func, - - /** Handles scale changed event in PDF component */ - onScaleChanged: PropTypes.func, - - /** Handles load complete event in PDF component */ - onLoadComplete: PropTypes.func, - - /** Should focus to the password input */ - isFocused: PropTypes.bool, - - /** Styles for the error label */ - errorLabelStyles: stylePropTypes, - - ...windowDimensionsPropTypes, - - ...withThemeStylesPropTypes, -}; - -const defaultProps = { - sourceURL: '', - fileName: '', - style: {}, - onPress: undefined, - onToggleKeyboard: () => {}, - onScaleChanged: () => {}, - onLoadComplete: () => {}, - isFocused: false, - errorLabelStyles: [], -}; - -export {propTypes, defaultProps}; diff --git a/src/components/Reactions/EmojiReactionsPropTypes.js b/src/components/Reactions/EmojiReactionsPropTypes.js deleted file mode 100644 index ace88abefcd9..000000000000 --- a/src/components/Reactions/EmojiReactionsPropTypes.js +++ /dev/null @@ -1,31 +0,0 @@ -import PropTypes from 'prop-types'; - -/** All the emoji reactions for the report action. An object that looks like this: - "emojiReactions": { - "+1": { // The emoji added to the action - "createdAt": "2021-01-01 00:00:00", - "users": { - 2352342: { // The accountID of the user who added this emoji - "skinTones": { - "1": "2021-01-01 00:00:00", - "2": "2021-01-01 00:00:00", - }, - }, - }, - }, - }, -*/ -export default PropTypes.objectOf( - PropTypes.shape({ - /** The time the emoji was added */ - createdAt: PropTypes.string, - - /** All the users who have added this emoji */ - users: PropTypes.objectOf( - PropTypes.shape({ - /** The skin tone which was used and also the timestamp of when it was added */ - skinTones: PropTypes.objectOf(PropTypes.string), - }), - ), - }), -); diff --git a/src/components/ReportActionItem/TaskView.tsx b/src/components/ReportActionItem/TaskView.tsx index e3e07ab0d7ad..9711e126907f 100644 --- a/src/components/ReportActionItem/TaskView.tsx +++ b/src/components/ReportActionItem/TaskView.tsx @@ -156,7 +156,7 @@ function TaskView({report, shouldShowHorizontalRule, ...props}: TaskViewProps) { 1; const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForAccountIDs(participantAccountIDs, personalDetails), isMultipleParticipant); @@ -58,6 +59,10 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP }; const welcomeHeroText = useMemo(() => { + if (isInvoiceRoom) { + return translate('reportActionsView.sayHello'); + } + if (isChatRoom) { return translate('reportActionsView.welcomeToRoom', {roomName: reportName}); } @@ -67,7 +72,7 @@ function ReportWelcomeText({report, policy, personalDetails}: ReportWelcomeTextP } return translate('reportActionsView.sayHello'); - }, [isChatRoom, isSelfDM, translate, reportName]); + }, [isChatRoom, isInvoiceRoom, isSelfDM, translate, reportName]); return ( <> diff --git a/src/components/Search.tsx b/src/components/Search.tsx index 38135fd2631e..0fb0db1924a2 100644 --- a/src/components/Search.tsx +++ b/src/components/Search.tsx @@ -1,68 +1,47 @@ -import React from 'react'; -import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native'; -import {View} from 'react-native'; -import useLocalize from '@hooks/useLocalize'; -import useTheme from '@hooks/useTheme'; -import useThemeStyles from '@hooks/useThemeStyles'; -import variables from '@styles/variables'; -import CONST from '@src/CONST'; -import Icon from './Icon'; -import * as Expensicons from './Icon/Expensicons'; -import {PressableWithFeedback} from './Pressable'; -import Text from './Text'; -import Tooltip from './Tooltip'; +import React, {useEffect} from 'react'; +import {useOnyx} from 'react-native-onyx'; +import useNetwork from '@hooks/useNetwork'; +import * as SearchActions from '@libs/actions/Search'; +import * as SearchUtils from '@libs/SearchUtils'; +import EmptySearchView from '@pages/Search/EmptySearchView'; +import ONYXKEYS from '@src/ONYXKEYS'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; +import TableListItemSkeleton from './Skeletons/TableListItemSkeleton'; type SearchProps = { - // Callback fired when component is pressed - onPress: (event?: GestureResponderEvent | KeyboardEvent) => void; + query: string; +}; - // Text explaining what the user can search for - placeholder?: string; +function Search({query}: SearchProps) { + const {isOffline} = useNetwork(); + const hash = SearchUtils.getQueryHash(query); + const [searchResults, searchResultsMeta] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${hash}`); - // Text showing up in a tooltip when component is hovered - tooltip?: string; + useEffect(() => { + SearchActions.search(query); + }, [query]); - // Styles to apply on the outer element - style?: StyleProp; + const isLoading = !isOffline && isLoadingOnyxValue(searchResultsMeta); + const shouldShowEmptyState = isEmptyObject(searchResults); - /** Styles to apply to the outermost element */ - containerStyle?: StyleProp; -}; + if (isLoading) { + return ; + } + + if (shouldShowEmptyState) { + return ; + } -function Search({onPress, placeholder, tooltip, style, containerStyle}: SearchProps) { - const styles = useThemeStyles(); - const theme = useTheme(); - const {translate} = useLocalize(); + const ListItem = SearchUtils.getListItem(); - return ( - - - - {({hovered}) => ( - - - - {placeholder ?? translate('common.searchWithThreeDots')} - - - )} - - - - ); + // This will be updated with the proper List component in another PR + return SearchUtils.getSections(searchResults.data).map((item) => ( + + )); } Search.displayName = 'Search'; diff --git a/src/components/SelectionList/TemporaryTransactionListItem.tsx b/src/components/SelectionList/TemporaryTransactionListItem.tsx new file mode 100644 index 000000000000..49544c4f5557 --- /dev/null +++ b/src/components/SelectionList/TemporaryTransactionListItem.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import {View} from 'react-native'; +import Text from '@components/Text'; +import useThemeStyles from '@hooks/useThemeStyles'; +import type {SearchTransaction} from '@src/types/onyx/SearchResults'; + +// NOTE: This is a completely temporary mock item so that something can be displayed in SearchWidget +// This should be removed and implement properly in: https://github.com/Expensify/App/issues/39877 +function TransactionListItem({item}: {item: SearchTransaction}) { + const styles = useThemeStyles(); + return ( + + Item: {item.transactionID} + + ); +} + +export default TransactionListItem; diff --git a/src/components/TabSelector/TabSelector.tsx b/src/components/TabSelector/TabSelector.tsx index fc19e6a8062e..9fe1665f6b19 100644 --- a/src/components/TabSelector/TabSelector.tsx +++ b/src/components/TabSelector/TabSelector.tsx @@ -26,7 +26,7 @@ function getIconAndTitle(route: string, translate: LocaleContextProps['translate case CONST.TAB_REQUEST.MANUAL: return {icon: Expensicons.Pencil, title: translate('tabSelector.manual')}; case CONST.TAB_REQUEST.SCAN: - return {icon: Expensicons.Receipt, title: translate('tabSelector.scan')}; + return {icon: Expensicons.ReceiptScan, title: translate('tabSelector.scan')}; case CONST.TAB.NEW_CHAT: return {icon: Expensicons.User, title: translate('tabSelector.chat')}; case CONST.TAB.NEW_ROOM: diff --git a/src/components/TaskHeaderActionButton.tsx b/src/components/TaskHeaderActionButton.tsx index 2d964f58c253..788734242f7b 100644 --- a/src/components/TaskHeaderActionButton.tsx +++ b/src/components/TaskHeaderActionButton.tsx @@ -25,6 +25,10 @@ function TaskHeaderActionButton({report, session}: TaskHeaderActionButtonProps) const {translate} = useLocalize(); const styles = useThemeStyles(); + if (!ReportUtils.canWriteInReport(report)) { + return null; + } + return (