Skip to content
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

Ntd/add students page and reducer #854

Merged
merged 80 commits into from
Jun 5, 2020
Merged
Show file tree
Hide file tree
Changes from 79 commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
3691fe3
Add env variable to enable MDA Point plans
May 7, 2020
5d5caed
Add Students list page to Admin dropdown
May 7, 2020
98847f9
Add Student page display strings
May 7, 2020
c3b41f8
Add path for Student CSV upload
May 7, 2020
262cd24
Init Student List View Page container
May 7, 2020
ac3549f
Add route for Student List View components
May 7, 2020
afaf7c7
Add student reducer
May 7, 2020
0769292
Add student reducer
May 7, 2020
f0ccfd4
Add files reducer
May 7, 2020
8c2f8ac
Add list-view package
kahummer May 11, 2020
1f2df2d
Update types
kahummer May 12, 2020
a20af7f
Connect component to store
kahummer May 12, 2020
6a89b52
Update lock file
kahummer May 12, 2020
3f2186b
Add api mock
kahummer May 12, 2020
9afa5b3
Add download attribute
kahummer May 12, 2020
b6a6fd7
Add jurisdictionselect on export
kahummer May 13, 2020
a8a7217
Build table data
kahummer May 15, 2020
0ff6b7c
Cleanup
kahummer May 15, 2020
298dac0
Add export tests
kahummer May 15, 2020
bf405fb
Add file tests fixtures
kahummer May 17, 2020
4be1116
Add file ducks test
kahummer May 17, 2020
e9af339
Update import
kahummer May 17, 2020
0b42d61
Add studentexportform tests
kahummer May 17, 2020
d6130bf
Setup studentlistview tests
kahummer May 17, 2020
d475a3b
Cleanup selectlistview
kahummer May 18, 2020
bf34692
Add tests for studentlistview
kahummer May 18, 2020
6d611cf
Update snapshot
kahummer May 18, 2020
2601634
Rename students to clients
kahummer May 19, 2020
e986a95
Delete unnecessary files
kahummer May 19, 2020
c3ff3ab
Update snapshot
kahummer May 19, 2020
4318063
Update snapshot
kahummer May 19, 2020
d8c48aa
upload working
kahummer May 21, 2020
48f18cd
Add csv download functionality
ciremusyoka May 21, 2020
3480f64
Update lang file
kahummer May 21, 2020
3fb1cd2
Move api calls to service hooks
kahummer May 21, 2020
1db1300
Working upload and listview
kahummer May 21, 2020
8bc46c8
Hook up export form with service
kahummer May 21, 2020
e2fd723
Add default params for easy mocking
kahummer May 22, 2020
2ff7fd2
Update fixtures
kahummer May 22, 2020
36eb9c4
Add Uploadstatus tests
kahummer May 22, 2020
4908196
Add servicehooks tests
kahummer May 22, 2020
686e74a
Update snaphsot
kahummer May 22, 2020
f882094
Get location id from jurisdiction select
kahummer May 22, 2020
f2f5c19
Update snapshots
kahummer May 22, 2020
5ea8b02
Update snapshot
kahummer May 22, 2020
28b7370
Cleanup
kahummer May 26, 2020
5576cc0
ExportForm and App cleanup
kahummer May 27, 2020
4cf4539
Drill down to location level
kahummer May 28, 2020
f20135d
Cleanup
kahummer May 28, 2020
8144cf5
Code cleanup
kahummer May 29, 2020
aabff56
Fix hierarchy label
kahummer May 29, 2020
542cf3f
Update snapshot
kahummer May 29, 2020
e2c120f
Add jurisdictionselect button
kahummer May 29, 2020
07b631f
ExportForm Cleanup
kahummer Jun 2, 2020
69e416e
Render client title configurably
kahummer Jun 2, 2020
d1b8676
Export and clientlistview cleanup
kahummer Jun 2, 2020
b645b57
Code cleanup
kahummer Jun 2, 2020
522e73c
Update tests and cleanup
kahummer Jun 2, 2020
47960b3
Update snapshot
kahummer Jun 2, 2020
55b68a7
Add LocationSelect component
kahummer May 29, 2020
018e3a5
Use reactstrap form
kahummer May 29, 2020
a53365e
Add simple org select
moshthepitt May 29, 2020
3bd9f60
Partial cleanup
kahummer May 29, 2020
4926643
Update Locationselect tests
kahummer Jun 2, 2020
5bb0177
Cleanup and test updates
kahummer Jun 2, 2020
57aaabc
Fix conflicts
kahummer Jun 2, 2020
1e47487
Add locationselect on exportform
kahummer Jun 3, 2020
ca7af99
ClientUpload cleanup and test updates
kahummer Jun 3, 2020
10ee969
Code cleanup
kahummer Jun 3, 2020
40285eb
Jurisdictionselect refactor & drilldown test
kahummer Jun 3, 2020
f4c90f7
SimpleOrgSelect cleanup
kahummer Jun 3, 2020
45f71e0
Update snapshot
kahummer Jun 4, 2020
012d8bf
Update snapshot
kahummer Jun 4, 2020
3449e1d
Add test for jurisdiction select
kahummer Jun 4, 2020
a8736ad
Remove unnecessary comments
kahummer Jun 4, 2020
cada51b
Update snapshot
kahummer Jun 4, 2020
373190b
Cleanup code and fix types
moshthepitt Jun 5, 2020
6563450
Use proper correct strings for clients
moshthepitt Jun 5, 2020
7e50943
Merge pull request #879 from onaio/jurisdiction-to-location
moshthepitt Jun 5, 2020
1ab11f1
Merge branch 'mda-staging' into NTD/add-students-page-and-reducer
moshthepitt Jun 5, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ REACT_APP_ENABLE_USERS=true
REACT_APP_ENABLE_ASSIGN=true
REACT_APP_ENABLE_ABOUT=true
REACT_APP_ENABLE_TEAMS=true
REACT_APP_ENABLE_MDA_POINT=true
REACT_APP_ENABLE_PRACTITIONERS=true
REACT_APP_DISABLE_LOGIN_PROTECTION=false
REACT_APP_SUPERSET_API_BASE=https://superset.reveal-stage.smartregister.org/ # notice the ending /
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@onaio/formik-effect": "^0.0.1",
"@onaio/gatekeeper": "^0.0.18",
"@onaio/google-analytics": "^0.0.2",
"@onaio/list-view": "^0.0.1",
"@onaio/list-view": "^0.0.3",
"@onaio/redux-reducer-registry": "^0.0.9",
"@onaio/session-reducer": "^0.0.10",
"@onaio/superset-connector": "^0.0.13",
Expand Down
10 changes: 10 additions & 0 deletions src/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
BACKEND_CALLBACK_PATH,
BACKEND_CALLBACK_URL,
BACKEND_LOGIN_URL,
CLIENTS_LIST_URL,
CREATE_ORGANIZATION_URL,
CREATE_PRACTITIONER_URL,
DRAFT_IRS_PLAN_URL,
Expand Down Expand Up @@ -82,6 +83,7 @@ import ConnectedIRSAssignmentPlansList from '../containers/pages/IRS/assignments
import ConnectedJurisdictionReport from '../containers/pages/IRS/JurisdictionsReport';
import ConnectedIRSReportingMap from '../containers/pages/IRS/Map';
import ConnectedIRSPlansList from '../containers/pages/IRS/plans';
import ConnectedClientListView from '../containers/pages/MDAPoint/ClientListView';
import ConnectedAssignPractitioner from '../containers/pages/OrganizationViews/AssignPractitioners';
import ConnectedCreateEditOrgView from '../containers/pages/OrganizationViews/CreateEditOrgView';
import ConnectedOrgsListView from '../containers/pages/OrganizationViews/OrganizationListView';
Expand Down Expand Up @@ -340,6 +342,14 @@ const App = (props: AppProps) => {
path={`${SINGLE_ORGANIZATION_URL}/:id`}
component={ConnectedSingleOrgView}
/>
{/* Student listing page */}
<ConnectedPrivateRoute
redirectPath={APP_CALLBACK_URL}
disableLoginProtection={DISABLE_LOGIN_PROTECTION}
exact={false}
path={CLIENTS_LIST_URL}
component={ConnectedClientListView}
/>
{/* Practitioner listing page */}
<ConnectedPrivateRoute
redirectPath={APP_CALLBACK_URL}
Expand Down
130 changes: 130 additions & 0 deletions src/components/forms/ExportForm/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import { ErrorMessage, Field, Form, Formik } from 'formik';
import React from 'react';
import { Alert, Button, Col, FormGroup, Label, Row } from 'reactstrap';
import * as Yup from 'yup';
import { ENABLE_MDA_POINT } from '../../../configs/env';
import {
DOWNLOAD,
EXPORT_BASED_ON_GEOGRAPHICAL_REGION,
EXPORT_CLIENT_LIST,
EXPORT_STUDENT_LIST,
LOCATION_ERROR_MESSAGE,
REQUIRED,
} from '../../../configs/lang';
import {
OPENSRP_EVENT_PARAM_VALUE,
OPENSRP_TEMPLATE_ENDPOINT,
OPENSRP_UPLOAD_ENDPOINT,
} from '../../../constants';
import { handleDownload } from '../../../containers/pages/MDAPoint/ClientListView/helpers/serviceHooks';
import LocationSelect from '../LocationSelect';
/** Yup validation schema for ExportForm */
export const JurisdictionSchema = Yup.object().shape({
jurisdictions: Yup.object().shape({
id: Yup.string().required(REQUIRED),
name: Yup.string(),
}),
});
/** Jurisdiction form field Option interface */
export interface JurisdictionFieldOptions {
id: string;
name: string;
}
/** Jurisdiction form field interface */
export interface JurisdictionFormField {
jurisdictions: JurisdictionFieldOptions;
}
/** initial values for exportform */
const defaultInitialValues: JurisdictionFormField = {
jurisdictions: {
id: '',
name: '',
},
};
/** Interface for ExportForm Props */
export interface ExportFormProps {
initialValues: JurisdictionFormField;
downloadFile: typeof handleDownload;
eventValue: string;
}
export const ExportForm = (props: ExportFormProps) => {
const { initialValues, downloadFile, eventValue } = props;
return (
<div>
<Row id="export-row">
<Col>
<h3 className="mb-3 mt-5 page-title">
{ENABLE_MDA_POINT ? EXPORT_STUDENT_LIST : EXPORT_CLIENT_LIST}
</h3>
{/* Download Form goes here */}
<Alert color="light">{EXPORT_BASED_ON_GEOGRAPHICAL_REGION}</Alert>
<Formik
initialValues={initialValues}
/* tslint:disable-next-line jsx-no-lambda */
onSubmit={values => {
// tslint:disable-next-line: no-floating-promises
downloadFile(
OPENSRP_TEMPLATE_ENDPOINT,
`${values.jurisdictions.name}.csv`,
OPENSRP_UPLOAD_ENDPOINT,
{
event_name: eventValue,
location_id: values.jurisdictions.id,
}
);
}}
validationSchema={JurisdictionSchema}
>
{({ errors }) => (
<Form className="mb-5">
<FormGroup className={'async-select-container'}>
<Label for={`jurisdictions-${1}-id`}>{'Geographical level to include'}</Label>
&nbsp;
<div style={{ display: 'inline-block', width: '24rem' }}>
<Field
required={true}
component={LocationSelect}
cascadingSelect={true}
name={`jurisdictions.id`}
id={`jurisdictions-id`}
className={'async-select'}
labelFieldName={`jurisdictions.name`}
/>
</div>
<Field type="hidden" name={`jurisdictions.name`} id={`jurisdictions-name`} />
{errors.jurisdictions && (
<small className="form-text text-danger jurisdictions-error">
{LOCATION_ERROR_MESSAGE}
</small>
)}
{
<ErrorMessage
name={`jurisdictions.id`}
component="small"
className="form-text text-danger"
/>
}
</FormGroup>
<Button
type="submit"
id="studentexportform-submit-button"
className="btn btn-md btn btn-primary"
color="primary"
>
{DOWNLOAD}
</Button>
</Form>
)}
</Formik>
</Col>
</Row>
</div>
);
};
const defaultProps: ExportFormProps = {
downloadFile: handleDownload,
eventValue: OPENSRP_EVENT_PARAM_VALUE,
initialValues: defaultInitialValues,
};
ExportForm.defaultProps = defaultProps;
export default ExportForm;
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`components/forms/ExportForm renders correctly: jurisdiction-select form label 1`] = `
<Label
for="jurisdictions-1-id"
tag="label"
widths={
Array [
"xs",
"sm",
"md",
"lg",
"xl",
]
}
>
<label
className=""
htmlFor="jurisdictions-1-id"
>
Geographical level to include
</label>
</Label>
`;

