-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
React async practitioner view #822
Closed
Closed
Changes from 12 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
237931c
Revert setLoading usage in Irs/assignments
peterMuriuki c33e1cb
Call setstaters only when component is mounted
peterMuriuki 3d89a0c
Install react-async
peterMuriuki 185e937
Use react-async in practionerListView
peterMuriuki 2a6d74d
Remove surplus IfRejected branch
peterMuriuki ab9ad20
Add AsyncRenderer component
peterMuriuki 7ca9feb
Export fetch organizations action interface
peterMuriuki 6318230
Add AsyncRenderer to Organizaiton list view
peterMuriuki 489d2b1
Test Asyncrenderer component
peterMuriuki f55b022
Refactor grammar errors in practitioner list view
peterMuriuki a6465de
Test AsyncGetPractitioners
peterMuriuki 93d211f
Refactor tests for practitionerListView
peterMuriuki da91fd4
Add tests for asyncGetOrganizations
peterMuriuki 835980b
Refactor test in organizationListView
peterMuriuki 2359f82
Rename props interface
peterMuriuki 7154913
Add and test asyncGetPlans
peterMuriuki 7338ee7
Add asyncGetPlans to /assign page
peterMuriuki c957cf0
fix asyncGet Organizaiton tests
peterMuriuki 0081ccd
setLoading to false only when component is mounted
peterMuriuki 695ddc5
Remove duplicate table in OrganizationList
peterMuriuki 871af57
Refactor IRS monitor page container as #806
peterMuriuki File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import React, { PropsWithChildren } from 'react'; | ||
import { AsyncState, IfFulfilled, IfPending, PromiseFn, useAsync } from 'react-async'; | ||
import { PLEASE_PROVIDE_CUSTOM_COMPONENT_TO_RENDER } from '../../constants'; | ||
import Loading from '../page/Loading'; | ||
|
||
/** props for AsyncRender component */ | ||
export interface AsyncRendererProps<TData, TPromiseFunctionProps> { | ||
data: TData[] /** interface describing data to be consumed by render component */; | ||
promiseFn: PromiseFn<TData[]> /** react-async-type asynchronous function */; | ||
promiseFnProps: TPromiseFunctionProps /** options to be passed to promiseFn */; | ||
ifLoadingRender: ( | ||
state: AsyncState<TData[]> | ||
) => React.ReactNode /** renderProp invoked while promise returned by promiseFn is pending */; | ||
ifFulfilledRender: ( | ||
state: AsyncState<TData[]> | ||
) => React.ReactNode /** renderProp invoked after promise returned by promiseFn is fulfilled */; | ||
} | ||
|
||
// tslint:disable-next-line: no-empty-destructuring | ||
const defaultPromiseFn = async ({}) => []; | ||
|
||
/** default props for AsyncRenderer */ | ||
const defaultAsyncRenderProps: AsyncRendererProps<any, any> = { | ||
data: [], | ||
ifFulfilledRender: () => <div>{PLEASE_PROVIDE_CUSTOM_COMPONENT_TO_RENDER}</div>, | ||
ifLoadingRender: () => <Loading />, | ||
promiseFn: defaultPromiseFn, | ||
promiseFnProps: {}, | ||
}; | ||
|
||
/** helps Dry out trivial react-async rendering */ | ||
export const AsyncRenderer = <TData, TPromiseFunctionProps>({ | ||
data, | ||
ifFulfilledRender, | ||
ifLoadingRender, | ||
promiseFn, | ||
promiseFnProps, | ||
}: PropsWithChildren< | ||
AsyncRendererProps<TData, TPromiseFunctionProps> | ||
> = defaultAsyncRenderProps) => { | ||
const loadPractitionersState = useAsync<TData[]>(promiseFn, promiseFnProps); | ||
|
||
React.useEffect(() => { | ||
if (data.length > 0) { | ||
loadPractitionersState.setData(data); | ||
} | ||
}, []); | ||
|
||
return ( | ||
<> | ||
<IfPending state={loadPractitionersState}> | ||
{ifLoadingRender(loadPractitionersState)} | ||
</IfPending> | ||
<IfFulfilled state={loadPractitionersState}> | ||
{ifFulfilledRender(loadPractitionersState)} | ||
</IfFulfilled> | ||
</> | ||
); | ||
}; |
9 changes: 9 additions & 0 deletions
9
src/components/AsyncRenderer/tests/__snapshots__/index.test.tsx.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`src/components/AsyncRenderer AsyncRenderer loads correctly: after Promise resolution 1`] = `"Promise Resolved with 200);"`; | ||
|
||
exports[`src/components/AsyncRenderer AsyncRenderer loads correctly: before promise resolution 1`] = `"Promise Pending);"`; | ||
|
||
exports[`src/components/AsyncRenderer Does not load when there is pre-populated data: after Promise resolution 1`] = `"Promise Resolved with 200);"`; | ||
|
||
exports[`src/components/AsyncRenderer Does not load when there is pre-populated data: before promise resolution 1`] = `"Promise Resolved with 100);"`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { mount, shallow } from 'enzyme'; | ||
import React from 'react'; | ||
import { AsyncState, PromiseFn } from 'react-async'; | ||
import { AsyncRenderer } from '..'; | ||
|
||
// tslint:disable-next-line: no-var-requires | ||
const fetch = require('jest-fetch-mock'); | ||
|
||
/** hasPrePopulatedData is meant to represent when there is some data | ||
* that the component can readily consume as a fetch request to get more data is | ||
* pending. | ||
*/ | ||
interface TestComponentProps { | ||
hasPrePopulatedData: boolean; | ||
} | ||
const defaultTestComponentProps = { | ||
hasPrePopulatedData: false, | ||
}; | ||
const TestComponent = (props: TestComponentProps = defaultTestComponentProps) => { | ||
interface PromiseFnProps { | ||
otherNumber: number; | ||
} | ||
const samplePromiseFn: PromiseFn<number[]> = async ( | ||
{ otherNumber }, | ||
{ signal }: AbortController | ||
) => | ||
fetch('https://someUrl.org', signal) | ||
.then(() => [otherNumber]) | ||
.catch(() => [400]); | ||
|
||
const asyncRendererProps = { | ||
data: props.hasPrePopulatedData ? [100] : [], | ||
ifFulfilledRender: ({ data }: AsyncState<number[]>) => <p>Promise Resolved with {data}</p>, | ||
ifLoadingRender: () => <p>Promise Pending</p>, | ||
promiseFn: samplePromiseFn, | ||
promiseFnProps: { otherNumber: 200 }, | ||
}; | ||
|
||
return ( | ||
<div> | ||
<AsyncRenderer<number, PromiseFnProps> {...asyncRendererProps} /> | ||
); | ||
</div> | ||
); | ||
}; | ||
|
||
describe('src/components/AsyncRenderer', () => { | ||
it('renders without crashing', () => { | ||
// its a type thing too | ||
interface PromiseFnProps { | ||
otherNumber: number; | ||
} | ||
const samplePromiseFn: PromiseFn<number[]> = async ({ otherNumber }) => { | ||
return [otherNumber]; | ||
}; | ||
|
||
const props = { | ||
data: [1], | ||
ifFulfilledRender: () => <p>Promise Resolved</p>, | ||
ifLoadingRender: () => <p>Promise Pending</p>, | ||
promiseFn: samplePromiseFn, | ||
promiseFnProps: { otherNumber: 5 }, | ||
}; | ||
|
||
shallow(<AsyncRenderer<number, PromiseFnProps> {...props} />); | ||
}); | ||
|
||
it('AsyncRenderer loads correctly', async () => { | ||
fetch.once(JSON.stringify([200])); | ||
const wrapper = mount(<TestComponent hasPrePopulatedData={false} />); | ||
// before fetch is resolved; we should see content rendered by the ifPending render prop | ||
expect(wrapper.text()).toMatchSnapshot('before promise resolution'); | ||
expect(wrapper.text().includes('Pending')).toEqual(true); | ||
expect(wrapper.text().includes('Resolved')).toEqual(false); | ||
await new Promise(resolve => setImmediate(resolve)); | ||
// upon flushing pending promises; we should now see content rendered by the ifFulfilled render prop | ||
expect(wrapper.text()).toMatchSnapshot('after Promise resolution'); | ||
expect(wrapper.text().includes('Pending')).toEqual(false); | ||
expect(wrapper.text().includes('Resolved')).toEqual(true); | ||
}); | ||
|
||
it('Does not load when there is pre-populated data', async () => { | ||
// this simulates a condition such as when there is already data in the store | ||
fetch.once(JSON.stringify([200])); | ||
const wrapper = mount(<TestComponent hasPrePopulatedData={true} />); | ||
// before the promise is resolved we render the initial data which is a [100] | ||
expect(wrapper.text()).toMatchSnapshot('before promise resolution'); | ||
await new Promise(resolve => setImmediate(resolve)); | ||
// after promise resolution we know render the fetched data which is [200] | ||
expect(wrapper.text()).toMatchSnapshot('after Promise resolution'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to do this in the
AsyncRenderer
component?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would then make the component re-suable only when we want to show a table. Do you think its a reasonable constraint, coz anyway, I'd be happy to refactor the
AsyncRenderer
. @moshthepittThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a fair point @p-netm - However how do we make it such that we dont end up rewriting the same code in different components that want to display a list of items?