initial commit

This commit is contained in:
aman.singh
2022-12-03 16:43:36 +05:30
parent bd3d793f00
commit 04408aeb3f
24 changed files with 982 additions and 172 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "RN-UI-LIB"]
path = RN-UI-LIB
url = git@github.cmd.navi-tech.in:medici/RN-UI-LIB.git

37
App.tsx
View File

@@ -9,13 +9,31 @@
*/
import React from 'react';
import {SafeAreaView, Text} from 'react-native';
import data from './src/data/data.json';
import {SafeAreaView, Text, View} from 'react-native';
import data from './src/data/templateData.json';
import userData from './src/data/userData.json';
import RenderingEngine from './src/components/formRenderingEngine';
import {Provider} from 'react-redux';
import store, {persistor} from './src/store/store';
import {PersistGate} from 'redux-persist/integration/react';
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';
function HomeScreen() {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<SafeAreaView>
<RenderingEngine data={data} userData={userData} />
</SafeAreaView>
</View>
);
}
const Stack = createNativeStackNavigator();
const App = () => {
// const [hasBeenManuplated, setHasBeenManuplated] = useState<boolean>(false);
return (
@@ -23,9 +41,18 @@ const App = () => {
<PersistGate
loading={<Text>Loading...</Text>}
persistor={persistor}>
<SafeAreaView>
<RenderingEngine data={data} />
</SafeAreaView>
<NavigationContainer ref={navigationRef}>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
{Object.keys(data.widgets).map(key => (
<Stack.Screen
key={key}
name={key}
component={Widget}
/>
))}
</Stack.Navigator>
</NavigationContainer>
</PersistGate>
</Provider>
);

1
RN-UI-LIB Submodule

Submodule RN-UI-LIB added at f77ac9a692

View File

@@ -10,7 +10,7 @@ module.exports = {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true,
inlineRequires: false,
},
}),
},

View File

@@ -15,9 +15,14 @@
"@react-native-async-storage/async-storage": "1.17.11",
"@react-native-firebase/app": "^16.4.6",
"@react-native-firebase/database": "^16.4.6",
"@react-navigation/native": "^6.0.16",
"@react-navigation/native-stack": "^6.9.4",
"@reduxjs/toolkit": "1.9.1",
"react": "18.1.0",
"react-hook-form": "7.40.0",
"react-native": "0.70.6",
"react-native-safe-area-context": "^4.4.1",
"react-native-screens": "^3.18.2",
"react-redux": "8.0.5",
"redux": "4.2.0",
"redux-persist": "6.0.0"

View File

@@ -0,0 +1,46 @@
import {StyleSheet, Text, View} from 'react-native';
import React from 'react';
import TextInput from './components/TextInput';
import RadioButton from './components/RadioButton';
import TextArea from './components/TextArea';
import ImageUpload from './components/ImageUpload';
import Checkbox from './components/Checkbox';
import Rating from './components/Rating';
import { Control } from 'react-hook-form';
const Component = {
TextInput: TextInput,
TextArea: TextArea,
RadioButton: RadioButton,
ImageUpload: ImageUpload,
Checkbox: Checkbox,
Rating: Rating,
};
interface IQuestionRenderingEngine {
questionType: string;
questionId: string;
name: string;
journeyId: string;
caseId: string;
widgitId: string;
control: Control<any, any>;
error: any;
sectionId: string;
}
const QuestionRenderingEngine: React.FC<IQuestionRenderingEngine> = props => {
const Comp = Component[props.questionType];
if (!Comp) {
return null;
}
return (
<View>
<Comp {...props} />
</View>
);
};
export default QuestionRenderingEngine;
const styles = StyleSheet.create({});

View File

@@ -0,0 +1,47 @@
import {StyleSheet, Text, View} from 'react-native';
import React from 'react';
import template from '../../data/templateData.json';
import QuestionRenderingEngine from './QuestionRenderingEngine';
import { Control } from 'react-hook-form';
interface IRenderQuestion {
questionMap: Array<string>;
journeyId: string;
name: string;
caseId: string;
sectionId: string;
widgetId: string;
control: Control<any, any>;
error: any;
}
const RenderQuestion: React.FC<IRenderQuestion> = props => {
const {name, questionMap, journeyId, caseId, sectionId} = props;
const questionHashMap = template.questions;
return (
<View>
{questionMap.map((question, index) => {
if (questionHashMap[question]) {
return (
<QuestionRenderingEngine
key={index}
questionType={questionHashMap[question].input_type}
questionId={question}
name={name}
journeyId={journeyId}
caseId={caseId}
sectionId={sectionId}
widgetId={props.widgetId}
control={props.control}
error={props.error}
/>
);
}
})}
</View>
);
};
export default RenderQuestion;
const styles = StyleSheet.create({});

