Skip to content

Commit 07b40b0

Browse files
committed
2 parents b94dde2 + 7b546b0 commit 07b40b0

30 files changed

+271
-236
lines changed

android/app/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ android {
9090
minSdkVersion rootProject.ext.minSdkVersion
9191
targetSdkVersion rootProject.ext.targetSdkVersion
9292
multiDexEnabled rootProject.ext.multiDexEnabled
93-
versionCode 1001039504
94-
versionName "1.3.95-4"
93+
versionCode 1001039505
94+
versionName "1.3.95-5"
9595
}
9696

9797
flavorDimensions "default"

ios/NewExpensify/Info.plist

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
</dict>
4141
</array>
4242
<key>CFBundleVersion</key>
43-
<string>1.3.95.4</string>
43+
<string>1.3.95.5</string>
4444
<key>ITSAppUsesNonExemptEncryption</key>
4545
<false/>
4646
<key>LSApplicationQueriesSchemes</key>

ios/NewExpensifyTests/Info.plist

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@
1919
<key>CFBundleSignature</key>
2020
<string>????</string>
2121
<key>CFBundleVersion</key>
22-
<string>1.3.95.4</string>
22+
<string>1.3.95.5</string>
2323
</dict>
2424
</plist>

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "new.expensify",
3-
"version": "1.3.95-4",
3+
"version": "1.3.95-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/CONST.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,7 @@ const CONST = {
13121312

13131313
TAX_ID: /^\d{9}$/,
13141314
NON_NUMERIC: /\D/g,
1315+
ANY_SPACE: /\s/g,
13151316

13161317
// Extract attachment's source from the data's html string
13171318
ATTACHMENT_DATA: /(data-expensify-source|data-name)="([^"]+)"/g,

