From 297a113232aff090c8f93d1160d6292d7477425f Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Wed, 11 Dec 2024 22:31:54 +0000 Subject: [PATCH 1/2] fix(debug mode): unable to add new report actions --- src/libs/actions/Debug.ts | 5 +++ src/pages/Debug/DebugDetails.tsx | 21 ++++----- src/pages/Debug/Report/DebugReportPage.tsx | 1 - .../DebugReportActionCreatePage.tsx | 43 +++++++++++-------- .../ReportAction/DebugReportActionPage.tsx | 10 +++-- .../Transaction/DebugTransactionPage.tsx | 18 ++++++-- .../DebugTransactionViolationPage.tsx | 8 +++- 7 files changed, 68 insertions(+), 38 deletions(-) diff --git a/src/libs/actions/Debug.ts b/src/libs/actions/Debug.ts index 4c3479ee9741..6fbf18505074 100644 --- a/src/libs/actions/Debug.ts +++ b/src/libs/actions/Debug.ts @@ -11,7 +11,12 @@ function setDebugData(on Onyx.set(onyxKey, onyxValue); } +function mergeDebugData(onyxKey: TKey, onyxValue: OnyxMergeInput) { + Onyx.merge(onyxKey, onyxValue); +} + export default { resetDebugDetailsDraftForm, setDebugData, + mergeDebugData, }; diff --git a/src/pages/Debug/DebugDetails.tsx b/src/pages/Debug/DebugDetails.tsx index 60126ef1937a..c8129e4b6568 100644 --- a/src/pages/Debug/DebugDetails.tsx +++ b/src/pages/Debug/DebugDetails.tsx @@ -15,8 +15,6 @@ import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import type {ObjectType, OnyxDataType} from '@libs/DebugUtils'; import DebugUtils from '@libs/DebugUtils'; -import * as PolicyUtils from '@libs/PolicyUtils'; -import * as TagsOptionsListUtils from '@libs/TagsOptionsListUtils'; import Debug from '@userActions/Debug'; import type CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; @@ -34,6 +32,10 @@ type DebugDetailsProps = { /** The report or report action data to be displayed and editted. */ data: OnyxEntry | OnyxEntry | OnyxEntry | OnyxEntry; + policyHasEnabledTags?: boolean; + + policyID?: string; + children?: React.ReactNode; /** Callback to be called when user saves the debug data. */ @@ -47,13 +49,10 @@ type DebugDetailsProps = { validate: (key: any, value: string) => void; }; -function DebugDetails({formType, data, children, onSave, onDelete, validate}: DebugDetailsProps) { +function DebugDetails({formType, data, policyHasEnabledTags, policyID, children, onSave, onDelete, validate}: DebugDetailsProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const [formDraftData] = useOnyx(ONYXKEYS.FORMS.DEBUG_DETAILS_FORM_DRAFT); - const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${(data as OnyxEntry)?.reportID ?? ''}`); - const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID}`); - const policyTagLists = useMemo(() => PolicyUtils.getTagLists(policyTags), [policyTags]); const booleanFields = useMemo( () => Object.entries(data ?? {}) @@ -66,13 +65,13 @@ function DebugDetails({formType, data, children, onSave, onDelete, validate}: De Object.entries(data ?? {}) .filter((entry): entry is [string, string] => { // Tag picker needs to be hidden when the policy has no tags available to pick - if (entry[0] === TRANSACTION_FORM_INPUT_IDS.TAG && !TagsOptionsListUtils.hasEnabledTags(policyTagLists)) { + if (entry[0] === TRANSACTION_FORM_INPUT_IDS.TAG && !policyHasEnabledTags) { return false; } return DETAILS_CONSTANT_FIELDS[formType].some(({fieldName}) => fieldName === entry[0]); }) .sort((a, b) => a[0].localeCompare(b[0])), - [data, formType, policyTagLists], + [data, formType, policyHasEnabledTags], ); const numberFields = useMemo( () => @@ -209,7 +208,7 @@ function DebugDetails({formType, data, children, onSave, onDelete, validate}: De name={key} shouldSaveDraft defaultValue={String(value)} - policyID={report?.policyID} + policyID={policyID} /> ))} {constantFields.length === 0 && {translate('debug.none')}} @@ -248,9 +247,7 @@ function DebugDetails({formType, data, children, onSave, onDelete, validate}: De danger large text={translate('common.delete')} - onPress={() => { - onDelete(); - }} + onPress={onDelete} /> diff --git a/src/pages/Debug/Report/DebugReportPage.tsx b/src/pages/Debug/Report/DebugReportPage.tsx index 16e23ed4c608..a31597bb59dd 100644 --- a/src/pages/Debug/Report/DebugReportPage.tsx +++ b/src/pages/Debug/Report/DebugReportPage.tsx @@ -144,7 +144,6 @@ function DebugReportPage({ Debug.setDebugData(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, data); }} onDelete={() => { - Debug.setDebugData(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, null); navigateToConciergeChatAndDeleteReport(reportID, true, true); }} validate={DebugUtils.validateReportDraftProperty} diff --git a/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx b/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx index 2066ab71c639..1162146b8f4d 100644 --- a/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx +++ b/src/pages/Debug/ReportAction/DebugReportActionCreatePage.tsx @@ -1,4 +1,4 @@ -import React, {useState} from 'react'; +import React, {useCallback, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx} from 'react-native-onyx'; @@ -51,6 +51,29 @@ function DebugReportActionCreatePage({ const [draftReportAction, setDraftReportAction] = useState(() => getInitialReportAction(reportID, session, personalDetailsList)); const [error, setError] = useState(); + const createReportAction = useCallback(() => { + const parsedReportAction = JSON.parse(draftReportAction.replaceAll('\n', '')) as ReportAction; + Debug.mergeDebugData(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, { + [parsedReportAction.reportActionID]: parsedReportAction, + }); + Navigation.navigate(ROUTES.DEBUG_REPORT_TAB_ACTIONS.getRoute(reportID)); + }, [draftReportAction, reportID]); + + const editJSON = useCallback( + (updatedJSON: string) => { + try { + DebugUtils.validateReportActionJSON(updatedJSON); + setError(''); + } catch (e) { + const {cause, message} = e as SyntaxError; + setError(cause ? translate(message as TranslationPaths, cause as never) : message); + } finally { + setDraftReportAction(updatedJSON); + } + }, + [translate], + ); + return ( { - try { - DebugUtils.validateReportActionJSON(updatedJSON); - setError(''); - } catch (e) { - const {cause, message} = e as SyntaxError; - setError(cause ? translate(message as TranslationPaths, cause as never) : message); - } finally { - setDraftReportAction(updatedJSON); - } - }} + onChangeText={editJSON} textInputContainerStyles={[styles.border, styles.borderBottom, styles.p5]} /> @@ -112,11 +125,7 @@ function DebugReportActionCreatePage({ success text={translate('common.save')} isDisabled={!draftReportAction || !!error} - onPress={() => { - const parsedReportAction = JSON.parse(draftReportAction.replaceAll('\n', '')) as ReportAction; - Debug.setDebugData(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {[parsedReportAction.reportActionID]: parsedReportAction}); - Navigation.navigate(ROUTES.DEBUG_REPORT_TAB_ACTIONS.getRoute(reportID)); - }} + onPress={createReportAction} /> diff --git a/src/pages/Debug/ReportAction/DebugReportActionPage.tsx b/src/pages/Debug/ReportAction/DebugReportActionPage.tsx index e072913c0c03..8c9e33af7f85 100644 --- a/src/pages/Debug/ReportAction/DebugReportActionPage.tsx +++ b/src/pages/Debug/ReportAction/DebugReportActionPage.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import {View} from 'react-native'; +import {InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -61,11 +61,15 @@ function DebugReportActionPage({ formType={CONST.DEBUG.FORMS.REPORT_ACTION} data={reportAction} onSave={(data) => { - Debug.setDebugData(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {[reportActionID]: data}); + Debug.mergeDebugData(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {[reportActionID]: data}); }} onDelete={() => { - Debug.setDebugData(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {[reportActionID]: null}); Navigation.goBack(); + // We need to wait for navigation animations to finish before deleting an action, + // otherwise the user will see a not found page briefly. + InteractionManager.runAfterInteractions(() => { + Debug.mergeDebugData(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {[reportActionID]: null}); + }); }} validate={DebugUtils.validateReportActionDraftProperty} > diff --git a/src/pages/Debug/Transaction/DebugTransactionPage.tsx b/src/pages/Debug/Transaction/DebugTransactionPage.tsx index b729d18374e9..86a8e3ded86a 100644 --- a/src/pages/Debug/Transaction/DebugTransactionPage.tsx +++ b/src/pages/Debug/Transaction/DebugTransactionPage.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import {View} from 'react-native'; +import React, {useMemo} from 'react'; +import {InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; @@ -14,6 +14,8 @@ import Navigation from '@libs/Navigation/Navigation'; import OnyxTabNavigator, {TopTab} from '@libs/Navigation/OnyxTabNavigator'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; import type {DebugParamList} from '@libs/Navigation/types'; +import * as PolicyUtils from '@libs/PolicyUtils'; +import * as TagsOptionsListUtils from '@libs/TagsOptionsListUtils'; import DebugDetails from '@pages/Debug/DebugDetails'; import DebugJSON from '@pages/Debug/DebugJSON'; import NotFoundPage from '@pages/ErrorPage/NotFoundPage'; @@ -32,6 +34,10 @@ function DebugTransactionPage({ }: DebugTransactionPageProps) { const {translate} = useLocalize(); const [transaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`); + const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${transaction?.reportID}`); + const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${report?.policyID}`); + const policyTagLists = useMemo(() => PolicyUtils.getTagLists(policyTags), [policyTags]); + const styles = useThemeStyles(); if (!transaction) { @@ -60,12 +66,18 @@ function DebugTransactionPage({ { Debug.setDebugData(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, data); }} onDelete={() => { - Debug.setDebugData(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, null); Navigation.goBack(); + // We need to wait for navigation animations to finish before deleting a transaction, + // otherwise the user will see a not found page briefly. + InteractionManager.runAfterInteractions(() => { + Debug.setDebugData(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, null); + }); }} validate={DebugUtils.validateTransactionDraftProperty} > diff --git a/src/pages/Debug/TransactionViolation/DebugTransactionViolationPage.tsx b/src/pages/Debug/TransactionViolation/DebugTransactionViolationPage.tsx index 2c44e936f10f..f615060ab6df 100644 --- a/src/pages/Debug/TransactionViolation/DebugTransactionViolationPage.tsx +++ b/src/pages/Debug/TransactionViolation/DebugTransactionViolationPage.tsx @@ -1,5 +1,5 @@ import React, {useCallback, useMemo} from 'react'; -import {View} from 'react-native'; +import {InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; @@ -45,8 +45,12 @@ function DebugTransactionViolationPage({ const deleteTransactionViolation = useCallback(() => { const updatedTransactionViolations = [...(transactionViolations ?? [])]; updatedTransactionViolations.splice(Number(index), 1); - Debug.setDebugData(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, updatedTransactionViolations); Navigation.goBack(); + // We need to wait for navigation animations to finish before deleting a violation, + // otherwise the user will see a not found page briefly. + InteractionManager.runAfterInteractions(() => { + Debug.setDebugData(`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`, updatedTransactionViolations); + }); }, [index, transactionID, transactionViolations]); if (!transactionViolation) { From f0d383c508a621421249c9fc5d9e84a2a8ade938 Mon Sep 17 00:00:00 2001 From: Pedro Guerreiro Date: Wed, 11 Dec 2024 22:51:42 +0000 Subject: [PATCH 2/2] docs: add missing prop descriptions --- src/pages/Debug/DebugDetails.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/Debug/DebugDetails.tsx b/src/pages/Debug/DebugDetails.tsx index c8129e4b6568..c5b0b068e65d 100644 --- a/src/pages/Debug/DebugDetails.tsx +++ b/src/pages/Debug/DebugDetails.tsx @@ -32,10 +32,13 @@ type DebugDetailsProps = { /** The report or report action data to be displayed and editted. */ data: OnyxEntry | OnyxEntry | OnyxEntry | OnyxEntry; + /** Whether the provided policy has enabled tags */ policyHasEnabledTags?: boolean; + /** ID of the provided policy */ policyID?: string; + /** Metadata UI */ children?: React.ReactNode; /** Callback to be called when user saves the debug data. */