View File

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

View File

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

View File

@@ -0,0 +1,135 @@
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 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 Text from '../../../../RN-UI-LIB/src/components/Text';
interface IRadioButton {
questionType: string;
questionId: string;
widgetId: string;
journeyId: string;
caseId: string;
sectionId: string;
control: Control<any, any>;
error: any;
}
const RadioButton: React.FC<IRadioButton> = props => {
const {questionId, widgetId, journeyId, caseId, sectionId, error} = props;
const question = template.questions[questionId];
const options = template.options;
const [associatedQuestions, setAssociatedQuestions] = useState([]);
// const dispatch = useDispatch();
// const answer = useSelector(
// (state: RootState) =>
// state.counter.caseForm?.[caseId]?.[journeyId]?.[widgetId]?.[
// sectionId
// ]?.[questionId] || 'not_found',
// );
// const registerValue = (id: string) => {
// dispatch(
// updateInteraction({
// caseId,
// journeyId,
// widgetId,
// questionId,
// answer: id,
// sectionId,
// }),
// );
// };
const computeNextQuestion = (optionId: string) => {
if (options[optionId]?.associateQuestions.length < 1) {
setAssociatedQuestions([]);
return;
}
setAssociatedQuestions(options[optionId]?.associateQuestions);
};
return (
<View style={GenericStyles.mt12}>
<Text>
{question.text}{' '}
{question.type === 'mandatory' && (
<Text style={{color: 'red'}}>*</Text>
)}
</Text>
<Controller
control={props.control}
rules={{
required: question.type === 'mandatory',
}}
render={({field: {onChange, value}}) => (
<RadioGroup
value={value}
onValueChange={change => {
onChange(change);
computeNextQuestion(change);
// registerValue(change);
}}
variant={'button'}
orientation={
question.metadata.orientation || 'verticle'
}>
{question?.metadata.buttonType === 'button'
? question.options.map(option => (
<RNRadioButton
id={option}
value={options[option].text}
/>
))
: question.options.map(option => (
<RadioChip
id={option}
value={options[option].text}
/>
))}
</RadioGroup>
)}
name={`${sectionId}.${questionId}`}
/>
{error?.[sectionId]?.[questionId] ? (
<Text style={{color: 'red'}}>This is mendatory field</Text>
) : null}
{associatedQuestions.map((question, index) => {
if (template.questions[question]) {
return (
<QuestionRenderingEngine
key={index}
questionType={
template.questions[question].input_type
}
questionId={question}
name={widgetId}
journeyId={journeyId}
caseId={caseId}
sectionId={sectionId}
widgetId={props.widgetId}
control={props.control}
error={props.error}
/>
);
}
})}
</View>
);
};
const styles = StyleSheet.create({});
export default RadioButton;

View File

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

View File

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

View File

@@ -0,0 +1,59 @@
import {StyleSheet, View} from 'react-native';
import React from 'react';
import RNTextInput from '../../../../RN-UI-LIB/src/components/TextInput';
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
import {Control, Controller} from 'react-hook-form';
import template from '../../../data/templateData.json';
import Text from '../../../../RN-UI-LIB/src/components/Text';
interface ITextInput {
questionType: string;
questionId: string;
widgetId: string;
journeyId: string;
caseId: string;
sectionId: string;
control: Control<any, any>;
error: any;
}
const TextInput: React.FC<ITextInput> = props => {
const {questionId, error, sectionId} = props;
const question = template.questions[questionId];
if (!question) {
return null;
}
return (
<View style={[GenericStyles.mt12]}>
<Text>
{question.text}{' '}
{question.type === 'mandatory' && (
<Text style={{color: 'red'}}>*</Text>
)}
</Text>
<Controller
control={props.control}
rules={{
required: question.type === 'mandatory',
}}
render={({field: {onChange, value}}) => (
<RNTextInput
onChangeText={onChange}
value={value}
containerStyle={[GenericStyles.mt12]}
/>
)}
name={`${props.sectionId}.${questionId}`}
/>
{error?.[sectionId]?.[questionId] ? (
<Text style={{color: 'red'}}>This is mendatory field</Text>
) : null}
</View>
);
};
export default TextInput;
const styles = StyleSheet.create({});

