From 982ffe50514f10cb877fbec5b04fa3238d9f952f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 11:01:00 -0600 Subject: [PATCH 01/27] create spend rules component --- src/languages/en.ts | 4 + src/pages/workspace/rules/PolicyRulesPage.tsx | 2 + .../rules/SpendRules/SpendRulesSection.tsx | 125 ++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx diff --git a/src/languages/en.ts b/src/languages/en.ts index 622dd0d14adde..5f399dfd563b9 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6626,6 +6626,10 @@ const translations = { title: 'Expense policy', cardSubtitle: "Here's where your team's expense policy lives, so everyone's on the same page about what's covered.", }, + spendRules: { + title: 'Spend', + subtitle: 'Set the spend rules so expenses arrive correctly coded and require less cleanup.', + }, }, planTypePage: { planTypes: { diff --git a/src/pages/workspace/rules/PolicyRulesPage.tsx b/src/pages/workspace/rules/PolicyRulesPage.tsx index 6714e1c6eb62f..1685065dc958e 100644 --- a/src/pages/workspace/rules/PolicyRulesPage.tsx +++ b/src/pages/workspace/rules/PolicyRulesPage.tsx @@ -15,6 +15,7 @@ import CONST from '@src/CONST'; import type SCREENS from '@src/SCREENS'; import IndividualExpenseRulesSection from './IndividualExpenseRulesSection'; import MerchantRulesSection from './MerchantRulesSection'; +import SpendRulesSection from './SpendRules/SpendRulesSection'; type PolicyRulesPageProps = PlatformStackScreenProps; @@ -55,6 +56,7 @@ function PolicyRulesPage({route}: PolicyRulesPageProps) { + {!!policy?.areExpensifyCardsEnabled && } diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx new file mode 100644 index 0000000000000..01fbab4b0536d --- /dev/null +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -0,0 +1,125 @@ +import React, {useMemo} from 'react'; +import {View} from 'react-native'; +import Badge from '@components/Badge'; +import MenuItem from '@components/MenuItem'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; +import Section from '@components/Section'; +import Text from '@components/Text'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; +import useLocalize from '@hooks/useLocalize'; +import usePolicy from '@hooks/usePolicy'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; + +type SpendRulesSectionProps = { + policyID: string; +}; + +function SpendRulesSection({policyID}: SpendRulesSectionProps) { + const {translate} = useLocalize(); + const styles = useThemeStyles(); + const theme = useTheme(); + // const policy = usePolicy(policyID); + // const expensifyIcons = useMemoizedLazyExpensifyIcons(['Plus']); + + // // Hoist iterator-independent translations to avoid redundant calls in the loop + // const fieldLabels: FieldLabels = useMemo( + // () => ({ + // category: translate('common.category').toLowerCase(), + // tag: translate('common.tag').toLowerCase(), + // description: translate('common.description').toLowerCase(), + // tax: translate('common.tax').toLowerCase(), + // }), + // [translate], + // ); + + // const codingRules = policy?.rules?.codingRules; + // const hasRules = !isEmptyObject(codingRules); + + // const sortedRules = useMemo(() => { + // if (!codingRules) { + // return []; + // } + + // return Object.entries(codingRules) + // .filter(([, rule]) => !!rule) + // .map(([ruleID, rule]) => ({...rule, ruleID})) + // .sort((a, b) => { + // if (a.created && b.created) { + // return a.created < b.created ? 1 : -1; + // } + // return 0; + // }); + // }, [codingRules]); + + const renderTitle = () => ( + + {translate('workspace.rules.merchantRules.title')} + + + ); + + return ( +
+ // {hasRules && ( + // + // {sortedRules.map((rule) => { + // const merchantName = rule.filters?.right ?? ''; + // const isExactMatch = rule.filters?.operator === CONST.SEARCH.SYNTAX_OPERATORS.EQUAL_TO; + // const matchDescription = translate('workspace.rules.merchantRules.ruleSummaryTitle', merchantName, isExactMatch); + // // const ruleDescription = getRuleDescription(rule, translate, fieldLabels); + + // return ( + // + // + // Navigation.navigate(ROUTES.RULES_MERCHANT_EDIT.getRoute(policyID, rule.ruleID))} + // sentryLabel={CONST.SENTRY_LABEL.WORKSPACE.RULES.MERCHANT_RULE_ITEM} + // disabled={rule.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE} + // /> + // + // + // ); + // })} + // + // )} + // Navigation.navigate(ROUTES.RULES_MERCHANT_NEW.getRoute(policyID))} + // sentryLabel={CONST.SENTRY_LABEL.WORKSPACE.RULES.ADD_MERCHANT_RULE} + // /> +
+ ); +} + +SpendRulesSection.displayName = 'SpendRulesSection'; + +export default SpendRulesSection; From cfea7b81bf05897c4e1367ca4773f3328281e00f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 11:02:40 -0600 Subject: [PATCH 02/27] update copy --- src/languages/en.ts | 2 +- .../rules/SpendRules/SpendRulesSection.tsx | 44 +------------------ 2 files changed, 3 insertions(+), 43 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 5f399dfd563b9..af8b82f8c8ed9 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6628,7 +6628,7 @@ const translations = { }, spendRules: { title: 'Spend', - subtitle: 'Set the spend rules so expenses arrive correctly coded and require less cleanup.', + subtitle: 'Approve or decline Expensify Card transactions in real time.', }, }, planTypePage: { diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index 01fbab4b0536d..5d81787ebf290 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -59,7 +59,7 @@ function SpendRulesSection({policyID}: SpendRulesSectionProps) { const renderTitle = () => ( - {translate('workspace.rules.merchantRules.title')} + {translate('workspace.rules.spendRules.title')} - // {hasRules && ( - // - // {sortedRules.map((rule) => { - // const merchantName = rule.filters?.right ?? ''; - // const isExactMatch = rule.filters?.operator === CONST.SEARCH.SYNTAX_OPERATORS.EQUAL_TO; - // const matchDescription = translate('workspace.rules.merchantRules.ruleSummaryTitle', merchantName, isExactMatch); - // // const ruleDescription = getRuleDescription(rule, translate, fieldLabels); - // return ( - // - // - // Navigation.navigate(ROUTES.RULES_MERCHANT_EDIT.getRoute(policyID, rule.ruleID))} - // sentryLabel={CONST.SENTRY_LABEL.WORKSPACE.RULES.MERCHANT_RULE_ITEM} - // disabled={rule.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE} - // /> - // - // - // ); - // })} - // - // )} - // Navigation.navigate(ROUTES.RULES_MERCHANT_NEW.getRoute(policyID))} - // sentryLabel={CONST.SENTRY_LABEL.WORKSPACE.RULES.ADD_MERCHANT_RULE} - // /> ); } From d03e0620a7ec0d045f790206a0217b39aeec6d09 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 11:32:09 -0600 Subject: [PATCH 03/27] clean up component --- src/languages/en.ts | 2 + .../rules/SpendRules/SpendRulesSection.tsx | 59 +++++-------------- 2 files changed, 16 insertions(+), 45 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index af8b82f8c8ed9..6b5bec6841829 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6629,6 +6629,8 @@ const translations = { spendRules: { title: 'Spend', subtitle: 'Approve or decline Expensify Card transactions in real time.', + defaultRuleDescription: 'All cards', + defaultRuleTitle: 'Categories: Adult services, ATMs, gambling, money transfers', }, }, planTypePage: { diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index 5d81787ebf290..07f293f4c760a 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -1,61 +1,20 @@ -import React, {useMemo} from 'react'; +import React from 'react'; import {View} from 'react-native'; import Badge from '@components/Badge'; -import MenuItem from '@components/MenuItem'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; -import OfflineWithFeedback from '@components/OfflineWithFeedback'; import Section from '@components/Section'; import Text from '@components/Text'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; -import usePolicy from '@hooks/usePolicy'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; -import ROUTES from '@src/ROUTES'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; -type SpendRulesSectionProps = { - policyID: string; -}; - -function SpendRulesSection({policyID}: SpendRulesSectionProps) { +function SpendRulesSection() { const {translate} = useLocalize(); const styles = useThemeStyles(); const theme = useTheme(); - // const policy = usePolicy(policyID); - // const expensifyIcons = useMemoizedLazyExpensifyIcons(['Plus']); - - // // Hoist iterator-independent translations to avoid redundant calls in the loop - // const fieldLabels: FieldLabels = useMemo( - // () => ({ - // category: translate('common.category').toLowerCase(), - // tag: translate('common.tag').toLowerCase(), - // description: translate('common.description').toLowerCase(), - // tax: translate('common.tax').toLowerCase(), - // }), - // [translate], - // ); - - // const codingRules = policy?.rules?.codingRules; - // const hasRules = !isEmptyObject(codingRules); - - // const sortedRules = useMemo(() => { - // if (!codingRules) { - // return []; - // } - - // return Object.entries(codingRules) - // .filter(([, rule]) => !!rule) - // .map(([ruleID, rule]) => ({...rule, ruleID})) - // .sort((a, b) => { - // if (a.created && b.created) { - // return a.created < b.created ? 1 : -1; - // } - // return 0; - // }); - // }, [codingRules]); + const expensifyIcons = useMemoizedLazyExpensifyIcons(['Lock']); const renderTitle = () => ( @@ -75,7 +34,17 @@ function SpendRulesSection({policyID}: SpendRulesSectionProps) { subtitle={translate('workspace.rules.spendRules.subtitle')} subtitleMuted > - + ); } From db5b4e286e84316dc88ae712bbc2c0d752fb7810 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 11:41:00 -0600 Subject: [PATCH 04/27] update props --- src/pages/workspace/rules/PolicyRulesPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/rules/PolicyRulesPage.tsx b/src/pages/workspace/rules/PolicyRulesPage.tsx index 1685065dc958e..4a0741f8e8b5d 100644 --- a/src/pages/workspace/rules/PolicyRulesPage.tsx +++ b/src/pages/workspace/rules/PolicyRulesPage.tsx @@ -56,7 +56,7 @@ function PolicyRulesPage({route}: PolicyRulesPageProps) { - {!!policy?.areExpensifyCardsEnabled && } + {!!policy?.areExpensifyCardsEnabled && } From e8413b07cdba0d2e43bb89b9e2d2d0d60bad864f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 12:06:46 -0600 Subject: [PATCH 05/27] update styles --- src/CONST/index.ts | 1 + src/languages/en.ts | 1 + .../rules/SpendRules/SpendRulesSection.tsx | 47 ++++++++++++++----- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index dbf9a74a32aaf..6fdf5d9f4ed64 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -9120,6 +9120,7 @@ const CONST = { }, RULES: { INDIVIDUAL_EXPENSES_MENU_ITEM: 'WorkspaceRules-IndividualExpensesMenuItem', + SPEND_RULE_ITEM: 'WorkspaceRules-SpendRuleItem', MERCHANT_RULE_ITEM: 'WorkspaceRules-MerchantRuleItem', ADD_MERCHANT_RULE: 'WorkspaceRules-AddMerchantRule', MERCHANT_RULE_SECTION_ITEM: 'WorkspaceRules-MerchantRuleSectionItem', diff --git a/src/languages/en.ts b/src/languages/en.ts index 6b5bec6841829..382d139d46974 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6630,6 +6630,7 @@ const translations = { title: 'Spend', subtitle: 'Approve or decline Expensify Card transactions in real time.', defaultRuleDescription: 'All cards', + block: 'Block', defaultRuleTitle: 'Categories: Adult services, ATMs, gambling, money transfers', }, }, diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index 07f293f4c760a..a4945f32099a7 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -1,13 +1,14 @@ import React from 'react'; import {View} from 'react-native'; import Badge from '@components/Badge'; -import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import MenuItem from '@components/MenuItem'; import Section from '@components/Section'; import Text from '@components/Text'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; 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'; function SpendRulesSection() { @@ -16,7 +17,11 @@ function SpendRulesSection() { const theme = useTheme(); const expensifyIcons = useMemoizedLazyExpensifyIcons(['Lock']); - const renderTitle = () => ( + const defaultRuleTitle = translate('workspace.rules.spendRules.defaultRuleTitle'); + const descriptionLabel = translate('workspace.rules.spendRules.defaultRuleDescription'); + const blockLabel = translate('workspace.rules.spendRules.block'); + + const renderSectionTitle = () => ( {translate('workspace.rules.spendRules.title')} ); + const menuItemTitle = () => ( + + + + {defaultRuleTitle} + + + ); + return (
-
); From 2969fd4222446c5850f3d3d46c10a99f1a35ac92 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 12:28:29 -0600 Subject: [PATCH 06/27] update styles --- .../rules/SpendRules/SpendRulesSection.tsx | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index a4945f32099a7..df1cedadeebe1 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -1,6 +1,7 @@ import React from 'react'; import {View} from 'react-native'; import Badge from '@components/Badge'; +import Icon from '@components/Icon'; import MenuItem from '@components/MenuItem'; import Section from '@components/Section'; import Text from '@components/Text'; @@ -32,19 +33,31 @@ function SpendRulesSection() {
); - const menuItemTitle = () => ( - - - - {defaultRuleTitle} - + const menuItemBody = ( + + + + + {descriptionLabel} + + + + + {defaultRuleTitle} + ); @@ -56,17 +69,11 @@ function SpendRulesSection() { subtitleMuted > ); From b182a96923a70aaaebd363a1c268d30c3a1dfb1d Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 12:57:15 -0600 Subject: [PATCH 07/27] add modal; --- src/languages/en.ts | 4 ++++ .../rules/SpendRules/SpendRulesSection.tsx | 22 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 382d139d46974..33b2c4999572c 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6632,6 +6632,10 @@ const translations = { defaultRuleDescription: 'All cards', block: 'Block', defaultRuleTitle: 'Categories: Adult services, ATMs, gambling, money transfers', + builtInProtectionModal: { + title: 'Expensify Cards offer built-in protection - always', + description: 'Expensify always declines these charges:', + } }, }, planTypePage: { diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index df1cedadeebe1..4ee71b345e1e0 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -5,18 +5,35 @@ import Icon from '@components/Icon'; import MenuItem from '@components/MenuItem'; import Section from '@components/Section'; import Text from '@components/Text'; -import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; +import {useMemoizedLazyExpensifyIcons, useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; 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 useConfirmModal from '@hooks/useConfirmModal'; function SpendRulesSection() { const {translate} = useLocalize(); const styles = useThemeStyles(); const theme = useTheme(); const expensifyIcons = useMemoizedLazyExpensifyIcons(['Lock']); + const {showConfirmModal} = useConfirmModal(); + const illustrations = useMemoizedLazyIllustrations(['ExpensifyCardIllustration']); + + const showBuiltInProtectionModal = () => { + showConfirmModal({ + image: illustrations.ExpensifyCardIllustration, + imageStyles: [styles.ph5, styles.pv5], + title: translate('workspace.rules.spendRules.builtInProtectionModal.title'), + titleStyles: [styles.textHeadlineH1], + titleContainerStyles: styles.mb2, + prompt: translate('workspace.rules.spendRules.builtInProtectionModal.description'), + shouldShowCancelButton: false, + success: false, + confirmText: translate('common.buttonConfirm'), + }); + }; const defaultRuleTitle = translate('workspace.rules.spendRules.defaultRuleTitle'); const descriptionLabel = translate('workspace.rules.spendRules.defaultRuleDescription'); @@ -63,9 +80,9 @@ function SpendRulesSection() { return (
From cd47b97d686f383f44a3a59a63e144cf399e0a83 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 13:24:31 -0600 Subject: [PATCH 08/27] add copy --- src/languages/en.ts | 2 +- src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 33b2c4999572c..ee14e8b2cb0c0 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6634,7 +6634,7 @@ const translations = { defaultRuleTitle: 'Categories: Adult services, ATMs, gambling, money transfers', builtInProtectionModal: { title: 'Expensify Cards offer built-in protection - always', - description: 'Expensify always declines these charges:', + description: `Expensify always declines these charges:\n\n • Adult services\n • ATMs\n • Gambling\n • Money transfers\n\nAdd more spend rules to protect company cash flow.`, } }, }, diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index 4ee71b345e1e0..e894f22b5f891 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -27,8 +27,9 @@ function SpendRulesSection() { imageStyles: [styles.ph5, styles.pv5], title: translate('workspace.rules.spendRules.builtInProtectionModal.title'), titleStyles: [styles.textHeadlineH1], - titleContainerStyles: styles.mb2, + titleContainerStyles: [styles.mb3], prompt: translate('workspace.rules.spendRules.builtInProtectionModal.description'), + promptStyles: [styles.preWrap], shouldShowCancelButton: false, success: false, confirmText: translate('common.buttonConfirm'), From f66ef4b4590bc36b77f1f058439c6c208b20b313 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 13:26:00 -0600 Subject: [PATCH 09/27] rm style --- src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index e894f22b5f891..8741dce5bf398 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -29,7 +29,6 @@ function SpendRulesSection() { titleStyles: [styles.textHeadlineH1], titleContainerStyles: [styles.mb3], prompt: translate('workspace.rules.spendRules.builtInProtectionModal.description'), - promptStyles: [styles.preWrap], shouldShowCancelButton: false, success: false, confirmText: translate('common.buttonConfirm'), From ee5df9c68676425c19046b57fa1f1f96d8b9db26 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 13:33:16 -0600 Subject: [PATCH 10/27] make modal 400px wide --- src/components/ConfirmModal.tsx | 6 +++++- src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx | 6 ++++++ src/styles/variables.ts | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/ConfirmModal.tsx b/src/components/ConfirmModal.tsx index 02be40520fb3d..5a8e75a1965a6 100755 --- a/src/components/ConfirmModal.tsx +++ b/src/components/ConfirmModal.tsx @@ -115,6 +115,9 @@ type ConfirmModalProps = { /** Whether to ignore the back handler during transition */ shouldIgnoreBackHandlerDuringTransition?: boolean; + + /** Merged into the modal container after default confirm styles (e.g. `width` overrides `variables.sideBarWidth` on wide screens). */ + innerContainerStyle?: ViewStyle; }; function ConfirmModal({ @@ -152,6 +155,7 @@ function ConfirmModal({ isConfirmLoading, shouldHandleNavigationBack, shouldIgnoreBackHandlerDuringTransition, + innerContainerStyle, }: ConfirmModalProps) { // We need to use isSmallScreenWidth instead of shouldUseNarrowLayout to use the correct modal type // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth @@ -174,7 +178,7 @@ function ConfirmModal({ shouldSetModalVisibility={shouldSetModalVisibility} onModalHide={onModalHide} type={isSmallScreenWidth ? CONST.MODAL.MODAL_TYPE.BOTTOM_DOCKED : CONST.MODAL.MODAL_TYPE.CONFIRM} - innerContainerStyle={styles.pv0} + innerContainerStyle={innerContainerStyle ? {...styles.pv0, ...innerContainerStyle} : styles.pv0} shouldEnableNewFocusManagement={shouldEnableNewFocusManagement} restoreFocusType={restoreFocusType} shouldHandleNavigationBack={shouldHandleNavigationBack} diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index 8741dce5bf398..53dcef881dd25 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -7,6 +7,8 @@ import Section from '@components/Section'; import Text from '@components/Text'; import {useMemoizedLazyExpensifyIcons, useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; @@ -16,7 +18,9 @@ import useConfirmModal from '@hooks/useConfirmModal'; function SpendRulesSection() { const {translate} = useLocalize(); const styles = useThemeStyles(); + const StyleUtils = useStyleUtils(); const theme = useTheme(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); const expensifyIcons = useMemoizedLazyExpensifyIcons(['Lock']); const {showConfirmModal} = useConfirmModal(); const illustrations = useMemoizedLazyIllustrations(['ExpensifyCardIllustration']); @@ -29,9 +33,11 @@ function SpendRulesSection() { titleStyles: [styles.textHeadlineH1], titleContainerStyles: [styles.mb3], prompt: translate('workspace.rules.spendRules.builtInProtectionModal.description'), + promptStyles: [styles.preWrap], shouldShowCancelButton: false, success: false, confirmText: translate('common.buttonConfirm'), + ...(shouldUseNarrowLayout ? {} : {innerContainerStyle: StyleUtils.getWidthStyle(variables.builtInProtectionModalWidth)}), }); }; diff --git a/src/styles/variables.ts b/src/styles/variables.ts index 1f8452a1d0afe..654ca4af47058 100644 --- a/src/styles/variables.ts +++ b/src/styles/variables.ts @@ -254,6 +254,7 @@ export default { onboardingModalWidth: 640, holdEducationModalWidth: 400, changePolicyEducationModalWidth: 400, + builtInProtectionModalWidth: 400, changePolicyEducationModalIconWidth: 147.69, changePolicyEducationModalIconHeight: 180, transactionReceiptButtonWidth: 100, From 1f7c684b395a991903f99d2ad81bb83bff097b7b Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 13:40:59 -0600 Subject: [PATCH 11/27] fix styles --- src/languages/en.ts | 2 +- src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index ee14e8b2cb0c0..c961352c93bf7 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6634,7 +6634,7 @@ const translations = { defaultRuleTitle: 'Categories: Adult services, ATMs, gambling, money transfers', builtInProtectionModal: { title: 'Expensify Cards offer built-in protection - always', - description: `Expensify always declines these charges:\n\n • Adult services\n • ATMs\n • Gambling\n • Money transfers\n\nAdd more spend rules to protect company cash flow.`, + description: `Expensify always declines these charges:\n\n • Adult services\n • ATMs\n • Gambling\n • Money transfers\n\nAdd more spend rules to protect company cash flow.`, } }, }, diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index 53dcef881dd25..e73c9b01b08eb 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -33,11 +33,11 @@ function SpendRulesSection() { titleStyles: [styles.textHeadlineH1], titleContainerStyles: [styles.mb3], prompt: translate('workspace.rules.spendRules.builtInProtectionModal.description'), - promptStyles: [styles.preWrap], + promptStyles: [styles.preWrap, styles.mb1], shouldShowCancelButton: false, success: false, confirmText: translate('common.buttonConfirm'), - ...(shouldUseNarrowLayout ? {} : {innerContainerStyle: StyleUtils.getWidthStyle(variables.builtInProtectionModalWidth)}), + innerContainerStyle: shouldUseNarrowLayout ? undefined : StyleUtils.getWidthStyle(variables.builtInProtectionModalWidth), }); }; From a30c3c5ad7d223b37a424ac4ba0183daa41405e3 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 13:43:04 -0600 Subject: [PATCH 12/27] fix overflow --- .../workspace/rules/SpendRules/SpendRulesSection.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index e73c9b01b08eb..e13421ac73758 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -33,7 +33,7 @@ function SpendRulesSection() { titleStyles: [styles.textHeadlineH1], titleContainerStyles: [styles.mb3], prompt: translate('workspace.rules.spendRules.builtInProtectionModal.description'), - promptStyles: [styles.preWrap, styles.mb1], + promptStyles: [styles.mb1], shouldShowCancelButton: false, success: false, confirmText: translate('common.buttonConfirm'), @@ -79,7 +79,13 @@ function SpendRulesSection() { error isCondensed /> - {defaultRuleTitle} + + {defaultRuleTitle} +
); From 6ede085c323a602b6806f1ba3e31e38c9c0d120d Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 13:45:22 -0600 Subject: [PATCH 13/27] fix prettier --- src/languages/en.ts | 2 +- src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index c961352c93bf7..e498ca91d5561 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6635,7 +6635,7 @@ const translations = { builtInProtectionModal: { title: 'Expensify Cards offer built-in protection - always', description: `Expensify always declines these charges:\n\n • Adult services\n • ATMs\n • Gambling\n • Money transfers\n\nAdd more spend rules to protect company cash flow.`, - } + }, }, }, planTypePage: { diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index e13421ac73758..1f8d3bfa065fc 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -5,6 +5,7 @@ import Icon from '@components/Icon'; import MenuItem from '@components/MenuItem'; import Section from '@components/Section'; import Text from '@components/Text'; +import useConfirmModal from '@hooks/useConfirmModal'; import {useMemoizedLazyExpensifyIcons, useMemoizedLazyIllustrations} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -13,7 +14,6 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import variables from '@styles/variables'; import CONST from '@src/CONST'; -import useConfirmModal from '@hooks/useConfirmModal'; function SpendRulesSection() { const {translate} = useLocalize(); From c6fcb679ef9af5d3f68c097593ae3bb21b8176fa Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 13:48:09 -0600 Subject: [PATCH 14/27] add translations --- src/languages/de.ts | 27 ++++++++++++++++++++++++++- src/languages/fr.ts | 27 ++++++++++++++++++++++++++- src/languages/it.ts | 27 ++++++++++++++++++++++++++- src/languages/ja.ts | 27 ++++++++++++++++++++++++++- src/languages/nl.ts | 27 ++++++++++++++++++++++++++- src/languages/pl.ts | 27 ++++++++++++++++++++++++++- src/languages/pt-BR.ts | 27 ++++++++++++++++++++++++++- src/languages/zh-hans.ts | 27 ++++++++++++++++++++++++++- 8 files changed, 208 insertions(+), 8 deletions(-) diff --git a/src/languages/de.ts b/src/languages/de.ts index e8746515f6845..d90913c6f848c 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -6647,6 +6647,24 @@ Fordern Sie Spesendetails wie Belege und Beschreibungen an, legen Sie Limits und title: 'Spesenrichtlinie', cardSubtitle: 'Hier ist die Spesenrichtlinie deines Teams hinterlegt, damit alle denselben Stand haben, was abgedeckt ist.', }, + spendRules: { + title: 'Ausgaben', + subtitle: 'Genehmigen oder lehnen Sie Expensify Karten-Transaktionen in Echtzeit ab.', + defaultRuleDescription: 'Alle Karten', + block: 'Block', + defaultRuleTitle: 'Kategorien: Dienste für Erwachsene, Geldautomaten, Glücksspiel, Geldüberweisungen', + builtInProtectionModal: { + title: 'Expensify Karten bieten integrierten Schutz – jederzeit', + description: `Expensify lehnt diese Belastungen immer ab: + + • Dienstleistungen für Erwachsene + • Geldautomaten (ATMs) + • Glücksspiel + • Geldüberweisungen + +Fügen Sie weitere Ausgabenregeln hinzu, um den Cashflow des Unternehmens zu schützen.`, + }, + }, }, planTypePage: { planTypes: { @@ -7445,7 +7463,14 @@ Fordern Sie Spesendetails wie Belege und Beschreibungen an, legen Sie Limits und searchIn: 'Suchen in', searchPlaceholder: 'Nach etwas suchen', suggestions: 'Vorschläge', - suggestionsAvailable: ({count}: {count: number}, query = '') => ({ + suggestionsAvailable: ( + { + count, + }: { + count: number; + }, + query = '', + ) => ({ one: `Vorschläge verfügbar${query ? ` für ${query}` : ''}. ${count} Ergebnis.`, other: (resultCount: number) => `Vorschläge verfügbar${query ? ` für ${query}` : ''}. ${resultCount} Ergebnisse.`, }), diff --git a/src/languages/fr.ts b/src/languages/fr.ts index ef75542dbc6e7..b95aede46ca71 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -6671,6 +6671,24 @@ Rendez obligatoires des informations de dépense comme les reçus et les descrip title: 'Politique de dépenses', cardSubtitle: 'C’est ici que se trouve la politique de dépenses de votre équipe, pour que tout le monde soit d’accord sur ce qui est couvert.', }, + spendRules: { + title: 'Dépenser', + subtitle: 'Approuvez ou refusez les transactions Carte Expensify en temps réel.', + defaultRuleDescription: 'Toutes les cartes', + block: 'Bloquer', + defaultRuleTitle: 'Catégories : services pour adultes, DAB, jeux d’argent, transferts d’argent', + builtInProtectionModal: { + title: 'Les Cartes Expensify offrent une protection intégrée – en permanence', + description: `Expensify refuse toujours ces types de dépenses : + + • Services pour adultes + • DAB + • Jeux d’argent + • Transferts d’argent + +Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’entreprise.`, + }, + }, }, planTypePage: { planTypes: { @@ -7469,7 +7487,14 @@ Rendez obligatoires des informations de dépense comme les reçus et les descrip searchIn: 'Rechercher dans', searchPlaceholder: 'Rechercher quelque chose', suggestions: 'Suggestions', - suggestionsAvailable: ({count}: {count: number}, query = '') => ({ + suggestionsAvailable: ( + { + count, + }: { + count: number; + }, + query = '', + ) => ({ one: `Suggestions disponibles${query ? ` pour ${query}` : ''}. ${count} résultat.`, other: (resultCount: number) => `Suggestions disponibles${query ? ` pour ${query}` : ''}. ${resultCount} résultats.`, }), diff --git a/src/languages/it.ts b/src/languages/it.ts index edc379199bcc1..c43330d90d634 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -6634,6 +6634,24 @@ Richiedi dettagli sulle spese come ricevute e descrizioni, imposta limiti e valo title: 'Politica di spesa', cardSubtitle: 'Qui trovi il regolamento spese del tuo team, così tutti sono allineati su cosa è coperto.', }, + spendRules: { + title: 'Spesa', + subtitle: 'Approva o rifiuta le transazioni della Carta Expensify in tempo reale.', + defaultRuleDescription: 'Tutte le carte', + block: 'Blocca', + defaultRuleTitle: 'Categorie: Servizi per adulti, Bancomat, gioco d’azzardo, trasferimenti di denaro', + builtInProtectionModal: { + title: 'Le Carte Expensify offrono una protezione integrata, sempre', + description: `Expensify rifiuta sempre queste spese: + + • Servizi per adulti + • Bancomat + • Gioco d’azzardo + • Trasferimenti di denaro + +Aggiungi altre regole di spesa per proteggere il flusso di cassa dell’azienda.`, + }, + }, }, planTypePage: { planTypes: { @@ -7433,7 +7451,14 @@ Richiedi dettagli sulle spese come ricevute e descrizioni, imposta limiti e valo searchIn: 'Cerca in', searchPlaceholder: 'Cerca qualcosa', suggestions: 'Suggerimenti', - suggestionsAvailable: ({count}: {count: number}, query = '') => ({ + suggestionsAvailable: ( + { + count, + }: { + count: number; + }, + query = '', + ) => ({ one: `Suggerimenti disponibili${query ? ` per ${query}` : ''}. ${count} risultato.`, other: (resultCount: number) => `Suggerimenti disponibili${query ? ` per ${query}` : ''}. ${resultCount} risultati.`, }), diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 348b4b72c3232..d8e7379ce1595 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -6560,6 +6560,24 @@ ${reportName} title: '経費ポリシー', cardSubtitle: 'ここはチームの経費ポリシーが保存されている場所です。何が対象になるか、全員が同じ認識を持てます。', }, + spendRules: { + title: '支出', + subtitle: 'Expensify カードの取引をリアルタイムで承認または却下できます。', + defaultRuleDescription: 'すべてのカード', + block: 'ブロック', + defaultRuleTitle: 'カテゴリ:アダルトサービス、ATM、ギャンブル、送金', + builtInProtectionModal: { + title: 'Expensify カードは、常に組み込みの保護機能を備えています', + description: `Expensify は常に次の利用を拒否します。 + + ・アダルトサービス + ・ATM + ・ギャンブル + ・送金 + +会社のキャッシュフローを守るために、支出ルールをさらに追加しましょう。`, + }, + }, }, planTypePage: { planTypes: { @@ -7341,7 +7359,14 @@ ${reportName} searchIn: '検索対象', searchPlaceholder: '何かを検索', suggestions: '提案', - suggestionsAvailable: ({count}: {count: number}, query = '') => ({ + suggestionsAvailable: ( + { + count, + }: { + count: number; + }, + query = '', + ) => ({ one: `候補があります${query ? `: ${query}` : ''}。${count}件の結果。`, other: (resultCount: number) => `候補があります${query ? `: ${query}` : ''}。${resultCount}件の結果。`, }), diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 538619e0600d8..924b45830a60d 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -6613,6 +6613,24 @@ Vereis onkostendetails zoals bonnen en beschrijvingen, stel limieten en standaar title: 'Declaratiebeleid', cardSubtitle: 'Hier staat het declaratiebeleid van je team, zodat iedereen hetzelfde beeld heeft van wat er wordt vergoed.', }, + spendRules: { + title: 'Uitgaven', + subtitle: 'Keur transacties met de Expensify Kaart in realtime goed of wijs ze af.', + defaultRuleDescription: 'Alle kaarten', + block: 'Blokkeren', + defaultRuleTitle: 'Categorieën: Diensten voor volwassenen, geldautomaten, gokken, geldoverdrachten', + builtInProtectionModal: { + title: 'Expensify Kaarten bieden altijd ingebouwde bescherming', + description: `Expensify wijst deze transacties altijd af: + + • Seksdiensten + • Geldautomaten (ATM's) + • Gokken + • Geldoverschrijvingen + +Voeg meer bestedingsregels toe om de cashflow van je bedrijf te beschermen.`, + }, + }, }, planTypePage: { planTypes: { @@ -7399,7 +7417,14 @@ Vereis onkostendetails zoals bonnen en beschrijvingen, stel limieten en standaar searchIn: 'Zoeken in', searchPlaceholder: 'Zoek iets', suggestions: 'Suggesties', - suggestionsAvailable: ({count}: {count: number}, query = '') => ({ + suggestionsAvailable: ( + { + count, + }: { + count: number; + }, + query = '', + ) => ({ one: `Suggesties beschikbaar${query ? ` voor ${query}` : ''}. ${count} resultaat.`, other: (resultCount: number) => `Suggesties beschikbaar${query ? ` voor ${query}` : ''}. ${resultCount} resultaten.`, }), diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 842652363aef1..0577802ac5abc 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -6608,6 +6608,24 @@ Wymagaj szczegółów wydatków, takich jak paragony i opisy, ustawiaj limity i title: 'Polityka wydatków', cardSubtitle: 'To tutaj znajduje się polityka wydatków Twojego zespołu, aby wszyscy mieli jasność co do tego, co jest objęte.', }, + spendRules: { + title: 'Wydatki', + subtitle: 'Zatwierdzaj lub odrzucaj transakcje Kartą Expensify w czasie rzeczywistym.', + defaultRuleDescription: 'Wszystkie karty', + block: 'Zablokuj', + defaultRuleTitle: 'Kategorie: usługi dla dorosłych, bankomaty, hazard, przelewy pieniężne', + builtInProtectionModal: { + title: 'Karty Expensify zapewniają wbudowaną ochronę – zawsze', + description: `Expensify zawsze odrzuca te obciążenia: + + • Usługi dla dorosłych + • Bankomaty + • Hazard + • Przelewy pieniężne + +Dodaj więcej zasad wydatków, żeby chronić przepływy pieniężne firmy.`, + }, + }, }, planTypePage: { planTypes: { @@ -7400,7 +7418,14 @@ Wymagaj szczegółów wydatków, takich jak paragony i opisy, ustawiaj limity i searchIn: 'Szukaj w', searchPlaceholder: 'Wyszukaj coś', suggestions: 'Sugestie', - suggestionsAvailable: ({count}: {count: number}, query = '') => ({ + suggestionsAvailable: ( + { + count, + }: { + count: number; + }, + query = '', + ) => ({ one: `Dostępne sugestie${query ? ` dla ${query}` : ''}. ${count} wynik.`, other: (resultCount: number) => `Dostępne sugestie${query ? ` dla ${query}` : ''}. ${resultCount} wyniki.`, }), diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 80ba6a316295d..efd53c34ba4b5 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -6612,6 +6612,24 @@ Exija dados de despesas como recibos e descrições, defina limites e padrões e title: 'Política de despesas', cardSubtitle: 'Aqui é onde fica a política de despesas da sua equipe, para que todo mundo esteja alinhado sobre o que é coberto.', }, + spendRules: { + title: 'Gasto', + subtitle: 'Aprove ou recuse transações do Cartão Expensify em tempo real.', + defaultRuleDescription: 'Todos os cartões', + block: 'Bloquear', + defaultRuleTitle: 'Categorias: Serviços adultos, caixas eletrônicos, jogos de azar, transferências de dinheiro', + builtInProtectionModal: { + title: 'Os Cartões Expensify oferecem proteção integrada — sempre', + description: `A Expensify sempre recusa estas cobranças: + + • Serviços adultos + • Caixas eletrônicos (ATMs) + • Jogos de azar + • Transferências de dinheiro + +Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, + }, + }, }, planTypePage: { planTypes: { @@ -7387,7 +7405,14 @@ Exija dados de despesas como recibos e descrições, defina limites e padrões e searchIn: 'Pesquisar em', searchPlaceholder: 'Pesquisar algo', suggestions: 'Sugestões', - suggestionsAvailable: ({count}: {count: number}, query = '') => ({ + suggestionsAvailable: ( + { + count, + }: { + count: number; + }, + query = '', + ) => ({ one: `Sugestões disponíveis${query ? ` para ${query}` : ''}. ${count} resultado.`, other: (resultCount: number) => `Sugestões disponíveis${query ? ` para ${query}` : ''}. ${resultCount} resultados.`, }), diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index f1ffd1b9cb941..20a0343b04714 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -6448,6 +6448,24 @@ ${reportName} title: '报销政策', cardSubtitle: '这是你们团队的报销政策所在之处,让所有人都清楚哪些内容在报销范围之内。', }, + spendRules: { + title: '支出', + subtitle: '实时批准或拒绝 Expensify 卡交易。', + defaultRuleDescription: '所有卡片', + block: '屏蔽', + defaultRuleTitle: '类别:成人服务、自动取款机、赌博、转账', + builtInProtectionModal: { + title: 'Expensify 卡提供始终内置的保护', + description: `Expensify 始终会拒绝以下消费: + + • 成人服务 + • 自动取款机(ATM) + • 赌博 + • 转账汇款 + +添加更多消费规则,保护公司的现金流。`, + }, + }, }, planTypePage: { planTypes: { @@ -7217,7 +7235,14 @@ ${reportName} searchIn: '搜索范围', searchPlaceholder: '搜索内容', suggestions: '建议', - suggestionsAvailable: ({count}: {count: number}, query = '') => ({ + suggestionsAvailable: ( + { + count, + }: { + count: number; + }, + query = '', + ) => ({ one: `有可用建议${query ? `:${query}` : ''}。共${count}条结果。`, other: (resultCount: number) => `有可用建议${query ? `:${query}` : ''}。共${resultCount}条结果。`, }), From ff055211f4c7b7b9bce4e6fa681cacf9f781747a Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 13:53:23 -0600 Subject: [PATCH 15/27] apply translations --- src/languages/de.ts | 9 +-------- src/languages/es.ts | 11 +++++++++++ src/languages/fr.ts | 9 +-------- src/languages/it.ts | 9 +-------- src/languages/ja.ts | 9 +-------- src/languages/nl.ts | 9 +-------- src/languages/pl.ts | 9 +-------- src/languages/pt-BR.ts | 9 +-------- src/languages/zh-hans.ts | 9 +-------- 9 files changed, 19 insertions(+), 64 deletions(-) diff --git a/src/languages/de.ts b/src/languages/de.ts index d90913c6f848c..06018537498c7 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -6655,14 +6655,7 @@ Fordern Sie Spesendetails wie Belege und Beschreibungen an, legen Sie Limits und defaultRuleTitle: 'Kategorien: Dienste für Erwachsene, Geldautomaten, Glücksspiel, Geldüberweisungen', builtInProtectionModal: { title: 'Expensify Karten bieten integrierten Schutz – jederzeit', - description: `Expensify lehnt diese Belastungen immer ab: - - • Dienstleistungen für Erwachsene - • Geldautomaten (ATMs) - • Glücksspiel - • Geldüberweisungen - -Fügen Sie weitere Ausgabenregeln hinzu, um den Cashflow des Unternehmens zu schützen.`, + description: `Expensify lehnt diese Belastungen immer ab:\n\n • Dienstleistungen für Erwachsene\n • Geldautomaten (ATMs)\n • Glücksspiel\n • Geldüberweisungen\n\nFügen Sie weitere Ausgabenregeln hinzu, um den Cashflow des Unternehmens zu schützen.`, }, }, }, diff --git a/src/languages/es.ts b/src/languages/es.ts index d4a4af81f76b6..16ec399d79e47 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -6540,6 +6540,17 @@ ${amount} para ${merchant} - ${date}`, title: 'Reglas personalizadas', cardSubtitle: 'Aquí es donde se definen las reglas de tu equipo, para que todos sepan lo que esta cubierto.', }, + spendRules: { + title: 'Gastos', + subtitle: 'Aprove o rechaza transacciones del Cartão Expensify en tiempo real.', + defaultRuleDescription: 'Todos los cartões', + block: 'Bloquear', + defaultRuleTitle: 'Categorías: Servicios para adultos, cajeros automáticos, juegos de azar, transferencias de dinero', + builtInProtectionModal: { + title: 'Los Expensify Cards oferecem proteção integrada — sempre', + description: `A Expensify siempre recusa estas cobranças:\n\n • Serviços adultos\n • Caixas eletrônicos (ATMs)\n • Jogos de azar\n • Transferências de dinheiro\n\nAdicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, + }, + }, }, }, getAssistancePage: { diff --git a/src/languages/fr.ts b/src/languages/fr.ts index b95aede46ca71..8ba2a5c0a4bde 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -6679,14 +6679,7 @@ Rendez obligatoires des informations de dépense comme les reçus et les descrip defaultRuleTitle: 'Catégories : services pour adultes, DAB, jeux d’argent, transferts d’argent', builtInProtectionModal: { title: 'Les Cartes Expensify offrent une protection intégrée – en permanence', - description: `Expensify refuse toujours ces types de dépenses : - - • Services pour adultes - • DAB - • Jeux d’argent - • Transferts d’argent - -Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’entreprise.`, + description: `Expensify refuse toujours ces types de dépenses:\n\n • Services pour adultes\n • DAB\n • Jeux d’argent\n • Transferts d’argent\n\nAjoutez davantage de règles de dépenses pour protéger la trésorerie de l’entreprise.`, }, }, }, diff --git a/src/languages/it.ts b/src/languages/it.ts index c43330d90d634..5a32b50f1daa8 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -6642,14 +6642,7 @@ Richiedi dettagli sulle spese come ricevute e descrizioni, imposta limiti e valo defaultRuleTitle: 'Categorie: Servizi per adulti, Bancomat, gioco d’azzardo, trasferimenti di denaro', builtInProtectionModal: { title: 'Le Carte Expensify offrono una protezione integrata, sempre', - description: `Expensify rifiuta sempre queste spese: - - • Servizi per adulti - • Bancomat - • Gioco d’azzardo - • Trasferimenti di denaro - -Aggiungi altre regole di spesa per proteggere il flusso di cassa dell’azienda.`, + description: `Expensify rifiuta sempre queste spese:\n\n • Servizi per adulti\n • Bancomat\n • Gioco d’azzardo\n • Trasferimenti di denaro\n\nAggiungi altre regole di spesa per proteggere il flusso di cassa dell’azienda.`, }, }, }, diff --git a/src/languages/ja.ts b/src/languages/ja.ts index d8e7379ce1595..a536cf9a76a02 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -6568,14 +6568,7 @@ ${reportName} defaultRuleTitle: 'カテゴリ:アダルトサービス、ATM、ギャンブル、送金', builtInProtectionModal: { title: 'Expensify カードは、常に組み込みの保護機能を備えています', - description: `Expensify は常に次の利用を拒否します。 - - ・アダルトサービス - ・ATM - ・ギャンブル - ・送金 - -会社のキャッシュフローを守るために、支出ルールをさらに追加しましょう。`, + description: `Expensify は常に次の利用を拒否します:\n\n ・アダルトサービス\n ・ATM\n ・ギャンブル\n ・送金\n\n会社のキャッシュフローを守るために、支出ルールをさらに追加しましょう。`, }, }, }, diff --git a/src/languages/nl.ts b/src/languages/nl.ts index 924b45830a60d..1fa366f01f3f2 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -6621,14 +6621,7 @@ Vereis onkostendetails zoals bonnen en beschrijvingen, stel limieten en standaar defaultRuleTitle: 'Categorieën: Diensten voor volwassenen, geldautomaten, gokken, geldoverdrachten', builtInProtectionModal: { title: 'Expensify Kaarten bieden altijd ingebouwde bescherming', - description: `Expensify wijst deze transacties altijd af: - - • Seksdiensten - • Geldautomaten (ATM's) - • Gokken - • Geldoverschrijvingen - -Voeg meer bestedingsregels toe om de cashflow van je bedrijf te beschermen.`, + description: `Expensify wijst deze transacties altijd af:\n\n • Seksdiensten\n • Geldautomaten (ATM's)\n • Gokken\n • Geldoverschrijvingen\n\nVoeg meer bestedingsregels toe om de cashflow van je bedrijf te beschermen.`, }, }, }, diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 0577802ac5abc..bc3fc52530b62 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -6616,14 +6616,7 @@ Wymagaj szczegółów wydatków, takich jak paragony i opisy, ustawiaj limity i defaultRuleTitle: 'Kategorie: usługi dla dorosłych, bankomaty, hazard, przelewy pieniężne', builtInProtectionModal: { title: 'Karty Expensify zapewniają wbudowaną ochronę – zawsze', - description: `Expensify zawsze odrzuca te obciążenia: - - • Usługi dla dorosłych - • Bankomaty - • Hazard - • Przelewy pieniężne - -Dodaj więcej zasad wydatków, żeby chronić przepływy pieniężne firmy.`, + description: `Expensify zawsze odrzuca te obciążenia:\n\n • Usługi dla dorosłych\n • Bankomaty\n • Hazard\n • Przelewy pieniężne\n\nDodaj więcej zasad wydatków, żeby chronić przepływy pieniężne firmy.`, }, }, }, diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index efd53c34ba4b5..d7dd66db02fa4 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -6620,14 +6620,7 @@ Exija dados de despesas como recibos e descrições, defina limites e padrões e defaultRuleTitle: 'Categorias: Serviços adultos, caixas eletrônicos, jogos de azar, transferências de dinheiro', builtInProtectionModal: { title: 'Os Cartões Expensify oferecem proteção integrada — sempre', - description: `A Expensify sempre recusa estas cobranças: - - • Serviços adultos - • Caixas eletrônicos (ATMs) - • Jogos de azar - • Transferências de dinheiro - -Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, + description: `A Expensify sempre recusa estas cobranças:\n\n • Serviços adultos\n • Caixas eletrônicos (ATMs)\n • Jogos de azar\n • Transferências de dinheiro\n\nAdicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, }, }, }, diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 20a0343b04714..6487593832d21 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -6456,14 +6456,7 @@ ${reportName} defaultRuleTitle: '类别:成人服务、自动取款机、赌博、转账', builtInProtectionModal: { title: 'Expensify 卡提供始终内置的保护', - description: `Expensify 始终会拒绝以下消费: - - • 成人服务 - • 自动取款机(ATM) - • 赌博 - • 转账汇款 - -添加更多消费规则,保护公司的现金流。`, + description: `Expensify 始终会拒绝以下消费:\n\n • 成人服务\n • 自动取款机(ATM)\n • 赌博\n • 转账汇款\n\n添加更多消费规则,保护公司的现金流。`, }, }, }, From 24c509678149fbd60664801cd84980df529f0d70 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 14:03:21 -0600 Subject: [PATCH 16/27] add illustration --- .../cardProtectionIllustration.svg | 175 ++++++++++++++++++ .../Icon/chunks/illustrations.chunk.ts | 2 + .../rules/SpendRules/SpendRulesSection.tsx | 6 +- 3 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 assets/images/expensifyCard/cardProtectionIllustration.svg diff --git a/assets/images/expensifyCard/cardProtectionIllustration.svg b/assets/images/expensifyCard/cardProtectionIllustration.svg new file mode 100644 index 0000000000000..ae8c6c6671565 --- /dev/null +++ b/assets/images/expensifyCard/cardProtectionIllustration.svg @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/Icon/chunks/illustrations.chunk.ts b/src/components/Icon/chunks/illustrations.chunk.ts index bc0a8e0a784fd..0f34af90475d6 100644 --- a/src/components/Icon/chunks/illustrations.chunk.ts +++ b/src/components/Icon/chunks/illustrations.chunk.ts @@ -38,6 +38,7 @@ import MultiScan from '@assets/images/educational-illustration__multi-scan.svg'; import ExpensifyCardCoins from '@assets/images/emptystate__expensify-card-coins.svg'; import ExpensifyCardImage from '@assets/images/expensify-card.svg'; import ExpensifyCardIllustration from '@assets/images/expensifyCard/cardIllustration.svg'; +import ExpensifyCardProtectionIllustration from '@assets/images/expensifyCard/cardProtectionIllustration.svg'; // Other Images import Hand from '@assets/images/hand.svg'; import LaptopOnDeskWithCoffeeAndKey from '@assets/images/laptop-on-desk-with-coffee-and-key.svg'; @@ -240,6 +241,7 @@ const Illustrations = { // Expensify Card ExpensifyCardIllustration, + ExpensifyCardProtectionIllustration, // Product Illustrations Abracadabra, diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index 1f8d3bfa065fc..a5003ea566d6c 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -23,12 +23,12 @@ function SpendRulesSection() { const {shouldUseNarrowLayout} = useResponsiveLayout(); const expensifyIcons = useMemoizedLazyExpensifyIcons(['Lock']); const {showConfirmModal} = useConfirmModal(); - const illustrations = useMemoizedLazyIllustrations(['ExpensifyCardIllustration']); + const illustrations = useMemoizedLazyIllustrations(['ExpensifyCardProtectionIllustration']); const showBuiltInProtectionModal = () => { showConfirmModal({ - image: illustrations.ExpensifyCardIllustration, - imageStyles: [styles.ph5, styles.pv5], + image: illustrations.ExpensifyCardProtectionIllustration, + imageStyles: [styles.w100], title: translate('workspace.rules.spendRules.builtInProtectionModal.title'), titleStyles: [styles.textHeadlineH1], titleContainerStyles: [styles.mb3], From 82b1bb329b70cb8f256ae626db548b94b3c44efa Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 14:09:17 -0600 Subject: [PATCH 17/27] fit image to container --- src/components/ConfirmContent.tsx | 8 ++++++-- src/components/ConfirmModal.tsx | 5 +++++ .../workspace/rules/SpendRules/SpendRulesSection.tsx | 1 + 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/ConfirmContent.tsx b/src/components/ConfirmContent.tsx index f1720a6216e8f..04cc8b6994b6a 100644 --- a/src/components/ConfirmContent.tsx +++ b/src/components/ConfirmContent.tsx @@ -97,6 +97,9 @@ type ConfirmContentProps = { /** Styles for the image */ imageStyles?: StyleProp; + /** Whether to fit the image to the container */ + shouldFitImageToContainer?: boolean; + /** Whether the modal is visible */ isVisible: boolean; @@ -129,6 +132,7 @@ function ConfirmContent({ shouldShowDismissIcon = false, image, imageStyles, + shouldFitImageToContainer = false, titleContainerStyles, shouldReverseStackedButtons = false, isVisible, @@ -149,8 +153,8 @@ function ConfirmContent({
diff --git a/src/components/ConfirmModal.tsx b/src/components/ConfirmModal.tsx index 5a8e75a1965a6..d85baa8cd0fce 100755 --- a/src/components/ConfirmModal.tsx +++ b/src/components/ConfirmModal.tsx @@ -98,6 +98,9 @@ type ConfirmModalProps = { /** Styles for the image */ imageStyles?: StyleProp; + /** Whether to fit the image to the container */ + shouldFitImageToContainer?: boolean; + /** * Whether the modal should enable the new focus manager. * We are attempting to migrate to a new refocus manager, adding this property for gradual migration. @@ -143,6 +146,7 @@ function ConfirmModal({ onConfirm, image, imageStyles, + shouldFitImageToContainer = false, iconWidth, iconHeight, iconFill, @@ -214,6 +218,7 @@ function ConfirmModal({ shouldReverseStackedButtons={shouldReverseStackedButtons} image={image} imageStyles={imageStyles} + shouldFitImageToContainer={shouldFitImageToContainer} isConfirmLoading={isConfirmLoading} /> diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index a5003ea566d6c..eaeac4364e0ee 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -29,6 +29,7 @@ function SpendRulesSection() { showConfirmModal({ image: illustrations.ExpensifyCardProtectionIllustration, imageStyles: [styles.w100], + shouldFitImageToContainer: true, title: translate('workspace.rules.spendRules.builtInProtectionModal.title'), titleStyles: [styles.textHeadlineH1], titleContainerStyles: [styles.mb3], From 7965f36d879476d7949ab7a24353932e05336b47 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 14:11:22 -0600 Subject: [PATCH 18/27] compress svg --- .../cardProtectionIllustration.svg | 176 +----------------- 1 file changed, 1 insertion(+), 175 deletions(-) diff --git a/assets/images/expensifyCard/cardProtectionIllustration.svg b/assets/images/expensifyCard/cardProtectionIllustration.svg index ae8c6c6671565..fecea99297535 100644 --- a/assets/images/expensifyCard/cardProtectionIllustration.svg +++ b/assets/images/expensifyCard/cardProtectionIllustration.svg @@ -1,175 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + \ No newline at end of file From dd07a74d476bf1ce450027aaff58ee7a9f471159 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Fri, 27 Mar 2026 14:57:46 -0600 Subject: [PATCH 19/27] update es --- src/languages/es.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index 16ec399d79e47..70768b3f2ff7c 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -6542,13 +6542,13 @@ ${amount} para ${merchant} - ${date}`, }, spendRules: { title: 'Gastos', - subtitle: 'Aprove o rechaza transacciones del Cartão Expensify en tiempo real.', - defaultRuleDescription: 'Todos los cartões', + subtitle: 'Apruebe o rechace transacciones con la Tarjeta Expensify en tiempo real.', + defaultRuleDescription: 'Todas las tarjetas', block: 'Bloquear', - defaultRuleTitle: 'Categorías: Servicios para adultos, cajeros automáticos, juegos de azar, transferencias de dinero', + defaultRuleTitle: 'Categorías: servicios para adultos, cajeros automáticos, juegos de azar, transferencias de dinero', builtInProtectionModal: { - title: 'Los Expensify Cards oferecem proteção integrada — sempre', - description: `A Expensify siempre recusa estas cobranças:\n\n • Serviços adultos\n • Caixas eletrônicos (ATMs)\n • Jogos de azar\n • Transferências de dinheiro\n\nAdicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, + title: 'Las tarjetas Expensify incluyen protección integrada: siempre', + description: `Expensify siempre rechaza estos cargos:\n\n • Servicios para adultos\n • Cajeros automáticos\n • Juegos de azar\n • Transferencias de dinero\n\nAñada más reglas de gastos para proteger el flujo de caja de la empresa.`, }, }, }, From c600f7bf33b6811e21f4ca14a45fbccfda53b09f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Mon, 30 Mar 2026 17:08:52 -0600 Subject: [PATCH 20/27] update es translations --- src/languages/en.ts | 2 +- src/languages/es.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 8946f7b430853..029ad7d3d8ff1 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -6656,7 +6656,7 @@ const translations = { }, spendRules: { title: 'Spend', - subtitle: 'Approve or decline Expensify Card transactions in real time.', + subtitle: 'Approve or decline Expensify Card transactions in realtime.', defaultRuleDescription: 'All cards', block: 'Block', defaultRuleTitle: 'Categories: Adult services, ATMs, gambling, money transfers', diff --git a/src/languages/es.ts b/src/languages/es.ts index 5aa191bc1e2d6..ef60cefca4abb 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -6571,13 +6571,13 @@ ${amount} para ${merchant} - ${date}`, }, spendRules: { title: 'Gastos', - subtitle: 'Apruebe o rechace transacciones con la Tarjeta Expensify en tiempo real.', + subtitle: 'Apruebe o rechace transacciones de la tarjeta Expensify en tiempo real.', defaultRuleDescription: 'Todas las tarjetas', block: 'Bloquear', - defaultRuleTitle: 'Categorías: servicios para adultos, cajeros automáticos, juegos de azar, transferencias de dinero', + defaultRuleTitle: 'Categorías: Servicios para adultos, cajeros automáticos, juegos de azar, transferencias de dinero', builtInProtectionModal: { - title: 'Las tarjetas Expensify incluyen protección integrada: siempre', - description: `Expensify siempre rechaza estos cargos:\n\n • Servicios para adultos\n • Cajeros automáticos\n • Juegos de azar\n • Transferencias de dinero\n\nAñada más reglas de gastos para proteger el flujo de caja de la empresa.`, + title: 'Las tarjetas Expensify ofrecen protección integrada, siempre', + description: `Expensify siempre rechaza estos cargos:\n\n • Servicios para adultos\n • Cajeros automáticos\n • Juegos de azar\n • Transferencias de dinero\n\nAgregue más reglas de gasto para proteger el flujo de caja de la empresa.`, }, }, }, From 3f523218795c40350f17d172bb05d8c7c4daa389 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 31 Mar 2026 09:29:31 -0600 Subject: [PATCH 21/27] rm bold text style --- src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index eaeac4364e0ee..6e597fa9c0af3 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -81,7 +81,7 @@ function SpendRulesSection() { isCondensed /> From 0222d8167a893c501074e897d3fbe19ad5f2f123 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 31 Mar 2026 09:30:16 -0600 Subject: [PATCH 22/27] rm badge border --- src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index 6e597fa9c0af3..941d8de376855 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -76,7 +76,7 @@ function SpendRulesSection() { From 9fc6980e3fc22f9aeb6d076d00ea983e3c23528e Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 31 Mar 2026 09:48:16 -0600 Subject: [PATCH 23/27] update copy --- src/languages/de.ts | 15 +++++++++++---- src/languages/fr.ts | 11 +++++++++-- src/languages/it.ts | 13 ++++++++++--- src/languages/ja.ts | 11 +++++++++-- src/languages/nl.ts | 13 ++++++++++--- src/languages/pl.ts | 13 ++++++++++--- src/languages/pt-BR.ts | 9 ++++++++- src/languages/zh-hans.ts | 13 ++++++++++--- 8 files changed, 77 insertions(+), 21 deletions(-) diff --git a/src/languages/de.ts b/src/languages/de.ts index 490a8fddc3ec9..188abc0f135fa 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -6707,13 +6707,20 @@ Fordern Sie Spesendetails wie Belege und Beschreibungen an, legen Sie Limits und }, spendRules: { title: 'Ausgaben', - subtitle: 'Genehmigen oder lehnen Sie Expensify Karten-Transaktionen in Echtzeit ab.', + subtitle: 'Genehmigen oder lehnen Sie Expensify Karte-Transaktionen in Echtzeit ab.', defaultRuleDescription: 'Alle Karten', - block: 'Block', - defaultRuleTitle: 'Kategorien: Dienste für Erwachsene, Geldautomaten, Glücksspiel, Geldüberweisungen', + block: 'Blockieren', + defaultRuleTitle: 'Kategorien: Erotikdienstleistungen, Geldautomaten, Glücksspiele, Geldüberweisungen', builtInProtectionModal: { title: 'Expensify Karten bieten integrierten Schutz – jederzeit', - description: `Expensify lehnt diese Belastungen immer ab:\n\n • Dienstleistungen für Erwachsene\n • Geldautomaten (ATMs)\n • Glücksspiel\n • Geldüberweisungen\n\nFügen Sie weitere Ausgabenregeln hinzu, um den Cashflow des Unternehmens zu schützen.`, + description: `Expensify lehnt diese Belastungen immer ab: + + • Erwachsenenservices + • Geldautomaten + • Glücksspiel + • Geldüberweisungen + +Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu schützen.`, }, }, }, diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 9f5d57d4ea506..c2cdb8824a4ba 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -6735,8 +6735,15 @@ Rendez obligatoires des informations de dépense comme les reçus et les descrip block: 'Bloquer', defaultRuleTitle: 'Catégories : services pour adultes, DAB, jeux d’argent, transferts d’argent', builtInProtectionModal: { - title: 'Les Cartes Expensify offrent une protection intégrée – en permanence', - description: `Expensify refuse toujours ces types de dépenses:\n\n • Services pour adultes\n • DAB\n • Jeux d’argent\n • Transferts d’argent\n\nAjoutez davantage de règles de dépenses pour protéger la trésorerie de l’entreprise.`, + title: 'Les Cartes Expensify offrent une protection intégrée – en permanence', + description: `Expensify refuse toujours ces dépenses : + + • Services pour adultes + • DAB + • Jeux d’argent + • Transferts d’argent + +Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’entreprise.`, }, }, }, diff --git a/src/languages/it.ts b/src/languages/it.ts index def611311c62f..9b66dddbc865e 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -6696,10 +6696,17 @@ Richiedi dettagli sulle spese come ricevute e descrizioni, imposta limiti e valo subtitle: 'Approva o rifiuta le transazioni della Carta Expensify in tempo reale.', defaultRuleDescription: 'Tutte le carte', block: 'Blocca', - defaultRuleTitle: 'Categorie: Servizi per adulti, Bancomat, gioco d’azzardo, trasferimenti di denaro', + defaultRuleTitle: 'Categorie: servizi per adulti, sportelli bancomat, gioco d’azzardo, trasferimenti di denaro', builtInProtectionModal: { - title: 'Le Carte Expensify offrono una protezione integrata, sempre', - description: `Expensify rifiuta sempre queste spese:\n\n • Servizi per adulti\n • Bancomat\n • Gioco d’azzardo\n • Trasferimenti di denaro\n\nAggiungi altre regole di spesa per proteggere il flusso di cassa dell’azienda.`, + title: 'Le Carte Expensify offrono sempre una protezione integrata', + description: `Expensify rifiuta sempre questi addebiti: + + • Servizi per adulti + • Bancomat + • Gioco d’azzardo + • Trasferimenti di denaro + +Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`, }, }, }, diff --git a/src/languages/ja.ts b/src/languages/ja.ts index f47de4329431e..86b71e85951a1 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -6624,8 +6624,15 @@ ${reportName} block: 'ブロック', defaultRuleTitle: 'カテゴリ:アダルトサービス、ATM、ギャンブル、送金', builtInProtectionModal: { - title: 'Expensify カードは、常に組み込みの保護機能を備えています', - description: `Expensify は常に次の利用を拒否します:\n\n ・アダルトサービス\n ・ATM\n ・ギャンブル\n ・送金\n\n会社のキャッシュフローを守るために、支出ルールをさらに追加しましょう。`, + title: 'Expensify カードには、常に標準で保護機能があります', + description: `Expensify は、次のような支払いを常に拒否します: + + ・アダルトサービス + ・ATM + ・ギャンブル + ・送金 + +会社のキャッシュフローを守るために、支出ルールをさらに追加しましょう。`, }, }, }, diff --git a/src/languages/nl.ts b/src/languages/nl.ts index c0a5793b015cc..60385f41e8620 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -6673,13 +6673,20 @@ Vereis onkostendetails zoals bonnen en beschrijvingen, stel limieten en standaar }, spendRules: { title: 'Uitgaven', - subtitle: 'Keur transacties met de Expensify Kaart in realtime goed of wijs ze af.', + subtitle: 'Keur Expensify Kaart-transacties in realtime goed of af.', defaultRuleDescription: 'Alle kaarten', block: 'Blokkeren', - defaultRuleTitle: 'Categorieën: Diensten voor volwassenen, geldautomaten, gokken, geldoverdrachten', + defaultRuleTitle: 'Categorieën: diensten voor volwassenen, geldautomaten, gokken, geldoverdrachten', builtInProtectionModal: { title: 'Expensify Kaarten bieden altijd ingebouwde bescherming', - description: `Expensify wijst deze transacties altijd af:\n\n • Seksdiensten\n • Geldautomaten (ATM's)\n • Gokken\n • Geldoverschrijvingen\n\nVoeg meer bestedingsregels toe om de cashflow van je bedrijf te beschermen.`, + description: `Expensify weigert deze uitgaven altijd: + + • Services voor volwassenen + • Geldautomaten (ATM's) + • Gokken + • Geldoverschrijvingen + +Voeg meer bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`, }, }, }, diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 3ac3402701e1f..3338a013920eb 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -6666,13 +6666,20 @@ Wymagaj szczegółów wydatków, takich jak paragony i opisy, ustawiaj limity i }, spendRules: { title: 'Wydatki', - subtitle: 'Zatwierdzaj lub odrzucaj transakcje Kartą Expensify w czasie rzeczywistym.', + subtitle: 'Zatwierdzaj lub odrzucaj transakcje Karty Expensify w czasie rzeczywistym.', defaultRuleDescription: 'Wszystkie karty', block: 'Zablokuj', - defaultRuleTitle: 'Kategorie: usługi dla dorosłych, bankomaty, hazard, przelewy pieniężne', + defaultRuleTitle: 'Kategorie: Usługi dla dorosłych, bankomaty, hazard, przelewy pieniężne', builtInProtectionModal: { title: 'Karty Expensify zapewniają wbudowaną ochronę – zawsze', - description: `Expensify zawsze odrzuca te obciążenia:\n\n • Usługi dla dorosłych\n • Bankomaty\n • Hazard\n • Przelewy pieniężne\n\nDodaj więcej zasad wydatków, żeby chronić przepływy pieniężne firmy.`, + description: `Expensify zawsze odrzuca te obciążenia: + + • Usługi dla dorosłych + • Bankomaty + • Hazard + • Przelewy pieniężne + +Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`, }, }, }, diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 0415050f01486..a11fd86a0d46f 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -6677,7 +6677,14 @@ Exija dados de despesas como recibos e descrições, defina limites e padrões e defaultRuleTitle: 'Categorias: Serviços adultos, caixas eletrônicos, jogos de azar, transferências de dinheiro', builtInProtectionModal: { title: 'Os Cartões Expensify oferecem proteção integrada — sempre', - description: `A Expensify sempre recusa estas cobranças:\n\n • Serviços adultos\n • Caixas eletrônicos (ATMs)\n • Jogos de azar\n • Transferências de dinheiro\n\nAdicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, + description: `A Expensify sempre recusa estas cobranças: + + • Serviços adultos + • Caixas eletrônicos (ATM) + • Jogos de azar + • Transferências de dinheiro + +Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`, }, }, }, diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 2c3b315145f19..0fdb5a5368936 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -6509,10 +6509,17 @@ ${reportName} subtitle: '实时批准或拒绝 Expensify 卡交易。', defaultRuleDescription: '所有卡片', block: '屏蔽', - defaultRuleTitle: '类别:成人服务、自动取款机、赌博、转账', + defaultRuleTitle: '类别:成人服务、ATM、赌博、转账', builtInProtectionModal: { - title: 'Expensify 卡提供始终内置的保护', - description: `Expensify 始终会拒绝以下消费:\n\n • 成人服务\n • 自动取款机(ATM)\n • 赌博\n • 转账汇款\n\n添加更多消费规则,保护公司的现金流。`, + title: 'Expensify 卡始终提供内置保护', + description: `Expensify 始终会拒绝以下消费: + + • 成人服务 + • ATM + • 赌博 + • 转账 + +添加更多消费规则以保护公司现金流。`, }, }, }, From 123e1b1b317a299cda9c64101bb8246bf6435093 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 31 Mar 2026 09:59:55 -0600 Subject: [PATCH 24/27] invert text --- .../rules/SpendRules/SpendRulesSection.tsx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx index 941d8de376855..388a3ed66390e 100644 --- a/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx +++ b/src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx @@ -59,20 +59,6 @@ function SpendRulesSection() { const menuItemBody = ( - - - - {descriptionLabel} - - + + + + {descriptionLabel} + + ); From ffc758f337e56df5c8c2571f00b402e9a9a3f69e Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 31 Mar 2026 14:34:01 -0600 Subject: [PATCH 25/27] adjust gap --- src/pages/workspace/rules/MerchantRulesSection.tsx | 2 +- src/pages/workspace/rules/SpendRules/SpendRulesSection.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/rules/MerchantRulesSection.tsx b/src/pages/workspace/rules/MerchantRulesSection.tsx index 2659c648e29c2..2079c3c7ffca1 100644 --- a/src/pages/workspace/rules/MerchantRulesSection.tsx +++ b/src/pages/workspace/rules/MerchantRulesSection.tsx @@ -102,7 +102,7 @@ function MerchantRulesSection({policyID}: MerchantRulesSectionProps) { }, [codingRules]); const renderTitle = () => ( - + {translate('workspace.rules.merchantRules.title')} ( - + {translate('workspace.rules.spendRules.title')} Date: Wed, 1 Apr 2026 14:13:37 -0600 Subject: [PATCH 26/27] fix modal --- src/components/ConfirmContent.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/ConfirmContent.tsx b/src/components/ConfirmContent.tsx index 8edfb27ab814e..e00a6024fe1a5 100644 --- a/src/components/ConfirmContent.tsx +++ b/src/components/ConfirmContent.tsx @@ -151,10 +151,11 @@ function ConfirmContent({ {!!image && ( From 3e12f167a1be65b518572aacadd26767da46a9ff Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 1 Apr 2026 15:50:55 -0600 Subject: [PATCH 27/27] Update src/languages/es.ts Co-authored-by: Carlos Alvarez --- src/languages/es.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/languages/es.ts b/src/languages/es.ts index dcca5f882c7ac..cc39a3af505cd 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -6622,7 +6622,7 @@ ${amount} para ${merchant} - ${date}`, }, spendRules: { title: 'Gastos', - subtitle: 'Apruebe o rechace transacciones de la tarjeta Expensify en tiempo real.', + subtitle: 'Aprueba o rechaza transacciones de la tarjeta Expensify en tiempo real.', defaultRuleDescription: 'Todas las tarjetas', block: 'Bloquear', defaultRuleTitle: 'Categorías: Servicios para adultos, cajeros automáticos, juegos de azar, transferencias de dinero',