From 56b504f39bd6db2109c49bd87294aeb7ece8b442 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 2 Jul 2024 15:04:06 +0200 Subject: [PATCH 01/55] create bare NamePage --- src/pages/workspace/reportFields/NamePage.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/pages/workspace/reportFields/NamePage.tsx diff --git a/src/pages/workspace/reportFields/NamePage.tsx b/src/pages/workspace/reportFields/NamePage.tsx new file mode 100644 index 0000000000000..9eec25bcc8ddb --- /dev/null +++ b/src/pages/workspace/reportFields/NamePage.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import Text from '@components/Text'; + +function NamePage() { + return Coming soon...; +} + +export default NamePage; From e943bf6097ae4e29754efff78c0d0dc010184332 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 2 Jul 2024 15:04:15 +0200 Subject: [PATCH 02/55] create bare TypePage --- src/pages/workspace/reportFields/TypePage.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/pages/workspace/reportFields/TypePage.tsx diff --git a/src/pages/workspace/reportFields/TypePage.tsx b/src/pages/workspace/reportFields/TypePage.tsx new file mode 100644 index 0000000000000..e83539fcbfb7c --- /dev/null +++ b/src/pages/workspace/reportFields/TypePage.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import Text from '@components/Text'; + +function TypePage() { + return Coming soon...; +} + +export default TypePage; From dd40132fab0f30cae7f5fa87d96c59550ef020df Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 2 Jul 2024 15:04:20 +0200 Subject: [PATCH 03/55] create bare InitialValuePage --- src/pages/workspace/reportFields/InitialValuePage.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/pages/workspace/reportFields/InitialValuePage.tsx diff --git a/src/pages/workspace/reportFields/InitialValuePage.tsx b/src/pages/workspace/reportFields/InitialValuePage.tsx new file mode 100644 index 0000000000000..2f98e92499736 --- /dev/null +++ b/src/pages/workspace/reportFields/InitialValuePage.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import Text from '@components/Text'; + +function InitialValuePage() { + return Coming soon...; +} + +export default InitialValuePage; From af0cec5ac3397d1e41bb89dc266d977ac3fa9610 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 2 Jul 2024 15:05:03 +0200 Subject: [PATCH 04/55] create EditReportFieldPage --- src/libs/WorkspaceReportFieldsUtils.ts | 15 ++- .../reportFields/EditReportFieldPage.tsx | 93 +++++++++++++++++++ src/pages/workspace/withPolicy.tsx | 1 + 3 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 src/pages/workspace/reportFields/EditReportFieldPage.tsx diff --git a/src/libs/WorkspaceReportFieldsUtils.ts b/src/libs/WorkspaceReportFieldsUtils.ts index 0cc3cae24a238..bed3148ad1e65 100644 --- a/src/libs/WorkspaceReportFieldsUtils.ts +++ b/src/libs/WorkspaceReportFieldsUtils.ts @@ -3,7 +3,7 @@ import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import type ONYXKEYS from '@src/ONYXKEYS'; import type {InputID} from '@src/types/form/WorkspaceReportFieldsForm'; -import type {PolicyReportFieldType} from '@src/types/onyx/Policy'; +import type {PolicyReportField, PolicyReportFieldType} from '@src/types/onyx/Policy'; import * as ErrorUtils from './ErrorUtils'; import * as Localize from './Localize'; import * as ValidationUtils from './ValidationUtils'; @@ -67,4 +67,15 @@ function generateFieldID(name: string) { return `field_id_${name.replace(CONST.REGEX.ANY_SPACE, '_').toUpperCase()}`; } -export {getReportFieldTypeTranslationKey, getReportFieldAlternativeTextTranslationKey, validateReportFieldListValueName, generateFieldID}; +/** + * Gets the initial value for a report field. + */ +function getReportFieldInitialValue(reportField: PolicyReportField): string { + if (reportField.type === CONST.REPORT_FIELD_TYPES.LIST) { + return reportField.defaultValue ?? ''; + } + + return reportField.value ?? reportField.defaultValue; +} + +export {getReportFieldTypeTranslationKey, getReportFieldAlternativeTextTranslationKey, validateReportFieldListValueName, generateFieldID, getReportFieldInitialValue}; diff --git a/src/pages/workspace/reportFields/EditReportFieldPage.tsx b/src/pages/workspace/reportFields/EditReportFieldPage.tsx new file mode 100644 index 0000000000000..1c724d3434df6 --- /dev/null +++ b/src/pages/workspace/reportFields/EditReportFieldPage.tsx @@ -0,0 +1,93 @@ +import type {StackScreenProps} from '@react-navigation/stack'; +import {Str} from 'expensify-common'; +import React, {useMemo} from 'react'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import {getReportFieldInitialValue, getReportFieldTypeTranslationKey} from '@libs/WorkspaceReportFieldsUtils'; +import type {SettingsNavigatorParamList} from '@navigation/types'; +import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading'; +import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; +import CONST from '@src/CONST'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; + +type EditReportFieldPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; + +function EditReportFieldPage({ + policy, + route: { + params: {policyID, reportFieldName}, + }, +}: EditReportFieldPageProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const reportField = useMemo(() => Object.values(policy?.fieldList ?? {}).find((field) => field.name === reportFieldName) ?? null, [policy, reportFieldName]); + + if (!reportField) { + return ; + } + + return ( + + + + + Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD_NAME.getRoute(`${policyID}`, reportFieldName))} + /> + Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD_TYPE.getRoute(`${policyID}`, reportFieldName))} + /> + Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE.getRoute(`${policyID}`, reportFieldName))} + /> + + {reportField.type === CONST.REPORT_FIELD_TYPES.LIST && ( + Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELD_LIST_VALUES.getRoute(policyID))} + /> + )} + + + ); +} + +EditReportFieldPage.displayName = 'EditReportFieldPage'; + +export default withPolicyAndFullscreenLoading(EditReportFieldPage); diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index 64ebb34e2a5cf..bbe0d40df8476 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -38,6 +38,7 @@ type PolicyRoute = RouteProp< | typeof SCREENS.WORKSPACE.DISTANCE_RATE_TAX_RECLAIMABLE_ON_EDIT | typeof SCREENS.WORKSPACE.REPORT_FIELDS_CREATE | typeof SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES + | typeof SCREENS.WORKSPACE.REPORT_FIELDS_EDIT >; function getPolicyIDFromRoute(route: PolicyRoute): string { From cddeaf96b25dc53ba897328033cda7b9599144e4 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 2 Jul 2024 15:05:52 +0200 Subject: [PATCH 05/55] connect screens to navigation --- src/ROUTES.ts | 16 +++++++++++++ src/SCREENS.ts | 4 ++++ .../ModalStackNavigators/index.tsx | 4 ++++ .../FULL_SCREEN_TO_RHP_MAPPING.ts | 4 ++++ src/libs/Navigation/linkingConfig/config.ts | 24 +++++++++++++++++++ src/libs/Navigation/types.ts | 16 +++++++++++++ .../WorkspaceReportFieldsPage.tsx | 2 +- 7 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 4ea46607a3820..c6090b9ae694a 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -803,6 +803,22 @@ const ROUTES = { route: 'settings/workspaces/:policyID/reportFields/new/:valueIndex/edit', getRoute: (policyID: string, valueIndex: number) => `settings/workspaces/${policyID}/reportFields/new/${valueIndex}/edit` as const, }, + WORKSPACE_EDIT_REPORT_FIELD: { + route: 'settings/workspaces/:policyID/reportFields/:reportFieldName/edit', + getRoute: (policyID: string, reportFieldName: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldName)}/edit` as const, + }, + WORKSPACE_EDIT_REPORT_FIELD_NAME: { + route: 'settings/workspaces/:policyID/reportFields/:reportFieldName/edit/name', + getRoute: (policyID: string, reportFieldName: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldName)}/edit/name` as const, + }, + WORKSPACE_EDIT_REPORT_FIELD_TYPE: { + route: 'settings/workspaces/:policyID/reportFields/:reportFieldName/edit/type', + getRoute: (policyID: string, reportFieldName: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldName)}/edit/type` as const, + }, + WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE: { + route: 'settings/workspaces/:policyID/reportFields/:reportFieldName/edit/initialValue', + getRoute: (policyID: string, reportFieldName: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldName)}/edit/initialValue` as const, + }, // TODO: uncomment after development is done // WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW: { // route: 'settings/workspaces/:policyID/expensify-card/issues-new', diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 79f35298655b8..29f02bf4f5512 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -317,6 +317,10 @@ const SCREENS = { REPORT_FIELDS_ADD_VALUE: 'Workspace_ReportFields_AddValue', REPORT_FIELDS_VALUE_SETTINGS: 'Workspace_ReportFields_ValueSettings', REPORT_FIELDS_EDIT_VALUE: 'Workspace_ReportFields_EditValue', + REPORT_FIELDS_EDIT: 'Workspace_ReportFields_Edit', + REPORT_FIELDS_EDIT_NAME: 'Workspace_ReportFields_EditName', + REPORT_FIELDS_EDIT_TYPE: 'Workspace_ReportFields_EditType', + REPORT_FIELDS_EDIT_INITIAL_VALUE: 'Workspace_ReportFields_EditInitialValue', TAX_EDIT: 'Workspace_Tax_Edit', TAX_NAME: 'Workspace_Tax_Name', TAX_VALUE: 'Workspace_Tax_Value', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index e63f62192fa12..15fab0b32d0e3 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -365,6 +365,10 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/reportFields/WorkspaceAddValuePage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS]: () => require('../../../../pages/workspace/reportFields/ValueSettingsPage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE]: () => require('../../../../pages/workspace/reportFields/EditValuePage').default, + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT]: () => require('../../../../pages/workspace/reportFields/EditReportFieldPage').default, + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_NAME]: () => require('../../../../pages/workspace/reportFields/NamePage').default, + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_TYPE]: () => require('../../../../pages/workspace/reportFields/TypePage').default, + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: () => require('../../../../pages/workspace/reportFields/InitialValuePage').default, }); const EnablePaymentsStackNavigator = createModalStackNavigator({ diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts index 4f481f912d7ae..6f56285037d0c 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -107,6 +107,10 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE, SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS, SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE, + SCREENS.WORKSPACE.REPORT_FIELDS_EDIT, + SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_NAME, + SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_TYPE, + SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE, ], [SCREENS.WORKSPACE.EXPENSIFY_CARD]: [], }; diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 68b83e288df63..ba35855e7be69 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -539,6 +539,30 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE]: { path: ROUTES.WORKSPACE_REPORT_FIELD_EDIT_VALUE.route, }, + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT]: { + path: ROUTES.WORKSPACE_EDIT_REPORT_FIELD.route, + parse: { + reportFieldName: (reportFieldName: string) => decodeURIComponent(reportFieldName), + }, + }, + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_NAME]: { + path: ROUTES.WORKSPACE_EDIT_REPORT_FIELD_NAME.route, + parse: { + reportFieldName: (reportFieldName: string) => decodeURIComponent(reportFieldName), + }, + }, + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_TYPE]: { + path: ROUTES.WORKSPACE_EDIT_REPORT_FIELD_TYPE.route, + parse: { + reportFieldName: (reportFieldName: string) => decodeURIComponent(reportFieldName), + }, + }, + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: { + path: ROUTES.WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE.route, + parse: { + reportFieldName: (reportFieldName: string) => decodeURIComponent(reportFieldName), + }, + }, [SCREENS.REIMBURSEMENT_ACCOUNT]: { path: ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.route, exact: true, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index f499c5c8fce49..106f991694d4d 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -285,6 +285,22 @@ type SettingsNavigatorParamList = { policyID: string; valueIndex: number; }; + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT]: { + policyID: string; + reportFieldName: string; + }; + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_NAME]: { + policyID: string; + reportFieldName: string; + }; + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_TYPE]: { + policyID: string; + reportFieldName: string; + }; + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: { + policyID: string; + reportFieldName: string; + }; [SCREENS.WORKSPACE.MEMBER_DETAILS]: { policyID: string; accountID: string; diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx index eeeeab32b54d2..4265b1d2b2cf5 100644 --- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx @@ -158,7 +158,7 @@ function WorkspaceReportFieldsPage({ canSelectMultiple sections={[{data: reportFieldsList, isDisabled: false}]} onCheckboxPress={updateSelectedReportFields} - onSelectRow={() => {}} + onSelectRow={(item: ReportFieldForList) => Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD.getRoute(policyID, item.value))} onSelectAll={() => {}} ListItem={TableListItem} customListHeader={getCustomListHeader()} From 7631cca974f1bc597e9f2aebab33b814e3e0c667 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 2 Jul 2024 15:06:11 +0200 Subject: [PATCH 06/55] create bare setters --- src/libs/actions/Policy/ReportFields.ts | 34 ++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Policy/ReportFields.ts b/src/libs/actions/Policy/ReportFields.ts index f94e2bf185f5f..c90396c413877 100644 --- a/src/libs/actions/Policy/ReportFields.ts +++ b/src/libs/actions/Policy/ReportFields.ts @@ -10,6 +10,7 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {WorkspaceReportFieldsForm} from '@src/types/form/WorkspaceReportFieldsForm'; import INPUT_IDS from '@src/types/form/WorkspaceReportFieldsForm'; import type {Policy, PolicyReportField} from '@src/types/onyx'; +import type {PolicyReportFieldType} from '@src/types/onyx/Policy'; import type {OnyxData} from '@src/types/onyx/Request'; let listValues: string[]; @@ -176,6 +177,37 @@ function createReportField(policyID: string, {name, type, initialValue}: CreateR API.write(WRITE_COMMANDS.CREATE_WORKSPACE_REPORT_FIELD, parameters, onyxData); } +/** + * Renames a report field. + */ +function renameReportField(policyID: string, reportFieldName: string, newName: string) { + console.debug('renameReportField', policyID, reportFieldName, newName); +} + +/** + * Updates the type of a report field. + */ +function updatePolicyReportFieldType(policyID: string, reportFieldName: string, newType: PolicyReportFieldType) { + console.debug('updatePolicyReportFieldType', policyID, reportFieldName, newType); +} + +/** + * Updates the initial value of a report field. + */ +function updatePolicyReportFieldInitialValue(policyID: string, reportFieldName: string, newInitialValue: string) { + console.debug('updatePolicyReportFieldInitialValue', policyID, reportFieldName, newInitialValue); +} + export type {CreateReportFieldArguments}; -export {setInitialCreateReportFieldsForm, createReportFieldsListValue, renameReportFieldsListValue, setReportFieldsListValueEnabled, deleteReportFieldsListValue, createReportField}; +export { + setInitialCreateReportFieldsForm, + createReportFieldsListValue, + renameReportFieldsListValue, + setReportFieldsListValueEnabled, + deleteReportFieldsListValue, + createReportField, + renameReportField, + updatePolicyReportFieldType, + updatePolicyReportFieldInitialValue, +}; From 143964fe8cd15622028e1ede652d2e388b92d6e8 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 2 Jul 2024 17:31:31 +0200 Subject: [PATCH 07/55] remove name and type editing pages --- src/ROUTES.ts | 8 ------- src/SCREENS.ts | 2 -- .../ModalStackNavigators/index.tsx | 2 -- .../FULL_SCREEN_TO_RHP_MAPPING.ts | 2 -- src/libs/Navigation/linkingConfig/config.ts | 12 ---------- src/libs/Navigation/types.ts | 8 ------- .../reportFields/EditReportFieldPage.tsx | 24 ++++++++++--------- src/pages/workspace/reportFields/NamePage.tsx | 8 ------- src/pages/workspace/reportFields/TypePage.tsx | 8 ------- 9 files changed, 13 insertions(+), 61 deletions(-) delete mode 100644 src/pages/workspace/reportFields/NamePage.tsx delete mode 100644 src/pages/workspace/reportFields/TypePage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index c6090b9ae694a..ff72bfab02836 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -807,14 +807,6 @@ const ROUTES = { route: 'settings/workspaces/:policyID/reportFields/:reportFieldName/edit', getRoute: (policyID: string, reportFieldName: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldName)}/edit` as const, }, - WORKSPACE_EDIT_REPORT_FIELD_NAME: { - route: 'settings/workspaces/:policyID/reportFields/:reportFieldName/edit/name', - getRoute: (policyID: string, reportFieldName: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldName)}/edit/name` as const, - }, - WORKSPACE_EDIT_REPORT_FIELD_TYPE: { - route: 'settings/workspaces/:policyID/reportFields/:reportFieldName/edit/type', - getRoute: (policyID: string, reportFieldName: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldName)}/edit/type` as const, - }, WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE: { route: 'settings/workspaces/:policyID/reportFields/:reportFieldName/edit/initialValue', getRoute: (policyID: string, reportFieldName: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldName)}/edit/initialValue` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 29f02bf4f5512..7f459b3cf258e 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -318,8 +318,6 @@ const SCREENS = { REPORT_FIELDS_VALUE_SETTINGS: 'Workspace_ReportFields_ValueSettings', REPORT_FIELDS_EDIT_VALUE: 'Workspace_ReportFields_EditValue', REPORT_FIELDS_EDIT: 'Workspace_ReportFields_Edit', - REPORT_FIELDS_EDIT_NAME: 'Workspace_ReportFields_EditName', - REPORT_FIELDS_EDIT_TYPE: 'Workspace_ReportFields_EditType', REPORT_FIELDS_EDIT_INITIAL_VALUE: 'Workspace_ReportFields_EditInitialValue', TAX_EDIT: 'Workspace_Tax_Edit', TAX_NAME: 'Workspace_Tax_Name', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 15fab0b32d0e3..10168b9272578 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -366,8 +366,6 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/reportFields/ValueSettingsPage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE]: () => require('../../../../pages/workspace/reportFields/EditValuePage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT]: () => require('../../../../pages/workspace/reportFields/EditReportFieldPage').default, - [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_NAME]: () => require('../../../../pages/workspace/reportFields/NamePage').default, - [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_TYPE]: () => require('../../../../pages/workspace/reportFields/TypePage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: () => require('../../../../pages/workspace/reportFields/InitialValuePage').default, }); diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts index 6f56285037d0c..988986a9f0679 100755 --- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts @@ -108,8 +108,6 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = { SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS, SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE, SCREENS.WORKSPACE.REPORT_FIELDS_EDIT, - SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_NAME, - SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_TYPE, SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE, ], [SCREENS.WORKSPACE.EXPENSIFY_CARD]: [], diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index ba35855e7be69..eeec5d1083e55 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -545,18 +545,6 @@ const config: LinkingOptions['config'] = { reportFieldName: (reportFieldName: string) => decodeURIComponent(reportFieldName), }, }, - [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_NAME]: { - path: ROUTES.WORKSPACE_EDIT_REPORT_FIELD_NAME.route, - parse: { - reportFieldName: (reportFieldName: string) => decodeURIComponent(reportFieldName), - }, - }, - [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_TYPE]: { - path: ROUTES.WORKSPACE_EDIT_REPORT_FIELD_TYPE.route, - parse: { - reportFieldName: (reportFieldName: string) => decodeURIComponent(reportFieldName), - }, - }, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: { path: ROUTES.WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE.route, parse: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 106f991694d4d..d2123d8733336 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -289,14 +289,6 @@ type SettingsNavigatorParamList = { policyID: string; reportFieldName: string; }; - [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_NAME]: { - policyID: string; - reportFieldName: string; - }; - [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_TYPE]: { - policyID: string; - reportFieldName: string; - }; [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: { policyID: string; reportFieldName: string; diff --git a/src/pages/workspace/reportFields/EditReportFieldPage.tsx b/src/pages/workspace/reportFields/EditReportFieldPage.tsx index 1c724d3434df6..a7d2ac9ceecdf 100644 --- a/src/pages/workspace/reportFields/EditReportFieldPage.tsx +++ b/src/pages/workspace/reportFields/EditReportFieldPage.tsx @@ -52,32 +52,34 @@ function EditReportFieldPage({ /> Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD_NAME.getRoute(`${policyID}`, reportFieldName))} + title={reportField.name} + description={translate('common.name')} + interactive={false} /> + Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD_TYPE.getRoute(`${policyID}`, reportFieldName))} + title={Str.recapitalize(translate(getReportFieldTypeTranslationKey(reportField.type)))} + description={translate('common.type')} + interactive={false} /> + Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE.getRoute(`${policyID}`, reportFieldName))} /> {reportField.type === CONST.REPORT_FIELD_TYPES.LIST && ( Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELD_LIST_VALUES.getRoute(policyID))} diff --git a/src/pages/workspace/reportFields/NamePage.tsx b/src/pages/workspace/reportFields/NamePage.tsx deleted file mode 100644 index 9eec25bcc8ddb..0000000000000 --- a/src/pages/workspace/reportFields/NamePage.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import Text from '@components/Text'; - -function NamePage() { - return Coming soon...; -} - -export default NamePage; diff --git a/src/pages/workspace/reportFields/TypePage.tsx b/src/pages/workspace/reportFields/TypePage.tsx deleted file mode 100644 index e83539fcbfb7c..0000000000000 --- a/src/pages/workspace/reportFields/TypePage.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import Text from '@components/Text'; - -function TypePage() { - return Coming soon...; -} - -export default TypePage; From ce74ea81a703e9e173c1744b6e681a634bdcc345 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 2 Jul 2024 17:46:42 +0200 Subject: [PATCH 08/55] use reportFieldID --- src/ROUTES.ts | 8 ++++---- src/libs/Navigation/linkingConfig/config.ts | 4 ++-- src/libs/Navigation/types.ts | 4 ++-- src/pages/workspace/reportFields/EditReportFieldPage.tsx | 7 ++++--- .../workspace/reportFields/WorkspaceReportFieldsPage.tsx | 2 +- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index ff72bfab02836..290b0ecdfd30d 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -804,12 +804,12 @@ const ROUTES = { getRoute: (policyID: string, valueIndex: number) => `settings/workspaces/${policyID}/reportFields/new/${valueIndex}/edit` as const, }, WORKSPACE_EDIT_REPORT_FIELD: { - route: 'settings/workspaces/:policyID/reportFields/:reportFieldName/edit', - getRoute: (policyID: string, reportFieldName: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldName)}/edit` as const, + route: 'settings/workspaces/:policyID/reportFields/:reportFieldID/edit', + getRoute: (policyID: string, reportFieldID: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldID)}/edit` as const, }, WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE: { - route: 'settings/workspaces/:policyID/reportFields/:reportFieldName/edit/initialValue', - getRoute: (policyID: string, reportFieldName: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldName)}/edit/initialValue` as const, + route: 'settings/workspaces/:policyID/reportFields/:reportFieldID/edit/initialValue', + getRoute: (policyID: string, reportFieldID: string) => `settings/workspaces/${policyID}/reportFields/${encodeURIComponent(reportFieldID)}/edit/initialValue` as const, }, // TODO: uncomment after development is done // WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW: { diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index eeec5d1083e55..47a34a829f40e 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -542,13 +542,13 @@ const config: LinkingOptions['config'] = { [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT]: { path: ROUTES.WORKSPACE_EDIT_REPORT_FIELD.route, parse: { - reportFieldName: (reportFieldName: string) => decodeURIComponent(reportFieldName), + reportFieldID: (reportFieldID: string) => decodeURIComponent(reportFieldID), }, }, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: { path: ROUTES.WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE.route, parse: { - reportFieldName: (reportFieldName: string) => decodeURIComponent(reportFieldName), + reportFieldID: (reportFieldID: string) => decodeURIComponent(reportFieldID), }, }, [SCREENS.REIMBURSEMENT_ACCOUNT]: { diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index d2123d8733336..ff8c1d1eb0388 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -287,11 +287,11 @@ type SettingsNavigatorParamList = { }; [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT]: { policyID: string; - reportFieldName: string; + reportFieldID: string; }; [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: { policyID: string; - reportFieldName: string; + reportFieldID: string; }; [SCREENS.WORKSPACE.MEMBER_DETAILS]: { policyID: string; diff --git a/src/pages/workspace/reportFields/EditReportFieldPage.tsx b/src/pages/workspace/reportFields/EditReportFieldPage.tsx index a7d2ac9ceecdf..b70f3f9533986 100644 --- a/src/pages/workspace/reportFields/EditReportFieldPage.tsx +++ b/src/pages/workspace/reportFields/EditReportFieldPage.tsx @@ -7,6 +7,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; +import * as ReportUtils from '@libs/ReportUtils'; import {getReportFieldInitialValue, getReportFieldTypeTranslationKey} from '@libs/WorkspaceReportFieldsUtils'; import type {SettingsNavigatorParamList} from '@navigation/types'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; @@ -22,13 +23,13 @@ type EditReportFieldPageProps = WithPolicyAndFullscreenLoadingProps & StackScree function EditReportFieldPage({ policy, route: { - params: {policyID, reportFieldName}, + params: {policyID, reportFieldID}, }, }: EditReportFieldPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const reportField = useMemo(() => Object.values(policy?.fieldList ?? {}).find((field) => field.name === reportFieldName) ?? null, [policy, reportFieldName]); + const reportField = useMemo(() => policy?.fieldList?.[ReportUtils.getReportFieldKey(reportFieldID)] ?? null, [policy, reportFieldID]); if (!reportField) { return ; @@ -73,7 +74,7 @@ function EditReportFieldPage({ title={getReportFieldInitialValue(reportField)} description={translate('common.initialValue')} shouldShowRightIcon - onPress={() => Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE.getRoute(`${policyID}`, reportFieldName))} + onPress={() => Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE.getRoute(`${policyID}`, reportFieldID))} /> {reportField.type === CONST.REPORT_FIELD_TYPES.LIST && ( diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx index 4265b1d2b2cf5..6eef5a7941eff 100644 --- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx @@ -158,7 +158,7 @@ function WorkspaceReportFieldsPage({ canSelectMultiple sections={[{data: reportFieldsList, isDisabled: false}]} onCheckboxPress={updateSelectedReportFields} - onSelectRow={(item: ReportFieldForList) => Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD.getRoute(policyID, item.value))} + onSelectRow={(item: ReportFieldForList) => Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD.getRoute(policyID, item.fieldID))} onSelectAll={() => {}} ListItem={TableListItem} customListHeader={getCustomListHeader()} From 7c95c6dba35badad664298c6fa88563132f35610 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 3 Jul 2024 13:14:59 +0200 Subject: [PATCH 09/55] restrict initial value fore date type --- src/libs/WorkspaceReportFieldsUtils.ts | 4 ++++ src/pages/workspace/reportFields/EditReportFieldPage.tsx | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libs/WorkspaceReportFieldsUtils.ts b/src/libs/WorkspaceReportFieldsUtils.ts index bed3148ad1e65..b34a87b3acf08 100644 --- a/src/libs/WorkspaceReportFieldsUtils.ts +++ b/src/libs/WorkspaceReportFieldsUtils.ts @@ -75,6 +75,10 @@ function getReportFieldInitialValue(reportField: PolicyReportField): string { return reportField.defaultValue ?? ''; } + if (reportField.type === CONST.REPORT_FIELD_TYPES.DATE) { + return Localize.translateLocal('common.currentDate'); + } + return reportField.value ?? reportField.defaultValue; } diff --git a/src/pages/workspace/reportFields/EditReportFieldPage.tsx b/src/pages/workspace/reportFields/EditReportFieldPage.tsx index b70f3f9533986..b41f754250c5b 100644 --- a/src/pages/workspace/reportFields/EditReportFieldPage.tsx +++ b/src/pages/workspace/reportFields/EditReportFieldPage.tsx @@ -35,6 +35,9 @@ function EditReportFieldPage({ return ; } + const isDateFieldType = reportField.type === CONST.REPORT_FIELD_TYPES.DATE; + const isListFieldType = reportField.type === CONST.REPORT_FIELD_TYPES.LIST; + return ( Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE.getRoute(`${policyID}`, reportFieldID))} /> - {reportField.type === CONST.REPORT_FIELD_TYPES.LIST && ( + {isListFieldType && ( Date: Wed, 3 Jul 2024 13:58:54 +0200 Subject: [PATCH 10/55] create InitialListValuePicker --- .../ReportFieldsInitialListValuePicker.tsx | 45 +++++++++++++++++++ .../InitialListValueSelectorModal.tsx | 28 +++--------- 2 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 src/components/ReportFieldsInitialListValuePicker.tsx diff --git a/src/components/ReportFieldsInitialListValuePicker.tsx b/src/components/ReportFieldsInitialListValuePicker.tsx new file mode 100644 index 0000000000000..95b08599602bd --- /dev/null +++ b/src/components/ReportFieldsInitialListValuePicker.tsx @@ -0,0 +1,45 @@ +import React, {useMemo} from 'react'; +import SelectionList from './SelectionList'; +import RadioListItem from './SelectionList/RadioListItem'; + +type ReportFieldsInitialListValuePickerProps = { + /** Options to select from if field is of type list */ + listValues: string[]; + + /** Collection of flags that state whether list field options are disabled */ + disabledOptions: boolean[]; + + /** Selected value */ + currentValue: string; + + /** Function to call when the user selects a value */ + onValueSelected: (value: string) => void; +}; + +function ReportFieldsInitialListValuePicker({listValues, disabledOptions, currentValue, onValueSelected}: ReportFieldsInitialListValuePickerProps) { + const listValueOptions = useMemo( + () => + Object.values(listValues ?? {}) + .filter((listValue, index) => !disabledOptions[index]) + .map((listValue) => ({ + keyForList: listValue, + value: listValue, + isSelected: currentValue === listValue, + text: listValue, + })), + [currentValue, listValues, disabledOptions], + ); + + return ( + onValueSelected(item.value)} + initiallyFocusedOptionKey={listValueOptions.find((listValue) => listValue.isSelected)?.keyForList} + /> + ); +} + +ReportFieldsInitialListValuePicker.displayName = 'ReportFieldsInitialListValuePicker'; + +export default ReportFieldsInitialListValuePicker; diff --git a/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx b/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx index 4776bb1dd999a..7c27824c685ee 100644 --- a/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx +++ b/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx @@ -1,11 +1,10 @@ -import React, {useMemo} from 'react'; +import React from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Modal from '@components/Modal'; +import ReportFieldsInitialListValuePicker from '@components/ReportFieldsInitialListValuePicker'; import ScreenWrapper from '@components/ScreenWrapper'; -import SelectionList from '@components/SelectionList'; -import RadioListItem from '@components/SelectionList/RadioListItem'; import Text from '@components/Text'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; @@ -36,19 +35,6 @@ function InitialListValueSelectorModal({isVisible, currentValue, label, subtitle const [formDraft] = useOnyx(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM_DRAFT); - const listValueOptions = useMemo( - () => - Object.values(formDraft?.listValues ?? {}) - .filter((listValue, index) => !formDraft?.disabledListValues?.[index]) - .map((listValue) => ({ - keyForList: listValue, - value: listValue, - isSelected: currentValue === listValue, - text: listValue, - })), - [currentValue, formDraft?.disabledListValues, formDraft?.listValues], - ); - return ( {subtitle} - onValueSelected(item.value)} - initiallyFocusedOptionKey={listValueOptions.find((listValue) => listValue.isSelected)?.keyForList} + From 1d608890eb7d07f4975cc8548924d9f2e7ac9ab4 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 3 Jul 2024 13:59:56 +0200 Subject: [PATCH 11/55] add route to type --- src/pages/workspace/withPolicy.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/workspace/withPolicy.tsx b/src/pages/workspace/withPolicy.tsx index bbe0d40df8476..5129267e9407c 100644 --- a/src/pages/workspace/withPolicy.tsx +++ b/src/pages/workspace/withPolicy.tsx @@ -39,6 +39,7 @@ type PolicyRoute = RouteProp< | typeof SCREENS.WORKSPACE.REPORT_FIELDS_CREATE | typeof SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES | typeof SCREENS.WORKSPACE.REPORT_FIELDS_EDIT + | typeof SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE >; function getPolicyIDFromRoute(route: PolicyRoute): string { From 861bd0cf88804785e00cefd8f9a159ed229c2f70 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 3 Jul 2024 15:28:12 +0200 Subject: [PATCH 12/55] convert ReportFieldsInitialListValuePicker as a input picker --- src/components/Form/types.ts | 4 +- .../ReportFieldsInitialListValuePicker.tsx | 37 ++++++++++--------- .../InitialListValueSelectorModal.tsx | 5 +-- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/components/Form/types.ts b/src/components/Form/types.ts index afbe2bb124b5a..2de05698cd648 100644 --- a/src/components/Form/types.ts +++ b/src/components/Form/types.ts @@ -13,6 +13,7 @@ import type DatePicker from '@components/DatePicker'; import type EmojiPickerButtonDropdown from '@components/EmojiPicker/EmojiPickerButtonDropdown'; import type Picker from '@components/Picker'; import type RadioButtons from '@components/RadioButtons'; +import type ReportFieldsInitialListValuePicker from '@components/ReportFieldsInitialListValuePicker'; import type RoomNameInput from '@components/RoomNameInput'; import type SingleChoiceQuestion from '@components/SingleChoiceQuestion'; import type StateSelector from '@components/StateSelector'; @@ -47,7 +48,8 @@ type ValidInputs = | typeof AmountPicker | typeof TextPicker | typeof AddPlaidBankAccount - | typeof EmojiPickerButtonDropdown; + | typeof EmojiPickerButtonDropdown + | typeof ReportFieldsInitialListValuePicker; type ValueTypeKey = 'string' | 'boolean' | 'date' | 'country' | 'reportFields' | 'disabledListValues'; type ValueTypeMap = { diff --git a/src/components/ReportFieldsInitialListValuePicker.tsx b/src/components/ReportFieldsInitialListValuePicker.tsx index 95b08599602bd..45f6bd6dd9778 100644 --- a/src/components/ReportFieldsInitialListValuePicker.tsx +++ b/src/components/ReportFieldsInitialListValuePicker.tsx @@ -10,32 +10,35 @@ type ReportFieldsInitialListValuePickerProps = { disabledOptions: boolean[]; /** Selected value */ - currentValue: string; + value: string; /** Function to call when the user selects a value */ - onValueSelected: (value: string) => void; + onInputChange?: (value: string) => void; }; -function ReportFieldsInitialListValuePicker({listValues, disabledOptions, currentValue, onValueSelected}: ReportFieldsInitialListValuePickerProps) { - const listValueOptions = useMemo( - () => - Object.values(listValues ?? {}) - .filter((listValue, index) => !disabledOptions[index]) - .map((listValue) => ({ - keyForList: listValue, - value: listValue, - isSelected: currentValue === listValue, - text: listValue, - })), - [currentValue, listValues, disabledOptions], +function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, onInputChange}: ReportFieldsInitialListValuePickerProps) { + const listValueSections = useMemo( + () => [ + { + data: Object.values(listValues ?? {}) + .filter((listValue, index) => !disabledOptions[index]) + .map((listValue) => ({ + keyForList: listValue, + value: listValue, + isSelected: value === listValue, + text: listValue, + })), + }, + ], + [value, listValues, disabledOptions], ); return ( onValueSelected(item.value)} - initiallyFocusedOptionKey={listValueOptions.find((listValue) => listValue.isSelected)?.keyForList} + onSelectRow={(item) => onInputChange?.(item.value)} + initiallyFocusedOptionKey={listValueSections[0].data.find((listValue) => listValue.isSelected)?.keyForList} /> ); } diff --git a/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx b/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx index 7c27824c685ee..3b995f91dbf5b 100644 --- a/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx +++ b/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx @@ -58,12 +58,11 @@ function InitialListValueSelectorModal({isVisible, currentValue, label, subtitle {subtitle} - From cd47a6e57f3e043c18c725dbb8b50225521052d6 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 3 Jul 2024 15:28:30 +0200 Subject: [PATCH 13/55] integrate InitialValuePage --- .../reportFields/InitialValuePage.tsx | 140 +++++++++++++++++- 1 file changed, 135 insertions(+), 5 deletions(-) diff --git a/src/pages/workspace/reportFields/InitialValuePage.tsx b/src/pages/workspace/reportFields/InitialValuePage.tsx index 2f98e92499736..d536f6f60ccd6 100644 --- a/src/pages/workspace/reportFields/InitialValuePage.tsx +++ b/src/pages/workspace/reportFields/InitialValuePage.tsx @@ -1,8 +1,138 @@ -import React from 'react'; -import Text from '@components/Text'; +import type {StackScreenProps} from '@react-navigation/stack'; +import React, {useCallback} from 'react'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; +import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ReportFieldsInitialListValuePicker from '@components/ReportFieldsInitialListValuePicker'; +import ScreenWrapper from '@components/ScreenWrapper'; +import TextInput from '@components/TextInput'; +import useAutoFocusInput from '@hooks/useAutoFocusInput'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import * as ReportUtils from '@libs/ReportUtils'; +import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; +import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading'; +import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; +import CONST from '@src/CONST'; +import * as ErrorUtils from '@src/libs/ErrorUtils'; +import * as ValidationUtils from '@src/libs/ValidationUtils'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; +import INPUT_IDS from '@src/types/form/WorkspaceReportFieldsForm'; -function InitialValuePage() { - return Coming soon...; +type InitialValuePagePageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +function InitialValuePage({ + policy, + route: { + params: {policyID, reportFieldID}, + }, +}: InitialValuePagePageProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const {inputCallbackRef} = useAutoFocusInput(); + + const reportField = policy?.fieldList?.[ReportUtils.getReportFieldKey(reportFieldID)] ?? null; + const availableListValuesLength = (reportField?.disabledOptions ?? []).filter((disabledListValue) => !disabledListValue).length; + + const submitForm = useCallback( + (values: FormOnyxValues) => { + console.debug('submitForm', policyID, values); + Navigation.goBack(); + }, + [policyID], + ); + + const validateForm = useCallback( + (values: FormOnyxValues): FormInputErrors => { + const {name, type, initialValue} = values; + const errors: FormInputErrors = {}; + + if (!ValidationUtils.isRequiredFulfilled(name)) { + errors[INPUT_IDS.NAME] = translate('workspace.reportFields.reportFieldNameRequiredError'); + } else if (Object.values(policy?.fieldList ?? {}).some((currentReportField) => currentReportField.name === name)) { + errors[INPUT_IDS.NAME] = translate('workspace.reportFields.existingReportFieldNameError'); + } else if ([...name].length > CONST.WORKSPACE_REPORT_FIELD_POLICY_MAX_LENGTH) { + // Uses the spread syntax to count the number of Unicode code points instead of the number of UTF-16 code units. + ErrorUtils.addErrorMessage( + errors, + INPUT_IDS.NAME, + translate('common.error.characterLimitExceedCounter', {length: [...name].length, limit: CONST.WORKSPACE_REPORT_FIELD_POLICY_MAX_LENGTH}), + ); + } + + if (type === CONST.REPORT_FIELD_TYPES.LIST && availableListValuesLength > 0 && !ValidationUtils.isRequiredFulfilled(initialValue)) { + errors[INPUT_IDS.INITIAL_VALUE] = translate('workspace.reportFields.reportFieldInitialValueRequiredError'); + } + + return errors; + }, + [availableListValuesLength, policy?.fieldList, translate], + ); + + if (!reportField) { + return ; + } + + const isTextFieldType = reportField.type === CONST.REPORT_FIELD_TYPES.TEXT; + const isListFieldType = reportField.type === CONST.REPORT_FIELD_TYPES.LIST; + + return ( + + + + + {isTextFieldType && ( + + )} + {isListFieldType && ( + + )} + + + + ); } -export default InitialValuePage; +InitialValuePage.displayName = 'InitialValuePage'; + +export default withPolicyAndFullscreenLoading(InitialValuePage); From 75dc4911a8b1d24b53527a5aa297d68401ffccfe Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 3 Jul 2024 16:02:00 +0200 Subject: [PATCH 14/55] integrate initial value state --- src/libs/WorkspaceReportFieldsUtils.ts | 6 +++++- .../reportFields/InitialValuePage.tsx | 20 ++++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/libs/WorkspaceReportFieldsUtils.ts b/src/libs/WorkspaceReportFieldsUtils.ts index b34a87b3acf08..6b68c371adbae 100644 --- a/src/libs/WorkspaceReportFieldsUtils.ts +++ b/src/libs/WorkspaceReportFieldsUtils.ts @@ -70,7 +70,11 @@ function generateFieldID(name: string) { /** * Gets the initial value for a report field. */ -function getReportFieldInitialValue(reportField: PolicyReportField): string { +function getReportFieldInitialValue(reportField: PolicyReportField | null): string { + if (!reportField) { + return ''; + } + if (reportField.type === CONST.REPORT_FIELD_TYPES.LIST) { return reportField.defaultValue ?? ''; } diff --git a/src/pages/workspace/reportFields/InitialValuePage.tsx b/src/pages/workspace/reportFields/InitialValuePage.tsx index d536f6f60ccd6..0b3b1775d441c 100644 --- a/src/pages/workspace/reportFields/InitialValuePage.tsx +++ b/src/pages/workspace/reportFields/InitialValuePage.tsx @@ -1,5 +1,5 @@ import type {StackScreenProps} from '@react-navigation/stack'; -import React, {useCallback} from 'react'; +import React, {useCallback, useState} from 'react'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; @@ -13,6 +13,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; +import {getReportFieldInitialValue} from '@libs/WorkspaceReportFieldsUtils'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading'; @@ -38,6 +39,8 @@ function InitialValuePage({ const reportField = policy?.fieldList?.[ReportUtils.getReportFieldKey(reportFieldID)] ?? null; const availableListValuesLength = (reportField?.disabledOptions ?? []).filter((disabledListValue) => !disabledListValue).length; + const [initialValue, setInitialValue] = useState(getReportFieldInitialValue(reportField)); + const submitForm = useCallback( (values: FormOnyxValues) => { console.debug('submitForm', policyID, values); @@ -48,7 +51,7 @@ function InitialValuePage({ const validateForm = useCallback( (values: FormOnyxValues): FormInputErrors => { - const {name, type, initialValue} = values; + const {name, type, initialValue: formInitialValue} = values; const errors: FormInputErrors = {}; if (!ValidationUtils.isRequiredFulfilled(name)) { @@ -64,7 +67,7 @@ function InitialValuePage({ ); } - if (type === CONST.REPORT_FIELD_TYPES.LIST && availableListValuesLength > 0 && !ValidationUtils.isRequiredFulfilled(initialValue)) { + if (type === CONST.REPORT_FIELD_TYPES.LIST && availableListValuesLength > 0 && !ValidationUtils.isRequiredFulfilled(formInitialValue)) { errors[INPUT_IDS.INITIAL_VALUE] = translate('workspace.reportFields.reportFieldInitialValueRequiredError'); } @@ -107,15 +110,17 @@ function InitialValuePage({ > {isTextFieldType && ( )} {isListFieldType && ( @@ -124,7 +129,12 @@ function InitialValuePage({ inputID={INPUT_IDS.INITIAL_VALUE} listValues={reportField.values} disabledOptions={reportField.disabledOptions} - value={reportField.defaultValue} + value={initialValue} + onValueChange={(value) => { + setInitialValue(value as string); + + Navigation.goBack(); + }} /> )} From 9c96dce8d398de3bba43aa7effb5eaea19d26c1d Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 3 Jul 2024 16:21:35 +0200 Subject: [PATCH 15/55] improve initial value form submitting --- .../workspace/reportFields/InitialValuePage.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/pages/workspace/reportFields/InitialValuePage.tsx b/src/pages/workspace/reportFields/InitialValuePage.tsx index 0b3b1775d441c..af566b2f23d50 100644 --- a/src/pages/workspace/reportFields/InitialValuePage.tsx +++ b/src/pages/workspace/reportFields/InitialValuePage.tsx @@ -49,6 +49,11 @@ function InitialValuePage({ [policyID], ); + const submitListValueUpdate = (value: string) => { + console.debug('submitListValueUpdate', policyID, reportFieldID, value); + Navigation.goBack(); + }; + const validateForm = useCallback( (values: FormOnyxValues): FormInputErrors => { const {name, type, initialValue: formInitialValue} = values; @@ -106,6 +111,7 @@ function InitialValuePage({ validate={validateForm} style={styles.flex1} enabledWhenOffline + isSubmitButtonVisible={isTextFieldType} submitButtonStyles={styles.mh5} > {isTextFieldType && ( @@ -130,11 +136,7 @@ function InitialValuePage({ listValues={reportField.values} disabledOptions={reportField.disabledOptions} value={initialValue} - onValueChange={(value) => { - setInitialValue(value as string); - - Navigation.goBack(); - }} + onValueChange={(value) => submitListValueUpdate(value as string)} /> )} From 694414adf3a09d5f973fb731cb7640637b7c477e Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 3 Jul 2024 16:53:16 +0200 Subject: [PATCH 16/55] connect reportField values of policy --- src/ROUTES.ts | 4 +-- src/libs/Navigation/linkingConfig/config.ts | 3 +++ src/libs/Navigation/types.ts | 1 + .../reportFields/EditReportFieldPage.tsx | 2 +- .../reportFields/WorkspaceListValuesPage.tsx | 27 ++++++++++++++----- 5 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 483e3e3d9469f..d7d0babd80345 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -788,8 +788,8 @@ const ROUTES = { getRoute: (policyID: string) => `settings/workspaces/${policyID}/reportFields/new` as const, }, WORKSPACE_REPORT_FIELD_LIST_VALUES: { - route: 'settings/workspaces/:policyID/reportFields/new/listValues', - getRoute: (policyID: string) => `settings/workspaces/${policyID}/reportFields/new/listValues` as const, + route: 'settings/workspaces/:policyID/reportFields/new/listValues/:reportFieldID?', + getRoute: (policyID: string, reportFieldID?: string) => `settings/workspaces/${policyID}/reportFields/new/listValues/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELD_ADD_VALUE: { route: 'settings/workspaces/:policyID/reportFields/new/addValue', diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 66b8c0e6bd958..1945384fe0e09 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -530,6 +530,9 @@ const config: LinkingOptions['config'] = { }, [SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES]: { path: ROUTES.WORKSPACE_REPORT_FIELD_LIST_VALUES.route, + parse: { + reportFieldID: (reportFieldID: string) => decodeURIComponent(reportFieldID), + }, }, [SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE]: { path: ROUTES.WORKSPACE_REPORT_FIELD_ADD_VALUE.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index e1e2c5adc3260..b128d5a064e9c 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -273,6 +273,7 @@ type SettingsNavigatorParamList = { }; [SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES]: { policyID: string; + reportFieldID?: string; }; [SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE]: { policyID: string; diff --git a/src/pages/workspace/reportFields/EditReportFieldPage.tsx b/src/pages/workspace/reportFields/EditReportFieldPage.tsx index b41f754250c5b..49d7c9ef31908 100644 --- a/src/pages/workspace/reportFields/EditReportFieldPage.tsx +++ b/src/pages/workspace/reportFields/EditReportFieldPage.tsx @@ -87,7 +87,7 @@ function EditReportFieldPage({ titleStyle={styles.flex1} description={translate('workspace.reportFields.listValues')} shouldShowRightIcon - onPress={() => Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELD_LIST_VALUES.getRoute(policyID))} + onPress={() => Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELD_LIST_VALUES.getRoute(policyID, reportFieldID))} /> )} diff --git a/src/pages/workspace/reportFields/WorkspaceListValuesPage.tsx b/src/pages/workspace/reportFields/WorkspaceListValuesPage.tsx index aadd23caff45e..29b310ec9450c 100644 --- a/src/pages/workspace/reportFields/WorkspaceListValuesPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceListValuesPage.tsx @@ -22,9 +22,11 @@ import useWindowDimensions from '@hooks/useWindowDimensions'; import * as ReportFields from '@libs/actions/Policy/ReportFields'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import Navigation from '@libs/Navigation/Navigation'; +import * as ReportUtils from '@libs/ReportUtils'; import type {SettingsNavigatorParamList} from '@navigation/types'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading'; +import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -40,8 +42,9 @@ type ValueListItem = ListItem & { type WorkspaceListValuesPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; function WorkspaceListValuesPage({ + policy, route: { - params: {policyID}, + params: {policyID, reportFieldID}, }, }: WorkspaceListValuesPageProps) { const styles = useThemeStyles(); @@ -53,23 +56,35 @@ function WorkspaceListValuesPage({ const [deleteValuesConfirmModalVisible, setDeleteValuesConfirmModalVisible] = useState(false); const listValuesSections = useMemo(() => { - const data = Object.values(formDraft?.listValues ?? {}).map((value, index) => ({ + let listValues: string[]; + let disabledListValues: boolean[]; + + if (reportFieldID) { + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + listValues = Object.values(policy?.fieldList?.[reportFieldKey]?.values ?? {}); + disabledListValues = Object.values(policy?.fieldList?.[reportFieldKey]?.disabledOptions ?? {}); + } else { + listValues = formDraft?.listValues ?? []; + disabledListValues = formDraft?.disabledListValues ?? []; + } + + const data = listValues.map((value, index) => ({ value, index, text: value, keyForList: value, isSelected: selectedValues[value], - enabled: formDraft?.disabledListValues?.[index] ?? true, + enabled: !disabledListValues[index] ?? true, rightElement: ( ), })); return [{data, isDisabled: false}]; - }, [formDraft?.disabledListValues, formDraft?.listValues, selectedValues, translate]); + }, [formDraft?.disabledListValues, formDraft?.listValues, policy?.fieldList, reportFieldID, selectedValues, translate]); const shouldShowEmptyState = Object.values(formDraft?.listValues ?? {}).length <= 0; const selectedValuesArray = Object.keys(selectedValues).filter((key) => selectedValues[key]); @@ -273,4 +288,4 @@ function WorkspaceListValuesPage({ WorkspaceListValuesPage.displayName = 'WorkspaceListValuesPage'; -export default WorkspaceListValuesPage; +export default withPolicyAndFullscreenLoading(WorkspaceListValuesPage); From 44eaf4914db58a98d8cd9ab0368d8a5b6a4681bd Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 3 Jul 2024 17:44:39 +0200 Subject: [PATCH 17/55] integrate values based on props --- .../reportFields/WorkspaceListValuesPage.tsx | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/pages/workspace/reportFields/WorkspaceListValuesPage.tsx b/src/pages/workspace/reportFields/WorkspaceListValuesPage.tsx index 29b310ec9450c..91c67125eefd7 100644 --- a/src/pages/workspace/reportFields/WorkspaceListValuesPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceListValuesPage.tsx @@ -55,19 +55,24 @@ function WorkspaceListValuesPage({ const [selectedValues, setSelectedValues] = useState>({}); const [deleteValuesConfirmModalVisible, setDeleteValuesConfirmModalVisible] = useState(false); - const listValuesSections = useMemo(() => { - let listValues: string[]; - let disabledListValues: boolean[]; + const [listValues, disabledListValues] = useMemo(() => { + let reportFieldValues: string[]; + let reportFieldDisabledValues: boolean[]; if (reportFieldID) { const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); - listValues = Object.values(policy?.fieldList?.[reportFieldKey]?.values ?? {}); - disabledListValues = Object.values(policy?.fieldList?.[reportFieldKey]?.disabledOptions ?? {}); - } else { - listValues = formDraft?.listValues ?? []; - disabledListValues = formDraft?.disabledListValues ?? []; + + reportFieldValues = Object.values(policy?.fieldList?.[reportFieldKey]?.values ?? {}); + reportFieldDisabledValues = Object.values(policy?.fieldList?.[reportFieldKey]?.disabledOptions ?? {}); } + reportFieldValues = formDraft?.listValues ?? []; + reportFieldDisabledValues = formDraft?.disabledListValues ?? []; + + return [reportFieldValues, reportFieldDisabledValues]; + }, [formDraft?.disabledListValues, formDraft?.listValues, policy?.fieldList, reportFieldID]); + + const listValuesSections = useMemo(() => { const data = listValues.map((value, index) => ({ value, index, @@ -84,9 +89,9 @@ function WorkspaceListValuesPage({ })); return [{data, isDisabled: false}]; - }, [formDraft?.disabledListValues, formDraft?.listValues, policy?.fieldList, reportFieldID, selectedValues, translate]); + }, [disabledListValues, listValues, selectedValues, translate]); - const shouldShowEmptyState = Object.values(formDraft?.listValues ?? {}).length <= 0; + const shouldShowEmptyState = Object.values(listValues ?? {}).length <= 0; const selectedValuesArray = Object.keys(selectedValues).filter((key) => selectedValues[key]); const toggleValue = (valueItem: ValueListItem) => { @@ -97,7 +102,6 @@ function WorkspaceListValuesPage({ }; const toggleAllValues = () => { - const listValues = formDraft?.listValues ?? []; const isAllSelected = listValues.length === Object.keys(selectedValues).length; setSelectedValues(isAllSelected ? {} : Object.fromEntries(listValues.map((value) => [value, true]))); @@ -107,7 +111,7 @@ function WorkspaceListValuesPage({ setSelectedValues({}); const valuesToDelete = selectedValuesArray.reduce((acc, valueName) => { - const index = formDraft?.listValues?.indexOf(valueName) ?? -1; + const index = listValues?.indexOf(valueName) ?? -1; if (index !== -1) { acc.push(index); @@ -149,14 +153,14 @@ function WorkspaceListValuesPage({ }); const enabledValues = selectedValuesArray.filter((valueName) => { - const index = formDraft?.listValues?.indexOf(valueName) ?? -1; - return !formDraft?.disabledListValues?.[index]; + const index = listValues?.indexOf(valueName) ?? -1; + return !disabledListValues?.[index]; }); if (enabledValues.length > 0) { const valuesToDisable = selectedValuesArray.reduce((acc, valueName) => { - const index = formDraft?.listValues?.indexOf(valueName) ?? -1; - if (!formDraft?.disabledListValues?.[index] && index !== -1) { + const index = listValues?.indexOf(valueName) ?? -1; + if (!disabledListValues?.[index] && index !== -1) { acc.push(index); } @@ -175,14 +179,14 @@ function WorkspaceListValuesPage({ } const disabledValues = selectedValuesArray.filter((valueName) => { - const index = formDraft?.listValues?.indexOf(valueName) ?? -1; - return formDraft?.disabledListValues?.[index]; + const index = listValues?.indexOf(valueName) ?? -1; + return disabledListValues?.[index]; }); if (disabledValues.length > 0) { const valuesToEnable = selectedValuesArray.reduce((acc, valueName) => { - const index = formDraft?.listValues?.indexOf(valueName) ?? -1; - if (formDraft?.disabledListValues?.[index] && index !== -1) { + const index = listValues?.indexOf(valueName) ?? -1; + if (disabledListValues?.[index] && index !== -1) { acc.push(index); } From 26b8885cf5fb336c3fb71e70da287b383d261ddb Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Wed, 3 Jul 2024 19:07:19 +0200 Subject: [PATCH 18/55] rename create report field page --- .../AppNavigator/ModalStackNavigators/index.tsx | 2 +- ...ReportFieldPage.tsx => CreateReportFieldPage.tsx} | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) rename src/pages/workspace/reportFields/{WorkspaceCreateReportFieldPage.tsx => CreateReportFieldPage.tsx} (95%) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 1f84309e6f5fa..bf8365f1bc110 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -361,7 +361,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Subscription/PaymentCard/ChangeBillingCurrency').default, [SCREENS.SETTINGS.SUBSCRIPTION.ADD_PAYMENT_CARD]: () => require('../../../../pages/settings/Subscription/PaymentCard').default, [SCREENS.SETTINGS.ADD_PAYMENT_CARD_CHANGE_CURRENCY]: () => require('../../../../pages/settings/PaymentCard/ChangeCurrency').default, - [SCREENS.WORKSPACE.REPORT_FIELDS_CREATE]: () => require('../../../../pages/workspace/reportFields/WorkspaceCreateReportFieldPage').default, + [SCREENS.WORKSPACE.REPORT_FIELDS_CREATE]: () => require('../../../../pages/workspace/reportFields/CreateReportFieldPage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES]: () => require('../../../../pages/workspace/reportFields/ReportFieldListValuesPage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE]: () => require('../../../../pages/workspace/reportFields/ReportFieldAddListValuePage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS]: () => require('../../../../pages/workspace/reportFields/ValueSettingsPage').default, diff --git a/src/pages/workspace/reportFields/WorkspaceCreateReportFieldPage.tsx b/src/pages/workspace/reportFields/CreateReportFieldPage.tsx similarity index 95% rename from src/pages/workspace/reportFields/WorkspaceCreateReportFieldPage.tsx rename to src/pages/workspace/reportFields/CreateReportFieldPage.tsx index 568fc83a084b8..ac45eb4d5ad36 100644 --- a/src/pages/workspace/reportFields/WorkspaceCreateReportFieldPage.tsx +++ b/src/pages/workspace/reportFields/CreateReportFieldPage.tsx @@ -28,16 +28,16 @@ import INPUT_IDS from '@src/types/form/WorkspaceReportFieldsForm'; import InitialListValueSelector from './InitialListValueSelector'; import TypeSelector from './TypeSelector'; -type WorkspaceCreateReportFieldPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type CreateReportFieldPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; const defaultDate = DateUtils.extractDate(new Date().toString()); -function WorkspaceCreateReportFieldPage({ +function CreateReportFieldPage({ policy, route: { params: {policyID}, }, -}: WorkspaceCreateReportFieldPageProps) { +}: CreateReportFieldPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const formRef = useRef(null); @@ -101,7 +101,7 @@ function WorkspaceCreateReportFieldPage({ Date: Thu, 4 Jul 2024 12:32:07 +0200 Subject: [PATCH 19/55] fix values getting --- .../workspace/reportFields/ReportFieldListValuesPage.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx index b8212c52e9b6b..f504e68a3a3b8 100644 --- a/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx @@ -69,11 +69,11 @@ function ReportFieldListValuesPage({ reportFieldValues = Object.values(policy?.fieldList?.[reportFieldKey]?.values ?? {}); reportFieldDisabledValues = Object.values(policy?.fieldList?.[reportFieldKey]?.disabledOptions ?? {}); + } else { + reportFieldValues = formDraft?.listValues ?? []; + reportFieldDisabledValues = formDraft?.disabledListValues ?? []; } - reportFieldValues = formDraft?.listValues ?? []; - reportFieldDisabledValues = formDraft?.disabledListValues ?? []; - return [reportFieldValues, reportFieldDisabledValues]; }, [formDraft?.disabledListValues, formDraft?.listValues, policy?.fieldList, reportFieldID]); From 6562d4098de49797d8178a780f54cfdeab320d0c Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 12:33:54 +0200 Subject: [PATCH 20/55] rename initial value page --- .../AppNavigator/ModalStackNavigators/index.tsx | 2 +- ...ValuePage.tsx => ReportFieldInitialValuePage.tsx} | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) rename src/pages/workspace/reportFields/{InitialValuePage.tsx => ReportFieldInitialValuePage.tsx} (93%) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index bf8365f1bc110..55a92c09f445d 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -366,7 +366,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/reportFields/ReportFieldAddListValuePage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS]: () => require('../../../../pages/workspace/reportFields/ValueSettingsPage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT]: () => require('../../../../pages/workspace/reportFields/EditReportFieldPage').default, - [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: () => require('../../../../pages/workspace/reportFields/InitialValuePage').default, + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: () => require('../../../../pages/workspace/reportFields/ReportFieldInitialValuePage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE]: () => require('../../../../pages/workspace/reportFields/ReportFieldEditValuePage').default, }); diff --git a/src/pages/workspace/reportFields/InitialValuePage.tsx b/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx similarity index 93% rename from src/pages/workspace/reportFields/InitialValuePage.tsx rename to src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx index af566b2f23d50..3798107e42ed1 100644 --- a/src/pages/workspace/reportFields/InitialValuePage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx @@ -25,13 +25,13 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/WorkspaceReportFieldsForm'; -type InitialValuePagePageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; -function InitialValuePage({ +type ReportFieldInitialValuePagePageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +function ReportFieldInitialValuePage({ policy, route: { params: {policyID, reportFieldID}, }, -}: InitialValuePagePageProps) { +}: ReportFieldInitialValuePagePageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {inputCallbackRef} = useAutoFocusInput(); @@ -97,7 +97,7 @@ function InitialValuePage({ Date: Thu, 4 Jul 2024 12:34:52 +0200 Subject: [PATCH 21/55] rename value settings page --- .../AppNavigator/ModalStackNavigators/index.tsx | 2 +- ...ingsPage.tsx => ReportFieldValueSettingsPage.tsx} | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) rename src/pages/workspace/reportFields/{ValueSettingsPage.tsx => ReportFieldValueSettingsPage.tsx} (91%) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 55a92c09f445d..8fbdb7e143ba9 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -364,7 +364,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/reportFields/CreateReportFieldPage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_LIST_VALUES]: () => require('../../../../pages/workspace/reportFields/ReportFieldListValuesPage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE]: () => require('../../../../pages/workspace/reportFields/ReportFieldAddListValuePage').default, - [SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS]: () => require('../../../../pages/workspace/reportFields/ValueSettingsPage').default, + [SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS]: () => require('../../../../pages/workspace/reportFields/ReportFieldValueSettingsPage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT]: () => require('../../../../pages/workspace/reportFields/EditReportFieldPage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: () => require('../../../../pages/workspace/reportFields/ReportFieldInitialValuePage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE]: () => require('../../../../pages/workspace/reportFields/ReportFieldEditValuePage').default, diff --git a/src/pages/workspace/reportFields/ValueSettingsPage.tsx b/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx similarity index 91% rename from src/pages/workspace/reportFields/ValueSettingsPage.tsx rename to src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx index 445d2bfd71f73..2f23c5ae6f33f 100644 --- a/src/pages/workspace/reportFields/ValueSettingsPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx @@ -22,13 +22,13 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -type ValueSettingsPageProps = StackScreenProps; +type ReportFieldValueSettingsPageProps = StackScreenProps; -function ValueSettingsPage({ +function ReportFieldValueSettingsPage({ route: { params: {policyID, valueIndex}, }, -}: ValueSettingsPageProps) { +}: ReportFieldValueSettingsPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const [formDraft] = useOnyx(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM_DRAFT); @@ -65,7 +65,7 @@ function ValueSettingsPage({ Date: Thu, 4 Jul 2024 12:36:18 +0200 Subject: [PATCH 22/55] rename report field edit page --- .../AppNavigator/ModalStackNavigators/index.tsx | 2 +- ...itReportFieldPage.tsx => ReportFieldEditPage.tsx} | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) rename src/pages/workspace/reportFields/{EditReportFieldPage.tsx => ReportFieldEditPage.tsx} (93%) diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 8fbdb7e143ba9..d4aaa1819b187 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -365,7 +365,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/reportFields/ReportFieldListValuesPage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE]: () => require('../../../../pages/workspace/reportFields/ReportFieldAddListValuePage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS]: () => require('../../../../pages/workspace/reportFields/ReportFieldValueSettingsPage').default, - [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT]: () => require('../../../../pages/workspace/reportFields/EditReportFieldPage').default, + [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT]: () => require('../../../../pages/workspace/reportFields/ReportFieldEditPage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_INITIAL_VALUE]: () => require('../../../../pages/workspace/reportFields/ReportFieldInitialValuePage').default, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE]: () => require('../../../../pages/workspace/reportFields/ReportFieldEditValuePage').default, }); diff --git a/src/pages/workspace/reportFields/EditReportFieldPage.tsx b/src/pages/workspace/reportFields/ReportFieldEditPage.tsx similarity index 93% rename from src/pages/workspace/reportFields/EditReportFieldPage.tsx rename to src/pages/workspace/reportFields/ReportFieldEditPage.tsx index 49d7c9ef31908..8ef5c6d02c3ee 100644 --- a/src/pages/workspace/reportFields/EditReportFieldPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldEditPage.tsx @@ -18,14 +18,14 @@ import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -type EditReportFieldPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; +type ReportFieldEditPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; -function EditReportFieldPage({ +function ReportFieldEditPage({ policy, route: { params: {policyID, reportFieldID}, }, -}: EditReportFieldPageProps) { +}: ReportFieldEditPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); @@ -47,7 +47,7 @@ function EditReportFieldPage({ Date: Thu, 4 Jul 2024 13:05:07 +0200 Subject: [PATCH 23/55] create bare report field updates --- src/libs/actions/Policy/ReportFields.ts | 26 +++++++------------------ 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/libs/actions/Policy/ReportFields.ts b/src/libs/actions/Policy/ReportFields.ts index eef67fe4bbd58..3362c06706d86 100644 --- a/src/libs/actions/Policy/ReportFields.ts +++ b/src/libs/actions/Policy/ReportFields.ts @@ -11,7 +11,6 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {WorkspaceReportFieldsForm} from '@src/types/form/WorkspaceReportFieldsForm'; import INPUT_IDS from '@src/types/form/WorkspaceReportFieldsForm'; import type {Policy, PolicyReportField} from '@src/types/onyx'; -import type {PolicyReportFieldType} from '@src/types/onyx/Policy'; import type {OnyxData} from '@src/types/onyx/Request'; let listValues: string[]; @@ -206,24 +205,14 @@ function createReportField(policyID: string, {name, type, initialValue}: CreateR } /** - * Renames a report field. - */ -function renameReportField(policyID: string, reportFieldName: string, newName: string) { - console.debug('renameReportField', policyID, reportFieldName, newName); -} - -/** - * Updates the type of a report field. + * Updates the initial value of a report field. */ -function updatePolicyReportFieldType(policyID: string, reportFieldName: string, newType: PolicyReportFieldType) { - console.debug('updatePolicyReportFieldType', policyID, reportFieldName, newType); +function updateReportFieldInitialValue(policyID: string, reportFieldID: string, newInitialValue: string) { + console.debug('updateReportFieldInitialValue', policyID, reportFieldID, newInitialValue); } -/** - * Updates the initial value of a report field. - */ -function updatePolicyReportFieldInitialValue(policyID: string, reportFieldName: string, newInitialValue: string) { - console.debug('updatePolicyReportFieldInitialValue', policyID, reportFieldName, newInitialValue); +function updateReportFieldListValueEnabled(policyID: string, reportFieldID: string, valueIndex: number, enabled: boolean) { + console.debug('updateReportFieldListValueEnabled', policyID, reportFieldID, valueIndex, enabled); } export type {CreateReportFieldArguments}; @@ -235,7 +224,6 @@ export { setReportFieldsListValueEnabled, deleteReportFieldsListValue, createReportField, - renameReportField, - updatePolicyReportFieldType, - updatePolicyReportFieldInitialValue, + updateReportFieldInitialValue, + updateReportFieldListValueEnabled, }; From 8841b35d90fa5876d35eef48bdd1158f94c51f50 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 13:07:19 +0200 Subject: [PATCH 24/55] create tests for updateReportFieldInitialValue --- tests/actions/ReportFieldsTest.ts | 71 +++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/actions/ReportFieldsTest.ts b/tests/actions/ReportFieldsTest.ts index 5008e51dd4681..65db217661af2 100644 --- a/tests/actions/ReportFieldsTest.ts +++ b/tests/actions/ReportFieldsTest.ts @@ -11,6 +11,7 @@ import * as ReportUtils from '@src/libs/ReportUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import INPUT_IDS from '@src/types/form/WorkspaceReportFieldsForm'; import type {PolicyReportField, Policy as PolicyType} from '@src/types/onyx'; +import createRandomPolicy from '../utils/collections/policies'; import * as TestHelper from '../utils/TestHelper'; import type {MockFetch} from '../utils/TestHelper'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; @@ -234,4 +235,74 @@ describe('actions/ReportFields', () => { expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); }); }); + + describe('updateReportFieldInitialValue', () => { + it('updates the initial value of a text report field', async () => { + mockFetch?.pause?.(); + + const policyID = Policy.generatePolicyID(); + const reportFieldName = 'Test Field'; + const oldInitialValue = 'Old initial value'; + const newInitialValue = 'New initial value'; + const reportFieldID = generateFieldID(reportFieldName); + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField: Omit = { + name: reportFieldName, + type: CONST.REPORT_FIELD_TYPES.TEXT, + defaultValue: oldInitialValue, + values: [], + disabledOptions: [], + fieldID: reportFieldID, + orderWeight: 1, + deletable: false, + keys: [], + externalIDs: [], + isTax: false, + }; + const fakePolicy = createRandomPolicy(Number(policyID)); + + Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); + await waitForBatchedUpdates(); + + ReportFields.updateReportFieldInitialValue(policyID, reportFieldID, newInitialValue); + await waitForBatchedUpdates(); + + let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // check if the new report field was added to the policy + expect(policy?.fieldList).toStrictEqual({ + [reportFieldKey]: { + ...reportField, + defaultValue: newInitialValue, + }, + }); + + // Check for success data + (fetch as MockFetch)?.resume?.(); + await waitForBatchedUpdates(); + + policy = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.POLICY, + waitForCollectionCallback: true, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // Check if the policy pending action was cleared + // @ts-expect-error pendingFields is not null + expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + }); + }); }); From 111c4ee875667f0bebcc5f7c15d768ce343a2c4d Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 13:21:02 +0200 Subject: [PATCH 25/55] create tests for updateReportFieldListValueEnabled --- tests/actions/ReportFieldsTest.ts | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/tests/actions/ReportFieldsTest.ts b/tests/actions/ReportFieldsTest.ts index 65db217661af2..c0029cd9a7438 100644 --- a/tests/actions/ReportFieldsTest.ts +++ b/tests/actions/ReportFieldsTest.ts @@ -305,4 +305,79 @@ describe('actions/ReportFields', () => { expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); }); }); + + describe('updateReportFieldListValueEnabled', () => { + it('updates the enabled flag of a report field list value', async () => { + mockFetch?.pause?.(); + + const policyID = Policy.generatePolicyID(); + const reportFieldName = 'Test Field'; + const valueIndexToUpdate = 1; + const oldEnabledFlag = false; + const newEnabledFlag = true; + const oldInitialValue = 'Value 2'; + const newInitialValue = ''; + const reportFieldID = generateFieldID(reportFieldName); + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField: PolicyReportField = { + name: reportFieldName, + type: CONST.REPORT_FIELD_TYPES.LIST, + defaultValue: oldInitialValue, + values: ['Value 1', oldInitialValue, 'Value 3'], + disabledOptions: [false, oldEnabledFlag, true], + fieldID: reportFieldID, + orderWeight: 1, + deletable: false, + keys: [], + externalIDs: [], + isTax: false, + value: CONST.REPORT_FIELD_TYPES.LIST, + }; + const fakePolicy = createRandomPolicy(Number(policyID)); + + Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); + await waitForBatchedUpdates(); + + ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexToUpdate, newEnabledFlag); + await waitForBatchedUpdates(); + + let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // check if the new report field was added to the policy + expect(policy?.fieldList).toStrictEqual({ + [reportFieldKey]: { + ...reportField, + defaultValue: newInitialValue, + disabledOptions: [false, newEnabledFlag, true], + }, + }); + + // Check for success data + (fetch as MockFetch)?.resume?.(); + await waitForBatchedUpdates(); + + policy = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: ONYXKEYS.COLLECTION.POLICY, + waitForCollectionCallback: true, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // Check if the policy pending action was cleared + // @ts-expect-error pendingFields is not null + expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + }); + }); }); From bbae275773929945434ed2aae12b08a4048f3144 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 15:50:18 +0200 Subject: [PATCH 26/55] integrate updateReportFieldInitialValue and updateReportFieldListValueEnabled --- ...ableWorkspaceReportFieldListValueParams.ts | 6 + ...eWorkspaceReportFieldInitialValueParams.ts | 6 + src/libs/API/parameters/index.ts | 2 + src/libs/API/types.ts | 4 + src/libs/actions/Policy/ReportFields.ts | 127 +++++++++++++++++- 5 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 src/libs/API/parameters/EnableWorkspaceReportFieldListValueParams.ts create mode 100644 src/libs/API/parameters/UpdateWorkspaceReportFieldInitialValueParams.ts diff --git a/src/libs/API/parameters/EnableWorkspaceReportFieldListValueParams.ts b/src/libs/API/parameters/EnableWorkspaceReportFieldListValueParams.ts new file mode 100644 index 0000000000000..b8fc126acfcfd --- /dev/null +++ b/src/libs/API/parameters/EnableWorkspaceReportFieldListValueParams.ts @@ -0,0 +1,6 @@ +type EnableWorkspaceReportFieldListValueParams = { + policyID: string; + reportFields: string; +}; + +export default EnableWorkspaceReportFieldListValueParams; diff --git a/src/libs/API/parameters/UpdateWorkspaceReportFieldInitialValueParams.ts b/src/libs/API/parameters/UpdateWorkspaceReportFieldInitialValueParams.ts new file mode 100644 index 0000000000000..74426d8873d5e --- /dev/null +++ b/src/libs/API/parameters/UpdateWorkspaceReportFieldInitialValueParams.ts @@ -0,0 +1,6 @@ +type UpdateWorkspaceReportFieldInitialValueParams = { + policyID: string; + reportFields: string; +}; + +export default UpdateWorkspaceReportFieldInitialValueParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 0b63ec3ed465b..bcd3607c4379b 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -239,6 +239,8 @@ export type {default as HoldMoneyRequestOnSearchParams} from './HoldMoneyRequest export type {default as UnholdMoneyRequestOnSearchParams} from './UnholdMoneyRequestOnSearchParams'; export type {default as UpdateNetSuiteSubsidiaryParams} from './UpdateNetSuiteSubsidiaryParams'; export type {default as CreateWorkspaceReportFieldParams} from './CreateWorkspaceReportFieldParams'; +export type {default as UpdateWorkspaceReportFieldInitialValueParams} from './UpdateWorkspaceReportFieldInitialValueParams'; +export type {default as EnableWorkspaceReportFieldListValueParams} from './EnableWorkspaceReportFieldListValueParams'; export type {default as OpenPolicyExpensifyCardsPageParams} from './OpenPolicyExpensifyCardsPageParams'; export type {default as RequestExpensifyCardLimitIncreaseParams} from './RequestExpensifyCardLimitIncreaseParams'; export type {default as UpdateNetSuiteGenericTypeParams} from './UpdateNetSuiteGenericTypeParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index bd10be8948bca..0744c55123e09 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -235,6 +235,8 @@ const WRITE_COMMANDS = { REQUEST_REFUND: 'User_RefundPurchase', UPDATE_NETSUITE_SUBSIDIARY: 'UpdateNetSuiteSubsidiary', CREATE_WORKSPACE_REPORT_FIELD: 'CreatePolicyReportField', + UPDATE_WORKSPACE_REPORT_FIELD_INITIAL_VALUE: 'SetPolicyReportFieldDefault', + ENABLE_WORKSPACE_REPORT_FIELD_LIST_VALUE: 'EnablePolicyReportFieldOption', UPDATE_NETSUITE_SYNC_TAX_CONFIGURATION: 'UpdateNetSuiteSyncTaxConfiguration', UPDATE_NETSUITE_EXPORTER: 'UpdateNetSuiteExporter', UPDATE_NETSUITE_EXPORT_DATE: 'UpdateNetSuiteExportDate', @@ -498,6 +500,8 @@ type WriteCommandParameters = { // Workspace report field parameters [WRITE_COMMANDS.CREATE_WORKSPACE_REPORT_FIELD]: Parameters.CreateWorkspaceReportFieldParams; + [WRITE_COMMANDS.UPDATE_WORKSPACE_REPORT_FIELD_INITIAL_VALUE]: Parameters.UpdateWorkspaceReportFieldInitialValueParams; + [WRITE_COMMANDS.ENABLE_WORKSPACE_REPORT_FIELD_LIST_VALUE]: Parameters.EnableWorkspaceReportFieldListValueParams; [WRITE_COMMANDS.UPDATE_NETSUITE_SYNC_TAX_CONFIGURATION]: Parameters.UpdateNetSuiteGenericTypeParams<'enabled', boolean>; [WRITE_COMMANDS.UPDATE_NETSUITE_EXPORTER]: Parameters.UpdateNetSuiteGenericTypeParams<'email', string>; diff --git a/src/libs/actions/Policy/ReportFields.ts b/src/libs/actions/Policy/ReportFields.ts index 3362c06706d86..9c07b242c8799 100644 --- a/src/libs/actions/Policy/ReportFields.ts +++ b/src/libs/actions/Policy/ReportFields.ts @@ -1,7 +1,7 @@ import type {NullishDeep, OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import * as API from '@libs/API'; -import type {CreateWorkspaceReportFieldParams} from '@libs/API/parameters'; +import type {CreateWorkspaceReportFieldParams, EnableWorkspaceReportFieldListValueParams, UpdateWorkspaceReportFieldInitialValueParams} from '@libs/API/parameters'; import {WRITE_COMMANDS} from '@libs/API/types'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -208,11 +208,132 @@ function createReportField(policyID: string, {name, type, initialValue}: CreateR * Updates the initial value of a report field. */ function updateReportFieldInitialValue(policyID: string, reportFieldID: string, newInitialValue: string) { - console.debug('updateReportFieldInitialValue', policyID, reportFieldID, newInitialValue); + const previousFieldList = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.fieldList ?? {}; + const fieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const updatedReportField: PolicyReportField = { + ...previousFieldList[fieldKey], + defaultValue: newInitialValue, + }; + const onyxData: OnyxData = { + optimisticData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + fieldList: { + [fieldKey]: updatedReportField, + }, + pendingFields: { + [fieldKey]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + errorFields: null, + }, + }, + ], + successData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + pendingFields: { + [fieldKey]: null, + }, + errorFields: null, + }, + }, + ], + failureData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + fieldList: { + [fieldKey]: null, + }, + pendingFields: { + [fieldKey]: null, + }, + errorFields: { + [fieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.reportFields.genericFailureMessage'), + }, + }, + }, + ], + }; + const parameters: UpdateWorkspaceReportFieldInitialValueParams = { + policyID, + reportFields: JSON.stringify([updatedReportField]), + }; + + API.write(WRITE_COMMANDS.UPDATE_WORKSPACE_REPORT_FIELD_INITIAL_VALUE, parameters, onyxData); } function updateReportFieldListValueEnabled(policyID: string, reportFieldID: string, valueIndex: number, enabled: boolean) { - console.debug('updateReportFieldListValueEnabled', policyID, reportFieldID, valueIndex, enabled); + const previousFieldList = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.fieldList ?? {}; + const fieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField = previousFieldList[fieldKey]; + const shouldResetDefaultValue = !enabled && reportField.defaultValue === reportField.values[valueIndex]; + const updatedReportField: PolicyReportField = { + ...reportField, + disabledOptions: reportField.disabledOptions.map((value, index) => (index === valueIndex ? !enabled : value)), + }; + + if (shouldResetDefaultValue) { + updatedReportField.defaultValue = ''; + } + + const onyxData: OnyxData = { + optimisticData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + fieldList: { + [fieldKey]: updatedReportField, + }, + pendingFields: { + [fieldKey]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + errorFields: null, + }, + }, + ], + successData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + pendingFields: { + [fieldKey]: null, + }, + errorFields: null, + }, + }, + ], + failureData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + fieldList: { + [fieldKey]: null, + }, + pendingFields: { + [fieldKey]: null, + }, + errorFields: { + [fieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.reportFields.genericFailureMessage'), + }, + }, + }, + ], + }; + const parameters: EnableWorkspaceReportFieldListValueParams = { + policyID, + reportFields: JSON.stringify([updatedReportField]), + }; + + API.write(WRITE_COMMANDS.ENABLE_WORKSPACE_REPORT_FIELD_LIST_VALUE, parameters, onyxData); } export type {CreateReportFieldArguments}; From 124091861e94afc87cea57f944b533511b4b3df6 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 15:50:32 +0200 Subject: [PATCH 27/55] improve tests --- tests/actions/ReportFieldsTest.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/actions/ReportFieldsTest.ts b/tests/actions/ReportFieldsTest.ts index c0029cd9a7438..db91f0f551a8a 100644 --- a/tests/actions/ReportFieldsTest.ts +++ b/tests/actions/ReportFieldsTest.ts @@ -313,8 +313,8 @@ describe('actions/ReportFields', () => { const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; const valueIndexToUpdate = 1; - const oldEnabledFlag = false; - const newEnabledFlag = true; + const oldDisabledFlag = false; + const newDisabledFlag = true; const oldInitialValue = 'Value 2'; const newInitialValue = ''; const reportFieldID = generateFieldID(reportFieldName); @@ -324,7 +324,7 @@ describe('actions/ReportFields', () => { type: CONST.REPORT_FIELD_TYPES.LIST, defaultValue: oldInitialValue, values: ['Value 1', oldInitialValue, 'Value 3'], - disabledOptions: [false, oldEnabledFlag, true], + disabledOptions: [false, oldDisabledFlag, true], fieldID: reportFieldID, orderWeight: 1, deletable: false, @@ -338,7 +338,7 @@ describe('actions/ReportFields', () => { Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); await waitForBatchedUpdates(); - ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexToUpdate, newEnabledFlag); + ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexToUpdate, !newDisabledFlag); await waitForBatchedUpdates(); let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { @@ -352,11 +352,11 @@ describe('actions/ReportFields', () => { }); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual({ + expect(policy?.fieldList).toStrictEqual>({ [reportFieldKey]: { ...reportField, defaultValue: newInitialValue, - disabledOptions: [false, newEnabledFlag, true], + disabledOptions: [false, newDisabledFlag, true], }, }); From 84284fd457061cf6be661129d11e05a25d1da4f7 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 15:51:05 +0200 Subject: [PATCH 28/55] integrate initial value updating --- .../workspace/reportFields/ReportFieldInitialValuePage.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx b/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx index 3798107e42ed1..72d3e2a7a8897 100644 --- a/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx @@ -10,6 +10,7 @@ import TextInput from '@components/TextInput'; import useAutoFocusInput from '@hooks/useAutoFocusInput'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import {updateReportFieldInitialValue} from '@libs/actions/Policy/ReportFields'; import Navigation from '@libs/Navigation/Navigation'; import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; @@ -43,14 +44,14 @@ function ReportFieldInitialValuePage({ const submitForm = useCallback( (values: FormOnyxValues) => { - console.debug('submitForm', policyID, values); + updateReportFieldInitialValue(policyID, reportFieldID, values.initialValue); Navigation.goBack(); }, - [policyID], + [policyID, reportFieldID], ); const submitListValueUpdate = (value: string) => { - console.debug('submitListValueUpdate', policyID, reportFieldID, value); + updateReportFieldInitialValue(policyID, reportFieldID, value); Navigation.goBack(); }; From 46a1a655423cf69862921ca96155603d4442649f Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 15:51:36 +0200 Subject: [PATCH 29/55] integrate list value enabling --- src/ROUTES.ts | 5 ++- src/libs/Navigation/linkingConfig/config.ts | 3 ++ src/libs/Navigation/types.ts | 1 + .../ReportFieldListValuesPage.tsx | 2 +- .../ReportFieldValueSettingsPage.tsx | 38 +++++++++++++++---- src/pages/workspace/withPolicy.tsx | 1 + 6 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index d7d0babd80345..6479f5faceb22 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -796,8 +796,9 @@ const ROUTES = { getRoute: (policyID: string) => `settings/workspaces/${policyID}/reportFields/new/addValue` as const, }, WORKSPACE_REPORT_FIELD_VALUE_SETTINGS: { - route: 'settings/workspaces/:policyID/reportFields/new/:valueIndex', - getRoute: (policyID: string, valueIndex: number) => `settings/workspaces/${policyID}/reportFields/new/${valueIndex}` as const, + route: 'settings/workspaces/:policyID/reportFields/new/:valueIndex/:reportFieldID?', + getRoute: (policyID: string, valueIndex: number, reportFieldID?: string) => + `settings/workspaces/${policyID}/reportFields/new/${valueIndex}/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELD_EDIT_VALUE: { route: 'settings/workspaces/:policyID/reportFields/new/:valueIndex/edit', diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 1945384fe0e09..ac21dc70fbe19 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -539,6 +539,9 @@ const config: LinkingOptions['config'] = { }, [SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS]: { path: ROUTES.WORKSPACE_REPORT_FIELD_VALUE_SETTINGS.route, + parse: { + reportFieldID: (reportFieldID: string) => decodeURIComponent(reportFieldID), + }, }, [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE]: { path: ROUTES.WORKSPACE_REPORT_FIELD_EDIT_VALUE.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index b128d5a064e9c..90f2e6ae5da1e 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -281,6 +281,7 @@ type SettingsNavigatorParamList = { [SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS]: { policyID: string; valueIndex: number; + reportFieldID?: string; }; [SCREENS.WORKSPACE.REPORT_FIELDS_EDIT_VALUE]: { policyID: string; diff --git a/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx index f504e68a3a3b8..c19ddd297f63b 100644 --- a/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx @@ -134,7 +134,7 @@ function ReportFieldListValuesPage({ return; } - Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELD_VALUE_SETTINGS.getRoute(policyID, valueItem.index)); + Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELD_VALUE_SETTINGS.getRoute(policyID, valueItem.index, reportFieldID)); setSelectedValues({}); }; diff --git a/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx b/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx index 2f23c5ae6f33f..3781dad5c9969 100644 --- a/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx @@ -1,5 +1,5 @@ import type {StackScreenProps} from '@react-navigation/stack'; -import React, {useState} from 'react'; +import React, {useMemo, useState} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import ConfirmModal from '@components/ConfirmModal'; @@ -14,19 +14,23 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ReportFields from '@libs/actions/Policy/ReportFields'; import Navigation from '@libs/Navigation/Navigation'; +import * as ReportUtils from '@libs/ReportUtils'; import type {SettingsNavigatorParamList} from '@navigation/types'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper'; +import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading'; +import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -type ReportFieldValueSettingsPageProps = StackScreenProps; +type ReportFieldValueSettingsPageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; function ReportFieldValueSettingsPage({ + policy, route: { - params: {policyID, valueIndex}, + params: {policyID, valueIndex, reportFieldID}, }, }: ReportFieldValueSettingsPageProps) { const styles = useThemeStyles(); @@ -35,8 +39,22 @@ function ReportFieldValueSettingsPage({ const [isDeleteTagModalOpen, setIsDeleteTagModalOpen] = useState(false); - const currentValueName = formDraft?.listValues?.[valueIndex] ?? ''; - const currentValueDisabled = formDraft?.disabledListValues?.[valueIndex] ?? false; + const [currentValueName, currentValueDisabled] = useMemo(() => { + let reportFieldValue: string; + let reportFieldDisabledValue: boolean; + + if (reportFieldID) { + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + + reportFieldValue = Object.values(policy?.fieldList?.[reportFieldKey]?.values ?? {})?.[valueIndex] ?? ''; + reportFieldDisabledValue = Object.values(policy?.fieldList?.[reportFieldKey]?.disabledOptions ?? {})?.[valueIndex] ?? false; + } else { + reportFieldValue = formDraft?.listValues?.[valueIndex] ?? ''; + reportFieldDisabledValue = formDraft?.disabledListValues?.[valueIndex] ?? false; + } + + return [reportFieldValue, reportFieldDisabledValue]; + }, [formDraft?.disabledListValues, formDraft?.listValues, policy?.fieldList, reportFieldID, valueIndex]); if (!currentValueName) { return ; @@ -49,6 +67,11 @@ function ReportFieldValueSettingsPage({ }; const updateListValueEnabled = (value: boolean) => { + if (reportFieldID) { + ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, Number(valueIndex), value); + return; + } + ReportFields.setReportFieldsListValueEnabled([valueIndex], value); }; @@ -96,8 +119,9 @@ function ReportFieldValueSettingsPage({ ; function getPolicyIDFromRoute(route: PolicyRoute): string { From a34a9281e57df9ad668c3ed73b039b3662031656 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 16:19:28 +0200 Subject: [PATCH 30/55] add correct failure data --- src/libs/actions/Policy/ReportFields.ts | 4 +- tests/actions/ReportFieldsTest.ts | 157 +++++++++++++++++++++++- 2 files changed, 158 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Policy/ReportFields.ts b/src/libs/actions/Policy/ReportFields.ts index 9c07b242c8799..5b0276efc6709 100644 --- a/src/libs/actions/Policy/ReportFields.ts +++ b/src/libs/actions/Policy/ReportFields.ts @@ -248,7 +248,7 @@ function updateReportFieldInitialValue(policyID: string, reportFieldID: string, onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [fieldKey]: null, + [fieldKey]: previousFieldList[fieldKey], }, pendingFields: { [fieldKey]: null, @@ -316,7 +316,7 @@ function updateReportFieldListValueEnabled(policyID: string, reportFieldID: stri onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [fieldKey]: null, + [fieldKey]: reportField, }, pendingFields: { [fieldKey]: null, diff --git a/tests/actions/ReportFieldsTest.ts b/tests/actions/ReportFieldsTest.ts index db91f0f551a8a..120f8636b9989 100644 --- a/tests/actions/ReportFieldsTest.ts +++ b/tests/actions/ReportFieldsTest.ts @@ -277,7 +277,7 @@ describe('actions/ReportFields', () => { }); }); - // check if the new report field was added to the policy + // check if the updated report field was set to the policy expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: { ...reportField, @@ -304,6 +304,81 @@ describe('actions/ReportFields', () => { // @ts-expect-error pendingFields is not null expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); }); + + it('updates the initial value of a text report field when api returns an error', async () => { + mockFetch?.pause?.(); + + const policyID = Policy.generatePolicyID(); + const reportFieldName = 'Test Field'; + const oldInitialValue = 'Old initial value'; + const newInitialValue = 'New initial value'; + const reportFieldID = generateFieldID(reportFieldName); + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField: Omit = { + name: reportFieldName, + type: CONST.REPORT_FIELD_TYPES.TEXT, + defaultValue: oldInitialValue, + values: [], + disabledOptions: [], + fieldID: reportFieldID, + orderWeight: 1, + deletable: false, + keys: [], + externalIDs: [], + isTax: false, + }; + const fakePolicy = createRandomPolicy(Number(policyID)); + + Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); + await waitForBatchedUpdates(); + + ReportFields.updateReportFieldInitialValue(policyID, reportFieldID, newInitialValue); + await waitForBatchedUpdates(); + + let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // check if the updated report field was set to the policy + expect(policy?.fieldList).toStrictEqual({ + [reportFieldKey]: { + ...reportField, + defaultValue: newInitialValue, + }, + }); + + // Check for failure data + mockFetch?.fail?.(); + mockFetch?.resume?.(); + await waitForBatchedUpdates(); + + policy = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // check if the updated report field was reset in the policy + expect(policy?.fieldList).toStrictEqual({ + [reportFieldKey]: reportField, + }); + // Check if the policy pending action was cleared + // @ts-expect-error pendingFields is not null + expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + // Check if the policy errors was set + // @ts-expect-error errorFields is not null + expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); + }); }); describe('updateReportFieldListValueEnabled', () => { @@ -379,5 +454,85 @@ describe('actions/ReportFields', () => { // @ts-expect-error pendingFields is not null expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); }); + + it('updates the enabled flag of a report field list value', async () => { + mockFetch?.pause?.(); + + const policyID = Policy.generatePolicyID(); + const reportFieldName = 'Test Field'; + const valueIndexToUpdate = 1; + const oldDisabledFlag = false; + const newDisabledFlag = true; + const oldInitialValue = 'Value 2'; + const newInitialValue = ''; + const reportFieldID = generateFieldID(reportFieldName); + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField: PolicyReportField = { + name: reportFieldName, + type: CONST.REPORT_FIELD_TYPES.LIST, + defaultValue: oldInitialValue, + values: ['Value 1', oldInitialValue, 'Value 3'], + disabledOptions: [false, oldDisabledFlag, true], + fieldID: reportFieldID, + orderWeight: 1, + deletable: false, + keys: [], + externalIDs: [], + isTax: false, + value: CONST.REPORT_FIELD_TYPES.LIST, + }; + const fakePolicy = createRandomPolicy(Number(policyID)); + + Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); + await waitForBatchedUpdates(); + + ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexToUpdate, !newDisabledFlag); + await waitForBatchedUpdates(); + + let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // check if the new report field was added to the policy + expect(policy?.fieldList).toStrictEqual>({ + [reportFieldKey]: { + ...reportField, + defaultValue: newInitialValue, + disabledOptions: [false, newDisabledFlag, true], + }, + }); + + // Check for failure data + mockFetch?.fail?.(); + mockFetch?.resume?.(); + await waitForBatchedUpdates(); + + policy = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // check if the updated report field was reset in the policy + expect(policy?.fieldList).toStrictEqual({ + [reportFieldKey]: reportField, + }); + // Check if the policy pending action was cleared + // @ts-expect-error pendingFields is not null + expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + // Check if the policy errors was set + // @ts-expect-error errorFields is not null + expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); + }); }); }); From b9a0da0c7ec7943dd4eb2a86a751abfeaf2783a9 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 16:32:37 +0200 Subject: [PATCH 31/55] improve updateReportFieldListValueEnabled to handle batch update --- src/libs/actions/Policy/ReportFields.ts | 21 +++++----- .../ReportFieldValueSettingsPage.tsx | 2 +- tests/actions/ReportFieldsTest.ts | 38 ++++++++----------- 3 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/libs/actions/Policy/ReportFields.ts b/src/libs/actions/Policy/ReportFields.ts index 5b0276efc6709..384ad4729815e 100644 --- a/src/libs/actions/Policy/ReportFields.ts +++ b/src/libs/actions/Policy/ReportFields.ts @@ -1,3 +1,4 @@ +import cloneDeep from 'lodash/cloneDeep'; import type {NullishDeep, OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import * as API from '@libs/API'; @@ -268,19 +269,21 @@ function updateReportFieldInitialValue(policyID: string, reportFieldID: string, API.write(WRITE_COMMANDS.UPDATE_WORKSPACE_REPORT_FIELD_INITIAL_VALUE, parameters, onyxData); } -function updateReportFieldListValueEnabled(policyID: string, reportFieldID: string, valueIndex: number, enabled: boolean) { +function updateReportFieldListValueEnabled(policyID: string, reportFieldID: string, valueIndexes: number[], enabled: boolean) { const previousFieldList = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.fieldList ?? {}; const fieldKey = ReportUtils.getReportFieldKey(reportFieldID); const reportField = previousFieldList[fieldKey]; - const shouldResetDefaultValue = !enabled && reportField.defaultValue === reportField.values[valueIndex]; - const updatedReportField: PolicyReportField = { - ...reportField, - disabledOptions: reportField.disabledOptions.map((value, index) => (index === valueIndex ? !enabled : value)), - }; - if (shouldResetDefaultValue) { - updatedReportField.defaultValue = ''; - } + const updatedReportField = cloneDeep(reportField); + + valueIndexes.forEach((valueIndex) => { + updatedReportField.disabledOptions[valueIndex] = !enabled; + const shouldResetDefaultValue = !enabled && reportField.defaultValue === reportField.values[valueIndex]; + + if (shouldResetDefaultValue) { + updatedReportField.defaultValue = ''; + } + }); const onyxData: OnyxData = { optimisticData: [ diff --git a/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx b/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx index 3781dad5c9969..64c9f2e55c120 100644 --- a/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx @@ -68,7 +68,7 @@ function ReportFieldValueSettingsPage({ const updateListValueEnabled = (value: boolean) => { if (reportFieldID) { - ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, Number(valueIndex), value); + ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, [Number(valueIndex)], value); return; } diff --git a/tests/actions/ReportFieldsTest.ts b/tests/actions/ReportFieldsTest.ts index 120f8636b9989..78e112bec17ff 100644 --- a/tests/actions/ReportFieldsTest.ts +++ b/tests/actions/ReportFieldsTest.ts @@ -382,24 +382,20 @@ describe('actions/ReportFields', () => { }); describe('updateReportFieldListValueEnabled', () => { - it('updates the enabled flag of a report field list value', async () => { + it('updates the enabled flag of report field list values', async () => { mockFetch?.pause?.(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; - const valueIndexToUpdate = 1; - const oldDisabledFlag = false; - const newDisabledFlag = true; - const oldInitialValue = 'Value 2'; - const newInitialValue = ''; + const valueIndexesTpUpdate = [1, 2]; const reportFieldID = generateFieldID(reportFieldName); const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); const reportField: PolicyReportField = { name: reportFieldName, type: CONST.REPORT_FIELD_TYPES.LIST, - defaultValue: oldInitialValue, - values: ['Value 1', oldInitialValue, 'Value 3'], - disabledOptions: [false, oldDisabledFlag, true], + defaultValue: 'Value 2', + values: ['Value 1', 'Value 2', 'Value 3'], + disabledOptions: [false, false, true], fieldID: reportFieldID, orderWeight: 1, deletable: false, @@ -413,7 +409,7 @@ describe('actions/ReportFields', () => { Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); await waitForBatchedUpdates(); - ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexToUpdate, !newDisabledFlag); + ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexesTpUpdate, false); await waitForBatchedUpdates(); let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { @@ -430,8 +426,8 @@ describe('actions/ReportFields', () => { expect(policy?.fieldList).toStrictEqual>({ [reportFieldKey]: { ...reportField, - defaultValue: newInitialValue, - disabledOptions: [false, newDisabledFlag, true], + defaultValue: '', + disabledOptions: [false, true, true], }, }); @@ -460,19 +456,15 @@ describe('actions/ReportFields', () => { const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; - const valueIndexToUpdate = 1; - const oldDisabledFlag = false; - const newDisabledFlag = true; - const oldInitialValue = 'Value 2'; - const newInitialValue = ''; + const valueIndexesToUpdate = [1]; const reportFieldID = generateFieldID(reportFieldName); const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); const reportField: PolicyReportField = { name: reportFieldName, type: CONST.REPORT_FIELD_TYPES.LIST, - defaultValue: oldInitialValue, - values: ['Value 1', oldInitialValue, 'Value 3'], - disabledOptions: [false, oldDisabledFlag, true], + defaultValue: 'Value 2', + values: ['Value 1', 'Value 2', 'Value 3'], + disabledOptions: [false, false, true], fieldID: reportFieldID, orderWeight: 1, deletable: false, @@ -486,7 +478,7 @@ describe('actions/ReportFields', () => { Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); await waitForBatchedUpdates(); - ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexToUpdate, !newDisabledFlag); + ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexesToUpdate, false); await waitForBatchedUpdates(); let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { @@ -503,8 +495,8 @@ describe('actions/ReportFields', () => { expect(policy?.fieldList).toStrictEqual>({ [reportFieldKey]: { ...reportField, - defaultValue: newInitialValue, - disabledOptions: [false, newDisabledFlag, true], + defaultValue: '', + disabledOptions: [false, true, true], }, }); From 05f86424a4645f308d9aa314dfcf787fa82e42d0 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 16:44:55 +0200 Subject: [PATCH 32/55] integrate batched updates --- .../reportFields/ReportFieldListValuesPage.tsx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx index c19ddd297f63b..f56f97bbf8b63 100644 --- a/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx @@ -178,6 +178,12 @@ function ReportFieldListValuesPage({ value: CONST.POLICY.BULK_ACTION_TYPES.DISABLE, onSelected: () => { setSelectedValues({}); + + if (reportFieldID) { + ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, valuesToDisable, false); + return; + } + ReportFields.setReportFieldsListValueEnabled(valuesToDisable, false); }, }); @@ -204,6 +210,12 @@ function ReportFieldListValuesPage({ value: CONST.POLICY.BULK_ACTION_TYPES.ENABLE, onSelected: () => { setSelectedValues({}); + + if (reportFieldID) { + ReportFields.updateReportFieldListValueEnabled(policyID, reportFieldID, valuesToEnable, true); + return; + } + ReportFields.setReportFieldsListValueEnabled(valuesToEnable, true); }, }); From 430d092554a1d88c1e186718631fa929aa9e77ba Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 17:46:31 +0200 Subject: [PATCH 33/55] integrate draft add list value --- src/ROUTES.ts | 4 +-- src/libs/Navigation/linkingConfig/config.ts | 3 +++ src/libs/Navigation/types.ts | 1 + src/libs/actions/Policy/ReportFields.ts | 9 +++++++ .../ReportFieldAddListValuePage.tsx | 25 +++++++++++++------ .../ReportFieldListValuesPage.tsx | 2 +- 6 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 6479f5faceb22..610756bf1252d 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -792,8 +792,8 @@ const ROUTES = { getRoute: (policyID: string, reportFieldID?: string) => `settings/workspaces/${policyID}/reportFields/new/listValues/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELD_ADD_VALUE: { - route: 'settings/workspaces/:policyID/reportFields/new/addValue', - getRoute: (policyID: string) => `settings/workspaces/${policyID}/reportFields/new/addValue` as const, + route: 'settings/workspaces/:policyID/reportFields/new/addValue/:reportFieldID?', + getRoute: (policyID: string, reportFieldID?: string) => `settings/workspaces/${policyID}/reportFields/new/addValue/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELD_VALUE_SETTINGS: { route: 'settings/workspaces/:policyID/reportFields/new/:valueIndex/:reportFieldID?', diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index ac21dc70fbe19..b464729ab1a87 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -536,6 +536,9 @@ const config: LinkingOptions['config'] = { }, [SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE]: { path: ROUTES.WORKSPACE_REPORT_FIELD_ADD_VALUE.route, + parse: { + reportFieldID: (reportFieldID: string) => decodeURIComponent(reportFieldID), + }, }, [SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS]: { path: ROUTES.WORKSPACE_REPORT_FIELD_VALUE_SETTINGS.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 90f2e6ae5da1e..5ef15d61b0ba5 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -277,6 +277,7 @@ type SettingsNavigatorParamList = { }; [SCREENS.WORKSPACE.REPORT_FIELDS_ADD_VALUE]: { policyID: string; + reportFieldID?: string; }; [SCREENS.WORKSPACE.REPORT_FIELDS_VALUE_SETTINGS]: { policyID: string; diff --git a/src/libs/actions/Policy/ReportFields.ts b/src/libs/actions/Policy/ReportFields.ts index 384ad4729815e..78b9c2d479006 100644 --- a/src/libs/actions/Policy/ReportFields.ts +++ b/src/libs/actions/Policy/ReportFields.ts @@ -339,6 +339,14 @@ function updateReportFieldListValueEnabled(policyID: string, reportFieldID: stri API.write(WRITE_COMMANDS.ENABLE_WORKSPACE_REPORT_FIELD_LIST_VALUE, parameters, onyxData); } +/** + * Adds a new list value to the workspace report fields. + */ +function addReportFieldListValue(policyID: string, reportFieldID: string, valueName: string) { + // eslint-disable-next-line no-console + console.info('addReportFieldListValue', policyID, reportFieldID, valueName); +} + export type {CreateReportFieldArguments}; export { @@ -350,4 +358,5 @@ export { createReportField, updateReportFieldInitialValue, updateReportFieldListValueEnabled, + addReportFieldListValue, }; diff --git a/src/pages/workspace/reportFields/ReportFieldAddListValuePage.tsx b/src/pages/workspace/reportFields/ReportFieldAddListValuePage.tsx index 715d947a7cbcb..c49da09438686 100644 --- a/src/pages/workspace/reportFields/ReportFieldAddListValuePage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldAddListValuePage.tsx @@ -23,7 +23,11 @@ import INPUT_IDS from '@src/types/form/WorkspaceReportFieldsForm'; type ReportFieldAddListValuePageProps = StackScreenProps; -function ReportFieldAddListValuePage({route}: ReportFieldAddListValuePageProps) { +function ReportFieldAddListValuePage({ + route: { + params: {policyID, reportFieldID}, + }, +}: ReportFieldAddListValuePageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const {inputCallbackRef} = useAutoFocusInput(); @@ -35,16 +39,23 @@ function ReportFieldAddListValuePage({route}: ReportFieldAddListValuePageProps) [formDraft], ); - const createValue = useCallback((values: FormOnyxValues) => { - ReportFields.createReportFieldsListValue(values[INPUT_IDS.VALUE_NAME]); - Keyboard.dismiss(); - Navigation.goBack(); - }, []); + const createValue = useCallback( + (values: FormOnyxValues) => { + if (reportFieldID) { + ReportFields.addReportFieldListValue(policyID, reportFieldID, values[INPUT_IDS.VALUE_NAME]); + } else { + ReportFields.createReportFieldsListValue(values[INPUT_IDS.VALUE_NAME]); + } + Keyboard.dismiss(); + Navigation.goBack(); + }, + [policyID, reportFieldID], + ); return ( Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELD_ADD_VALUE.getRoute(policyID))} + onPress={() => Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELD_ADD_VALUE.getRoute(policyID, reportFieldID))} /> ); }; From 9df8869cf165de44d029e8eba5183713c3df34df Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 18:33:58 +0200 Subject: [PATCH 34/55] integrate addReportFieldListValue --- ...eateWorkspaceReportFieldListValueParams.ts | 6 + src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 + src/libs/actions/Policy/ReportFields.ts | 63 +++++++- tests/actions/ReportFieldsTest.ts | 148 +++++++++++++++++- 5 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 src/libs/API/parameters/CreateWorkspaceReportFieldListValueParams.ts diff --git a/src/libs/API/parameters/CreateWorkspaceReportFieldListValueParams.ts b/src/libs/API/parameters/CreateWorkspaceReportFieldListValueParams.ts new file mode 100644 index 0000000000000..06ebe4dda82a6 --- /dev/null +++ b/src/libs/API/parameters/CreateWorkspaceReportFieldListValueParams.ts @@ -0,0 +1,6 @@ +type CreateWorkspaceReportFieldListValueParams = { + policyID: string; + reportFields: string; +}; + +export default CreateWorkspaceReportFieldListValueParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index bcd3607c4379b..e1deee61363e7 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -241,6 +241,7 @@ export type {default as UpdateNetSuiteSubsidiaryParams} from './UpdateNetSuiteSu export type {default as CreateWorkspaceReportFieldParams} from './CreateWorkspaceReportFieldParams'; export type {default as UpdateWorkspaceReportFieldInitialValueParams} from './UpdateWorkspaceReportFieldInitialValueParams'; export type {default as EnableWorkspaceReportFieldListValueParams} from './EnableWorkspaceReportFieldListValueParams'; +export type {default as CreateWorkspaceReportFieldListValueParams} from './CreateWorkspaceReportFieldListValueParams'; export type {default as OpenPolicyExpensifyCardsPageParams} from './OpenPolicyExpensifyCardsPageParams'; export type {default as RequestExpensifyCardLimitIncreaseParams} from './RequestExpensifyCardLimitIncreaseParams'; export type {default as UpdateNetSuiteGenericTypeParams} from './UpdateNetSuiteGenericTypeParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 0744c55123e09..e846df216090f 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -237,6 +237,7 @@ const WRITE_COMMANDS = { CREATE_WORKSPACE_REPORT_FIELD: 'CreatePolicyReportField', UPDATE_WORKSPACE_REPORT_FIELD_INITIAL_VALUE: 'SetPolicyReportFieldDefault', ENABLE_WORKSPACE_REPORT_FIELD_LIST_VALUE: 'EnablePolicyReportFieldOption', + CREATE_WORKSPACE_REPORT_FIELD_LIST_VALUE: 'CreatePolicyReportFieldOption', UPDATE_NETSUITE_SYNC_TAX_CONFIGURATION: 'UpdateNetSuiteSyncTaxConfiguration', UPDATE_NETSUITE_EXPORTER: 'UpdateNetSuiteExporter', UPDATE_NETSUITE_EXPORT_DATE: 'UpdateNetSuiteExportDate', @@ -502,6 +503,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.CREATE_WORKSPACE_REPORT_FIELD]: Parameters.CreateWorkspaceReportFieldParams; [WRITE_COMMANDS.UPDATE_WORKSPACE_REPORT_FIELD_INITIAL_VALUE]: Parameters.UpdateWorkspaceReportFieldInitialValueParams; [WRITE_COMMANDS.ENABLE_WORKSPACE_REPORT_FIELD_LIST_VALUE]: Parameters.EnableWorkspaceReportFieldListValueParams; + [WRITE_COMMANDS.CREATE_WORKSPACE_REPORT_FIELD_LIST_VALUE]: Parameters.CreateWorkspaceReportFieldListValueParams; [WRITE_COMMANDS.UPDATE_NETSUITE_SYNC_TAX_CONFIGURATION]: Parameters.UpdateNetSuiteGenericTypeParams<'enabled', boolean>; [WRITE_COMMANDS.UPDATE_NETSUITE_EXPORTER]: Parameters.UpdateNetSuiteGenericTypeParams<'email', string>; diff --git a/src/libs/actions/Policy/ReportFields.ts b/src/libs/actions/Policy/ReportFields.ts index 78b9c2d479006..f2f47be9e76a1 100644 --- a/src/libs/actions/Policy/ReportFields.ts +++ b/src/libs/actions/Policy/ReportFields.ts @@ -343,8 +343,67 @@ function updateReportFieldListValueEnabled(policyID: string, reportFieldID: stri * Adds a new list value to the workspace report fields. */ function addReportFieldListValue(policyID: string, reportFieldID: string, valueName: string) { - // eslint-disable-next-line no-console - console.info('addReportFieldListValue', policyID, reportFieldID, valueName); + const previousFieldList = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.fieldList ?? {}; + const fieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField = previousFieldList[fieldKey]; + const updatedReportField = cloneDeep(reportField); + + updatedReportField.values.push(valueName); + updatedReportField.disabledOptions.push(false); + + const onyxData: OnyxData = { + optimisticData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + fieldList: { + [fieldKey]: updatedReportField, + }, + pendingFields: { + [fieldKey]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + errorFields: null, + }, + }, + ], + successData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + pendingFields: { + [fieldKey]: null, + }, + errorFields: null, + }, + }, + ], + failureData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + fieldList: { + [fieldKey]: reportField, + }, + pendingFields: { + [fieldKey]: null, + }, + errorFields: { + [fieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.reportFields.genericFailureMessage'), + }, + }, + }, + ], + }; + + const parameters: EnableWorkspaceReportFieldListValueParams = { + policyID, + reportFields: JSON.stringify([updatedReportField]), + }; + + API.write(WRITE_COMMANDS.CREATE_WORKSPACE_REPORT_FIELD_LIST_VALUE, parameters, onyxData); } export type {CreateReportFieldArguments}; diff --git a/tests/actions/ReportFieldsTest.ts b/tests/actions/ReportFieldsTest.ts index 78e112bec17ff..223399e982bd8 100644 --- a/tests/actions/ReportFieldsTest.ts +++ b/tests/actions/ReportFieldsTest.ts @@ -451,7 +451,7 @@ describe('actions/ReportFields', () => { expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); }); - it('updates the enabled flag of a report field list value', async () => { + it('updates the enabled flag of a report field list value when api returns an error', async () => { mockFetch?.pause?.(); const policyID = Policy.generatePolicyID(); @@ -527,4 +527,150 @@ describe('actions/ReportFields', () => { expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); }); }); + + describe('addReportFieldListValue', () => { + it('adds a new value to a report field list', async () => { + mockFetch?.pause?.(); + + const policyID = Policy.generatePolicyID(); + const reportFieldName = 'Test Field'; + const reportFieldID = generateFieldID(reportFieldName); + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField: PolicyReportField = { + name: reportFieldName, + type: CONST.REPORT_FIELD_TYPES.LIST, + defaultValue: 'Value 2', + values: ['Value 1', 'Value 2', 'Value 3'], + disabledOptions: [false, false, true], + fieldID: reportFieldID, + orderWeight: 1, + deletable: false, + keys: [], + externalIDs: [], + isTax: false, + value: CONST.REPORT_FIELD_TYPES.LIST, + }; + const fakePolicy = createRandomPolicy(Number(policyID)); + const newListValueName = 'Value 4'; + + Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); + await waitForBatchedUpdates(); + + ReportFields.addReportFieldListValue(policyID, reportFieldID, newListValueName); + await waitForBatchedUpdates(); + + let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // check if the new report field was added to the policy + expect(policy?.fieldList).toStrictEqual>({ + [reportFieldKey]: { + ...reportField, + values: [...reportField.values, newListValueName], + disabledOptions: [...reportField.disabledOptions, false], + }, + }); + + // Check for success data + mockFetch?.resume?.(); + await waitForBatchedUpdates(); + + policy = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // Check if the policy pending action was cleared + // @ts-expect-error pendingFields is not null + expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + }); + + it('adds a new value to a report field list when api returns an error', async () => { + mockFetch?.pause?.(); + + const policyID = Policy.generatePolicyID(); + const reportFieldName = 'Test Field'; + const reportFieldID = generateFieldID(reportFieldName); + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField: PolicyReportField = { + name: reportFieldName, + type: CONST.REPORT_FIELD_TYPES.LIST, + defaultValue: 'Value 2', + values: ['Value 1', 'Value 2', 'Value 3'], + disabledOptions: [false, false, true], + fieldID: reportFieldID, + orderWeight: 1, + deletable: false, + keys: [], + externalIDs: [], + isTax: false, + value: CONST.REPORT_FIELD_TYPES.LIST, + }; + const fakePolicy = createRandomPolicy(Number(policyID)); + const newListValueName = 'Value 4'; + + Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); + await waitForBatchedUpdates(); + + ReportFields.addReportFieldListValue(policyID, reportFieldID, newListValueName); + await waitForBatchedUpdates(); + + let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // check if the new report field was added to the policy + expect(policy?.fieldList).toStrictEqual>({ + [reportFieldKey]: { + ...reportField, + values: [...reportField.values, newListValueName], + disabledOptions: [...reportField.disabledOptions, false], + }, + }); + + // Check for success data + mockFetch?.fail?.(); + mockFetch?.resume?.(); + await waitForBatchedUpdates(); + + policy = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // check if the updated report field was reset in the policy + expect(policy?.fieldList).toStrictEqual({ + [reportFieldKey]: reportField, + }); + // Check if the policy pending action was cleared + // @ts-expect-error pendingFields is not null + expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + // Check if the policy errors was set + // @ts-expect-error errorFields is not null + expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); + }); + }); }); From 029dded99f8298070f5d4cee0ba48a68e77fdc88 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Thu, 4 Jul 2024 18:35:55 +0200 Subject: [PATCH 35/55] prettify tests --- tests/actions/ReportFieldsTest.ts | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/tests/actions/ReportFieldsTest.ts b/tests/actions/ReportFieldsTest.ts index 223399e982bd8..495dcb60f7eea 100644 --- a/tests/actions/ReportFieldsTest.ts +++ b/tests/actions/ReportFieldsTest.ts @@ -79,13 +79,12 @@ describe('actions/ReportFields', () => { }); // Check for success data - (fetch as MockFetch)?.resume?.(); + mockFetch?.resume?.(); await waitForBatchedUpdates(); policy = await new Promise((resolve) => { const connectionID = Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY, - waitForCollectionCallback: true, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, callback: (workspace) => { Onyx.disconnect(connectionID); resolve(workspace); @@ -146,20 +145,18 @@ describe('actions/ReportFields', () => { }); // Check for success data - (fetch as MockFetch)?.resume?.(); + mockFetch?.resume?.(); await waitForBatchedUpdates(); policy = await new Promise((resolve) => { const connectionID = Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY, - waitForCollectionCallback: true, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, callback: (workspace) => { Onyx.disconnect(connectionID); resolve(workspace); }, }); }); - // Check if the policy pending action was cleared // @ts-expect-error pendingFields is not null expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); @@ -216,13 +213,12 @@ describe('actions/ReportFields', () => { }); // Check for success data - (fetch as MockFetch)?.resume?.(); + mockFetch?.resume?.(); await waitForBatchedUpdates(); policy = await new Promise((resolve) => { const connectionID = Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY, - waitForCollectionCallback: true, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, callback: (workspace) => { Onyx.disconnect(connectionID); resolve(workspace); @@ -286,13 +282,12 @@ describe('actions/ReportFields', () => { }); // Check for success data - (fetch as MockFetch)?.resume?.(); + mockFetch?.resume?.(); await waitForBatchedUpdates(); policy = await new Promise((resolve) => { const connectionID = Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY, - waitForCollectionCallback: true, + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, callback: (workspace) => { Onyx.disconnect(connectionID); resolve(workspace); @@ -432,7 +427,7 @@ describe('actions/ReportFields', () => { }); // Check for success data - (fetch as MockFetch)?.resume?.(); + mockFetch?.resume?.(); await waitForBatchedUpdates(); policy = await new Promise((resolve) => { From ee455fa124c62851229bf5e4e0fc02e7c50e5cce Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 5 Jul 2024 14:20:47 +0200 Subject: [PATCH 36/55] memorise reportFieldsSections --- .../WorkspaceReportFieldsPage.tsx | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx index 6eef5a7941eff..8465ec03c4f09 100644 --- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx @@ -60,24 +60,30 @@ function WorkspaceReportFieldsPage({ setSelectedReportFields([]); }, [isFocused]); - const reportFieldsList = useMemo(() => { + const reportFieldsSections = useMemo(() => { if (!policy) { - return []; + return [{data: [], isDisabled: true}]; } - return Object.values(filteredPolicyFieldList).map((reportField) => ({ - value: reportField.name, - fieldID: reportField.fieldID, - keyForList: String(reportField.orderWeight), - orderWeight: reportField.orderWeight, - isSelected: selectedReportFields.find((selectedReportField) => selectedReportField.name === reportField.name) !== undefined, - text: reportField.name, - rightElement: ( - - ), - })); + + return [ + { + data: Object.values(filteredPolicyFieldList).map((reportField) => ({ + value: reportField.name, + fieldID: reportField.fieldID, + keyForList: String(reportField.orderWeight), + orderWeight: reportField.orderWeight, + isSelected: selectedReportFields.find((selectedReportField) => selectedReportField.name === reportField.name) !== undefined, + text: reportField.name, + rightElement: ( + + ), + })), + isDisabled: false, + }, + ]; }, [filteredPolicyFieldList, policy, selectedReportFields]); const updateSelectedReportFields = (item: ReportFieldForList) => { @@ -88,7 +94,7 @@ function WorkspaceReportFieldsPage({ setSelectedReportFields(updatedReportFields); }; - const isLoading = reportFieldsList === undefined; + const isLoading = policy === undefined; const shouldShowEmptyState = Object.values(filteredPolicyFieldList).length <= 0 && !isLoading; const getHeaderButtons = () => ( @@ -138,7 +144,7 @@ function WorkspaceReportFieldsPage({ {!isSmallScreenWidth && getHeaderButtons()} {isSmallScreenWidth && {getHeaderButtons()}} - {(!isSmallScreenWidth || reportFieldsList.length === 0 || isLoading) && getHeaderText()} + {(!isSmallScreenWidth || reportFieldsSections[0].data.length === 0 || isLoading) && getHeaderText()} {isLoading && ( Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELD.getRoute(policyID, item.fieldID))} onSelectAll={() => {}} From 48c185cba3c58e1148cd86605d19c86a2b7639c0 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 5 Jul 2024 15:05:40 +0200 Subject: [PATCH 37/55] integrate values list removing --- ...moveWorkspaceReportFieldListValueParams.ts | 6 + src/libs/API/parameters/index.ts | 1 + src/libs/API/types.ts | 2 + src/libs/actions/Policy/ReportFields.ts | 95 +++++++++-- .../ReportFieldListValuesPage.tsx | 12 +- .../ReportFieldValueSettingsPage.tsx | 7 +- src/types/onyx/Policy.ts | 2 +- tests/actions/ReportFieldsTest.ts | 153 +++++++++++++++++- 8 files changed, 263 insertions(+), 15 deletions(-) create mode 100644 src/libs/API/parameters/RemoveWorkspaceReportFieldListValueParams.ts diff --git a/src/libs/API/parameters/RemoveWorkspaceReportFieldListValueParams.ts b/src/libs/API/parameters/RemoveWorkspaceReportFieldListValueParams.ts new file mode 100644 index 0000000000000..0774d7840aea6 --- /dev/null +++ b/src/libs/API/parameters/RemoveWorkspaceReportFieldListValueParams.ts @@ -0,0 +1,6 @@ +type RemoveWorkspaceReportFieldListValueParams = { + policyID: string; + reportFields: string; +}; + +export default RemoveWorkspaceReportFieldListValueParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 17b8d4698f760..310987ee54c40 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -243,6 +243,7 @@ export type {default as CreateWorkspaceReportFieldParams} from './CreateWorkspac export type {default as UpdateWorkspaceReportFieldInitialValueParams} from './UpdateWorkspaceReportFieldInitialValueParams'; export type {default as EnableWorkspaceReportFieldListValueParams} from './EnableWorkspaceReportFieldListValueParams'; export type {default as CreateWorkspaceReportFieldListValueParams} from './CreateWorkspaceReportFieldListValueParams'; +export type {default as RemoveWorkspaceReportFieldListValueParams} from './RemoveWorkspaceReportFieldListValueParams'; export type {default as OpenPolicyExpensifyCardsPageParams} from './OpenPolicyExpensifyCardsPageParams'; export type {default as RequestExpensifyCardLimitIncreaseParams} from './RequestExpensifyCardLimitIncreaseParams'; export type {default as UpdateNetSuiteGenericTypeParams} from './UpdateNetSuiteGenericTypeParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index c8b72c0fc79ec..7c5071d1fe317 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -238,6 +238,7 @@ const WRITE_COMMANDS = { UPDATE_WORKSPACE_REPORT_FIELD_INITIAL_VALUE: 'SetPolicyReportFieldDefault', ENABLE_WORKSPACE_REPORT_FIELD_LIST_VALUE: 'EnablePolicyReportFieldOption', CREATE_WORKSPACE_REPORT_FIELD_LIST_VALUE: 'CreatePolicyReportFieldOption', + REMOVE_WORKSPACE_REPORT_FIELD_LIST_VALUE: 'RemovePolicyReportFieldOption', UPDATE_NETSUITE_SYNC_TAX_CONFIGURATION: 'UpdateNetSuiteSyncTaxConfiguration', UPDATE_NETSUITE_CROSS_SUBSIDIARY_CUSTOMER_CONFIGURATION: 'UpdateNetSuiteCrossSubsidiaryCustomerConfiguration', UPDATE_NETSUITE_DEPARTMENTS_MAPPING: 'UpdateNetSuiteDepartmentsMapping', @@ -517,6 +518,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.UPDATE_WORKSPACE_REPORT_FIELD_INITIAL_VALUE]: Parameters.UpdateWorkspaceReportFieldInitialValueParams; [WRITE_COMMANDS.ENABLE_WORKSPACE_REPORT_FIELD_LIST_VALUE]: Parameters.EnableWorkspaceReportFieldListValueParams; [WRITE_COMMANDS.CREATE_WORKSPACE_REPORT_FIELD_LIST_VALUE]: Parameters.CreateWorkspaceReportFieldListValueParams; + [WRITE_COMMANDS.REMOVE_WORKSPACE_REPORT_FIELD_LIST_VALUE]: Parameters.RemoveWorkspaceReportFieldListValueParams; [WRITE_COMMANDS.UPDATE_NETSUITE_SYNC_TAX_CONFIGURATION]: Parameters.UpdateNetSuiteGenericTypeParams<'enabled', boolean>; [WRITE_COMMANDS.UPDATE_NETSUITE_CROSS_SUBSIDIARY_CUSTOMER_CONFIGURATION]: Parameters.UpdateNetSuiteGenericTypeParams<'enabled', boolean>; diff --git a/src/libs/actions/Policy/ReportFields.ts b/src/libs/actions/Policy/ReportFields.ts index f2f47be9e76a1..d3ee03d8f55e4 100644 --- a/src/libs/actions/Policy/ReportFields.ts +++ b/src/libs/actions/Policy/ReportFields.ts @@ -2,7 +2,12 @@ import cloneDeep from 'lodash/cloneDeep'; import type {NullishDeep, OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import * as API from '@libs/API'; -import type {CreateWorkspaceReportFieldParams, EnableWorkspaceReportFieldListValueParams, UpdateWorkspaceReportFieldInitialValueParams} from '@libs/API/parameters'; +import type { + CreateWorkspaceReportFieldParams, + EnableWorkspaceReportFieldListValueParams, + RemoveWorkspaceReportFieldListValueParams, + UpdateWorkspaceReportFieldInitialValueParams, +} from '@libs/API/parameters'; import {WRITE_COMMANDS} from '@libs/API/types'; import * as ErrorUtils from '@libs/ErrorUtils'; import * as ReportUtils from '@libs/ReportUtils'; @@ -344,8 +349,8 @@ function updateReportFieldListValueEnabled(policyID: string, reportFieldID: stri */ function addReportFieldListValue(policyID: string, reportFieldID: string, valueName: string) { const previousFieldList = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.fieldList ?? {}; - const fieldKey = ReportUtils.getReportFieldKey(reportFieldID); - const reportField = previousFieldList[fieldKey]; + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField = previousFieldList[reportFieldKey]; const updatedReportField = cloneDeep(reportField); updatedReportField.values.push(valueName); @@ -358,10 +363,10 @@ function addReportFieldListValue(policyID: string, reportFieldID: string, valueN onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [fieldKey]: updatedReportField, + [reportFieldKey]: updatedReportField, }, pendingFields: { - [fieldKey]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + [reportFieldKey]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, errorFields: null, }, @@ -373,7 +378,7 @@ function addReportFieldListValue(policyID: string, reportFieldID: string, valueN onyxMethod: Onyx.METHOD.MERGE, value: { pendingFields: { - [fieldKey]: null, + [reportFieldKey]: null, }, errorFields: null, }, @@ -385,13 +390,13 @@ function addReportFieldListValue(policyID: string, reportFieldID: string, valueN onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [fieldKey]: reportField, + [reportFieldKey]: reportField, }, pendingFields: { - [fieldKey]: null, + [reportFieldKey]: null, }, errorFields: { - [fieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.reportFields.genericFailureMessage'), + [reportFieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.reportFields.genericFailureMessage'), }, }, }, @@ -406,6 +411,77 @@ function addReportFieldListValue(policyID: string, reportFieldID: string, valueN API.write(WRITE_COMMANDS.CREATE_WORKSPACE_REPORT_FIELD_LIST_VALUE, parameters, onyxData); } +/** + * Removes a list value from the workspace report fields. + */ +function removeReportFieldListValue(policyID: string, reportFieldID: string, valueIndexes: number[]) { + const previousFieldList = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.fieldList ?? {}; + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField = previousFieldList[reportFieldKey]; + const updatedReportField = cloneDeep(reportField); + + valueIndexes + .sort((a, b) => b - a) + .forEach((valueIndex) => { + const shouldResetDefaultValue = reportField.defaultValue === reportField.values[valueIndex]; + + if (shouldResetDefaultValue) { + updatedReportField.defaultValue = ''; + } + + updatedReportField.values.splice(valueIndex, 1); + updatedReportField.disabledOptions.splice(valueIndex, 1); + }); + + const onyxData: OnyxData = { + optimisticData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + fieldList: { + [reportFieldKey]: {...updatedReportField, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE}, + }, + errorFields: null, + }, + }, + ], + successData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + fieldList: { + [reportFieldKey]: {pendingAction: null}, + }, + errorFields: null, + }, + }, + ], + failureData: [ + { + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + onyxMethod: Onyx.METHOD.MERGE, + value: { + fieldList: { + [reportFieldKey]: {...reportField, pendingAction: null}, + }, + errorFields: { + [reportFieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.reportFields.genericFailureMessage'), + }, + }, + }, + ], + }; + + const parameters: RemoveWorkspaceReportFieldListValueParams = { + policyID, + reportFields: JSON.stringify([updatedReportField]), + }; + + API.write(WRITE_COMMANDS.REMOVE_WORKSPACE_REPORT_FIELD_LIST_VALUE, parameters, onyxData); +} + export type {CreateReportFieldArguments}; export { @@ -418,4 +494,5 @@ export { updateReportFieldInitialValue, updateReportFieldListValueEnabled, addReportFieldListValue, + removeReportFieldListValue, }; diff --git a/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx index 1635c1b8b360a..73567f1f3dbd6 100644 --- a/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldListValuesPage.tsx @@ -78,13 +78,14 @@ function ReportFieldListValuesPage({ }, [formDraft?.disabledListValues, formDraft?.listValues, policy?.fieldList, reportFieldID]); const listValuesSections = useMemo(() => { - const data = listValues.map((value, index) => ({ + const data = listValues.map((value, index) => ({ value, index, text: value, keyForList: value, isSelected: selectedValues[value], enabled: !disabledListValues[index] ?? true, + pendingAction: reportFieldID ? policy?.fieldList?.[ReportUtils.getReportFieldKey(reportFieldID)]?.pendingAction : null, rightElement: ( selectedValues[key]); @@ -125,7 +126,12 @@ function ReportFieldListValuesPage({ return acc; }, []); - ReportFields.deleteReportFieldsListValue(valuesToDelete); + if (reportFieldID) { + ReportFields.removeReportFieldListValue(policyID, reportFieldID, valuesToDelete); + } else { + ReportFields.deleteReportFieldsListValue(valuesToDelete); + } + setDeleteValuesConfirmModalVisible(false); }; diff --git a/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx b/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx index 64c9f2e55c120..c8020a0293b92 100644 --- a/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldValueSettingsPage.tsx @@ -61,7 +61,12 @@ function ReportFieldValueSettingsPage({ } const deleteListValueAndHideModal = () => { - ReportFields.deleteReportFieldsListValue([valueIndex]); + if (reportFieldID) { + ReportFields.removeReportFieldListValue(policyID, reportFieldID, [valueIndex]); + } else { + ReportFields.deleteReportFieldsListValue([valueIndex]); + } + setIsDeleteTagModalOpen(false); Navigation.goBack(); }; diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 098869d7bf8e6..5ac9f26ab6d37 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -1259,7 +1259,7 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< connections?: Connections; /** Report fields attached to the policy */ - fieldList?: Record; + fieldList?: Record>; /** Whether the Categories feature is enabled */ areCategoriesEnabled?: boolean; diff --git a/tests/actions/ReportFieldsTest.ts b/tests/actions/ReportFieldsTest.ts index 495dcb60f7eea..959d2096d52ce 100644 --- a/tests/actions/ReportFieldsTest.ts +++ b/tests/actions/ReportFieldsTest.ts @@ -11,6 +11,7 @@ import * as ReportUtils from '@src/libs/ReportUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import INPUT_IDS from '@src/types/form/WorkspaceReportFieldsForm'; import type {PolicyReportField, Policy as PolicyType} from '@src/types/onyx'; +import type {OnyxValueWithOfflineFeedback} from '@src/types/onyx/OnyxCommon'; import createRandomPolicy from '../utils/collections/policies'; import * as TestHelper from '../utils/TestHelper'; import type {MockFetch} from '../utils/TestHelper'; @@ -641,7 +642,7 @@ describe('actions/ReportFields', () => { }, }); - // Check for success data + // Check for failure data mockFetch?.fail?.(); mockFetch?.resume?.(); await waitForBatchedUpdates(); @@ -668,4 +669,154 @@ describe('actions/ReportFields', () => { expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); }); }); + + describe('removeReportFieldListValue', () => { + it('removes list values from a report field list', async () => { + mockFetch?.pause?.(); + + const policyID = Policy.generatePolicyID(); + const reportFieldName = 'Test Field'; + const reportFieldID = generateFieldID(reportFieldName); + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField: PolicyReportField = { + name: reportFieldName, + type: CONST.REPORT_FIELD_TYPES.LIST, + defaultValue: 'Value 2', + values: ['Value 1', 'Value 2', 'Value 3'], + disabledOptions: [false, false, true], + fieldID: reportFieldID, + orderWeight: 1, + deletable: false, + keys: [], + externalIDs: [], + isTax: false, + value: CONST.REPORT_FIELD_TYPES.LIST, + }; + const fakePolicy = createRandomPolicy(Number(policyID)); + + Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); + await waitForBatchedUpdates(); + + ReportFields.removeReportFieldListValue(policyID, reportFieldID, [1, 2]); + await waitForBatchedUpdates(); + + let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // Check if the values were removed from the report field + expect(policy?.fieldList).toStrictEqual>>({ + [reportFieldKey]: { + ...reportField, + defaultValue: '', + values: ['Value 1'], + disabledOptions: [false], + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + }, + }); + + // Check for success data + mockFetch?.resume?.(); + await waitForBatchedUpdates(); + + policy = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // Check if the policy pending action was cleared + // @ts-expect-error pendingFields is not null + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); + }); + + it('removes list values from a report field list when api returns an error', async () => { + mockFetch?.pause?.(); + + const policyID = Policy.generatePolicyID(); + const reportFieldName = 'Test Field'; + const reportFieldID = generateFieldID(reportFieldName); + const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); + const reportField: PolicyReportField = { + name: reportFieldName, + type: CONST.REPORT_FIELD_TYPES.LIST, + defaultValue: 'Value 2', + values: ['Value 1', 'Value 2', 'Value 3'], + disabledOptions: [false, false, true], + fieldID: reportFieldID, + orderWeight: 1, + deletable: false, + keys: [], + externalIDs: [], + isTax: false, + value: CONST.REPORT_FIELD_TYPES.LIST, + }; + const fakePolicy = createRandomPolicy(Number(policyID)); + + Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); + await waitForBatchedUpdates(); + + ReportFields.removeReportFieldListValue(policyID, reportFieldID, [1, 2]); + await waitForBatchedUpdates(); + + let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // Check if the values were removed from the report field + expect(policy?.fieldList).toStrictEqual>>({ + [reportFieldKey]: { + ...reportField, + defaultValue: '', + values: ['Value 1'], + disabledOptions: [false], + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + }, + }); + + // Check for failure data + mockFetch?.fail?.(); + mockFetch?.resume?.(); + await waitForBatchedUpdates(); + + policy = await new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + + // check if the updated report field was reset in the policy + expect(policy?.fieldList).toStrictEqual({ + [reportFieldKey]: reportField, + }); + // Check if the policy pending action was cleared + // @ts-expect-error pendingFields is not null + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); + // Check if the policy errors was set + // @ts-expect-error errorFields is not null + expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); + }); + }); }); From acf5dd08979bdef8f71c4a0d0fae621c9f632819 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 5 Jul 2024 15:31:45 +0200 Subject: [PATCH 38/55] use update pending action for values list --- src/libs/actions/Policy/ReportFields.ts | 22 +++++++++++----------- tests/actions/ReportFieldsTest.ts | 16 ++++++++++------ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/libs/actions/Policy/ReportFields.ts b/src/libs/actions/Policy/ReportFields.ts index d3ee03d8f55e4..c66402f3b4bae 100644 --- a/src/libs/actions/Policy/ReportFields.ts +++ b/src/libs/actions/Policy/ReportFields.ts @@ -363,10 +363,10 @@ function addReportFieldListValue(policyID: string, reportFieldID: string, valueN onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [reportFieldKey]: updatedReportField, - }, - pendingFields: { - [reportFieldKey]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + [reportFieldKey]: { + ...updatedReportField, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, }, errorFields: null, }, @@ -377,8 +377,8 @@ function addReportFieldListValue(policyID: string, reportFieldID: string, valueN key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, onyxMethod: Onyx.METHOD.MERGE, value: { - pendingFields: { - [reportFieldKey]: null, + fieldList: { + [reportFieldKey]: {pendingAction: null}, }, errorFields: null, }, @@ -390,10 +390,7 @@ function addReportFieldListValue(policyID: string, reportFieldID: string, valueN onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [reportFieldKey]: reportField, - }, - pendingFields: { - [reportFieldKey]: null, + [reportFieldKey]: {...reportField, pendingAction: null}, }, errorFields: { [reportFieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.reportFields.genericFailureMessage'), @@ -440,7 +437,10 @@ function removeReportFieldListValue(policyID: string, reportFieldID: string, val onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [reportFieldKey]: {...updatedReportField, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE}, + [reportFieldKey]: { + ...updatedReportField, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, }, errorFields: null, }, diff --git a/tests/actions/ReportFieldsTest.ts b/tests/actions/ReportFieldsTest.ts index 959d2096d52ce..a0eca96c9a582 100644 --- a/tests/actions/ReportFieldsTest.ts +++ b/tests/actions/ReportFieldsTest.ts @@ -566,11 +566,12 @@ describe('actions/ReportFields', () => { }); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual>({ + expect(policy?.fieldList).toStrictEqual>>({ [reportFieldKey]: { ...reportField, values: [...reportField.values, newListValueName], disabledOptions: [...reportField.disabledOptions, false], + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }); @@ -590,7 +591,8 @@ describe('actions/ReportFields', () => { // Check if the policy pending action was cleared // @ts-expect-error pendingFields is not null - expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); }); it('adds a new value to a report field list when api returns an error', async () => { @@ -634,11 +636,12 @@ describe('actions/ReportFields', () => { }); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual>({ + expect(policy?.fieldList).toStrictEqual>>({ [reportFieldKey]: { ...reportField, values: [...reportField.values, newListValueName], disabledOptions: [...reportField.disabledOptions, false], + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }); @@ -663,7 +666,8 @@ describe('actions/ReportFields', () => { }); // Check if the policy pending action was cleared // @ts-expect-error pendingFields is not null - expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); // Check if the policy errors was set // @ts-expect-error errorFields is not null expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); @@ -717,7 +721,7 @@ describe('actions/ReportFields', () => { defaultValue: '', values: ['Value 1'], disabledOptions: [false], - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }); @@ -787,7 +791,7 @@ describe('actions/ReportFields', () => { defaultValue: '', values: ['Value 1'], disabledOptions: [false], - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }); From aef7cb52631d7942af3c6189a4634a2368fb07ae Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 5 Jul 2024 15:36:39 +0200 Subject: [PATCH 39/55] clarify routes --- src/ROUTES.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index d0744f49210ba..b18962ad4b386 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -788,17 +788,17 @@ const ROUTES = { getRoute: (policyID: string) => `settings/workspaces/${policyID}/reportFields/new` as const, }, WORKSPACE_REPORT_FIELD_LIST_VALUES: { - route: 'settings/workspaces/:policyID/reportFields/new/listValues/:reportFieldID?', - getRoute: (policyID: string, reportFieldID?: string) => `settings/workspaces/${policyID}/reportFields/new/listValues/${encodeURIComponent(reportFieldID ?? '')}` as const, + route: 'settings/workspaces/:policyID/reportFields/listValues/:reportFieldID?', + getRoute: (policyID: string, reportFieldID?: string) => `settings/workspaces/${policyID}/reportFields/listValues/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELD_ADD_VALUE: { - route: 'settings/workspaces/:policyID/reportFields/new/addValue/:reportFieldID?', - getRoute: (policyID: string, reportFieldID?: string) => `settings/workspaces/${policyID}/reportFields/new/addValue/${encodeURIComponent(reportFieldID ?? '')}` as const, + route: 'settings/workspaces/:policyID/reportFields/addValue/:reportFieldID?', + getRoute: (policyID: string, reportFieldID?: string) => `settings/workspaces/${policyID}/reportFields/addValue/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELD_VALUE_SETTINGS: { - route: 'settings/workspaces/:policyID/reportFields/new/:valueIndex/:reportFieldID?', + route: 'settings/workspaces/:policyID/reportFields/:valueIndex/:reportFieldID?', getRoute: (policyID: string, valueIndex: number, reportFieldID?: string) => - `settings/workspaces/${policyID}/reportFields/new/${valueIndex}/${encodeURIComponent(reportFieldID ?? '')}` as const, + `settings/workspaces/${policyID}/reportFields/${valueIndex}/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELD_EDIT_VALUE: { route: 'settings/workspaces/:policyID/reportFields/new/:valueIndex/edit', From b10ad13f36827db150ec8761dc6874b0b939d695 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 5 Jul 2024 15:40:23 +0200 Subject: [PATCH 40/55] add js doc --- src/libs/API/parameters/CreateWorkspaceReportFieldParams.ts | 4 ++++ .../parameters/EnableWorkspaceReportFieldListValueParams.ts | 4 ++++ .../parameters/RemoveWorkspaceReportFieldListValueParams.ts | 4 ++++ .../UpdateWorkspaceReportFieldInitialValueParams.ts | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/src/libs/API/parameters/CreateWorkspaceReportFieldParams.ts b/src/libs/API/parameters/CreateWorkspaceReportFieldParams.ts index 13844a279905e..33692d2109599 100644 --- a/src/libs/API/parameters/CreateWorkspaceReportFieldParams.ts +++ b/src/libs/API/parameters/CreateWorkspaceReportFieldParams.ts @@ -1,5 +1,9 @@ type CreateWorkspaceReportFieldParams = { policyID: string; + /** + * Stringified JSON object with type of following structure: + * Array + */ reportFields: string; }; diff --git a/src/libs/API/parameters/EnableWorkspaceReportFieldListValueParams.ts b/src/libs/API/parameters/EnableWorkspaceReportFieldListValueParams.ts index b8fc126acfcfd..7c54a2f4c68b8 100644 --- a/src/libs/API/parameters/EnableWorkspaceReportFieldListValueParams.ts +++ b/src/libs/API/parameters/EnableWorkspaceReportFieldListValueParams.ts @@ -1,5 +1,9 @@ type EnableWorkspaceReportFieldListValueParams = { policyID: string; + /** + * Stringified JSON object with type of following structure: + * Array + */ reportFields: string; }; diff --git a/src/libs/API/parameters/RemoveWorkspaceReportFieldListValueParams.ts b/src/libs/API/parameters/RemoveWorkspaceReportFieldListValueParams.ts index 0774d7840aea6..94d90a8dbaaec 100644 --- a/src/libs/API/parameters/RemoveWorkspaceReportFieldListValueParams.ts +++ b/src/libs/API/parameters/RemoveWorkspaceReportFieldListValueParams.ts @@ -1,5 +1,9 @@ type RemoveWorkspaceReportFieldListValueParams = { policyID: string; + /** + * Stringified JSON object with type of following structure: + * Array + */ reportFields: string; }; diff --git a/src/libs/API/parameters/UpdateWorkspaceReportFieldInitialValueParams.ts b/src/libs/API/parameters/UpdateWorkspaceReportFieldInitialValueParams.ts index 74426d8873d5e..a72781ff1c37c 100644 --- a/src/libs/API/parameters/UpdateWorkspaceReportFieldInitialValueParams.ts +++ b/src/libs/API/parameters/UpdateWorkspaceReportFieldInitialValueParams.ts @@ -1,5 +1,9 @@ type UpdateWorkspaceReportFieldInitialValueParams = { policyID: string; + /** + * Stringified JSON object with type of following structure: + * Array + */ reportFields: string; }; From 2655a143510b622e8a57fb0327a2ffd792960e68 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Fri, 5 Jul 2024 16:40:53 +0200 Subject: [PATCH 41/55] fix ref error --- src/components/ReportFieldsInitialListValuePicker.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/ReportFieldsInitialListValuePicker.tsx b/src/components/ReportFieldsInitialListValuePicker.tsx index 45f6bd6dd9778..33911462b9c48 100644 --- a/src/components/ReportFieldsInitialListValuePicker.tsx +++ b/src/components/ReportFieldsInitialListValuePicker.tsx @@ -1,6 +1,8 @@ -import React, {useMemo} from 'react'; +import type {ForwardedRef} from 'react'; +import React, {forwardRef, useMemo} from 'react'; import SelectionList from './SelectionList'; import RadioListItem from './SelectionList/RadioListItem'; +import type {SelectionListHandle} from './SelectionList/types'; type ReportFieldsInitialListValuePickerProps = { /** Options to select from if field is of type list */ @@ -16,7 +18,7 @@ type ReportFieldsInitialListValuePickerProps = { onInputChange?: (value: string) => void; }; -function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, onInputChange}: ReportFieldsInitialListValuePickerProps) { +function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, onInputChange}: ReportFieldsInitialListValuePickerProps, forwardedRef: ForwardedRef) { const listValueSections = useMemo( () => [ { @@ -35,6 +37,7 @@ function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, return ( onInputChange?.(item.value)} @@ -45,4 +48,4 @@ function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, ReportFieldsInitialListValuePicker.displayName = 'ReportFieldsInitialListValuePicker'; -export default ReportFieldsInitialListValuePicker; +export default forwardRef(ReportFieldsInitialListValuePicker); From 773706ca9be5e1f32a86933ecb37c8e8898c695f Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 11:08:08 +0200 Subject: [PATCH 42/55] clarify route --- src/ROUTES.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 324fa7c9a5d45..8ed7587d438f6 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -809,8 +809,8 @@ const ROUTES = { `settings/workspaces/${policyID}/reportField/${valueIndex}/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELD_EDIT_VALUE: { - route: 'settings/workspaces/:policyID/reportField/new/:valueIndex/edit', - getRoute: (policyID: string, valueIndex: number) => `settings/workspaces/${policyID}/reportField/new/${valueIndex}/edit` as const, + route: 'settings/workspaces/:policyID/reportField/:valueIndex/edit', + getRoute: (policyID: string, valueIndex: number) => `settings/workspaces/${policyID}/reportField/${valueIndex}/edit` as const, }, WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE: { route: 'settings/workspaces/:policyID/reportField/:reportFieldID/edit/initialValue', From abf31ce24e3afed1e149a6103902df36ea3c2386 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 11:15:00 +0200 Subject: [PATCH 43/55] Revert "clarify route" This reverts commit 773706ca9be5e1f32a86933ecb37c8e8898c695f. --- src/ROUTES.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 8ed7587d438f6..324fa7c9a5d45 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -809,8 +809,8 @@ const ROUTES = { `settings/workspaces/${policyID}/reportField/${valueIndex}/${encodeURIComponent(reportFieldID ?? '')}` as const, }, WORKSPACE_REPORT_FIELD_EDIT_VALUE: { - route: 'settings/workspaces/:policyID/reportField/:valueIndex/edit', - getRoute: (policyID: string, valueIndex: number) => `settings/workspaces/${policyID}/reportField/${valueIndex}/edit` as const, + route: 'settings/workspaces/:policyID/reportField/new/:valueIndex/edit', + getRoute: (policyID: string, valueIndex: number) => `settings/workspaces/${policyID}/reportField/new/${valueIndex}/edit` as const, }, WORKSPACE_EDIT_REPORT_FIELD_INITIAL_VALUE: { route: 'settings/workspaces/:policyID/reportField/:reportFieldID/edit/initialValue', From 69e9f7989f217b96578cd837822da27420c8c966 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 12:47:25 +0200 Subject: [PATCH 44/55] fix list key --- src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx index 8db43dfeef5d2..4ab6e48811c59 100644 --- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx +++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx @@ -75,7 +75,7 @@ function WorkspaceReportFieldsPage({ data: Object.values(filteredPolicyFieldList).map((reportField) => ({ value: reportField.name, fieldID: reportField.fieldID, - keyForList: String(reportField.orderWeight), + keyForList: String(reportField.fieldID), orderWeight: reportField.orderWeight, pendingAction: reportField.pendingAction, isSelected: selectedReportFields.find((selectedReportField) => selectedReportField.name === reportField.name) !== undefined, From 72ec86e8ece7daefdb26dfd0bc598c9410030b1b Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 12:54:23 +0200 Subject: [PATCH 45/55] fix scroll view nesting --- .../ReportFieldInitialValuePage.tsx | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx b/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx index 7576e5d547a97..9fd9757b3882c 100644 --- a/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx @@ -105,17 +105,17 @@ function ReportFieldInitialValuePage({ title={reportField.name} onBackButtonPress={Navigation.goBack} /> - - {isTextFieldType && ( + {isTextFieldType && ( + - )} - {isListFieldType && ( - submitListValueUpdate(value as string)} - /> - )} - + + )} + {isListFieldType && ( + + )} ); From a09e692635db722c192cfc5358dc28e71a0d3c24 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 13:37:01 +0200 Subject: [PATCH 46/55] mark value as not required property of a report field --- src/types/onyx/Policy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 395de399bc9d3..9e50c5c77bf01 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -1062,7 +1062,7 @@ type PolicyReportField = { deletable: boolean; /** Value of the field */ - value: string | null; + value?: string | null; /** Options to select from if field is of type dropdown */ values: string[]; From b844f08b6eb3a43291b8d5a8aea913bacbd6cef1 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 13:37:25 +0200 Subject: [PATCH 47/55] fix and improve pendingAction setting --- src/libs/actions/Policy/ReportField.ts | 33 ++---- tests/actions/ReportFieldTest.ts | 146 +++++++++++++------------ 2 files changed, 85 insertions(+), 94 deletions(-) diff --git a/src/libs/actions/Policy/ReportField.ts b/src/libs/actions/Policy/ReportField.ts index 1e11d98af6b91..9590ae9df3f23 100644 --- a/src/libs/actions/Policy/ReportField.ts +++ b/src/libs/actions/Policy/ReportField.ts @@ -143,7 +143,7 @@ function createReportField(policyID: string, {name, type, initialValue}: CreateR const previousFieldList = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.fieldList ?? {}; const fieldID = WorkspaceReportFieldUtils.generateFieldID(name); const fieldKey = ReportUtils.getReportFieldKey(fieldID); - const newReportField: OnyxValueWithOfflineFeedback = { + const newReportField: PolicyReportField = { name, type, defaultValue: initialValue, @@ -156,7 +156,6 @@ function createReportField(policyID: string, {name, type, initialValue}: CreateR keys: [], externalIDs: [], isTax: false, - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }; const onyxData: OnyxData = { optimisticData: [ @@ -165,7 +164,7 @@ function createReportField(policyID: string, {name, type, initialValue}: CreateR onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [fieldKey]: newReportField, + [fieldKey]: {...newReportField, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, }, errorFields: null, }, @@ -285,10 +284,7 @@ function updateReportFieldInitialValue(policyID: string, reportFieldID: string, onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [fieldKey]: updatedReportField, - }, - pendingFields: { - [fieldKey]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + [fieldKey]: {...updatedReportField, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}, }, errorFields: null, }, @@ -299,8 +295,8 @@ function updateReportFieldInitialValue(policyID: string, reportFieldID: string, key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, onyxMethod: Onyx.METHOD.MERGE, value: { - pendingFields: { - [fieldKey]: null, + fieldList: { + [fieldKey]: {pendingAction: null}, }, errorFields: null, }, @@ -312,10 +308,7 @@ function updateReportFieldInitialValue(policyID: string, reportFieldID: string, onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [fieldKey]: previousFieldList[fieldKey], - }, - pendingFields: { - [fieldKey]: null, + [fieldKey]: {...previousFieldList[fieldKey], pendingAction: null}, }, errorFields: { [fieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.reportFields.genericFailureMessage'), @@ -355,10 +348,7 @@ function updateReportFieldListValueEnabled(policyID: string, reportFieldID: stri onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [fieldKey]: updatedReportField, - }, - pendingFields: { - [fieldKey]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + [fieldKey]: {...updatedReportField, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}, }, errorFields: null, }, @@ -369,8 +359,8 @@ function updateReportFieldListValueEnabled(policyID: string, reportFieldID: stri key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, onyxMethod: Onyx.METHOD.MERGE, value: { - pendingFields: { - [fieldKey]: null, + fieldList: { + [fieldKey]: {pendingAction: null}, }, errorFields: null, }, @@ -382,10 +372,7 @@ function updateReportFieldListValueEnabled(policyID: string, reportFieldID: stri onyxMethod: Onyx.METHOD.MERGE, value: { fieldList: { - [fieldKey]: reportField, - }, - pendingFields: { - [fieldKey]: null, + [fieldKey]: {...reportField, pendingAction: null}, }, errorFields: { [fieldKey]: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.reportFields.genericFailureMessage'), diff --git a/tests/actions/ReportFieldTest.ts b/tests/actions/ReportFieldTest.ts index d7870711db6f9..b8dff2503186d 100644 --- a/tests/actions/ReportFieldTest.ts +++ b/tests/actions/ReportFieldTest.ts @@ -42,7 +42,7 @@ describe('actions/ReportField', () => { const reportFieldName = 'Test Field'; const reportFieldID = generateFieldID(reportFieldName); const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); - const newReportField: OnyxValueWithOfflineFeedback> = { + const newReportField: OnyxValueWithOfflineFeedback = { name: reportFieldName, type: CONST.REPORT_FIELD_TYPES.TEXT, defaultValue: 'Default Value', @@ -76,8 +76,8 @@ describe('actions/ReportField', () => { }); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual({ - [reportFieldKey]: newReportField, + expect(policy?.fieldList).toStrictEqual>>({ + [reportFieldKey]: {...newReportField, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, }); // Check for success data @@ -110,7 +110,7 @@ describe('actions/ReportField', () => { const reportFieldID = generateFieldID(reportFieldName); const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); const defaultDate = DateUtils.extractDate(new Date().toString()); - const newReportField: OnyxValueWithOfflineFeedback> = { + const newReportField: OnyxValueWithOfflineFeedback = { name: reportFieldName, type: CONST.REPORT_FIELD_TYPES.DATE, defaultValue: defaultDate, @@ -144,8 +144,8 @@ describe('actions/ReportField', () => { }); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual({ - [reportFieldKey]: newReportField, + expect(policy?.fieldList).toStrictEqual>>({ + [reportFieldKey]: {...newReportField, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, }); // Check for success data @@ -214,8 +214,8 @@ describe('actions/ReportField', () => { }); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual({ - [reportFieldKey]: newReportField, + expect(policy?.fieldList).toStrictEqual>>({ + [reportFieldKey]: {...newReportField, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, }); // Check for success data @@ -276,7 +276,7 @@ describe('actions/ReportField', () => { }); // check if the report field exists in the policy - expect(policy?.fieldList).toStrictEqual({ + expect(policy?.fieldList).toStrictEqual>>({ [reportFieldKey]: fakeReportField, }); @@ -344,7 +344,7 @@ describe('actions/ReportField', () => { }); // check if the report field exists in the policy - expect(policy?.fieldList).toStrictEqual({ + expect(policy?.fieldList).toStrictEqual>>({ [reportFieldKey]: fakeReportField, }); @@ -367,7 +367,7 @@ describe('actions/ReportField', () => { }); // check if the deleted report field was reset in the policy - expect(policy?.fieldList).toStrictEqual({ + expect(policy?.fieldList).toStrictEqual>>({ [reportFieldKey]: fakeReportField, }); // Check if the policy pending action was cleared @@ -379,35 +379,37 @@ describe('actions/ReportField', () => { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); }); + }); - it('updates the enabled flag of a report field list value when api returns an error', async () => { + describe('updateReportFieldInitialValue', () => { + it('updates the initial value of a text report field', async () => { mockFetch?.pause?.(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; - const valueIndexesToUpdate = [1]; + const oldInitialValue = 'Old initial value'; + const newInitialValue = 'New initial value'; const reportFieldID = generateFieldID(reportFieldName); const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); const reportField: PolicyReportField = { name: reportFieldName, - type: CONST.REPORT_FIELD_TYPES.LIST, - defaultValue: 'Value 2', - values: ['Value 1', 'Value 2', 'Value 3'], - disabledOptions: [false, false, true], + type: CONST.REPORT_FIELD_TYPES.TEXT, + defaultValue: oldInitialValue, + values: [], + disabledOptions: [], fieldID: reportFieldID, orderWeight: 1, deletable: false, keys: [], externalIDs: [], isTax: false, - value: CONST.REPORT_FIELD_TYPES.LIST, }; const fakePolicy = createRandomPolicy(Number(policyID)); Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); await waitForBatchedUpdates(); - ReportField.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexesToUpdate, false); + ReportField.updateReportFieldInitialValue(policyID, reportFieldID, newInitialValue); await waitForBatchedUpdates(); let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { @@ -420,17 +422,16 @@ describe('actions/ReportField', () => { }); }); - // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual>({ + // check if the updated report field was set to the policy + expect(policy?.fieldList).toStrictEqual>>({ [reportFieldKey]: { ...reportField, - defaultValue: '', - disabledOptions: [false, true, true], + defaultValue: newInitialValue, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }); - // Check for failure data - mockFetch?.fail?.(); + // Check for success data mockFetch?.resume?.(); await waitForBatchedUpdates(); @@ -444,21 +445,12 @@ describe('actions/ReportField', () => { }); }); - // check if the updated report field was reset in the policy - expect(policy?.fieldList).toStrictEqual({ - [reportFieldKey]: reportField, - }); // Check if the policy pending action was cleared // @ts-expect-error pendingFields is not null expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); - // Check if the policy errors was set - // @ts-expect-error errorFields is not null - expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); }); - }); - describe('updateReportFieldInitialValue', () => { - it('updates the initial value of a text report field', async () => { + it('updates the initial value of a text report field when api returns an error', async () => { mockFetch?.pause?.(); const policyID = Policy.generatePolicyID(); @@ -467,7 +459,7 @@ describe('actions/ReportField', () => { const newInitialValue = 'New initial value'; const reportFieldID = generateFieldID(reportFieldName); const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); - const reportField: Omit = { + const reportField: PolicyReportField = { name: reportFieldName, type: CONST.REPORT_FIELD_TYPES.TEXT, defaultValue: oldInitialValue, @@ -499,14 +491,16 @@ describe('actions/ReportField', () => { }); // check if the updated report field was set to the policy - expect(policy?.fieldList).toStrictEqual({ + expect(policy?.fieldList).toStrictEqual>>({ [reportFieldKey]: { ...reportField, defaultValue: newInitialValue, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }); - // Check for success data + // Check for failure data + mockFetch?.fail?.(); mockFetch?.resume?.(); await waitForBatchedUpdates(); @@ -520,39 +514,48 @@ describe('actions/ReportField', () => { }); }); + // check if the updated report field was reset in the policy + expect(policy?.fieldList).toStrictEqual>>({ + [reportFieldKey]: reportField, + }); // Check if the policy pending action was cleared // @ts-expect-error pendingFields is not null expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + // Check if the policy errors was set + // @ts-expect-error errorFields is not null + expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); }); + }); - it('updates the initial value of a text report field when api returns an error', async () => { + describe('updateReportFieldListValueEnabled', () => { + it('updates the enabled flag of report field list values', async () => { mockFetch?.pause?.(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; - const oldInitialValue = 'Old initial value'; - const newInitialValue = 'New initial value'; + const valueIndexesTpUpdate = [1, 2]; const reportFieldID = generateFieldID(reportFieldName); const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); - const reportField: Omit = { + const reportField: PolicyReportField = { name: reportFieldName, - type: CONST.REPORT_FIELD_TYPES.TEXT, - defaultValue: oldInitialValue, - values: [], - disabledOptions: [], + type: CONST.REPORT_FIELD_TYPES.LIST, + defaultValue: 'Value 2', + values: ['Value 1', 'Value 2', 'Value 3'], + disabledOptions: [false, false, true], fieldID: reportFieldID, orderWeight: 1, deletable: false, keys: [], externalIDs: [], isTax: false, + value: CONST.REPORT_FIELD_TYPES.LIST, }; const fakePolicy = createRandomPolicy(Number(policyID)); Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); await waitForBatchedUpdates(); - ReportField.updateReportFieldInitialValue(policyID, reportFieldID, newInitialValue); + ReportField.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexesTpUpdate, false); await waitForBatchedUpdates(); let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { @@ -565,16 +568,17 @@ describe('actions/ReportField', () => { }); }); - // check if the updated report field was set to the policy - expect(policy?.fieldList).toStrictEqual({ + // check if the new report field was added to the policy + expect(policy?.fieldList).toStrictEqual>>({ [reportFieldKey]: { ...reportField, - defaultValue: newInitialValue, + defaultValue: '', + disabledOptions: [false, true, true], + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }); - // Check for failure data - mockFetch?.fail?.(); + // Check for success data mockFetch?.resume?.(); await waitForBatchedUpdates(); @@ -588,26 +592,18 @@ describe('actions/ReportField', () => { }); }); - // check if the updated report field was reset in the policy - expect(policy?.fieldList).toStrictEqual({ - [reportFieldKey]: reportField, - }); // Check if the policy pending action was cleared // @ts-expect-error pendingFields is not null - expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); - // Check if the policy errors was set - // @ts-expect-error errorFields is not null - expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); }); - }); - describe('updateReportFieldListValueEnabled', () => { - it('updates the enabled flag of report field list values', async () => { + it('updates the enabled flag of a report field list value when api returns an error', async () => { mockFetch?.pause?.(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; - const valueIndexesTpUpdate = [1, 2]; + const valueIndexesToUpdate = [1]; const reportFieldID = generateFieldID(reportFieldName); const reportFieldKey = ReportUtils.getReportFieldKey(reportFieldID); const reportField: PolicyReportField = { @@ -629,7 +625,7 @@ describe('actions/ReportField', () => { Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {...fakePolicy, fieldList: {[reportFieldKey]: reportField}}); await waitForBatchedUpdates(); - ReportField.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexesTpUpdate, false); + ReportField.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexesToUpdate, false); await waitForBatchedUpdates(); let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { @@ -643,15 +639,17 @@ describe('actions/ReportField', () => { }); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual>({ + expect(policy?.fieldList).toStrictEqual>>({ [reportFieldKey]: { ...reportField, defaultValue: '', disabledOptions: [false, true, true], + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }); - // Check for success data + // Check for failure data + mockFetch?.fail?.(); mockFetch?.resume?.(); await waitForBatchedUpdates(); @@ -665,10 +663,16 @@ describe('actions/ReportField', () => { }); }); + // check if the updated report field was reset in the policy + expect(policy?.fieldList).toStrictEqual>>({ + [reportFieldKey]: reportField, + }); // Check if the policy pending action was cleared // @ts-expect-error pendingFields is not null - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); + expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + // Check if the policy errors was set + // @ts-expect-error errorFields is not null + expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); }); }); @@ -809,7 +813,7 @@ describe('actions/ReportField', () => { }); // check if the updated report field was reset in the policy - expect(policy?.fieldList).toStrictEqual({ + expect(policy?.fieldList).toStrictEqual>>({ [reportFieldKey]: reportField, }); // Check if the policy pending action was cleared @@ -959,7 +963,7 @@ describe('actions/ReportField', () => { }); // check if the updated report field was reset in the policy - expect(policy?.fieldList).toStrictEqual({ + expect(policy?.fieldList).toStrictEqual>>({ [reportFieldKey]: reportField, }); // Check if the policy pending action was cleared From 9ca2958db6ff334610075b98f99fb6bed8f9dda1 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 13:43:52 +0200 Subject: [PATCH 48/55] not capitalize --- src/ONYXKEYS.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 2f9e5516e51dd..44f3fcb55520c 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -460,8 +460,8 @@ const ONYXKEYS = { WORKSPACE_RATE_AND_UNIT_FORM_DRAFT: 'workspaceRateAndUnitFormDraft', WORKSPACE_TAX_CUSTOM_NAME: 'workspaceTaxCustomName', WORKSPACE_TAX_CUSTOM_NAME_DRAFT: 'workspaceTaxCustomNameDraft', - WORKSPACE_REPORT_FIELDS_FORM: 'WorkspaceReportFieldForm', - WORKSPACE_REPORT_FIELDS_FORM_DRAFT: 'WorkspaceReportFieldFormDraft', + WORKSPACE_REPORT_FIELDS_FORM: 'workspaceReportFieldForm', + WORKSPACE_REPORT_FIELDS_FORM_DRAFT: 'workspaceReportFieldFormDraft', POLICY_CREATE_DISTANCE_RATE_FORM: 'policyCreateDistanceRateForm', POLICY_CREATE_DISTANCE_RATE_FORM_DRAFT: 'policyCreateDistanceRateFormDraft', POLICY_DISTANCE_RATE_EDIT_FORM: 'policyDistanceRateEditForm', From 0376879aabdc7d1eea9ff5ba249552f651b7fcad Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 13:46:47 +0200 Subject: [PATCH 49/55] revert form props for ReportFieldsInitialListValuePicker --- src/components/Form/types.ts | 4 +--- src/components/ReportFieldsInitialListValuePicker.tsx | 6 +++--- .../InitialListValueSelectorModal.tsx | 2 +- .../workspace/reportFields/ReportFieldInitialValuePage.tsx | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/components/Form/types.ts b/src/components/Form/types.ts index 2de05698cd648..afbe2bb124b5a 100644 --- a/src/components/Form/types.ts +++ b/src/components/Form/types.ts @@ -13,7 +13,6 @@ import type DatePicker from '@components/DatePicker'; import type EmojiPickerButtonDropdown from '@components/EmojiPicker/EmojiPickerButtonDropdown'; import type Picker from '@components/Picker'; import type RadioButtons from '@components/RadioButtons'; -import type ReportFieldsInitialListValuePicker from '@components/ReportFieldsInitialListValuePicker'; import type RoomNameInput from '@components/RoomNameInput'; import type SingleChoiceQuestion from '@components/SingleChoiceQuestion'; import type StateSelector from '@components/StateSelector'; @@ -48,8 +47,7 @@ type ValidInputs = | typeof AmountPicker | typeof TextPicker | typeof AddPlaidBankAccount - | typeof EmojiPickerButtonDropdown - | typeof ReportFieldsInitialListValuePicker; + | typeof EmojiPickerButtonDropdown; type ValueTypeKey = 'string' | 'boolean' | 'date' | 'country' | 'reportFields' | 'disabledListValues'; type ValueTypeMap = { diff --git a/src/components/ReportFieldsInitialListValuePicker.tsx b/src/components/ReportFieldsInitialListValuePicker.tsx index 33911462b9c48..ac5abfb09abc1 100644 --- a/src/components/ReportFieldsInitialListValuePicker.tsx +++ b/src/components/ReportFieldsInitialListValuePicker.tsx @@ -15,10 +15,10 @@ type ReportFieldsInitialListValuePickerProps = { value: string; /** Function to call when the user selects a value */ - onInputChange?: (value: string) => void; + onValueChange: (value: string) => void; }; -function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, onInputChange}: ReportFieldsInitialListValuePickerProps, forwardedRef: ForwardedRef) { +function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, onValueChange}: ReportFieldsInitialListValuePickerProps, forwardedRef: ForwardedRef) { const listValueSections = useMemo( () => [ { @@ -40,7 +40,7 @@ function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, ref={forwardedRef} sections={listValueSections} ListItem={RadioListItem} - onSelectRow={(item) => onInputChange?.(item.value)} + onSelectRow={(item) => onValueChange(item.value)} initiallyFocusedOptionKey={listValueSections[0].data.find((listValue) => listValue.isSelected)?.keyForList} /> ); diff --git a/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx b/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx index 3b995f91dbf5b..acf4f20f13be0 100644 --- a/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx +++ b/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx @@ -62,7 +62,7 @@ function InitialListValueSelectorModal({isVisible, currentValue, label, subtitle listValues={formDraft?.listValues ?? []} disabledOptions={formDraft?.disabledListValues ?? []} value={currentValue} - onInputChange={onValueSelected} + onValueChange={onValueSelected} /> diff --git a/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx b/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx index 9fd9757b3882c..960999765a1c3 100644 --- a/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx @@ -136,7 +136,7 @@ function ReportFieldInitialValuePage({ listValues={reportField.values} disabledOptions={reportField.disabledOptions} value={initialValue} - onInputChange={submitListValueUpdate} + onValueChange={submitListValueUpdate} /> )} From c01d2a4881046f93e2406cb74cd896b4a16841a5 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 13:48:00 +0200 Subject: [PATCH 50/55] move ReportFieldsInitialListValuePicker --- .../InitialListValueSelectorModal.tsx | 2 +- .../ReportFieldsInitialListValuePicker.tsx | 6 +++--- .../workspace/reportFields/ReportFieldInitialValuePage.tsx | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename src/{components => pages/workspace/reportFields/InitialListValueSelector}/ReportFieldsInitialListValuePicker.tsx (89%) diff --git a/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx b/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx index acf4f20f13be0..fa6c5dc76bdbf 100644 --- a/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx +++ b/src/pages/workspace/reportFields/InitialListValueSelector/InitialListValueSelectorModal.tsx @@ -3,12 +3,12 @@ import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Modal from '@components/Modal'; -import ReportFieldsInitialListValuePicker from '@components/ReportFieldsInitialListValuePicker'; import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ReportFieldsInitialListValuePicker from './ReportFieldsInitialListValuePicker'; type InitialListValueSelectorModalProps = { /** Whether the modal is visible */ diff --git a/src/components/ReportFieldsInitialListValuePicker.tsx b/src/pages/workspace/reportFields/InitialListValueSelector/ReportFieldsInitialListValuePicker.tsx similarity index 89% rename from src/components/ReportFieldsInitialListValuePicker.tsx rename to src/pages/workspace/reportFields/InitialListValueSelector/ReportFieldsInitialListValuePicker.tsx index ac5abfb09abc1..5a8e6ca34287e 100644 --- a/src/components/ReportFieldsInitialListValuePicker.tsx +++ b/src/pages/workspace/reportFields/InitialListValueSelector/ReportFieldsInitialListValuePicker.tsx @@ -1,8 +1,8 @@ import type {ForwardedRef} from 'react'; import React, {forwardRef, useMemo} from 'react'; -import SelectionList from './SelectionList'; -import RadioListItem from './SelectionList/RadioListItem'; -import type {SelectionListHandle} from './SelectionList/types'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import type {SelectionListHandle} from '@components/SelectionList/types'; type ReportFieldsInitialListValuePickerProps = { /** Options to select from if field is of type list */ diff --git a/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx b/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx index 960999765a1c3..1cf075d27f016 100644 --- a/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx +++ b/src/pages/workspace/reportFields/ReportFieldInitialValuePage.tsx @@ -4,7 +4,6 @@ import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import ReportFieldsInitialListValuePicker from '@components/ReportFieldsInitialListValuePicker'; import ScreenWrapper from '@components/ScreenWrapper'; import TextInput from '@components/TextInput'; import useAutoFocusInput from '@hooks/useAutoFocusInput'; @@ -25,6 +24,7 @@ import * as ValidationUtils from '@src/libs/ValidationUtils'; import ONYXKEYS from '@src/ONYXKEYS'; import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/WorkspaceReportFieldForm'; +import ReportFieldsInitialListValuePicker from './InitialListValueSelector/ReportFieldsInitialListValuePicker'; type ReportFieldInitialValuePagePageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps; function ReportFieldInitialValuePage({ From 68610edbaa9b606e1d3af4ddd2c67fb1565532ae Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 13:48:48 +0200 Subject: [PATCH 51/55] remove ref from ReportFieldsInitialListValuePicker --- .../ReportFieldsInitialListValuePicker.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/pages/workspace/reportFields/InitialListValueSelector/ReportFieldsInitialListValuePicker.tsx b/src/pages/workspace/reportFields/InitialListValueSelector/ReportFieldsInitialListValuePicker.tsx index 5a8e6ca34287e..18f9f9d652592 100644 --- a/src/pages/workspace/reportFields/InitialListValueSelector/ReportFieldsInitialListValuePicker.tsx +++ b/src/pages/workspace/reportFields/InitialListValueSelector/ReportFieldsInitialListValuePicker.tsx @@ -1,8 +1,6 @@ -import type {ForwardedRef} from 'react'; -import React, {forwardRef, useMemo} from 'react'; +import React, {useMemo} from 'react'; import SelectionList from '@components/SelectionList'; import RadioListItem from '@components/SelectionList/RadioListItem'; -import type {SelectionListHandle} from '@components/SelectionList/types'; type ReportFieldsInitialListValuePickerProps = { /** Options to select from if field is of type list */ @@ -18,7 +16,7 @@ type ReportFieldsInitialListValuePickerProps = { onValueChange: (value: string) => void; }; -function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, onValueChange}: ReportFieldsInitialListValuePickerProps, forwardedRef: ForwardedRef) { +function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, onValueChange}: ReportFieldsInitialListValuePickerProps) { const listValueSections = useMemo( () => [ { @@ -37,7 +35,6 @@ function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, return ( onValueChange(item.value)} @@ -48,4 +45,4 @@ function ReportFieldsInitialListValuePicker({listValues, disabledOptions, value, ReportFieldsInitialListValuePicker.displayName = 'ReportFieldsInitialListValuePicker'; -export default forwardRef(ReportFieldsInitialListValuePicker); +export default ReportFieldsInitialListValuePicker; From ac9c1a8f7c46557decf6ef19cb56b84bc419a954 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 13:49:30 +0200 Subject: [PATCH 52/55] add js doc --- .../parameters/CreateWorkspaceReportFieldListValueParams.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libs/API/parameters/CreateWorkspaceReportFieldListValueParams.ts b/src/libs/API/parameters/CreateWorkspaceReportFieldListValueParams.ts index 06ebe4dda82a6..950287bc5d04d 100644 --- a/src/libs/API/parameters/CreateWorkspaceReportFieldListValueParams.ts +++ b/src/libs/API/parameters/CreateWorkspaceReportFieldListValueParams.ts @@ -1,5 +1,9 @@ type CreateWorkspaceReportFieldListValueParams = { policyID: string; + /** + * Stringified JSON object with type of following structure: + * Array + */ reportFields: string; }; From 001061f20e3580c7f2fdad1fb98bb7fa8bff9e23 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Mon, 8 Jul 2024 14:16:16 +0200 Subject: [PATCH 53/55] refactor ReportFieldTest --- tests/actions/ReportFieldTest.ts | 439 +++++++------------------------ 1 file changed, 99 insertions(+), 340 deletions(-) diff --git a/tests/actions/ReportFieldTest.ts b/tests/actions/ReportFieldTest.ts index b8dff2503186d..4676d187a211b 100644 --- a/tests/actions/ReportFieldTest.ts +++ b/tests/actions/ReportFieldTest.ts @@ -1,4 +1,4 @@ -import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import DateUtils from '@libs/DateUtils'; import {generateFieldID} from '@libs/WorkspaceReportFieldUtils'; @@ -19,6 +19,20 @@ import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; OnyxUpdateManager(); describe('actions/ReportField', () => { + type PolicyReportFieldWithOfflineFeedback = Record>; + + function connectToFetchPolicy(policyID: string): Promise> { + return new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, + callback: (workspace) => { + Onyx.disconnect(connectionID); + resolve(workspace); + }, + }); + }); + } + beforeAll(() => { Onyx.init({ keys: ONYXKEYS, @@ -34,7 +48,7 @@ describe('actions/ReportField', () => { describe('createReportField', () => { it('creates a new text report field of a workspace', async () => { - mockFetch?.pause?.(); + mockFetch.pause(); Onyx.set(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM_DRAFT, {}); await waitForBatchedUpdates(); @@ -65,43 +79,25 @@ describe('actions/ReportField', () => { ReportField.createReportField(policyID, createReportFieldArguments); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: {...newReportField, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, }); // Check for success data - mockFetch?.resume?.(); + mockFetch.resume(); await waitForBatchedUpdates(); - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + policy = await connectToFetchPolicy(policyID); // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); }); it('creates a new date report field of a workspace', async () => { - mockFetch?.pause?.(); + mockFetch.pause(); Onyx.set(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM_DRAFT, {}); await waitForBatchedUpdates(); @@ -133,42 +129,25 @@ describe('actions/ReportField', () => { ReportField.createReportField(policyID, createReportFieldArguments); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: {...newReportField, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, }); // Check for success data - mockFetch?.resume?.(); + mockFetch.resume(); await waitForBatchedUpdates(); - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + policy = await connectToFetchPolicy(policyID); + // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); }); it('creates a new list report field of a workspace', async () => { - mockFetch?.pause?.(); + mockFetch.pause(); Onyx.set(ONYXKEYS.FORMS.WORKSPACE_REPORT_FIELDS_FORM_DRAFT, { [INPUT_IDS.LIST_VALUES]: ['Value 1', 'Value 2'], [INPUT_IDS.DISABLED_LIST_VALUES]: [false, true], @@ -203,38 +182,21 @@ describe('actions/ReportField', () => { ReportField.createReportField(policyID, createReportFieldArguments); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: {...newReportField, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, }); // Check for success data - mockFetch?.resume?.(); + mockFetch.resume(); await waitForBatchedUpdates(); - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + policy = await connectToFetchPolicy(policyID); // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + expect(policy?.fieldList?.[reportFieldKey].pendingAction).toBeFalsy(); }); }); @@ -265,18 +227,10 @@ describe('actions/ReportField', () => { Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${fakePolicy.id}`, fakePolicy); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${fakePolicy.id}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(fakePolicy.id); // check if the report field exists in the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: fakeReportField, }); @@ -284,27 +238,13 @@ describe('actions/ReportField', () => { await waitForBatchedUpdates(); // Check for success data - mockFetch?.resume?.(); + mockFetch.resume(); await waitForBatchedUpdates(); - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${fakePolicy.id}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + policy = await connectToFetchPolicy(fakePolicy.id); // Check if the policy report field was removed - // @ts-expect-error fieldList is not null expect(policy?.fieldList?.[reportFieldKey]).toBeFalsy(); - - // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); }); it('Deleted a report field from a workspace when API fails', async () => { @@ -333,57 +273,33 @@ describe('actions/ReportField', () => { Onyx.set(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, fakePolicy); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // check if the report field exists in the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: fakeReportField, }); // Check for failure data - mockFetch?.fail?.(); + mockFetch.fail(); ReportField.deleteReportFields(policyID, [reportFieldKey]); await waitForBatchedUpdates(); - mockFetch?.resume?.(); + mockFetch.resume(); await waitForBatchedUpdates(); - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + policy = await connectToFetchPolicy(policyID); // check if the deleted report field was reset in the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: fakeReportField, }); - // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); - - // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); }); }); describe('updateReportFieldInitialValue', () => { it('updates the initial value of a text report field', async () => { - mockFetch?.pause?.(); + mockFetch.pause(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; @@ -412,18 +328,10 @@ describe('actions/ReportField', () => { ReportField.updateReportFieldInitialValue(policyID, reportFieldID, newInitialValue); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // check if the updated report field was set to the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: { ...reportField, defaultValue: newInitialValue, @@ -432,26 +340,17 @@ describe('actions/ReportField', () => { }); // Check for success data - mockFetch?.resume?.(); + mockFetch.resume(); await waitForBatchedUpdates(); - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + policy = await connectToFetchPolicy(policyID); // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); + expect(policy?.fieldList?.[reportFieldKey].pendingAction).toBeFalsy(); }); it('updates the initial value of a text report field when api returns an error', async () => { - mockFetch?.pause?.(); + mockFetch.pause(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; @@ -480,18 +379,10 @@ describe('actions/ReportField', () => { ReportField.updateReportFieldInitialValue(policyID, reportFieldID, newInitialValue); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // check if the updated report field was set to the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: { ...reportField, defaultValue: newInitialValue, @@ -500,36 +391,24 @@ describe('actions/ReportField', () => { }); // Check for failure data - mockFetch?.fail?.(); - mockFetch?.resume?.(); - await waitForBatchedUpdates(); - - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + mockFetch.fail(); + mockFetch.resume(); + await waitForBatchedUpdates(); + + policy = await connectToFetchPolicy(policyID); // check if the updated report field was reset in the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: reportField, }); - // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); // Check if the policy errors was set - // @ts-expect-error errorFields is not null expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); }); }); describe('updateReportFieldListValueEnabled', () => { it('updates the enabled flag of report field list values', async () => { - mockFetch?.pause?.(); + mockFetch.pause(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; @@ -558,18 +437,10 @@ describe('actions/ReportField', () => { ReportField.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexesTpUpdate, false); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: { ...reportField, defaultValue: '', @@ -579,27 +450,17 @@ describe('actions/ReportField', () => { }); // Check for success data - mockFetch?.resume?.(); + mockFetch.resume(); await waitForBatchedUpdates(); - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + policy = await connectToFetchPolicy(policyID); // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); }); it('updates the enabled flag of a report field list value when api returns an error', async () => { - mockFetch?.pause?.(); + mockFetch.pause(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; @@ -628,18 +489,10 @@ describe('actions/ReportField', () => { ReportField.updateReportFieldListValueEnabled(policyID, reportFieldID, valueIndexesToUpdate, false); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: { ...reportField, defaultValue: '', @@ -649,36 +502,24 @@ describe('actions/ReportField', () => { }); // Check for failure data - mockFetch?.fail?.(); - mockFetch?.resume?.(); - await waitForBatchedUpdates(); - - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + mockFetch.fail(); + mockFetch.resume(); + await waitForBatchedUpdates(); + + policy = await connectToFetchPolicy(policyID); // check if the updated report field was reset in the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: reportField, }); - // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - expect(policy?.pendingFields?.[reportFieldKey]).toBeFalsy(); // Check if the policy errors was set - // @ts-expect-error errorFields is not null expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); }); }); describe('addReportFieldListValue', () => { it('adds a new value to a report field list', async () => { - mockFetch?.pause?.(); + mockFetch.pause(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; @@ -707,18 +548,9 @@ describe('actions/ReportField', () => { ReportField.addReportFieldListValue(policyID, reportFieldID, newListValueName); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); - + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: { ...reportField, values: [...reportField.values, newListValueName], @@ -728,27 +560,17 @@ describe('actions/ReportField', () => { }); // Check for success data - mockFetch?.resume?.(); + mockFetch.resume(); await waitForBatchedUpdates(); - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + policy = await connectToFetchPolicy(policyID); // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); }); it('adds a new value to a report field list when api returns an error', async () => { - mockFetch?.pause?.(); + mockFetch.pause(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; @@ -777,18 +599,10 @@ describe('actions/ReportField', () => { ReportField.addReportFieldListValue(policyID, reportFieldID, newListValueName); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // check if the new report field was added to the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: { ...reportField, values: [...reportField.values, newListValueName], @@ -798,37 +612,22 @@ describe('actions/ReportField', () => { }); // Check for failure data - mockFetch?.fail?.(); - mockFetch?.resume?.(); - await waitForBatchedUpdates(); - - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + mockFetch.fail(); + mockFetch.resume(); + await waitForBatchedUpdates(); + + policy = await connectToFetchPolicy(policyID); // check if the updated report field was reset in the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: reportField, }); - // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); - // Check if the policy errors was set - // @ts-expect-error errorFields is not null - expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); }); }); describe('removeReportFieldListValue', () => { it('removes list values from a report field list', async () => { - mockFetch?.pause?.(); + mockFetch.pause(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; @@ -856,18 +655,10 @@ describe('actions/ReportField', () => { ReportField.removeReportFieldListValue(policyID, reportFieldID, [1, 2]); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // Check if the values were removed from the report field - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: { ...reportField, defaultValue: '', @@ -878,27 +669,16 @@ describe('actions/ReportField', () => { }); // Check for success data - mockFetch?.resume?.(); + mockFetch.resume(); await waitForBatchedUpdates(); - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); - + policy = await connectToFetchPolicy(policyID); // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); }); it('removes list values from a report field list when api returns an error', async () => { - mockFetch?.pause?.(); + mockFetch.pause(); const policyID = Policy.generatePolicyID(); const reportFieldName = 'Test Field'; @@ -926,18 +706,10 @@ describe('actions/ReportField', () => { ReportField.removeReportFieldListValue(policyID, reportFieldID, [1, 2]); await waitForBatchedUpdates(); - let policy: OnyxEntry | OnyxCollection = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + let policy: OnyxEntry = await connectToFetchPolicy(policyID); // Check if the values were removed from the report field - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: { ...reportField, defaultValue: '', @@ -948,30 +720,17 @@ describe('actions/ReportField', () => { }); // Check for failure data - mockFetch?.fail?.(); - mockFetch?.resume?.(); - await waitForBatchedUpdates(); - - policy = await new Promise((resolve) => { - const connectionID = Onyx.connect({ - key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, - callback: (workspace) => { - Onyx.disconnect(connectionID); - resolve(workspace); - }, - }); - }); + mockFetch.fail(); + mockFetch.resume(); + await waitForBatchedUpdates(); + + policy = await connectToFetchPolicy(policyID); // check if the updated report field was reset in the policy - expect(policy?.fieldList).toStrictEqual>>({ + expect(policy?.fieldList).toStrictEqual({ [reportFieldKey]: reportField, }); - // Check if the policy pending action was cleared - // @ts-expect-error pendingFields is not null - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - expect(policy?.fieldList?.[reportFieldKey]?.pendingAction).toBeFalsy(); // Check if the policy errors was set - // @ts-expect-error errorFields is not null expect(policy?.errorFields?.[reportFieldKey]).toBeTruthy(); }); }); From b18736a4da05fd1a2a4c184f7ca8cae33928fdfe Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 9 Jul 2024 17:48:27 +0200 Subject: [PATCH 54/55] tweak comment --- src/libs/actions/Policy/ReportField.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Policy/ReportField.ts b/src/libs/actions/Policy/ReportField.ts index 9590ae9df3f23..6b7a125207a09 100644 --- a/src/libs/actions/Policy/ReportField.ts +++ b/src/libs/actions/Policy/ReportField.ts @@ -390,7 +390,7 @@ function updateReportFieldListValueEnabled(policyID: string, reportFieldID: stri } /** - * Adds a new list value to the workspace report fields. + * Adds a new option to the list type report field on a workspace. */ function addReportFieldListValue(policyID: string, reportFieldID: string, valueName: string) { const previousFieldList = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.fieldList ?? {}; From e724077911c1019e0c3a5bbf8dbed16cc3975eb4 Mon Sep 17 00:00:00 2001 From: Mykhailo Kravchenko Date: Tue, 9 Jul 2024 17:50:20 +0200 Subject: [PATCH 55/55] fix type usage --- src/libs/actions/Policy/ReportField.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/Policy/ReportField.ts b/src/libs/actions/Policy/ReportField.ts index 6b7a125207a09..31af3ff53c4ce 100644 --- a/src/libs/actions/Policy/ReportField.ts +++ b/src/libs/actions/Policy/ReportField.ts @@ -3,6 +3,7 @@ import type {NullishDeep, OnyxCollection} from 'react-native-onyx'; import Onyx from 'react-native-onyx'; import * as API from '@libs/API'; import type { + CreateWorkspaceReportFieldListValueParams, CreateWorkspaceReportFieldParams, EnableWorkspaceReportFieldListValueParams, PolicyReportFieldsReplace, @@ -445,7 +446,7 @@ function addReportFieldListValue(policyID: string, reportFieldID: string, valueN ], }; - const parameters: EnableWorkspaceReportFieldListValueParams = { + const parameters: CreateWorkspaceReportFieldListValueParams = { policyID, reportFields: JSON.stringify([updatedReportField]), };