From 06e5ea49b0c2d761180a7c05ebfcc8133dd1cfad Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Wed, 27 Mar 2024 16:16:31 -0700 Subject: [PATCH 01/33] chore: add parameter type for OpenPolicyAccountingPage --- src/libs/API/parameters/OpenPolicyAccountingPageParams.ts | 5 +++++ src/libs/API/parameters/index.ts | 1 + 2 files changed, 6 insertions(+) create mode 100644 src/libs/API/parameters/OpenPolicyAccountingPageParams.ts diff --git a/src/libs/API/parameters/OpenPolicyAccountingPageParams.ts b/src/libs/API/parameters/OpenPolicyAccountingPageParams.ts new file mode 100644 index 000000000000..0ebaa58ef0d1 --- /dev/null +++ b/src/libs/API/parameters/OpenPolicyAccountingPageParams.ts @@ -0,0 +1,5 @@ +type OpenPolicyAccountingPageParams = { + policyID: string; +}; + +export default OpenPolicyAccountingPageParams; diff --git a/src/libs/API/parameters/index.ts b/src/libs/API/parameters/index.ts index 87d9e2265568..27c9f718a950 100644 --- a/src/libs/API/parameters/index.ts +++ b/src/libs/API/parameters/index.ts @@ -198,3 +198,4 @@ export type {default as SetPolicyCustomTaxNameParams} from './SetPolicyCustomTax export type {default as SetPolicyForeignCurrencyDefaultParams} from './SetPolicyForeignCurrencyDefaultParams'; export type {default as SetPolicyCurrencyDefaultParams} from './SetPolicyCurrencyDefaultParams'; export type {default as RenamePolicyTaxParams} from './RenamePolicyTaxParams'; +export type {default as OpenPolicyAccountingPageParams} from './OpenPolicyAccountingPageParams'; From c9455856db0bd6835463c8ac2a247dcb98b6c129 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Wed, 27 Mar 2024 16:18:35 -0700 Subject: [PATCH 02/33] chore: add new command --- src/libs/API/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index fd84e65c028e..c8a878fd6a14 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -426,6 +426,7 @@ const READ_COMMANDS = { OPEN_POLICY_WORKFLOWS_PAGE: 'OpenPolicyWorkflowsPage', OPEN_POLICY_DISTANCE_RATES_PAGE: 'OpenPolicyDistanceRatesPage', OPEN_POLICY_MORE_FEATURES_PAGE: 'OpenPolicyMoreFeaturesPage', + OPEN_POLICY_ACCOUNTING_PAGE: 'OpenPolicyAccountingPage', } as const; type ReadCommand = ValueOf; @@ -466,6 +467,7 @@ type ReadCommandParameters = { [READ_COMMANDS.OPEN_POLICY_WORKFLOWS_PAGE]: Parameters.OpenPolicyWorkflowsPageParams; [READ_COMMANDS.OPEN_POLICY_DISTANCE_RATES_PAGE]: Parameters.OpenPolicyDistanceRatesPageParams; [READ_COMMANDS.OPEN_POLICY_MORE_FEATURES_PAGE]: Parameters.OpenPolicyMoreFeaturesPageParams; + [READ_COMMANDS.OPEN_POLICY_ACCOUNTING_PAGE]: Parameters.OpenPolicyAccountingPageParams; }; const SIDE_EFFECT_REQUEST_COMMANDS = { From e0532d5aaceb560bb1648dae198129656c6dfd08 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Wed, 27 Mar 2024 16:19:04 -0700 Subject: [PATCH 03/33] chore: add new action func to call web-e command --- src/libs/actions/PolicyConnections.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/libs/actions/PolicyConnections.ts diff --git a/src/libs/actions/PolicyConnections.ts b/src/libs/actions/PolicyConnections.ts new file mode 100644 index 000000000000..1270a7173d3f --- /dev/null +++ b/src/libs/actions/PolicyConnections.ts @@ -0,0 +1,15 @@ +import * as API from '@libs/API'; +import type {OpenPolicyAccountingPageParams} from '@libs/API/parameters'; +import {READ_COMMANDS} from '@libs/API/types'; + +function openPolicyAccountingPage({policyID}: {policyID: string}) { + const parameters: OpenPolicyAccountingPageParams = { + policyID, + }; + + API.read(READ_COMMANDS.OPEN_POLICY_ACCOUNTING_PAGE, parameters); +} + +// More action functions will be added later +// eslint-disable-next-line import/prefer-default-export +export {openPolicyAccountingPage}; From e6292e33f285564a63b26e6e25b68f425b54ea3d Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Wed, 27 Mar 2024 16:25:50 -0700 Subject: [PATCH 04/33] feat: add new HOC component --- src/pages/workspace/withPolicyConnections.tsx | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/pages/workspace/withPolicyConnections.tsx diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx new file mode 100644 index 000000000000..f4b6fd96a4d3 --- /dev/null +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -0,0 +1,55 @@ +import {useEffect} from 'react'; +import type {ComponentType} from 'react'; +import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; +import useNetwork from '@hooks/useNetwork'; +import {openPolicyAccountingPage} from '@libs/actions/PolicyConnections'; +import withPolicy from './withPolicy'; +import type {WithPolicyProps} from './withPolicy'; + +type WithPolicyConnectionsProps = WithPolicyProps; + +function withPolicyConnections(WrappedComponent: ComponentType) { + function WithPolicyConnections({policy, policyMembers, policyDraft, policyMembersDraft, route}: WithPolicyConnectionsProps) { + const {isOffline} = useNetwork(); + + useEffect(() => { + if (!policy?.connections || policy?.connections) { + return; + } + + openPolicyAccountingPage({policyID: policy?.id}); + }, [policy]); + + if (!policy?.connections) { + if (isOffline) { + return ( + + + + ); + } + + return null; + } + + return ( + + ); + } + + return withPolicy(WithPolicyConnections); +} + +export default withPolicyConnections; From b509d0fcabf73131eac2ee4b3373147a4e28eb73 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Thu, 28 Mar 2024 10:29:17 -0700 Subject: [PATCH 05/33] fix: conditional statement & change the parameter from object to single string --- src/libs/actions/PolicyConnections.ts | 2 +- src/pages/workspace/withPolicyConnections.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/PolicyConnections.ts b/src/libs/actions/PolicyConnections.ts index 1270a7173d3f..89eae3d20ace 100644 --- a/src/libs/actions/PolicyConnections.ts +++ b/src/libs/actions/PolicyConnections.ts @@ -2,7 +2,7 @@ import * as API from '@libs/API'; import type {OpenPolicyAccountingPageParams} from '@libs/API/parameters'; import {READ_COMMANDS} from '@libs/API/types'; -function openPolicyAccountingPage({policyID}: {policyID: string}) { +function openPolicyAccountingPage(policyID: string) { const parameters: OpenPolicyAccountingPageParams = { policyID, }; diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index f4b6fd96a4d3..435aa7873428 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -13,11 +13,11 @@ function withPolicyConnections(WrappedComponent: ComponentType { - if (!policy?.connections || policy?.connections) { + if (!!policy?.connections || !policy?.id) { return; } - openPolicyAccountingPage({policyID: policy?.id}); + openPolicyAccountingPage(policy.id); }, [policy]); if (!policy?.connections) { From 8e32fded9dff0a2401b310b4a31efeee4708d9d8 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Thu, 28 Mar 2024 10:36:28 -0700 Subject: [PATCH 06/33] fix: check if the connections feature is enabled & add comments --- src/pages/workspace/withPolicyConnections.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 435aa7873428..e733e947168a 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -13,10 +13,12 @@ function withPolicyConnections(WrappedComponent: ComponentType { - if (!!policy?.connections || !policy?.id) { + if (!policy?.areConnectionsEnabled || !!policy?.connections || !policy?.id) { return; } + // If the policy doesn't have the connections data when it has the accounting connections feature enabled, + // call the API to get the data openPolicyAccountingPage(policy.id); }, [policy]); From d8139a8c5fe43e9d0cd562cbfe2dda09d599f2f1 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Fri, 29 Mar 2024 10:14:53 -0700 Subject: [PATCH 07/33] doc: add and improve comments --- src/pages/workspace/withPolicyConnections.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index e733e947168a..49013e711334 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -8,17 +8,27 @@ import type {WithPolicyProps} from './withPolicy'; type WithPolicyConnectionsProps = WithPolicyProps; +/** + * Higher-order component that fetches the connections data and populates + * the corresponding field of the policy object if the field is empty. It then passes the policy object + * to the wrapped component. + * + * Use this HOC when you need the policy object with its connections field populated. + * + * Only the active policy gets the complete policy data upon app start that includes the connections data. + * For other policies, the connections data needs to be fetched when it's needed. + */ function withPolicyConnections(WrappedComponent: ComponentType) { function WithPolicyConnections({policy, policyMembers, policyDraft, policyMembersDraft, route}: WithPolicyConnectionsProps) { const {isOffline} = useNetwork(); useEffect(() => { + // When the accounting feature is not enabled, or if the connections data already exists, + // there is no need to fetch the connections data. if (!policy?.areConnectionsEnabled || !!policy?.connections || !policy?.id) { return; } - // If the policy doesn't have the connections data when it has the accounting connections feature enabled, - // call the API to get the data openPolicyAccountingPage(policy.id); }, [policy]); From 9a44aeb3151b93cea19a61ebda2eb30a4efede1f Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Fri, 29 Mar 2024 10:22:11 -0700 Subject: [PATCH 08/33] doc: add comment on the purpose of the new state --- src/pages/workspace/withPolicyConnections.tsx | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 49013e711334..ea562d5acca6 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -1,4 +1,4 @@ -import {useEffect} from 'react'; +import {useEffect, useState} from 'react'; import type {ComponentType} from 'react'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import useNetwork from '@hooks/useNetwork'; @@ -19,18 +19,37 @@ type WithPolicyConnectionsProps = WithPolicyProps; * For other policies, the connections data needs to be fetched when it's needed. */ function withPolicyConnections(WrappedComponent: ComponentType) { + /** + * Higher-order component that adds policy connections functionality to a component. + * + * @component + * @param {WithPolicyConnectionsProps} props - The props for the component. + * @returns {JSX.Element | null} The wrapped component with policy connections functionality. + */ + /** + * Higher-order component that adds policy connections functionality to a component. + * + * @param {WithPolicyConnectionsProps} props - The props for the component. + * @returns {React.ReactNode} - The wrapped component. + */ function WithPolicyConnections({policy, policyMembers, policyDraft, policyMembersDraft, route}: WithPolicyConnectionsProps) { const {isOffline} = useNetwork(); + // When the accounting feature is enabled, but the user hasn't connected to any accounting software, + // the connections data doesn't exist. We don't want to continually attempt to fetch non-existent data. + // This state helps us track whether a data fetch attempt has been made. + const [wasConnectionsDataFetched, setWasConnectionsDataFetched] = useState(false); + useEffect(() => { // When the accounting feature is not enabled, or if the connections data already exists, // there is no need to fetch the connections data. - if (!policy?.areConnectionsEnabled || !!policy?.connections || !policy?.id) { + if (wasConnectionsDataFetched || !policy?.areConnectionsEnabled || !!policy?.connections || !policy?.id) { return; } openPolicyAccountingPage(policy.id); - }, [policy]); + setWasConnectionsDataFetched(true); + }, [policy, wasConnectionsDataFetched]); if (!policy?.connections) { if (isOffline) { From cf2cce6c92f6629e75f381f2b50c4ac3e103a1e7 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Fri, 29 Mar 2024 10:38:59 -0700 Subject: [PATCH 09/33] doc: remove unnecessary comments --- src/pages/workspace/withPolicyConnections.tsx | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index ea562d5acca6..06431c2653ca 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -19,19 +19,6 @@ type WithPolicyConnectionsProps = WithPolicyProps; * For other policies, the connections data needs to be fetched when it's needed. */ function withPolicyConnections(WrappedComponent: ComponentType) { - /** - * Higher-order component that adds policy connections functionality to a component. - * - * @component - * @param {WithPolicyConnectionsProps} props - The props for the component. - * @returns {JSX.Element | null} The wrapped component with policy connections functionality. - */ - /** - * Higher-order component that adds policy connections functionality to a component. - * - * @param {WithPolicyConnectionsProps} props - The props for the component. - * @returns {React.ReactNode} - The wrapped component. - */ function WithPolicyConnections({policy, policyMembers, policyDraft, policyMembersDraft, route}: WithPolicyConnectionsProps) { const {isOffline} = useNetwork(); From 23702781c6a90ee8786318d43323bb90c9b2326a Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Thu, 4 Apr 2024 13:58:32 -0700 Subject: [PATCH 10/33] chore: create a context --- src/pages/workspace/withPolicyConnections.tsx | 97 +++++++++---------- 1 file changed, 47 insertions(+), 50 deletions(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 06431c2653ca..2a28832dbaf2 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -1,73 +1,70 @@ -import {useEffect, useState} from 'react'; -import type {ComponentType} from 'react'; +import {createContext, useContext, useEffect, useState} from 'react'; +import type {ComponentType, PropsWithChildren} from 'react'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import useNetwork from '@hooks/useNetwork'; import {openPolicyAccountingPage} from '@libs/actions/PolicyConnections'; -import withPolicy from './withPolicy'; +import type {Policy} from '@src/types/onyx'; import type {WithPolicyProps} from './withPolicy'; +import withPolicy from './withPolicy'; -type WithPolicyConnectionsProps = WithPolicyProps; +const PolicyWithConnectionsDataContext = createContext(null); + +function usePolicyWithConnectionsData() { + const policy = useContext(PolicyWithConnectionsDataContext); + if (!policy) { + throw new Error('usePolicyWithConnectionsData must be used within a PolicyWithConnectionsDataProvider'); + } + return policy; +} /** - * Higher-order component that fetches the connections data and populates - * the corresponding field of the policy object if the field is empty. It then passes the policy object - * to the wrapped component. - * - * Use this HOC when you need the policy object with its connections field populated. - * - * Only the active policy gets the complete policy data upon app start that includes the connections data. - * For other policies, the connections data needs to be fetched when it's needed. + * A context that provides the policy object and ensures that the `connections` data is fetched once. The context maintains a state to track + * whether the `connections` data has been fetched, ensuring the fetch request is made only once per user session. + * Note that the policy object provided by this context may not have the `connections` field populated. When the `connections` data is being + * fetched, the `connections` field is empty. + * For this reason, use the `withPolicyConnections` HOC defined in this file when consuming the policy object. It manages the rendering logic + * when the connections field is empty, ensuring that the `policy` object has its `connections` field populated when the wrapped component is + * rendered. */ -function withPolicyConnections(WrappedComponent: ComponentType) { - function WithPolicyConnections({policy, policyMembers, policyDraft, policyMembersDraft, route}: WithPolicyConnectionsProps) { - const {isOffline} = useNetwork(); +function PolicyWithConnectionsDataContextProviderWrapped({policy, children}: PropsWithChildren) { + const [hasFetchedConnectionsData, setHasFetchedConnectionsData] = useState(false); + + useEffect(() => { + if (hasFetchedConnectionsData || !policy || policy.connections) { + return; + } - // When the accounting feature is enabled, but the user hasn't connected to any accounting software, - // the connections data doesn't exist. We don't want to continually attempt to fetch non-existent data. - // This state helps us track whether a data fetch attempt has been made. - const [wasConnectionsDataFetched, setWasConnectionsDataFetched] = useState(false); + openPolicyAccountingPage(policy.id); + setHasFetchedConnectionsData(true); + }, [policy, hasFetchedConnectionsData]); - useEffect(() => { - // When the accounting feature is not enabled, or if the connections data already exists, - // there is no need to fetch the connections data. - if (wasConnectionsDataFetched || !policy?.areConnectionsEnabled || !!policy?.connections || !policy?.id) { - return; - } + return {children}; +} + +const PolicyWithConnectionsDataContextProvider = withPolicy(PolicyWithConnectionsDataContextProviderWrapped); - openPolicyAccountingPage(policy.id); - setWasConnectionsDataFetched(true); - }, [policy, wasConnectionsDataFetched]); +/** + * Higher-order component that provides the policy object which is guaranteed to have the `connections` field populated. + * If the `connections` field is absent, it either renders nothing or displays the full offline screen when the device is offline. + * Use this HOC when you need the policy object with its connections field populated. + */ +function withPolicyConnections(WrappedComponent: ComponentType<{policy: Policy}>) { + function WithPolicyConnections() { + const {isOffline} = useNetwork(); + const policy = usePolicyWithConnectionsData(); if (!policy?.connections) { if (isOffline) { - return ( - - - - ); + return {null}; } return null; } - return ( - - ); + return ; } - return withPolicy(WithPolicyConnections); + return WithPolicyConnections; } -export default withPolicyConnections; +export {PolicyWithConnectionsDataContextProvider, withPolicyConnections}; From db3252e0aca375bd9f38fe40e2af66456135395a Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Thu, 4 Apr 2024 14:04:48 -0700 Subject: [PATCH 11/33] fix: import react --- src/pages/workspace/withPolicyConnections.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 2a28832dbaf2..4e9d8776237e 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -1,4 +1,4 @@ -import {createContext, useContext, useEffect, useState} from 'react'; +import React, {createContext, useContext, useEffect, useState} from 'react'; import type {ComponentType, PropsWithChildren} from 'react'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import useNetwork from '@hooks/useNetwork'; From 1b09ba0f25e3c0d8e7a4b71d28c9dae86533ac02 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Fri, 12 Apr 2024 11:33:07 -0700 Subject: [PATCH 12/33] chore: remove the context --- src/pages/workspace/withPolicyConnections.tsx | 97 ++++++++++--------- 1 file changed, 50 insertions(+), 47 deletions(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 4e9d8776237e..06431c2653ca 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -1,70 +1,73 @@ -import React, {createContext, useContext, useEffect, useState} from 'react'; -import type {ComponentType, PropsWithChildren} from 'react'; +import {useEffect, useState} from 'react'; +import type {ComponentType} from 'react'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import useNetwork from '@hooks/useNetwork'; import {openPolicyAccountingPage} from '@libs/actions/PolicyConnections'; -import type {Policy} from '@src/types/onyx'; -import type {WithPolicyProps} from './withPolicy'; import withPolicy from './withPolicy'; +import type {WithPolicyProps} from './withPolicy'; -const PolicyWithConnectionsDataContext = createContext(null); - -function usePolicyWithConnectionsData() { - const policy = useContext(PolicyWithConnectionsDataContext); - if (!policy) { - throw new Error('usePolicyWithConnectionsData must be used within a PolicyWithConnectionsDataProvider'); - } - return policy; -} +type WithPolicyConnectionsProps = WithPolicyProps; /** - * A context that provides the policy object and ensures that the `connections` data is fetched once. The context maintains a state to track - * whether the `connections` data has been fetched, ensuring the fetch request is made only once per user session. - * Note that the policy object provided by this context may not have the `connections` field populated. When the `connections` data is being - * fetched, the `connections` field is empty. - * For this reason, use the `withPolicyConnections` HOC defined in this file when consuming the policy object. It manages the rendering logic - * when the connections field is empty, ensuring that the `policy` object has its `connections` field populated when the wrapped component is - * rendered. + * Higher-order component that fetches the connections data and populates + * the corresponding field of the policy object if the field is empty. It then passes the policy object + * to the wrapped component. + * + * Use this HOC when you need the policy object with its connections field populated. + * + * Only the active policy gets the complete policy data upon app start that includes the connections data. + * For other policies, the connections data needs to be fetched when it's needed. */ -function PolicyWithConnectionsDataContextProviderWrapped({policy, children}: PropsWithChildren) { - const [hasFetchedConnectionsData, setHasFetchedConnectionsData] = useState(false); - - useEffect(() => { - if (hasFetchedConnectionsData || !policy || policy.connections) { - return; - } - - openPolicyAccountingPage(policy.id); - setHasFetchedConnectionsData(true); - }, [policy, hasFetchedConnectionsData]); +function withPolicyConnections(WrappedComponent: ComponentType) { + function WithPolicyConnections({policy, policyMembers, policyDraft, policyMembersDraft, route}: WithPolicyConnectionsProps) { + const {isOffline} = useNetwork(); - return {children}; -} + // When the accounting feature is enabled, but the user hasn't connected to any accounting software, + // the connections data doesn't exist. We don't want to continually attempt to fetch non-existent data. + // This state helps us track whether a data fetch attempt has been made. + const [wasConnectionsDataFetched, setWasConnectionsDataFetched] = useState(false); -const PolicyWithConnectionsDataContextProvider = withPolicy(PolicyWithConnectionsDataContextProviderWrapped); + useEffect(() => { + // When the accounting feature is not enabled, or if the connections data already exists, + // there is no need to fetch the connections data. + if (wasConnectionsDataFetched || !policy?.areConnectionsEnabled || !!policy?.connections || !policy?.id) { + return; + } -/** - * Higher-order component that provides the policy object which is guaranteed to have the `connections` field populated. - * If the `connections` field is absent, it either renders nothing or displays the full offline screen when the device is offline. - * Use this HOC when you need the policy object with its connections field populated. - */ -function withPolicyConnections(WrappedComponent: ComponentType<{policy: Policy}>) { - function WithPolicyConnections() { - const {isOffline} = useNetwork(); - const policy = usePolicyWithConnectionsData(); + openPolicyAccountingPage(policy.id); + setWasConnectionsDataFetched(true); + }, [policy, wasConnectionsDataFetched]); if (!policy?.connections) { if (isOffline) { - return {null}; + return ( + + + + ); } return null; } - return ; + return ( + + ); } - return WithPolicyConnections; + return withPolicy(WithPolicyConnections); } -export {PolicyWithConnectionsDataContextProvider, withPolicyConnections}; +export default withPolicyConnections; From 32e979b3253f73813afd5a8a918f2461085bc542 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Fri, 12 Apr 2024 11:36:32 -0700 Subject: [PATCH 13/33] chore: use withPolicyConnectionsHOC --- src/pages/workspace/accounting/WorkspaceAccountingPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx index 6fada466e2bb..412d82d6375a 100644 --- a/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx +++ b/src/pages/workspace/accounting/WorkspaceAccountingPage.tsx @@ -22,8 +22,8 @@ import Navigation from '@navigation/Navigation'; import AdminPolicyAccessOrNotFoundWrapper from '@pages/workspace/AdminPolicyAccessOrNotFoundWrapper'; import FeatureEnabledAccessOrNotFoundWrapper from '@pages/workspace/FeatureEnabledAccessOrNotFoundWrapper'; import PaidPolicyAccessOrNotFoundWrapper from '@pages/workspace/PaidPolicyAccessOrNotFoundWrapper'; -import withPolicy from '@pages/workspace/withPolicy'; import type {WithPolicyProps} from '@pages/workspace/withPolicy'; +import withPolicyConnections from '@pages/workspace/withPolicyConnections'; import type {AnchorPosition} from '@styles/index'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; @@ -237,4 +237,4 @@ function WorkspaceAccountingPage({policy}: WithPolicyProps) { WorkspaceAccountingPage.displayName = 'WorkspaceAccountingPage'; -export default withPolicy(WorkspaceAccountingPage); +export default withPolicyConnections(WorkspaceAccountingPage); From 6f5d49b7d8afcedb17c2a143dc321173ecc95af9 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Mon, 15 Apr 2024 13:10:09 -0700 Subject: [PATCH 14/33] feat: add field for loading status inside policy --- src/libs/actions/PolicyConnections.ts | 39 ++++++++++++++++++++++++++- src/types/onyx/Policy.ts | 3 +++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/PolicyConnections.ts b/src/libs/actions/PolicyConnections.ts index 89eae3d20ace..5aad8bc66898 100644 --- a/src/libs/actions/PolicyConnections.ts +++ b/src/libs/actions/PolicyConnections.ts @@ -1,13 +1,50 @@ +import Onyx from 'react-native-onyx'; +import type {OnyxUpdate} from 'react-native-onyx'; import * as API from '@libs/API'; import type {OpenPolicyAccountingPageParams} from '@libs/API/parameters'; import {READ_COMMANDS} from '@libs/API/types'; +import ONYXKEYS from '@src/ONYXKEYS'; function openPolicyAccountingPage(policyID: string) { + const policyKey = `${ONYXKEYS.COLLECTION.POLICY}${policyID}` as const; + + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: policyKey, + value: { + isLoadingConnections: true, + }, + }, + ]; + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: policyKey, + value: { + isLoadingConnections: false, + }, + }, + ]; + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: policyKey, + value: { + isLoadingConnections: false, + }, + }, + ]; + const parameters: OpenPolicyAccountingPageParams = { policyID, }; - API.read(READ_COMMANDS.OPEN_POLICY_ACCOUNTING_PAGE, parameters); + API.read(READ_COMMANDS.OPEN_POLICY_ACCOUNTING_PAGE, parameters, { + optimisticData, + successData, + failureData, + }); } // More action functions will be added later diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index a21e98f4bfec..40140338ff94 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -402,6 +402,9 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< /** All the integration connections attached to the policy */ connections?: Connections; + /** Whether the connections data is being fetched */ + isLoadingConnections?: boolean; + /** Report fields attached to the policy */ fieldList?: Record; From 14c8e929da2781dc558e919fb28f968b5c2adce9 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Mon, 15 Apr 2024 13:25:51 -0700 Subject: [PATCH 15/33] feat: add new field to Policy object --- src/types/onyx/Policy.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 40140338ff94..170f0c547831 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -405,6 +405,9 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< /** Whether the connections data is being fetched */ isLoadingConnections?: boolean; + /** Whether or not the connections data has been fetched or not */ + hasConnectionsDataBeenFetched?: boolean; + /** Report fields attached to the policy */ fieldList?: Record; From 357ce2507801e49d49bb68aed7f34f1d8d645e82 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Mon, 15 Apr 2024 13:29:52 -0700 Subject: [PATCH 16/33] chore: update the fetching status field when taking the API request --- src/libs/actions/PolicyConnections.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/actions/PolicyConnections.ts b/src/libs/actions/PolicyConnections.ts index 5aad8bc66898..d581c032e134 100644 --- a/src/libs/actions/PolicyConnections.ts +++ b/src/libs/actions/PolicyConnections.ts @@ -14,6 +14,7 @@ function openPolicyAccountingPage(policyID: string) { key: policyKey, value: { isLoadingConnections: true, + hasConnectionsDataBeenFetched: false, }, }, ]; @@ -23,6 +24,7 @@ function openPolicyAccountingPage(policyID: string) { key: policyKey, value: { isLoadingConnections: false, + hasConnectionsDataBeenFetched: true, }, }, ]; @@ -32,6 +34,7 @@ function openPolicyAccountingPage(policyID: string) { key: policyKey, value: { isLoadingConnections: false, + hasConnectionsDataBeenFetched: true, }, }, ]; From d9340cf121075a8c9d9aec5a96dea292fcbf11e0 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Mon, 15 Apr 2024 13:30:49 -0700 Subject: [PATCH 17/33] chore: check the fetched and loading statuses before making the api request --- src/pages/workspace/withPolicyConnections.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 06431c2653ca..4e4dd799adeb 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -30,7 +30,7 @@ function withPolicyConnections(WrappedComponent: ComponentType { // When the accounting feature is not enabled, or if the connections data already exists, // there is no need to fetch the connections data. - if (wasConnectionsDataFetched || !policy?.areConnectionsEnabled || !!policy?.connections || !policy?.id) { + if (!policy || !policy.areConnectionsEnabled || !!policy.connections || !!policy.hasConnectionsDataBeenFetched || !!policy.isLoadingConnections || !policy.id) { return; } From 68db14d92abec38f317649af55dfc02a270ca715 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Mon, 15 Apr 2024 13:31:39 -0700 Subject: [PATCH 18/33] refactor: remove unused statuses --- src/pages/workspace/withPolicyConnections.tsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 4e4dd799adeb..01feef800042 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -1,4 +1,4 @@ -import {useEffect, useState} from 'react'; +import {useEffect} from 'react'; import type {ComponentType} from 'react'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import useNetwork from '@hooks/useNetwork'; @@ -22,11 +22,6 @@ function withPolicyConnections(WrappedComponent: ComponentType { // When the accounting feature is not enabled, or if the connections data already exists, // there is no need to fetch the connections data. @@ -35,8 +30,7 @@ function withPolicyConnections(WrappedComponent: ComponentType Date: Tue, 16 Apr 2024 22:04:45 -0700 Subject: [PATCH 19/33] feat: add a new Onyx key --- src/ONYXKEYS.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 3959f76a626f..8482bce38db0 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -220,6 +220,9 @@ const ONYXKEYS = { /** Set when we are loading payment methods */ IS_LOADING_PAYMENT_METHODS: 'isLoadingPaymentMethods', + /** Whether the connections data was attempted to be fetched in the current user session */ + HAS_CONNECTIONS_DATA_BEEN_FETCHED: 'hasConnectionsDataBeenFetched', + /** Is report data loading? */ IS_LOADING_REPORT_DATA: 'isLoadingReportData', @@ -624,6 +627,7 @@ type OnyxValuesMapping = { [ONYXKEYS.FREQUENTLY_USED_EMOJIS]: OnyxTypes.FrequentlyUsedEmoji[]; [ONYXKEYS.REIMBURSEMENT_ACCOUNT_WORKSPACE_ID]: string; [ONYXKEYS.IS_LOADING_PAYMENT_METHODS]: boolean; + [ONYXKEYS.HAS_CONNECTIONS_DATA_BEEN_FETCHED]: boolean; [ONYXKEYS.IS_LOADING_REPORT_DATA]: boolean; [ONYXKEYS.IS_TEST_TOOLS_MODAL_OPEN]: boolean; [ONYXKEYS.APP_PROFILING_IN_PROGRESS]: boolean; From b1272d445486d88a67ff703508632acbb3e693c8 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Tue, 16 Apr 2024 22:06:14 -0700 Subject: [PATCH 20/33] chore: remove fetch state from the policy object --- src/libs/actions/PolicyConnections.ts | 3 --- src/pages/workspace/withPolicyConnections.tsx | 2 +- src/types/onyx/Policy.ts | 3 --- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/libs/actions/PolicyConnections.ts b/src/libs/actions/PolicyConnections.ts index d581c032e134..5aad8bc66898 100644 --- a/src/libs/actions/PolicyConnections.ts +++ b/src/libs/actions/PolicyConnections.ts @@ -14,7 +14,6 @@ function openPolicyAccountingPage(policyID: string) { key: policyKey, value: { isLoadingConnections: true, - hasConnectionsDataBeenFetched: false, }, }, ]; @@ -24,7 +23,6 @@ function openPolicyAccountingPage(policyID: string) { key: policyKey, value: { isLoadingConnections: false, - hasConnectionsDataBeenFetched: true, }, }, ]; @@ -34,7 +32,6 @@ function openPolicyAccountingPage(policyID: string) { key: policyKey, value: { isLoadingConnections: false, - hasConnectionsDataBeenFetched: true, }, }, ]; diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 01feef800042..afd87d3e9b96 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -25,7 +25,7 @@ function withPolicyConnections(WrappedComponent: ComponentType { // When the accounting feature is not enabled, or if the connections data already exists, // there is no need to fetch the connections data. - if (!policy || !policy.areConnectionsEnabled || !!policy.connections || !!policy.hasConnectionsDataBeenFetched || !!policy.isLoadingConnections || !policy.id) { + if (!policy || !policy.areConnectionsEnabled || !!policy.connections || !!policy.isLoadingConnections || !policy.id) { return; } diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index c84d8d8b6a95..339fd5e59cda 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -407,9 +407,6 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< /** Whether the connections data is being fetched */ isLoadingConnections?: boolean; - /** Whether or not the connections data has been fetched or not */ - hasConnectionsDataBeenFetched?: boolean; - /** Report fields attached to the policy */ fieldList?: Record; From d29646d5272ac36de4837e1843d49d874f33cea8 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Tue, 16 Apr 2024 22:07:51 -0700 Subject: [PATCH 21/33] chore: remove unused field from the policy object --- src/libs/actions/PolicyConnections.ts | 12 +++--------- src/types/onyx/Policy.ts | 3 --- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/src/libs/actions/PolicyConnections.ts b/src/libs/actions/PolicyConnections.ts index 5aad8bc66898..d18c7b43a452 100644 --- a/src/libs/actions/PolicyConnections.ts +++ b/src/libs/actions/PolicyConnections.ts @@ -12,27 +12,21 @@ function openPolicyAccountingPage(policyID: string) { { onyxMethod: Onyx.METHOD.MERGE, key: policyKey, - value: { - isLoadingConnections: true, - }, + value: {}, }, ]; const successData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: policyKey, - value: { - isLoadingConnections: false, - }, + value: {}, }, ]; const failureData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: policyKey, - value: { - isLoadingConnections: false, - }, + value: {}, }, ]; diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts index 339fd5e59cda..3d85a6a2a526 100644 --- a/src/types/onyx/Policy.ts +++ b/src/types/onyx/Policy.ts @@ -404,9 +404,6 @@ type Policy = OnyxCommon.OnyxValueWithOfflineFeedback< /** All the integration connections attached to the policy */ connections?: Connections; - /** Whether the connections data is being fetched */ - isLoadingConnections?: boolean; - /** Report fields attached to the policy */ fieldList?: Record; From 124f534a18223ab28ea1205a15d83f995b0ec1b1 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Tue, 16 Apr 2024 22:08:20 -0700 Subject: [PATCH 22/33] fix: delete non-existing variable --- src/pages/workspace/withPolicyConnections.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index afd87d3e9b96..80bf23eb7f8e 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -25,7 +25,7 @@ function withPolicyConnections(WrappedComponent: ComponentType { // When the accounting feature is not enabled, or if the connections data already exists, // there is no need to fetch the connections data. - if (!policy || !policy.areConnectionsEnabled || !!policy.connections || !!policy.isLoadingConnections || !policy.id) { + if (!policy || !policy.areConnectionsEnabled || !!policy.connections || !policy.id) { return; } From c1e0cac961bfa37c383fd1ed14031808cb603731 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Tue, 16 Apr 2024 22:14:41 -0700 Subject: [PATCH 23/33] fix: change the new key to the collections --- src/ONYXKEYS.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 8482bce38db0..ebf78b57efd3 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -220,9 +220,6 @@ const ONYXKEYS = { /** Set when we are loading payment methods */ IS_LOADING_PAYMENT_METHODS: 'isLoadingPaymentMethods', - /** Whether the connections data was attempted to be fetched in the current user session */ - HAS_CONNECTIONS_DATA_BEEN_FETCHED: 'hasConnectionsDataBeenFetched', - /** Is report data loading? */ IS_LOADING_REPORT_DATA: 'isLoadingReportData', @@ -323,6 +320,8 @@ const ONYXKEYS = { POLICY_RECENTLY_USED_CATEGORIES: 'policyRecentlyUsedCategories_', POLICY_TAGS: 'policyTags_', POLICY_RECENTLY_USED_TAGS: 'nvp_recentlyUsedTags_', + /** Whether the connections data for the policy was attempted to be fetched in the current user session */ + POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED: 'policyHasConnectionsDataBeenFetched', OLD_POLICY_RECENTLY_USED_TAGS: 'policyRecentlyUsedTags_', WORKSPACE_INVITE_MEMBERS_DRAFT: 'workspaceInviteMembersDraft_', WORKSPACE_INVITE_MESSAGE_DRAFT: 'workspaceInviteMessageDraft_', @@ -532,6 +531,7 @@ type OnyxCollectionValuesMapping = { [ONYXKEYS.COLLECTION.POLICY_MEMBERS]: OnyxTypes.PolicyMembers; [ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS]: OnyxTypes.PolicyMember; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES]: OnyxTypes.RecentlyUsedCategories; + [ONYXKEYS.COLLECTION.POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED]: boolean; [ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST]: OnyxTypes.PolicyMembers; [ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT]: OnyxTypes.InvitedEmailsToAccountIDs; [ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MESSAGE_DRAFT]: string; @@ -627,7 +627,6 @@ type OnyxValuesMapping = { [ONYXKEYS.FREQUENTLY_USED_EMOJIS]: OnyxTypes.FrequentlyUsedEmoji[]; [ONYXKEYS.REIMBURSEMENT_ACCOUNT_WORKSPACE_ID]: string; [ONYXKEYS.IS_LOADING_PAYMENT_METHODS]: boolean; - [ONYXKEYS.HAS_CONNECTIONS_DATA_BEEN_FETCHED]: boolean; [ONYXKEYS.IS_LOADING_REPORT_DATA]: boolean; [ONYXKEYS.IS_TEST_TOOLS_MODAL_OPEN]: boolean; [ONYXKEYS.APP_PROFILING_IN_PROGRESS]: boolean; From 515833e49d7367e008d4835d515c953e02505129 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Tue, 16 Apr 2024 22:15:28 -0700 Subject: [PATCH 24/33] feat: use the fetched state --- src/pages/workspace/withPolicyConnections.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 80bf23eb7f8e..36e16f1940fb 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -1,8 +1,10 @@ import {useEffect} from 'react'; import type {ComponentType} from 'react'; +import {useOnyx} from 'react-native-onyx'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; import useNetwork from '@hooks/useNetwork'; import {openPolicyAccountingPage} from '@libs/actions/PolicyConnections'; +import ONYXKEYS from '@src/ONYXKEYS'; import withPolicy from './withPolicy'; import type {WithPolicyProps} from './withPolicy'; @@ -21,16 +23,17 @@ type WithPolicyConnectionsProps = WithPolicyProps; function withPolicyConnections(WrappedComponent: ComponentType) { function WithPolicyConnections({policy, policyMembers, policyDraft, policyMembersDraft, route}: WithPolicyConnectionsProps) { const {isOffline} = useNetwork(); + const hasConnectionsDataBeenFetched = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED}${policy?.id ?? ''}` as const, {initWithStoredValues: false}); useEffect(() => { // When the accounting feature is not enabled, or if the connections data already exists, // there is no need to fetch the connections data. - if (!policy || !policy.areConnectionsEnabled || !!policy.connections || !policy.id) { + if (!policy || !policy.areConnectionsEnabled || hasConnectionsDataBeenFetched || !!policy.connections) { return; } openPolicyAccountingPage(policy.id); - }, [policy]); + }, [hasConnectionsDataBeenFetched, policy]); if (!policy?.connections) { if (isOffline) { From f21307ae8a2ece1702e3bd95207ec9751f55a705 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Tue, 16 Apr 2024 22:17:45 -0700 Subject: [PATCH 25/33] chore: update the fetched state --- src/libs/actions/PolicyConnections.ts | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/libs/actions/PolicyConnections.ts b/src/libs/actions/PolicyConnections.ts index d18c7b43a452..7ccf9f2506bd 100644 --- a/src/libs/actions/PolicyConnections.ts +++ b/src/libs/actions/PolicyConnections.ts @@ -6,27 +6,20 @@ import {READ_COMMANDS} from '@libs/API/types'; import ONYXKEYS from '@src/ONYXKEYS'; function openPolicyAccountingPage(policyID: string) { - const policyKey = `${ONYXKEYS.COLLECTION.POLICY}${policyID}` as const; + const hasConnectionsDataBeenFetchedKey = `${ONYXKEYS.COLLECTION.POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED}${policyID}` as const; const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: policyKey, - value: {}, + key: hasConnectionsDataBeenFetchedKey, + value: false, }, ]; - const successData: OnyxUpdate[] = [ + const finallyData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, - key: policyKey, - value: {}, - }, - ]; - const failureData: OnyxUpdate[] = [ - { - onyxMethod: Onyx.METHOD.MERGE, - key: policyKey, - value: {}, + key: hasConnectionsDataBeenFetchedKey, + value: true, }, ]; @@ -36,8 +29,7 @@ function openPolicyAccountingPage(policyID: string) { API.read(READ_COMMANDS.OPEN_POLICY_ACCOUNTING_PAGE, parameters, { optimisticData, - successData, - failureData, + finallyData, }); } From a44ab1c619d18aa7efec783589af97b2c14015ed Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Tue, 16 Apr 2024 22:22:16 -0700 Subject: [PATCH 26/33] chore: display loading indicator while data is being fetched --- src/pages/workspace/withPolicyConnections.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 36e16f1940fb..bbc30b2c72b2 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -2,6 +2,7 @@ import {useEffect} from 'react'; import type {ComponentType} from 'react'; import {useOnyx} from 'react-native-onyx'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; +import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import useNetwork from '@hooks/useNetwork'; import {openPolicyAccountingPage} from '@libs/actions/PolicyConnections'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -35,6 +36,10 @@ function withPolicyConnections(WrappedComponent: ComponentType; + } + if (!policy?.connections) { if (isOffline) { return ( @@ -50,7 +55,7 @@ function withPolicyConnections(WrappedComponent: ComponentType Date: Tue, 16 Apr 2024 22:24:24 -0700 Subject: [PATCH 27/33] chore: ensure to display offline screen --- src/pages/workspace/withPolicyConnections.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index bbc30b2c72b2..493e419d8270 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -37,10 +37,6 @@ function withPolicyConnections(WrappedComponent: ComponentType; - } - - if (!policy?.connections) { if (isOffline) { return ( @@ -55,6 +51,10 @@ function withPolicyConnections(WrappedComponent: ComponentType; + } + + if (!policy?.connections) { throw new Error('Policy connections data should be fetched before rendering the component'); } From f25a3e55f28a3765eaae86f6f899c5bf3f028d28 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Tue, 16 Apr 2024 22:33:15 -0700 Subject: [PATCH 28/33] fix: getting the actual value and status from useOnyx --- src/pages/workspace/withPolicyConnections.tsx | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 493e419d8270..d9839da13dd8 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -1,4 +1,4 @@ -import {useEffect} from 'react'; +import React, {useEffect} from 'react'; import type {ComponentType} from 'react'; import {useOnyx} from 'react-native-onyx'; import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView'; @@ -24,19 +24,21 @@ type WithPolicyConnectionsProps = WithPolicyProps; function withPolicyConnections(WrappedComponent: ComponentType) { function WithPolicyConnections({policy, policyMembers, policyDraft, policyMembersDraft, route}: WithPolicyConnectionsProps) { const {isOffline} = useNetwork(); - const hasConnectionsDataBeenFetched = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED}${policy?.id ?? ''}` as const, {initWithStoredValues: false}); + const [hasConnectionsDataBeenFetched, {status}] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED}${policy?.id ?? ''}` as const, { + initWithStoredValues: false, + }); useEffect(() => { // When the accounting feature is not enabled, or if the connections data already exists, // there is no need to fetch the connections data. - if (!policy || !policy.areConnectionsEnabled || hasConnectionsDataBeenFetched || !!policy.connections) { + if (!policy || !policy.areConnectionsEnabled || !!hasConnectionsDataBeenFetched || !!policy.connections) { return; } openPolicyAccountingPage(policy.id); }, [hasConnectionsDataBeenFetched, policy]); - if (!hasConnectionsDataBeenFetched) { + if (status === 'loading' || !hasConnectionsDataBeenFetched) { if (isOffline) { return ( @@ -54,10 +56,6 @@ function withPolicyConnections(WrappedComponent: ComponentType; } - if (!policy?.connections) { - throw new Error('Policy connections data should be fetched before rendering the component'); - } - return ( Date: Tue, 16 Apr 2024 22:37:43 -0700 Subject: [PATCH 29/33] fix: update the prop list --- src/pages/workspace/withPolicyConnections.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index d9839da13dd8..60574563be3a 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -22,7 +22,7 @@ type WithPolicyConnectionsProps = WithPolicyProps; * For other policies, the connections data needs to be fetched when it's needed. */ function withPolicyConnections(WrappedComponent: ComponentType) { - function WithPolicyConnections({policy, policyMembers, policyDraft, policyMembersDraft, route}: WithPolicyConnectionsProps) { + function WithPolicyConnections({policy, policyDraft, route}: WithPolicyConnectionsProps) { const {isOffline} = useNetwork(); const [hasConnectionsDataBeenFetched, {status}] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED}${policy?.id ?? ''}` as const, { initWithStoredValues: false, @@ -44,9 +44,7 @@ function withPolicyConnections(WrappedComponent: ComponentType @@ -59,9 +57,7 @@ function withPolicyConnections(WrappedComponent: ComponentType ); From c4593e75d4635e36a2e491c03a536cff1568dc6a Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Wed, 17 Apr 2024 08:59:47 -0700 Subject: [PATCH 30/33] add missing underscore at the end of the Onyx collection key name Co-authored-by: Luthfi --- src/ONYXKEYS.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index edf0296eb9c8..c76dd80974c0 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -319,7 +319,7 @@ const ONYXKEYS = { POLICY_TAGS: 'policyTags_', POLICY_RECENTLY_USED_TAGS: 'nvp_recentlyUsedTags_', /** Whether the connections data for the policy was attempted to be fetched in the current user session */ - POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED: 'policyHasConnectionsDataBeenFetched', + POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED: 'policyHasConnectionsDataBeenFetched_', OLD_POLICY_RECENTLY_USED_TAGS: 'policyRecentlyUsedTags_', WORKSPACE_INVITE_MEMBERS_DRAFT: 'workspaceInviteMembersDraft_', WORKSPACE_INVITE_MESSAGE_DRAFT: 'workspaceInviteMessageDraft_', From 4804fd19f34f2f9c3a89c82b4d6e296d4a1b05ac Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Wed, 17 Apr 2024 09:52:05 -0700 Subject: [PATCH 31/33] fix: default policy id to 0 --- src/pages/workspace/withPolicyConnections.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index 60574563be3a..dc678df62cf7 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -24,7 +24,7 @@ type WithPolicyConnectionsProps = WithPolicyProps; function withPolicyConnections(WrappedComponent: ComponentType) { function WithPolicyConnections({policy, policyDraft, route}: WithPolicyConnectionsProps) { const {isOffline} = useNetwork(); - const [hasConnectionsDataBeenFetched, {status}] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED}${policy?.id ?? ''}` as const, { + const [hasConnectionsDataBeenFetched, {status}] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED}${policy?.id ?? '0'}` as const, { initWithStoredValues: false, }); From e19060b4968066e581ec5e825d59bf4c7d9b707a Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Wed, 17 Apr 2024 09:57:19 -0700 Subject: [PATCH 32/33] doc: specify the reason why the loading state can't be inside the policy object --- src/ONYXKEYS.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index c76dd80974c0..e51d760604e8 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -318,7 +318,10 @@ const ONYXKEYS = { POLICY_RECENTLY_USED_CATEGORIES: 'policyRecentlyUsedCategories_', POLICY_TAGS: 'policyTags_', POLICY_RECENTLY_USED_TAGS: 'nvp_recentlyUsedTags_', - /** Whether the connections data for the policy was attempted to be fetched in the current user session */ + // Whether the policy's connection data was attempted to be fetched in + // the current user session. As this state only exists client-side, it + // should not be included as part of the policy object. The policy + // object should mirror the data as it's stored in the database. POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED: 'policyHasConnectionsDataBeenFetched_', OLD_POLICY_RECENTLY_USED_TAGS: 'policyRecentlyUsedTags_', WORKSPACE_INVITE_MEMBERS_DRAFT: 'workspaceInviteMembersDraft_', From a084e5295dea50b4d14fb560c2ad5e58e83cb1f0 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Wed, 17 Apr 2024 09:58:25 -0700 Subject: [PATCH 33/33] fix: remove as const statement --- src/pages/workspace/withPolicyConnections.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/withPolicyConnections.tsx b/src/pages/workspace/withPolicyConnections.tsx index dc678df62cf7..d540e7e5a681 100644 --- a/src/pages/workspace/withPolicyConnections.tsx +++ b/src/pages/workspace/withPolicyConnections.tsx @@ -24,7 +24,7 @@ type WithPolicyConnectionsProps = WithPolicyProps; function withPolicyConnections(WrappedComponent: ComponentType) { function WithPolicyConnections({policy, policyDraft, route}: WithPolicyConnectionsProps) { const {isOffline} = useNetwork(); - const [hasConnectionsDataBeenFetched, {status}] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED}${policy?.id ?? '0'}` as const, { + const [hasConnectionsDataBeenFetched, {status}] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_HAS_CONNECTIONS_DATA_BEEN_FETCHED}${policy?.id ?? '0'}`, { initWithStoredValues: false, });