Skip to content

Commit

Permalink
Merge pull request #52778 from FitseTLT/fix-showing-workspace-rbr-for…
Browse files Browse the repository at this point in the history
…-non-admin

Fix - Getting RBR for a workspace connection sync on a workspace I’m not an admin of
  • Loading branch information
puneetlath authored Nov 25, 2024
2 parents e55847a + 631f908 commit 0354bae
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 55 deletions.
8 changes: 4 additions & 4 deletions src/hooks/useIndicatorStatus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ function useIndicatorStatus(): IndicatorStatusResult {
const cleanPolicies = useMemo(() => Object.fromEntries(Object.entries(policies ?? {}).filter(([, policy]) => policy?.id)), [policies]);

const policyErrors = {
[CONST.INDICATOR_STATUS.HAS_POLICY_ERRORS]: Object.values(cleanPolicies).find(PolicyUtils.hasPolicyError),
[CONST.INDICATOR_STATUS.HAS_CUSTOM_UNITS_ERROR]: Object.values(cleanPolicies).find(PolicyUtils.hasCustomUnitsError),
[CONST.INDICATOR_STATUS.HAS_EMPLOYEE_LIST_ERROR]: Object.values(cleanPolicies).find(PolicyUtils.hasEmployeeListError),
[CONST.INDICATOR_STATUS.HAS_POLICY_ERRORS]: Object.values(cleanPolicies).find(PolicyUtils.shouldShowPolicyError),
[CONST.INDICATOR_STATUS.HAS_CUSTOM_UNITS_ERROR]: Object.values(cleanPolicies).find(PolicyUtils.shouldShowCustomUnitsError),
[CONST.INDICATOR_STATUS.HAS_EMPLOYEE_LIST_ERROR]: Object.values(cleanPolicies).find(PolicyUtils.shouldShowEmployeeListError),
[CONST.INDICATOR_STATUS.HAS_SYNC_ERRORS]: Object.values(cleanPolicies).find((cleanPolicy) =>
PolicyUtils.hasSyncError(
PolicyUtils.shouldShowSyncError(
cleanPolicy,
isConnectionInProgress(allConnectionSyncProgresses?.[`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${cleanPolicy?.id}`], cleanPolicy),
),
Expand Down
50 changes: 26 additions & 24 deletions src/libs/PolicyUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,26 @@ function getActivePolicies(policies: OnyxCollection<Policy> | null): Policy[] {
(policy): policy is Policy => !!policy && policy.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && !!policy.name && !!policy.id,
);
}
/**
* Checks if the current user is an admin of the policy.
*/
const isPolicyAdmin = (policy: OnyxInputOrEntry<Policy> | SearchPolicy, currentUserLogin?: string): boolean => getPolicyRole(policy, currentUserLogin) === CONST.POLICY.ROLE.ADMIN;

/**
* Checks if we have any errors stored within the policy?.employeeList. Determines whether we should show a red brick road error or not.
*/
function hasEmployeeListError(policy: OnyxEntry<Policy>): boolean {
return Object.values(policy?.employeeList ?? {}).some((employee) => Object.keys(employee?.errors ?? {}).length > 0);
function shouldShowEmployeeListError(policy: OnyxEntry<Policy>): boolean {
return isPolicyAdmin(policy) && Object.values(policy?.employeeList ?? {}).some((employee) => Object.keys(employee?.errors ?? {}).length > 0);
}

/**
* Check if the policy has any tax rate errors.
*/
function hasTaxRateError(policy: OnyxEntry<Policy>): boolean {
return Object.values(policy?.taxRates?.taxes ?? {}).some((taxRate) => Object.keys(taxRate?.errors ?? {}).length > 0 || Object.values(taxRate?.errorFields ?? {}).some(Boolean));
function shouldShowTaxRateError(policy: OnyxEntry<Policy>): boolean {
return (
isPolicyAdmin(policy) &&
Object.values(policy?.taxRates?.taxes ?? {}).some((taxRate) => Object.keys(taxRate?.errors ?? {}).length > 0 || Object.values(taxRate?.errorFields ?? {}).some(Boolean))
);
}

/**
Expand All @@ -101,29 +108,29 @@ function hasPolicyCategoriesError(policyCategories: OnyxEntry<PolicyCategories>)
/**
* Checks if the policy had a sync error.
*/
function hasSyncError(policy: OnyxEntry<Policy>, isSyncInProgress: boolean): boolean {
return (Object.keys(policy?.connections ?? {}) as ConnectionName[]).some((connection) => !!hasSynchronizationErrorMessage(policy, connection, isSyncInProgress));
function shouldShowSyncError(policy: OnyxEntry<Policy>, isSyncInProgress: boolean): boolean {
return isPolicyAdmin(policy) && (Object.keys(policy?.connections ?? {}) as ConnectionName[]).some((connection) => !!hasSynchronizationErrorMessage(policy, connection, isSyncInProgress));
}

/**
* Check if the policy has any error fields.
*/
function hasPolicyErrorFields(policy: OnyxEntry<Policy>): boolean {
return Object.values(policy?.errorFields ?? {}).some((fieldErrors) => Object.keys(fieldErrors ?? {}).length > 0);
function shouldShowPolicyErrorFields(policy: OnyxEntry<Policy>): boolean {
return isPolicyAdmin(policy) && Object.values(policy?.errorFields ?? {}).some((fieldErrors) => Object.keys(fieldErrors ?? {}).length > 0);
}

/**
* Check if the policy has any errors, and if it doesn't, then check if it has any error fields.
*/
function hasPolicyError(policy: OnyxEntry<Policy>): boolean {
return Object.keys(policy?.errors ?? {}).length > 0 ? true : hasPolicyErrorFields(policy);
function shouldShowPolicyError(policy: OnyxEntry<Policy>): boolean {
return Object.keys(policy?.errors ?? {}).length > 0 ? isPolicyAdmin(policy) : shouldShowPolicyErrorFields(policy);
}

/**
* Checks if we have any errors stored within the policy custom units.
*/
function hasCustomUnitsError(policy: OnyxEntry<Policy>): boolean {
return Object.keys(policy?.customUnits?.errors ?? {}).length > 0;
function shouldShowCustomUnitsError(policy: OnyxEntry<Policy>): boolean {
return isPolicyAdmin(policy) && Object.keys(policy?.customUnits?.errors ?? {}).length > 0;
}

function getNumericValue(value: number | string, toLocaleDigit: (arg: string) => string): number | string {
Expand Down Expand Up @@ -181,7 +188,7 @@ function getUnitRateValue(toLocaleDigit: (arg: string) => string, customUnitRate
* Get the brick road indicator status for a policy. The policy has an error status if there is a policy member error, a custom unit error or a field error.
*/
function getPolicyBrickRoadIndicatorStatus(policy: OnyxEntry<Policy>, isConnectionInProgress: boolean): ValueOf<typeof CONST.BRICK_ROAD_INDICATOR_STATUS> | undefined {
if (hasEmployeeListError(policy) || hasCustomUnitsError(policy) || hasPolicyErrorFields(policy) || hasSyncError(policy, isConnectionInProgress)) {
if (shouldShowEmployeeListError(policy) || shouldShowCustomUnitsError(policy) || shouldShowPolicyErrorFields(policy) || shouldShowSyncError(policy, isConnectionInProgress)) {
return CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR;
}
return undefined;
Expand Down Expand Up @@ -218,11 +225,6 @@ function isExpensifyTeam(email: string | undefined): boolean {
*/
const isUserPolicyAdmin = (policy: OnyxInputOrEntry<Policy>, login?: string) => !!(policy && policy.employeeList && login && policy.employeeList[login]?.role === CONST.POLICY.ROLE.ADMIN);

/**
* Checks if the current user is an admin of the policy.
*/
const isPolicyAdmin = (policy: OnyxInputOrEntry<Policy> | SearchPolicy, currentUserLogin?: string): boolean => getPolicyRole(policy, currentUserLogin) === CONST.POLICY.ROLE.ADMIN;

/**
* Checks if the current user is of the role "user" on the policy.
*/
Expand Down Expand Up @@ -1151,15 +1153,15 @@ export {
getRateDisplayValue,
goBackFromInvalidPolicy,
hasAccountingConnections,
hasSyncError,
shouldShowSyncError,
hasPolicyFeedsError,
hasCustomUnitsError,
hasEmployeeListError,
shouldShowCustomUnitsError,
shouldShowEmployeeListError,
hasIntegrationAutoSync,
hasPolicyCategoriesError,
hasPolicyError,
hasPolicyErrorFields,
hasTaxRateError,
shouldShowPolicyError,
shouldShowPolicyErrorFields,
shouldShowTaxRateError,
isControlOnAdvancedApprovalMode,
isExpensifyTeam,
isDeletedPolicyEmployee,
Expand Down
28 changes: 17 additions & 11 deletions src/libs/WorkspacesSettingsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {Beta, Policy, PriorityMode, ReimbursementAccount, Report, ReportAct
import type {PolicyConnectionSyncProgress, Unit} from '@src/types/onyx/Policy';
import {isConnectionInProgress} from './actions/connections';
import * as CurrencyUtils from './CurrencyUtils';
import {hasCustomUnitsError, hasEmployeeListError, hasPolicyError, hasSyncError, hasTaxRateError} from './PolicyUtils';
import {isPolicyAdmin, shouldShowCustomUnitsError, shouldShowEmployeeListError, shouldShowPolicyError, shouldShowSyncError, shouldShowTaxRateError} from './PolicyUtils';
import * as ReportActionsUtils from './ReportActionsUtils';
import * as ReportUtils from './ReportUtils';
import SidebarUtils from './SidebarUtils';
Expand Down Expand Up @@ -102,25 +102,31 @@ function hasGlobalWorkspaceSettingsRBR(policies: OnyxCollection<Policy>, allConn
const cleanPolicies = Object.fromEntries(Object.entries(policies ?? {}).filter(([, policy]) => policy?.id));

const errorCheckingMethods: CheckingMethod[] = [
() => Object.values(cleanPolicies).some(hasPolicyError),
() => Object.values(cleanPolicies).some(hasCustomUnitsError),
() => Object.values(cleanPolicies).some(hasTaxRateError),
() => Object.values(cleanPolicies).some(hasEmployeeListError),
() => Object.values(cleanPolicies).some(shouldShowPolicyError),
() => Object.values(cleanPolicies).some(shouldShowCustomUnitsError),
() => Object.values(cleanPolicies).some(shouldShowTaxRateError),
() => Object.values(cleanPolicies).some(shouldShowEmployeeListError),
() =>
Object.values(cleanPolicies).some((cleanPolicy) =>
hasSyncError(cleanPolicy, isConnectionInProgress(allConnectionProgresses?.[`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${cleanPolicy?.id}`], cleanPolicy)),
shouldShowSyncError(cleanPolicy, isConnectionInProgress(allConnectionProgresses?.[`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${cleanPolicy?.id}`], cleanPolicy)),
),
() => Object.keys(reimbursementAccount?.errors ?? {}).length > 0,
() => Object.values(cleanPolicies).some((cleanPolicy) => isPolicyAdmin(cleanPolicy) && Object.keys(reimbursementAccount?.errors ?? {}).length > 0),
];

return errorCheckingMethods.some((errorCheckingMethod) => errorCheckingMethod());
}

function hasWorkspaceSettingsRBR(policy: Policy) {
const policyMemberError = hasEmployeeListError(policy);
const taxRateError = hasTaxRateError(policy);

return Object.keys(reimbursementAccount?.errors ?? {}).length > 0 || hasPolicyError(policy) || hasCustomUnitsError(policy) || policyMemberError || taxRateError;
const policyMemberError = shouldShowEmployeeListError(policy);
const taxRateError = shouldShowTaxRateError(policy);

return (
(isPolicyAdmin(policy) && Object.keys(reimbursementAccount?.errors ?? {}).length > 0) ||
shouldShowPolicyError(policy) ||
shouldShowCustomUnitsError(policy) ||
policyMemberError ||
taxRateError
);
}

function getChatTabBrickRoadReport(
Expand Down
6 changes: 3 additions & 3 deletions src/pages/workspace/WorkspaceInitialPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac
const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`);
const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.email});
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${route.params?.policyID ?? '-1'}`);
const hasSyncError = PolicyUtils.hasSyncError(policy, isConnectionInProgress(connectionSyncProgress, policy));
const hasSyncError = PolicyUtils.shouldShowSyncError(policy, isConnectionInProgress(connectionSyncProgress, policy));
const waitForNavigate = useWaitForNavigation();
const {singleExecution, isExecuting} = useSingleExecution();
const activeRoute = useNavigationState(getTopmostRouteName);
Expand Down Expand Up @@ -152,7 +152,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac
ReimbursementAccount.navigateToBankAccountRoute(policyID);
}, [policyID, policyName]);

const hasMembersError = PolicyUtils.hasEmployeeListError(policy);
const hasMembersError = PolicyUtils.shouldShowEmployeeListError(policy);
const hasPolicyCategoryError = PolicyUtils.hasPolicyCategoriesError(policyCategories);
const hasGeneralSettingsError =
!isEmptyObject(policy?.errorFields?.name ?? {}) ||
Expand Down Expand Up @@ -286,7 +286,7 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac
icon: Expensicons.Coins,
action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_TAXES.getRoute(policyID)))),
routeName: SCREENS.WORKSPACE.TAXES,
brickRoadIndicator: PolicyUtils.hasTaxRateError(policy) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
brickRoadIndicator: PolicyUtils.shouldShowTaxRateError(policy) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
});
}

Expand Down
13 changes: 7 additions & 6 deletions src/pages/workspace/WorkspacesListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -344,12 +344,13 @@ function WorkspacesListPage() {
title: policy.name,
icon: policy.avatarURL ? policy.avatarURL : ReportUtils.getDefaultWorkspaceAvatar(policy.name),
action: () => Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policy.id)),
brickRoadIndicator:
reimbursementAccountBrickRoadIndicator ??
PolicyUtils.getPolicyBrickRoadIndicatorStatus(
policy,
isConnectionInProgress(allConnectionSyncProgresses?.[`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy.id}`], policy),
),
brickRoadIndicator: !PolicyUtils.isPolicyAdmin(policy)
? undefined
: reimbursementAccountBrickRoadIndicator ??
PolicyUtils.getPolicyBrickRoadIndicatorStatus(
policy,
isConnectionInProgress(allConnectionSyncProgresses?.[`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy.id}`], policy),
),
pendingAction: policy.pendingAction,
errors: policy.errors,
dismissError: () => dismissWorkspaceError(policy.id, policy.pendingAction),
Expand Down
2 changes: 1 addition & 1 deletion src/pages/workspace/accounting/PolicyAccountingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ function PolicyAccountingPage({policy}: PolicyAccountingPageProps) {
connectedIntegration === connectionSyncProgress?.connectionName ? connectionSyncProgress : undefined,
);

const hasSyncError = PolicyUtils.hasSyncError(policy, isSyncInProgress);
const hasSyncError = PolicyUtils.shouldShowSyncError(policy, isSyncInProgress);
const hasUnsupportedNDIntegration = !isEmptyObject(policy?.connections) && PolicyUtils.hasUnsupportedIntegration(policy, accountingIntegrations);

const tenants = useMemo(() => getXeroTenants(policy), [policy]);
Expand Down
2 changes: 1 addition & 1 deletion src/pages/workspace/categories/WorkspaceCategoriesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function WorkspaceCategoriesPage({route}: WorkspaceCategoriesPageProps) {
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyId}`);
const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`);
const isSyncInProgress = isConnectionInProgress(connectionSyncProgress, policy);
const hasSyncError = PolicyUtils.hasSyncError(policy, isSyncInProgress);
const hasSyncError = PolicyUtils.shouldShowSyncError(policy, isSyncInProgress);
const isConnectedToAccounting = Object.keys(policy?.connections ?? {}).length > 0;
const currentConnectionName = PolicyUtils.getCurrentConnectionName(policy);
const isQuickSettingsFlow = !!backTo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ function WorkspaceReportFieldsPage({
const hasAccountingConnections = PolicyUtils.hasAccountingConnections(policy);
const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`);
const isSyncInProgress = isConnectionInProgress(connectionSyncProgress, policy);
const hasSyncError = PolicyUtils.hasSyncError(policy, isSyncInProgress);
const hasSyncError = PolicyUtils.shouldShowSyncError(policy, isSyncInProgress);
const isConnectedToAccounting = Object.keys(policy?.connections ?? {}).length > 0;
const currentConnectionName = PolicyUtils.getCurrentConnectionName(policy);

Expand Down
2 changes: 1 addition & 1 deletion src/pages/workspace/tags/WorkspaceTagsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
const {environmentURL} = useEnvironment();
const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`);
const isSyncInProgress = isConnectionInProgress(connectionSyncProgress, policy);
const hasSyncError = PolicyUtils.hasSyncError(policy, isSyncInProgress);
const hasSyncError = PolicyUtils.shouldShowSyncError(policy, isSyncInProgress);
const isConnectedToAccounting = Object.keys(policy?.connections ?? {}).length > 0;
const currentConnectionName = PolicyUtils.getCurrentConnectionName(policy);
const [policyTagLists, isMultiLevelTags] = useMemo(() => [PolicyUtils.getTagLists(policyTags), PolicyUtils.isMultiLevelTags(policyTags)], [policyTags]);
Expand Down
2 changes: 1 addition & 1 deletion src/pages/workspace/taxes/WorkspaceTaxesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ function WorkspaceTaxesPage({
const hasAccountingConnections = PolicyUtils.hasAccountingConnections(policy);
const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`);
const isSyncInProgress = isConnectionInProgress(connectionSyncProgress, policy);
const hasSyncError = PolicyUtils.hasSyncError(policy, isSyncInProgress);
const hasSyncError = PolicyUtils.shouldShowSyncError(policy, isSyncInProgress);

const isConnectedToAccounting = Object.keys(policy?.connections ?? {}).length > 0;
const currentConnectionName = PolicyUtils.getCurrentConnectionName(policy);
Expand Down
Loading

0 comments on commit 0354bae

Please sign in to comment.