View File

@@ -0,0 +1,136 @@
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 {useForm} from 'react-hook-form';
import {useState} from 'react';
import {useEffect} from 'react';
const Widget = (props: any) => {
const {name, params} = props.route;
const {caseId, journey} = params;
const {sections, transitionRules} = template.widgets[name];
const sectionMap = template.sections;
const {actions, conditions} = transitionRules;
const [error, setError] = useState();
const {
control,
handleSubmit,
formState: {errors},
} = useForm({});
const dataToBeValidated = useSelector(
(state: RootState) =>
state.counter.caseForm?.[caseId]?.[journey]?.[name],
);
console.log('defaultValues', dataToBeValidated);
// useEffect(() => {
// setValue('defaultValues', dataToBeValidated);
// }, [dataToBeValidated, setValue]);
const evaluateLeaf = (leaf: {
left: string;
right: string;
operator: string;
section: string;
}): boolean => {
switch (leaf.operator) {
case 'MATCHES':
return (
leaf.right === dataToBeValidated[leaf.section][leaf.left]
);
default:
return false;
}
};
const evaluateComposite = (composite: {
left: any;
right: any;
operator: string;
section: string;
}): boolean => {
let left = false,
right = false;
if (composite.left.condition_type === 'COMPOSITE') {
left = evaluateComposite(composite.left);
} else if (composite.left.condition_type === 'LEAF_NODE') {
return evaluateLeaf(composite.left);
}
if (composite.right.condition_type === 'COMPOSITE') {
left = evaluateComposite(composite.right);
} else if (composite.right.condition_type === 'LEAF_NODE') {
return evaluateLeaf(composite.right);
}
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)];
} else {
// console.log(evaluateComposite(transitionRules));
const answer = String(evaluateComposite(transitionRules));
const nextScreenName = actions[answer];
navigateToScreen(nextScreenName, {
journey: journey,
caseId,
});
console.log({nextScreenName, actions});
}
};
const onSubmit = data => {
console.log(data, 'data');
};
const onError = data => {
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>
);
};
const styles = StyleSheet.create({});
export default Widget;

View File

