From 0f25f752f82aa4c3d98635441c8abd28f8e24444 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Sun, 14 Jan 2024 22:34:32 +0500 Subject: [PATCH 01/13] feat: save the report fields in backend --- .../ReportActionItem/MoneyReportView.tsx | 6 +- src/languages/en.ts | 1 + src/languages/es.ts | 1 + src/libs/Permissions.ts | 2 +- src/libs/ReportUtils.ts | 6 +- src/libs/actions/Report.ts | 61 ++++++++++++++++++- src/pages/EditReportFieldDatePage.tsx | 2 +- src/pages/EditReportFieldDropdownPage.tsx | 9 ++- src/pages/EditReportFieldPage.tsx | 17 +++++- src/pages/EditReportFieldTextPage.tsx | 2 +- 10 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/components/ReportActionItem/MoneyReportView.tsx b/src/components/ReportActionItem/MoneyReportView.tsx index 8c6e818d2411..ccac50d688b2 100644 --- a/src/components/ReportActionItem/MoneyReportView.tsx +++ b/src/components/ReportActionItem/MoneyReportView.tsx @@ -55,8 +55,8 @@ function MoneyReportView({report, policyReportFields, shouldShowHorizontalRule}: StyleUtils.getColorStyle(theme.textSupporting), ]; - const sortedPolicyReportFields = useMemo( - () => policyReportFields.sort(({orderWeight: firstOrderWeight}, {orderWeight: secondOrderWeight}) => firstOrderWeight - secondOrderWeight), + const sortedPolicyReportFields = useMemo( + (): PolicyReportField[] => policyReportFields.sort(({orderWeight: firstOrderWeight}, {orderWeight: secondOrderWeight}) => firstOrderWeight - secondOrderWeight), [policyReportFields], ); @@ -70,6 +70,8 @@ function MoneyReportView({report, policyReportFields, shouldShowHorizontalRule}: return ( ): boolean { } function canUseReportFields(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.REPORT_FIELDS) || canUseAllBetas(betas); + return true; // !!betas?.includes(CONST.BETAS.REPORT_FIELDS) || canUseAllBetas(betas); } function canUseViolations(betas: OnyxEntry): boolean { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index c2d98c1ee00c..e00d8afc1362 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4330,15 +4330,15 @@ function getReportFieldTitle(report: OnyxEntry, reportField: PolicyRepor const value = report?.reportFields?.[reportField.fieldID] ?? reportField.defaultValue; if (reportField.type !== 'formula') { - return value; + return value as string; } - return value.replaceAll(CONST.REGEX.REPORT_FIELD_TITLE, (match, property) => { + return value.replaceAll(CONST.REGEX.REPORT_FIELD_TITLE, (match: string, property: string) => { if (report && property in report) { return report[property as keyof Report]?.toString() ?? match; } return match; - }); + }) as string; } /** diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 55e91834a803..f041e4f50c39 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -31,7 +31,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; -import type {PersonalDetails, PersonalDetailsList, ReportActionReactions, ReportUserIsTyping} from '@src/types/onyx'; +import type {PersonalDetails, PersonalDetailsList, PolicyReportField, ReportActionReactions, ReportUserIsTyping} from '@src/types/onyx'; import type {Decision, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; import type {NotificationPreference, WriteCapability} from '@src/types/onyx/Report'; import type Report from '@src/types/onyx/Report'; @@ -1481,6 +1481,64 @@ function toggleSubscribeToChildReport(childReportID = '0', parentReportAction: P } } +function updatePolicyReportField(reportID: string, policyField: PolicyReportField, fieldValue: string) { + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + reportFields: { + [policyField.fieldID]: fieldValue, + }, + pendingFields: { + [policyField.fieldID]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + }, + }, + ]; + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + pendingFields: { + [policyField.fieldID]: null, + }, + errorFields: { + [policyField.fieldID]: ErrorUtils.getMicroSecondOnyxError('report.genericUpdateReportFieldFailureMessage'), + }, + }, + }, + ]; + + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + pendingFields: { + [policyField.fieldID]: null, + }, + errorFields: { + [policyField.fieldID]: null, + }, + }, + }, + ]; + + type UpdateReportFieldParameters = { + reportID: string; + reportFields: string; + }; + + const parameters: UpdateReportFieldParameters = { + reportID, + reportFields: JSON.stringify({[policyField.fieldID]: {fieldID: policyField.fieldID, value: fieldValue, type: policyField.type, name: policyField.name}}), + }; + + API.write('Report_SetFields', parameters, {optimisticData, failureData, successData}); +} + function updateWelcomeMessage(reportID: string, previousValue: string, newValue: string) { // No change needed, navigate back if (previousValue === newValue) { @@ -2649,4 +2707,5 @@ export { getDraftPrivateNote, updateLastVisitTime, clearNewRoomFormError, + updatePolicyReportField, }; diff --git a/src/pages/EditReportFieldDatePage.tsx b/src/pages/EditReportFieldDatePage.tsx index 5ee86b2bf8e6..8b3a8b74ba0d 100644 --- a/src/pages/EditReportFieldDatePage.tsx +++ b/src/pages/EditReportFieldDatePage.tsx @@ -21,7 +21,7 @@ type EditReportFieldDatePageProps = { fieldID: string; /** Callback to fire when the Save button is pressed */ - onSubmit: () => void; + onSubmit: (form: Record) => void; }; function EditReportFieldDatePage({fieldName, onSubmit, fieldValue, fieldID}: EditReportFieldDatePageProps) { diff --git a/src/pages/EditReportFieldDropdownPage.tsx b/src/pages/EditReportFieldDropdownPage.tsx index 7c16a3dad3f6..bae02482d964 100644 --- a/src/pages/EditReportFieldDropdownPage.tsx +++ b/src/pages/EditReportFieldDropdownPage.tsx @@ -13,14 +13,17 @@ type EditReportFieldDropdownPageProps = { /** Name of the policy report field */ fieldName: string; + /** ID of the policy report field */ + fieldID: string; + /** Options of the policy report field */ fieldOptions: string[]; /** Callback to fire when the Save button is pressed */ - onSubmit: () => void; + onSubmit: (form: Record) => void; }; -function EditReportFieldDropdownPage({fieldName, onSubmit, fieldValue, fieldOptions}: EditReportFieldDropdownPageProps) { +function EditReportFieldDropdownPage({fieldName, onSubmit, fieldID, fieldValue, fieldOptions}: EditReportFieldDropdownPageProps) { const [searchValue, setSearchValue] = useState(''); const styles = useThemeStyles(); const {getSafeAreaMargins} = useStyleUtils(); @@ -66,7 +69,7 @@ function EditReportFieldDropdownPage({fieldName, onSubmit, fieldValue, fieldOpti boldStyle sections={sections} value={searchValue} - onSelectRow={onSubmit} + onSelectRow={(option: Record) => onSubmit({[fieldID]: option.text})} onChangeText={setSearchValue} highlightSelectedOptions isRowMultilineSupported diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index d74582708995..6ed17636d043 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -3,6 +3,8 @@ import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import ScreenWrapper from '@components/ScreenWrapper'; +import Navigation from '@libs/Navigation/Navigation'; +import * as ReportActions from '@src/libs/actions/Report'; import ONYXKEYS from '@src/ONYXKEYS'; import type {PolicyReportFields, Report} from '@src/types/onyx'; import EditReportFieldDatePage from './EditReportFieldDatePage'; @@ -41,6 +43,14 @@ function EditReportFieldPage({route, report, policyReportFields}: EditReportFiel // Decides whether to allow or disallow editing a money request useEffect(() => {}, []); + const handleReportFieldChange = (form: Record) => { + if (report && policyReportField) { + const value = form[policyReportField.fieldID] || ''; + ReportActions.updatePolicyReportField(report.reportID, policyReportField, value); + } + Navigation.dismissModal(report?.reportID); + }; + if (policyReportField) { if (policyReportField.type === 'text' || policyReportField.type === 'formula') { return ( @@ -48,7 +58,7 @@ function EditReportFieldPage({route, report, policyReportFields}: EditReportFiel fieldName={policyReportField.name} fieldID={policyReportField.fieldID} fieldValue={reportFieldValue ?? policyReportField.defaultValue} - onSubmit={() => {}} + onSubmit={handleReportFieldChange} /> ); } @@ -59,7 +69,7 @@ function EditReportFieldPage({route, report, policyReportFields}: EditReportFiel fieldName={policyReportField.name} fieldID={policyReportField.fieldID} fieldValue={reportFieldValue ?? policyReportField.defaultValue} - onSubmit={() => {}} + onSubmit={handleReportFieldChange} /> ); } @@ -67,10 +77,11 @@ function EditReportFieldPage({route, report, policyReportFields}: EditReportFiel if (policyReportField.type === 'dropdown') { return ( {}} + onSubmit={handleReportFieldChange} /> ); } diff --git a/src/pages/EditReportFieldTextPage.tsx b/src/pages/EditReportFieldTextPage.tsx index b468861e9a27..eac85053448f 100644 --- a/src/pages/EditReportFieldTextPage.tsx +++ b/src/pages/EditReportFieldTextPage.tsx @@ -21,7 +21,7 @@ type EditReportFieldTextPageProps = { fieldID: string; /** Callback to fire when the Save button is pressed */ - onSubmit: () => void; + onSubmit: (form: Record) => void; }; function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, fieldID}: EditReportFieldTextPageProps) { From e08945548b9a0fa77620fa96a78e75d629a12db2 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Sun, 14 Jan 2024 22:42:45 +0500 Subject: [PATCH 02/13] fix: revert canUseReportField beta --- src/libs/Permissions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index 47c6ae0f9a2d..ce5e0e674c59 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -19,7 +19,7 @@ function canUseCommentLinking(betas: OnyxEntry): boolean { } function canUseReportFields(betas: OnyxEntry): boolean { - return true; // !!betas?.includes(CONST.BETAS.REPORT_FIELDS) || canUseAllBetas(betas); + return !!betas?.includes(CONST.BETAS.REPORT_FIELDS) || canUseAllBetas(betas); } function canUseViolations(betas: OnyxEntry): boolean { From 7532fffd317f0e57b47606c568861dc31ded8903 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Mon, 15 Jan 2024 00:02:27 +0500 Subject: [PATCH 03/13] fix: lint errors --- src/libs/ReportUtils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6892f05b39ab..ca3357c29dd6 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4333,15 +4333,15 @@ function getReportFieldTitle(report: OnyxEntry, reportField: PolicyRepor const value = report?.reportFields?.[reportField.fieldID] ?? reportField.defaultValue; if (reportField.type !== 'formula') { - return value as string; + return value; } - return value.replaceAll(CONST.REGEX.REPORT_FIELD_TITLE, (match: string, property: string) => { + return value.replaceAll(CONST.REGEX.REPORT_FIELD_TITLE, (match, property) => { if (report && property in report) { return report[property as keyof Report]?.toString() ?? match; } return match; - }) as string; + }); } /** From b0f6f9bb0965ec37a482e9ca51f185efcf6aba3a Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Mon, 29 Jan 2024 04:28:17 +0500 Subject: [PATCH 04/13] include the whole reportfield object in the report --- .../ReportActionItem/MoneyReportView.tsx | 29 +++-- src/languages/en.ts | 1 + src/languages/es.ts | 1 + src/libs/Permissions.ts | 2 +- src/libs/ReportUtils.ts | 88 +++++++++---- src/libs/actions/Report.ts | 105 +++++++++++++-- src/pages/EditReportFieldDatePage.tsx | 9 +- src/pages/EditReportFieldDropdownPage.tsx | 40 +++++- src/pages/EditReportFieldPage.tsx | 122 ++++++++++-------- src/pages/EditReportFieldTextPage.tsx | 9 +- src/pages/home/report/ReportActionItem.js | 9 +- src/types/onyx/PolicyReportField.ts | 3 + src/types/onyx/Report.ts | 3 +- 13 files changed, 303 insertions(+), 118 deletions(-) diff --git a/src/components/ReportActionItem/MoneyReportView.tsx b/src/components/ReportActionItem/MoneyReportView.tsx index d81072d67b90..5651d0b943ab 100644 --- a/src/components/ReportActionItem/MoneyReportView.tsx +++ b/src/components/ReportActionItem/MoneyReportView.tsx @@ -19,12 +19,15 @@ import * as ReportUtils from '@libs/ReportUtils'; import AnimatedEmptyStateBackground from '@pages/home/report/AnimatedEmptyStateBackground'; import variables from '@styles/variables'; import ROUTES from '@src/ROUTES'; -import type {PolicyReportField, Report} from '@src/types/onyx'; +import type {Policy, PolicyReportField, Report} from '@src/types/onyx'; type MoneyReportViewProps = { /** The report currently being looked at */ report: Report; + /** Policy that the report belongs to */ + policy: Policy; + /** Policy report fields */ policyReportFields: PolicyReportField[]; @@ -32,7 +35,7 @@ type MoneyReportViewProps = { shouldShowHorizontalRule: boolean; }; -function MoneyReportView({report, policyReportFields, shouldShowHorizontalRule}: MoneyReportViewProps) { +function MoneyReportView({report, policy, policyReportFields, shouldShowHorizontalRule}: MoneyReportViewProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -55,10 +58,13 @@ function MoneyReportView({report, policyReportFields, shouldShowHorizontalRule}: StyleUtils.getColorStyle(theme.textSupporting), ]; - const sortedPolicyReportFields = useMemo( - (): PolicyReportField[] => policyReportFields.sort(({orderWeight: firstOrderWeight}, {orderWeight: secondOrderWeight}) => firstOrderWeight - secondOrderWeight), - [policyReportFields], - ); + const sortedPolicyReportFields = useMemo((): PolicyReportField[] => { + const reportFields = Object.values(report.reportFields ?? {}); + const mergedFieldIds = Array.from(new Set([...policyReportFields.map(({fieldID}) => fieldID), ...reportFields.map(({fieldID}) => fieldID)])); + const mergedFields = mergedFieldIds.map((id) => report?.reportFields?.[id] ?? policyReportFields.find(({fieldID}) => fieldID === id)) as PolicyReportField[]; + const allReportFields = isSettled ? reportFields : mergedFields; + return allReportFields.sort(({orderWeight: firstOrderWeight}, {orderWeight: secondOrderWeight}) => firstOrderWeight - secondOrderWeight); + }, [policyReportFields, report.reportFields, isSettled]); return ( @@ -66,7 +72,10 @@ function MoneyReportView({report, policyReportFields, shouldShowHorizontalRule}: {canUseReportFields && sortedPolicyReportFields.map((reportField) => { - const title = ReportUtils.getReportFieldTitle(report, reportField); + const isTitleField = ReportUtils.isReportFieldOfTypeTitle(reportField); + const fieldValue = isTitleField ? report.reportName : reportField.value ?? reportField.defaultValue; + const isFieldDisabled = ReportUtils.isReportFieldDisabled(report, reportField, policy); + return ( Navigation.navigate(ROUTES.EDIT_REPORT_FIELD_REQUEST.getRoute(report.reportID, report.policyID ?? '', reportField.fieldID))} shouldShowRightIcon - disabled={ReportUtils.isReportFieldOfTypeTitle(reportField)} + disabled={isFieldDisabled} wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]} shouldGreyOutWhenDisabled={false} numberOfLinesTitle={0} diff --git a/src/languages/en.ts b/src/languages/en.ts index c1ccacaadf53..f4fc98a88a02 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1882,6 +1882,7 @@ export default { genericCreateReportFailureMessage: 'Unexpected error creating this chat, please try again later', genericAddCommentFailureMessage: 'Unexpected error while posting the comment, please try again later', genericUpdateReportFieldFailureMessage: 'Unexpected error while updating the field, please try again later', + genericUpdateReporNameEditFailureMessage: 'Unexpected error while renaming the report, please try again later', noActivityYet: 'No activity yet', }, chronos: { diff --git a/src/languages/es.ts b/src/languages/es.ts index f5278d093319..31389ba9c17a 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1908,6 +1908,7 @@ export default { genericCreateReportFailureMessage: 'Error inesperado al crear el chat. Por favor, inténtalo más tarde', genericAddCommentFailureMessage: 'Error inesperado al añadir el comentario. Por favor, inténtalo más tarde', genericUpdateReportFieldFailureMessage: 'Error inesperado al actualizar el campo. Por favor, inténtalo más tarde', + genericUpdateReporNameEditFailureMessage: 'Error inesperado al cambiar el nombre del informe. Vuelva a intentarlo más tarde.', noActivityYet: 'Sin actividad todavía', }, chronos: { diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index ce5e0e674c59..af85ce5c7576 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -3,7 +3,7 @@ import CONST from '@src/CONST'; import type Beta from '@src/types/onyx/Beta'; function canUseAllBetas(betas: OnyxEntry): boolean { - return !!betas?.includes(CONST.BETAS.ALL); + return true; // !!betas?.includes(CONST.BETAS.ALL); } function canUseChronos(betas: OnyxEntry): boolean { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 86f939edc1b5..ef744dde5488 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -21,6 +21,7 @@ import type { PersonalDetailsList, Policy, PolicyReportField, + PolicyReportFields, Report, ReportAction, ReportMetadata, @@ -465,8 +466,21 @@ Onyx.connect({ callback: (value) => (loginList = value), }); -let allTransactions: OnyxCollection = {}; +let allPolicyReportFields: OnyxCollection; + +Onyx.connect({ + key: ONYXKEYS.COLLECTION.POLICY_REPORT_FIELDS, + waitForCollectionCallback: true, + callback: (value) => (allPolicyReportFields = value), +}); +let allBetas: OnyxEntry; +Onyx.connect({ + key: ONYXKEYS.BETAS, + callback: (value) => (allBetas = value), +}); + +let allTransactions: OnyxCollection = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.TRANSACTION, waitForCollectionCallback: true, @@ -1898,10 +1912,54 @@ function getPolicyExpenseChatName(report: OnyxEntry, policy: OnyxEntry

): boolean { + return reportField?.type === 'formula' && reportField?.fieldID === CONST.REPORT_FIELD_TITLE_FIELD_ID; +} + +/** + * Given a report field, check if the field can be edited or not. + * For title fields, its considered disabled if `deletable` prop is `true` (https://github.com/Expensify/App/issues/35043#issuecomment-1911275433) + * For non title fields, its considered disabled if: + * 1. The user is not admin of the report + * 2. Report is settled or it is closed + */ +function isReportFieldDisabled(report: OnyxEntry, reportField: OnyxEntry, policy: OnyxEntry): boolean { + const isReportSettled = isSettled(report?.reportID); + const isReportClosed = report?.statusNum === CONST.REPORT.STATUS_NUM.CLOSED; + const isTitleField = isReportFieldOfTypeTitle(reportField); + const isAdmin = isPolicyAdmin(report?.policyID ?? '', {[`${ONYXKEYS.COLLECTION.POLICY}${policy?.id ?? ''}`]: policy}); + return isTitleField ? !reportField?.deletable : !isAdmin && (isReportSettled || isReportClosed); +} + +/** + * Given a set of report fields, return the field of type formula + */ +function getFormulaTypeReportField(reportFields: PolicyReportFields) { + return Object.values(reportFields).find((field) => field.type === 'formula'); +} + +/** + * Get the report fields attached to the policy given policyID + */ +function getReportFieldsByPolicyID(policyID: string) { + return Object.entries(allPolicyReportFields ?? {}).find(([key]) => key.replace(ONYXKEYS.COLLECTION.POLICY_REPORT_FIELDS, '') === policyID)?.[1]; +} + /** * Get the title for an IOU or expense chat which will be showing the payer and the amount */ function getMoneyRequestReportName(report: OnyxEntry, policy: OnyxEntry | undefined = undefined): string { + const isReportSettled = isSettled(report?.reportID ?? ''); + const reportFields = isReportSettled ? report?.reportFields : getReportFieldsByPolicyID(report?.policyID ?? ''); + const titleReportField = getFormulaTypeReportField(reportFields ?? {}); + + if (titleReportField && report?.reportName && Permissions.canUseReportFields(allBetas ?? [])) { + return report.reportName; + } + const moneyRequestTotal = getMoneyRequestReimbursableTotal(report); const formattedAmount = CurrencyUtils.convertToDisplayString(moneyRequestTotal, report?.currency, hasOnlyDistanceRequestTransactions(report?.reportID)); const payerOrApproverName = isExpenseReport(report) ? getPolicyName(report, false, policy) : getDisplayNameForParticipant(report?.managerID) ?? ''; @@ -4551,32 +4609,6 @@ function navigateToPrivateNotes(report: Report, session: Session) { Navigation.navigate(ROUTES.PRIVATE_NOTES_LIST.getRoute(report.reportID)); } -/** - * Given a report field and a report, get the title of the field. - * This is specially useful when we have a report field of type formula. - */ -function getReportFieldTitle(report: OnyxEntry, reportField: PolicyReportField): string { - const value = report?.reportFields?.[reportField.fieldID] ?? reportField.defaultValue; - - if (reportField.type !== 'formula') { - return value; - } - - return value.replaceAll(CONST.REGEX.REPORT_FIELD_TITLE, (match, property) => { - if (report && property in report) { - return report[property as keyof Report]?.toString() ?? match; - } - return match; - }); -} - -/** - * Given a report field, check if the field is for the report title. - */ -function isReportFieldOfTypeTitle(reportField: PolicyReportField): boolean { - return reportField.type === 'formula' && reportField.fieldID === CONST.REPORT_FIELD_TITLE_FIELD_ID; -} - /** * Checks if thread replies should be displayed */ @@ -4787,12 +4819,12 @@ export { canEditWriteCapability, hasSmartscanError, shouldAutoFocusOnKeyPress, - getReportFieldTitle, shouldDisplayThreadReplies, shouldDisableThread, doesReportBelongToWorkspace, getChildReportNotificationPreference, isReportFieldOfTypeTitle, + isReportFieldDisabled, }; export type { diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 3030a160ddb3..d466c0a9b1a9 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -32,7 +32,7 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; -import type {PersonalDetails, PersonalDetailsList, PolicyReportField, ReportActionReactions, ReportUserIsTyping} from '@src/types/onyx'; +import type {PersonalDetails, PersonalDetailsList, PolicyReportField, RecentlyUsedReportFields, ReportActionReactions, ReportUserIsTyping} from '@src/types/onyx'; import type {Decision, OriginalMessageIOU} from '@src/types/onyx/OriginalMessage'; import type {NotificationPreference, WriteCapability} from '@src/types/onyx/Report'; import type Report from '@src/types/onyx/Report'; @@ -137,6 +137,13 @@ Linking.getInitialURL().then((url) => { reportIDDeeplinkedFromOldDot = reportID; }); +let allRecentlyUsedReportFields: OnyxCollection = {}; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_REPORT_FIELDS, + waitForCollectionCallback: true, + callback: (val) => (allRecentlyUsedReportFields = val), +}); + /** Get the private pusher channel name for a Report. */ function getReportChannelName(reportID: string): string { return `${CONST.PUSHER.PRIVATE_REPORT_CHANNEL_PREFIX}${reportID}${CONFIG.PUSHER.SUFFIX}`; @@ -1499,46 +1506,125 @@ function toggleSubscribeToChildReport(childReportID = '0', parentReportAction: P } } -function updatePolicyReportField(reportID: string, policyField: PolicyReportField, fieldValue: string) { +function updatePolicyReportName(reportID: string, value: string) { + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + reportName: value, + pendingFields: { + reportName: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + }, + }, + }, + ]; + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + pendingFields: { + reportName: null, + }, + errorFields: { + reportName: ErrorUtils.getMicroSecondOnyxError('report.genericUpdateReporNameEditFailureMessage'), + }, + }, + }, + ]; + + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, + value: { + pendingFields: { + reportName: null, + }, + errorFields: { + reportName: null, + }, + }, + }, + ]; + + type UpdateReportNameParameters = { + reportID: string; + reportName: string; + }; + + const parameters: UpdateReportNameParameters = { + reportID, + reportName: value, + }; + + API.write('RenameReport', parameters, {optimisticData, failureData, successData}); +} + +function updatePolicyReportField(policyID: string, reportID: string, reportField: PolicyReportField) { + const recentlyUsedValues = allRecentlyUsedReportFields?.[policyID]?.[reportField.fieldID] ?? []; + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { reportFields: { - [policyField.fieldID]: fieldValue, + [reportField.fieldID]: reportField, }, pendingFields: { - [policyField.fieldID]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + [reportField.fieldID]: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, }, ]; + + if (reportField.type === 'dropdown') { + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_REPORT_FIELDS}${policyID}`, + value: { + [reportField.fieldID]: [...new Set([...recentlyUsedValues, reportField.value])], + }, + }); + } + const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { pendingFields: { - [policyField.fieldID]: null, + [reportField.fieldID]: null, }, errorFields: { - [policyField.fieldID]: ErrorUtils.getMicroSecondOnyxError('report.genericUpdateReportFieldFailureMessage'), + [reportField.fieldID]: ErrorUtils.getMicroSecondOnyxError('report.genericUpdateReportFieldFailureMessage'), }, }, }, ]; + if (reportField.type === 'dropdown') { + failureData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_REPORT_FIELDS}${policyID}`, + value: { + [reportField.fieldID]: recentlyUsedValues, + }, + }); + } + const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { pendingFields: { - [policyField.fieldID]: null, + [reportField.fieldID]: null, }, errorFields: { - [policyField.fieldID]: null, + [reportField.fieldID]: null, }, }, }, @@ -1551,7 +1637,7 @@ function updatePolicyReportField(reportID: string, policyField: PolicyReportFiel const parameters: UpdateReportFieldParameters = { reportID, - reportFields: JSON.stringify({[policyField.fieldID]: {fieldID: policyField.fieldID, value: fieldValue, type: policyField.type, name: policyField.name}}), + reportFields: JSON.stringify({[reportField.fieldID]: {fieldID: reportField.fieldID, value: reportField.value, type: reportField.type, name: reportField.name}}), }; API.write('Report_SetFields', parameters, {optimisticData, failureData, successData}); @@ -2885,5 +2971,6 @@ export { updateLastVisitTime, clearNewRoomFormError, updatePolicyReportField, + updatePolicyReportName, resolveActionableMentionWhisper, }; diff --git a/src/pages/EditReportFieldDatePage.tsx b/src/pages/EditReportFieldDatePage.tsx index 8b3a8b74ba0d..8740d1ddecf6 100644 --- a/src/pages/EditReportFieldDatePage.tsx +++ b/src/pages/EditReportFieldDatePage.tsx @@ -20,11 +20,14 @@ type EditReportFieldDatePageProps = { /** ID of the policy report field */ fieldID: string; + /** Flag to indicate if the field can be left blank */ + isRequired: boolean; + /** Callback to fire when the Save button is pressed */ onSubmit: (form: Record) => void; }; -function EditReportFieldDatePage({fieldName, onSubmit, fieldValue, fieldID}: EditReportFieldDatePageProps) { +function EditReportFieldDatePage({fieldName, isRequired, onSubmit, fieldValue, fieldID}: EditReportFieldDatePageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const inputRef = useRef(null); @@ -32,12 +35,12 @@ function EditReportFieldDatePage({fieldName, onSubmit, fieldValue, fieldID}: Edi const validate = useCallback( (value: Record) => { const errors: Record = {}; - if (value[fieldID].trim() === '') { + if (isRequired && value[fieldID].trim() === '') { errors[fieldID] = 'common.error.fieldRequired'; } return errors; }, - [fieldID], + [fieldID, isRequired], ); return ( diff --git a/src/pages/EditReportFieldDropdownPage.tsx b/src/pages/EditReportFieldDropdownPage.tsx index ccecc9a5f289..448ec5d68773 100644 --- a/src/pages/EditReportFieldDropdownPage.tsx +++ b/src/pages/EditReportFieldDropdownPage.tsx @@ -1,12 +1,16 @@ import React, {useMemo, useState} from 'react'; +import {withOnyx} from 'react-native-onyx'; +import type {OnyxEntry} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import OptionsSelector from '@components/OptionsSelector'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {RecentlyUsedReportFields} from '@src/types/onyx'; -type EditReportFieldDropdownPageProps = { +type EditReportFieldDropdownPageComponentProps = { /** Value of the policy report field */ fieldValue: string; @@ -16,6 +20,10 @@ type EditReportFieldDropdownPageProps = { /** ID of the policy report field */ fieldID: string; + /** ID of the policy this report field belongs to */ + // eslint-disable-next-line react/no-unused-prop-types + policyID: string; + /** Options of the policy report field */ fieldOptions: string[]; @@ -23,24 +31,38 @@ type EditReportFieldDropdownPageProps = { onSubmit: (form: Record) => void; }; -function EditReportFieldDropdownPage({fieldName, onSubmit, fieldID, fieldValue, fieldOptions}: EditReportFieldDropdownPageProps) { +type EditReportFieldDropdownPageOnyxProps = { + policyRecentlyUsedReportFields: OnyxEntry; +}; + +type EditReportFieldDropdownPageProps = EditReportFieldDropdownPageComponentProps & EditReportFieldDropdownPageOnyxProps; + +function EditReportFieldDropdownPage({fieldName, onSubmit, fieldID, fieldValue, fieldOptions, policyRecentlyUsedReportFields}: EditReportFieldDropdownPageProps) { const [searchValue, setSearchValue] = useState(''); const styles = useThemeStyles(); const {getSafeAreaMargins} = useStyleUtils(); const {translate} = useLocalize(); + const recentlyUsedOptions = useMemo(() => policyRecentlyUsedReportFields?.[fieldID] ?? [], [policyRecentlyUsedReportFields, fieldID]); const sections = useMemo(() => { - const filteredOptions = fieldOptions.filter((option) => option.toLowerCase().includes(searchValue.toLowerCase())); + const filteredRecentOptions = recentlyUsedOptions.filter((option) => option.toLowerCase().includes(searchValue.toLowerCase())); + const filteredRestOfOptions = fieldOptions.filter((option) => !filteredRecentOptions.includes(option) && option.toLowerCase().includes(searchValue.toLowerCase())); + return [ { title: translate('common.recents'), shouldShow: true, - data: [], + data: filteredRecentOptions.map((option) => ({ + text: option, + keyForList: option, + searchText: option, + tooltipText: option, + })), }, { title: translate('common.all'), shouldShow: true, - data: filteredOptions.map((option) => ({ + data: filteredRestOfOptions.map((option) => ({ text: option, keyForList: option, searchText: option, @@ -48,7 +70,7 @@ function EditReportFieldDropdownPage({fieldName, onSubmit, fieldID, fieldValue, })), }, ]; - }, [fieldOptions, searchValue, translate]); + }, [fieldOptions, recentlyUsedOptions, searchValue, translate]); return ( ({ + policyRecentlyUsedReportFields: { + key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_REPORT_FIELDS}${policyID}`, + }, +})(EditReportFieldDropdownPage); diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index 6ed17636d043..f411583fc681 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -1,12 +1,13 @@ -import React, {useEffect} from 'react'; +import React from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import ScreenWrapper from '@components/ScreenWrapper'; import Navigation from '@libs/Navigation/Navigation'; +import * as ReportUtils from '@libs/ReportUtils'; import * as ReportActions from '@src/libs/actions/Report'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {PolicyReportFields, Report} from '@src/types/onyx'; +import type {Policy, PolicyReportFields, Report} from '@src/types/onyx'; import EditReportFieldDatePage from './EditReportFieldDatePage'; import EditReportFieldDropdownPage from './EditReportFieldDropdownPage'; import EditReportFieldTextPage from './EditReportFieldTextPage'; @@ -17,6 +18,9 @@ type EditReportFieldPageOnyxProps = { /** Policy report fields */ policyReportFields: OnyxEntry; + + /** Policy to which the report belongs to */ + policy: OnyxEntry; }; type EditReportFieldPageProps = EditReportFieldPageOnyxProps & { @@ -36,70 +40,77 @@ type EditReportFieldPageProps = EditReportFieldPageOnyxProps & { }; }; -function EditReportFieldPage({route, report, policyReportFields}: EditReportFieldPageProps) { - const policyReportField = policyReportFields?.[route.params.fieldID]; - const reportFieldValue = report?.reportFields?.[policyReportField?.fieldID ?? '']; +function EditReportFieldPage({route, policy, report, policyReportFields}: EditReportFieldPageProps) { + const reportField = report?.reportFields?.[route.params.fieldID] ?? policyReportFields?.[route.params.fieldID]; + const isDisabled = ReportUtils.isReportFieldDisabled(report, reportField ?? null, policy); + + if (!reportField || !report || isDisabled) { + return ( + + {}} + onLinkPress={() => {}} + /> + + ); + } - // Decides whether to allow or disallow editing a money request - useEffect(() => {}, []); + const isReportFieldTitle = ReportUtils.isReportFieldOfTypeTitle(reportField); const handleReportFieldChange = (form: Record) => { - if (report && policyReportField) { - const value = form[policyReportField.fieldID] || ''; - ReportActions.updatePolicyReportField(report.reportID, policyReportField, value); + const value = form[reportField.fieldID] || ''; + if (isReportFieldTitle) { + ReportActions.updatePolicyReportName(report.reportID, value); + } else { + ReportActions.updatePolicyReportField(report.policyID ?? '', report.reportID, {...reportField, value}); } + Navigation.dismissModal(report?.reportID); }; - if (policyReportField) { - if (policyReportField.type === 'text' || policyReportField.type === 'formula') { - return ( - - ); - } + const fieldValue = isReportFieldTitle ? report.reportName ?? '' : reportField.value ?? reportField.defaultValue; - if (policyReportField.type === 'date') { - return ( - - ); - } + if (reportField.type === 'text' || isReportFieldTitle) { + return ( + + ); + } - if (policyReportField.type === 'dropdown') { - return ( - - ); - } + if (reportField.type === 'date') { + return ( + + ); } - return ( - - {}} - onLinkPress={() => {}} + if (reportField.type === 'dropdown') { + return ( + - - ); + ); + } } EditReportFieldPage.displayName = 'EditReportFieldPage'; @@ -111,4 +122,7 @@ export default withOnyx( policyReportFields: { key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY_REPORT_FIELDS}${route.params.policyID}`, }, + policy: { + key: ({route}) => `${ONYXKEYS.COLLECTION.POLICY}${route.params.policyID}`, + }, })(EditReportFieldPage); diff --git a/src/pages/EditReportFieldTextPage.tsx b/src/pages/EditReportFieldTextPage.tsx index eac85053448f..b2e76a9596bc 100644 --- a/src/pages/EditReportFieldTextPage.tsx +++ b/src/pages/EditReportFieldTextPage.tsx @@ -20,11 +20,14 @@ type EditReportFieldTextPageProps = { /** ID of the policy report field */ fieldID: string; + /** Flag to indicate if the field can be left blank */ + isRequired: boolean; + /** Callback to fire when the Save button is pressed */ onSubmit: (form: Record) => void; }; -function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, fieldID}: EditReportFieldTextPageProps) { +function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, isRequired, fieldID}: EditReportFieldTextPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const inputRef = useRef(null); @@ -32,12 +35,12 @@ function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, fieldID}: Edi const validate = useCallback( (value: Record) => { const errors: Record = {}; - if (value[fieldID].trim() === '') { + if (isRequired && value[fieldID].trim() === '') { errors[fieldID] = 'common.error.fieldRequired'; } return errors; }, - [fieldID], + [fieldID, isRequired], ); return ( diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 00ce20c19a85..a550397d0fc5 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -107,7 +107,6 @@ const propTypes = { /** Stores user's preferred skin tone */ preferredSkinTone: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), - ...windowDimensionsPropTypes, emojiReactions: EmojiReactionsPropTypes, /** IOU report for this action, if any */ @@ -650,6 +649,7 @@ function ReportActionItem(props) { @@ -805,6 +805,10 @@ export default compose( key: ({report}) => (report && 'policyID' in report ? `${ONYXKEYS.COLLECTION.POLICY_REPORT_FIELDS}${report.policyID}` : undefined), initialValue: [], }, + policy: { + key: ({report}) => (report && 'policyID' in report ? `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}` : undefined), + initialValue: {}, + }, emojiReactions: { key: ({action}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS}${action.reportActionID}`, initialValue: {}, @@ -848,6 +852,7 @@ export default compose( lodashGet(prevProps.report, 'nonReimbursableTotal', 0) === lodashGet(nextProps.report, 'nonReimbursableTotal', 0) && prevProps.linkedReportActionID === nextProps.linkedReportActionID && _.isEqual(prevProps.policyReportFields, nextProps.policyReportFields) && - _.isEqual(prevProps.report.reportFields, nextProps.report.reportFields), + _.isEqual(prevProps.report.reportFields, nextProps.report.reportFields) && + _.isEqual(prevProps.policy, nextProps.policy), ), ); diff --git a/src/types/onyx/PolicyReportField.ts b/src/types/onyx/PolicyReportField.ts index a1724a9ff52f..de385070aa25 100644 --- a/src/types/onyx/PolicyReportField.ts +++ b/src/types/onyx/PolicyReportField.ts @@ -19,6 +19,9 @@ type PolicyReportField = { /** Tells if the field is required or not */ deletable: boolean; + /** Value of the field */ + value: string; + /** Options to select from if field is of type dropdown */ values: string[]; }; diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index b1571e7514e4..95ea6152a725 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -2,6 +2,7 @@ import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type * as OnyxCommon from './OnyxCommon'; import type PersonalDetails from './PersonalDetails'; +import type {PolicyReportField} from './PolicyReportField'; type NotificationPreference = ValueOf; @@ -160,7 +161,7 @@ type Report = { isLoadingPrivateNotes?: boolean; /** If the report contains reportFields, save the field id and its value */ - reportFields?: Record; + reportFields?: Record; }; export default Report; From 06b2b16747f87c88d5e72897ed6384182a744ae5 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Mon, 29 Jan 2024 05:06:56 +0500 Subject: [PATCH 05/13] create new types for the write commands --- src/libs/API/parameters/SetPolicyReportFieldParams.ts | 6 ++++++ src/libs/API/parameters/SetPolicyReportNameParams.ts | 6 ++++++ src/libs/API/parameters/index.ts | 2 ++ src/libs/API/types.ts | 4 ++++ 4 files changed, 18 insertions(+) create mode 100644 src/libs/API/parameters/SetPolicyReportFieldParams.ts create mode 100644 src/libs/API/parameters/SetPolicyReportNameParams.ts diff --git a/src/libs/API/parameters/SetPolicyReportFieldParams.ts b/src/libs/API/parameters/SetPolicyReportFieldParams.ts new file mode 100644 index 000000000000..94f059057b58 --- /dev/null +++ b/src/libs/API/parameters/SetPolicyReportFieldParams.ts @@ -0,0 +1,6 @@ +type SetPolicyReportFieldParams = { + reportID: string; + reportFields: string; +}; + +export default SetPolicyReportFieldParams; diff --git a/src/libs/API/parameters/SetPolicyReportNameParams.ts b/src/libs/API/parameters/SetPolicyReportNameParams.ts new file mode 100644 index 000000000000..d6310ee18115 --- /dev/null +++ b/src/libs/API/parameters/SetPolicyReportNameParams.ts @@ -0,0 +1,6 @@ +type SetPolicyReportNameParams = { + reportID: string; + reportName: string; +}; + +export default SetPolicyReportNameParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 039398c0fbf6..635887b33e4b 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -122,3 +122,5 @@ export type {default as ReopenTaskParams} from './ReopenTaskParams'; export type {default as CompleteTaskParams} from './CompleteTaskParams'; export type {default as CompleteEngagementModalParams} from './CompleteEngagementModalParams'; export type {default as SetNameValuePairParams} from './SetNameValuePairParams'; +export type {default as SetPolicyReportFieldParams} from './SetPolicyReportFieldParams'; +export type {default as SetPolicyReportNameParams} from './SetPolicyReportNameParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index f58ebc30b4a2..ca13e828f1bd 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -113,6 +113,8 @@ const WRITE_COMMANDS = { COMPLETE_TASK: 'CompleteTask', COMPLETE_ENGAGEMENT_MODAL: 'CompleteEngagementModal', SET_NAME_VALUE_PAIR: 'SetNameValuePair', + SET_POLICY_REPORT_FIELD: 'Report_SetFields', + SET_POLICY_REPORT_NAME: 'RenameReport', } as const; type WriteCommand = ValueOf; @@ -223,6 +225,8 @@ type WriteCommandParameters = { [WRITE_COMMANDS.COMPLETE_TASK]: Parameters.CompleteTaskParams; [WRITE_COMMANDS.COMPLETE_ENGAGEMENT_MODAL]: Parameters.CompleteEngagementModalParams; [WRITE_COMMANDS.SET_NAME_VALUE_PAIR]: Parameters.SetNameValuePairParams; + [WRITE_COMMANDS.SET_POLICY_REPORT_FIELD]: Parameters.SetPolicyReportFieldParams; + [WRITE_COMMANDS.SET_POLICY_REPORT_NAME]: Parameters.SetPolicyReportNameParams; }; const READ_COMMANDS = { From b58d85b873517ab82a701ad54ffb60c952c02640 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Mon, 29 Jan 2024 05:09:19 +0500 Subject: [PATCH 06/13] fix lint issues --- src/pages/EditReportFieldDatePage.tsx | 7 +++++-- src/pages/EditReportFieldTextPage.tsx | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/pages/EditReportFieldDatePage.tsx b/src/pages/EditReportFieldDatePage.tsx index 473317663998..2496e5b23bf2 100644 --- a/src/pages/EditReportFieldDatePage.tsx +++ b/src/pages/EditReportFieldDatePage.tsx @@ -11,6 +11,7 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; type EditReportFieldDatePageProps = { /** Value of the policy report field */ @@ -36,7 +37,7 @@ function EditReportFieldDatePage({fieldName, isRequired, onSubmit, fieldValue, f const validate = useCallback( (value: OnyxFormValuesFields) => { - const errors: Record = {}; + const errors: Errors = {}; if (isRequired && value[fieldID].toString().trim() === '') { errors[fieldID] = 'common.error.fieldRequired'; } @@ -49,7 +50,9 @@ function EditReportFieldDatePage({fieldName, isRequired, onSubmit, fieldValue, f {inputRef.current?.focus()}} + onEntryTransitionEnd={() => { + inputRef.current?.focus(); + }} testID={EditReportFieldDatePage.displayName} > diff --git a/src/pages/EditReportFieldTextPage.tsx b/src/pages/EditReportFieldTextPage.tsx index 18cf84fcfbf3..096967cf4003 100644 --- a/src/pages/EditReportFieldTextPage.tsx +++ b/src/pages/EditReportFieldTextPage.tsx @@ -37,7 +37,7 @@ function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, isRequired, f const validate = useCallback( (values: OnyxFormValuesFields) => { - const errors: Errors = {}; + const errors: Errors = {}; if (isRequired && values[fieldID].toString().trim() === '') { errors[fieldID] = 'common.error.fieldRequired'; } @@ -50,7 +50,9 @@ function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, isRequired, f {inputRef.current?.focus()}} + onEntryTransitionEnd={() => { + inputRef.current?.focus(); + }} testID={EditReportFieldTextPage.displayName} > From 19cafde76db980e66fd977952d241d9aaa44aa6f Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Mon, 29 Jan 2024 05:21:45 +0500 Subject: [PATCH 07/13] fix: typechecks --- src/pages/EditReportFieldPage.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index f411583fc681..2cb47918ce34 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -2,6 +2,7 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import type {OnyxFormValuesFields} from '@components/Form/types'; import ScreenWrapper from '@components/ScreenWrapper'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; @@ -62,8 +63,8 @@ function EditReportFieldPage({route, policy, report, policyReportFields}: EditRe const isReportFieldTitle = ReportUtils.isReportFieldOfTypeTitle(reportField); - const handleReportFieldChange = (form: Record) => { - const value = form[reportField.fieldID] || ''; + const handleReportFieldChange = (form: OnyxFormValuesFields) => { + const value = form[reportField.fieldID].toString() || ''; if (isReportFieldTitle) { ReportActions.updatePolicyReportName(report.reportID, value); } else { From 72b68c91a687fd588454de0e34d3298b4eda7844 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Mon, 29 Jan 2024 05:25:40 +0500 Subject: [PATCH 08/13] fix: remove leftover code --- src/libs/Permissions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts index af85ce5c7576..ce5e0e674c59 100644 --- a/src/libs/Permissions.ts +++ b/src/libs/Permissions.ts @@ -3,7 +3,7 @@ import CONST from '@src/CONST'; import type Beta from '@src/types/onyx/Beta'; function canUseAllBetas(betas: OnyxEntry): boolean { - return true; // !!betas?.includes(CONST.BETAS.ALL); + return !!betas?.includes(CONST.BETAS.ALL); } function canUseChronos(betas: OnyxEntry): boolean { From cd576d8291384e4f05ed435c7836f20dca3adb71 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Tue, 30 Jan 2024 02:34:59 +0500 Subject: [PATCH 09/13] fix: update recently used field implementation --- src/ONYXKEYS.ts | 6 ++++-- src/libs/actions/Report.ts | 13 ++++++------- src/pages/EditReportFieldDropdownPage.tsx | 10 +++++----- src/pages/EditReportFieldPage.tsx | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 7abf6db1769d..cfcae988d6b5 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -243,6 +243,9 @@ const ONYXKEYS = { // Max width supported for HTML element MAX_CANVAS_WIDTH: 'maxCanvasWidth', + // Stores the recently used report fields + RECENTLY_USED_REPORT_FIELDS: 'recentlyUsedReportFields', + /** Collection Keys */ COLLECTION: { DOWNLOAD: 'download_', @@ -256,7 +259,6 @@ const ONYXKEYS = { POLICY_TAX_RATE: 'policyTaxRates_', POLICY_RECENTLY_USED_TAGS: 'policyRecentlyUsedTags_', POLICY_REPORT_FIELDS: 'policyReportFields_', - POLICY_RECENTLY_USED_REPORT_FIELDS: 'policyRecentlyUsedReportFields_', WORKSPACE_INVITE_MEMBERS_DRAFT: 'workspaceInviteMembersDraft_', WORKSPACE_INVITE_MESSAGE_DRAFT: 'workspaceInviteMessageDraft_', REPORT: 'report_', @@ -440,6 +442,7 @@ type OnyxValues = { [ONYXKEYS.MAX_CANVAS_AREA]: number; [ONYXKEYS.MAX_CANVAS_HEIGHT]: number; [ONYXKEYS.MAX_CANVAS_WIDTH]: number; + [ONYXKEYS.RECENTLY_USED_REPORT_FIELDS]: OnyxTypes.RecentlyUsedReportFields; // Collections [ONYXKEYS.COLLECTION.DOWNLOAD]: OnyxTypes.Download; @@ -451,7 +454,6 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS]: OnyxTypes.PolicyMember; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES]: OnyxTypes.RecentlyUsedCategories; [ONYXKEYS.COLLECTION.POLICY_REPORT_FIELDS]: OnyxTypes.PolicyReportFields; - [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_REPORT_FIELDS]: OnyxTypes.RecentlyUsedReportFields; [ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST]: OnyxTypes.PolicyMembers; [ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT]: Record; [ONYXKEYS.COLLECTION.REPORT]: OnyxTypes.Report; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index afb3f3711746..fe273aefd000 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -176,10 +176,9 @@ Linking.getInitialURL().then((url) => { reportIDDeeplinkedFromOldDot = reportID; }); -let allRecentlyUsedReportFields: OnyxCollection = {}; +let allRecentlyUsedReportFields: OnyxEntry = {}; Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_REPORT_FIELDS, - waitForCollectionCallback: true, + key: ONYXKEYS.RECENTLY_USED_REPORT_FIELDS, callback: (val) => (allRecentlyUsedReportFields = val), }); @@ -1526,8 +1525,8 @@ function updatePolicyReportName(reportID: string, value: string) { API.write('RenameReport', parameters, {optimisticData, failureData, successData}); } -function updatePolicyReportField(policyID: string, reportID: string, reportField: PolicyReportField) { - const recentlyUsedValues = allRecentlyUsedReportFields?.[policyID]?.[reportField.fieldID] ?? []; +function updatePolicyReportField(reportID: string, reportField: PolicyReportField) { + const recentlyUsedValues = allRecentlyUsedReportFields?.[reportField.fieldID] ?? []; const optimisticData: OnyxUpdate[] = [ { @@ -1547,7 +1546,7 @@ function updatePolicyReportField(policyID: string, reportID: string, reportField if (reportField.type === 'dropdown') { optimisticData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_REPORT_FIELDS}${policyID}`, + key: ONYXKEYS.RECENTLY_USED_REPORT_FIELDS, value: { [reportField.fieldID]: [...new Set([...recentlyUsedValues, reportField.value])], }, @@ -1572,7 +1571,7 @@ function updatePolicyReportField(policyID: string, reportID: string, reportField if (reportField.type === 'dropdown') { failureData.push({ onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_REPORT_FIELDS}${policyID}`, + key: ONYXKEYS.RECENTLY_USED_REPORT_FIELDS, value: { [reportField.fieldID]: recentlyUsedValues, }, diff --git a/src/pages/EditReportFieldDropdownPage.tsx b/src/pages/EditReportFieldDropdownPage.tsx index 448ec5d68773..2815867778eb 100644 --- a/src/pages/EditReportFieldDropdownPage.tsx +++ b/src/pages/EditReportFieldDropdownPage.tsx @@ -32,17 +32,17 @@ type EditReportFieldDropdownPageComponentProps = { }; type EditReportFieldDropdownPageOnyxProps = { - policyRecentlyUsedReportFields: OnyxEntry; + recentlyUsedReportFields: OnyxEntry; }; type EditReportFieldDropdownPageProps = EditReportFieldDropdownPageComponentProps & EditReportFieldDropdownPageOnyxProps; -function EditReportFieldDropdownPage({fieldName, onSubmit, fieldID, fieldValue, fieldOptions, policyRecentlyUsedReportFields}: EditReportFieldDropdownPageProps) { +function EditReportFieldDropdownPage({fieldName, onSubmit, fieldID, fieldValue, fieldOptions, recentlyUsedReportFields}: EditReportFieldDropdownPageProps) { const [searchValue, setSearchValue] = useState(''); const styles = useThemeStyles(); const {getSafeAreaMargins} = useStyleUtils(); const {translate} = useLocalize(); - const recentlyUsedOptions = useMemo(() => policyRecentlyUsedReportFields?.[fieldID] ?? [], [policyRecentlyUsedReportFields, fieldID]); + const recentlyUsedOptions = useMemo(() => recentlyUsedReportFields?.[fieldID] ?? [], [recentlyUsedReportFields, fieldID]); const sections = useMemo(() => { const filteredRecentOptions = recentlyUsedOptions.filter((option) => option.toLowerCase().includes(searchValue.toLowerCase())); @@ -105,7 +105,7 @@ function EditReportFieldDropdownPage({fieldName, onSubmit, fieldID, fieldValue, EditReportFieldDropdownPage.displayName = 'EditReportFieldDropdownPage'; export default withOnyx({ - policyRecentlyUsedReportFields: { - key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_REPORT_FIELDS}${policyID}`, + recentlyUsedReportFields: { + key: () => ONYXKEYS.RECENTLY_USED_REPORT_FIELDS, }, })(EditReportFieldDropdownPage); diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index 2cb47918ce34..24ade45993f6 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -68,7 +68,7 @@ function EditReportFieldPage({route, policy, report, policyReportFields}: EditRe if (isReportFieldTitle) { ReportActions.updatePolicyReportName(report.reportID, value); } else { - ReportActions.updatePolicyReportField(report.policyID ?? '', report.reportID, {...reportField, value}); + ReportActions.updatePolicyReportField(report.reportID, {...reportField, value}); } Navigation.dismissModal(report?.reportID); From 022efe32a9c8dad2c62a43d646fe3e1dbbab21ce Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Wed, 31 Jan 2024 04:22:43 +0500 Subject: [PATCH 10/13] fix: minor refactors to function names --- .../ReportActionItem/MoneyReportView.tsx | 9 +++----- .../parameters/SetPolicyReportNameParams.ts | 6 ------ .../API/parameters/SetReportNameParams.ts | 6 ++++++ src/libs/API/parameters/index.ts | 2 +- src/libs/API/types.ts | 4 ++-- src/libs/ReportUtils.ts | 21 +++++++++++++++++++ src/libs/actions/Report.ts | 10 ++++++--- src/pages/EditReportFieldPage.tsx | 4 ++-- 8 files changed, 42 insertions(+), 20 deletions(-) delete mode 100644 src/libs/API/parameters/SetPolicyReportNameParams.ts create mode 100644 src/libs/API/parameters/SetReportNameParams.ts diff --git a/src/components/ReportActionItem/MoneyReportView.tsx b/src/components/ReportActionItem/MoneyReportView.tsx index 5651d0b943ab..4af5ee7f86fa 100644 --- a/src/components/ReportActionItem/MoneyReportView.tsx +++ b/src/components/ReportActionItem/MoneyReportView.tsx @@ -59,12 +59,9 @@ function MoneyReportView({report, policy, policyReportFields, shouldShowHorizont ]; const sortedPolicyReportFields = useMemo((): PolicyReportField[] => { - const reportFields = Object.values(report.reportFields ?? {}); - const mergedFieldIds = Array.from(new Set([...policyReportFields.map(({fieldID}) => fieldID), ...reportFields.map(({fieldID}) => fieldID)])); - const mergedFields = mergedFieldIds.map((id) => report?.reportFields?.[id] ?? policyReportFields.find(({fieldID}) => fieldID === id)) as PolicyReportField[]; - const allReportFields = isSettled ? reportFields : mergedFields; - return allReportFields.sort(({orderWeight: firstOrderWeight}, {orderWeight: secondOrderWeight}) => firstOrderWeight - secondOrderWeight); - }, [policyReportFields, report.reportFields, isSettled]); + const fields = ReportUtils.getAvailableReportFields(report, policyReportFields); + return fields.sort(({orderWeight: firstOrderWeight}, {orderWeight: secondOrderWeight}) => firstOrderWeight - secondOrderWeight); + }, [policyReportFields, report]); return ( diff --git a/src/libs/API/parameters/SetPolicyReportNameParams.ts b/src/libs/API/parameters/SetPolicyReportNameParams.ts deleted file mode 100644 index d6310ee18115..000000000000 --- a/src/libs/API/parameters/SetPolicyReportNameParams.ts +++ /dev/null @@ -1,6 +0,0 @@ -type SetPolicyReportNameParams = { - reportID: string; - reportName: string; -}; - -export default SetPolicyReportNameParams; diff --git a/src/libs/API/parameters/SetReportNameParams.ts b/src/libs/API/parameters/SetReportNameParams.ts new file mode 100644 index 000000000000..784674e1486e --- /dev/null +++ b/src/libs/API/parameters/SetReportNameParams.ts @@ -0,0 +1,6 @@ +type SetReportNameParams = { + reportID: string; + reportName: string; +}; + +export default SetReportNameParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 635887b33e4b..b2a68fca8562 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -123,4 +123,4 @@ export type {default as CompleteTaskParams} from './CompleteTaskParams'; export type {default as CompleteEngagementModalParams} from './CompleteEngagementModalParams'; export type {default as SetNameValuePairParams} from './SetNameValuePairParams'; export type {default as SetPolicyReportFieldParams} from './SetPolicyReportFieldParams'; -export type {default as SetPolicyReportNameParams} from './SetPolicyReportNameParams'; +export type {default as SetReportNameParams} from './SetReportNameParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index ca13e828f1bd..83f30700a2c6 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -114,7 +114,7 @@ const WRITE_COMMANDS = { COMPLETE_ENGAGEMENT_MODAL: 'CompleteEngagementModal', SET_NAME_VALUE_PAIR: 'SetNameValuePair', SET_POLICY_REPORT_FIELD: 'Report_SetFields', - SET_POLICY_REPORT_NAME: 'RenameReport', + SET_REPORT_NAME: 'RenameReport', } as const; type WriteCommand = ValueOf; @@ -226,7 +226,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.COMPLETE_ENGAGEMENT_MODAL]: Parameters.CompleteEngagementModalParams; [WRITE_COMMANDS.SET_NAME_VALUE_PAIR]: Parameters.SetNameValuePairParams; [WRITE_COMMANDS.SET_POLICY_REPORT_FIELD]: Parameters.SetPolicyReportFieldParams; - [WRITE_COMMANDS.SET_POLICY_REPORT_NAME]: Parameters.SetPolicyReportNameParams; + [WRITE_COMMANDS.SET_REPORT_NAME]: Parameters.SetReportNameParams; }; const READ_COMMANDS = { diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 9f3d52eecd48..0f656b05f252 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1913,6 +1913,26 @@ function getReportFieldsByPolicyID(policyID: string) { return Object.entries(allPolicyReportFields ?? {}).find(([key]) => key.replace(ONYXKEYS.COLLECTION.POLICY_REPORT_FIELDS, '') === policyID)?.[1]; } +/** + * Get the report fields that we should display a MoneyReportView gets opened + */ + +function getAvailableReportFields(report: Report, policyReportFields: PolicyReportField[]): PolicyReportField[] { + // Get the report fields that are attached to a report. These will persist even if a field is deleted from the policy. + const reportFields = Object.values(report.reportFields ?? {}); + const reportIsSettled = isSettled(report.reportID); + + // If the report is settled, we don't want to show any new field that gets added to the policy. + if (reportIsSettled) { + return reportFields; + } + + // If the report is unsettled, we want to merge the new fields that get added to the policy with the fields that + // are attached to the report. + const mergedFieldIds = Array.from(new Set([...policyReportFields.map(({fieldID}) => fieldID), ...reportFields.map(({fieldID}) => fieldID)])); + return mergedFieldIds.map((id) => report?.reportFields?.[id] ?? policyReportFields.find(({fieldID}) => fieldID === id)) as PolicyReportField[]; +} + /** * Get the title for an IOU or expense chat which will be showing the payer and the amount */ @@ -4843,6 +4863,7 @@ export { isValidReport, isReportFieldOfTypeTitle, isReportFieldDisabled, + getAvailableReportFields, }; export type { diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 3dad99f59df1..f60fb0a62b1f 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1468,7 +1468,7 @@ function toggleSubscribeToChildReport(childReportID = '0', parentReportAction: P } } -function updatePolicyReportName(reportID: string, value: string) { +function updateReportName(reportID: string, value: string, previousValue: string) { const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -1486,6 +1486,7 @@ function updatePolicyReportName(reportID: string, value: string) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { + reportName: previousValue, pendingFields: { reportName: null, }, @@ -1519,7 +1520,7 @@ function updatePolicyReportName(reportID: string, value: string) { API.write('RenameReport', parameters, {optimisticData, failureData, successData}); } -function updatePolicyReportField(reportID: string, reportField: PolicyReportField) { +function updatePolicyReportField(reportID: string, reportField: PolicyReportField, previousReportField: PolicyReportField) { const recentlyUsedValues = allRecentlyUsedReportFields?.[reportField.fieldID] ?? []; const optimisticData: OnyxUpdate[] = [ @@ -1552,6 +1553,9 @@ function updatePolicyReportField(reportID: string, reportField: PolicyReportFiel onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { + reportFields: { + [reportField.fieldID]: previousReportField, + }, pendingFields: { [reportField.fieldID]: null, }, @@ -2855,6 +2859,6 @@ export { updateLastVisitTime, clearNewRoomFormError, updatePolicyReportField, - updatePolicyReportName, + updateReportName, resolveActionableMentionWhisper, }; diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index 24ade45993f6..b2d04e714d27 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -66,9 +66,9 @@ function EditReportFieldPage({route, policy, report, policyReportFields}: EditRe const handleReportFieldChange = (form: OnyxFormValuesFields) => { const value = form[reportField.fieldID].toString() || ''; if (isReportFieldTitle) { - ReportActions.updatePolicyReportName(report.reportID, value); + ReportActions.updateReportName(report.reportID, value, report.reportName ?? ''); } else { - ReportActions.updatePolicyReportField(report.reportID, {...reportField, value}); + ReportActions.updatePolicyReportField(report.reportID, {...reportField, value}, reportField); } Navigation.dismissModal(report?.reportID); From db3738de68e25edb3bc5c7eb59b79d06329b62a3 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Wed, 31 Jan 2024 04:32:01 +0500 Subject: [PATCH 11/13] fix: lint issues --- src/libs/API/parameters/SetPolicyReportFieldParams.ts | 6 ------ src/libs/API/parameters/SetReportFieldParams.ts | 6 ++++++ src/libs/API/parameters/index.ts | 2 +- src/libs/API/types.ts | 4 ++-- src/libs/actions/Report.ts | 8 ++++---- src/pages/EditReportFieldPage.tsx | 2 +- src/pages/EditReportFieldTextPage.tsx | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) delete mode 100644 src/libs/API/parameters/SetPolicyReportFieldParams.ts create mode 100644 src/libs/API/parameters/SetReportFieldParams.ts diff --git a/src/libs/API/parameters/SetPolicyReportFieldParams.ts b/src/libs/API/parameters/SetPolicyReportFieldParams.ts deleted file mode 100644 index 94f059057b58..000000000000 --- a/src/libs/API/parameters/SetPolicyReportFieldParams.ts +++ /dev/null @@ -1,6 +0,0 @@ -type SetPolicyReportFieldParams = { - reportID: string; - reportFields: string; -}; - -export default SetPolicyReportFieldParams; diff --git a/src/libs/API/parameters/SetReportFieldParams.ts b/src/libs/API/parameters/SetReportFieldParams.ts new file mode 100644 index 000000000000..8b6c8682d657 --- /dev/null +++ b/src/libs/API/parameters/SetReportFieldParams.ts @@ -0,0 +1,6 @@ +type SetReportFieldParams = { + reportID: string; + reportFields: string; +}; + +export default SetReportFieldParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index b2a68fca8562..8c0c2fde17cf 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -122,5 +122,5 @@ export type {default as ReopenTaskParams} from './ReopenTaskParams'; export type {default as CompleteTaskParams} from './CompleteTaskParams'; export type {default as CompleteEngagementModalParams} from './CompleteEngagementModalParams'; export type {default as SetNameValuePairParams} from './SetNameValuePairParams'; -export type {default as SetPolicyReportFieldParams} from './SetPolicyReportFieldParams'; +export type {default as SetReportFieldParams} from './SetReportFieldParams'; export type {default as SetReportNameParams} from './SetReportNameParams'; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 83f30700a2c6..05b658ee0702 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -113,7 +113,7 @@ const WRITE_COMMANDS = { COMPLETE_TASK: 'CompleteTask', COMPLETE_ENGAGEMENT_MODAL: 'CompleteEngagementModal', SET_NAME_VALUE_PAIR: 'SetNameValuePair', - SET_POLICY_REPORT_FIELD: 'Report_SetFields', + SET_REPORT_FIELD: 'Report_SetFields', SET_REPORT_NAME: 'RenameReport', } as const; @@ -225,7 +225,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.COMPLETE_TASK]: Parameters.CompleteTaskParams; [WRITE_COMMANDS.COMPLETE_ENGAGEMENT_MODAL]: Parameters.CompleteEngagementModalParams; [WRITE_COMMANDS.SET_NAME_VALUE_PAIR]: Parameters.SetNameValuePairParams; - [WRITE_COMMANDS.SET_POLICY_REPORT_FIELD]: Parameters.SetPolicyReportFieldParams; + [WRITE_COMMANDS.SET_REPORT_FIELD]: Parameters.SetReportFieldParams; [WRITE_COMMANDS.SET_REPORT_NAME]: Parameters.SetReportNameParams; }; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index f60fb0a62b1f..38a73c1d3055 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1517,10 +1517,10 @@ function updateReportName(reportID: string, value: string, previousValue: string reportName: value, }; - API.write('RenameReport', parameters, {optimisticData, failureData, successData}); + API.write(WRITE_COMMANDS.SET_REPORT_NAME, parameters, {optimisticData, failureData, successData}); } -function updatePolicyReportField(reportID: string, reportField: PolicyReportField, previousReportField: PolicyReportField) { +function updateReportField(reportID: string, reportField: PolicyReportField, previousReportField: PolicyReportField) { const recentlyUsedValues = allRecentlyUsedReportFields?.[reportField.fieldID] ?? []; const optimisticData: OnyxUpdate[] = [ @@ -1596,7 +1596,7 @@ function updatePolicyReportField(reportID: string, reportField: PolicyReportFiel reportFields: JSON.stringify({[reportField.fieldID]: {fieldID: reportField.fieldID, value: reportField.value, type: reportField.type, name: reportField.name}}), }; - API.write('Report_SetFields', parameters, {optimisticData, failureData, successData}); + API.write(WRITE_COMMANDS.SET_REPORT_FIELD, parameters, {optimisticData, failureData, successData}); } function updateWelcomeMessage(reportID: string, previousValue: string, newValue: string) { @@ -2858,7 +2858,7 @@ export { getDraftPrivateNote, updateLastVisitTime, clearNewRoomFormError, - updatePolicyReportField, + updateReportField, updateReportName, resolveActionableMentionWhisper, }; diff --git a/src/pages/EditReportFieldPage.tsx b/src/pages/EditReportFieldPage.tsx index b2d04e714d27..602f2eed161e 100644 --- a/src/pages/EditReportFieldPage.tsx +++ b/src/pages/EditReportFieldPage.tsx @@ -68,7 +68,7 @@ function EditReportFieldPage({route, policy, report, policyReportFields}: EditRe if (isReportFieldTitle) { ReportActions.updateReportName(report.reportID, value, report.reportName ?? ''); } else { - ReportActions.updatePolicyReportField(report.reportID, {...reportField, value}, reportField); + ReportActions.updateReportField(report.reportID, {...reportField, value}, reportField); } Navigation.dismissModal(report?.reportID); diff --git a/src/pages/EditReportFieldTextPage.tsx b/src/pages/EditReportFieldTextPage.tsx index 096967cf4003..bb1a42103da1 100644 --- a/src/pages/EditReportFieldTextPage.tsx +++ b/src/pages/EditReportFieldTextPage.tsx @@ -38,7 +38,7 @@ function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, isRequired, f const validate = useCallback( (values: OnyxFormValuesFields) => { const errors: Errors = {}; - if (isRequired && values[fieldID].toString().trim() === '') { + if (isRequired && (values[fieldID] as string).trim() === '') { errors[fieldID] = 'common.error.fieldRequired'; } return errors; From d0db92fda86a6f7aec6736dd21e882c11e4d4af6 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Wed, 31 Jan 2024 04:46:27 +0500 Subject: [PATCH 12/13] fix: use ucfirst str lib function and handle more lint issues --- src/ONYXKEYS.ts | 8 ++++---- src/components/ReportActionItem/MoneyReportView.tsx | 3 ++- src/pages/EditReportFieldDatePage.tsx | 8 ++++---- src/pages/EditReportFieldPage.tsx | 11 ++++++----- src/pages/EditReportFieldTextPage.tsx | 8 ++++---- src/types/onyx/Form.ts | 4 +++- src/types/onyx/index.ts | 3 ++- 7 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index e3c42238318d..b4ca0c898b0b 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -358,8 +358,8 @@ const ONYXKEYS = { REPORT_VIRTUAL_CARD_FRAUD_DRAFT: 'reportVirtualCardFraudFormDraft', GET_PHYSICAL_CARD_FORM: 'getPhysicalCardForm', GET_PHYSICAL_CARD_FORM_DRAFT: 'getPhysicalCardFormDraft', - POLICY_REPORT_FIELD_EDIT_FORM: 'policyReportFieldEditForm', - POLICY_REPORT_FIELD_EDIT_FORM_DRAFT: 'policyReportFieldEditFormDraft', + REPORT_FIELD_EDIT_FORM: 'reportFieldEditForm', + REPORT_FIELD_EDIT_FORM_DRAFT: 'reportFieldEditFormDraft', REIMBURSEMENT_ACCOUNT_FORM: 'reimbursementAccount', REIMBURSEMENT_ACCOUNT_FORM_DRAFT: 'reimbursementAccountDraft', }, @@ -542,8 +542,8 @@ type OnyxValues = { [ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.GET_PHYSICAL_CARD_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.GET_PHYSICAL_CARD_FORM_DRAFT]: OnyxTypes.Form; - [ONYXKEYS.FORMS.POLICY_REPORT_FIELD_EDIT_FORM]: OnyxTypes.Form; - [ONYXKEYS.FORMS.POLICY_REPORT_FIELD_EDIT_FORM_DRAFT]: OnyxTypes.Form; + [ONYXKEYS.FORMS.REPORT_FIELD_EDIT_FORM]: OnyxTypes.ReportFieldEditForm; + [ONYXKEYS.FORMS.REPORT_FIELD_EDIT_FORM_DRAFT]: OnyxTypes.Form; // @ts-expect-error Different values are defined under the same key: ReimbursementAccount and ReimbursementAccountForm [ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.REIMBURSEMENT_ACCOUNT_FORM_DRAFT]: OnyxTypes.Form; diff --git a/src/components/ReportActionItem/MoneyReportView.tsx b/src/components/ReportActionItem/MoneyReportView.tsx index 4af5ee7f86fa..3c0e50b2c940 100644 --- a/src/components/ReportActionItem/MoneyReportView.tsx +++ b/src/components/ReportActionItem/MoneyReportView.tsx @@ -1,3 +1,4 @@ +import Str from 'expensify-common/lib/str'; import React, {useMemo} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; import {View} from 'react-native'; @@ -81,7 +82,7 @@ function MoneyReportView({report, policy, policyReportFields, shouldShowHorizont key={`menuItem-${reportField.fieldID}`} > Navigation.navigate(ROUTES.EDIT_REPORT_FIELD_REQUEST.getRoute(report.reportID, report.policyID ?? '', reportField.fieldID))} shouldShowRightIcon diff --git a/src/pages/EditReportFieldDatePage.tsx b/src/pages/EditReportFieldDatePage.tsx index 2496e5b23bf2..82659eca62c2 100644 --- a/src/pages/EditReportFieldDatePage.tsx +++ b/src/pages/EditReportFieldDatePage.tsx @@ -27,7 +27,7 @@ type EditReportFieldDatePageProps = { isRequired: boolean; /** Callback to fire when the Save button is pressed */ - onSubmit: (form: OnyxFormValuesFields) => void; + onSubmit: (form: OnyxFormValuesFields) => void; }; function EditReportFieldDatePage({fieldName, isRequired, onSubmit, fieldValue, fieldID}: EditReportFieldDatePageProps) { @@ -36,9 +36,9 @@ function EditReportFieldDatePage({fieldName, isRequired, onSubmit, fieldValue, f const inputRef = useRef(null); const validate = useCallback( - (value: OnyxFormValuesFields) => { + (value: OnyxFormValuesFields) => { const errors: Errors = {}; - if (isRequired && value[fieldID].toString().trim() === '') { + if (isRequired && value[fieldID].trim() === '') { errors[fieldID] = 'common.error.fieldRequired'; } return errors; @@ -58,7 +58,7 @@ function EditReportFieldDatePage({fieldName, isRequired, onSubmit, fieldValue, f ) => { - const value = form[reportField.fieldID].toString() || ''; + const handleReportFieldChange = (form: OnyxFormValuesFields) => { + const value = form[reportField.fieldID] || ''; if (isReportFieldTitle) { ReportActions.updateReportName(report.reportID, value, report.reportName ?? ''); } else { @@ -79,7 +80,7 @@ function EditReportFieldPage({route, policy, report, policyReportFields}: EditRe if (reportField.type === 'text' || isReportFieldTitle) { return ( ) => void; + onSubmit: (form: OnyxFormValuesFields) => void; }; function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, isRequired, fieldID}: EditReportFieldTextPageProps) { @@ -36,9 +36,9 @@ function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, isRequired, f const inputRef = useRef(null); const validate = useCallback( - (values: OnyxFormValuesFields) => { + (values: OnyxFormValuesFields) => { const errors: Errors = {}; - if (isRequired && (values[fieldID] as string).trim() === '') { + if (isRequired && values[fieldID].trim() === '') { errors[fieldID] = 'common.error.fieldRequired'; } return errors; @@ -58,7 +58,7 @@ function EditReportFieldTextPage({fieldName, onSubmit, fieldValue, isRequired, f ; +type ReportFieldEditForm = Form>; + export default Form; -export type {AddDebitCardForm, DateOfBirthForm, PrivateNotesForm, DisplayNameForm, FormValueType, NewRoomForm, BaseForm, IKnowATeacherForm, IntroSchoolPrincipalForm}; +export type {AddDebitCardForm, DateOfBirthForm, PrivateNotesForm, DisplayNameForm, FormValueType, NewRoomForm, BaseForm, IKnowATeacherForm, IntroSchoolPrincipalForm, ReportFieldEditForm}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 5b04cae58671..64eec736b5bf 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -9,7 +9,7 @@ import type Credentials from './Credentials'; import type Currency from './Currency'; import type CustomStatusDraft from './CustomStatusDraft'; import type Download from './Download'; -import type {AddDebitCardForm, DateOfBirthForm, DisplayNameForm, IKnowATeacherForm, IntroSchoolPrincipalForm, NewRoomForm, PrivateNotesForm} from './Form'; +import type {AddDebitCardForm, DateOfBirthForm, DisplayNameForm, IKnowATeacherForm, IntroSchoolPrincipalForm, NewRoomForm, PrivateNotesForm, ReportFieldEditForm} from './Form'; import type Form from './Form'; import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji'; import type {FundList} from './Fund'; @@ -151,4 +151,5 @@ export type { IKnowATeacherForm, IntroSchoolPrincipalForm, PrivateNotesForm, + ReportFieldEditForm, }; From 0c9939ac37fc152c2fb7f3f73d12a86cfc77d933 Mon Sep 17 00:00:00 2001 From: Sibtain Ali Date: Wed, 31 Jan 2024 04:51:32 +0500 Subject: [PATCH 13/13] fix: include the whole report field object in the set report field call --- src/libs/actions/Report.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index 38a73c1d3055..221c7f8d4f88 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -1593,7 +1593,7 @@ function updateReportField(reportID: string, reportField: PolicyReportField, pre const parameters = { reportID, - reportFields: JSON.stringify({[reportField.fieldID]: {fieldID: reportField.fieldID, value: reportField.value, type: reportField.type, name: reportField.name}}), + reportFields: JSON.stringify({[reportField.fieldID]: reportField}), }; API.write(WRITE_COMMANDS.SET_REPORT_FIELD, parameters, {optimisticData, failureData, successData});