Skip to content

Commit

Permalink
Merge pull request #107 from akvo/feature/106-question-group-navigation
Browse files Browse the repository at this point in the history
Feature/106 question group navigation
  • Loading branch information
dedenbangkit committed Aug 1, 2023
2 parents fe89122 + d75dfea commit aadc299
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 16 deletions.
1 change: 1 addition & 0 deletions app/src/components/LogoutButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const LogoutButton = () => {
s.question = [];
s.currentValues = {}; // answers
s.questionGroupListCurrentValues = {}; // answers for question group list component
s.visitedQuestionGroup = [];
s.dataPointName = [];
s.surveyDuration = 0;
});
Expand Down
9 changes: 7 additions & 2 deletions app/src/form/FormContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,11 @@ const FormContainer = ({ forms, initialValues = {}, onSubmit, onSave }) => {
}, [currentValues, onSave]);

const formDefinition = useMemo(() => {
return transformForm(forms, activeLang);
const transformedForm = transformForm(forms, activeLang);
FormState.update((s) => {
s.visitedQuestionGroup = [transformedForm.question_group[0].id];
});
return transformedForm;
}, [forms, activeLang]);

const currentGroup = useMemo(() => {
Expand All @@ -91,12 +95,13 @@ const FormContainer = ({ forms, initialValues = {}, onSubmit, onSave }) => {
return initialValues;
}
return currentValues;
}, [initialValues]);
}, [initialValues, currentValues]);

