diff --git a/src/containers/pages/IRS/plans/hooks.tsx b/src/containers/pages/IRS/plans/hooks.tsx new file mode 100644 index 0000000000..9377762fc2 --- /dev/null +++ b/src/containers/pages/IRS/plans/hooks.tsx @@ -0,0 +1,53 @@ +import { SupersetFormData } from '@onaio/superset-connector/dist/types'; +import React, { useEffect, useState } from 'react'; +import { ActionCreator } from 'redux'; +import { SUPERSET_IRS_REPORTING_PLANS_SLICE } from '../../../../configs/env'; +import { displayError } from '../../../../helpers/errors'; +import supersetFetch from '../../../../services/superset'; + +interface AsyncSupersetPlans { + superset: typeof supersetFetch; + data: TData[]; + fetchPlans: ActionCreator; + supersetSlice: string; + supersetOptions: SupersetFormData | null; +} + +export const useAsyncSupersetPlans = ({ + superset = supersetFetch, + data = [], + fetchPlans, + supersetSlice = SUPERSET_IRS_REPORTING_PLANS_SLICE, + supersetOptions = null, +}: AsyncSupersetPlans) => { + const [loading, setLoading] = useState(false); + const mounted = React.useRef(false); + + /** async function to load the data */ + async function loadData() { + try { + setLoading(data.length === 0); // only set loading when there are no plans + const asyncOperation = supersetOptions + ? superset(supersetSlice, supersetOptions) + : superset(supersetSlice); + + await asyncOperation.then((result: TData[]) => fetchPlans(result)); + } catch (e) { + throw e; + } finally { + if (mounted) { + setLoading(false); + } + } + } + + useEffect(() => { + mounted.current = true; + loadData().catch(error => displayError(error)); + return () => { + mounted.current = false; + }; + }, []); + + return loading; +}; diff --git a/src/containers/pages/IRS/plans/index.tsx b/src/containers/pages/IRS/plans/index.tsx index 286db52903..96a56fac61 100644 --- a/src/containers/pages/IRS/plans/index.tsx +++ b/src/containers/pages/IRS/plans/index.tsx @@ -1,6 +1,6 @@ import ListView from '@onaio/list-view'; import reducerRegistry from '@onaio/redux-reducer-registry'; -import React, { useEffect, useState } from 'react'; +import React from 'react'; import { Helmet } from 'react-helmet'; import { connect } from 'react-redux'; import { Link } from 'react-router-dom'; @@ -14,13 +14,13 @@ import { END_DATE, HOME, IRS_PLANS, + NO_PLANS_LOADED_MESSAGE, START_DATE, STATUS_HEADER, TITLE, } from '../../../../configs/lang'; import { planStatusDisplay } from '../../../../configs/settings'; import { HOME_URL, REPORT_IRS_PLAN_URL } from '../../../../constants'; -import { displayError } from '../../../../helpers/errors'; import supersetFetch from '../../../../services/superset'; import IRSPlansReducer, { fetchIRSPlans, @@ -28,6 +28,7 @@ import IRSPlansReducer, { IRSPlan, reducerName as IRSPlansReducerName, } from '../../../../store/ducks/generic/plans'; +import { useAsyncSupersetPlans } from './hooks'; /** register the plan definitions reducer */ reducerRegistry.register(IRSPlansReducerName, IRSPlansReducer); @@ -42,7 +43,7 @@ interface PlanListProps { /** Simple component that loads the new plan form and allows you to create a new plan */ const IRSPlansList = (props: PlanListProps) => { const { fetchPlans, plans, service } = props; - const [loading, setLoading] = useState(true); + // const [loading, setLoading] = useState(true); const pageTitle: string = IRS_PLANS; @@ -59,27 +60,15 @@ const IRSPlansList = (props: PlanListProps) => { ], }; - /** async function to load the data */ - async function loadData() { - try { - setLoading(plans.length < 1); // only set loading when there are no plans - await service(SUPERSET_IRS_REPORTING_PLANS_SLICE).then((result: IRSPlan[]) => - fetchPlans(result) - ); - } catch (e) { - // do something with the error? - } finally { - setLoading(false); - } - } - - useEffect(() => { - loadData().catch(error => displayError(error)); - }, []); - - if (loading === true) { - return ; - } + const asyncSupersetOptions = { + data: plans, + fetchPlans, + superset: service, + supersetOptions: null, + supersetSlice: SUPERSET_IRS_REPORTING_PLANS_SLICE, + }; + + const loading = useAsyncSupersetPlans(asyncSupersetOptions); const listViewProps = { data: plans.map(planObj => { @@ -108,11 +97,15 @@ const IRSPlansList = (props: PlanListProps) => {

{pageTitle}

- - - - - + {loading ? ( + + ) : ( + + + {plans.length > 0 ? :

{NO_PLANS_LOADED_MESSAGE}

} + +
+ )} ); }; diff --git a/src/containers/pages/IRS/plans/tests/__snapshots__/index.test.tsx.snap b/src/containers/pages/IRS/plans/tests/__snapshots__/index.test.tsx.snap index 8cb81b3c9c..991c12ed10 100644 --- a/src/containers/pages/IRS/plans/tests/__snapshots__/index.test.tsx.snap +++ b/src/containers/pages/IRS/plans/tests/__snapshots__/index.test.tsx.snap @@ -1,5 +1,9 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`components/IRS Reports/IRSPlansList Does not show loader when store has data: First table rows 1`] = `"IRS 2019-09-05 TEST"`; + +exports[`components/IRS Reports/IRSPlansList Works with store: First table row 1`] = `"IRS 2019-09-05 TEST"`; + exports[`components/IRS Reports/IRSPlansList renders plan definition list correctly: breadcrumbs 1`] = ` Array [
  • { }); it('renders plan definition list correctly', () => { - fetch.mockResponseOnce(JSON.stringify({})); const props = { plans: fixtures.plans as IRSPlan[], }; @@ -44,4 +48,46 @@ describe('components/IRS Reports/IRSPlansList', () => { expect(toJson(wrapper.find('tbody tr td'))).toMatchSnapshot('table rows'); wrapper.unmount(); }); + + it('Works with store', async () => { + const supersetMock: any = jest.fn(async () => fixtures.plans); + const wrapper = mount( + + + + + + ); + expect(wrapper.find('Ripple').length).toEqual(1); + + await new Promise(resolve => setImmediate(resolve)); + wrapper.update(); + expect( + wrapper + .find('tbody tr td') + .at(0) + .text() + ).toMatchSnapshot('First table row'); + wrapper.unmount(); + }); + + it('Does not show loader when store has data', async () => { + store.dispatch(fetchIRSPlans(fixtures.plans as IRSPlan[])); + const supersetMock: any = jest.fn(async () => fixtures.plans); + const wrapper = mount( + + + + + + ); + expect(wrapper.find('Ripple').length).toEqual(0); + expect( + wrapper + .find('tbody tr td') + .at(0) + .text() + ).toMatchSnapshot('First table rows'); + wrapper.unmount(); + }); });