diff --git a/android/app/build.gradle b/android/app/build.gradle
index 402cd5a61bd6..91817a990792 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -107,8 +107,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1001048204
- versionName "1.4.82-4"
+ versionCode 1001048300
+ versionName "1.4.83-0"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index dae86af11b18..89d58a307eb4 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -19,7 +19,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.4.82
+ 1.4.83
CFBundleSignature
????
CFBundleURLTypes
@@ -40,7 +40,7 @@
CFBundleVersion
- 1.4.82.4
+ 1.4.83.0
FullStory
OrgId
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index 1d3f54796afd..7e02bc5287a2 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 1.4.82
+ 1.4.83
CFBundleSignature
????
CFBundleVersion
- 1.4.82.4
+ 1.4.83.0
diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist
index 064b395be9c7..3a279cea4f8d 100644
--- a/ios/NotificationServiceExtension/Info.plist
+++ b/ios/NotificationServiceExtension/Info.plist
@@ -11,9 +11,9 @@
CFBundleName
$(PRODUCT_NAME)
CFBundleShortVersionString
- 1.4.82
+ 1.4.83
CFBundleVersion
- 1.4.82.4
+ 1.4.83.0
NSExtension
NSExtensionPointIdentifier
diff --git a/package-lock.json b/package-lock.json
index 9b8f74c7d7e8..f2f3e2664382 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.4.82-4",
+ "version": "1.4.83-0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.4.82-4",
+ "version": "1.4.83-0",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index 246890592c5d..fb2785923e94 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.4.82-4",
+ "version": "1.4.83-0",
"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.",
diff --git a/src/components/AmountPicker/index.tsx b/src/components/AmountPicker/index.tsx
index 014932f7736b..b84ec19e2ffd 100644
--- a/src/components/AmountPicker/index.tsx
+++ b/src/components/AmountPicker/index.tsx
@@ -2,15 +2,12 @@ import React, {forwardRef, useState} from 'react';
import type {ForwardedRef} from 'react';
import {View} from 'react-native';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
-import useStyleUtils from '@hooks/useStyleUtils';
-import variables from '@styles/variables';
import CONST from '@src/CONST';
import callOrReturn from '@src/types/utils/callOrReturn';
import AmountSelectorModal from './AmountSelectorModal';
import type {AmountPickerProps} from './types';
function AmountPicker({value, description, title, errorText = '', onInputChange, furtherDetails, rightLabel, ...rest}: AmountPickerProps, forwardedRef: ForwardedRef) {
- const StyleUtils = useStyleUtils();
const [isPickerVisible, setIsPickerVisible] = useState(false);
const showPickerModal = () => {
@@ -29,15 +26,12 @@ function AmountPicker({value, description, title, errorText = '', onInputChange,
hidePickerModal();
};
- const descStyle = !value || value.length === 0 ? StyleUtils.getFontSizeStyle(variables.fontSizeLabel) : null;
-
return (
- ) : (
-
- {text}
-
- )}
+ {text &&
+ (shouldRenderHTML ? (
+
+ ) : (
+
+ {text}
+
+ ))}
{shouldShowCloseButton && !!onClose && (
diff --git a/src/components/MoneyRequestHeader.tsx b/src/components/MoneyRequestHeader.tsx
index e4aaa611f7a1..a1f214ae847a 100644
--- a/src/components/MoneyRequestHeader.tsx
+++ b/src/components/MoneyRequestHeader.tsx
@@ -22,6 +22,7 @@ import type {Route} from '@src/ROUTES';
import type {Policy, Report, ReportAction} from '@src/types/onyx';
import type {OriginalMessageIOU} from '@src/types/onyx/OriginalMessage';
import type IconAsset from '@src/types/utils/IconAsset';
+import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
import Button from './Button';
import ConfirmModal from './ConfirmModal';
import HeaderWithBackButton from './HeaderWithBackButton';
@@ -53,7 +54,8 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow
const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${(parentReportAction as ReportAction & OriginalMessageIOU)?.originalMessage?.IOUTransactionID ?? -1}`);
const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
const [session] = useOnyx(ONYXKEYS.SESSION);
- const [shownHoldUseExplanation] = useOnyx(ONYXKEYS.NVP_HOLD_USE_EXPLAINED, {initWithStoredValues: false});
+ const [holdUseExplained, holdUseExplainedResult] = useOnyx(ONYXKEYS.NVP_HOLD_USE_EXPLAINED);
+ const isLoadingHoldUseExplained = isLoadingOnyxValue(holdUseExplainedResult);
const styles = useThemeStyles();
const theme = useTheme();
@@ -175,8 +177,11 @@ function MoneyRequestHeader({report, parentReportAction, policy, shouldUseNarrow
}
useEffect(() => {
- setShouldShowHoldMenu(isOnHold && !shownHoldUseExplanation);
- }, [isOnHold, shownHoldUseExplanation]);
+ if (isLoadingHoldUseExplained) {
+ return;
+ }
+ setShouldShowHoldMenu(isOnHold && !holdUseExplained);
+ }, [isOnHold, holdUseExplained, isLoadingHoldUseExplained]);
useEffect(() => {
if (!shouldShowHoldMenu) {
diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx
index cff183b8e8e0..cb588ca911f7 100644
--- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx
+++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx
@@ -106,6 +106,7 @@ function MoneyRequestPreviewContent({
const isFullySettled = isSettled && !isSettlementOrApprovalPartial;
const isFullyApproved = ReportUtils.isReportApproved(iouReport) && !isSettlementOrApprovalPartial;
const shouldShowRBR = hasNoticeTypeViolations || hasViolations || hasFieldErrors || (!isFullySettled && !isFullyApproved && isOnHold);
+ const showCashOrCard = isCardTransaction ? translate('iou.card') : translate('iou.cash');
const shouldShowHoldMessage = !(isSettled && !isSettlementOrApprovalPartial) && isOnHold;
/*
@@ -140,7 +141,7 @@ function MoneyRequestPreviewContent({
};
const getPreviewHeaderText = (): string => {
- let message = translate('iou.cash');
+ let message = showCashOrCard;
if (isDistanceRequest) {
message = translate('common.distance');
@@ -363,7 +364,7 @@ function MoneyRequestPreviewContent({
onPressOut={() => ControlSelection.unblock()}
onLongPress={showContextMenu}
shouldUseHapticsOnLongPress
- accessibilityLabel={isBillSplit ? translate('iou.split') : translate('iou.cash')}
+ accessibilityLabel={isBillSplit ? translate('iou.split') : showCashOrCard}
accessibilityHint={CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency)}
style={[
styles.moneyRequestPreviewBox,
diff --git a/src/components/SelectionList/BaseListItem.tsx b/src/components/SelectionList/BaseListItem.tsx
index b1c689b55afa..c9dc773c8818 100644
--- a/src/components/SelectionList/BaseListItem.tsx
+++ b/src/components/SelectionList/BaseListItem.tsx
@@ -18,7 +18,6 @@ function BaseListItem({
wrapperStyle,
containerStyle,
isDisabled = false,
- shouldPreventDefaultFocusOnSelectRow = false,
shouldPreventEnterKeySubmit = false,
canSelectMultiple = false,
onSelectRow,
@@ -88,7 +87,7 @@ function BaseListItem({
hoverDimmingValue={1}
hoverStyle={[!item.isDisabled && styles.hoveredComponentBG, hoverStyle]}
dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
- onMouseDown={shouldPreventDefaultFocusOnSelectRow ? (e) => e.preventDefault() : undefined}
+ onMouseDown={(e) => e.preventDefault()}
id={keyForList ?? ''}
style={pressableStyle}
onFocus={onFocus}
diff --git a/src/components/SelectionList/InviteMemberListItem.tsx b/src/components/SelectionList/InviteMemberListItem.tsx
index 13b0014efb2d..2b3c01c04a69 100644
--- a/src/components/SelectionList/InviteMemberListItem.tsx
+++ b/src/components/SelectionList/InviteMemberListItem.tsx
@@ -24,7 +24,6 @@ function InviteMemberListItem({
onSelectRow,
onCheckboxPress,
onDismissError,
- shouldPreventDefaultFocusOnSelectRow,
rightHandSideComponent,
onFocus,
shouldSyncFocus,
@@ -56,7 +55,6 @@ function InviteMemberListItem({
canSelectMultiple={canSelectMultiple}
onSelectRow={onSelectRow}
onDismissError={onDismissError}
- shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
rightHandSideComponent={rightHandSideComponent}
errors={item.errors}
pendingAction={item.pendingAction}
diff --git a/src/components/SelectionList/RadioListItem.tsx b/src/components/SelectionList/RadioListItem.tsx
index c7884690c067..48ca474f6c60 100644
--- a/src/components/SelectionList/RadioListItem.tsx
+++ b/src/components/SelectionList/RadioListItem.tsx
@@ -13,7 +13,6 @@ function RadioListItem({
isDisabled,
onSelectRow,
onDismissError,
- shouldPreventDefaultFocusOnSelectRow,
shouldPreventEnterKeySubmit,
rightHandSideComponent,
isMultilineSupported = false,
@@ -34,7 +33,6 @@ function RadioListItem({
showTooltip={showTooltip}
onSelectRow={onSelectRow}
onDismissError={onDismissError}
- shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
shouldPreventEnterKeySubmit={shouldPreventEnterKeySubmit}
rightHandSideComponent={rightHandSideComponent}
keyForList={item.keyForList}
diff --git a/src/components/SelectionList/Search/ReportListItem.tsx b/src/components/SelectionList/Search/ReportListItem.tsx
index 9adff46395e6..2273b80e529d 100644
--- a/src/components/SelectionList/Search/ReportListItem.tsx
+++ b/src/components/SelectionList/Search/ReportListItem.tsx
@@ -68,7 +68,6 @@ function ReportListItem({
canSelectMultiple,
onSelectRow,
onDismissError,
- shouldPreventDefaultFocusOnSelectRow,
onFocus,
shouldSyncFocus,
}: ReportListItemProps) {
@@ -119,7 +118,6 @@ function ReportListItem({
canSelectMultiple={canSelectMultiple}
onSelectRow={() => openReportInRHP(transactionItem)}
onDismissError={onDismissError}
- shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
onFocus={onFocus}
shouldSyncFocus={shouldSyncFocus}
/>
@@ -138,7 +136,6 @@ function ReportListItem({
canSelectMultiple={canSelectMultiple}
onSelectRow={onSelectRow}
onDismissError={onDismissError}
- shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
errors={item.errors}
pendingAction={item.pendingAction}
keyForList={item.keyForList}
diff --git a/src/components/SelectionList/Search/TransactionListItem.tsx b/src/components/SelectionList/Search/TransactionListItem.tsx
index ecf9264301c2..23ab549dd495 100644
--- a/src/components/SelectionList/Search/TransactionListItem.tsx
+++ b/src/components/SelectionList/Search/TransactionListItem.tsx
@@ -13,7 +13,6 @@ function TransactionListItem({
canSelectMultiple,
onSelectRow,
onDismissError,
- shouldPreventDefaultFocusOnSelectRow,
onFocus,
shouldSyncFocus,
}: TransactionListItemProps) {
@@ -42,7 +41,6 @@ function TransactionListItem({
canSelectMultiple={canSelectMultiple}
onSelectRow={onSelectRow}
onDismissError={onDismissError}
- shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
errors={item.errors}
pendingAction={item.pendingAction}
keyForList={item.keyForList}
diff --git a/src/components/SelectionList/TableListItem.tsx b/src/components/SelectionList/TableListItem.tsx
index d07d658f6b12..9fc138254f8b 100644
--- a/src/components/SelectionList/TableListItem.tsx
+++ b/src/components/SelectionList/TableListItem.tsx
@@ -21,7 +21,6 @@ function TableListItem({
onSelectRow,
onCheckboxPress,
onDismissError,
- shouldPreventDefaultFocusOnSelectRow,
rightHandSideComponent,
onFocus,
shouldSyncFocus,
@@ -53,7 +52,6 @@ function TableListItem({
canSelectMultiple={canSelectMultiple}
onSelectRow={onSelectRow}
onDismissError={onDismissError}
- shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
rightHandSideComponent={rightHandSideComponent}
errors={item.errors}
pendingAction={item.pendingAction}
diff --git a/src/components/SelectionList/UserListItem.tsx b/src/components/SelectionList/UserListItem.tsx
index d07ac03c00f5..104990cf479c 100644
--- a/src/components/SelectionList/UserListItem.tsx
+++ b/src/components/SelectionList/UserListItem.tsx
@@ -25,7 +25,6 @@ function UserListItem({
onSelectRow,
onCheckboxPress,
onDismissError,
- shouldPreventDefaultFocusOnSelectRow,
shouldPreventEnterKeySubmit,
rightHandSideComponent,
onFocus,
@@ -59,7 +58,6 @@ function UserListItem({
canSelectMultiple={canSelectMultiple}
onSelectRow={onSelectRow}
onDismissError={onDismissError}
- shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
shouldPreventEnterKeySubmit={shouldPreventEnterKeySubmit}
rightHandSideComponent={rightHandSideComponent}
errors={item.errors}
diff --git a/src/components/TextPicker/index.tsx b/src/components/TextPicker/index.tsx
index 0900884d874c..968338391aaa 100644
--- a/src/components/TextPicker/index.tsx
+++ b/src/components/TextPicker/index.tsx
@@ -2,16 +2,13 @@ import React, {forwardRef, useState} from 'react';
import type {ForwardedRef} from 'react';
import {View} from 'react-native';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
-import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
-import variables from '@styles/variables';
import CONST from '@src/CONST';
import TextSelectorModal from './TextSelectorModal';
import type {TextPickerProps} from './types';
function TextPicker({value, description, placeholder = '', errorText = '', onInputChange, furtherDetails, rightLabel, ...rest}: TextPickerProps, forwardedRef: ForwardedRef) {
const styles = useThemeStyles();
- const StyleUtils = useStyleUtils();
const [isPickerVisible, setIsPickerVisible] = useState(false);
const showPickerModal = () => {
@@ -29,15 +26,12 @@ function TextPicker({value, description, placeholder = '', errorText = '', onInp
hidePickerModal();
};
- const descStyle = !value || value.length === 0 ? StyleUtils.getFontSizeStyle(variables.fontSizeLabel) : null;
-
return (
(lastUpdateIDAppliedToClient = value ?? 0),
+ callback: (value) => {
+ if (value) {
+ lastUpdateIDAppliedToClient = value;
+ } else {
+ lastUpdateIDAppliedToClient = -1;
+ }
+ },
});
/**
diff --git a/src/libs/API/parameters/SetPolicyTagsRequired.ts b/src/libs/API/parameters/SetPolicyTagsRequired.ts
new file mode 100644
index 000000000000..8defd4a80840
--- /dev/null
+++ b/src/libs/API/parameters/SetPolicyTagsRequired.ts
@@ -0,0 +1,7 @@
+type SetPolicyTagsRequired = {
+ policyID: string;
+ tagListIndex: number;
+ requireTagList: boolean;
+};
+
+export default SetPolicyTagsRequired;
diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts
index 8baf8bb63485..52e76b842f38 100644
--- a/src/libs/API/parameters/index.ts
+++ b/src/libs/API/parameters/index.ts
@@ -172,6 +172,7 @@ export type {default as SetWorkspaceApprovalModeParams} from './SetWorkspaceAppr
export type {default as SetWorkspacePayerParams} from './SetWorkspacePayerParams';
export type {default as SetWorkspaceReimbursementParams} from './SetWorkspaceReimbursementParams';
export type {default as SetPolicyRequiresTag} from './SetPolicyRequiresTag';
+export type {default as SetPolicyTagsRequired} from './SetPolicyTagsRequired';
export type {default as RenamePolicyTaglistParams} from './RenamePolicyTaglistParams';
export type {default as SwitchToOldDotParams} from './SwitchToOldDotParams';
export type {default as TrackExpenseParams} from './TrackExpenseParams';
diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts
index 07f89e045c11..b6ae0ab23f7c 100644
--- a/src/libs/API/types.ts
+++ b/src/libs/API/types.ts
@@ -133,6 +133,7 @@ const WRITE_COMMANDS = {
RENAME_POLICY_TAG: 'RenamePolicyTag',
SET_WORKSPACE_REQUIRES_CATEGORY: 'SetWorkspaceRequiresCategory',
DELETE_WORKSPACE_CATEGORIES: 'DeleteWorkspaceCategories',
+ SET_POLICY_TAGS_REQUIRED: 'SetPolicyTagsRequired',
SET_POLICY_REQUIRES_TAG: 'SetPolicyRequiresTag',
RENAME_POLICY_TAG_LIST: 'RenamePolicyTaglist',
DELETE_POLICY_TAGS: 'DeletePolicyTags',
@@ -345,6 +346,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.SET_WORKSPACE_REQUIRES_CATEGORY]: Parameters.SetWorkspaceRequiresCategoryParams;
[WRITE_COMMANDS.DELETE_WORKSPACE_CATEGORIES]: Parameters.DeleteWorkspaceCategoriesParams;
[WRITE_COMMANDS.SET_POLICY_REQUIRES_TAG]: Parameters.SetPolicyRequiresTag;
+ [WRITE_COMMANDS.SET_POLICY_TAGS_REQUIRED]: Parameters.SetPolicyTagsRequired;
[WRITE_COMMANDS.RENAME_POLICY_TAG_LIST]: Parameters.RenamePolicyTaglistParams;
[WRITE_COMMANDS.CREATE_POLICY_TAG]: Parameters.CreatePolicyTagsParams;
[WRITE_COMMANDS.RENAME_POLICY_TAG]: Parameters.RenamePolicyTagsParams;
diff --git a/src/libs/NetworkConnection.ts b/src/libs/NetworkConnection.ts
index 3fc0fbdeb534..8c76e52aa42d 100644
--- a/src/libs/NetworkConnection.ts
+++ b/src/libs/NetworkConnection.ts
@@ -91,6 +91,17 @@ Onyx.connect({
},
});
+let accountID = 0;
+Onyx.connect({
+ key: ONYXKEYS.SESSION,
+ callback: (session) => {
+ if (!session?.accountID) {
+ return;
+ }
+ accountID = session.accountID;
+ },
+});
+
/**
* Set interval to periodically (re)check backend status.
* Because backend unreachability might imply lost internet connection, we need to check internet reachability.
@@ -107,7 +118,7 @@ function subscribeToBackendAndInternetReachability(): () => void {
return;
}
// Using the API url ensures reachability is tested over internet
- fetch(`${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/Ping`, {
+ fetch(`${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/Ping?accountID=${accountID || 'unknown'}`, {
method: 'GET',
cache: 'no-cache',
})
diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts
index 47a655715bda..820444443d78 100644
--- a/src/libs/SidebarUtils.ts
+++ b/src/libs/SidebarUtils.ts
@@ -62,6 +62,16 @@ function compareStringDates(a: string, b: string): 0 | 1 | -1 {
return 0;
}
+/**
+ * A mini report object that contains only the necessary information to sort reports.
+ * This is used to avoid copying the entire report object and only the necessary information.
+ */
+type MiniReport = {
+ reportID?: string;
+ displayName: string;
+ lastVisibleActionCreated?: string;
+};
+
/**
* @returns An array of reportIDs sorted in the proper order
*/
@@ -132,10 +142,10 @@ function getOrderedReportIDs(
// 4. Archived reports
// - Sorted by lastVisibleActionCreated in default (most recent) view mode
// - Sorted by reportDisplayName in GSD (focus) view mode
- const pinnedAndGBRReports: Array> = [];
- const draftReports: Array> = [];
- const nonArchivedReports: Array> = [];
- const archivedReports: Array> = [];
+ const pinnedAndGBRReports: MiniReport[] = [];
+ const draftReports: MiniReport[] = [];
+ const nonArchivedReports: MiniReport[] = [];
+ const archivedReports: MiniReport[] = [];
if (currentPolicyID || policyMemberAccountIDs.length > 0) {
reportsToDisplay = reportsToDisplay.filter(
@@ -144,24 +154,23 @@ function getOrderedReportIDs(
}
// There are a few properties that need to be calculated for the report which are used when sorting reports.
reportsToDisplay.forEach((reportToDisplay) => {
- let report = reportToDisplay as OnyxEntry;
- if (report) {
- report = {
- ...report,
- displayName: ReportUtils.getReportName(report),
- };
- }
+ const report = reportToDisplay as OnyxEntry;
+ const miniReport: MiniReport = {
+ reportID: report?.reportID,
+ displayName: ReportUtils.getReportName(report),
+ lastVisibleActionCreated: report?.lastVisibleActionCreated,
+ };
const isPinned = report?.isPinned ?? false;
const reportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '-1', report?.parentReportActionID ?? '-1');
if (isPinned || ReportUtils.requiresAttentionFromCurrentUser(report, reportAction)) {
- pinnedAndGBRReports.push(report);
+ pinnedAndGBRReports.push(miniReport);
} else if (hasValidDraftComment(report?.reportID ?? '-1')) {
- draftReports.push(report);
+ draftReports.push(miniReport);
} else if (ReportUtils.isArchivedRoom(report)) {
- archivedReports.push(report);
+ archivedReports.push(miniReport);
} else {
- nonArchivedReports.push(report);
+ nonArchivedReports.push(miniReport);
}
});
diff --git a/src/libs/actions/Policy/Tag.ts b/src/libs/actions/Policy/Tag.ts
index 85080d741011..a8607ca8f5f9 100644
--- a/src/libs/actions/Policy/Tag.ts
+++ b/src/libs/actions/Policy/Tag.ts
@@ -1,7 +1,7 @@
import type {NullishDeep, OnyxCollection, OnyxEntry} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import * as API from '@libs/API';
-import type {EnablePolicyTagsParams, OpenPolicyTagsPageParams, RenamePolicyTaglistParams, RenamePolicyTagsParams, SetPolicyTagsEnabled} from '@libs/API/parameters';
+import type {EnablePolicyTagsParams, OpenPolicyTagsPageParams, RenamePolicyTaglistParams, RenamePolicyTagsParams, SetPolicyTagsEnabled, SetPolicyTagsRequired} from '@libs/API/parameters';
import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
import * as ErrorUtils from '@libs/ErrorUtils';
import getIsNarrowLayout from '@libs/getIsNarrowLayout';
@@ -161,6 +161,7 @@ function createPolicyTag(policyID: string, tagName: string) {
tags: {
[newTagName]: {
errors: ErrorUtils.getMicroSecondOnyxError('workspace.tags.genericFailureMessage'),
+ pendingAction: null,
},
},
},
@@ -329,8 +330,8 @@ function deletePolicyTags(policyID: string, tagsToDelete: string[]) {
API.write(WRITE_COMMANDS.DELETE_POLICY_TAGS, parameters, onyxData);
}
-function clearPolicyTagErrors(policyID: string, tagName: string) {
- const tagListName = Object.keys(allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {})[0];
+function clearPolicyTagErrors(policyID: string, tagName: string, tagListIndex: number) {
+ const tagListName = Object.keys(allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {})[tagListIndex];
const tag = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`]?.[tagListName].tags?.[tagName];
if (!tag) {
return;
@@ -359,10 +360,25 @@ function clearPolicyTagErrors(policyID: string, tagName: string) {
});
}
+function clearPolicyTagListError(policyID: string, tagListIndex: number, errorField: string) {
+ const policyTag = PolicyUtils.getTagLists(allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {})?.[tagListIndex] ?? {};
+
+ if (!policyTag.name) {
+ return;
+ }
+
+ Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {
+ [policyTag.name]: {
+ errorFields: {
+ [errorField]: null,
+ },
+ },
+ });
+}
+
function renamePolicyTag(policyID: string, policyTag: {oldName: string; newName: string}, tagListIndex: number) {
const tagList = PolicyUtils.getTagLists(allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {})?.[tagListIndex] ?? {};
const tag = tagList.tags?.[policyTag.oldName];
-
const oldTagName = policyTag.oldName;
const newTagName = PolicyUtils.escapeTagName(policyTag.newName);
const onyxData: OnyxData = {
@@ -611,15 +627,75 @@ function setPolicyRequiresTag(policyID: string, requiresTag: boolean) {
API.write(WRITE_COMMANDS.SET_POLICY_REQUIRES_TAG, parameters, onyxData);
}
+function setPolicyTagsRequired(policyID: string, requiresTag: boolean, tagListIndex: number) {
+ const policyTag = PolicyUtils.getTagLists(allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {})?.[tagListIndex] ?? {};
+
+ if (!policyTag.name) {
+ return;
+ }
+
+ const onyxData: OnyxData = {
+ optimisticData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`,
+ value: {
+ [policyTag.name]: {
+ required: requiresTag,
+ pendingFields: {required: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE},
+ errorFields: {required: null},
+ },
+ },
+ },
+ ],
+ successData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`,
+ value: {
+ [policyTag.name]: {
+ pendingFields: {required: null},
+ },
+ },
+ },
+ ],
+ failureData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`,
+ value: {
+ [policyTag.name]: {
+ required: policyTag.required,
+ pendingFields: {required: null},
+ errorFields: {
+ required: ErrorUtils.getMicroSecondOnyxError('workspace.tags.genericFailureMessage'),
+ },
+ },
+ },
+ },
+ ],
+ };
+
+ const parameters: SetPolicyTagsRequired = {
+ policyID,
+ tagListIndex,
+ requireTagList: requiresTag,
+ };
+
+ API.write(WRITE_COMMANDS.SET_POLICY_TAGS_REQUIRED, parameters, onyxData);
+}
+
export {
openPolicyTagsPage,
buildOptimisticPolicyRecentlyUsedTags,
setPolicyRequiresTag,
+ setPolicyTagsRequired,
renamePolicyTaglist,
enablePolicyTags,
createPolicyTag,
renamePolicyTag,
clearPolicyTagErrors,
+ clearPolicyTagListError,
deletePolicyTags,
setWorkspaceTagEnabled,
};
diff --git a/src/pages/home/report/SystemChatReportFooterMessage.tsx b/src/pages/home/report/SystemChatReportFooterMessage.tsx
index e323818f5d59..d75158ed2f0c 100644
--- a/src/pages/home/report/SystemChatReportFooterMessage.tsx
+++ b/src/pages/home/report/SystemChatReportFooterMessage.tsx
@@ -70,7 +70,14 @@ function SystemChatReportFooterMessage({choice, policies, activePolicyID}: Syste
containerStyles={[styles.chatFooterBanner]}
shouldShowIcon
icon={Expensicons.Lightbulb}
- content={{content}}
+ content={
+
+ {content}
+
+ }
/>
);
}
diff --git a/src/pages/iou/request/step/IOURequestStepParticipants.tsx b/src/pages/iou/request/step/IOURequestStepParticipants.tsx
index dc769ce76682..66591246434d 100644
--- a/src/pages/iou/request/step/IOURequestStepParticipants.tsx
+++ b/src/pages/iou/request/step/IOURequestStepParticipants.tsx
@@ -1,3 +1,4 @@
+import {useIsFocused} from '@react-navigation/core';
import React, {useCallback, useEffect, useMemo, useRef} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
@@ -43,6 +44,7 @@ function IOURequestStepParticipants({
const participants = transaction?.participants;
const {translate} = useLocalize();
const styles = useThemeStyles();
+ const isFocused = useIsFocused();
// We need to set selectedReportID if user has navigated back from confirmation page and navigates to confirmation page with already selected participant
const selectedReportID = useRef(participants?.length === 1 ? participants[0]?.reportID ?? reportID : reportID);
@@ -140,6 +142,15 @@ function IOURequestStepParticipants({
IOUUtils.navigateToStartMoneyRequestStep(iouRequestType, iouType, transactionID, reportID, action);
}, [iouRequestType, iouType, transactionID, reportID, action]);
+ useEffect(() => {
+ const isCategorizing = action === CONST.IOU.ACTION.CATEGORIZE;
+ const isShareAction = action === CONST.IOU.ACTION.SHARE;
+ if (isFocused && (isCategorizing || isShareAction)) {
+ IOU.setMoneyRequestParticipants(transactionID, []);
+ numberOfParticipants.current = 0;
+ }
+ }, [isFocused, action, transactionID]);
+
return (
Tag.clearPolicyTagErrors(route.params.policyID, route.params.tagName)}
+ onClose={() => Tag.clearPolicyTagErrors(route.params.policyID, route.params.tagName, route.params.orderWeight)}
>
diff --git a/src/pages/workspace/tags/WorkspaceTagsPage.tsx b/src/pages/workspace/tags/WorkspaceTagsPage.tsx
index d9f52b917b25..0c9da8fbe90e 100644
--- a/src/pages/workspace/tags/WorkspaceTagsPage.tsx
+++ b/src/pages/workspace/tags/WorkspaceTagsPage.tsx
@@ -350,7 +350,7 @@ function WorkspaceTagsPage({route}: WorkspaceTagsPageProps) {
customListHeader={getCustomListHeader()}
shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()}
listHeaderWrapperStyle={[styles.ph9, styles.pv3, styles.pb5]}
- onDismissError={(item) => Tag.clearPolicyTagErrors(policyID, item.value)}
+ onDismissError={(item) => !isMultiLevelTags && Tag.clearPolicyTagErrors(policyID, item.value, 0)}
listHeaderContent={isSmallScreenWidth ? getHeaderText() : null}
showScrollIndicator={false}
/>
diff --git a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx
index bc6fcef46c0c..f889c34b66d1 100644
--- a/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx
+++ b/src/pages/workspace/tags/WorkspaceViewTagsPage.tsx
@@ -27,6 +27,7 @@ import * as PolicyUtils from '@libs/PolicyUtils';
import type {SettingsNavigatorParamList} from '@navigation/types';
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
+import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow';
import * as Tag from '@userActions/Policy/Tag';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
@@ -65,10 +66,9 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
setSelectedTags({});
}, [isFocused]);
- const policyTagList = useMemo(() => PolicyUtils.getTagLists(policyTags).find((policyTag) => policyTag.name === currentTagListName), [currentTagListName, policyTags]);
const tagList = useMemo(
() =>
- Object.values(policyTagList?.tags ?? {})
+ Object.values(currentPolicyTag?.tags ?? {})
.sort((tagA, tagB) => localeCompare(tagA.name, tagB.name))
.map((tag) => ({
value: tag.name,
@@ -81,7 +81,7 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
isDisabled: tag.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
rightElement: ,
})),
- [policyTagList, selectedTags, translate],
+ [currentPolicyTag, selectedTags, translate],
);
const tagListKeyedByName = useMemo(
@@ -234,6 +234,18 @@ function WorkspaceViewTagsPage({route}: WorkspaceViewTagsProps) {
cancelText={translate('common.cancel')}
danger
/>
+
+ Tag.setPolicyTagsRequired(policyID, on, route.params.orderWeight)}
+ pendingAction={currentPolicyTag.pendingFields?.required}
+ errors={currentPolicyTag?.errorFields?.required ?? undefined}
+ onCloseError={() => Tag.clearPolicyTagListError(policyID, route.params.orderWeight, 'required')}
+ disabled={!currentPolicyTag?.required && !Object.values(currentPolicyTag?.tags ?? {}).some((tag) => tag.enabled)}
+ />
+
Tag.clearPolicyTagErrors(policyID, item.value)}
+ onDismissError={(item) => {
+ Tag.clearPolicyTagErrors(policyID, item.value, route.params.orderWeight);
+ }}
/>
)}
diff --git a/src/types/onyx/PolicyTag.ts b/src/types/onyx/PolicyTag.ts
index 467ba3271981..ec552515ec32 100644
--- a/src/types/onyx/PolicyTag.ts
+++ b/src/types/onyx/PolicyTag.ts
@@ -55,6 +55,9 @@ type PolicyTagList = Record<
/** A list of errors keyed by microtime */
errors?: OnyxCommon.Errors;
+
+ /** Error objects keyed by field name containing errors keyed by microtime */
+ errorFields?: OnyxCommon.ErrorFields;
}>
>;