@@ -1,25 +1,61 @@
// @ts-nocheck
import {Button, Text, View} from 'react-native';
import React from 'react';
import {Template} from './types';
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 { increaseByOne } from '../../reducer/caseReducre';
import {increaseByOne} from '../../reducer/caseReducre';
import {navigateToScreen} from '../utlis/navigationUtlis';
interface RenderingEngine {
data: Template;
userData: {
id: string;
journeyOrder: Array<string>;
interactions: {
caseVerdict: string;
journeysMap: {
[id: string]: {
formData: {};
startWidget: string;
verdict: string;
addressId: string;
title: string;
completed: false;
isSynced: false;
};
};
};
};
}
const RenderingEngine: React.FC<RenderingEngine> = props => {
const dispatch = useDispatch();
const journey = props?.data?.journeys;
const journeyOrder = props?.data?.journey_order;
console.log(journey, journeyOrder, 'journey ');
const journeyOrder = props?.userData?.journeyOrder;
const data = useSelector((state: RootState) => state.counter.value);
console.log(data, 'cda');
const handleNextContext = (journey: EachJourney) => {
navigateToScreen(journey.startWidget, {
journey: journey.id,
caseId: props.userData.id,
});
};
const JourneyRendering = useMemo(
() =>
journeyOrder.map((eachJourney, index) => {
const journey =
props.data.journeys[eachJourney]
journeyOrder.map(eachJourney => console.log(journey[eachJourney]));
return (
<Pressable
onPress={() => handleNextContext(journey)}
key={index}>
<Text>{journey.name}</Text>
</Pressable>
);
}),
[journeyOrder, handleNextContext, props.userData],
);
const handlePress = () => {
dispatch(increaseByOne());
@@ -28,6 +64,7 @@ const RenderingEngine: React.FC<RenderingEngine> = props => {
return (
<View>
<Text>Rendering Engine {data}</Text>
{JourneyRendering}
<Button title="add todo" onPress={handlePress} />
</View>
);

View File

@@ -109,11 +109,7 @@ export interface J5 {
}
export interface Journeys {
j1: J1;
j2: J2;
j3: J3;
j4: J4;
j5: J5;
[id: string]: EachJourney;
}
export interface Left4 {
@@ -539,3 +535,48 @@ export interface Template {
questions: Questions;
options: Options;
}
// ENUMS
export enum Adderss {
COMMUNICATION = 'Communication',
PARMENENT = 'Parmanent',
LATEST_GEO = 'Latest geo location',
CALL_TO_CUSTOMER = 'Call to customer',
NEW_ADDRESS = 'New address',
}
export enum Operator {
MATCHES,
NOT_MATHES,
}
export enum ConditionType {
LEAF_OPERATOR,
COMPOSITE_OPERATOR,
}
// journey context
export interface EachJourney {
name: keyof typeof Adderss;
journeyType: string;
startWidget: string;
staticRules: {
operator: keyof typeof Operator;
conditionType: keyof typeof ConditionType;
left: {
operator: keyof typeof Operator;
conditionType: keyof typeof ConditionType;
questionId: string;
widgetId: string;
journeyId: string;
};
right: {
answer: string;
};
};
actions: {
true: string;
false: string;
};
}

View File

@@ -0,0 +1,31 @@
import {StackActions} from '@react-navigation/native';
import React, {RefObject} from 'react';
export const navigationRef: RefObject<any> = React.createRef();
// if screen already exists then navigate to it otherwise push screen
export function navigateToScreen(name: string, params: object = {}) {
navigationRef.current?.navigate(name, params);
}
// push a new screen on top of stack
export function pushToScreen(name: string, params: object = {}) {
navigationRef.current?.dispatch(StackActions.push(name, params));
}
export function popToScreen(count: number) {
navigationRef.current?.dispatch(StackActions.pop(count));
}
export function goBack() {
navigationRef.current?.goBack();
}
export function resetNavigation(params: {
routes: Array<{
name: string;
}>;
index: number | undefined;
}) {
navigationRef.current?.reset(params);
}

View File

@@ -1,30 +1,16 @@
{
"template_id": "t1",
"created_at": "",
"version": "v1",
"active": true,
"journey_order": [
"j1",
"j2",
"j3",
"j4",
"j5"
],
"journeys": {
"j1": {
"name": "communication_address_verification",
"journey_type": "address_verification",
"status_rules": {
"id": "j1",
"name": "COMMUNICATION",
"journeyType": "address_verification",
"startWidget": "w1",
"statusRules": {
"conditions": {
"operator": "MATCHES",
"condition_type": "LEAF_NODE",
"left": {
"questions_id": "q1"
},
"right": {
"value": "o1",
"type": "option"
}
"left": "q1",
"right":"o1"
},
"actions": {
"true": "verified",
@@ -34,24 +20,35 @@
"is_leaf": false
},
"j2": {
"name": "transition_after_communication",
"journey_type": "transition",
"status_rules": "",
"id": "j2",
"name": "PARMENENT",
"journeyType": "address_verification",
"startWidget": "w1",
"statusRules": {
"conditions": {
"operator": "MATCHES",
"condition_type": "LEAF_NODE",
"left": "q1",
"right":"o1"
},
"actions": {
"true": "verified",
"false": "unverified"
}
},
"is_leaf": false
},
"j3": {
"name": "permanent_address_verification",
"journey_type": "address_verification",
"status_rules": {
"id": "j3",
"name": "LATEST_GEO",
"journeyType": "address_verification",
"startWidget": "w1",
"statusRules": {
"conditions": {
"operator": "MATCHES",
"left": {
"questions_id": "q3"
},
"right": {
"value": "o7",
"type": "text"
}
"condition_type": "LEAF_NODE",
"left": "q1",
"right":"o1"
},
"actions": {
"true": "verified",
@@ -61,53 +58,84 @@
"is_leaf": false
},
"j4": {
"name": "calling",
"journey_type": "calling",
"status_rules": "",
"is_leaf": false
},
"j5": {
"name": "new_address_verification",
"journey_type": "address_verification",
"status_rules": {
"id": "j4",
"name": "CALL_TO_CUSTOMER",
"journeyType": "address_verification",
"startWidget": "w1",
"statusRules": {
"conditions": {
"operator": "MATCHES",
"left": {
"questions_id": "q7"
},
"right": {
"value": "o13",
"value/type": "option/text"
}
"condition_type": "LEAF_NODE",
"left": "q1",
"right":"o1"
},
"actions": {
"true": "verified",
"false": "unverified"
}
},
"is_leaf": true
"is_leaf": false
},
"j5": {
"id": "j5",
"name": "NEW_ADDRESS",
"journeyType": "address_verification",
"startWidget": "w1",
"statusRules": {
"conditions": {
"operator": "MATCHES",
"condition_type": "LEAF_NODE",
"left": "q1",
"right":"o1"
},
"actions": {
"true": "verified",
"false": "unverified"
}
},
"is_leaf": false
}
},
"widgets": {
"w1": {
"journey_id": "j1",
"sections": [
"s1"
"s1",
"s2"
],
"transition_rules": {
"transitionRules": {
"conditions": {
"operator": "MATCHES",
"left": {
"questions_id": "q1"
"operator": "AND",
"condition_type": "COMPOSITE",
"left":{
"operator": "MATCHES",
"condition_type": "COMPOSITE",
"right":{
"operator": "MATCHES",
"condition_type": "LEAF_NODE",
"left":"q1",
"right": "o1",
"section":"s1"
},
"left":{
"operator": "MATCHES",
"condition_type": "LEAF_NODE",
"left":"q1",
"right": "o1",
"section":"s1"
}
},
"right": {
"value": "o1",
"type": "option"
"right":{
"operator": "MATCHES",
"condition_type": "LEAF_NODE",
"left":"q1",
"right": "o1",
"section":"s1"
}
},
"actions": {
"true": "w2",
"false": "w5"
"false": "w3"
}
},
"is_leaf": false
@@ -117,7 +145,7 @@
"sections": [
"s2"
],
"transition_rules": {
"transitionRules": {
},
"is_leaf": true
@@ -127,7 +155,7 @@
"sections": [
"s3"
],
"transition_rules": {
"transitionRules": {
"conditions": {
"operator": "MATCHES",
"left": {
@@ -139,72 +167,13 @@
}
},
"actions": {
"true": "w7",
"false": "w8"
"true": "w2",
"false": "w1"
}
}
},
"is_leaf": true
},
"w4": {
"journey_id": "j2",
"sections": [
"s4"
],
"transition_rules": {
"conditions": {
"operator": "MATCHES",
"left": {
"questions_id": "q3"
},
"right": {
"value": "o9",
"type": "option"
}
},
"actions": {
"true": "w3",
"false": "w5"
}
},
"is_leaf": true
},
"w5": {
"journey_id": "j4",
"sections": [
"s5"
],
"transition_rules": {
"conditions": {
"operator": "MATCHES",
"left": {
"questions_id": "q6"
},
"right": {
"value": [
"o11",
"o12"
],
"type": "option"
}
},
"actions": {
"true": "w3",
"false": "w5"
}
},
"is_leaf": true
},
"w6": {
"journey_id": "j5",
"sections": [
"s6"
],
"transition_rules": {
},
"is_leaf": true
},
"sections": {
"s1": {
"label": "Section1",
@@ -215,7 +184,8 @@
"s2": {
"label": "Section2",
"questions": [
"q2"
"q2",
"q3"
]
},
"s3": {
@@ -247,19 +217,20 @@
"q1": {
"text": "Communication address question: Address found?",
"type": "mandatory",
"input_type": "single_select",
"input_type": "RadioButton",
"options": [
"o1",
"o2"
],
"metadata": {
"formatting_type": "radio"
"buttonType": "button",
"orientation": "verticle"
}
},
"q2": {
"text": "Communication address question: Reason for taking a loan",
"type": "mandatory",
"input_type": "multi_select",
"input_type": "RadioButton",
"options": [
"o5",
"o6",
@@ -267,25 +238,29 @@
"o8"
],
"metadata": {
"formatting_type": "checkbox"
"buttonType": "chip",
"orientation": "horizontal"
}
},
"q3": {
"text": "Permanent address question: xyz?",
"type": "mandatory",
"input_type": "single_select",
"input_type": "RadioButton",
"options": [
"o3",
"o4"
],
"metadata": {
"formatting_type": "radio"
"metadata": {
"buttonType": "button",
"orientation": "verticle"
}
}
},
"q4": {
"text": "Communication address question: Enter other reason for taking a loan",
"type": "mandatory",
"input_type": "text",
"input_type": "TextInput",
"options": [
],
@@ -296,37 +271,37 @@
"q5": {
"text": "Transition question: Permanent address withing 5 km?",
"type": "mandatory",
"input_type": "single_select",
"input_type": "RadioButton",
"options": [
"o3",
"o4"
],
"metadata": {
"formatting_type": "radio"
"formatting_type": "RadioButton"
}
},
"q6": {
"text": "Calling question: Status of call?",
"type": "mandatory",
"input_type": "single_select",
"input_type": "RadioButton",
"options": [
"o11",
"o12"
],
"metadata": {
"formatting_type": "radio"
"formatting_type": "RadioButton"
}
},
"q7": {
"text": "New Address Verification question: some question?",
"type": "mandatory",
"input_type": "multi_select",
"input_type": "RadioButton",
"options": [
"o5",
"o6"
],
"metadata": {
"formatting_type": "radio"
"formatting_type": "RadioButton"
}
}
},
@@ -334,7 +309,7 @@
"o1": {
"type": "single_select",
"text": "Found",
"associate_questions": [
"associateQuestions": [
],
"metadata": {
@@ -344,7 +319,7 @@
"o2": {
"type": "single_select",
"text": "Not Found",
"associate_questions": [
"associateQuestions": [
],
"metadata": {
@@ -354,7 +329,7 @@
"o3": {
"type": "single_select",
"text": "Yes",
"associate_questions": [
"associateQuestions": [
],
"metadata": {
@@ -364,7 +339,7 @@
"o4": {
"type": "single_select",
"text": "No",
"associate_questions": [
"associateQuestions": [
],
"metadata": {
@@ -374,7 +349,7 @@
"o5": {
"type": "multi_select",
"text": "Medical issue",
"associate_questions": [
"associateQuestions": [
],
"metadata": {
@@ -384,7 +359,7 @@
"o6": {
"type": "multi_select",
"text": "Covid",
"associate_questions": [
"associateQuestions": [
],
"metadata": {
@@ -394,7 +369,7 @@
"o7": {
"type": "multi_select",
"text": "Business purpose",
"associate_questions": [
"associateQuestions": [
],
"metadata": {
@@ -404,7 +379,7 @@
"o8": {
"type": "multi_select",
"text": "other",
"associate_questions": [
"associateQuestions": [
"q4"
],
"metadata": {
@@ -414,7 +389,7 @@
"o9": {
"type": "multi_select",
"text": "Flat",
"associate_questions": [
"associateQuestions": [
],
"metadata": {
@@ -424,7 +399,7 @@
"o10": {
"type": "multi_select",
"text": "city",
"associate_questions": [
"associateQuestions": [
],
"metadata": {
@@ -434,7 +409,7 @@
"o11": {
"type": "single_select",
"text": "PTP",
"associate_questions": [
"associateQuestions": [
],
"metadata": {
@@ -444,7 +419,7 @@
"o22": {
"type": "single_select",
"text": "RNR",
"associate_questions": [
"associateQuestions": [
],
"metadata": {

61
src/data/userData.json Normal file
View File

@@ -0,0 +1,61 @@
{
"id": "KJBL-KHBKLBS-MNBS-231",
"journeyOrder": [
"j1",
"j2",
"j3",
"j4",
"j5"
],
"version": "v1",
"interactions": {
"caseVerdict": "string",
"journeysMap": {
"j1": {
"formData": {},
"startWidget": "w1",
"verdict": "",
"addressId": "string",
"title": "Communication Address",
"completed": false,
"isSynced": false
},
"j2": {
"formData": {},
"startWidget": "w1",
"verdict": "",
"addressId": "string",
"title": "Permanent Address",
"completed": false,
"isSynced": false
},
"j3": {
"formData": {},
"startWidget": "w1",
"verdict": "",
"addressId": "string",
"title": "Geolocation Address",
"completed": false,
"isSynced": false
},
"j4": {
"formData": {},
"startWidget": "w1",
"verdict": "",
"addressId": "string",
"title": "Calling",
"completed": false,
"isSynced": false
},
"j5": {
"formData": {},
"startWidget": "w1",
"verdict": "",
"addressId": "string",
"title": "New address",
"completed": false,
"isSynced": false
}
}
}
}

View File

@@ -4,6 +4,7 @@ export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0,
caseForm: {},
},
reducers: {
increaseByOne: state => {
@@ -12,9 +13,29 @@ export const counterSlice = createSlice({
decreaseByOne: state => {
state.value--;
},
updateInteraction: (state, action) => {
const {caseId, journeyId, widgetId, questionId, answer, sectionId} =
action.payload;
const data = state.caseForm || {};
if (!data[caseId]) {
data[caseId] = {};
}
if (!data[caseId][journeyId]) {
data[caseId][journeyId] = {};
}
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;
state.caseForm = data;
},
},
});
export const {increaseByOne, decreaseByOne} = counterSlice.actions;
export const {increaseByOne, decreaseByOne, updateInteraction} =
counterSlice.actions;
export default counterSlice.reducer;

17
src/reducer/formData.ts Normal file
View File

@@ -0,0 +1,17 @@
import {createSlice} from '@reduxjs/toolkit';
export const formReducer = createSlice({
name: 'formData',
initialState: {
value: 0,
},
reducers: {
decreaseByOne: state => {
state.value--;
},
},
});
export const {decreaseByOne} = formReducer.actions;
export default formReducer.reducer;

View File

@@ -1,8 +1,10 @@
import {combineReducers} from 'redux';
import caseReducer from './caseReducre';
import formReducer from './formData';
const rootReducer = combineReducers({
caseDetail: caseReducer,
formData: formReducer,
});
export default rootReducer;

View File

@@ -5,6 +5,11 @@
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Completeness */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
"paths": {
"@navi/RN-UI/*":[
"./RN-UI-LIB/src/componets/*"
]
}
}
}

107
yarn.lock
View File

@@ -1412,6 +1412,48 @@
resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-2.0.0.tgz#4c40b74655c83982c8cf47530ee7dc13d957b6aa"
integrity sha512-K0aGNn1TjalKj+65D7ycc1//H9roAQ51GJVk5ZJQFb2teECGmzd86bYDC0aYdbRf7gtovescq4Zt6FR0tgXiHQ==
"@react-navigation/core@^6.4.3":
version "6.4.3"
resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-6.4.3.tgz#5609bab95e3080d190eff46a64e52cc06eb0c4cf"
integrity sha512-+HGHeEq7GK029Jy2jFkV2uQYc6a6AurjjUAVFlSz5tsNo4L5E3ZCzo7sk5+lcvt0Agdedf5Q+wTiWjT7IrixgA==
dependencies:
"@react-navigation/routers" "^6.1.5"
escape-string-regexp "^4.0.0"
nanoid "^3.1.23"
query-string "^7.0.0"
react-is "^16.13.0"
use-latest-callback "^0.1.5"
"@react-navigation/elements@^1.3.9":
version "1.3.9"
resolved "https://registry.yarnpkg.com/@react-navigation/elements/-/elements-1.3.9.tgz#33e26d7ad655b012e024ef0a005a3f66201287f8"
integrity sha512-V9aIZN19ufaKWlXT4UcM545tDiEt9DIQS+74pDgbnzoQcDypn0CvSqWopFhPACMdJatgmlZUuOrrMfTeNrBWgA==
"@react-navigation/native-stack@^6.9.4":
version "6.9.4"
resolved "https://registry.yarnpkg.com/@react-navigation/native-stack/-/native-stack-6.9.4.tgz#d9cc26ad97afcee1c0e3fb092ae4c60f848b1572"
integrity sha512-R40G2Zfo748hE4+we/TUAEClw53l0QdFDJ0q/9VS1moxgI4zUopdBxN5SmF32OMFfkedMRAT9J+aVbwgmdn7pA==
dependencies:
"@react-navigation/elements" "^1.3.9"
warn-once "^0.1.0"
"@react-navigation/native@^6.0.16":
version "6.0.16"
resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-6.0.16.tgz#a37df62da9db912c91c53e2cdeadb954865a6a9b"
integrity sha512-YVmzypkDppV/vAG+66KTJ2RFtPjhDTLLjgk8TNTCHG3pahq1q13zbnEPjqB42bU4kgL5SG17O4saErt1DJaWQg==
dependencies:
"@react-navigation/core" "^6.4.3"
escape-string-regexp "^4.0.0"
fast-deep-equal "^3.1.3"
nanoid "^3.1.23"
"@react-navigation/routers@^6.1.5":
version "6.1.5"
resolved "https://registry.yarnpkg.com/@react-navigation/routers/-/routers-6.1.5.tgz#b3e06bc09346ad94206bcc71c46538d5b6dc4883"
integrity sha512-JzMRiRRu8J0yUMC7BV8wOVzevjkHnIPONbpCTL/vH5yceTm+dSH/U3esIObgk8wYYbov+jYlVhwUQNGRb2to6g==
dependencies:
nanoid "^3.1.23"
"@reduxjs/toolkit@1.9.1":
version "1.9.1"
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.1.tgz#4c34dc4ddcec161535288c60da5c19c3ef15180e"
@@ -3408,6 +3450,11 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
filter-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b"
integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==
finalhandler@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
@@ -5424,6 +5471,11 @@ ms@2.1.3, ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
nanoid@^3.1.23:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
@@ -5986,6 +6038,16 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
query-string@^7.0.0:
version "7.1.1"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.1.tgz#754620669db978625a90f635f12617c271a088e1"
integrity sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==
dependencies:
decode-uri-component "^0.2.0"
filter-obj "^1.1.0"
split-on-first "^1.0.0"
strict-uri-encode "^2.0.0"
querystringify@^2.1.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
@@ -6009,12 +6071,22 @@ react-devtools-core@4.24.0:
shell-quote "^1.6.1"
ws "^7"
react-freeze@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/react-freeze/-/react-freeze-1.0.3.tgz#5e3ca90e682fed1d73a7cb50c2c7402b3e85618d"
integrity sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g==
react-hook-form@7.40.0:
version "7.40.0"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.40.0.tgz#62bc939dddca88522cd7f5135b6603192ccf7e17"
integrity sha512-0rokdxMPJs0k9bvFtY6dbcSydyNhnZNXCR49jgDr/aR03FDHFOK6gfh8ccqB3fl696Mk7lqh04xdm+agqWXKSw==
"react-is@^16.12.0 || ^17.0.0 || ^18.0.0", react-is@^18.0.0, react-is@^18.1.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
react-is@^16.13.1, react-is@^16.7.0:
react-is@^16.13.0, react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -6039,6 +6111,19 @@ react-native-gradle-plugin@^0.70.3:
resolved "https://registry.yarnpkg.com/react-native-gradle-plugin/-/react-native-gradle-plugin-0.70.3.tgz#cbcf0619cbfbddaa9128701aa2d7b4145f9c4fc8"
integrity sha512-oOanj84fJEXUg9FoEAQomA8ISG+DVIrTZ3qF7m69VQUJyOGYyDZmPqKcjvRku4KXlEH6hWO9i4ACLzNBh8gC0A==
react-native-safe-area-context@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-4.4.1.tgz#239c60b8a9a80eac70a38a822b04c0f1d15ffc01"
integrity sha512-N9XTjiuD73ZpVlejHrUWIFZc+6Z14co1K/p1IFMkImU7+avD69F3y+lhkqA2hN/+vljdZrBSiOwXPkuo43nFQA==
react-native-screens@^3.18.2:
version "3.18.2"
resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-3.18.2.tgz#d7ab2d145258d3db9fa630fa5379dc4474117866"
integrity sha512-ANUEuvMUlsYJ1QKukEhzhfrvOUO9BVH9Nzg+6eWxpn3cfD/O83yPBOF8Mx6x5H/2+sMy+VS5x/chWOOo/U7QJw==
dependencies:
react-freeze "^1.0.0"
warn-once "^0.1.0"
react-native@0.70.6:
version "0.70.6"
resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.70.6.tgz#d692f8b51baffc28e1a8bc5190cdb779de937aa8"
@@ -6713,6 +6798,11 @@ spdx-license-ids@^3.0.0:
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz#69077835abe2710b65f03969898b6637b505a779"
integrity sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==
split-on-first@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
split-string@^3.0.1, split-string@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
@@ -6767,6 +6857,11 @@ stream-buffers@2.2.x:
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
integrity sha512-uyQK/mx5QjHun80FLJTfaWE7JtwfRMKBLkMne6udYOmvH0CawotVa7TfgYHzAnpphn4+TweIx1QKMnRIbipmUg==
strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==
string-length@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
@@ -7230,6 +7325,11 @@ url-parse@^1.5.3:
querystringify "^2.1.1"
requires-port "^1.0.0"
use-latest-callback@^0.1.5:
version "0.1.5"
resolved "https://registry.yarnpkg.com/use-latest-callback/-/use-latest-callback-0.1.5.tgz#a4a836c08fa72f6608730b5b8f4bbd9c57c04f51"
integrity sha512-HtHatS2U4/h32NlkhupDsPlrbiD27gSH5swBdtXbCAlc6pfOFzaj0FehW/FO12rx8j2Vy4/lJScCiJyM01E+bQ==
use-sync-external-store@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
@@ -7308,6 +7408,11 @@ walker@^1.0.7, walker@~1.0.5:
dependencies:
makeerror "1.0.12"
warn-once@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/warn-once/-/warn-once-0.1.1.tgz#952088f4fb56896e73fd4e6a3767272a3fccce43"
integrity sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==
wcwidth@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"