diff --git a/src/languages/de.ts b/src/languages/de.ts index 7e10ad6b46f3..ff0990a21bb3 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -6740,8 +6740,8 @@ Der Control-Tarif beginnt bei 9 $ pro aktivem Mitglied und Monat.`, chooseLimitType: 'Wähle einen Limittyp', smartLimit: 'Intelligentes Limit', smartLimitDescription: 'Bis zu einem bestimmten Betrag ausgeben, bevor eine Genehmigung erforderlich ist', - smartLimitDisabledDescription: (workspaceWorkflowsLink: string) => - `Bis zu einem bestimmten Betrag ausgeben, bevor eine Genehmigung erforderlich ist. Aktiviere Genehmigungen, um diese Option auszuwählen.`, + smartLimitDisabledDescription: (workspaceWorkflowsLink?: string) => + `Bis zu einem bestimmten Betrag ausgeben, bevor eine Genehmigung erforderlich ist. ${workspaceWorkflowsLink ? `Aktiviere Genehmigungen` : 'Aktiviere Genehmigungen'}, um diese Option auszuwählen.`, monthly: 'Monatlich', monthlyDescription: 'Bis zu einem bestimmten Betrag pro Monat ausgeben', fixedAmount: 'Fester Betrag', diff --git a/src/languages/el.ts b/src/languages/el.ts index a076ba28c2ab..0881dc102596 100644 --- a/src/languages/el.ts +++ b/src/languages/el.ts @@ -6890,8 +6890,8 @@ _Για πιο αναλυτικές οδηγίες, [επισκεφθείτε τ chooseLimitType: 'Επιλέξτε τύπο ορίου', smartLimit: 'Έξυπνο όριο', smartLimitDescription: 'Ξοδέψτε έως ένα συγκεκριμένο ποσό πριν απαιτείται έγκριση', - smartLimitDisabledDescription: (workspaceWorkflowsLink: string) => - `Ξοδέψτε έως ένα συγκεκριμένο ποσό πριν απαιτείται έγκριση. Ενεργοποιήστε τις εγκρίσεις για να επιλέξετε αυτήν την επιλογή.`, + smartLimitDisabledDescription: (workspaceWorkflowsLink?: string) => + `Ξοδέψτε έως ένα συγκεκριμένο ποσό πριν απαιτείται έγκριση. ${workspaceWorkflowsLink ? `Ενεργοποιήστε τις εγκρίσεις` : 'Ενεργοποιήστε τις εγκρίσεις'} για να επιλέξετε αυτήν την επιλογή.`, monthly: 'Μηνιαίως', monthlyDescription: 'Το όριο ανανεώνεται μηνιαία', fixedAmount: 'Σταθερό ποσό', diff --git a/src/languages/en.ts b/src/languages/en.ts index 6b85984d3650..39eacdcbd92d 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6841,8 +6841,8 @@ const translations = { chooseLimitType: 'Choose a limit type', smartLimit: 'Smart Limit', smartLimitDescription: 'Spend up to a certain amount before requiring approval', - smartLimitDisabledDescription: (workspaceWorkflowsLink: string) => - `Spend up to a certain amount before requiring approval. Enable approvals to select this option.`, + smartLimitDisabledDescription: (workspaceWorkflowsLink?: string) => + `Spend up to a certain amount before requiring approval. ${workspaceWorkflowsLink ? `Enable approvals` : 'Enable approvals'} to select this option.`, monthly: 'Monthly', monthlyDescription: 'Limit renews monthly', fixedAmount: 'Fixed amount', diff --git a/src/languages/es.ts b/src/languages/es.ts index 7e9ae24e7f9d..4ac72b6551d7 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -6911,8 +6911,8 @@ El plan Controlar empieza en 9 $ por miembro activo al mes.`, chooseLimitType: 'Elegir un tipo de límite', smartLimit: 'Límite inteligente', smartLimitDescription: 'Gasta hasta un determinado importe antes de requerir aprobación', - smartLimitDisabledDescription: (workspaceWorkflowsLink: string) => - `Gasta hasta un determinado importe antes de requerir aprobación. Habilita las aprobaciones para seleccionar esta opción.`, + smartLimitDisabledDescription: (workspaceWorkflowsLink?: string) => + `Gasta hasta un determinado importe antes de requerir aprobación. ${workspaceWorkflowsLink ? `Habilita las aprobaciones` : 'Habilita las aprobaciones'} para seleccionar esta opción.`, monthly: 'Mensual', monthlyDescription: 'Gasta hasta un determinado importe al mes', fixedAmount: 'Importe fijo', diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 65cdbbe47578..5f5680ce6632 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -6762,8 +6762,8 @@ Le forfait Control commence à 9 $ par Membre actif et par mois.`, chooseLimitType: 'Choisissez un type de limite', smartLimit: 'Limite intelligente', smartLimitDescription: 'Dépenser jusqu’à un certain montant avant de nécessiter une approbation', - smartLimitDisabledDescription: (workspaceWorkflowsLink: string) => - `Dépenser jusqu’à un certain montant avant de nécessiter une approbation. Activez les approbations pour sélectionner cette option.`, + smartLimitDisabledDescription: (workspaceWorkflowsLink?: string) => + `Dépenser jusqu’à un certain montant avant de nécessiter une approbation. ${workspaceWorkflowsLink ? `Activez les approbations` : 'Activez les approbations'} pour sélectionner cette option.`, monthly: 'Mensuel', monthlyDescription: 'Dépenser jusqu’à un certain montant par mois', fixedAmount: 'Montant fixe', diff --git a/src/languages/it.ts b/src/languages/it.ts index d1ac9de01f06..dd8ff1bf4680 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -6713,8 +6713,8 @@ Il piano Control parte da 9 $ al mese per ogni membro attivo.`, chooseLimitType: 'Scegli un tipo di limite', smartLimit: 'Limite intelligente', smartLimitDescription: 'Spendi fino a un certo importo prima di richiedere l’approvazione', - smartLimitDisabledDescription: (workspaceWorkflowsLink: string) => - `Spendi fino a un certo importo prima di richiedere l’approvazione. Abilita le approvazioni per selezionare questa opzione.`, + smartLimitDisabledDescription: (workspaceWorkflowsLink?: string) => + `Spendi fino a un certo importo prima di richiedere l’approvazione. ${workspaceWorkflowsLink ? `Abilita le approvazioni` : 'Abilita le approvazioni'} per selezionare questa opzione.`, monthly: 'Mensile', monthlyDescription: 'Spendi fino a un certo importo al mese', fixedAmount: 'Importo fisso', diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 08206bc52c4c..9045e283a94b 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -6628,8 +6628,8 @@ Control プランは、アクティブメンバー1人あたり月額 $9 から chooseLimitType: '上限の種類を選択', smartLimit: 'スマート制限', smartLimitDescription: '承認が必要になる前に、一定額まで支出できる', - smartLimitDisabledDescription: (workspaceWorkflowsLink: string) => - `承認が必要になる前に、一定額まで支出できます。このオプションを選択するには承認を有効化してください。`, + smartLimitDisabledDescription: (workspaceWorkflowsLink?: string) => + `承認が必要になる前に、一定額まで支出できます。このオプションを選択するには${workspaceWorkflowsLink ? `承認を有効化` : '承認を有効化'}してください。`, monthly: '毎月', monthlyDescription: '毎月、一定額まで利用する', fixedAmount: '固定額', diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 5996b7309f14..ad4387b80bb1 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -6696,8 +6696,8 @@ Het Control-abonnement begint bij $9 per actieve deelnemer per maand.`, chooseLimitType: 'Kies een limiettype', smartLimit: 'Slimme limiet', smartLimitDescription: 'Tot een bepaald bedrag uitgeven voordat goedkeuring vereist is', - smartLimitDisabledDescription: (workspaceWorkflowsLink: string) => - `Tot een bepaald bedrag uitgeven voordat goedkeuring vereist is. Schakel goedkeuringen in om deze optie te selecteren.`, + smartLimitDisabledDescription: (workspaceWorkflowsLink?: string) => + `Tot een bepaald bedrag uitgeven voordat goedkeuring vereist is. ${workspaceWorkflowsLink ? `Schakel goedkeuringen in` : 'Schakel goedkeuringen in'} om deze optie te selecteren.`, monthly: 'Maandelijks', monthlyDescription: 'Geef per maand tot een bepaald bedrag uit', fixedAmount: 'Vast bedrag', diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 9dd24e35f6fc..724408fd6cc3 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -6678,8 +6678,8 @@ Plan Control zaczyna się od 9 USD za aktywnego członka miesięcznie.`, chooseLimitType: 'Wybierz typ limitu', smartLimit: 'Inteligentny limit', smartLimitDescription: 'Wydawaj do określonej kwoty przed wymaganiem zatwierdzenia', - smartLimitDisabledDescription: (workspaceWorkflowsLink: string) => - `Wydawaj do określonej kwoty przed wymaganiem zatwierdzenia. Włącz zatwierdzanie, aby wybrać tę opcję.`, + smartLimitDisabledDescription: (workspaceWorkflowsLink?: string) => + `Wydawaj do określonej kwoty przed wymaganiem zatwierdzenia. ${workspaceWorkflowsLink ? `Włącz zatwierdzanie` : 'Włącz zatwierdzanie'}, aby wybrać tę opcję.`, monthly: 'Miesięcznie', monthlyDescription: 'Wydawaj do określonej kwoty miesięcznie', fixedAmount: 'Stała kwota', diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index f875d1849292..322fcf4629de 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -6699,8 +6699,8 @@ O plano Control começa em US$ 9 por membro ativo por mês.`, chooseLimitType: 'Escolha um tipo de limite', smartLimit: 'Limite Inteligente', smartLimitDescription: 'Gaste até um determinado valor antes de exigir aprovação', - smartLimitDisabledDescription: (workspaceWorkflowsLink: string) => - `Gaste até um determinado valor antes de exigir aprovação. Ative as aprovações para selecionar esta opção.`, + smartLimitDisabledDescription: (workspaceWorkflowsLink?: string) => + `Gaste até um determinado valor antes de exigir aprovação. ${workspaceWorkflowsLink ? `Ative as aprovações` : 'Ative as aprovações'} para selecionar esta opção.`, monthly: 'Mensal', monthlyDescription: 'Gastar até um determinado valor por mês', fixedAmount: 'Valor fixo', diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 772d881dcaba..16cf896a02e2 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -6467,8 +6467,8 @@ _如需更详细的说明,请[访问我们的帮助网站](${CONST.NETSUITE_IM chooseLimitType: '选择限额类型', smartLimit: '智能限额', smartLimitDescription: '在需要审批前可支出至指定金额上限', - smartLimitDisabledDescription: (workspaceWorkflowsLink: string) => - `在需要审批前可支出至指定金额上限。启用审批后即可选择此选项。`, + smartLimitDisabledDescription: (workspaceWorkflowsLink?: string) => + `在需要审批前可支出至指定金额上限。${workspaceWorkflowsLink ? `启用审批` : '启用审批'}后即可选择此选项。`, monthly: '每月', monthlyDescription: '每月消费上限为特定金额', fixedAmount: '固定金额', diff --git a/src/pages/workspace/expensifyCard/DynamicExpensifyCardLimitTypePage.tsx b/src/pages/workspace/expensifyCard/DynamicExpensifyCardLimitTypePage.tsx index ec7d8e39d970..59bedddd9148 100644 --- a/src/pages/workspace/expensifyCard/DynamicExpensifyCardLimitTypePage.tsx +++ b/src/pages/workspace/expensifyCard/DynamicExpensifyCardLimitTypePage.tsx @@ -30,7 +30,7 @@ import {openPolicyEditCardLimitTypePage} from '@libs/actions/Policy/Policy'; import {filterInactiveCardsForWorkspace, getDefaultExpensifyCardLimitType} from '@libs/CardUtils'; import DateUtils from '@libs/DateUtils'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; -import {getApprovalWorkflow} from '@libs/PolicyUtils'; +import {canMemberRead, getApprovalWorkflow} from '@libs/PolicyUtils'; import Navigation from '@navigation/Navigation'; import type {SettingsNavigatorParamList} from '@navigation/types'; @@ -46,6 +46,7 @@ import INPUT_IDS from '@src/types/form/EditExpensifyCardLimitTypeForm'; import type {CardLimitType} from '@src/types/onyx/Card'; import {useFocusEffect} from '@react-navigation/native'; +import {emailSelector} from '@selectors/Session'; import {format, toZonedTime} from 'date-fns-tz'; import React, {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; @@ -64,6 +65,7 @@ function DynamicExpensifyCardLimitTypePage({route}: WorkspaceEditCardLimitTypePa const policy = usePolicy(policyID); const defaultFundID = useDefaultFundID(policyID); const [cardsList] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${defaultFundID}_${CONST.EXPENSIFY_CARD.BANK}`, {selector: filterInactiveCardsForWorkspace}); + const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector}); const card = cardsList?.[cardID]; // Keep the latest card snapshot so a confirmation that resolves after the card refreshes (e.g. while the @@ -170,7 +172,10 @@ function DynamicExpensifyCardLimitTypePage({route}: WorkspaceEditCardLimitTypePa } } - const workspaceWorkflowsPageURL = `${environmentURL}/${ROUTES.WORKSPACE_WORKFLOWS.getRoute(policyID)}`; + // Only link to the Workflows page when the current user can actually read it. Card admins without Workflows + // access would otherwise be dropped onto the Not Found page. When they lack access, render plain (non-linked) text. + const canReadWorkflows = canMemberRead(policy, currentUserLogin ?? '', CONST.POLICY.POLICY_FEATURE.WORKFLOWS); + const workspaceWorkflowsPageURL = canReadWorkflows ? `${environmentURL}/${ROUTES.WORKSPACE_WORKFLOWS.getRoute(policyID)}` : undefined; const data = []; diff --git a/src/pages/workspace/expensifyCard/issueNew/LimitTypeStep.tsx b/src/pages/workspace/expensifyCard/issueNew/LimitTypeStep.tsx index 0f3d438fe678..7eb3d7481ff0 100644 --- a/src/pages/workspace/expensifyCard/issueNew/LimitTypeStep.tsx +++ b/src/pages/workspace/expensifyCard/issueNew/LimitTypeStep.tsx @@ -18,7 +18,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {setIssueNewCardStepAndData} from '@libs/actions/Card'; import {getDefaultExpensifyCardLimitType} from '@libs/CardUtils'; import {convertToBackendAmount, convertToFrontendAmountAsString} from '@libs/CurrencyUtils'; -import {getApprovalWorkflow, isPolicyFeatureEnabled} from '@libs/PolicyUtils'; +import {canMemberRead, getApprovalWorkflow, isPolicyFeatureEnabled} from '@libs/PolicyUtils'; import {getFieldRequiredErrors} from '@libs/ValidationUtils'; import CONST from '@src/CONST'; @@ -31,6 +31,7 @@ import KeyboardUtils from '@src/utils/keyboard'; import type {OnyxEntry} from 'react-native-onyx'; +import {emailSelector} from '@selectors/Session'; import React, {useCallback, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; @@ -56,6 +57,11 @@ function LimitTypeStep({policy, stepNames, startStepIndex}: LimitTypeStepProps) const formRef = useRef(null); const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.RAM_ONLY_ISSUE_NEW_EXPENSIFY_CARD}${policyID}`); const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`); + const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector}); + + // Only link to the Workflows page when the current user can actually read it. Card admins without Workflows + // access would otherwise be dropped onto the Not Found page. When they lack access, render plain (non-linked) text. + const canReadWorkflows = canMemberRead(policy, currentUserLogin ?? '', CONST.POLICY.POLICY_FEATURE.WORKFLOWS); const areApprovalsConfigured = getApprovalWorkflow(policy) !== CONST.POLICY.APPROVAL_MODE.OPTIONAL; const defaultType = getDefaultExpensifyCardLimitType(policy); @@ -102,7 +108,7 @@ function LimitTypeStep({policy, stepNames, startStepIndex}: LimitTypeStepProps) setIssueNewCardStepAndData({step: CONST.EXPENSIFY_CARD.STEP.CARD_TYPE, policyID}); }, [isEditing, policyID]); - const workspaceWorkflowsPageURL = `${environmentURL}/${ROUTES.WORKSPACE_WORKFLOWS.getRoute(policyID)}`; + const workspaceWorkflowsPageURL = canReadWorkflows ? `${environmentURL}/${ROUTES.WORKSPACE_WORKFLOWS.getRoute(policyID)}` : undefined; const data = useMemo(() => { const options = [];