src/components/DatePicker/index.android.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import RNDatePicker from '@react-native-community/datetimepicker';
2-
import {format} from 'date-fns';
2+
import {format, parseISO} from 'date-fns';
33
import React, {forwardRef, useCallback, useImperativeHandle, useRef, useState} from 'react';
44
import {Keyboard} from 'react-native';
55
import TextInput from '@components/TextInput';
@@ -39,7 +39,7 @@ function DatePicker({value, defaultValue, label, placeholder, errorText, contain
3939
);
4040

4141
const date = value || defaultValue;
42-
const dateAsText = date ? format(new Date(date), CONST.DATE.FNS_FORMAT_STRING) : '';
42+
const dateAsText = date ? format(parseISO(date), CONST.DATE.FNS_FORMAT_STRING) : '';
4343

4444
return (
4545
<>

src/components/DatePicker/index.ios.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import RNDatePicker from '@react-native-community/datetimepicker';
2-
import {format} from 'date-fns';
2+
import {format, parseISO} from 'date-fns';
33
import isFunction from 'lodash/isFunction';
44
import React, {useCallback, useEffect, useRef, useState} from 'react';
55
import {Button, Keyboard, View} from 'react-native';
@@ -77,7 +77,7 @@ function DatePicker({value, defaultValue, innerRef, onInputChange, preferredLoca
7777
setSelectedDate(date);
7878
};
7979

80-
const dateAsText = dateValue ? format(new Date(dateValue), CONST.DATE.FNS_FORMAT_STRING) : '';
80+
const dateAsText = dateValue ? format(parseISO(dateValue), CONST.DATE.FNS_FORMAT_STRING) : '';
8181

8282
return (
8383
<>

src/components/DatePicker/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {format, isValid} from 'date-fns';
1+
import {format, isValid, parseISO} from 'date-fns';
22
import React, {useEffect, useRef} from 'react';
33
import _ from 'underscore';
44
import TextInput from '@components/TextInput';
@@ -29,7 +29,7 @@ function DatePicker({maxDate, minDate, onInputChange, innerRef, label, value, pl
2929
return;
3030
}
3131

32-
const date = new Date(text);
32+
const date = parseISO(text);
3333
if (isValid(date)) {
3434
onInputChange(format(date, CONST.DATE.FNS_FORMAT_STRING));
3535
}

src/components/InlineErrorText.js

-31
This file was deleted.

src/components/LHNOptionsList/OptionRowLHNData.js

+1-6
Original file line numberDiff line numberDiff line change
@@ -168,17 +168,14 @@ export default React.memo(
168168
},
169169
fullReport: {
170170
key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
171-
initialValue: {},
172171
},
173172
reportActions: {
174173
key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
175174
canEvict: false,
176-
initialValue: {},
177175
},
178176
personalDetails: {
179177
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
180178
selector: personalDetailsSelector,
181-
initialValue: {},
182179
},
183180
preferredLocale: {
184181
key: ONYXKEYS.NVP_PREFERRED_LOCALE,
@@ -189,17 +186,15 @@ export default React.memo(
189186
parentReportActions: {
190187
key: ({fullReport}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${fullReport.parentReportID}`,
191188
canEvict: false,
192-
initialValue: {},
193189
},
194190
policy: {
195191
key: ({fullReport}) => `${ONYXKEYS.COLLECTION.POLICY}${fullReport.policyID}`,
196-
initialValue: {},
197192
},
198193
// Ideally, we aim to access only the last transaction for the current report by listening to changes in reportActions.
199194
// In some scenarios, a transaction might be created after reportActions have been modified.
200195
// This can lead to situations where `lastTransaction` doesn't update and retains the previous value.
201196
// However, performance overhead of this is minimized by using memos inside the component.
202-
receiptTransactions: {key: ONYXKEYS.COLLECTION.TRANSACTION, initialValue: {}},
197+
receiptTransactions: {key: ONYXKEYS.COLLECTION.TRANSACTION},
203198
}),
204199
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
205200
withOnyx({

src/hooks/useDebounce.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import lodashDebounce from 'lodash/debounce';
2-
import {useEffect, useRef} from 'react';
2+
import {useCallback, useEffect, useRef} from 'react';
33

44
/**
55
* Create and return a debounced function.
@@ -27,11 +27,13 @@ export default function useDebounce(func, wait, options) {
2727
return debouncedFn.cancel;
2828
}, [func, wait, leading, maxWait, trailing]);
2929

30-
return (...args) => {
30+
const debounceCallback = useCallback((...args) => {
3131
const debouncedFn = debouncedFnRef.current;
3232

3333
if (debouncedFn) {
3434
debouncedFn(...args);
3535
}
36-
};
36+
}, []);
37+
38+
return debounceCallback;
3739
}

src/libs/Clipboard/index.native.js

-18
This file was deleted.

src/libs/Clipboard/index.native.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import Clipboard from '@react-native-clipboard/clipboard';
2+
import {CanSetHtml, SetHtml, SetString} from './types';
3+
4+
/**
5+
* Sets a string on the Clipboard object via @react-native-clipboard/clipboard
6+
*/
7+
const setString: SetString = (text) => {
8+
Clipboard.setString(text);
9+
};
10+
11+
// We don't want to set HTML on native platforms so noop them.
12+
const canSetHtml: CanSetHtml = () => false;
13+
const setHtml: SetHtml = () => {};
14+
15+
export default {
16+
setString,
17+
canSetHtml,
18+
setHtml,
19+
};

src/libs/Clipboard/index.js src/libs/Clipboard/index.ts

+42-21
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,34 @@
11
import Clipboard from '@react-native-clipboard/clipboard';
2-
import lodashGet from 'lodash/get';
32
import * as Browser from '@libs/Browser';
43
import CONST from '@src/CONST';
4+
import {CanSetHtml, SetHtml, SetString} from './types';
55

6-
const canSetHtml = () => lodashGet(navigator, 'clipboard.write');
6+
type ComposerSelection = {
7+
start: number;
8+
end: number;
9+
direction: 'forward' | 'backward' | 'none';
10+
};
11+
12+
type AnchorSelection = {
13+
anchorOffset: number;
14+
focusOffset: number;
15+
anchorNode: Node;
16+
focusNode: Node;
17+
};
18+
19+
type NullableObject<T> = {[K in keyof T]: T[K] | null};
20+
21+
type OriginalSelection = ComposerSelection | NullableObject<AnchorSelection>;
22+
23+
const canSetHtml: CanSetHtml =
24+
() =>
25+
(...args: ClipboardItems) =>
26+
navigator?.clipboard?.write([...args]);
727

828
/**
929
* Deprecated method to write the content as HTML to clipboard.
10-
* @param {String} html HTML representation
11-
* @param {String} text Plain text representation
1230
*/
13-
function setHTMLSync(html, text) {
31+
function setHTMLSync(html: string, text: string) {
1432
const node = document.createElement('span');
1533
node.textContent = html;
1634
node.style.all = 'unset';
@@ -21,16 +39,21 @@ function setHTMLSync(html, text) {
2139
node.addEventListener('copy', (e) => {
2240
e.stopPropagation();
2341
e.preventDefault();
24-
e.clipboardData.clearData();
25-
e.clipboardData.setData('text/html', html);
26-
e.clipboardData.setData('text/plain', text);
42+
e.clipboardData?.clearData();
43+
e.clipboardData?.setData('text/html', html);
44+
e.clipboardData?.setData('text/plain', text);
2745
});
2846
document.body.appendChild(node);
2947

30-
const selection = window.getSelection();
31-
const firstAnchorChild = selection.anchorNode && selection.anchorNode.firstChild;
48+
const selection = window?.getSelection();
49+
50+
if (selection === null) {
51+
return;
52+
}
53+
54+
const firstAnchorChild = selection.anchorNode?.firstChild;
3255
const isComposer = firstAnchorChild instanceof HTMLTextAreaElement;
33-
let originalSelection = null;
56+
let originalSelection: OriginalSelection | null = null;
3457
if (isComposer) {
3558
originalSelection = {
3659
start: firstAnchorChild.selectionStart,
@@ -60,23 +83,23 @@ function setHTMLSync(html, text) {
6083

6184
selection.removeAllRanges();
6285

63-
if (isComposer) {
86+
const anchorSelection = originalSelection as AnchorSelection;
87+
88+
if (isComposer && 'start' in originalSelection) {
6489
firstAnchorChild.setSelectionRange(originalSelection.start, originalSelection.end, originalSelection.direction);
65-
} else if (originalSelection.anchorNode && originalSelection.focusNode) {
90+
} else if (anchorSelection.anchorNode && anchorSelection.focusNode) {
6691
// When copying to the clipboard here, the original values of anchorNode and focusNode will be null since there will be no user selection.
6792
// We are adding a check to prevent null values from being passed to setBaseAndExtent, in accordance with the standards of the Selection API as outlined here: https://w3c.github.io/selection-api/#dom-selection-setbaseandextent.
68-
selection.setBaseAndExtent(originalSelection.anchorNode, originalSelection.anchorOffset, originalSelection.focusNode, originalSelection.focusOffset);
93+
selection.setBaseAndExtent(anchorSelection.anchorNode, anchorSelection.anchorOffset, anchorSelection.focusNode, anchorSelection.focusOffset);
6994
}
7095

7196
document.body.removeChild(node);
7297
}
7398

7499
/**
75100
* Writes the content as HTML if the web client supports it.
76-
* @param {String} html HTML representation
77-
* @param {String} text Plain text representation
78101
*/
79-
const setHtml = (html, text) => {
102+
const setHtml: SetHtml = (html: string, text: string) => {
80103
if (!html || !text) {
81104
return;
82105
}
@@ -93,8 +116,8 @@ const setHtml = (html, text) => {
93116
setHTMLSync(html, text);
94117
} else {
95118
navigator.clipboard.write([
96-
// eslint-disable-next-line no-undef
97119
new ClipboardItem({
120+
/* eslint-disable @typescript-eslint/naming-convention */
98121
'text/html': new Blob([html], {type: 'text/html'}),
99122
'text/plain': new Blob([text], {type: 'text/plain'}),
100123
}),
@@ -104,10 +127,8 @@ const setHtml = (html, text) => {
104127

105128
/**
106129
* Sets a string on the Clipboard object via react-native-web
107-
*
108-
* @param {String} text
109130
*/
110-
const setString = (text) => {
131+
const setString: SetString = (text) => {
111132
Clipboard.setString(text);
112133
};
113134

src/libs/Clipboard/types.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
type SetString = (text: string) => void;
2+
type SetHtml = (html: string, text: string) => void;
3+
type CanSetHtml = (() => (...args: ClipboardItems) => Promise<void>) | (() => boolean);
4+
5+
export type {SetString, CanSetHtml, SetHtml};

src/libs/ComposerUtils/index.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ function canSkipTriggerHotkeys(isSmallScreenWidth: boolean, isKeyboardShown: boo
3232
*/
3333
function getCommonSuffixLength(str1: string, str2: string): number {
3434
let i = 0;
35-
while (str1[str1.length - 1 - i] === str2[str2.length - 1 - i]) {
35+
if (str1.length === 0 || str2.length === 0) {
36+
return 0;
37+
}
38+
const minLen = Math.min(str1.length, str2.length);
39+
while (i < minLen && str1[str1.length - 1 - i] === str2[str2.length - 1 - i]) {
3640
i++;
3741
}
3842
return i;

src/libs/OptionsListUtils.js

-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ Onyx.connect({
8787
const policyExpenseReports = {};
8888
Onyx.connect({
8989
key: ONYXKEYS.COLLECTION.REPORT,
90-
waitForCollectionCallback: true,
9190
callback: (report, key) => {
9291
if (!ReportUtils.isPolicyExpenseChat(report)) {
9392
return;

src/libs/ReportActionsUtils.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -524,12 +524,9 @@ function getLastVisibleMessage(reportID: string, actionsToMerge: ReportActions =
524524
};
525525
}
526526

527-
let messageText = message?.text ?? '';
528-
if (messageText) {
529-
messageText = String(messageText).replace(CONST.REGEX.AFTER_FIRST_LINE_BREAK, '').substring(0, CONST.REPORT.LAST_MESSAGE_TEXT_MAX_LENGTH).trim();
530-
}
527+
const messageText = message?.text ?? '';
531528
return {
532-
lastMessageText: messageText,
529+
lastMessageText: String(messageText).replace(CONST.REGEX.AFTER_FIRST_LINE_BREAK, '').substring(0, CONST.REPORT.LAST_MESSAGE_TEXT_MAX_LENGTH).trim(),
533530
};
534531
}
535532

0 commit comments

Comments
 (0)