exports[`components/forms/ExportForm renders correctly: submit button 1`] = `null`;

exports[`components/forms/ExportForm renders jurisdictions fields correctly: jurisdictions.id field 1`] = `null`;

exports[`components/forms/ExportForm renders jurisdictions fields correctly: jurisdictions.id label 1`] = `
<Label
for="jurisdictions-1-id"
tag="label"
widths={
Array [
"xs",
"sm",
"md",
"lg",
"xl",
]
}
>
<label
className=""
htmlFor="jurisdictions-1-id"
>
Geographical level to include
</label>
</Label>
`;

exports[`components/forms/ExportForm renders jurisdictions fields correctly: jurisdictions.name field 1`] = `
<input
id="jurisdictions-name"
name="jurisdictions.name"
onBlur={[Function]}
onChange={[Function]}
type="hidden"
value=""
/>
`;
120 changes: 120 additions & 0 deletions src/components/forms/ExportForm/tests/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { getOpenSRPUserInfo } from '@onaio/gatekeeper';
kahummer marked this conversation as resolved.
Show resolved Hide resolved
import { authenticateUser } from '@onaio/session-reducer';
import { mount, shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import React from 'react';
import ExportForm from '..';
import { OpenSRPAPIResponse } from '../../../../services/opensrp/tests/fixtures/session';
import store from '../../../../store';
import * as fixtures from '../../PlanForm/tests/fixtures';

/* tslint:disable-next-line no-var-requires */
const fetch = require('jest-fetch-mock');

jest.mock('../../../../configs/env');

describe('components/forms/ExportForm', () => {
beforeEach(() => {
jest.resetAllMocks();
});

it('renders without crashing', () => {
shallow(<ExportForm />);
});

it('renders correctly', () => {
fetch.mockResponseOnce(fixtures.jurisdictionLevel0JSON);
const wrapper = mount(<ExportForm />);

expect(toJson(wrapper.find('Label'))).toMatchSnapshot('jurisdiction-select form label');
expect(toJson(wrapper.find('#ExportForm-submit-button button'))).toMatchSnapshot(
'submit button'
);
expect(wrapper.find('#jurisdictions-select-container')).toEqual({});
expect(wrapper.find('#jurisdictions-display-container').length).toEqual(0);
wrapper.unmount();
});
it('renders jurisdictions fields correctly', () => {
fetch.mockResponseOnce(fixtures.jurisdictionLevel0JSON);
const wrapper = mount(<ExportForm />);

expect(toJson(wrapper.find({ for: `jurisdictions-1-id` }))).toMatchSnapshot(
`jurisdictions.id label`
);
expect(toJson(wrapper.find(`#jurisdictions-1-id input`))).toMatchSnapshot(
`jurisdictions.id field`
);
expect(wrapper.find({ for: `jurisdictions-1-name` }).length).toEqual(0);
expect(toJson(wrapper.find(`#jurisdictions-name input`))).toMatchSnapshot(
`jurisdictions.name field`
);
// ensure there is only one options so far
expect(wrapper.find(`#jurisdictions-1-id input`).length).toEqual(0);
// there is no button to remove jurisdictions
expect(wrapper.find(`.removeJurisdiction`).length).toEqual(0);
// there is no button to add more jurisdictions
expect(wrapper.find(`.addJurisdiction`).length).toEqual(0);
wrapper.unmount();
});
it('Form validation works', async () => {
const wrapper = mount(<ExportForm />);

// no errors are initially shown
expect(
(wrapper
.find('FieldInner')
.first()
.props() as any).formik.errors
).toEqual({});

wrapper.find('form').simulate('submit');

await new Promise<any>(resolve => setImmediate(resolve));
wrapper.update();

// we now have some errors
expect(
(wrapper
.find('FieldInner')
.first()
.props() as any).formik.errors
).toEqual({
jurisdictions: {
id: 'Required',
},
});
expect(wrapper.find('small.jurisdictions-error').text()).toEqual('Please select location');
});
it('Export Form submission works', async () => {
// ensure that we are logged in so that we can get the OpenSRP token from Redux
const { authenticated, user, extraData } = getOpenSRPUserInfo(OpenSRPAPIResponse);
store.dispatch(authenticateUser(authenticated, user, extraData));

fetch.mockResponseOnce(JSON.stringify({}), { status: 201 });

const wrapper = mount(<ExportForm />);

// set jurisdiction id
(wrapper
.find('FieldInner')
.first()
.props() as any).formik.setFieldValue('jurisdictions.id', '1337');
// set jurisdiction name
wrapper
.find('input[name="jurisdictions.name"]')
.simulate('change', { target: { name: 'jurisdictions.name', value: 'Onyx' } });

wrapper.find('form').simulate('submit');
await new Promise<any>(resolve => setImmediate(resolve));
wrapper.update();

// no errors are initially shown
expect(
(wrapper
.find('FieldInner')
.first()
.props() as any).formik.errors
).toEqual({});
// Todo test the api get once form is submitted
});
});
Loading