From 8c5199b253f80ff84adbc2fd61e533d86af94ffb Mon Sep 17 00:00:00 2001 From: Peter Velkov Date: Thu, 23 Nov 2023 19:51:58 +0200 Subject: [PATCH 01/18] Make file.name required in attachment prop types Some bugs can be caught earlier if we're warned when `file` or `file.name` is missing --- src/components/Attachments/AttachmentCarousel/CarouselItem.js | 4 ++-- src/components/Attachments/propTypes.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Attachments/AttachmentCarousel/CarouselItem.js b/src/components/Attachments/AttachmentCarousel/CarouselItem.js index b6cc0cbf21a4..fbc49590d5ae 100644 --- a/src/components/Attachments/AttachmentCarousel/CarouselItem.js +++ b/src/components/Attachments/AttachmentCarousel/CarouselItem.js @@ -27,8 +27,8 @@ const propTypes = { /** Additional information about the attachment file */ file: PropTypes.shape({ /** File name of the attachment */ - name: PropTypes.string, - }), + name: PropTypes.string.isRequired, + }).isRequired, /** Whether the attachment has been flagged */ hasBeenFlagged: PropTypes.bool, diff --git a/src/components/Attachments/propTypes.js b/src/components/Attachments/propTypes.js index 698a41de9648..13adc468ce64 100644 --- a/src/components/Attachments/propTypes.js +++ b/src/components/Attachments/propTypes.js @@ -2,7 +2,7 @@ import PropTypes from 'prop-types'; const attachmentSourcePropType = PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.number]); const attachmentFilePropType = PropTypes.shape({ - name: PropTypes.string, + name: PropTypes.string.isRequired, }); const attachmentPropType = PropTypes.shape({ @@ -13,7 +13,7 @@ const attachmentPropType = PropTypes.shape({ source: attachmentSourcePropType.isRequired, /** File object can be an instance of File or Object */ - file: attachmentFilePropType, + file: attachmentFilePropType.isRequired, }); const attachmentsPropType = PropTypes.arrayOf(attachmentPropType); From 4823b7ec72591894c16f9c573633222237385c35 Mon Sep 17 00:00:00 2001 From: Peter Velkov Date: Thu, 23 Nov 2023 20:50:07 +0200 Subject: [PATCH 02/18] fix(AttachmentCarousel): Use source URL for fallback file names Introduce getFileName in FileUtils to generate fallback names for attachments lacking original file names. This function extracts and sanitizes filenames from URLs, ensuring attachments in AttachmentCarousel have meaningful names even when original names are missing. Updated AttachmentCarousel to utilize this new utility function. At this time, the only know case is embedded attachments shared by the Concierge account via drag and drop --- .../extractAttachmentsFromReport.js | 7 +++++-- src/libs/fileDownload/FileUtils.ts | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js b/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js index 0f1fa15c99ca..6cd85e4243b2 100644 --- a/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js +++ b/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js @@ -1,6 +1,7 @@ import {Parser as HtmlParser} from 'htmlparser2'; import lodashGet from 'lodash/get'; import _ from 'underscore'; +import * as FileUtils from '@libs/fileDownload/FileUtils'; import * as ReceiptUtils from '@libs/ReceiptUtils'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; @@ -25,14 +26,16 @@ function extractAttachmentsFromReport(parentReportAction, reportActions, transac } const expensifySource = attribs[CONST.ATTACHMENT_SOURCE_ATTRIBUTE]; + const source = tryResolveUrlFromApiRoot(expensifySource || attribs.src); + const fileName = attribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE] || FileUtils.getFileName(`${source}`); // By iterating actions in chronological order and prepending each attachment // we ensure correct order of attachments even across actions with multiple attachments. attachments.unshift({ + source, reportActionID: attribs['data-id'], - source: tryResolveUrlFromApiRoot(expensifySource || attribs.src), isAuthTokenRequired: Boolean(expensifySource), - file: {name: attribs[CONST.ATTACHMENT_ORIGINAL_FILENAME_ATTRIBUTE]}, + file: {name: fileName}, isReceipt: false, hasBeenFlagged: attribs['data-flagged'] === 'true', }); diff --git a/src/libs/fileDownload/FileUtils.ts b/src/libs/fileDownload/FileUtils.ts index 618571ddf400..253e0ff13426 100644 --- a/src/libs/fileDownload/FileUtils.ts +++ b/src/libs/fileDownload/FileUtils.ts @@ -1,6 +1,7 @@ import {Alert, Linking, Platform} from 'react-native'; import DateUtils from '@libs/DateUtils'; import * as Localize from '@libs/Localize'; +import Log from '@libs/Log'; import CONST from '@src/CONST'; import type {ReadFileAsync, SplitExtensionFromFileName} from './types'; @@ -74,6 +75,25 @@ function showCameraPermissionsAlert() { ); } +/** + * Extracts a filename from a given URL and sanitizes it for file system usage. + * + * This function takes a URL as input and performs the following operations: + * 1. Extracts the last segment of the URL, which could be a file name, a path segment, + * or a query string parameter. + * 2. Decodes the extracted segment from URL encoding to a plain string for better readability. + * 3. Replaces any characters in the decoded string that are illegal in file names + * with underscores. + */ +function getFileName(url: string): string { + const fileName = url.split(/[#?/]/).pop() ?? ''; + if (!fileName) { + Log.warn('[FileUtils] Could not get attachment name', {url}); + } + + return decodeURIComponent(fileName).replace(CONST.REGEX.ILLEGAL_FILENAME_CHARACTERS, '_'); +} + /** * Generate a random file name with timestamp and file extension */ @@ -232,6 +252,7 @@ export { showCameraPermissionsAlert, splitExtensionFromFileName, getAttachmentName, + getFileName, getFileType, cleanFileName, appendTimeToFileName, From 999155008f3deec85a328d9c7906e45cb2340136 Mon Sep 17 00:00:00 2001 From: Peter Velkov Date: Thu, 23 Nov 2023 21:04:38 +0200 Subject: [PATCH 03/18] fix(libs/fileDownload): Ensure reachable fallback for filenames Addressed a bug in libs/fileDownload where the intended fallback for filenames was never reached due to `FileUtils.appendTimeToFileName` always providing a return value. This fix refines the filename determination logic, ensuring effective use of fallback mechanisms across various components including AttachmentCarousel, particularly for cases like attachments shared by the Concierge account. --- src/libs/fileDownload/index.android.ts | 3 ++- src/libs/fileDownload/index.ios.ts | 3 ++- src/libs/fileDownload/index.ts | 6 ++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libs/fileDownload/index.android.ts b/src/libs/fileDownload/index.android.ts index 41c7cb29550a..3bb91e538b00 100644 --- a/src/libs/fileDownload/index.android.ts +++ b/src/libs/fileDownload/index.android.ts @@ -38,7 +38,8 @@ function handleDownload(url: string, fileName: string): Promise { // Android files will download to Download directory const path = dirs.DownloadDir; - const attachmentName = FileUtils.appendTimeToFileName(fileName) || FileUtils.getAttachmentName(url); + const name = fileName.length > 0 ? fileName : FileUtils.getFileName(url); + const attachmentName = FileUtils.appendTimeToFileName(name); const isLocalFile = url.startsWith('file://'); diff --git a/src/libs/fileDownload/index.ios.ts b/src/libs/fileDownload/index.ios.ts index fdc4a78e0b9b..11a74c43f15a 100644 --- a/src/libs/fileDownload/index.ios.ts +++ b/src/libs/fileDownload/index.ios.ts @@ -73,7 +73,8 @@ const fileDownload: FileDownload = (fileUrl, fileName) => new Promise((resolve) => { let fileDownloadPromise; const fileType = FileUtils.getFileType(fileUrl); - const attachmentName = FileUtils.appendTimeToFileName(fileName) || FileUtils.getAttachmentName(fileUrl); + const name = fileName.length > 0 ? fileName : FileUtils.getFileName(fileUrl); + const attachmentName = FileUtils.appendTimeToFileName(name); switch (fileType) { case CONST.ATTACHMENT_FILE_TYPE.IMAGE: diff --git a/src/libs/fileDownload/index.ts b/src/libs/fileDownload/index.ts index ef36647e549d..91ec7d5058a2 100644 --- a/src/libs/fileDownload/index.ts +++ b/src/libs/fileDownload/index.ts @@ -25,14 +25,12 @@ const fileDownload: FileDownload = (url, fileName) => { // creating anchor tag to initiate download const link = document.createElement('a'); + const name = fileName.length > 0 ? fileName : FileUtils.getFileName(url); // adding href to anchor link.href = href; link.style.display = 'none'; - link.setAttribute( - 'download', - FileUtils.appendTimeToFileName(fileName) || FileUtils.getAttachmentName(url), // generating the file name - ); + link.setAttribute('download', FileUtils.appendTimeToFileName(name)); // Append to html link element page document.body.appendChild(link); From 1b58d05718ba57d20696f5d1f9fb404caeecf15d Mon Sep 17 00:00:00 2001 From: Peter Velkov Date: Thu, 23 Nov 2023 21:05:32 +0200 Subject: [PATCH 04/18] refactor(libs/FileUtils): remove `getAttachmentName` - unused --- src/libs/fileDownload/FileUtils.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/libs/fileDownload/FileUtils.ts b/src/libs/fileDownload/FileUtils.ts index 253e0ff13426..09cc1222310f 100644 --- a/src/libs/fileDownload/FileUtils.ts +++ b/src/libs/fileDownload/FileUtils.ts @@ -94,16 +94,6 @@ function getFileName(url: string): string { return decodeURIComponent(fileName).replace(CONST.REGEX.ILLEGAL_FILENAME_CHARACTERS, '_'); } -/** - * Generate a random file name with timestamp and file extension - */ -function getAttachmentName(url: string): string { - if (!url) { - return ''; - } - return `${DateUtils.getDBTime()}.${url.split(/[#?]/)[0].split('.').pop()?.trim()}`; -} - function isImage(fileName: string): boolean { return CONST.FILE_TYPE_REGEX.IMAGE.test(fileName); } @@ -251,7 +241,6 @@ export { showPermissionErrorAlert, showCameraPermissionsAlert, splitExtensionFromFileName, - getAttachmentName, getFileName, getFileType, cleanFileName, From 5e6d28388a73a49e3ae6901c4b6d78af4b8bfb58 Mon Sep 17 00:00:00 2001 From: maddylewis <38016013+maddylewis@users.noreply.github.com> Date: Sun, 26 Nov 2023 10:55:29 -0500 Subject: [PATCH 05/18] Rename Trip-Actions.md to Navan.md updating title to reflect integration name --- .../travel-integrations/{Trip-Actions.md => Navan.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/articles/expensify-classic/integrations/travel-integrations/{Trip-Actions.md => Navan.md} (100%) diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Trip-Actions.md b/docs/articles/expensify-classic/integrations/travel-integrations/Navan.md similarity index 100% rename from docs/articles/expensify-classic/integrations/travel-integrations/Trip-Actions.md rename to docs/articles/expensify-classic/integrations/travel-integrations/Navan.md From c4c13aaa0bca461bcabcc524dc68eae71c32d70e Mon Sep 17 00:00:00 2001 From: David Cardoza Date: Tue, 28 Nov 2023 00:57:30 +0800 Subject: [PATCH 06/18] Update Your-Expensify-Partner-Manager.md Making adjustments per https://expensify.slack.com/archives/C02QSAC6BJ8/p1701022712329789 --- .../Your-Expensify-Partner-Manager.md | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md b/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md index 2db69d0a8791..8243833dcc23 100644 --- a/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md +++ b/docs/articles/expensify-classic/expensify-partner-program/Your-Expensify-Partner-Manager.md @@ -1,5 +1,5 @@ --- -title: Your Expensify Partner Manager +title: Expensify Partner Support description: Understanding support for our partners --- @@ -10,6 +10,7 @@ Our well-rounded support methodology is designed to provide comprehensive assist ## 1. ExpensifyApproved! University **Purpose:** Equip your team with a comprehensive understanding of Expensify. + **Benefits:** - Foundation-level knowledge about the platform. - 3 CPE credits upon successful completion (US-only). @@ -17,16 +18,39 @@ Our well-rounded support methodology is designed to provide comprehensive assist - Visit university.Expensify.com to access our comprehensive training program. ## 2. Partner Manager -**Role:** A designated liaison for your firm. +**Role:** +A Partner Manager is a dedicated point of contact for your firm Partner Managers support our accounting partners by providing recommendations for client’s accounts, assisting with firm-wide training, and ensuring partners receive the full benefits of our partnership program. They will actively monitor open technical issues and be proactive with recommendations to increase efficiency. + + **Key Responsibilities:** - Handle any escalations promptly. - Organize firm-wide training sessions. - Assist with strategic planning and the introduction of new features. - Once you've completed the ExpensifyApproved! University, log in to your Expensify account. Click on the "Support" option to connect with your dedicated Partner Manager. +**How do I know if I have a Partner Manager?** + +For your firm to be assigned a Partner Manager, you must complete the ExpensifyApproved! University training course. Every external accountant or bookkeeper who completes the training is automatically enrolled in our program and receives all the benefits, including access to the Partner Manager. So everyone at your firm must complete the training to receive the maximum benefit. + +You can check to see if you’ve completed the course and enrolled in the ExpensifyApproved! Accountants program simply by logging into your Expensify account. In the bottom left-hand corner of the website, you will see the ExpensifyApproved! logo. + +**How do I contact my Partner Manager?** +1. Signing in to new.expensify.com and searching for your Partner Manager +2. Replying to or clicking the chat link on any email you get from your Partner Manager + +**How do I know if my Partner Manager is online?** + +You will be able to see if they are online via their status in new.expensify.com, which will either say “online” or have their working hours. + +**Can I get on a call with my Partner Manager?** + +Of course! You can ask your Partner Manager to schedule a call whenever you think one might be helpful. Partner Managers can discuss client onboarding strategies, firm-wide training, and client setups. + +We recommend continuing to work with Concierge for general support questions, as this team is always online and available to help immediately. ## 3. Client Setup Specialist **Purpose:** Ensure smooth onboarding for every client you refer. + **Duties:** - Comprehensive assistance with setting up Expensify. - Help with configuring accounting integrations. @@ -35,6 +59,7 @@ Our well-rounded support methodology is designed to provide comprehensive assist ## 4. Client Account Manager **Role:** Dedicated support for ongoing client needs. + **Responsibilities:** - Address day-to-day product inquiries. - Assist clients in navigating and optimizing their use of Expensify. @@ -42,6 +67,7 @@ Our well-rounded support methodology is designed to provide comprehensive assist ## 5. Concierge chat support **Availability:** Real-time support for any urgent inquiries. + **Features:** - Immediate assistance with an average response time of under two minutes. - Available to both accountants and clients for all product-related questions. From f5ebc0b8597008a2470149a6e0f54a201a5c7c2f Mon Sep 17 00:00:00 2001 From: Cheryl W <58196921+CherylWalsh@users.noreply.github.com> Date: Tue, 28 Nov 2023 19:12:48 +0000 Subject: [PATCH 07/18] Delete docs/articles/expensify-classic/workspace-and-domain-settings/Creating-Per-Diem-Expenses.md Deleting article --- .../Creating-Per-Diem-Expenses.md | 45 ------------------- 1 file changed, 45 deletions(-) delete mode 100644 docs/articles/expensify-classic/workspace-and-domain-settings/Creating-Per-Diem-Expenses.md diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/Creating-Per-Diem-Expenses.md b/docs/articles/expensify-classic/workspace-and-domain-settings/Creating-Per-Diem-Expenses.md deleted file mode 100644 index 214188e35137..000000000000 --- a/docs/articles/expensify-classic/workspace-and-domain-settings/Creating-Per-Diem-Expenses.md +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Creating Per Diem Expenses -description: How to create Per Diem expenses on mobile and web. ---- -# Overview - -What are Per Diems? Per diems, short for "per diem allowance" or "daily allowance," are fixed daily payments provided by your employer to cover expenses incurred during business or work-related travel. These allowances simplify expense tracking and reimbursement for meals, lodging, and incidental expenses during a trip. Per Diems can be masterfully tracked in Expensify! - -## How To create per diem expenses - -To add per diem expenses, you need three pieces of information: -1. Where did you go? - Specify your travel destination. -2. How long were you away? - Define the period you're claiming for. -3. Which rate did you use? - Select the appropriate per diem rate. - -### Step 1: On either the web or mobile app, click New Expense and choose Per Diem - -### Step 2: Select your travel destination from the Destination dropdown -If your trip involves multiple stops, create a separate Per Diem expense for each destination. Remember, the times are relative to your home city. - -### Step 3: Select your Start date, End date, Start time, and End time -Expensify will automatically calculate the duration of your trip. We'll show you a breakdown of your days: the time between departure and midnight on the first day, the total days in between, and the time between midnight and your return time on the last day. - -### Step 4: Select a Subrate based on the trip duration from the dropdown list -You can include meal deductions or overnight lodging costs if your jurisdiction permits. - -### Step 5: Enter any other required coding and click “Save” - -### Step 6: Submit for Approval -Finally, submit your Per Diem expense for approval, and you'll be on your way to getting reimbursed! - -# FAQ - -## Can I Edit My Per Diems? -Per Diems cannot be amended. To make changes, delete the expense and recreate it as needed. - -## What If My Admin Requires Daily Per Diems? -No problem! Create a separate Per Diem expense for each day of your trip. - -## I Have Questions About the Amount I'm Due -Reach out to your internal Admin team, as they've configured the rates in your policy to meet specific requirements. - -## Can I Add Start and End Times to a Per Diem? -Unfortunately, you cannot add start and end times to Per Diems in Expensify. -By following these steps, you can efficiently create and manage your Per Diem expenses in Expensify, making the process of tracking and getting reimbursed hassle-free. From 931b7857e7f5b8faff9481f0a7b05aa0cac061f7 Mon Sep 17 00:00:00 2001 From: Peter Velkov Date: Wed, 29 Nov 2023 20:18:12 +0200 Subject: [PATCH 08/18] `fileDownload`: Apply PR suggestions https://github.com/Expensify/App/pull/31791#discussion_r1405428758 --- src/libs/fileDownload/index.android.ts | 3 +-- src/libs/fileDownload/index.ios.ts | 3 +-- src/libs/fileDownload/index.ts | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/libs/fileDownload/index.android.ts b/src/libs/fileDownload/index.android.ts index 3bb91e538b00..8496c1cb6cf5 100644 --- a/src/libs/fileDownload/index.android.ts +++ b/src/libs/fileDownload/index.android.ts @@ -38,8 +38,7 @@ function handleDownload(url: string, fileName: string): Promise { // Android files will download to Download directory const path = dirs.DownloadDir; - const name = fileName.length > 0 ? fileName : FileUtils.getFileName(url); - const attachmentName = FileUtils.appendTimeToFileName(name); + const attachmentName = FileUtils.appendTimeToFileName(fileName || FileUtils.getFileName(url)); const isLocalFile = url.startsWith('file://'); diff --git a/src/libs/fileDownload/index.ios.ts b/src/libs/fileDownload/index.ios.ts index 11a74c43f15a..7672b4b14926 100644 --- a/src/libs/fileDownload/index.ios.ts +++ b/src/libs/fileDownload/index.ios.ts @@ -73,8 +73,7 @@ const fileDownload: FileDownload = (fileUrl, fileName) => new Promise((resolve) => { let fileDownloadPromise; const fileType = FileUtils.getFileType(fileUrl); - const name = fileName.length > 0 ? fileName : FileUtils.getFileName(fileUrl); - const attachmentName = FileUtils.appendTimeToFileName(name); + const attachmentName = FileUtils.appendTimeToFileName(fileName || FileUtils.getFileName(fileUrl)); switch (fileType) { case CONST.ATTACHMENT_FILE_TYPE.IMAGE: diff --git a/src/libs/fileDownload/index.ts b/src/libs/fileDownload/index.ts index 91ec7d5058a2..4f43b215925f 100644 --- a/src/libs/fileDownload/index.ts +++ b/src/libs/fileDownload/index.ts @@ -25,12 +25,11 @@ const fileDownload: FileDownload = (url, fileName) => { // creating anchor tag to initiate download const link = document.createElement('a'); - const name = fileName.length > 0 ? fileName : FileUtils.getFileName(url); // adding href to anchor link.href = href; link.style.display = 'none'; - link.setAttribute('download', FileUtils.appendTimeToFileName(name)); + link.download = FileUtils.appendTimeToFileName(fileName || FileUtils.getFileName(url)); // Append to html link element page document.body.appendChild(link); From c2758b10f2e15b020d3b95a172781105b4fadd39 Mon Sep 17 00:00:00 2001 From: Julian Kobrynski Date: Thu, 30 Nov 2023 15:59:19 +0100 Subject: [PATCH 09/18] migrate AvatarSkeleton.tsx to TypeScript --- src/components/{AvatarSkeleton.js => AvatarSkeleton.tsx} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/components/{AvatarSkeleton.js => AvatarSkeleton.tsx} (100%) diff --git a/src/components/AvatarSkeleton.js b/src/components/AvatarSkeleton.tsx similarity index 100% rename from src/components/AvatarSkeleton.js rename to src/components/AvatarSkeleton.tsx From 6e3438d9fe4d316a9b9f4eef2f587574b2f830a3 Mon Sep 17 00:00:00 2001 From: tienifr Date: Fri, 1 Dec 2023 14:11:21 +0700 Subject: [PATCH 10/18] fix: 31415 Input field on Login page gets white background after using auto-fill --- web/index.html | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/web/index.html b/web/index.html index a7630b1a2cdc..d4555b45cd32 100644 --- a/web/index.html +++ b/web/index.html @@ -74,6 +74,15 @@ } /* Customizes the background and text colors for autofill inputs in Chrome */ + input[chrome-autofilled], + input[chrome-autofilled]:hover, + input[chrome-autofilled]:focus, + textarea[chrome-autofilled], + textarea[chrome-autofilled]:hover, + textarea[chrome-autofilled]:focus, + select[chrome-autofilled], + select[chrome-autofilled]:hover, + select[chrome-autofilled]:focus, input:-webkit-autofill, input:-webkit-autofill:hover, input:-webkit-autofill:focus, @@ -89,7 +98,7 @@ } /* Prevent autofill from overlapping with the input label in Chrome */ - div:has(input:-webkit-autofill) > label { + div:has(input:-webkit-autofill, input[chrome-autofilled]) > label { transform: translateY(var(--active-label-translate-y)) scale(var(--active-label-scale)) !important; transition: transform var(--label-transition-duration); } From e42ba1ed55b954100388b55dffcf3e92657e74c8 Mon Sep 17 00:00:00 2001 From: tienifr Date: Mon, 4 Dec 2023 10:32:06 +0700 Subject: [PATCH 11/18] add comment --- web/index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/index.html b/web/index.html index d4555b45cd32..d19eac29c5da 100644 --- a/web/index.html +++ b/web/index.html @@ -74,6 +74,8 @@ } /* Customizes the background and text colors for autofill inputs in Chrome */ + /* Chrome on iOS does not support the autofill pseudo class because it is a non-standard webkit feature. + We should rely on the chrome-autofilled property that being added to the input when users use auto-fill function */ input[chrome-autofilled], input[chrome-autofilled]:hover, input[chrome-autofilled]:focus, From 76abee21baee946efd9bd966827cbc6f19e49a7f Mon Sep 17 00:00:00 2001 From: Al Garces Date: Mon, 4 Dec 2023 09:22:07 -0800 Subject: [PATCH 12/18] Rename Notification-Troubbleshooting.md to Notification-Troubleshooting.md There should only be one B in troubleshooting --- ...cation-Troubbleshooting.md => Notification-Troubleshooting.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/articles/expensify-classic/account-settings/{Notification-Troubbleshooting.md => Notification-Troubleshooting.md} (100%) diff --git a/docs/articles/expensify-classic/account-settings/Notification-Troubbleshooting.md b/docs/articles/expensify-classic/account-settings/Notification-Troubleshooting.md similarity index 100% rename from docs/articles/expensify-classic/account-settings/Notification-Troubbleshooting.md rename to docs/articles/expensify-classic/account-settings/Notification-Troubleshooting.md From 4f7dfa29e530c823e777cc55ee56881e228eb2e9 Mon Sep 17 00:00:00 2001 From: Fedi Rajhi Date: Tue, 5 Dec 2023 00:34:33 +0100 Subject: [PATCH 13/18] [Fix] - Disable minHeight for safari browser --- src/components/ScreenWrapper/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ScreenWrapper/index.js b/src/components/ScreenWrapper/index.js index 16bf9ba0761c..6af67c51ffaf 100644 --- a/src/components/ScreenWrapper/index.js +++ b/src/components/ScreenWrapper/index.js @@ -51,7 +51,7 @@ const ScreenWrapper = React.forwardRef( const navigation = useNavigation(); const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); const maxHeight = shouldEnableMaxHeight ? windowHeight : undefined; - const minHeight = shouldEnableMinHeight ? initialHeight : undefined; + const minHeight = shouldEnableMinHeight && !Browser.isSafari() ? initialHeight : undefined; const isKeyboardShown = lodashGet(keyboardState, 'isKeyboardShown', false); const isKeyboardShownRef = useRef(); From 700cded6e5d2ee28ed52c2b6d96d06537d29b87f Mon Sep 17 00:00:00 2001 From: tienifr Date: Tue, 5 Dec 2023 15:06:53 +0700 Subject: [PATCH 14/18] fix: comment --- web/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/index.html b/web/index.html index d19eac29c5da..1c0425bf38da 100644 --- a/web/index.html +++ b/web/index.html @@ -75,7 +75,7 @@ /* Customizes the background and text colors for autofill inputs in Chrome */ /* Chrome on iOS does not support the autofill pseudo class because it is a non-standard webkit feature. - We should rely on the chrome-autofilled property that being added to the input when users use auto-fill function */ + We should rely on the chrome-autofilled property being added to the input when users use auto-fill */ input[chrome-autofilled], input[chrome-autofilled]:hover, input[chrome-autofilled]:focus, From 7c151c7cf6a66865aa470343809899b7dbe8c9d6 Mon Sep 17 00:00:00 2001 From: Yuwen Memon Date: Tue, 5 Dec 2023 10:26:30 -0800 Subject: [PATCH 15/18] Add c3024's device to AdHoc builds provisioning profile --- ios/expensify_chat_adhoc.mobileprovision.gpg | Bin 11244 -> 11262 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/ios/expensify_chat_adhoc.mobileprovision.gpg b/ios/expensify_chat_adhoc.mobileprovision.gpg index 1dae451f168cf63993fe6eee42965d5eff226d42..f4691df10d67d8234b7a54b75e74c34dae9be396 100644 GIT binary patch literal 11262 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 literal 11244 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 W0Q3B*O~gK&l=Xy*>BxoIfA0O6){A5S From 9845aec05a631edb92216ef728101cf1ebc9221b Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 5 Dec 2023 09:09:39 -1000 Subject: [PATCH 16/18] Tell TS this is a Route --- src/libs/actions/Link.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Link.ts b/src/libs/actions/Link.ts index 5ee15c1cd1d0..e6d33fec118d 100644 --- a/src/libs/actions/Link.ts +++ b/src/libs/actions/Link.ts @@ -7,7 +7,7 @@ import * as Url from '@libs/Url'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import ROUTES from '@src/ROUTES'; +import ROUTES, {Route} from '@src/ROUTES'; let isNetworkOffline = false; Onyx.connect({ @@ -100,7 +100,7 @@ function openLink(href: string, environmentURL: string, isAttachment = false) { // If we are handling a New Expensify link then we will assume this should be opened by the app internally. This ensures that the links are opened internally via react-navigation // instead of in a new tab or with a page refresh (which is the default behavior of an anchor tag) if (internalNewExpensifyPath && hasSameOrigin) { - Navigation.navigate(internalNewExpensifyPath); + Navigation.navigate(internalNewExpensifyPath as Route); return; } From 5b11d3a244b0bb0731f7ee55bddf47e89a8b9dae Mon Sep 17 00:00:00 2001 From: neil-marcellini Date: Tue, 5 Dec 2023 11:29:03 -0800 Subject: [PATCH 17/18] Revert "Merge pull request #31467 from dukenv0307/fix/31105" This reverts commit 90cda7cff1fe6fa2f28423a7716260121b03646c, reversing changes made to 0e3a0058a63fcc3de357c5484d979ea0056d1558. --- src/components/AttachmentModal.js | 26 +++++++-------- .../extractAttachmentsFromReport.js | 33 +++++++++++++++++-- .../Attachments/AttachmentCarousel/index.js | 27 +++++++++++++-- .../AttachmentCarousel/index.native.js | 27 +++++++++++++-- .../ReportActionItem/ReportActionItemImage.js | 33 ++++++++----------- 5 files changed, 103 insertions(+), 43 deletions(-) diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index fc0e2c1348d5..57b0c6466a7f 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -90,9 +90,6 @@ const propTypes = { /** Denotes whether it is a workspace avatar or not */ isWorkspaceAvatar: PropTypes.bool, - - /** Whether it is a receipt attachment or not */ - isReceiptAttachment: PropTypes.bool, }; const defaultProps = { @@ -110,7 +107,6 @@ const defaultProps = { onModalHide: () => {}, onCarouselAttachmentChange: () => {}, isWorkspaceAvatar: false, - isReceiptAttachment: false, }; function AttachmentModal(props) { @@ -122,6 +118,7 @@ function AttachmentModal(props) { const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false); const [isDeleteReceiptConfirmModalVisible, setIsDeleteReceiptConfirmModalVisible] = useState(false); const [isAuthTokenRequired, setIsAuthTokenRequired] = useState(props.isAuthTokenRequired); + const [isAttachmentReceipt, setIsAttachmentReceipt] = useState(null); const [attachmentInvalidReasonTitle, setAttachmentInvalidReasonTitle] = useState(''); const [attachmentInvalidReason, setAttachmentInvalidReason] = useState(null); const [source, setSource] = useState(props.source); @@ -157,6 +154,7 @@ function AttachmentModal(props) { (attachment) => { setSource(attachment.source); setFile(attachment.file); + setIsAttachmentReceipt(attachment.isReceipt); setIsAuthTokenRequired(attachment.isAuthTokenRequired); onCarouselAttachmentChange(attachment); }, @@ -359,7 +357,7 @@ function AttachmentModal(props) { const sourceForAttachmentView = props.source || source; const threeDotsMenuItems = useMemo(() => { - if (!props.isReceiptAttachment || !props.parentReport || !props.parentReportActions) { + if (!isAttachmentReceipt || !props.parentReport || !props.parentReportActions) { return []; } const menuItems = []; @@ -394,17 +392,17 @@ function AttachmentModal(props) { } return menuItems; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.isReceiptAttachment, props.parentReport, props.parentReportActions, props.policy, props.transaction, file]); + }, [isAttachmentReceipt, props.parentReport, props.parentReportActions, props.policy, props.transaction, file]); // There are a few things that shouldn't be set until we absolutely know if the file is a receipt or an attachment. - // props.isReceiptAttachment will be null until its certain what the file is, in which case it will then be true|false. + // isAttachmentReceipt will be null until its certain what the file is, in which case it will then be true|false. let headerTitle = props.headerTitle; let shouldShowDownloadButton = false; let shouldShowThreeDotsButton = false; - if (!_.isNull(props.isReceiptAttachment)) { - headerTitle = translate(props.isReceiptAttachment ? 'common.receipt' : 'common.attachment'); - shouldShowDownloadButton = props.allowDownload && isDownloadButtonReadyToBeShown && !props.isReceiptAttachment && !isOffline; - shouldShowThreeDotsButton = props.isReceiptAttachment && isModalOpen; + if (!_.isNull(isAttachmentReceipt)) { + headerTitle = translate(isAttachmentReceipt ? 'common.receipt' : 'common.attachment'); + shouldShowDownloadButton = props.allowDownload && isDownloadButtonReadyToBeShown && !isAttachmentReceipt && !isOffline; + shouldShowThreeDotsButton = isAttachmentReceipt && isModalOpen; } return ( @@ -445,7 +443,7 @@ function AttachmentModal(props) { shouldOverlay /> - {!_.isEmpty(props.report) && !props.isReceiptAttachment ? ( + {!_.isEmpty(props.report) ? ( )} - {props.isReceiptAttachment && ( + {isAttachmentReceipt && ( )} - {!props.isReceiptAttachment && ( + {!isAttachmentReceipt && ( { - if (!ReportActionsUtils.shouldReportActionBeVisible(action, key) || ReportActionsUtils.isMoneyRequestAction(action)) { + if (!ReportActionsUtils.shouldReportActionBeVisible(action, key)) { return; } + // We're handling receipts differently here because receipt images are not + // part of the report action message, the images are constructed client-side + if (ReportActionsUtils.isMoneyRequestAction(action)) { + const transactionID = lodashGet(action, ['originalMessage', 'IOUTransactionID']); + if (!transactionID) { + return; + } + + if (TransactionUtils.hasReceipt(transaction)) { + const {image} = ReceiptUtils.getThumbnailAndImageURIs(transaction); + const isLocalFile = typeof image === 'string' && _.some(CONST.ATTACHMENT_LOCAL_URL_PREFIX, (prefix) => image.startsWith(prefix)); + attachments.unshift({ + source: tryResolveUrlFromApiRoot(image), + isAuthTokenRequired: !isLocalFile, + file: {name: transaction.filename}, + isReceipt: true, + transactionID, + }); + return; + } + } + const decision = _.get(action, ['message', 0, 'moderationDecision', 'decision'], ''); const hasBeenFlagged = decision === CONST.MODERATION.MODERATOR_DECISION_PENDING_HIDE || decision === CONST.MODERATION.MODERATOR_DECISION_HIDDEN; const html = _.get(action, ['message', 0, 'html'], '').replace('/>', `data-flagged="${hasBeenFlagged}" data-id="${action.reportActionID}"/>`); diff --git a/src/components/Attachments/AttachmentCarousel/index.js b/src/components/Attachments/AttachmentCarousel/index.js index 1696f4adf0b4..141e619e489e 100644 --- a/src/components/Attachments/AttachmentCarousel/index.js +++ b/src/components/Attachments/AttachmentCarousel/index.js @@ -1,3 +1,4 @@ +import lodashGet from 'lodash/get'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {FlatList, Keyboard, PixelRatio, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; @@ -27,7 +28,7 @@ const viewabilityConfig = { itemVisiblePercentThreshold: 95, }; -function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate}) { +function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate, transaction}) { const styles = useThemeStyles(); const scrollRef = useRef(null); @@ -38,12 +39,21 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, const [attachments, setAttachments] = useState([]); const [activeSource, setActiveSource] = useState(source); const [shouldShowArrows, setShouldShowArrows, autoHideArrows, cancelAutoHideArrows] = useCarouselArrows(); + const [isReceipt, setIsReceipt] = useState(false); - const compareImage = useCallback((attachment) => attachment.source === source, [source]); + const compareImage = useCallback( + (attachment) => { + if (attachment.isReceipt && isReceipt) { + return attachment.transactionID === transaction.transactionID; + } + return attachment.source === source; + }, + [source, isReceipt, transaction], + ); useEffect(() => { const parentReportAction = parentReportActions[report.parentReportActionID]; - const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions); + const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions, transaction); const initialPage = _.findIndex(attachmentsFromReport, compareImage); @@ -78,10 +88,12 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, // to get the index of the current page const entry = _.first(viewableItems); if (!entry) { + setIsReceipt(false); setActiveSource(null); return; } + setIsReceipt(entry.item.isReceipt); setPage(entry.index); setActiveSource(entry.item.source); @@ -229,6 +241,15 @@ export default compose( canEvict: false, }, }), + // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file + withOnyx({ + transaction: { + key: ({report, parentReportActions}) => { + const parentReportAction = lodashGet(parentReportActions, [report.parentReportActionID]); + return `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(parentReportAction, 'originalMessage.IOUTransactionID', 0)}`; + }, + }, + }), withLocalize, withWindowDimensions, )(AttachmentCarousel); diff --git a/src/components/Attachments/AttachmentCarousel/index.native.js b/src/components/Attachments/AttachmentCarousel/index.native.js index 4a62335a492d..6bf4e63c01e7 100644 --- a/src/components/Attachments/AttachmentCarousel/index.native.js +++ b/src/components/Attachments/AttachmentCarousel/index.native.js @@ -1,3 +1,4 @@ +import lodashGet from 'lodash/get'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {Keyboard, PixelRatio, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; @@ -17,7 +18,7 @@ import extractAttachmentsFromReport from './extractAttachmentsFromReport'; import AttachmentCarouselPager from './Pager'; import useCarouselArrows from './useCarouselArrows'; -function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate, onClose}) { +function AttachmentCarousel({report, reportActions, parentReportActions, source, onNavigate, setDownloadButtonVisibility, translate, transaction, onClose}) { const styles = useThemeStyles(); const pagerRef = useRef(null); @@ -27,12 +28,21 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, const [activeSource, setActiveSource] = useState(source); const [isPinchGestureRunning, setIsPinchGestureRunning] = useState(true); const [shouldShowArrows, setShouldShowArrows, autoHideArrows, cancelAutoHideArrows] = useCarouselArrows(); + const [isReceipt, setIsReceipt] = useState(false); - const compareImage = useCallback((attachment) => attachment.source === source, [source]); + const compareImage = useCallback( + (attachment) => { + if (attachment.isReceipt && isReceipt) { + return attachment.transactionID === transaction.transactionID; + } + return attachment.source === source; + }, + [source, isReceipt, transaction], + ); useEffect(() => { const parentReportAction = parentReportActions[report.parentReportActionID]; - const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions); + const attachmentsFromReport = extractAttachmentsFromReport(parentReportAction, reportActions, transaction); const initialPage = _.findIndex(attachmentsFromReport, compareImage); @@ -67,7 +77,9 @@ function AttachmentCarousel({report, reportActions, parentReportActions, source, const item = attachments[newPageIndex]; setPage(newPageIndex); + setIsReceipt(item.isReceipt); setActiveSource(item.source); + onNavigate(item); }, [setShouldShowArrows, attachments, onNavigate], @@ -174,5 +186,14 @@ export default compose( canEvict: false, }, }), + // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file + withOnyx({ + transaction: { + key: ({report, parentReportActions}) => { + const parentReportAction = lodashGet(parentReportActions, [report.parentReportActionID]); + return `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(parentReportAction, 'originalMessage.IOUTransactionID', 0)}`; + }, + }, + }), withLocalize, )(AttachmentCarousel); diff --git a/src/components/ReportActionItem/ReportActionItemImage.js b/src/components/ReportActionItem/ReportActionItemImage.js index 6181e799ab2a..f0eed3ac2f02 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.js +++ b/src/components/ReportActionItem/ReportActionItemImage.js @@ -2,7 +2,6 @@ import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; import _ from 'underscore'; -import AttachmentModal from '@components/AttachmentModal'; import EReceiptThumbnail from '@components/EReceiptThumbnail'; import Image from '@components/Image'; import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus'; @@ -10,10 +9,12 @@ import {ShowContextMenuContext} from '@components/ShowContextMenuContext'; import ThumbnailImage from '@components/ThumbnailImage'; import transactionPropTypes from '@components/transactionPropTypes'; import useLocalize from '@hooks/useLocalize'; +import Navigation from '@libs/Navigation/Navigation'; import * as TransactionUtils from '@libs/TransactionUtils'; import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot'; import useThemeStyles from '@styles/useThemeStyles'; import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; const propTypes = { /** thumbnail URI for the image */ @@ -46,11 +47,11 @@ const defaultProps = { */ function ReportActionItemImage({thumbnail, image, enablePreviewModal, transaction, isLocalFile}) { + const styles = useThemeStyles(); const {translate} = useLocalize(); const imageSource = tryResolveUrlFromApiRoot(image || ''); const thumbnailSource = tryResolveUrlFromApiRoot(thumbnail || ''); const isEReceipt = !_.isEmpty(transaction) && TransactionUtils.hasEReceipt(transaction); - const styles = useThemeStyles(); let receiptImageComponent; @@ -82,25 +83,17 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal, transactio return ( {({report}) => ( - { + const route = ROUTES.REPORT_ATTACHMENTS.getRoute(report.reportID, imageSource); + Navigation.navigate(route); + }} + role={CONST.ACCESSIBILITY_ROLE.IMAGEBUTTON} + accessibilityLabel={translate('accessibilityHints.viewAttachment')} > - {({show}) => ( - - {receiptImageComponent} - - )} - + {receiptImageComponent} + )} ); From f893f06cdfda34873eb37e9da13c1257aaf29ff8 Mon Sep 17 00:00:00 2001 From: situchan Date: Wed, 6 Dec 2023 02:30:57 +0600 Subject: [PATCH 18/18] fix possible crash on app reload --- src/libs/Navigation/linkTo.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/linkTo.ts b/src/libs/Navigation/linkTo.ts index 1a4aa2d0cfb7..8be8dd1ecfae 100644 --- a/src/libs/Navigation/linkTo.ts +++ b/src/libs/Navigation/linkTo.ts @@ -89,7 +89,7 @@ export default function linkTo(navigation: NavigationContainerRef