From 2a4ba06b8f6fa967d40d0949b2a3cb29e92bad65 Mon Sep 17 00:00:00 2001 From: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> Date: Tue, 30 Apr 2024 18:52:13 +0100 Subject: [PATCH 01/22] copy changes from 41337 --- .../account-settings/Set-Notifications.md | 75 ----------------- src/ROUTES.ts | 4 + src/SCREENS.ts | 1 + src/languages/en.ts | 1 + src/languages/es.ts | 1 + .../ModalStackNavigators/index.tsx | 1 + .../FULL_SCREEN_TO_RHP_MAPPING.ts | 9 +- src/libs/Navigation/linkingConfig/config.ts | 6 ++ src/libs/Navigation/types.ts | 4 + .../qbo/import/QuickbooksImportPage.tsx | 2 +- .../workspace/tags/WorkspaceTagsPage.tsx | 83 +++++++++++-------- 11 files changed, 77 insertions(+), 110 deletions(-) delete mode 100644 docs/articles/expensify-classic/settings/account-settings/Set-Notifications.md diff --git a/docs/articles/expensify-classic/settings/account-settings/Set-Notifications.md b/docs/articles/expensify-classic/settings/account-settings/Set-Notifications.md deleted file mode 100644 index 0e18d6f22cf5..000000000000 --- a/docs/articles/expensify-classic/settings/account-settings/Set-Notifications.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: Set notifications -description: This article is about how to troubleshoot notifications from Expensify. ---- - -# Overview -Sometimes, members may have trouble receiving important email notifications from Expensify, such as Expensify Magic Code emails, account validation emails, secondary login validations, integration emails, or report action notifications (rejections, approvals, etc.). - -# Here's how to troubleshoot missing Expensify notifications: - -1. **No error message, but the email is never received** -The email might be delayed; give it 30-60 minutes to arrive in your inbox. -Check **Email Preferences** on the web via **Settings > Your Account > Preferences**In the **Contact Preferences** section. Ensure that the relevant boxes are checked for the email type you're missing. Check your email spam and trash folders, as Expensify messages might end up there inadvertently. -Check to make sure you haven't unintentionally blocked Expensify emails and whitelist [expensify.com](https://community.expensify.com/home/leaving?allowTrusted=1&target=http%3A%2F%2Fexpensify.com%2F), mg.expensify.com, and [amazonSES.com](https://community.expensify.com/home/leaving?allowTrusted=1&target=http%3A%2F%2Famazonses.com%2F) with your email provider. - -2. **A "We're having trouble emailing you" banner at the top of your screen** -Verify that your email address in your account settings is correct and is a real deliverable email address. -Re-send Verification Email: Look for an option to re-send a verification email, usually provided when this banner appears. - -![ExpensifyHelp_EmailError]({{site.url}}/assets/images/ExpensifyHelp_EmailError.png){:width="100%"} - -# Deep Dive - -**For Private Domains**: - -If your organization uses a private domain, consult your IT department or IT person to ensure that the following domains are whitelisted to receive our emails: expensify.com, mg.expensify.com, and amazonSES.com. These domains are the sources of various notification emails, so make sure they aren't being blocked. - -**For Public Domains (e.g., Gmail, Yahoo, Hotmail)**: - -To whitelist our emails on public email services: - -1. Check your Spam Folder: Search for messages from expensify.com in your Spam folder, open them, and click "Not Spam" at the top of the message. -2. Create a Filter: Set up a filter that identifies the entire expensify.com domain and directs all incoming messages to your inbox, preventing them from going to Spam. -3. Add Specific Contacts: While optional, adding specific email addresses from Expensify as contacts can further prevent emails from going to Spam. - -Please note that even if you receive emails from our Concierge support communication, ensure that both expensify.com and mg.expensify.com are whitelisted as they use different servers. - -**Email Server Blocking**: -Your email server may be blocking our emails due to spam filters or other services. Check with your IT department to investigate and resolve any server-level email blocking issues. - -**Mimecast**: -If your company uses Mimecast, a service that can affect email deliverability, check with your IT department. If Mimecast is in use, reach out to us at concierge@expensify.com through a new email, as this should ensure delivery to your inbox. Mimecast should eventually recognize the Expensify domain, preventing future filtering. - -**For Outlook Users**: -For Outlook users specifically: - -1. Click the gear icon in Outlook and select "View all Outlook settings." -2. Choose "Mail" from the settings menu. -3. Under the "Junk email" submenu, click "Add" under "Safe senders and domains." -4. Enter the email address you want to whitelist. -5. Click "Save." - -When you click the "Settings" link in the banner in Expensify, you'll be directed to your account settings page, where you may encounter a few different scenarios: - -- "Temporarily Suspended Emails": If the message mentions "temporarily suspended emails to," follow the steps provided in the yellow box. This situation typically occurs when we can't find a valid inbox to send our emails to. Possible reasons include: - - A misspelled email address during account creation. - - Use of a distribution list email (acting as an "alias" email) without a linked inbox. - - An auto-responder that has been responding to our emails for an extended period. -- To resolve this issue, confirm that the email address is indeed associated with an active inbox. Then, click the link that says "here," and your email should be unblocked shortly. -- SMTP Error (Gray Box): In some cases, you might encounter a gray box with an SMTP error message. This error can vary, but it typically looks something like this: - -![ExpensifyHelp_SMTPError]({{site.url}}/assets/images/ExpensifyHelp_SMTPError.png){:width="100%"} - -**These look a bit cryptic, yes, but hang in there!** - -The error messages you see are the raw message text received from your email provider's server to Amazon. These messages can vary in text, but the best course of action is to follow the link provided (by copying and pasting) in the text for the next steps. - -**Scenario 1**: If the message in the gray box includes "mimecast.com": It means that our emails are being blocked by the server. In this case, you should contact your IT person or team to address the issue. - -**Scenario 2**: If the message in the gray box mentions "blacklist at org/.com/.net," or resembles the screenshot provided, it indicates that your IT team has configured your email to use a third-party email reputation or blacklisting service. Here's what you need to know: -- All our emails are SPF and DKIM-signed, meaning they are cryptographically signed as coming from us and are not spam. -- The problem arises because we send mail from a cloud-based service. This means that the sender's IP serves multiple vendors, including Expensify. If one of those vendors is marked as spam, it can block all messages from that IP, even if they're from different vendors (including us). -- The better approach is for the server to flag spam via DKIM and SPF (rather than solely relying on the sender's IP address), as our messages are correctly signed and encrypted to prevent spoofing. - -To resolve these issues, consider discussing them with your IT team, as they can help implement the necessary changes to ensure you receive our emails without interruption. diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 6e69d2d4e53f..08623f0ad7ca 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -667,6 +667,10 @@ const ROUTES = { route: 'settings/workspaces/:policyID/tag/:tagName', getRoute: (policyID: string, tagName: string) => `settings/workspaces/${policyID}/tag/${encodeURIComponent(tagName)}` as const, }, + WORKSPACE_TAG_LIST_VIEW: { + route: 'settings/workspaces/:policyID/tag-list/:order', + getRoute: (policyID: string, order: string) => `settings/workspaces/${policyID}/tag-list/${encodeURIComponent(order)}` as const, + }, WORKSPACE_TAXES: { route: 'settings/workspaces/:policyID/taxes', getRoute: (policyID: string) => `settings/workspaces/${policyID}/taxes` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 725cab85f12b..1dc68cbe7a14 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -263,6 +263,7 @@ const SCREENS = { TAX_CREATE: 'Workspace_Tax_Create', TAG_CREATE: 'Tag_Create', TAG_SETTINGS: 'Tag_Settings', + TAG_LIST_VIEW: 'Tag_List_View', CURRENCY: 'Workspace_Profile_Currency', WORKFLOWS: 'Workspace_Workflows', WORKFLOWS_PAYER: 'Workspace_Workflows_Payer', diff --git a/src/languages/en.ts b/src/languages/en.ts index 39b648d110c4..9a66f4e433b2 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1846,6 +1846,7 @@ export default { disabled: 'Disabled', delete: 'Delete workspace', settings: 'Settings', + required: 'Required', reimburse: 'Reimbursements', categories: 'Categories', tags: 'Tags', diff --git a/src/languages/es.ts b/src/languages/es.ts index c762d76fe070..efbfab183f05 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1868,6 +1868,7 @@ export default { edit: 'Editar espacio de trabajo', enabled: 'Activada', disabled: 'Desactivada', + required: 'Obligatorio', delete: 'Eliminar espacio de trabajo', settings: 'ConfiguraciĆ³n', reimburse: 'Reembolsos', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 96ae6fdfffcc..569e21708dba 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -242,6 +242,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/distanceRates/PolicyDistanceRateEditPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAGS_SETTINGS]: () => require('../../../../pages/workspace/tags/WorkspaceTagsSettingsPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAG_SETTINGS]: () => require('../../../../pages/workspace/tags/TagSettingsPage').default as React.ComponentType, + [SCREENS.WORKSPACE.TAG_LIST_VIEW]: () => require('../../../../pages/workspace/tags/WorkspaceViewTagsPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAGS_EDIT]: () => require('../../../../pages/workspace/tags/WorkspaceEditTagsPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAG_CREATE]: () => require('../../../../pages/workspace/tags/WorkspaceCreateTagPage').default as React.ComponentType, [SCREENS.WORKSPACE.TAG_EDIT]: () => require('../../../../pages/workspace/tags/EditTagPage').default as React.ComponentType, diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts index b2aa7ad35a05..69f98961749e 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -51,7 +51,14 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.TAX_NAME, SCREENS.WORKSPACE.TAX_VALUE, ], - [SCREENS.WORKSPACE.TAGS]: [SCREENS.WORKSPACE.TAGS_SETTINGS, SCREENS.WORKSPACE.TAGS_EDIT, SCREENS.WORKSPACE.TAG_CREATE, SCREENS.WORKSPACE.TAG_SETTINGS, SCREENS.WORKSPACE.TAG_EDIT], + [SCREENS.WORKSPACE.TAGS]: [ + SCREENS.WORKSPACE.TAGS_SETTINGS, + SCREENS.WORKSPACE.TAGS_EDIT, + SCREENS.WORKSPACE.TAG_CREATE, + SCREENS.WORKSPACE.TAG_SETTINGS, + SCREENS.WORKSPACE.TAG_EDIT, + SCREENS.WORKSPACE.TAG_LIST_VIEW, + ], [SCREENS.WORKSPACE.CATEGORIES]: [SCREENS.WORKSPACE.CATEGORY_CREATE, SCREENS.WORKSPACE.CATEGORY_SETTINGS, SCREENS.WORKSPACE.CATEGORIES_SETTINGS, SCREENS.WORKSPACE.CATEGORY_EDIT], [SCREENS.WORKSPACE.DISTANCE_RATES]: [ SCREENS.WORKSPACE.CREATE_DISTANCE_RATE, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index aa0e7fd20924..602755d41f1d 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -416,6 +416,12 @@ const config: LinkingOptions['config'] = { tagName: (tagName: string) => decodeURIComponent(tagName), }, }, + [SCREENS.WORKSPACE.TAG_LIST_VIEW]: { + path: ROUTES.WORKSPACE_TAG_LIST_VIEW.route, + parse: { + order: (order: string) => decodeURIComponent(order), + }, + }, [SCREENS.WORKSPACE.TAXES_SETTINGS]: { path: ROUTES.WORKSPACE_TAXES_SETTINGS.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index cf999631a803..7a6d5ea9104a 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -213,6 +213,10 @@ type SettingsNavigatorParamList = { policyID: string; tagName: string; }; + [SCREENS.WORKSPACE.TAG_LIST_VIEW]: { + policyID: string; + order: string; + }; [SCREENS.WORKSPACE.TAGS_EDIT]: { policyID: string; tagName: string; diff --git a/src/pages/workspace/accounting/qbo/import/QuickbooksImportPage.tsx b/src/pages/workspace/accounting/qbo/import/QuickbooksImportPage.tsx index 7d6ee38a1a29..460e8de4cc31 100644 --- a/src/pages/workspace/accounting/qbo/import/QuickbooksImportPage.tsx +++ b/src/pages/workspace/accounting/qbo/import/QuickbooksImportPage.tsx @@ -59,7 +59,7 @@ function QuickbooksImportPage({policy}: WithPolicyProps) { }, ]; - if (policy?.connections?.quickbooksOnline.data.country !== CONST.COUNTRY.US) { + if (policy?.connections?.quickbooksOnline?.data?.country !== CONST.COUNTRY.US) { sections.push({ description: translate('workspace.qbo.taxes'), action: () => Navigation.navigate(ROUTES.POLICY_ACCOUNTING_QUICKBOOKS_ONLINE_TAXES.getRoute(policyID)), diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx index 4e4ab5ddb66e..e805f07b7230 100644 --- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx +++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx @@ -13,6 +13,7 @@ import * as Illustrations from '@components/Icon/Illustrations'; import ScreenWrapper from '@components/ScreenWrapper'; import SelectionList from '@components/SelectionList'; import RightElementEnabledStatus from '@components/SelectionList/RightElementEnabledStatus'; +import RightElementRequiredStatus from '@components/SelectionList/RightElementRequiredStatus'; import TableListItem from '@components/SelectionList/TableListItem'; import type {ListItem} from '@components/SelectionList/types'; import Text from '@components/Text'; @@ -68,6 +69,8 @@ function WorkspaceTagsPage({route, policy}: WorkspaceTagsPageProps) { const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`); const {environmentURL} = useEnvironment(); const isConnectedToAccounting = Object.keys(policy?.connections ?? {}).length > 0; + const policyTagsLists = useMemo(() => PolicyUtils.getTagLists(policyTags), [policyTags]); + const isOnlyOneTagsLists = Object.keys(policyTagsLists).length === 1; const fetchTags = useCallback(() => { Policy.openPolicyTagsPage(policyID); @@ -88,31 +91,39 @@ function WorkspaceTagsPage({route, policy}: WorkspaceTagsPageProps) { setSelectedTags({}); }, [isFocused]); - // We currently don't support multi level tags, so let's only get the first level tags. - const policyTagLists = useMemo(() => PolicyUtils.getTagLists(policyTags).slice(0, 1), [policyTags]); - const tagList = useMemo( - () => - policyTagLists - .map((policyTagList) => - lodashSortBy(Object.values(policyTagList.tags || []), 'name', localeCompare).map((value) => { - const tag = value as OnyxCommon.OnyxValueWithOfflineFeedback; - const isDisabled = tag.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; - return { - value: tag.name, - text: PolicyUtils.getCleanedTagName(tag.name), - keyForList: tag.name, - isSelected: !!selectedTags[tag.name], - pendingAction: tag.pendingAction, - errors: tag.errors ?? undefined, - enabled: tag.enabled, - isDisabled, - rightElement: , - }; - }), - ) - .flat(), - [policyTagLists, selectedTags], - ); + const tagList = useMemo(() => { + const policyTagLists = isOnlyOneTagsLists ? policyTagsLists.slice(0, 1) : policyTagsLists; + if (!isOnlyOneTagsLists) { + return Object.values(policyTagLists).map((policyTagList) => ({ + value: policyTagList.name, + text: PolicyUtils.getCleanedTagName(policyTagList.name), + keyForList: policyTagList.orderWeight.toString(), + isSelected: !!selectedTags[policyTagList.name], + enabled: true, + required: policyTagList.required, + rightElement: , + })); + } + return policyTagLists + .map((policyTagList) => + lodashSortBy(Object.values(policyTagList.tags || []), 'name', localeCompare).map((value) => { + const tag = value as OnyxCommon.OnyxValueWithOfflineFeedback; + const isDisabled = tag.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE; + return { + value: tag.name, + text: PolicyUtils.getCleanedTagName(tag.name), + keyForList: tag.name, + isSelected: !!selectedTags[tag.name], + pendingAction: tag.pendingAction, + errors: tag.errors ?? undefined, + enabled: tag.enabled, + isDisabled, + rightElement: , + }; + }), + ) + .flat(); + }, [isOnlyOneTagsLists, policyTagsLists, selectedTags]); const tagListKeyedByName = tagList.reduce>((acc, tag) => { acc[tag.value] = tag; @@ -147,6 +158,10 @@ function WorkspaceTagsPage({route, policy}: WorkspaceTagsPageProps) { }; const navigateToTagSettings = (tag: PolicyOption) => { + if (!isOnlyOneTagsLists) { + Navigation.navigate(ROUTES.WORKSPACE_TAG_LIST_VIEW.getRoute(policyID, tag.keyForList)); + return; + } Navigation.navigate(ROUTES.WORKSPACE_TAG_SETTINGS.getRoute(policyID, tag.keyForList)); }; @@ -233,14 +248,16 @@ function WorkspaceTagsPage({route, policy}: WorkspaceTagsPageProps) { return ( -