Skip to content

Commit 2f1ae41

Browse files
committed
Merge branch 'main' into claude-stripIncompleteMarkdownDuringStreaming
2 parents a283fbb + 2aca6a2 commit 2f1ae41

13 files changed

Lines changed: 161 additions & 67 deletions

File tree

Mobile-Expensify

android/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ android {
111111
minSdkVersion rootProject.ext.minSdkVersion
112112
targetSdkVersion rootProject.ext.targetSdkVersion
113113
multiDexEnabled rootProject.ext.multiDexEnabled
114-
versionCode 1009036704
115-
versionName "9.3.67-4"
114+
versionCode 1009036705
115+
versionName "9.3.67-5"
116116
// Supported language variants must be declared here to avoid from being removed during the compilation.
117117
// This also helps us to not include unnecessary language variants in the APK.
118118
resConfigs "en", "es"

ios/NewExpensify/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
</dict>
4545
</array>
4646
<key>CFBundleVersion</key>
47-
<string>9.3.67.4</string>
47+
<string>9.3.67.5</string>
4848
<key>FullStory</key>
4949
<dict>
5050
<key>OrgId</key>

ios/NotificationServiceExtension/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<key>CFBundleShortVersionString</key>
1414
<string>9.3.67</string>
1515
<key>CFBundleVersion</key>
16-
<string>9.3.67.4</string>
16+
<string>9.3.67.5</string>
1717
<key>NSExtension</key>
1818
<dict>
1919
<key>NSExtensionPointIdentifier</key>

ios/ShareViewController/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<key>CFBundleShortVersionString</key>
1414
<string>9.3.67</string>
1515
<key>CFBundleVersion</key>
16-
<string>9.3.67.4</string>
16+
<string>9.3.67.5</string>
1717
<key>NSExtension</key>
1818
<dict>
1919
<key>NSExtensionAttributes</key>

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "new.expensify",
3-
"version": "9.3.67-4",
3+
"version": "9.3.67-5",
44
"author": "Expensify, Inc.",
55
"homepage": "https://new.expensify.com",
66
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",

src/DeepLinkHandler.tsx

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ function DeepLinkHandler({onInitialUrl}: DeepLinkHandlerProps) {
2828
const linkingChangeListener = useRef<NativeEventSubscription | null>(null);
2929
const initialUrlProcessed = useRef(false);
3030

31-
const [allReports, allReportsMetadata] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
31+
const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
3232
const [, sessionMetadata] = useOnyx(ONYXKEYS.SESSION);
33-
const [conciergeReportID, conciergeReportIDMetadata] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
34-
const [introSelected, introSelectedMetadata] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
33+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
34+
const [introSelected] = useOnyx(ONYXKEYS.NVP_INTRO_SELECTED);
3535
const [isSelfTourViewed, isSelfTourViewedMetadata] = useOnyx(ONYXKEYS.NVP_ONBOARDING, {selector: hasSeenTourSelector});
36-
const [betas, betasMetadata] = useOnyx(ONYXKEYS.BETAS);
36+
const [betas] = useOnyx(ONYXKEYS.BETAS);
3737
const isAuthenticated = useIsAuthenticated();
3838

3939
useEffect(() => {
40-
if (isLoadingOnyxValue(allReportsMetadata, sessionMetadata, conciergeReportIDMetadata, introSelectedMetadata, isSelfTourViewedMetadata, betasMetadata)) {
40+
if (isLoadingOnyxValue(sessionMetadata, isSelfTourViewedMetadata)) {
4141
return;
4242
}
4343

@@ -111,17 +111,7 @@ function DeepLinkHandler({onInitialUrl}: DeepLinkHandlerProps) {
111111
linkingChangeListener.current?.remove();
112112
};
113113
// eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally excluding allReports, isAuthenticated, and onInitialUrl to avoid re-triggering deep link handling on every report update
114-
}, [
115-
conciergeReportID,
116-
introSelected,
117-
betas,
118-
allReportsMetadata.status,
119-
sessionMetadata.status,
120-
conciergeReportIDMetadata.status,
121-
introSelectedMetadata.status,
122-
isSelfTourViewedMetadata.status,
123-
betasMetadata.status,
124-
]);
114+
}, [sessionMetadata?.status, conciergeReportID, introSelected, isSelfTourViewedMetadata, betas]);
125115

126116
// Safety net: if getInitialURL() resolves before the session loads, hasAuthToken() may return false
127117
// for an authenticated user, causing openReportFromDeepLink to take the wrong path. Once isAuthenticated

src/libs/PolicyUtils.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,17 +298,42 @@ function hasEligibleActiveAdminFromWorkspaces(policies: OnyxCollection<Policy> |
298298
return false;
299299
}
300300

301+
function cloneCustomUnitWithNewIDs(unit: CustomUnit, newCustomUnitID: string, newDefaultRateID?: string): CustomUnit {
302+
if (newDefaultRateID) {
303+
// The server-side DUPLICATE_POLICY assigns newDefaultRateID to the source's default rate.
304+
// Mirror getDefaultMileageRate's selection (enabled rates, sorted by index with
305+
// CONST.DEFAULT_NUMBER_ID for missing indexes) so the optimistic clone aligns with the
306+
// rate the expense flow will later treat as default. Other source rates get fresh server
307+
// IDs, so we drop them from the optimistic state to avoid stale duplicates.
308+
const defaultRate = Object.values(unit.rates)
309+
.filter((rate) => rate.enabled !== false)
310+
.sort((a, b) => (a.index ?? CONST.DEFAULT_NUMBER_ID) - (b.index ?? CONST.DEFAULT_NUMBER_ID))
311+
.at(0);
312+
return {
313+
...unit,
314+
customUnitID: newCustomUnitID,
315+
rates: defaultRate ? {[newDefaultRateID]: {...defaultRate, customUnitRateID: newDefaultRateID}} : {},
316+
};
317+
}
318+
319+
return {
320+
...unit,
321+
customUnitID: newCustomUnitID,
322+
};
323+
}
324+
301325
function getCustomUnitsForDuplication(
302326
policy: Policy,
303327
isDistanceRatesOptionSelected: boolean,
304328
isPerDiemOptionSelected: boolean,
305329
customUnitIDs: {
306330
distanceCustomUnitID: string;
307331
perDiemCustomUnitID: string;
332+
customUnitRateID?: string;
308333
},
309334
): Record<string, CustomUnit> | undefined {
310335
const customUnits = policy?.customUnits;
311-
const {distanceCustomUnitID, perDiemCustomUnitID} = customUnitIDs ?? {};
336+
const {distanceCustomUnitID, perDiemCustomUnitID, customUnitRateID} = customUnitIDs ?? {};
312337

313338
if ((!isDistanceRatesOptionSelected && !isPerDiemOptionSelected) || !customUnits || Object.keys(customUnits).length === 0) {
314339
return undefined;
@@ -339,20 +364,23 @@ function getCustomUnitsForDuplication(
339364
return undefined;
340365
}
341366

342-
return {[distanceCustomUnitID]: distanceCustomUnit, [perDiemCustomUnitID]: perDiemUnit};
367+
return {
368+
[distanceCustomUnitID]: cloneCustomUnitWithNewIDs(distanceCustomUnit, distanceCustomUnitID, customUnitRateID),
369+
[perDiemCustomUnitID]: cloneCustomUnitWithNewIDs(perDiemUnit, perDiemCustomUnitID),
370+
};
343371
}
344372

345373
if (isDistanceRatesOptionSelected && distanceCustomUnitID) {
346374
if (!distanceCustomUnit) {
347375
return undefined;
348376
}
349-
return {[distanceCustomUnitID]: distanceCustomUnit};
377+
return {[distanceCustomUnitID]: cloneCustomUnitWithNewIDs(distanceCustomUnit, distanceCustomUnitID, customUnitRateID)};
350378
}
351379

352380
if (!perDiemUnit || !perDiemCustomUnitID) {
353381
return undefined;
354382
}
355-
return {[perDiemCustomUnitID]: perDiemUnit};
383+
return {[perDiemCustomUnitID]: cloneCustomUnitWithNewIDs(perDiemUnit, perDiemCustomUnitID)};
356384
}
357385

358386
/**

src/libs/actions/Policy/Policy.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3112,7 +3112,10 @@ function createDraftWorkspace({
31123112
return params;
31133113
}
31143114

3115-
function buildOptimisticDuplicatePolicy(sourcePolicy: Policy, policyOptions: DuplicatePolicyDataOptions & {distanceCustomUnitID: string; perDiemCustomUnitID: string}) {
3115+
function buildOptimisticDuplicatePolicy(
3116+
sourcePolicy: Policy,
3117+
policyOptions: DuplicatePolicyDataOptions & {distanceCustomUnitID: string; perDiemCustomUnitID: string; customUnitRateID: string},
3118+
) {
31163119
const {
31173120
policyName: duplicatedPolicyName = '',
31183121
targetPolicyID: duplicatedPolicyID,
@@ -3121,6 +3124,7 @@ function buildOptimisticDuplicatePolicy(sourcePolicy: Policy, policyOptions: Dup
31213124
localCurrency: duplicatedLocalCurrency,
31223125
distanceCustomUnitID: duplicatedDistanceCustomUnitID,
31233126
perDiemCustomUnitID: duplicatedPerDiemCustomUnitID,
3127+
customUnitRateID: duplicatedCustomUnitRateID,
31243128
} = policyOptions;
31253129

31263130
const isMemberFeatureSelected = duplicatedParts?.people;
@@ -3182,6 +3186,7 @@ function buildOptimisticDuplicatePolicy(sourcePolicy: Policy, policyOptions: Dup
31823186
customUnits: getCustomUnitsForDuplication(sourcePolicy, isDistanceRatesFeatureSelected, isPerDiemFeatureSelected, {
31833187
distanceCustomUnitID: duplicatedDistanceCustomUnitID,
31843188
perDiemCustomUnitID: duplicatedPerDiemCustomUnitID,
3189+
customUnitRateID: duplicatedCustomUnitRateID,
31853190
}),
31863191
taxRates: isTaxesFeatureSelected ? taxRatesWithoutPendingDelete : undefined,
31873192
rules: isCodingRulesFeatureSelected ? {codingRules: codingRulesWithoutPendingDelete} : undefined,
@@ -3264,7 +3269,7 @@ function buildDuplicatePolicyData(policy: Policy, options: DuplicatePolicyDataOp
32643269
{
32653270
onyxMethod: Onyx.METHOD.SET,
32663271
key: `${ONYXKEYS.COLLECTION.POLICY}${targetPolicyID}`,
3267-
value: buildOptimisticDuplicatePolicy(policy, {...options, targetPolicyID, distanceCustomUnitID, perDiemCustomUnitID}),
3272+
value: buildOptimisticDuplicatePolicy(policy, {...options, targetPolicyID, distanceCustomUnitID, perDiemCustomUnitID, customUnitRateID}),
32683273
},
32693274
{
32703275
onyxMethod: Onyx.METHOD.MERGE,

0 commit comments

Comments
 (0)