Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ function WorkspaceExpenseDefaultsTableRow({item, rowIndex, shouldUseNarrowTableL
const showSectionHeader = hasMultipleSections && (rowIndex === 0 || !!prevItem?.isMerchantType !== !!item.isMerchantType);

const lockIcon = item.isMerchantType ? (
<Tooltip text={translate('common.locked')}>
<Tooltip text={translate('workspace.rules.spendRules.defaultRulesCannotBeDeleted')}>
<View>
<Icon
src={Expensicons.Lock}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function WorkspaceSpendRulesTableRow({item, rowIndex, shouldUseNarrowTableLayout
const showSectionHeader = hasMultipleTypes && (rowIndex === 0 || !!prevItem?.isDefault !== !!item.isDefault);

const lockIcon = item.isDefault ? (
<Tooltip text={translate('common.locked')}>
<Tooltip text={translate('workspace.rules.spendRules.defaultRulesCannotBeDeleted')}>
<View>
<Icon
src={Expensicons.Lock}
Expand Down
1 change: 1 addition & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7939,6 +7939,7 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
'Gebühren werden genehmigt, wenn sie in zulässigen Währungen erfolgen und einen Höchstbetrag nicht überschreiten oder wenn das Geschäft bzw. die Geschäftsart übereinstimmt.',
summaryCurrencies: ({currencies, hiddenCount, shownCount}: {currencies: string; hiddenCount: number; shownCount: number}) =>
`Erlaubt ${shownCount > 1 ? 'Währungen' : 'Währung'}: ${currencies}${hiddenCount > 0 ? `, +${hiddenCount} weitere` : ''}`,
defaultRulesCannotBeDeleted: 'Standardregeln können nicht gelöscht werden',
},
agentRules: {
title: 'Agentenregeln',
Expand Down
1 change: 1 addition & 0 deletions src/languages/el.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8347,6 +8347,7 @@ ${reportName}`,
[CONST.SPEND_RULES.CATEGORIES.TRANSIT_AND_RIDESHARE]: 'Δημόσιες συγκοινωνίες και υπηρεσίες κοινής μετακίνησης',
[CONST.SPEND_RULES.CATEGORIES.TRAVEL_AGENCIES]: 'Ταξιδιωτικά πρακτορεία',
},
defaultRulesCannotBeDeleted: 'Οι προεπιλεγμένοι κανόνες δεν μπορούν να διαγραφούν',
},
agentRules: {
title: 'Κανόνες αντιπροσώπου',
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8137,6 +8137,7 @@ const translations = {
findRule: 'Find rule',
defaultSection: 'Default',
customRulesSection: 'Custom rules',
defaultRulesCannotBeDeleted: 'Default rules cannot be deleted',
Comment thread
Krishna2323 marked this conversation as resolved.
tableColumnType: 'Type',
tableColumnCard: 'Card',
tableColumnRule: 'Rule',
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7882,6 +7882,7 @@ El plan Controlar empieza en 9 $ por miembro activo al mes.`,
restrictMerchantsBlockSubtitle: 'Los cargos se aprueban para monedas permitidas que no superen un importe máximo, o cuando el comercio o el tipo de comercio coinciden.',
summaryCurrencies: ({currencies, hiddenCount, shownCount}: {currencies: string; hiddenCount: number; shownCount: number}) =>
`Permitido ${shownCount > 1 ? 'divisas' : 'moneda'}: ${currencies}${hiddenCount > 0 ? `, +${hiddenCount} más` : ''}`,
defaultRulesCannotBeDeleted: 'Las reglas predeterminadas no se pueden eliminar',
},
agentRules: {
title: 'Reglas del agente',
Expand Down
1 change: 1 addition & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7964,6 +7964,7 @@ Ajoutez davantage de règles de dépenses pour protéger la trésorerie de l’e
'Les dépenses sont approuvées pour les devises autorisées qui ne dépassent pas un montant maximal, ou lorsque le commerçant ou le type de commerçant correspond.',
summaryCurrencies: ({currencies, hiddenCount, shownCount}: {currencies: string; hiddenCount: number; shownCount: number}) =>
`Autorisé ${shownCount > 1 ? 'devises' : 'devise'} : ${currencies}${hiddenCount > 0 ? `, +${hiddenCount} de plus` : ''}`,
defaultRulesCannotBeDeleted: 'Les règles par défaut ne peuvent pas être supprimées',
},
agentRules: {
title: 'Règles d’agent',
Expand Down
1 change: 1 addition & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7908,6 +7908,7 @@ Aggiungi altre regole di spesa per proteggere il flusso di cassa aziendale.`,
'Gli addebiti vengono approvati per le valute consentite che non superano un importo massimo oppure quando l’esercente o il tipo di esercente corrispondono.',
summaryCurrencies: ({currencies, hiddenCount, shownCount}: {currencies: string; hiddenCount: number; shownCount: number}) =>
`Consentito ${shownCount > 1 ? 'valute' : 'valuta'}: ${currencies}${hiddenCount > 0 ? `, +${hiddenCount} altri` : ''}`,
defaultRulesCannotBeDeleted: 'Le regole predefinite non possono essere eliminate',
},
agentRules: {
title: 'Regole agente',
Expand Down
1 change: 1 addition & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7809,6 +7809,7 @@ ${reportName}`,
restrictMerchantsBlockSubtitle: '承認される支出は、許可された通貨で上限金額を超えないもの、または加盟店または加盟店の種類が条件に一致するものです。',
summaryCurrencies: ({currencies, hiddenCount, shownCount}: {currencies: string; hiddenCount: number; shownCount: number}) =>
`許可された ${shownCount > 1 ? '通貨' : '通貨'}:${currencies}${hiddenCount > 0 ? `、ほか +${hiddenCount} 件` : ''}`,
defaultRulesCannotBeDeleted: '既定のルールは削除できません',
},
agentRules: {
title: 'エージェントルール',
Expand Down
1 change: 1 addition & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7886,6 +7886,7 @@ er bestedingsregels toe om de kasstroom van het bedrijf te beschermen.`,
'Kosten worden goedgekeurd voor toegestane valuta’s die een maximumbedrag niet overschrijden, of wanneer de handelaar of het handelaarstype overeenkomt.',
summaryCurrencies: ({currencies, hiddenCount, shownCount}: {currencies: string; hiddenCount: number; shownCount: number}) =>
`Toegestaan ${shownCount > 1 ? 'valuta’s' : 'valuta'}: ${currencies}${hiddenCount > 0 ? `, +${hiddenCount} meer` : ''}`,
defaultRulesCannotBeDeleted: 'Standaardregels kunnen niet worden verwijderd',
},
agentRules: {
title: 'Agentregels',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7867,6 +7867,7 @@ Dodaj więcej zasad wydatków, żeby chronić płynność finansową firmy.`,
restrictMerchantsBlockSubtitle: 'Obciążenia są zatwierdzane dla dozwolonych walut, które nie przekraczają maksymalnej kwoty, lub gdy pasuje sprzedawca albo typ sprzedawcy.',
summaryCurrencies: ({currencies, hiddenCount, shownCount}: {currencies: string; hiddenCount: number; shownCount: number}) =>
`Dozwolone ${shownCount > 1 ? 'waluty' : 'waluta'}: ${currencies}${hiddenCount > 0 ? `, +${hiddenCount} więcej` : ''}`,
defaultRulesCannotBeDeleted: 'Domyślnych reguł nie można usunąć',
},
agentRules: {
title: 'Zasady agenta',
Expand Down
1 change: 1 addition & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7888,6 +7888,7 @@ Adicione mais regras de gasto para proteger o fluxo de caixa da empresa.`,
'As cobranças são aprovadas para moedas permitidas que não ultrapassem um valor máximo ou quando o comerciante ou o tipo de comerciante correspondem.',
summaryCurrencies: ({currencies, hiddenCount, shownCount}: {currencies: string; hiddenCount: number; shownCount: number}) =>
`Permitido ${shownCount > 1 ? 'moedas' : 'moeda'}: ${currencies}${hiddenCount > 0 ? `, +${hiddenCount} mais` : ''}`,
defaultRulesCannotBeDeleted: 'Regras padrão não podem ser excluídas',
},
agentRules: {
title: 'Regras do agente',
Expand Down
1 change: 1 addition & 0 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7622,6 +7622,7 @@ ${reportName}`,
restrictMerchantsBlockSubtitle: '对于允许的币种中,若消费金额未超过最高限额,或商户或商户类型匹配,则该笔消费将被批准。',
summaryCurrencies: ({currencies, hiddenCount, shownCount}: {currencies: string; hiddenCount: number; shownCount: number}) =>
`已允许 ${shownCount > 1 ? '货币' : '货币'}:${currencies}${hiddenCount > 0 ? `,还有 +${hiddenCount} 项` : ''}`,
defaultRulesCannotBeDeleted: '默认规则无法删除',
},
agentRules: {
title: '代理规则',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Text from '@components/Text';

import useDynamicBackPath from '@hooks/useDynamicBackPath';
import useLocalize from '@hooks/useLocalize';
import usePermissions from '@hooks/usePermissions';
import usePolicyData from '@hooks/usePolicyData';
import useThemeStyles from '@hooks/useThemeStyles';

Expand Down Expand Up @@ -43,6 +44,8 @@ function DynamicWorkspaceCategoriesSettingsPage({policy, route}: DynamicWorkspac
const {policyID} = route.params;
const styles = useThemeStyles();
const {translate} = useLocalize();
const {isBetaEnabled} = usePermissions();
const isRulesRevampEnabled = isBetaEnabled(CONST.BETAS.RULES_REVAMP);
const policyData = usePolicyData(policyID);
const isConnectedToAccounting = Object.keys(policy?.connections ?? {}).length > 0;
const currentConnectionName = getCurrentAccountingIntegrationName(policy, translate);
Expand Down Expand Up @@ -80,6 +83,9 @@ function DynamicWorkspaceCategoriesSettingsPage({policy, route}: DynamicWorkspac
const hasEnabledCategories = hasEnabledOptions(policyData.categories);
const isToggleDisabled = !policy?.areCategoriesEnabled || !hasEnabledCategories || isConnectedToAccounting;

// Under the revamp only the GL codes toggle is left here, so the page has nothing to show without it.
const shouldBlockEmptySettings = isRulesRevampEnabled && !policy?.glCodes;

const onSelectItem = (item: ListItem) => {
if (!item.groupID) {
return;
Expand All @@ -105,6 +111,7 @@ function DynamicWorkspaceCategoriesSettingsPage({policy, route}: DynamicWorkspac
policyID={policyID}
accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN, CONST.POLICY.ACCESS_VARIANTS.PAID]}
featureName={CONST.POLICY.MORE_FEATURES.ARE_CATEGORIES_ENABLED}
shouldBeBlocked={shouldBlockEmptySettings}
>
<ScreenWrapper
enableEdgeToEdgeBottomSafeAreaPadding
Expand All @@ -116,19 +123,21 @@ function DynamicWorkspaceCategoriesSettingsPage({policy, route}: DynamicWorkspac
onBackButtonPress={() => Navigation.goBack(isQuickSettingsFlow ? backPath : undefined)}
/>
<ScrollView contentContainerStyle={[styles.flexGrow1]}>
<ToggleSettingOptionRow
title={translate('workspace.categories.requiresCategory')}
subtitle={toggleSubtitle}
switchAccessibilityLabel={translate('workspace.categories.requiresCategory')}
isActive={policy?.requiresCategory ?? false}
onToggle={updateWorkspaceRequiresCategory}
pendingAction={policy?.pendingFields?.requiresCategory}
disabled={isToggleDisabled}
wrapperStyle={[styles.pv2, styles.mh5]}
errors={policy?.errorFields?.requiresCategory ?? undefined}
onCloseError={() => clearPolicyErrorField(policy?.id, 'requiresCategory')}
shouldPlaceSubtitleBelowSwitch
/>
{!isRulesRevampEnabled && (
<ToggleSettingOptionRow
title={translate('workspace.categories.requiresCategory')}
subtitle={toggleSubtitle}
switchAccessibilityLabel={translate('workspace.categories.requiresCategory')}
isActive={policy?.requiresCategory ?? false}
onToggle={updateWorkspaceRequiresCategory}
pendingAction={policy?.pendingFields?.requiresCategory}
disabled={isToggleDisabled}
wrapperStyle={[styles.pv2, styles.mh5]}
errors={policy?.errorFields?.requiresCategory ?? undefined}
onCloseError={() => clearPolicyErrorField(policy?.id, 'requiresCategory')}
shouldPlaceSubtitleBelowSwitch
/>
)}
{!!policy?.glCodes && (
<ToggleSettingOptionRow
title={translate('workspace.categories.showCategoryGLCodes')}
Expand All @@ -142,18 +151,23 @@ function DynamicWorkspaceCategoriesSettingsPage({policy, route}: DynamicWorkspac
onCloseError={() => clearPolicyErrorField(policy?.id, 'showCategoryGLCodes')}
/>
)}
<View style={[styles.sectionDividerLine, styles.mh5, styles.mv6]} />
<View style={[styles.containerWithSpaceBetween]}>
{!!policyData.policy && (data?.length ?? 0) > 0 && (
<SelectionList
addBottomSafeAreaPadding
customListHeaderContent={selectionListHeaderContent}
data={data}
ListItem={SpendCategorySelectorListItem}
onSelectRow={onSelectItem}
/>
)}
</View>
{/* Default spend categories moved to Rules > Expense defaults, so they'd be a second source of truth here. */}
{!isRulesRevampEnabled && (
<>
<View style={[styles.sectionDividerLine, styles.mh5, styles.mv6]} />
<View style={[styles.containerWithSpaceBetween]}>
{!!policyData.policy && (data?.length ?? 0) > 0 && (
<SelectionList
addBottomSafeAreaPadding
customListHeaderContent={selectionListHeaderContent}
data={data}
ListItem={SpendCategorySelectorListItem}
onSelectRow={onSelectItem}
/>
)}
</View>
</>
)}
</ScrollView>
</ScreenWrapper>
</AccessOrNotFoundWrapper>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,8 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) {

const secondaryActions = useMemo(() => {
const menuItems = [];
if (canWriteCategories && !isRulesRevampEnabled) {
// Under the revamp the other settings moved to Rules, so this is only worth showing for the GL codes toggle.
if (canWriteCategories && (!isRulesRevampEnabled || !!policy?.glCodes)) {
menuItems.push({
icon: icons.Gear,
text: translate('common.settings'),
Expand Down Expand Up @@ -412,6 +413,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) {
navigateToCategoriesSettings,
canWriteCategories,
isRulesRevampEnabled,
policy?.glCodes,
policyHasAccountingConnections,
hasVisibleCategories,
navigateToImportSpreadsheet,
Expand Down
13 changes: 9 additions & 4 deletions src/pages/workspace/tags/WorkspaceTagsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,12 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
const {canWrite: canWriteTags, showReadOnlyModal} = usePolicyFeatureWriteAccess(policy, CONST.POLICY.POLICY_FEATURE.TAGS);
const {isBetaEnabled} = usePermissions();
const isRulesRevampEnabled = isBetaEnabled(CONST.BETAS.RULES_REVAMP);
const shouldShowTagsSettings = canWriteTags && !(isRulesRevampEnabled && isMultiLevelTags);
const canSelectMultiple = canWriteTags && !hasDependentTags && (shouldUseNarrowLayout ? isMobileSelectionModeEnabled : true);
// The revamp moves the multi-level tag settings to Rules, but the GL codes toggle stays here and needs a way in.
const shouldShowTagsSettings = canWriteTags && (!(isRulesRevampEnabled && isMultiLevelTags) || !!policy?.glCodes);
// Multi-level tag rows only ever offered the Required bulk actions, and those moved to Rules, so selecting them
// would open a dropdown with nothing in it.
const isSelectionEnabled = canWriteTags && !hasDependentTags && !(isRulesRevampEnabled && isMultiLevelTags);
const canSelectMultiple = isSelectionEnabled && (shouldUseNarrowLayout ? isMobileSelectionModeEnabled : true);
const isControlPolicyWithWideLayout = !shouldUseNarrowLayout && isControlPolicy(policy);
const tagApproverEmails = useMemo(() => {
const approverEmails: Record<string, string> = {};
Expand Down Expand Up @@ -569,7 +573,8 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
const selectedTagsObject = selectedTagKeys.map((key) => policyTagLists.at(0)?.tags?.[key]);
const selectedTagLists = selectedTagKeys.map((selectedTag) => policyTagLists.find((policyTagList) => policyTagList.name === selectedTag));

if (!canWriteTags || (shouldUseNarrowLayout ? !isMobileSelectionModeEnabled : selectedTagKeys.length === 0)) {
// Without selection there are no bulk actions, so keep the normal header even if selection mode lingered from elsewhere.
if (!canWriteTags || !isSelectionEnabled || (shouldUseNarrowLayout ? !isMobileSelectionModeEnabled : selectedTagKeys.length === 0)) {
const hasPrimaryActions = canWriteTags && !hasAccountingConnections && !isMultiLevelTags && hasVisibleTags;
return (
<View style={[styles.flexRow, styles.gap2, shouldDisplayButtonsInSeparateLine && styles.mb3]}>
Expand Down Expand Up @@ -878,7 +883,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {

<WorkspaceTagsTable
tags={tagRows}
selectionEnabled={canWriteTags && !hasDependentTags}
selectionEnabled={isSelectionEnabled}
selectedKeys={selectedTagKeys}
isMultiLevelTags={isMultiLevelTags}
hasDependentTags={hasDependentTags}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/workspace/tags/WorkspaceTagsSettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function WorkspaceTagsSettingsPage({route}: WorkspaceTagsSettingsPageProps) {
);
const isQuickSettingsFlow = route.name === SCREENS.SETTINGS_TAGS.DYNAMIC_SETTINGS_TAGS_SETTINGS;
const backPath = useDynamicBackPath(DYNAMIC_ROUTES.SETTINGS_TAGS_SETTINGS.path);
const shouldBlockEmptySettings = isRulesRevampEnabled && isMultiLevelTags && !isLoading;
const shouldBlockEmptySettings = isRulesRevampEnabled && isMultiLevelTags && !isLoading && !policyData.policy?.glCodes;

const getTagsSettings = (policy: OnyxEntry<Policy>) => {
const updateShowTagGLCodes = (value: boolean) => {
Expand Down
Loading