const refreshForm = () => {
FormState.update((s) => {
s.currentValues = {};
s.questionGroupListCurrentValues = {};
s.visitedQuestionGroup = [];
s.dataPointName = [];
s.surveyDuration = 0;
});
Expand Down
5 changes: 4 additions & 1 deletion app/src/form/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export const styles = StyleSheet.create({
paddingHorizontal: 10,
},
questionGroupListItemActive: {
backgroundColor: '#F3F3F3',
backgroundColor: '#E9E9E9',
},
questionGroupListItemIcon: {
paddingHorizontal: 10,
Expand All @@ -159,6 +159,9 @@ export const styles = StyleSheet.create({
questionGroupListItemName: {
marginLeft: 10,
},
questionGroupListItemNameActive: {
fontWeight: 'bold',
},
cascadeContainer: {
display: 'flex',
flexDirection: 'column',
Expand Down
12 changes: 10 additions & 2 deletions app/src/form/support/FormNavigation.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import React, { useEffect } from 'react';
import { Platform, ToastAndroid } from 'react-native';
import { Tab } from '@rneui/themed';
import { styles } from '../styles';
import { UIState } from '../../store';
import { UIState, FormState } from '../../store';
import { i18n } from '../../lib';

const FormNavigation = ({
Expand All @@ -15,9 +15,17 @@ const FormNavigation = ({
showQuestionGroupList,
setShowQuestionGroupList,
}) => {
const visitedQuestionGroup = FormState.useState((s) => s.visitedQuestionGroup);
const activeLang = UIState.useState((s) => s.lang);
const trans = i18n.text(activeLang);

useEffect(() => {
const updateVisitedQuestionGroup = [...visitedQuestionGroup, ...[activeGroup]];
FormState.update((s) => {
s.visitedQuestionGroup = [...new Set(updateVisitedQuestionGroup)];
});
}, [activeGroup]);

const validateOnFormNavigation = async () => {
let errors = false;
if (formRef?.current) {
Expand Down
7 changes: 6 additions & 1 deletion app/src/form/support/QuestionGroupList.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Text, Divider } from '@rneui/themed';
import QuestionGroupListItem from './QuestionGroupListItem';
import { validateDependency, modifyDependency } from '../lib';
import { styles } from '../styles';
import { FormState } from '../../store';

export const checkCompleteQuestionGroup = (form, values) => {
return form.question_group.map((questionGroup) => {
Expand Down Expand Up @@ -41,6 +42,8 @@ const QuestionGroupList = ({
setActiveQuestionGroup,
setShowQuestionGroupList,
}) => {
const visitedQuestionGroup = FormState.useState((s) => s.visitedQuestionGroup);

const completedQuestionGroup = useMemo(() => {
return checkCompleteQuestionGroup(form, values);
});
Expand Down Expand Up @@ -69,7 +72,9 @@ const QuestionGroupList = ({
key={questionGroup.id}
name={questionGroup.name}
active={activeQuestionGroup === questionGroup.id}
completedQuestionGroup={completedQuestionGroup[qx]}
completedQuestionGroup={
completedQuestionGroup[qx] && visitedQuestionGroup.includes(questionGroup.id)
}
onPress={() => handleOnPress(questionGroup.id)}
/>
))}
Expand Down
5 changes: 3 additions & 2 deletions app/src/form/support/QuestionGroupListItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const QuestionGroupListItem = ({ name, active, completedQuestionGroup = false, o
const icon = completedQuestionGroup ? 'check-circle' : 'circle';
const bgColor = completedQuestionGroup ? '#2884bd' : '#d4d4d4';
const activeOpacity = active ? styles.questionGroupListItemActive : {};
const activeName = active ? styles.questionGroupListItemNameActive : {};
return (
<TouchableOpacity
style={{ ...styles.questionGroupListItemWrapper, ...activeOpacity }}
Expand All @@ -16,12 +17,12 @@ const QuestionGroupListItem = ({ name, active, completedQuestionGroup = false, o
>
<Icon
testID="icon-mark"
name={icon}
name="circle"
type="font-awesome"
color={bgColor}
style={styles.questionGroupListItemIcon}
/>
<Text style={styles.questionGroupListItemName}>{name}</Text>
<Text style={{ ...styles.questionGroupListItemName, ...activeName }}>{name}</Text>
</TouchableOpacity>
);
};
Expand Down
17 changes: 9 additions & 8 deletions app/src/form/support/__test__/QuestionGroupListItem.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { render } from '@testing-library/react-native';
import { render, act, waitFor } from '@testing-library/react-native';
jest.useFakeTimers();
import QuestionGroupList, { checkCompleteQuestionGroup } from '../QuestionGroupList';
import QuestionGroupListItem from '../QuestionGroupListItem';
Expand Down Expand Up @@ -214,6 +214,11 @@ const example = {

describe('QuestionGroup & QuestionGroupListItem without mock', () => {
describe('checkCompleteQuestionGroup function', () => {
it('Should return boolean if completed/not', () => {
const completed = checkCompleteQuestionGroup(example, { 1: 'Galih' });
expect(completed).toEqual([true, false, false, true]);
});

it.failing(
'Should failing when only one question answered from two required questions in a question group',
() => {
Expand Down Expand Up @@ -290,11 +295,6 @@ describe('QuestionGroup & QuestionGroupListItem without mock', () => {
expect(dataPointElement).toBeFalsy();
});

it('Should return boolean if completed/not', () => {
const completed = checkCompleteQuestionGroup(example, { 1: 'Galih' });
expect(completed).toEqual([true, false, false, true]);
});

it('Should render question group name', () => {
const wrapper = render(
<QuestionGroupListItem name="Group 1" active={true} completedQuestionGroup={false} />,
Expand All @@ -312,7 +312,8 @@ describe('QuestionGroup & QuestionGroupListItem without mock', () => {
const iconEl = wrapper.getByTestId('icon-mark');
const iconElProps = iconEl.props.children.props.children.props;
expect(iconElProps.color).toBe('#2884bd');
expect(iconElProps.name).toBe('check-circle');
// Drop the check mark (this can be implemented later after discussion with the design team )
expect(iconElProps.name).toBe('circle'); // check-circle
});

it('Should have disabled mark if not completed', () => {
Expand Down Expand Up @@ -348,7 +349,7 @@ describe('QuestionGroup & QuestionGroupListItem without mock', () => {
<QuestionGroupListItem name="Group 1" active={true} completedQuestionGroup={false} />,
);
const itemEl = wrapper.getByTestId('question-group-list-item-wrapper');
expect(itemEl.props.style.backgroundColor).toBe('#F3F3F3');
expect(itemEl.props.style.backgroundColor).toBe('#E9E9E9');
});

it.failing('Should highlight question group if not active', () => {
Expand Down
1 change: 1 addition & 0 deletions app/src/navigation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ const Navigation = (props) => {
FormState.update((s) => {
s.currentValues = {};
s.questionGroupListCurrentValues = {};
s.visitedQuestionGroup = [];
s.dataPointName = [];
s.surveyDuration = 0;
});
Expand Down
1 change: 1 addition & 0 deletions app/src/store/forms.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const FormState = new Store({
submitted: false,
currentValues: {}, // answers
questionGroupListCurrentValues: {}, // answers for question group list component
visitedQuestionGroup: [], // to store visited question group id
dataPointName: [],
surveyDuration: 0,
});
Expand Down

0 comments on commit aadc299

Please sign in to comment.