Skip to content

Commit

Permalink
Merge pull request #92 from akvo/feature/91-cascade-in-display-name
Browse files Browse the repository at this point in the history
Feature/91 cascade in display name
  • Loading branch information
dedenbangkit committed Jul 30, 2023
2 parents 925aa28 + f25c3f5 commit 0b31c31
Show file tree
Hide file tree
Showing 2 changed files with 210 additions and 3 deletions.
18 changes: 15 additions & 3 deletions app/src/form/fields/TypeCascade.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { View, Text } from 'react-native';
import { Dropdown } from 'react-native-element-dropdown';
import { FieldLabel } from '../support';
import { styles } from '../styles';
import { FormState } from '../../store';

const TypeCascade = ({
onChange,
Expand Down Expand Up @@ -50,21 +51,32 @@ const TypeCascade = ({
value: null,
});
}
const dropdownValues = updatedItems.filter((dd) => dd.value).map((dd) => dd.value);
const finalValues = updatedItems.length !== dropdownValues.length ? null : dropdownValues;
const dropdownValues = updatedItems.filter((dd) => dd.value);
const finalValues =
updatedItems.length !== dropdownValues.length ? null : dropdownValues.map((dd) => dd.value);
onChange(id, finalValues);

if (finalValues) {
const { options: selectedOptions, value: selectedValue } = dropdownValues.pop();
const findSelected = selectedOptions?.find((o) => o.id === selectedValue) || [];
const cascadeName = findSelected?.name || null;
FormState.update((s) => {
s.dataPointName = s.dataPointName.map((dn) =>
dn.type === 'cascade' ? { ...dn, value: cascadeName } : dn,
);
});
}
setDropdownItems(updatedItems);
};

