Skip to content

Commit df26892

Browse files
authored
Merge pull request #87737 from nkdengineer/revert-87675-revert-85746-fix/83130
fix: Offline deleted rules reappear after reconnecting until cache is cleared v2
2 parents 45531d7 + ad64277 commit df26892

6 files changed

Lines changed: 132 additions & 66 deletions

File tree

src/libs/PolicyUtils.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -323,10 +323,27 @@ function getCustomUnitsForDuplication(
323323
return undefined;
324324
}
325325

326-
if (isDistanceRatesOptionSelected && isPerDiemOptionSelected) {
327-
const distanceCustomUnit = Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
328-
const perDiemUnit = Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_PER_DIEM_INTERNATIONAL);
326+
const getUnitWithoutPendingDeleteRates = (customUnit: CustomUnit | undefined, customUnitID: string) => {
327+
if (!customUnit) {
328+
return undefined;
329+
}
330+
return {
331+
...customUnit,
332+
customUnitID,
333+
rates: Object.fromEntries(Object.entries(customUnit.rates).filter(([, rate]) => rate.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE)),
334+
};
335+
};
329336

337+
const distanceCustomUnit = getUnitWithoutPendingDeleteRates(
338+
Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE),
339+
distanceCustomUnitID,
340+
);
341+
const perDiemUnit = getUnitWithoutPendingDeleteRates(
342+
Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_PER_DIEM_INTERNATIONAL),
343+
perDiemCustomUnitID,
344+
);
345+
346+
if (isDistanceRatesOptionSelected && isPerDiemOptionSelected) {
330347
if (!perDiemUnit || !distanceCustomUnit || !perDiemCustomUnitID || !distanceCustomUnitID) {
331348
return undefined;
332349
}
@@ -335,14 +352,12 @@ function getCustomUnitsForDuplication(
335352
}
336353

337354
if (isDistanceRatesOptionSelected && distanceCustomUnitID) {
338-
const distanceCustomUnit = Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
339355
if (!distanceCustomUnit) {
340356
return undefined;
341357
}
342358
return {[distanceCustomUnitID]: distanceCustomUnit};
343359
}
344360

345-
const perDiemUnit = Object.values(customUnits).find((customUnit) => customUnit.name === CONST.CUSTOM_UNITS.NAME_PER_DIEM_INTERNATIONAL);
346361
if (!perDiemUnit || !perDiemCustomUnitID) {
347362
return undefined;
348363
}

src/libs/ReportUtils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4528,7 +4528,7 @@ function getReportFieldKey(reportFieldId: string | undefined) {
45284528
/**
45294529
* Get the report fields attached to the policy given policyID
45304530
*/
4531-
function getReportFieldsByPolicyID(policyID: string | undefined): Record<string, PolicyReportField> {
4531+
function getReportFieldsByPolicyID(policyID: string | undefined): Policy['fieldList'] {
45324532
if (!policyID) {
45334533
return {};
45344534
}

src/libs/actions/Policy/Category.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ function appendSetupCategoriesOnboardingData(
106106
function buildOptimisticPolicyWithExistingCategories(policyID: string, categories: PolicyCategories) {
107107
const categoriesValues = Object.values(categories);
108108
const optimisticCategoryMap = categoriesValues.reduce<Record<string, Partial<PolicyCategory>>>((acc, category) => {
109+
if (category.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE) {
110+
return acc;
111+
}
109112
acc[category.name] = {
110113
...category,
111114
errors: null,

src/libs/actions/Policy/Policy.ts

Lines changed: 93 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3092,6 +3092,98 @@ function createDraftWorkspace({
30923092
return params;
30933093
}
30943094

3095+
function buildOptimisticDuplicatePolicy(sourcePolicy: Policy, policyOptions: DuplicatePolicyDataOptions & {distanceCustomUnitID: string; perDiemCustomUnitID: string}) {
3096+
const {
3097+
policyName: duplicatedPolicyName = '',
3098+
targetPolicyID: duplicatedPolicyID,
3099+
file: duplicatedPolicyFile,
3100+
parts: duplicatedParts,
3101+
localCurrency: duplicatedLocalCurrency,
3102+
distanceCustomUnitID: duplicatedDistanceCustomUnitID,
3103+
perDiemCustomUnitID: duplicatedPerDiemCustomUnitID,
3104+
} = policyOptions;
3105+
3106+
const isMemberFeatureSelected = duplicatedParts?.people;
3107+
const isReportsFeatureSelected = duplicatedParts?.reports;
3108+
const isConnectionsFeatureSelected = duplicatedParts?.connections;
3109+
const isTaxesFeatureSelected = duplicatedParts?.taxes;
3110+
const isTagsFeatureSelected = duplicatedParts?.tags;
3111+
const isInvoicesFeatureSelected = duplicatedParts?.invoices;
3112+
const isDistanceRatesFeatureSelected = duplicatedParts?.distance;
3113+
const isRulesFeatureSelected = duplicatedParts?.expenses;
3114+
const isWorkflowsFeatureSelected = duplicatedParts?.exportLayouts;
3115+
const isPerDiemFeatureSelected = duplicatedParts?.perDiem;
3116+
const isOverviewFeatureSelected = duplicatedParts?.overview;
3117+
const isTravelFeatureSelected = duplicatedParts?.travel;
3118+
const isCodingRulesFeatureSelected = duplicatedParts?.codingRules;
3119+
const duplicatedOutputCurrency = isOverviewFeatureSelected ? sourcePolicy?.outputCurrency : duplicatedLocalCurrency;
3120+
3121+
const filterPendingDeleteData = <T>(data?: Record<string, T>): Record<string, T> | undefined =>
3122+
data
3123+
? (Object.fromEntries(
3124+
Object.entries(data).filter(([, value]) => {
3125+
if (!value || typeof value !== 'object' || !('pendingAction' in value)) {
3126+
return true;
3127+
}
3128+
return value.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
3129+
}),
3130+
) as Record<string, T>)
3131+
: undefined;
3132+
3133+
const codingRulesWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.rules?.codingRules);
3134+
const employeeListWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.employeeList);
3135+
const fieldListWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.fieldList);
3136+
const connectionsWithoutPendingDelete = filterPendingDeleteData(sourcePolicy?.connections);
3137+
const taxRatesWithoutPendingDelete = {
3138+
...sourcePolicy?.taxRates,
3139+
taxes: filterPendingDeleteData(sourcePolicy?.taxRates?.taxes),
3140+
};
3141+
3142+
return {
3143+
...sourcePolicy,
3144+
areCategoriesEnabled: true,
3145+
areTagsEnabled: isTagsFeatureSelected,
3146+
areDistanceRatesEnabled: isDistanceRatesFeatureSelected,
3147+
areInvoicesEnabled: isInvoicesFeatureSelected,
3148+
areRulesEnabled: isRulesFeatureSelected,
3149+
areWorkflowsEnabled: isWorkflowsFeatureSelected,
3150+
areReportFieldsEnabled: isReportsFeatureSelected,
3151+
areConnectionsEnabled: isConnectionsFeatureSelected,
3152+
arePerDiemRatesEnabled: isPerDiemFeatureSelected,
3153+
isTravelEnabled: isTravelFeatureSelected ? sourcePolicy?.isTravelEnabled : undefined,
3154+
travelSettings: undefined,
3155+
workspaceAccountID: undefined,
3156+
tax: isTaxesFeatureSelected ? sourcePolicy?.tax : undefined,
3157+
employeeList: isMemberFeatureSelected ? employeeListWithoutPendingDelete : {[sourcePolicy.owner]: sourcePolicy?.employeeList?.[sourcePolicy.owner]},
3158+
id: duplicatedPolicyID,
3159+
name: duplicatedPolicyName,
3160+
fieldList: isReportsFeatureSelected ? fieldListWithoutPendingDelete : undefined,
3161+
connections: isConnectionsFeatureSelected ? connectionsWithoutPendingDelete : undefined,
3162+
customUnits: getCustomUnitsForDuplication(sourcePolicy, isDistanceRatesFeatureSelected, isPerDiemFeatureSelected, {
3163+
distanceCustomUnitID: duplicatedDistanceCustomUnitID,
3164+
perDiemCustomUnitID: duplicatedPerDiemCustomUnitID,
3165+
}),
3166+
taxRates: isTaxesFeatureSelected ? taxRatesWithoutPendingDelete : undefined,
3167+
rules: isCodingRulesFeatureSelected ? {codingRules: codingRulesWithoutPendingDelete} : undefined,
3168+
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3169+
pendingFields: {
3170+
autoReporting: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3171+
approvalMode: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3172+
reimbursementChoice: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3173+
name: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3174+
outputCurrency: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3175+
address: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3176+
description: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3177+
type: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3178+
areReportFieldsEnabled: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3179+
},
3180+
avatarURL: duplicatedPolicyFile?.uri,
3181+
originalFileName: duplicatedPolicyFile?.name,
3182+
outputCurrency: duplicatedOutputCurrency,
3183+
address: isOverviewFeatureSelected ? sourcePolicy?.address : undefined,
3184+
};
3185+
}
3186+
30953187
function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOptions) {
30963188
const {
30973189
policyName = '',
@@ -3118,19 +3210,8 @@ function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOp
31183210
pendingChatMembers,
31193211
} = ReportUtils.buildOptimisticWorkspaceChats(targetPolicyID, policyName, currentUserAccountID, currentUserEmail);
31203212
const isMemberOptionSelected = parts?.people;
3121-
const isReportsOptionSelected = parts?.reports;
3122-
const isConnectionsOptionSelected = parts?.connections;
31233213
const isCategoriesOptionSelected = parts?.categories;
3124-
const isTaxesOptionSelected = parts?.taxes;
3125-
const isTagsOptionSelected = parts?.tags;
3126-
const isInvoicesOptionSelected = parts?.invoices;
3127-
const isDistanceRatesOptionSelected = parts?.distance;
3128-
const isRulesOptionSelected = parts?.expenses;
3129-
const isWorkflowsOptionSelected = parts?.exportLayouts;
3130-
const isPerDiemOptionSelected = parts?.perDiem;
31313214
const isOverviewOptionSelected = parts?.overview;
3132-
const isTravelOptionSelected = parts?.travel;
3133-
const isCodingRulesOptionSelected = parts?.codingRules;
31343215

31353216
const outputCurrency = isOverviewOptionSelected && policy?.outputCurrency ? policy?.outputCurrency : localCurrency;
31363217

@@ -3163,46 +3244,7 @@ function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOp
31633244
{
31643245
onyxMethod: Onyx.METHOD.SET,
31653246
key: `${ONYXKEYS.COLLECTION.POLICY}${targetPolicyID}`,
3166-
value: {
3167-
...policy,
3168-
areCategoriesEnabled: true,
3169-
areTagsEnabled: isTagsOptionSelected,
3170-
areDistanceRatesEnabled: isDistanceRatesOptionSelected,
3171-
areInvoicesEnabled: isInvoicesOptionSelected,
3172-
areRulesEnabled: isRulesOptionSelected,
3173-
areWorkflowsEnabled: isWorkflowsOptionSelected,
3174-
areReportFieldsEnabled: isReportsOptionSelected,
3175-
areConnectionsEnabled: isConnectionsOptionSelected,
3176-
arePerDiemRatesEnabled: isPerDiemOptionSelected,
3177-
isTravelEnabled: isTravelOptionSelected ? policy?.isTravelEnabled : undefined,
3178-
travelSettings: undefined,
3179-
workspaceAccountID: undefined,
3180-
tax: isTaxesOptionSelected ? policy?.tax : undefined,
3181-
employeeList: isMemberOptionSelected ? policy.employeeList : {[policy.owner]: policy?.employeeList?.[policy.owner]},
3182-
id: targetPolicyID,
3183-
name: policyName,
3184-
fieldList: isReportsOptionSelected ? policy?.fieldList : undefined,
3185-
connections: isConnectionsOptionSelected ? policy?.connections : undefined,
3186-
customUnits: getCustomUnitsForDuplication(policy, isDistanceRatesOptionSelected, isPerDiemOptionSelected, {distanceCustomUnitID, perDiemCustomUnitID}),
3187-
taxRates: isTaxesOptionSelected ? policy?.taxRates : undefined,
3188-
rules: isCodingRulesOptionSelected ? {codingRules: policy?.rules?.codingRules} : undefined,
3189-
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3190-
pendingFields: {
3191-
autoReporting: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3192-
approvalMode: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3193-
reimbursementChoice: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3194-
name: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3195-
outputCurrency: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3196-
address: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3197-
description: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3198-
type: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3199-
areReportFieldsEnabled: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
3200-
},
3201-
avatarURL: file?.uri,
3202-
originalFileName: file?.name,
3203-
outputCurrency,
3204-
address: isOverviewOptionSelected ? policy?.address : undefined,
3205-
},
3247+
value: buildOptimisticDuplicatePolicy(policy, {...options, targetPolicyID, distanceCustomUnitID, perDiemCustomUnitID}),
32063248
},
32073249
{
32083250
onyxMethod: Onyx.METHOD.MERGE,

src/pages/workspace/duplicate/WorkspaceDuplicateSelectFeaturesForm.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,26 +38,26 @@ function WorkspaceDuplicateSelectFeaturesForm({policyID}: WorkspaceDuplicateForm
3838
const [duplicateWorkspace] = useOnyx(ONYXKEYS.DUPLICATE_WORKSPACE);
3939
const [duplicatedWorkspaceAvatar, setDuplicatedWorkspaceAvatar] = useState<File | undefined>();
4040
const [isDuplicateModalOpen, setIsDuplicateModalOpen] = useState(false);
41-
const allIds = getMemberAccountIDsForWorkspace(policy?.employeeList);
41+
const allIds = getMemberAccountIDsForWorkspace(policy?.employeeList, false, false);
4242
const totalMembers = Object.keys(allIds).length;
4343
const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`);
44-
const taxesLength = Object.keys(policy?.taxRates?.taxes ?? {}).length ?? 0;
44+
const taxesLength = Object.values(policy?.taxRates?.taxes ?? {}).filter((tax) => tax.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length ?? 0;
4545
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`);
46-
const categoriesCount = Object.keys(policyCategories ?? {}).length;
47-
const codingRulesCount = Object.keys(policy?.rules?.codingRules ?? {}).length;
46+
const categoriesCount = Object.values(policyCategories ?? {}).filter((category) => category.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length;
47+
const codingRulesCount = Object.values(policy?.rules?.codingRules ?? {}).filter((rule) => rule.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length;
4848
const [selectedItems, setSelectedItems] = useState<string[]>([]);
49-
const reportFields = Object.keys(getReportFieldsByPolicyID(policyID)).length ?? 0;
49+
const reportFields = Object.values(getReportFieldsByPolicyID(policyID) ?? {}).filter((field) => field.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length ?? 0;
5050
const customUnits = getPerDiemCustomUnit(policy);
5151
const customUnitRates: Record<string, Rate> = customUnits?.rates ?? {};
52-
const allRates = Object.values(customUnitRates)?.length;
52+
const allRates = Object.values(customUnitRates)?.filter((rate) => rate.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length ?? 0;
5353
const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST);
5454
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
5555

5656
const accountingIntegrations = CONST.POLICY.CONNECTIONS.ACCOUNTING_CONNECTION_NAMES;
5757
const connectedIntegration = getAllValidConnectedIntegration(policy, accountingIntegrations);
5858

5959
const customUnit = getDistanceRateCustomUnit(policy);
60-
const ratesCount = Object.keys(customUnit?.rates ?? {}).length;
60+
const ratesCount = Object.values(customUnit?.rates ?? {}).filter((rate) => rate.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length;
6161
const invoiceCompany =
6262
policy?.invoice?.companyName && policy?.invoice?.companyWebsite
6363
? `${policy?.invoice?.companyName}, ${policy?.invoice?.companyWebsite}`
@@ -67,7 +67,10 @@ function WorkspaceDuplicateSelectFeaturesForm({policyID}: WorkspaceDuplicateForm
6767
if (!policyTags) {
6868
return 0;
6969
}
70-
return Object.values(policyTags).reduce((sum, tagGroup) => sum + Number(Object.values(tagGroup.tags)?.length ?? 0), 0);
70+
return Object.values(policyTags).reduce(
71+
(sum, tagGroup) => sum + (Object.values(tagGroup.tags)?.filter((tag) => tag.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length ?? 0),
72+
0,
73+
);
7174
}, [policyTags]);
7275

7376
const formattedAddress = !isEmptyObject(policy) && !isEmptyObject(policy.address) ? formatAddressToString(policy.address) : '';

tests/actions/PolicyTest.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,10 @@ describe('actions/Policy', () => {
271271
it('duplicate workspace', async () => {
272272
(fetch as MockFetch)?.pause?.();
273273
await Onyx.set(ONYXKEYS.SESSION, {email: ESH_EMAIL, accountID: ESH_ACCOUNT_ID});
274-
const fakePolicy = createRandomPolicy(10, CONST.POLICY.TYPE.PERSONAL);
274+
const fakePolicy = {
275+
...createRandomPolicy(10, CONST.POLICY.TYPE.PERSONAL),
276+
employeeList: {},
277+
};
275278
await Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${fakePolicy.id}`, fakePolicy);
276279
await Onyx.set(`${ONYXKEYS.NVP_ACTIVE_POLICY_ID}`, fakePolicy.id);
277280
await Onyx.set(`${ONYXKEYS.NVP_INTRO_SELECTED}`, {choice: CONST.ONBOARDING_CHOICES.MANAGE_TEAM});

0 commit comments

Comments
 (0)