Merge branch 'rendering_engine' of github.cmd.navi-tech.in:medici/Address-Verification-App into TP-12803

# Conflicts:
#	src/data/templateData.json
This commit is contained in:
kunalsharma
2022-12-05 13:51:49 +05:30
9 changed files with 320 additions and 155 deletions

View File

@@ -21,6 +21,7 @@ import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import Widget from './src/components/form';
import {navigationRef} from './src/components/utlis/navigationUtlis';
import {GenericStyles} from './RN-UI-LIB/src/styles';
function HomeScreen() {
return (

View File

@@ -1,14 +1,14 @@
import { StyleSheet, Text, View } from 'react-native'
import React from 'react'
import {StyleSheet, Text, View} from 'react-native';
import React from 'react';
const Checkbox = () => {
return (
<View>
<Text>Checkbox</Text>
</View>
)
}
return (
<View>
<Text>Checkbox</Text>
</View>
);
};
export default Checkbox
export default Checkbox;
const styles = StyleSheet.create({})
const styles = StyleSheet.create({});

View File

@@ -1,10 +1,88 @@
import {StyleSheet, Text, View} from 'react-native';
import React from 'react';
import {Image, StyleSheet, Text, View} from 'react-native';
import React, { useEffect } from 'react';
import {Control, Controller} from 'react-hook-form';
import CameraClickPicture from '../../../../RN-UI-LIB/src/components/camera_click_picture/CameraClickPicture';
const ImageUpload = () => {
import template from '../../../data/templateData.json';
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
import {useState} from 'react';
import {useSelector} from 'react-redux';
import {RootState} from '../../../store/store';
interface IImageUpload {
questionType: string;
questionId: string;
widgetId: string;
journeyId: string;
caseId: string;
sectionId: string;
control: Control<any, any>;
error: any;
}
const ImageUpload: React.FC<IImageUpload> = props => {
const {questionId, error, sectionId, caseId, journeyId, widgetId} = props;
const [image, setImage] = useState('');
const question = template.questions[questionId];
const dataFromRedux = useSelector(
(state: RootState) =>
state.case.caseForm?.[caseId]?.[journeyId]?.[widgetId]?.[
sectionId
]?.[questionId],
);
useEffect(() => {
if (dataFromRedux) {
setImage(dataFromRedux);
}
}, [dataFromRedux]);
if (!question) {
return null;
}
return (
<View>
<Text>ImageUpload</Text>
<View style={[GenericStyles.mt12]}>
<Text>
{question.text}{' '}
{question.type === 'mandatory' && (
<Text style={{color: 'red'}}>*</Text>
)}
</Text>
{!image ? (
<Controller
control={props.control}
rules={{
required: question.type === 'mandatory',
}}
render={({field: {onChange}}) => (
<CameraClickPicture
onPictureClickSuccess={image => {
const data = `data:image/jpeg;base64,${image}`;
setImage(data);
onChange(data);
}}
/>
)}
name={`${props.sectionId}.${questionId}`}
/>
) : (
<View>
<Text onPress={() => setImage('')}>delete</Text>
<Image
style={{
width: 300,
height: 300,
resizeMode: 'contain',
borderWidth: 1,
borderColor: 'red',
}}
source={{uri: image}}
/>
</View>
)}
{error?.[sectionId]?.[questionId] ? (
<Text style={{color: 'red'}}>This is mendatory field</Text>
) : null}
</View>
);
};

View File

@@ -1,19 +1,17 @@
import React, {useEffect} from 'react';
import {StyleSheet, View} from 'react-native';
import React from 'react';
import template from '../../../data/templateData.json';
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
import RadioGroup from '../../../../RN-UI-LIB/src/components/radio_button/RadioGroup';
import {useState} from 'react';
import {Control, Controller} from 'react-hook-form';
import {useSelector} from 'react-redux';
import RNRadioButton from '../../../../RN-UI-LIB/src/components/radio_button/RadioButton';
import RadioChip from '../../../../RN-UI-LIB/src/components/radio_button/RadioChip';
import {useDispatch, useSelector} from 'react-redux';
import {decreaseByOne} from '../../../reducer/formData';
import {updateInteraction} from '../../../reducer/caseReducre';
import {RootState} from '../../../store/store';
import {Control, Controller} from 'react-hook-form';
import {useState} from 'react';
import QuestionRenderingEngine from '../QuestionRenderingEngine';
import RadioGroup from '../../../../RN-UI-LIB/src/components/radio_button/RadioGroup';
import Text from '../../../../RN-UI-LIB/src/components/Text';
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
import template from '../../../data/templateData.json';
import {RootState} from '../../../store/store';
import QuestionRenderingEngine from '../QuestionRenderingEngine';
interface IRadioButton {
questionType: string;
@@ -31,6 +29,21 @@ const RadioButton: React.FC<IRadioButton> = props => {
const question = template.questions[questionId];
const options = template.options;
const [associatedQuestions, setAssociatedQuestions] = useState([]);
const dataFromRedux = useSelector(
(state: RootState) =>
state.case.caseForm?.[caseId]?.[journeyId]?.[widgetId]?.[
sectionId
]?.[questionId],
);
useEffect(() => {
if (dataFromRedux) {
computeNextQuestion(dataFromRedux);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [dataFromRedux]);
// const dispatch = useDispatch();
// const answer = useSelector(
// (state: RootState) =>

View File

@@ -1,41 +1,35 @@
import {ScrollView, StyleSheet, Text, View} from 'react-native';
import React, {Component, useCallback} from 'react';
import {navigateToScreen} from '../utlis/navigationUtlis';
import template from '../../data/templateData.json';
import Heading from '../../../RN-UI-LIB/src/components/Heading';
import RenderQuestion from './RenderQuestion';
import {GenericStyles} from '../../../RN-UI-LIB/src/styles';
import {useSelector} from 'react-redux';
import {RootState} from '../../store/store';
import Button from '../../../RN-UI-LIB/src/components/Button';
import {Operator} from '../formRenderingEngine/types';
import React, {useState} from 'react';
import {useForm} from 'react-hook-form';
import {useState} from 'react';
import {useEffect} from 'react';
import {ScrollView, StyleSheet, View} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import {useDispatch, useSelector} from 'react-redux';
import Button from '../../../RN-UI-LIB/src/components/Button';
import Heading from '../../../RN-UI-LIB/src/components/Heading';
import {GenericStyles, getShadowStyle} from '../../../RN-UI-LIB/src/styles';
import {COLORS} from '../../../RN-UI-LIB/src/styles/colors';
import template from '../../data/templateData.json';
import {updateInteraction} from '../../reducer/caseReducre';
import {RootState} from '../../store/store';
import {goBack, navigateToScreen} from '../utlis/navigationUtlis';
import RenderQuestion from './RenderQuestion';
const Widget = (props: any) => {
const {name, params} = props.route;
const {caseId, journey} = params;
const {sections, transitionRules} = template.widgets[name];
const {sections, transitionRules, isLeaf} = template.widgets[name];
const sectionMap = template.sections;
const {actions, conditions} = transitionRules;
const [error, setError] = useState();
const {
control,
handleSubmit,
formState: {errors},
} = useForm({});
const dispatch = useDispatch();
const dataToBeValidated = useSelector(
(state: RootState) =>
state.counter.caseForm?.[caseId]?.[journey]?.[name],
state.case.caseForm?.[caseId]?.[journey]?.[name],
);
console.log('defaultValues', dataToBeValidated);
// useEffect(() => {
// setValue('defaultValues', dataToBeValidated);
// }, [dataToBeValidated, setValue]);
const {control, handleSubmit} = useForm({
defaultValues: dataToBeValidated,
});
const evaluateLeaf = (leaf: {
left: string;
@@ -75,62 +69,98 @@ const Widget = (props: any) => {
return composite.operator === 'AND' ? left && right : left || right;
};
const handleValidation = (transitionRules: any) => {
if (transitionRules.condition_type === 'LEAF_NODE') {
// console.log(evaluateLeaf(transitionRules));
const nextScreenName = actions[evaluateLeaf(transitionRules)];
const handleValidation = (rules: any) => {
let nextScreenName = '';
if (rules.condition_type === 'LEAF_NODE') {
nextScreenName = actions[evaluateLeaf(rules)];
} else {
// console.log(evaluateComposite(transitionRules));
const answer = String(evaluateComposite(transitionRules));
const nextScreenName = actions[answer];
navigateToScreen(nextScreenName, {
journey: journey,
caseId,
});
console.log({nextScreenName, actions});
const answer = String(evaluateComposite(rules));
nextScreenName = actions[answer];
}
navigateToScreen(nextScreenName, {
journey: journey,
caseId,
});
};
const onSubmit = data => {
console.log(data, 'data');
const onSubmit = (data: any) => {
dispatch(
updateInteraction({
caseId,
journeyId: journey,
widgetId: name,
answer: data,
}),
);
handleValidation(conditions);
};
const onError = data => {
const onError = (data: any) => {
console.log(data);
setError(data);
};
return (
<ScrollView>
{sections.map((section: string, index: number) => (
<View
style={[
GenericStyles.p16,
GenericStyles.whiteBackground,
index > 0 ? GenericStyles.mt16 : null,
]}>
<Heading key={index} type={'h3'} dark>
{sectionMap[section]?.label}
</Heading>
<RenderQuestion
questionMap={sectionMap[section].questions}
journeyId={journey}
caseId={caseId}
sectionId={section}
widgetId={name}
control={control}
error={error}
/>
</View>
))}
<Button
title="handle validation"
onPress={handleSubmit(onSubmit, onError)}
/>
</ScrollView>
<SafeAreaView
style={[GenericStyles.whiteBackground, GenericStyles.fill]}>
<ScrollView
contentContainerStyle={[
GenericStyles.p16,
GenericStyles.whiteBackground,
]}>
{sections.map(
(section: keyof typeof sectionMap, index: number) => (
<View
key={section + index}
style={[
GenericStyles.p16,
GenericStyles.whiteBackground,
index > 0 ? GenericStyles.mt16 : null,
getShadowStyle(5),
styles.br8,
]}>
<Heading key={index} type={'h3'} dark>
{sectionMap[section]?.label}
</Heading>
<RenderQuestion
questionMap={sectionMap[section].questions}
journeyId={journey}
caseId={caseId}
sectionId={section}
widgetId={name}
control={control}
error={error}
name={name}
/>
</View>
),
)}
</ScrollView>
<View
style={[
GenericStyles.row,
GenericStyles.justifyContentSpaceBetween,
GenericStyles.p16,
styles.borderTop,
]}>
<Button title="Go Back" onPress={goBack} />
<Button
title={isLeaf ? 'Submit' : 'next'}
onPress={handleSubmit(onSubmit, onError)}
/>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({});
const styles = StyleSheet.create({
br8: {
borderRadius: 8,
},
borderTop: {
borderTopColor: COLORS.BORDER.PRIMARY,
borderTopWidth: 1,
},
});
export default Widget;

View File

@@ -1,11 +1,12 @@
// @ts-nocheck
import React, {useMemo} from 'react';
import {Button, Pressable, Text, View} from 'react-native';
import React, {useCallback, useMemo} from 'react';
import {Adderss, EachJourney, Template} from './types';
import {useDispatch, useSelector} from 'react-redux';
import {RootState} from '../../store/store';
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
import {increaseByOne} from '../../reducer/caseReducre';
import {RootState} from '../../store/store';
import {navigateToScreen} from '../utlis/navigationUtlis';
import {EachJourney, Template} from './types';
interface RenderingEngine {
data: Template;
@@ -32,19 +33,22 @@ interface RenderingEngine {
const RenderingEngine: React.FC<RenderingEngine> = props => {
const dispatch = useDispatch();
const journeyOrder = props?.userData?.journeyOrder;
const data = useSelector((state: RootState) => state.counter.value);
const data = useSelector((state: RootState) => state.case.value);
const handleNextContext = (journey: EachJourney) => {
navigateToScreen(journey.startWidget, {
journey: journey.id,
caseId: props.userData.id,
});
};
const handleNextContext = useMemo(
() => (journey: EachJourney) => {
navigateToScreen(journey.startWidget, {
journey: journey.id,
caseId: props.userData.id,
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[],
);
const JourneyRendering = useMemo(
() =>
journeyOrder.map((eachJourney, index) => {
const journey =
props.data.journeys[eachJourney]
const journey = props.data.journeys[eachJourney];
return (
<Pressable
@@ -54,7 +58,7 @@ const RenderingEngine: React.FC<RenderingEngine> = props => {
</Pressable>
);
}),
[journeyOrder, handleNextContext, props.userData],
[journeyOrder, handleNextContext, props],
);
const handlePress = () => {
@@ -62,7 +66,7 @@ const RenderingEngine: React.FC<RenderingEngine> = props => {
};
return (
<View>
<View style={GenericStyles.whiteBackground}>
<Text>Rendering Engine {data}</Text>
{JourneyRendering}
<Button title="add todo" onPress={handlePress} />

View File

@@ -17,7 +17,7 @@
"false": "unverified"
}
},
"is_leaf": false
"isLeaf": false
},
"j2": {
"id": "j2",
@@ -36,7 +36,7 @@
"false": "unverified"
}
},
"is_leaf": false
"isLeaf": false
},
"j3": {
"id": "j3",
@@ -55,7 +55,7 @@
"false": "unverified"
}
},
"is_leaf": false
"isLeaf": false
},
"j4": {
"id": "j4",
@@ -74,7 +74,7 @@
"false": "unverified"
}
},
"is_leaf": false
"isLeaf": false
},
"j5": {
"id": "j5",
@@ -93,7 +93,7 @@
"false": "unverified"
}
},
"is_leaf": false
"isLeaf": false
}
},
"widgets": {
@@ -138,7 +138,7 @@
"false": "w3"
}
},
"is_leaf": false
"isLeaf": false
},
"w2": {
"journey_id": "j1",
@@ -146,9 +146,20 @@
"s2"
],
"transitionRules": {
"conditions": {
"operator": "MATCHES",
"condition_type": "LEAF_NODE",
"left":"q3",
"right": "o3",
"section":"s2"
},
"actions": {
"true": "w4",
"false": "w3"
}
},
"is_leaf": true
"isLeaf": false
},
"w3": {
"journey_id": "j3",
@@ -172,7 +183,27 @@
}
}
},
"is_leaf": true
"w4": {
"journey_id": "j1",
"sections": [
"s2"
],
"transitionRules": {
"conditions": {
"operator": "MATCHES",
"condition_type": "LEAF_NODE",
"left":"q3",
"right": "o3",
"section":"s2"
},
"actions": {
"true": "w2",
"false": "w3"
}
},
"isLeaf": true
}
},
"sections": {
"s1": {
@@ -180,7 +211,8 @@
"questions": [
"q1",
"q8",
"q9"
"q9",
"q10"
]
},
"s2": {
@@ -264,7 +296,7 @@
"type": "mandatory",
"input_type": "TextInput",
"options": [
],
"metadata": {
"formatting_type": "textbox"
@@ -323,77 +355,87 @@
"metadata": {
"formatting_type": "Rating"
}
},
"q10": {
"text": "New Address Verification question: some question?",
"type": "na",
"input_type": "ImageUpload",
"options": [],
"metadata": {
"formatting_type": "Rating"
}
}
},
"options": {
"o1": {
"type": "single_select",
"text": "Found",
"associateQuestions": [
],
"metadata": {
}
},
"o2": {
"type": "single_select",
"text": "Not Found",
"associateQuestions": [
],
"metadata": {
}
},
"o3": {
"type": "single_select",
"text": "Yes",
"associateQuestions": [
],
"metadata": {
}
},
"o4": {
"type": "single_select",
"text": "No",
"associateQuestions": [
],
"metadata": {
}
},
"o5": {
"type": "multi_select",
"text": "Medical issue",
"associateQuestions": [
],
"metadata": {
}
},
"o6": {
"type": "multi_select",
"text": "Covid",
"associateQuestions": [
],
"metadata": {
}
},
"o7": {
"type": "multi_select",
"text": "Business purpose",
"associateQuestions": [
],
"metadata": {
}
},
"o8": {
@@ -403,48 +445,48 @@
"q4"
],
"metadata": {
}
},
"o9": {
"type": "multi_select",
"text": "Flat",
"associateQuestions": [
],
"metadata": {
}
},
"o10": {
"type": "multi_select",
"text": "city",
"associateQuestions": [
],
"metadata": {
}
},
"o11": {
"type": "single_select",
"text": "PTP",
"associateQuestions": [
],
"metadata": {
}
},
"o22": {
"type": "single_select",
"text": "RNR",
"associateQuestions": [
],
"metadata": {
}
}
},
}
}
}

View File

@@ -1,7 +1,8 @@
// @ts-nocheck
import {createSlice} from '@reduxjs/toolkit';
export const counterSlice = createSlice({
name: 'counter',
name: 'case',
initialState: {
value: 0,
caseForm: {},
@@ -14,8 +15,7 @@ export const counterSlice = createSlice({
state.value--;
},
updateInteraction: (state, action) => {
const {caseId, journeyId, widgetId, questionId, answer, sectionId} =
action.payload;
const {caseId, journeyId, widgetId, answer} = action.payload;
const data = state.caseForm || {};
if (!data[caseId]) {
data[caseId] = {};
@@ -26,10 +26,7 @@ export const counterSlice = createSlice({
if (!data[caseId][journeyId][widgetId]) {
data[caseId][journeyId][widgetId] = {};
}
if (!data[caseId][journeyId][widgetId][sectionId]) {
data[caseId][journeyId][widgetId][sectionId] = {};
}
data[caseId][journeyId][widgetId][sectionId][questionId] = answer;
data[caseId][journeyId][widgetId] = answer;
state.caseForm = data;
},
},

View File

@@ -12,17 +12,17 @@ import {
} from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';
import counterReducer from '../reducer/caseReducre';
import caseReducer from '../reducer/caseReducre';
const rootReducer = combineReducers({
counter: counterReducer,
case: caseReducer,
});
const persistConfig = {
key: 'root',
version: 1,
storage: AsyncStorage,
whitelist: ['counter'],
whitelist: ['case'],
};
const persistedReducer = persistReducer(persistConfig, rootReducer);