diff --git a/src/languages/de.ts b/src/languages/de.ts index 549ee4755bf9..af5c04a6363b 100644 --- a/src/languages/de.ts +++ b/src/languages/de.ts @@ -9156,6 +9156,9 @@ Hier ist ein *Testbeleg*, um dir zu zeigen, wie es funktioniert:`, `Möchtest du ${newName} wirklich zur Standardgruppe machen? Neue Mitglieder werden zu dieser Gruppe anstelle der bisherigen Standardgruppe (${currentName}) eingeladen. `, makeDefault: 'Als Standard festlegen', neverMind: 'Vergiss es', + permissions: 'Gruppenberechtigungen', + StrictlyEnforceWorkspaceRules: 'Workspace-Regeln strikt durchsetzen', + StrictlyEnforceWorkspaceRulesDescription: 'Alle Workspace-Regeln müssen erfüllt sein, bevor ein Bericht eingereicht wird. Manuelle Ausnahmen sind nicht zulässig.', }, }, proactiveAppReview: { diff --git a/src/languages/en.ts b/src/languages/en.ts index 4c299d6f7ebe..ecce86ebdf3d 100644 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -9147,6 +9147,9 @@ const translations = { `Are you sure you want to make ${newName} the default group? New members will be invited to this group instead of the previous default group (${currentName}). `, makeDefault: 'Make default', neverMind: 'Never mind', + permissions: 'Group permissions', + StrictlyEnforceWorkspaceRules: 'Strictly enforce workspace rules', + StrictlyEnforceWorkspaceRulesDescription: 'All workspace rules must be met before submitting a report. No manual exceptions allowed.', }, }, }; diff --git a/src/languages/es.ts b/src/languages/es.ts index b139108bd470..284f9f507b5a 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -9378,6 +9378,9 @@ ${amount} para ${merchant} - ${date}`, `¿Estás seguro de que quieres establecer ${newName} como el grupo predeterminado? Los nuevos miembros serán invitados a este grupo en lugar del grupo predeterminado anterior (${currentName}). `, makeDefault: 'Establecer como predeterminado', neverMind: 'No importa', + permissions: 'Permisos de grupo', + StrictlyEnforceWorkspaceRules: 'Hacer cumplir estrictamente las reglas del espacio de trabajo', + StrictlyEnforceWorkspaceRulesDescription: 'Todas las reglas del espacio de trabajo deben cumplirse antes de enviar un informe. No se permiten excepciones manuales.', }, }, gps: { diff --git a/src/languages/fr.ts b/src/languages/fr.ts index 68425ca27457..07711b488bc2 100644 --- a/src/languages/fr.ts +++ b/src/languages/fr.ts @@ -9179,6 +9179,10 @@ Voici un *reçu test* pour vous montrer comment ça fonctionne :`, `Êtes-vous sûr de vouloir faire de ${newName} le groupe par défaut ? Les nouveaux membres seront invités à ce groupe au lieu du groupe par défaut précédent (${currentName}). `, makeDefault: 'Définir par défaut', neverMind: 'Peu importe', + permissions: 'Autorisations du groupe', + StrictlyEnforceWorkspaceRules: 'Appliquer strictement les règles de l’espace de travail', + StrictlyEnforceWorkspaceRulesDescription: + 'Toutes les règles de l’espace de travail doivent être respectées avant de soumettre un rapport. Aucune exception manuelle n’est autorisée.', }, }, proactiveAppReview: { diff --git a/src/languages/it.ts b/src/languages/it.ts index b871b5ed5359..64fae0abf953 100644 --- a/src/languages/it.ts +++ b/src/languages/it.ts @@ -9146,6 +9146,9 @@ Ecco una *ricevuta di prova* per mostrarti come funziona:`, `Sei sicuro di voler impostare ${newName} come gruppo predefinito? I nuovi membri verranno invitati a questo gruppo invece del precedente gruppo predefinito (${currentName}). `, makeDefault: 'Imposta come predefinito', neverMind: 'Lascia perdere', + permissions: 'Autorizzazioni del gruppo', + StrictlyEnforceWorkspaceRules: 'Applica rigorosamente le regole dello spazio di lavoro', + StrictlyEnforceWorkspaceRulesDescription: 'Tutte le regole dello spazio di lavoro devono essere soddisfatte prima di inviare un rapporto. Non sono consentite eccezioni manuali.', }, }, proactiveAppReview: { diff --git a/src/languages/ja.ts b/src/languages/ja.ts index 06ee398b3e2a..d94dd48c7a25 100644 --- a/src/languages/ja.ts +++ b/src/languages/ja.ts @@ -9032,6 +9032,9 @@ ${reportName} `本当に ${newName} をデフォルトグループに設定しますか?新しいメンバーは、以前のデフォルトグループ (${currentName}) ではなく、このグループに招待されます。`, makeDefault: 'デフォルトに設定', neverMind: 'やめておく', + permissions: 'グループの権限', + StrictlyEnforceWorkspaceRules: 'ワークスペースのルールを厳密に適用する', + StrictlyEnforceWorkspaceRulesDescription: 'レポートを送信する前にすべてのワークスペースのルールを満たす必要があります。手動による例外は許可されていません。', }, }, proactiveAppReview: { diff --git a/src/languages/nl.ts b/src/languages/nl.ts index ddbb615bd528..137ca2f2b70a 100644 --- a/src/languages/nl.ts +++ b/src/languages/nl.ts @@ -9118,6 +9118,10 @@ Hier is een *proefbon* om je te laten zien hoe het werkt:`, `Weet je zeker dat je ${newName} de standaardgroep wilt maken? Nieuwe leden worden uitgenodigd voor deze groep in plaats van de vorige standaardgroep (${currentName}). `, makeDefault: 'Standaard maken', neverMind: 'Laat maar', + permissions: 'Groepsmachtigingen', + StrictlyEnforceWorkspaceRules: 'Werkruimteregels strikt afdwingen', + StrictlyEnforceWorkspaceRulesDescription: + 'Aan alle werkruimteregels moet worden voldaan voordat een rapport kan worden ingediend. Handmatige uitzonderingen zijn niet toegestaan.', }, }, proactiveAppReview: { diff --git a/src/languages/pl.ts b/src/languages/pl.ts index 39ce739e8621..6b727dd3261d 100644 --- a/src/languages/pl.ts +++ b/src/languages/pl.ts @@ -9100,6 +9100,9 @@ Oto *paragon testowy*, żeby pokazać Ci, jak to działa:`, `Czy na pewno chcesz ustawić ${newName} jako grupę domyślną? Nowi członkowie będą zapraszani do tej grupy zamiast do poprzedniej grupy domyślnej (${currentName}). `, makeDefault: 'Ustaw jako domyślną', neverMind: 'Nieważne', + permissions: 'Uprawnienia grupy', + StrictlyEnforceWorkspaceRules: 'Ściśle egzekwuj reguły przestrzeni roboczej', + StrictlyEnforceWorkspaceRulesDescription: 'Przed przesłaniem raportu muszą zostać spełnione wszystkie reguły przestrzeni roboczej. Ręczne wyjątki są niedozwolone.', }, }, proactiveAppReview: { diff --git a/src/languages/pt-BR.ts b/src/languages/pt-BR.ts index 0baa2105761f..575cfd614628 100644 --- a/src/languages/pt-BR.ts +++ b/src/languages/pt-BR.ts @@ -9108,6 +9108,9 @@ Aqui está um *comprovante de teste* para mostrar como funciona:`, `Tem certeza de que deseja tornar ${newName} o grupo padrão? Novos membros serão convidados para este grupo em vez do grupo padrão anterior (${currentName}). `, makeDefault: 'Tornar padrão', neverMind: 'Deixa pra lá', + permissions: 'Permissões do grupo', + StrictlyEnforceWorkspaceRules: 'Aplicar rigorosamente as regras do espaço de trabalho', + StrictlyEnforceWorkspaceRulesDescription: 'Todas as regras do espaço de trabalho devem ser atendidas antes de enviar um relatório. Não são permitidas exceções manuais.', }, }, proactiveAppReview: { diff --git a/src/languages/zh-hans.ts b/src/languages/zh-hans.ts index 8fd1bf1de791..5c25689a1ee3 100644 --- a/src/languages/zh-hans.ts +++ b/src/languages/zh-hans.ts @@ -8873,6 +8873,9 @@ ${reportName} defaultGroupPrompt: (currentName: string, newName: string) => `您确定要将 ${newName} 设为默认群组吗?新成员将被邀请加入此群组,而不是之前的默认群组(${currentName})。`, makeDefault: '设为默认', neverMind: '算了', + permissions: '群组权限', + StrictlyEnforceWorkspaceRules: '严格执行工作空间规则', + StrictlyEnforceWorkspaceRulesDescription: '提交报告前必须满足所有工作空间规则。不允许手动例外。', }, }, proactiveAppReview: {title: '喜欢全新的 Expensify 吗?', description: '请告诉我们,这样我们就能帮助您让报销体验变得更好。', positiveButton: '太棒了!', negativeButton: '不太是'}, diff --git a/src/libs/actions/Domain.ts b/src/libs/actions/Domain.ts index e03700d10987..b049782c89fd 100644 --- a/src/libs/actions/Domain.ts +++ b/src/libs/actions/Domain.ts @@ -1836,7 +1836,7 @@ function updateDomainSecurityGroup( groupID: string, currentSecurityGroup: DomainSecurityGroup, newSettingValue: Partial, - settingsName: keyof Pick, + settingsName: keyof Pick, ) { const SECURITY_GROUP_KEY = `${CONST.DOMAIN.DOMAIN_SECURITY_GROUP_PREFIX}${groupID}`; const newSecurityGroup = {...currentSecurityGroup, ...newSettingValue}; @@ -1879,9 +1879,9 @@ function updateDomainSecurityGroup( key: `${ONYXKEYS.COLLECTION.DOMAIN}${domainAccountID}`, value: { [SECURITY_GROUP_KEY]: { - [settingsName]: currentSecurityGroup[settingsName], + [settingsName]: currentSecurityGroup[settingsName] ?? null, }, - } as PrefixedRecord, + } as PrefixedRecord>, }, { onyxMethod: Onyx.METHOD.MERGE, diff --git a/src/pages/domain/Groups/DomainGroupDetailsPage.tsx b/src/pages/domain/Groups/DomainGroupDetailsPage.tsx index cab0998abfb0..c0384685c577 100644 --- a/src/pages/domain/Groups/DomainGroupDetailsPage.tsx +++ b/src/pages/domain/Groups/DomainGroupDetailsPage.tsx @@ -1,10 +1,12 @@ import {domainSecurityGroupSettingErrorsSelector, domainSecurityGroupSettingPendingActionSelector, selectGroupByID} from '@selectors/Domain'; import React from 'react'; +import {View} from 'react-native'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import OfflineWithFeedback from '@components/OfflineWithFeedback'; import ScreenWrapper from '@components/ScreenWrapper'; import ScrollView from '@components/ScrollView'; +import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -17,14 +19,15 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import DefaultGroupToggle from './DefaultGroupToggle'; +import StrictlyEnforceWorkspaceRulesToggle from './StrictlyEnforceWorkspaceRulesToggle'; type DomainGroupDetailsPageProps = PlatformStackScreenProps; function DomainGroupDetailsPage({route}: DomainGroupDetailsPageProps) { + const styles = useThemeStyles(); const {domainAccountID, groupID} = route.params; const {translate} = useLocalize(); - const styles = useThemeStyles(); const [group] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN}${domainAccountID}`, { selector: selectGroupByID(groupID), @@ -62,6 +65,12 @@ function DomainGroupDetailsPage({route}: DomainGroupDetailsPageProps) { groupID={groupID} groupName={group?.name} /> + + {translate('domain.groups.permissions')} + diff --git a/src/pages/domain/Groups/StrictlyEnforceWorkspaceRulesToggle.tsx b/src/pages/domain/Groups/StrictlyEnforceWorkspaceRulesToggle.tsx new file mode 100644 index 000000000000..02eeee68e264 --- /dev/null +++ b/src/pages/domain/Groups/StrictlyEnforceWorkspaceRulesToggle.tsx @@ -0,0 +1,56 @@ +import {domainSecurityGroupSettingErrorsSelector, domainSecurityGroupSettingPendingActionSelector, selectGroupByID} from '@selectors/Domain'; +import React from 'react'; +import {View} from 'react-native'; +import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; +import useThemeStyles from '@hooks/useThemeStyles'; +import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow'; +import {clearDomainSecurityGroupSettingError, updateDomainSecurityGroup} from '@userActions/Domain'; +import ONYXKEYS from '@src/ONYXKEYS'; + +type StrictlyEnforceWorkspaceRulesToggleProps = { + domainAccountID: number; + groupID: string; +}; + +function StrictlyEnforceWorkspaceRulesToggle({domainAccountID, groupID}: StrictlyEnforceWorkspaceRulesToggleProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const [group] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN}${domainAccountID}`, { + selector: selectGroupByID(groupID), + }); + + const [enableStrictPolicyRulesPendingAction] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN_PENDING_ACTIONS}${domainAccountID}`, { + selector: domainSecurityGroupSettingPendingActionSelector('enableStrictPolicyRules', groupID), + }); + const [enableStrictPolicyRulesErrors] = useOnyx(`${ONYXKEYS.COLLECTION.DOMAIN_ERRORS}${domainAccountID}`, { + selector: domainSecurityGroupSettingErrorsSelector('enableStrictPolicyRulesErrors', groupID), + }); + + const isEnabled = !!group?.enableStrictPolicyRules; + + return ( + + { + if (!group) { + return; + } + updateDomainSecurityGroup(domainAccountID, groupID, group, {enableStrictPolicyRules: enabled}, 'enableStrictPolicyRules'); + }} + wrapperStyle={[styles.ph5]} + pendingAction={enableStrictPolicyRulesPendingAction} + errors={enableStrictPolicyRulesErrors} + onCloseError={() => clearDomainSecurityGroupSettingError(domainAccountID, groupID, 'enableStrictPolicyRulesErrors')} + /> + + ); +} + +export default StrictlyEnforceWorkspaceRulesToggle; diff --git a/src/types/onyx/DomainErrors.ts b/src/types/onyx/DomainErrors.ts index f319734f2996..fa5c41552269 100644 --- a/src/types/onyx/DomainErrors.ts +++ b/src/types/onyx/DomainErrors.ts @@ -49,6 +49,11 @@ type DomainSecurityGroupErrors = { * Errors related to the default security group ID setting */ defaultSecurityGroupIDErrors?: OnyxCommon.Errors; + + /** + * Errors related to the strictly enforce workspace rules setting + */ + enableStrictPolicyRulesErrors?: OnyxCommon.Errors; }; /** diff --git a/src/types/onyx/DomainPendingActions.ts b/src/types/onyx/DomainPendingActions.ts index 567578bcce85..d2598277f869 100644 --- a/src/types/onyx/DomainPendingActions.ts +++ b/src/types/onyx/DomainPendingActions.ts @@ -45,6 +45,11 @@ type DomainSecurityGroupPendingActions = { */ name?: OnyxCommon.PendingAction; + /** + * Pending action for the strictly enforce workspace rules setting + */ + enableStrictPolicyRules?: OnyxCommon.PendingAction; + /** * Pending action for the default security group ID */