useEffect(() => {
const parentID = source?.parent_id || 0;
const filterDs = dataSource.filter(
(ds) =>
ds?.id === parentID ||
ds?.parent === parentID ||
(values[id] && (values[id].includes(ds?.id) || values[id].includes(ds?.parent))),
);

if (dropdownItems.length === 0 && dataSource.length && filterDs.length) {
const groupedDs = groupBy(filterDs, 'parent');
const initialDropdowns = Object.values(groupedDs).map((options, ox) => {
Expand Down
195 changes: 195 additions & 0 deletions app/src/form/fields/__test__/TypeCascade.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { useState } from 'react';
import { render, fireEvent, act, waitFor, renderHook } from '@testing-library/react-native';
import TypeCascade from '../TypeCascade';
import { generateDataPointName } from '../../lib';
import { FormState } from '../../../store';

const dummyLocations = [
{ id: 106, name: 'DI YOGYAKARTA', parent: 0 },
Expand Down Expand Up @@ -409,4 +411,197 @@ describe('TypeCascade', () => {
const requiredIcon = wrapper.getByText('**');
expect(requiredIcon).toBeTruthy();
});

it('should use id when parent id not found', () => {
const fieldID = 'location';
const fieldName = 'Location';
const initialValue = null;
const values = { [fieldID]: initialValue };

const mockedOnChange = jest.fn((fieldName, value) => {
values[fieldName] = value;
});

const questionSource = { file: 'file.sqlite', parent_id: 114 };
const { getByTestId, getByText } = render(
<TypeCascade
onChange={mockedOnChange}
id={fieldID}
name={fieldName}
values={values}
dataSource={dummyLocations}
source={questionSource}
/>,
);

const parentDropdown = getByTestId('dropdown-cascade-0');
expect(parentDropdown).toBeDefined();

fireEvent.press(parentDropdown);

const validOption = getByText('Kembaran');
expect(validOption).toBeDefined();
});

it('Should get cascade name as datapoint name', async () => {
/**
* Set datapointName first
*/

act(() => {
FormState.update((s) => {
s.dataPointName = [
{ type: 'cascade', value: null },
{ type: 'text', value: 'Example' },
];
});
});
const fieldID = 'location';
const fieldName = 'Location';
const initialValue = null;
const values = { [fieldID]: initialValue };

const mockedOnChange = jest.fn((fieldName, value) => {
values[fieldName] = value;
});

const questionSource = { file: 'file.sqlite', parent_id: 107 };
const { getByTestId, getByText } = render(
<TypeCascade
onChange={mockedOnChange}
id={fieldID}
name={fieldName}
values={values}
dataSource={dummyLocations}
source={questionSource}
/>,
);

const dropdown1 = getByTestId('dropdown-cascade-0');
expect(dropdown1).toBeDefined();

const dropdown2 = getByTestId('dropdown-cascade-1');
expect(dropdown2).toBeDefined();
fireEvent.press(dropdown2);

const selectedText = getByText('Sabdodadi');
fireEvent.press(selectedText);

act(() => {
mockedOnChange(fieldID, [107, 109]);
const cascadeName = 'Sabdodadi';
FormState.update((s) => {
s.dataPointName = s.dataPointName.map((dn) =>
dn.type === 'cascade' ? { ...dn, value: cascadeName } : dn,
);
});
});

await waitFor(() => {
const { result } = renderHook(() => FormState.useState((s) => s.dataPointName));
const { dpName } = generateDataPointName(result.current);
expect(dpName).toBe('Sabdodadi - Example');
expect(values[fieldID]).toEqual([107, 109]);
});
});

it('Should not get cascade name as datapoint name when FormState.dataPointName is empty or there is no cascade type', async () => {
/**
* Update datapointName first
*/
act(() => {
FormState.update((s) => {
s.dataPointName = [];
});
});
const fieldID = 'location';
const fieldName = 'Location';
const initialValue = null;
const values = { [fieldID]: initialValue };

const mockedOnChange = jest.fn((fieldName, value) => {
values[fieldName] = value;
});

const questionSource = { file: 'file.sqlite', parent_id: 107 };
const { getByTestId, getByText, rerender } = render(
<TypeCascade
onChange={mockedOnChange}
id={fieldID}
name={fieldName}
values={values}
dataSource={dummyLocations}
source={questionSource}
/>,
);

const dropdown1 = getByTestId('dropdown-cascade-0');
expect(dropdown1).toBeDefined();

const dropdown2 = getByTestId('dropdown-cascade-1');
expect(dropdown2).toBeDefined();
fireEvent.press(dropdown2);

const selectedText = getByText('Bantul');
fireEvent.press(selectedText);

act(() => {
mockedOnChange(fieldID, [107, 108]);
const cascadeName = 'Bantul';
FormState.update((s) => {
s.dataPointName = s.dataPointName.map((dn) =>
dn.type === 'cascade' ? { ...dn, value: cascadeName } : dn,
);
});
});

await waitFor(() => {
const { result } = renderHook(() => FormState.useState((s) => s.dataPointName));
const { dpName } = generateDataPointName(result.current);
expect(dpName).toBe('');
expect(values[fieldID]).toEqual([107, 108]);
});

act(() => {
FormState.update((s) => {
s.dataPointName = [
{ type: 'text', value: 'Example' },
{ types: 'geo', value: null },
];
});
});

rerender(
<TypeCascade
onChange={mockedOnChange}
id={fieldID}
name={fieldName}
values={values}
dataSource={dummyLocations}
source={questionSource}
/>,
);

fireEvent.press(dropdown2);

const selectedText2 = getByText('Sabdodadi');
fireEvent.press(selectedText2);

act(() => {
mockedOnChange(fieldID, [107, 109]);
const cascadeName = 'Sabdodadi';
FormState.update((s) => {
s.dataPointName = s.dataPointName.map((dn) =>
dn.type === 'cascade' ? { ...dn, value: cascadeName } : dn,
);
});
});

await waitFor(() => {
const { result } = renderHook(() => FormState.useState((s) => s.dataPointName));
const { dpName } = generateDataPointName(result.current);
expect(dpName).toBe('Example');
expect(values[fieldID]).toEqual([107, 109]);
});
});
});

0 comments on commit 0b31c31

Please sign in to comment.