Skip to content

Commit

Permalink
Merge branch 'feat/#Expensify#23229-linking' of https://github.com/ma…
Browse files Browse the repository at this point in the history
  • Loading branch information
perunt committed Nov 3, 2023
2 parents b94dde2 + 7b546b0 commit 07b40b0
Show file tree
Hide file tree
Showing 30 changed files with 271 additions and 236 deletions.
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001039504
versionName "1.3.95-4"
versionCode 1001039505
versionName "1.3.95-5"
}

flavorDimensions "default"
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.3.95.4</string>
<string>1.3.95.5</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
2 changes: 1 addition & 1 deletion ios/NewExpensifyTests/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.3.95.4</string>
<string>1.3.95.5</string>
</dict>
</plist>
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
"version": "1.3.95-4",
"version": "1.3.95-5",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
Expand Down
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1312,6 +1312,7 @@ const CONST = {

TAX_ID: /^\d{9}$/,
NON_NUMERIC: /\D/g,
ANY_SPACE: /\s/g,

// Extract attachment's source from the data's html string
ATTACHMENT_DATA: /(data-expensify-source|data-name)="([^"]+)"/g,
Expand Down
4 changes: 2 additions & 2 deletions src/components/DatePicker/index.android.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import RNDatePicker from '@react-native-community/datetimepicker';
import {format} from 'date-fns';
import {format, parseISO} from 'date-fns';
import React, {forwardRef, useCallback, useImperativeHandle, useRef, useState} from 'react';
import {Keyboard} from 'react-native';
import TextInput from '@components/TextInput';
Expand Down Expand Up @@ -39,7 +39,7 @@ function DatePicker({value, defaultValue, label, placeholder, errorText, contain
);

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

return (
<>
Expand Down
4 changes: 2 additions & 2 deletions src/components/DatePicker/index.ios.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import RNDatePicker from '@react-native-community/datetimepicker';
import {format} from 'date-fns';
import {format, parseISO} from 'date-fns';
import isFunction from 'lodash/isFunction';
import React, {useCallback, useEffect, useRef, useState} from 'react';
import {Button, Keyboard, View} from 'react-native';
Expand Down Expand Up @@ -77,7 +77,7 @@ function DatePicker({value, defaultValue, innerRef, onInputChange, preferredLoca
setSelectedDate(date);
};

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

return (
<>
Expand Down
4 changes: 2 additions & 2 deletions src/components/DatePicker/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {format, isValid} from 'date-fns';
import {format, isValid, parseISO} from 'date-fns';
import React, {useEffect, useRef} from 'react';
import _ from 'underscore';
import TextInput from '@components/TextInput';
Expand Down Expand Up @@ -29,7 +29,7 @@ function DatePicker({maxDate, minDate, onInputChange, innerRef, label, value, pl
return;
}

const date = new Date(text);
const date = parseISO(text);
if (isValid(date)) {
onInputChange(format(date, CONST.DATE.FNS_FORMAT_STRING));
}
Expand Down
31 changes: 0 additions & 31 deletions src/components/InlineErrorText.js

This file was deleted.

7 changes: 1 addition & 6 deletions src/components/LHNOptionsList/OptionRowLHNData.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,17 +168,14 @@ export default React.memo(
},
fullReport: {
key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
initialValue: {},
},
reportActions: {
key: ({reportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
canEvict: false,
initialValue: {},
},
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
selector: personalDetailsSelector,
initialValue: {},
},
preferredLocale: {
key: ONYXKEYS.NVP_PREFERRED_LOCALE,
Expand All @@ -189,17 +186,15 @@ export default React.memo(
parentReportActions: {
key: ({fullReport}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${fullReport.parentReportID}`,
canEvict: false,
initialValue: {},
},
policy: {
key: ({fullReport}) => `${ONYXKEYS.COLLECTION.POLICY}${fullReport.policyID}`,
initialValue: {},
},
// Ideally, we aim to access only the last transaction for the current report by listening to changes in reportActions.
// In some scenarios, a transaction might be created after reportActions have been modified.
// This can lead to situations where `lastTransaction` doesn't update and retains the previous value.
// However, performance overhead of this is minimized by using memos inside the component.
receiptTransactions: {key: ONYXKEYS.COLLECTION.TRANSACTION, initialValue: {}},
receiptTransactions: {key: ONYXKEYS.COLLECTION.TRANSACTION},
}),
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
withOnyx({
Expand Down
8 changes: 5 additions & 3 deletions src/hooks/useDebounce.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import lodashDebounce from 'lodash/debounce';
import {useEffect, useRef} from 'react';
import {useCallback, useEffect, useRef} from 'react';

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

return (...args) => {
const debounceCallback = useCallback((...args) => {
const debouncedFn = debouncedFnRef.current;

if (debouncedFn) {
debouncedFn(...args);
}
};
}, []);

return debounceCallback;
}
18 changes: 0 additions & 18 deletions src/libs/Clipboard/index.native.js

This file was deleted.

19 changes: 19 additions & 0 deletions src/libs/Clipboard/index.native.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Clipboard from '@react-native-clipboard/clipboard';
import {CanSetHtml, SetHtml, SetString} from './types';

/**
* Sets a string on the Clipboard object via @react-native-clipboard/clipboard
*/
const setString: SetString = (text) => {
Clipboard.setString(text);
};

// We don't want to set HTML on native platforms so noop them.
const canSetHtml: CanSetHtml = () => false;
const setHtml: SetHtml = () => {};

export default {
setString,
canSetHtml,
setHtml,
};
63 changes: 42 additions & 21 deletions src/libs/Clipboard/index.js → src/libs/Clipboard/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
import Clipboard from '@react-native-clipboard/clipboard';
import lodashGet from 'lodash/get';
import * as Browser from '@libs/Browser';
import CONST from '@src/CONST';
import {CanSetHtml, SetHtml, SetString} from './types';

const canSetHtml = () => lodashGet(navigator, 'clipboard.write');
type ComposerSelection = {
start: number;
end: number;
direction: 'forward' | 'backward' | 'none';
};

type AnchorSelection = {
anchorOffset: number;
focusOffset: number;
anchorNode: Node;
focusNode: Node;
};

type NullableObject<T> = {[K in keyof T]: T[K] | null};

type OriginalSelection = ComposerSelection | NullableObject<AnchorSelection>;

const canSetHtml: CanSetHtml =
() =>
(...args: ClipboardItems) =>
navigator?.clipboard?.write([...args]);

/**
* Deprecated method to write the content as HTML to clipboard.
* @param {String} html HTML representation
* @param {String} text Plain text representation
*/
function setHTMLSync(html, text) {
function setHTMLSync(html: string, text: string) {
const node = document.createElement('span');
node.textContent = html;
node.style.all = 'unset';
Expand All @@ -21,16 +39,21 @@ function setHTMLSync(html, text) {
node.addEventListener('copy', (e) => {
e.stopPropagation();
e.preventDefault();
e.clipboardData.clearData();
e.clipboardData.setData('text/html', html);
e.clipboardData.setData('text/plain', text);
e.clipboardData?.clearData();
e.clipboardData?.setData('text/html', html);
e.clipboardData?.setData('text/plain', text);
});
document.body.appendChild(node);

const selection = window.getSelection();
const firstAnchorChild = selection.anchorNode && selection.anchorNode.firstChild;
const selection = window?.getSelection();

if (selection === null) {
return;
}

const firstAnchorChild = selection.anchorNode?.firstChild;
const isComposer = firstAnchorChild instanceof HTMLTextAreaElement;
let originalSelection = null;
let originalSelection: OriginalSelection | null = null;
if (isComposer) {
originalSelection = {
start: firstAnchorChild.selectionStart,
Expand Down Expand Up @@ -60,23 +83,23 @@ function setHTMLSync(html, text) {

selection.removeAllRanges();

if (isComposer) {
const anchorSelection = originalSelection as AnchorSelection;

if (isComposer && 'start' in originalSelection) {
firstAnchorChild.setSelectionRange(originalSelection.start, originalSelection.end, originalSelection.direction);
} else if (originalSelection.anchorNode && originalSelection.focusNode) {
} else if (anchorSelection.anchorNode && anchorSelection.focusNode) {
// When copying to the clipboard here, the original values of anchorNode and focusNode will be null since there will be no user selection.
// 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.
selection.setBaseAndExtent(originalSelection.anchorNode, originalSelection.anchorOffset, originalSelection.focusNode, originalSelection.focusOffset);
selection.setBaseAndExtent(anchorSelection.anchorNode, anchorSelection.anchorOffset, anchorSelection.focusNode, anchorSelection.focusOffset);
}

document.body.removeChild(node);
}

/**
* Writes the content as HTML if the web client supports it.
* @param {String} html HTML representation
* @param {String} text Plain text representation
*/
const setHtml = (html, text) => {
const setHtml: SetHtml = (html: string, text: string) => {
if (!html || !text) {
return;
}
Expand All @@ -93,8 +116,8 @@ const setHtml = (html, text) => {
setHTMLSync(html, text);
} else {
navigator.clipboard.write([
// eslint-disable-next-line no-undef
new ClipboardItem({
/* eslint-disable @typescript-eslint/naming-convention */
'text/html': new Blob([html], {type: 'text/html'}),
'text/plain': new Blob([text], {type: 'text/plain'}),
}),
Expand All @@ -104,10 +127,8 @@ const setHtml = (html, text) => {

/**
* Sets a string on the Clipboard object via react-native-web
*
* @param {String} text
*/
const setString = (text) => {
const setString: SetString = (text) => {
Clipboard.setString(text);
};

Expand Down
5 changes: 5 additions & 0 deletions src/libs/Clipboard/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type SetString = (text: string) => void;
type SetHtml = (html: string, text: string) => void;
type CanSetHtml = (() => (...args: ClipboardItems) => Promise<void>) | (() => boolean);

export type {SetString, CanSetHtml, SetHtml};
6 changes: 5 additions & 1 deletion src/libs/ComposerUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ function canSkipTriggerHotkeys(isSmallScreenWidth: boolean, isKeyboardShown: boo
*/
function getCommonSuffixLength(str1: string, str2: string): number {
let i = 0;
while (str1[str1.length - 1 - i] === str2[str2.length - 1 - i]) {
if (str1.length === 0 || str2.length === 0) {
return 0;
}
const minLen = Math.min(str1.length, str2.length);
while (i < minLen && str1[str1.length - 1 - i] === str2[str2.length - 1 - i]) {
i++;
}
return i;
Expand Down
1 change: 0 additions & 1 deletion src/libs/OptionsListUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ Onyx.connect({
const policyExpenseReports = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (report, key) => {
if (!ReportUtils.isPolicyExpenseChat(report)) {
return;
Expand Down
7 changes: 2 additions & 5 deletions src/libs/ReportActionsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -524,12 +524,9 @@ function getLastVisibleMessage(reportID: string, actionsToMerge: ReportActions =
};
}

let messageText = message?.text ?? '';
if (messageText) {
messageText = String(messageText).replace(CONST.REGEX.AFTER_FIRST_LINE_BREAK, '').substring(0, CONST.REPORT.LAST_MESSAGE_TEXT_MAX_LENGTH).trim();
}
const messageText = message?.text ?? '';
return {
lastMessageText: messageText,
lastMessageText: String(messageText).replace(CONST.REGEX.AFTER_FIRST_LINE_BREAK, '').substring(0, CONST.REPORT.LAST_MESSAGE_TEXT_MAX_LENGTH).trim(),
};
}

Expand Down
Loading

0 comments on commit 07b40b0

Please sign in to comment.