Merge branch 'all_cases_case_details_api_integration' of github.cmd.navi-tech.in:medici/Address-Verification-App into filters
# Conflicts: # src/reducer/allCasesSlice.ts # src/screens/allCases/AllCases.tsx
This commit is contained in:
@@ -15,21 +15,11 @@ import Login from './src/screens/login';
|
||||
import OtpInput from './src/screens/login/OtpInput';
|
||||
import TodoList from './src/screens/todoList/TodoList';
|
||||
import { RootState } from './src/store/store';
|
||||
import Profile from './src/screens/Profile';
|
||||
import interactionsHandler from './src/screens/caseDetails/interactionsHandler';
|
||||
|
||||
const Stack = createNativeStackNavigator();
|
||||
|
||||
const LoginScreen = () => <Login />;
|
||||
|
||||
const OTPScreen = () => <OtpInput />;
|
||||
|
||||
// const HomeScreen = () => (
|
||||
// <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
|
||||
// <SafeAreaView>
|
||||
// <RenderingEngine data={data} userData={userData} />
|
||||
// </SafeAreaView>
|
||||
// </View>
|
||||
// );
|
||||
|
||||
const ProtectedRouter = () => {
|
||||
const user = useSelector(
|
||||
(state: RootState) => state.user,
|
||||
@@ -39,7 +29,7 @@ const ProtectedRouter = () => {
|
||||
|
||||
// for setting user token in global.ts for api calling's
|
||||
setGlobalUserData(sessionDetails?.sessionToken);
|
||||
|
||||
const d = interactionsHandler()
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
if (!deviceId) {
|
||||
@@ -57,6 +47,14 @@ const ProtectedRouter = () => {
|
||||
header: () => null,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Profile"
|
||||
component={Profile}
|
||||
options={{
|
||||
header: () => null,
|
||||
animation: 'slide_from_right'
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="caseDetail"
|
||||
component={CaseDetails}
|
||||
@@ -71,6 +69,7 @@ const ProtectedRouter = () => {
|
||||
component={Widget}
|
||||
options={{
|
||||
header: () => null,
|
||||
animation: 'slide_from_right'
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
@@ -79,6 +78,7 @@ const ProtectedRouter = () => {
|
||||
component={TodoList}
|
||||
options={{
|
||||
header: () => null,
|
||||
animation: 'slide_from_bottom'
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
@@ -86,14 +86,14 @@ const ProtectedRouter = () => {
|
||||
<>
|
||||
<Stack.Screen
|
||||
name="Login"
|
||||
component={LoginScreen}
|
||||
component={Login}
|
||||
options={{
|
||||
header: () => null,
|
||||
}}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="OTP"
|
||||
component={OTPScreen}
|
||||
component={OtpInput}
|
||||
options={{
|
||||
header: () => null,
|
||||
}}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {IUser, setAuthData} from '../reducer/userSlice';
|
||||
import axiosInstance, {ApiKeys, getApiUrl} from '../components/utlis/apiHelper';
|
||||
import {
|
||||
resetLoginForm,
|
||||
setFormLoading,
|
||||
setOTPError,
|
||||
setShowOTPScreen,
|
||||
@@ -10,8 +11,8 @@ import {
|
||||
import {Dispatch} from '@reduxjs/toolkit';
|
||||
import {navigateToScreen} from '../components/utlis/navigationUtlis';
|
||||
import {AxiosResponse} from 'axios';
|
||||
import { updateCaseList } from './dataActions';
|
||||
import { setCasesListData } from '../reducer/allCasesSlice';
|
||||
import {AppDispatch} from '../store/store';
|
||||
import {setGlobalUserData} from '../constants/Global';
|
||||
|
||||
export interface GenerateOTPPayload {
|
||||
phoneNumber: string;
|
||||
@@ -71,8 +72,26 @@ export const verifyOTP =
|
||||
}),
|
||||
);
|
||||
dispatch(setVerifyOTPSuccess('OTP verified'));
|
||||
dispatch(resetLoginForm());
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(setVerifyOTPError('Invalid OTP, try again'));
|
||||
});
|
||||
};
|
||||
|
||||
export const logout = () => (dispatch: AppDispatch) => {
|
||||
const url = getApiUrl(ApiKeys.LOGOUT);
|
||||
axiosInstance
|
||||
.get(url)
|
||||
.then(response => {
|
||||
setGlobalUserData('');
|
||||
dispatch(
|
||||
setAuthData({
|
||||
sessionDetails: null,
|
||||
user: null,
|
||||
isLoggedIn: false,
|
||||
}),
|
||||
);
|
||||
})
|
||||
.catch(err => console.log(err));
|
||||
};
|
||||
|
||||
@@ -1,24 +1,68 @@
|
||||
import {Dispatch} from 'redux';
|
||||
import axiosInstance, {ApiKeys, getApiUrl} from '../components/utlis/apiHelper';
|
||||
import {setCasesListData} from '../reducer/allCasesSlice';
|
||||
import {navigateToScreen} from '../components/utlis/navigationUtlis';
|
||||
import {
|
||||
resetTodoList,
|
||||
setCasesListData,
|
||||
setLoading,
|
||||
setTodoListOffline,
|
||||
} from '../reducer/allCasesSlice';
|
||||
import {ICaseItem} from '../screens/allCases/interface';
|
||||
import {AppDispatch} from '../store/store';
|
||||
|
||||
export const getAllCases = () => (dispatch: Dispatch) => {
|
||||
export const getAllCases = () => (dispatch: AppDispatch) => {
|
||||
const url = getApiUrl(ApiKeys.ALL_CASES);
|
||||
axiosInstance.get(url).then(async response => {
|
||||
const caseDetails = await getAllCaseDetails(response.data)
|
||||
dispatch(setCasesListData({allCases : response.data, details: caseDetails }));
|
||||
dispatch(setLoading(true));
|
||||
axiosInstance.get(url).then(response => {
|
||||
dispatch(getAllCaseDetails(response.data));
|
||||
});
|
||||
};
|
||||
|
||||
export const getAllCaseDetails = async (data: Array<ICaseItem>) => {
|
||||
const caseList = data.map(caseItem => caseItem.caseReferenceId);
|
||||
const url = getApiUrl(ApiKeys.CASE_DETAIL);
|
||||
try {
|
||||
const result = await axiosInstance.get(url, {params: {caseIds: caseList.join(',')}})
|
||||
console.log(result)
|
||||
return await result.data;
|
||||
} catch (error) {
|
||||
return {};
|
||||
}
|
||||
export const getAllCaseDetails =
|
||||
(data: Array<ICaseItem>) => (dispatch: AppDispatch) => {
|
||||
const caseList = data.map(caseItem => caseItem.caseReferenceId);
|
||||
const url = getApiUrl(ApiKeys.CASE_DETAIL);
|
||||
axiosInstance
|
||||
.get(url, {
|
||||
params: {caseIds: caseList.join(',')},
|
||||
})
|
||||
.then(response => {
|
||||
dispatch(
|
||||
setCasesListData({allCases: data, details: response.data}),
|
||||
);
|
||||
dispatch(resetTodoList());
|
||||
})
|
||||
.catch(err => console.log(err));
|
||||
};
|
||||
|
||||
export const postPinnedList =
|
||||
(pinnedCases: ICaseItem[], updatedCaseList: ICaseItem[]) =>
|
||||
(dispatch: AppDispatch) => {
|
||||
dispatch(setTodoListOffline(updatedCaseList));
|
||||
navigateToScreen('Home');
|
||||
const payload = pinnedCases
|
||||
.map(caseItem => caseItem.caseReferenceId)
|
||||
.join('&pins=');
|
||||
const url = getApiUrl(ApiKeys.PINNED_CASES);
|
||||
axiosInstance
|
||||
.post(url + `?pins=${payload}`)
|
||||
.then(response => {
|
||||
dispatch(getAllCases());
|
||||
})
|
||||
.catch(err => {
|
||||
dispatch(setTodoListOffline(updatedCaseList));
|
||||
});
|
||||
};
|
||||
|
||||
export const syncCaseDetail = (data: any) => (dispatch: AppDispatch) => {
|
||||
const url = getApiUrl(ApiKeys.FEEDBACK);
|
||||
|
||||
console.log(data);
|
||||
axiosInstance
|
||||
.post(url, {
|
||||
id: data.id,
|
||||
...data,
|
||||
})
|
||||
.then(res => console.log(res.data))
|
||||
.catch(err => console.log(err, 'error'));
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ const IconLabel: React.FC<IconLabelProps> = props => {
|
||||
<View style={[styles.icon, iconStyle]}>
|
||||
{icon ? icon : <BulletIcon />}
|
||||
</View>
|
||||
<Text style={textStyle}>{text}</Text>
|
||||
<Text light style={textStyle}>{text}</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
49
src/components/floatingInfoText/index.tsx
Normal file
49
src/components/floatingInfoText/index.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import {View, StyleSheet} from 'react-native';
|
||||
import React from 'react';
|
||||
import {GenericStyles, getShadowStyle} from '../../../RN-UI-LIB/src/styles';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import {COLORS} from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import InfoIcon from '../../../RN-UI-LIB/src/Icons/InfoIcon';
|
||||
|
||||
interface IFloatingInfoText {
|
||||
top?: number;
|
||||
bottom?: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
const FloatingInfoText: React.FC<IFloatingInfoText> = ({message, top, bottom}) => {
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
styles.container,
|
||||
GenericStyles.centerAlignedRow,
|
||||
{top, bottom},
|
||||
]}>
|
||||
<View style={[styles.textContainer, getShadowStyle(2), GenericStyles.centerAlignedRow]}>
|
||||
<InfoIcon color={COLORS.BASE.BLUE} />
|
||||
<Text small style={styles.text}>
|
||||
{message}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
position: 'absolute',
|
||||
width: '100%',
|
||||
},
|
||||
textContainer: {
|
||||
paddingHorizontal: 30,
|
||||
paddingVertical: 3,
|
||||
borderRadius: 4,
|
||||
backgroundColor: COLORS.BACKGROUND.BLUE,
|
||||
},
|
||||
text: {
|
||||
color: COLORS.BASE.BLUE,
|
||||
marginLeft: 10
|
||||
},
|
||||
});
|
||||
|
||||
export default FloatingInfoText;
|
||||
@@ -1,18 +1,18 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import React, {useEffect} from 'react';
|
||||
import {View} from 'react-native';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { Control, Controller } from 'react-hook-form';
|
||||
import { useSelector } from 'react-redux';
|
||||
import RNDropDown from '../../../../RN-UI-LIB/src/components/dropdown/Dropdown';
|
||||
import RNOptions from '../../../../RN-UI-LIB/src/components/dropdown/Options';
|
||||
import {useState} from 'react';
|
||||
import {Control, Controller} from 'react-hook-form';
|
||||
import {useSelector} from 'react-redux';
|
||||
import RNCheckboxGroup from '../../../../RN-UI-LIB/src/components/chechbox/CheckboxGroup';
|
||||
import {ICheckboxOption} from '../../../../RN-UI-LIB/src/components/chechbox/types';
|
||||
import Text from '../../../../RN-UI-LIB/src/components/Text';
|
||||
import { GenericStyles } from '../../../../RN-UI-LIB/src/styles';
|
||||
import template from '../../../data/RealTemplateData.json';
|
||||
import { RootState } from '../../../store/store';
|
||||
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
|
||||
import {RootState} from '../../../store/store';
|
||||
import {AnswerType} from '../interface';
|
||||
import QuestionRenderingEngine from '../QuestionRenderingEngine';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import RNCheckboxGroup from '../../../../RN-UI-LIB/src/components/chechbox/CheckboxGroup';
|
||||
import {useAppSelector } from '../../../hooks';
|
||||
|
||||
interface ICheckBoxGroup {
|
||||
questionType: string;
|
||||
@@ -27,6 +27,7 @@ interface ICheckBoxGroup {
|
||||
|
||||
const CheckBoxGroup: React.FC<ICheckBoxGroup> = props => {
|
||||
const {questionId, widgetId, journeyId, caseId, sectionId, error} = props;
|
||||
const template = useAppSelector(state => state.case.templateData)
|
||||
const question =
|
||||
template.questions[questionId as keyof typeof template.questions];
|
||||
const options = template.options;
|
||||
@@ -36,9 +37,7 @@ const CheckBoxGroup: React.FC<ICheckBoxGroup> = props => {
|
||||
|
||||
const dataFromRedux = useSelector(
|
||||
(state: RootState) =>
|
||||
state.case.caseForm?.[caseId]?.[journeyId]?.[widgetId]?.[
|
||||
sectionId
|
||||
]?.[questionId],
|
||||
state.case.caseForm?.[caseId]?.[journeyId]?.widgetContext?.[widgetId]?.sectionContext?.[sectionId]?.questionContext?.[questionId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -48,27 +47,6 @@ const CheckBoxGroup: React.FC<ICheckBoxGroup> = props => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dataFromRedux]);
|
||||
|
||||
// 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: keyof typeof options) => {
|
||||
if (options[optionId]?.associateQuestions.length < 1) {
|
||||
setAssociatedQuestions([]);
|
||||
@@ -77,30 +55,52 @@ const CheckBoxGroup: React.FC<ICheckBoxGroup> = props => {
|
||||
setAssociatedQuestions(options[optionId]?.associateQuestions);
|
||||
};
|
||||
|
||||
const optiosList = question.options.map(option =>({label: options[option].text, value: option}));
|
||||
const optiosList = question.options.map((option: any) => ({
|
||||
label: options[option].text,
|
||||
value: option,
|
||||
}));
|
||||
|
||||
const handleChange = (
|
||||
change: Array<ICheckboxOption> | null,
|
||||
onChange: (...event: any[]) => void,
|
||||
) => {
|
||||
const values = change?.map(item => item.value);
|
||||
onChange({
|
||||
answer: values,
|
||||
type: AnswerType.array,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={GenericStyles.mt12}>
|
||||
{question.text ?<Text dark bold>
|
||||
{question.text}{' '}
|
||||
{question.type === 'mandatory' && (
|
||||
<Text style={GenericStyles.redText}>*</Text>
|
||||
)}
|
||||
</Text>: null}
|
||||
{question.text ? (
|
||||
<Text dark bold>
|
||||
{question.text}{' '}
|
||||
{question.type === 'mandatory' && (
|
||||
<Text style={GenericStyles.redText}>*</Text>
|
||||
)}
|
||||
</Text>
|
||||
) : null}
|
||||
<Controller
|
||||
control={props.control}
|
||||
rules={{
|
||||
required: question.type === 'mandatory',
|
||||
}}
|
||||
render={({field: {onChange, value}}) => {
|
||||
console.log(value)
|
||||
return(
|
||||
<RNCheckboxGroup onSelectionChange={(cange => {const values = cange?.map(item=>item.value); onChange(values)})} defaultValue={value} options={optiosList} />
|
||||
)
|
||||
console.log(value);
|
||||
return (
|
||||
<RNCheckboxGroup
|
||||
onSelectionChange={change =>
|
||||
handleChange(change, onChange)
|
||||
}
|
||||
defaultValue={value?.answer}
|
||||
options={optiosList}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
name={`${sectionId}.${questionId}`}
|
||||
name={`widgetContext.${widgetId}.sectionContext.${props.sectionId}.questionContext.${questionId}`}
|
||||
/>
|
||||
<ErrorMessage show={error?.[sectionId]?.[questionId]} />
|
||||
<ErrorMessage show={error?.sectionContext?.[sectionId]?.questionContext?.[questionId]} />
|
||||
{associatedQuestions?.map((nextQuestion: string, index) => {
|
||||
if (
|
||||
template.questions[
|
||||
|
||||
@@ -4,17 +4,15 @@ import {View} from 'react-native';
|
||||
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 RadioGroup from '../../../../RN-UI-LIB/src/components/radio_button/RadioGroup';
|
||||
import RNDropDown from '../../../../RN-UI-LIB/src/components/dropdown/Dropdown';
|
||||
import RNOptions from '../../../../RN-UI-LIB/src/components/dropdown/Options';
|
||||
import Text from '../../../../RN-UI-LIB/src/components/Text';
|
||||
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
|
||||
import template from '../../../data/RealTemplateData.json';
|
||||
import {RootState} from '../../../store/store';
|
||||
import QuestionRenderingEngine from '../QuestionRenderingEngine';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import RNDropDown from '../../../../RN-UI-LIB/src/components/dropdown/Dropdown';
|
||||
import RNOptions from '../../../../RN-UI-LIB/src/components/dropdown/Options';
|
||||
import {AnswerType, Options} from '../interface';
|
||||
import { useAppSelector } from '../../../hooks';
|
||||
|
||||
interface IDropDown {
|
||||
questionType: string;
|
||||
@@ -29,6 +27,7 @@ interface IDropDown {
|
||||
|
||||
const DropDown: React.FC<IDropDown> = props => {
|
||||
const {questionId, widgetId, journeyId, caseId, sectionId, error} = props;
|
||||
const template = useAppSelector(state => state.case.templateData);
|
||||
const question =
|
||||
template.questions[questionId as keyof typeof template.questions];
|
||||
const options = template.options;
|
||||
@@ -38,9 +37,7 @@ const DropDown: React.FC<IDropDown> = props => {
|
||||
|
||||
const dataFromRedux = useSelector(
|
||||
(state: RootState) =>
|
||||
state.case.caseForm?.[caseId]?.[journeyId]?.[widgetId]?.[
|
||||
sectionId
|
||||
]?.[questionId],
|
||||
state.case.caseForm?.[caseId]?.[journeyId]?.widgetContext?.[widgetId]?.sectionContext?.[sectionId]?.questionContext?.[questionId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -50,27 +47,6 @@ const DropDown: React.FC<IDropDown> = props => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dataFromRedux]);
|
||||
|
||||
// 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: keyof typeof options) => {
|
||||
if (options[optionId]?.associateQuestions.length < 1) {
|
||||
setAssociatedQuestions([]);
|
||||
@@ -79,6 +55,16 @@ const DropDown: React.FC<IDropDown> = props => {
|
||||
setAssociatedQuestions(options[optionId]?.associateQuestions);
|
||||
};
|
||||
|
||||
const handleChange = (
|
||||
change: string | null,
|
||||
onChange: (...event: any[]) => void,
|
||||
) => {
|
||||
onChange({
|
||||
answer: change,
|
||||
type: AnswerType.option,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={GenericStyles.mt12}>
|
||||
<Text dark bold style={GenericStyles.mb12}>
|
||||
@@ -93,24 +79,25 @@ const DropDown: React.FC<IDropDown> = props => {
|
||||
required: question.type === 'mandatory',
|
||||
}}
|
||||
render={({field: {onChange, value}}) => (
|
||||
<RNDropDown bottomSheetHeight={question.options.length -1 * 10} onValueChange={onChange} value={value}>
|
||||
{question.options.map(option => {
|
||||
return(
|
||||
<RNOptions
|
||||
id={option}
|
||||
label={
|
||||
options[
|
||||
option as keyof typeof options
|
||||
]?.text
|
||||
}
|
||||
/>
|
||||
)})}
|
||||
|
||||
<RNDropDown
|
||||
bottomSheetHeight={question.options.length - 1 * 10}
|
||||
onValueChange={change => handleChange(change, onChange)}
|
||||
value={value?.answer}>
|
||||
{question.options.map((option: keyof typeof options) => {
|
||||
return (
|
||||
<RNOptions
|
||||
id={option as string}
|
||||
label={
|
||||
options[option]?.text
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</RNDropDown>
|
||||
)}
|
||||
name={`${sectionId}.${questionId}`}
|
||||
name={`widgetContext.${widgetId}.sectionContext.${props.sectionId}.questionContext.${questionId}`}
|
||||
/>
|
||||
<ErrorMessage show={error?.[sectionId]?.[questionId]} />
|
||||
<ErrorMessage show={error?.sectionContext?.[sectionId]?.questionContext?.[questionId]} />
|
||||
{associatedQuestions?.map((nextQuestion: string, index) => {
|
||||
if (
|
||||
template.questions[
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { Control, Controller } from 'react-hook-form';
|
||||
import {
|
||||
Image,
|
||||
ImageBackground,
|
||||
Pressable,
|
||||
StyleSheet,
|
||||
View,
|
||||
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';
|
||||
|
||||
import template from '../../../data/RealTemplateData.json';
|
||||
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
|
||||
import {useState} from 'react';
|
||||
import {useSelector} from 'react-redux';
|
||||
import {RootState} from '../../../store/store';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import DeleteIcon from '../../../../RN-UI-LIB/src/Icons/DeleteIcon';
|
||||
import {COLORS} from '../../../../RN-UI-LIB/src/styles/colors';
|
||||
import { useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import Text from '../../../../RN-UI-LIB/src/components/Text';
|
||||
import DeleteIcon from '../../../../RN-UI-LIB/src/Icons/DeleteIcon';
|
||||
import { GenericStyles } from '../../../../RN-UI-LIB/src/styles';
|
||||
import { COLORS } from '../../../../RN-UI-LIB/src/styles/colors';
|
||||
import { useAppSelector } from '../../../hooks';
|
||||
import { RootState } from '../../../store/store';
|
||||
import { AnswerType } from '../interface';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
|
||||
interface IImageUpload {
|
||||
questionType: string;
|
||||
@@ -33,13 +33,12 @@ interface IImageUpload {
|
||||
const ImageUpload: React.FC<IImageUpload> = props => {
|
||||
const {questionId, error, sectionId, caseId, journeyId, widgetId} = props;
|
||||
const [image, setImage] = useState('');
|
||||
const template = useAppSelector(state => state.case.templateData);
|
||||
const question =
|
||||
template.questions[questionId as keyof typeof template.questions];
|
||||
const dataFromRedux = useSelector(
|
||||
(state: RootState) =>
|
||||
state.case.caseForm?.[caseId]?.[journeyId]?.[widgetId]?.[
|
||||
sectionId
|
||||
]?.[questionId],
|
||||
state.case.caseForm?.[caseId]?.[journeyId]?.widgetContext?.[widgetId]?.sectionContext?.[sectionId]?.questionContext?.[questionId]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -51,6 +50,19 @@ const ImageUpload: React.FC<IImageUpload> = props => {
|
||||
if (!question) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleChange = (
|
||||
clickedImage: string | null,
|
||||
onChange: (...event: any[]) => void,
|
||||
) => {
|
||||
const data = `data:image/jpeg;base64,${clickedImage}`;
|
||||
setImage(data);
|
||||
onChange({
|
||||
answer: data,
|
||||
type: AnswerType.text,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={[GenericStyles.mt12]}>
|
||||
<Text dark bold style={GenericStyles.mb12}>
|
||||
@@ -67,14 +79,10 @@ const ImageUpload: React.FC<IImageUpload> = props => {
|
||||
}}
|
||||
render={({field: {onChange}}) => (
|
||||
<CameraClickPicture
|
||||
onPictureClickSuccess={clickedImage => {
|
||||
const data = `data:image/jpeg;base64,${clickedImage}`;
|
||||
setImage(data);
|
||||
onChange(data);
|
||||
}}
|
||||
onPictureClickSuccess={clickedImage => handleChange(clickedImage, onChange)}
|
||||
/>
|
||||
)}
|
||||
name={`${props.sectionId}.${questionId}`}
|
||||
name={`widgetContext.${widgetId}.sectionContext.${props.sectionId}.questionContext.${questionId}`}
|
||||
/>
|
||||
) : (
|
||||
<View>
|
||||
@@ -87,7 +95,7 @@ const ImageUpload: React.FC<IImageUpload> = props => {
|
||||
</ImageBackground>
|
||||
</View>
|
||||
)}
|
||||
<ErrorMessage show={error?.[sectionId]?.[questionId]} />
|
||||
<ErrorMessage show={error?.sectionContext?.[sectionId]?.questionContext?.[questionId]} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -9,10 +9,11 @@ import RadioChip from '../../../../RN-UI-LIB/src/components/radio_button/RadioCh
|
||||
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/RealTemplateData.json';
|
||||
import {RootState} from '../../../store/store';
|
||||
import QuestionRenderingEngine from '../QuestionRenderingEngine';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import {AnswerType} from '../interface';
|
||||
import {useAppSelector} from '../../../hooks';
|
||||
|
||||
interface IRadioButton {
|
||||
questionType: string;
|
||||
@@ -27,8 +28,8 @@ interface IRadioButton {
|
||||
|
||||
const RadioButton: React.FC<IRadioButton> = props => {
|
||||
const {questionId, widgetId, journeyId, caseId, sectionId, error} = props;
|
||||
const question =
|
||||
template.questions[questionId as keyof typeof template.questions];
|
||||
const template = useAppSelector(state => state.case.templateData);
|
||||
const question = template.questions[questionId];
|
||||
const options = template.options;
|
||||
const [associatedQuestions, setAssociatedQuestions] = useState<
|
||||
Array<string>
|
||||
@@ -36,9 +37,9 @@ const RadioButton: React.FC<IRadioButton> = props => {
|
||||
|
||||
const dataFromRedux = useSelector(
|
||||
(state: RootState) =>
|
||||
state.case.caseForm?.[caseId]?.[journeyId]?.[widgetId]?.[
|
||||
sectionId
|
||||
]?.[questionId],
|
||||
state.case.caseForm?.[caseId]?.[journeyId]?.widgetContext?.[
|
||||
widgetId
|
||||
]?.sectionContext?.[sectionId]?.questionContext?.[questionId],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -48,27 +49,6 @@ const RadioButton: React.FC<IRadioButton> = props => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dataFromRedux]);
|
||||
|
||||
// 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: keyof typeof options) => {
|
||||
if (options[optionId]?.associateQuestions.length < 1) {
|
||||
setAssociatedQuestions([]);
|
||||
@@ -77,6 +57,17 @@ const RadioButton: React.FC<IRadioButton> = props => {
|
||||
setAssociatedQuestions(options[optionId]?.associateQuestions);
|
||||
};
|
||||
|
||||
const handleChange = (
|
||||
change: string | null,
|
||||
onChange: (...event: any[]) => void,
|
||||
) => {
|
||||
computeNextQuestion(change as keyof typeof options);
|
||||
onChange({
|
||||
answer: change,
|
||||
type: AnswerType.option,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={GenericStyles.mt12}>
|
||||
<Text dark bold>
|
||||
@@ -92,43 +83,42 @@ const RadioButton: React.FC<IRadioButton> = props => {
|
||||
}}
|
||||
render={({field: {onChange, value}}) => (
|
||||
<RadioGroup
|
||||
value={value}
|
||||
onValueChange={change => {
|
||||
onChange(change);
|
||||
computeNextQuestion(change as keyof typeof options);
|
||||
// registerValue(change);
|
||||
}}
|
||||
value={value?.answer}
|
||||
onValueChange={change => handleChange(change, onChange)}
|
||||
orientation={
|
||||
question.metadata.orientation || 'verticle'
|
||||
}>
|
||||
{question?.metadata.buttonType === 'button'
|
||||
? question.options.map(option => {
|
||||
return(
|
||||
<RNRadioButton
|
||||
id={option}
|
||||
value={
|
||||
options[
|
||||
option as keyof typeof options
|
||||
]?.text
|
||||
}
|
||||
/>
|
||||
)})
|
||||
: question.options.map(option => (
|
||||
? question.options.map((option: keyof typeof options) => {
|
||||
return (
|
||||
<RNRadioButton
|
||||
id={option as string}
|
||||
value={
|
||||
options[option]?.text
|
||||
}
|
||||
/>
|
||||
);
|
||||
})
|
||||
: question.options.map((option: keyof typeof options) => (
|
||||
<RadioChip
|
||||
id={option}
|
||||
id={option as string}
|
||||
value={
|
||||
options[
|
||||
option as keyof typeof options
|
||||
]?.text
|
||||
options[option]?.text
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</RadioGroup>
|
||||
)}
|
||||
name={`${sectionId}.${questionId}`}
|
||||
name={`widgetContext.${widgetId}.sectionContext.${props.sectionId}.questionContext.${questionId}`}
|
||||
/>
|
||||
<ErrorMessage show={error?.[sectionId]?.[questionId]} />
|
||||
{associatedQuestions.map((nextQuestion: string, index) => {
|
||||
<ErrorMessage
|
||||
show={
|
||||
error?.widgetContext?.[widgetId]?.sectionContext?.[
|
||||
sectionId
|
||||
]?.questionContext?.[questionId]
|
||||
}
|
||||
/>
|
||||
{associatedQuestions?.map((nextQuestion: string, index) => {
|
||||
if (
|
||||
template.questions[
|
||||
nextQuestion as keyof typeof template.questions
|
||||
@@ -140,7 +130,7 @@ const RadioButton: React.FC<IRadioButton> = props => {
|
||||
questionType={
|
||||
template.questions[
|
||||
nextQuestion as keyof typeof template.questions
|
||||
].input_type
|
||||
].inputType
|
||||
}
|
||||
questionId={nextQuestion}
|
||||
name={widgetId}
|
||||
|
||||
@@ -3,9 +3,10 @@ import React from 'react';
|
||||
import {Control, Controller} from 'react-hook-form';
|
||||
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
|
||||
import StarRating from '../../../../RN-UI-LIB/src/components/star_rating/StarRating';
|
||||
import template from '../../../data/RealTemplateData.json';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import Text from '../../../../RN-UI-LIB/src/components/Text';
|
||||
import { AnswerType } from '../interface';
|
||||
import { useAppSelector } from '../../../hooks';
|
||||
interface IRating {
|
||||
questionType: string;
|
||||
questionId: string;
|
||||
@@ -18,13 +19,22 @@ interface IRating {
|
||||
}
|
||||
|
||||
const Rating: React.FC<IRating> = props => {
|
||||
const {questionId, error, sectionId} = props;
|
||||
|
||||
const {questionId, error, sectionId, widgetId} = props;
|
||||
const template = useAppSelector(state => state.case.templateData);
|
||||
const question =
|
||||
template.questions[questionId as keyof typeof template.questions];
|
||||
if (!question) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleChange = (text : number, onChange : (...event: any[]) => void) => {
|
||||
onChange({
|
||||
answer: text,
|
||||
type: AnswerType.number
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<View style={[GenericStyles.mt12]}>
|
||||
<Text dark bold style={GenericStyles.mb12}>
|
||||
@@ -40,14 +50,14 @@ const Rating: React.FC<IRating> = props => {
|
||||
}}
|
||||
render={({field: {onChange, value}}) => (
|
||||
<StarRating
|
||||
onSelectionChange={onChange}
|
||||
defaultValue={value}
|
||||
onSelectionChange={(value)=> handleChange(value,onChange)}
|
||||
defaultValue={value?.answer}
|
||||
maxRating={5}
|
||||
/>
|
||||
)}
|
||||
name={`${props.sectionId}.${questionId}`}
|
||||
name={`widgetContext.${widgetId}.sectionContext.${props.sectionId}.questionContext.${questionId}`}
|
||||
/>
|
||||
<ErrorMessage show={error?.[sectionId]?.[questionId]} />
|
||||
<ErrorMessage show={error?.sectionContext?.[sectionId]?.questionContext?.[questionId]} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,11 +2,12 @@ import {View} from 'react-native';
|
||||
import React from 'react';
|
||||
import {Control, Controller} from 'react-hook-form';
|
||||
|
||||
import template from '../../../data/RealTemplateData.json';
|
||||
import RNTextArea from '../../../../RN-UI-LIB/src/components/TextArea';
|
||||
import Text from '../../../../RN-UI-LIB/src/components/Text';
|
||||
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import { AnswerType } from '../interface';
|
||||
import { useAppSelector } from '../../../hooks';
|
||||
|
||||
interface ITextArea {
|
||||
questionType: string;
|
||||
@@ -20,13 +21,21 @@ interface ITextArea {
|
||||
}
|
||||
|
||||
const TextArea: React.FC<ITextArea> = props => {
|
||||
const {questionId, error, sectionId} = props;
|
||||
|
||||
const {questionId, error, sectionId, widgetId} = props;
|
||||
const template = useAppSelector(state => state.case.templateData);
|
||||
const question =
|
||||
template.questions[questionId as keyof typeof template.questions];
|
||||
if (!question) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleChange = (text : string, onChange : (...event: any[]) => void) => {
|
||||
onChange({
|
||||
answer: text,
|
||||
type: AnswerType.text
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[GenericStyles.mt12]}>
|
||||
<Text dark bold>
|
||||
@@ -42,16 +51,16 @@ const TextArea: React.FC<ITextArea> = props => {
|
||||
}}
|
||||
render={({field: {onChange, value}}) => (
|
||||
<RNTextArea
|
||||
onChangeText={onChange}
|
||||
value={value}
|
||||
onChangeText={(text)=> handleChange(text, onChange)}
|
||||
value={value?.answer}
|
||||
containerStyle={[GenericStyles.mt12]}
|
||||
numberOfLines={3}
|
||||
title=""
|
||||
/>
|
||||
)}
|
||||
name={`${props.sectionId}.${questionId}`}
|
||||
name={`widgetContext.${widgetId}.sectionContext.${props.sectionId}.questionContext.${questionId}`}
|
||||
/>
|
||||
<ErrorMessage show={error?.[sectionId]?.[questionId]} />
|
||||
<ErrorMessage show={error?.sectionContext?.[sectionId]?.questionContext?.[questionId]} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,9 +4,10 @@ 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/RealTemplateData.json';
|
||||
import Text from '../../../../RN-UI-LIB/src/components/Text';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import { AnswerType } from '../interface';
|
||||
import { useAppSelector } from '../../../hooks';
|
||||
|
||||
interface ITextInput {
|
||||
questionType: string;
|
||||
@@ -20,13 +21,21 @@ interface ITextInput {
|
||||
}
|
||||
|
||||
const TextInput: React.FC<ITextInput> = props => {
|
||||
const {questionId, error, sectionId} = props;
|
||||
|
||||
const {questionId, error, sectionId, widgetId} = props;
|
||||
const template = useAppSelector(state => state.case.templateData);
|
||||
const question =
|
||||
template.questions[questionId as keyof typeof template.questions];
|
||||
if (!question) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleChange = (text : string, onChange : (...event: any[]) => void) => {
|
||||
onChange({
|
||||
answer: text,
|
||||
type: AnswerType.text
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[GenericStyles.mt12]}>
|
||||
<Text dark bold>
|
||||
@@ -42,14 +51,14 @@ const TextInput: React.FC<ITextInput> = props => {
|
||||
}}
|
||||
render={({field: {onChange, value}}) => (
|
||||
<RNTextInput
|
||||
onChangeText={onChange}
|
||||
value={value}
|
||||
onChangeText={(text) => handleChange(text, onChange)}
|
||||
value={value?.answer}
|
||||
containerStyle={[GenericStyles.mt12]}
|
||||
/>
|
||||
)}
|
||||
name={`${props.sectionId}.${questionId}`}
|
||||
name={`widgetContext.${widgetId}.sectionContext.${props.sectionId}.questionContext.${questionId}`}
|
||||
/>
|
||||
<ErrorMessage show={error?.[sectionId]?.[questionId]} />
|
||||
<ErrorMessage show={error?.widgetContext?.[widgetId]?.sectionContext?.[sectionId]?.questionContext?.[questionId]} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -6,20 +6,16 @@ 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 Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import BackArrowIcon from '../../../RN-UI-LIB/src/Icons/BackArrowIcon';
|
||||
import CloseIcon from '../../../RN-UI-LIB/src/Icons/CloseIcon';
|
||||
import {GenericStyles, getShadowStyle} from '../../../RN-UI-LIB/src/styles';
|
||||
import {COLORS} from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import Realjson from '../../data/RealTemplateData.json';
|
||||
import {updateInteraction} from '../../reducer/caseReducre';
|
||||
import {useAppSelector} from '../../hooks';
|
||||
import { updateCaseDetail } from '../../reducer/allCasesSlice';
|
||||
import {deleteInteraction, updateInteraction} from '../../reducer/caseReducre';
|
||||
import {RootState} from '../../store/store';
|
||||
import {goBack, navigateToScreen} from '../utlis/navigationUtlis';
|
||||
import {
|
||||
ConditionType,
|
||||
IDecision,
|
||||
IEvaluateLeaf,
|
||||
IEvaluateLeafJourney,
|
||||
ILeaf,
|
||||
} from './interface';
|
||||
import {ConditionType, IDecision, ILeaf} from './interface';
|
||||
import RenderQuestion from './RenderQuestion';
|
||||
|
||||
interface IWidget {
|
||||
@@ -35,21 +31,25 @@ interface IWidget {
|
||||
const Widget: React.FC<IWidget> = props => {
|
||||
const {name, params} = props.route;
|
||||
const {caseId, journey} = params;
|
||||
const {sections, transitionRules, isLeaf, isNoBrainer} =
|
||||
Realjson.widget[name as keyof typeof Realjson.widget];
|
||||
const sectionMap = Realjson.sections;
|
||||
const templateData = useAppSelector(state => state.case.templateData);
|
||||
const caseData = useAppSelector(state => state.allCases.caseDetails[caseId]);
|
||||
const {sections, transitionRules, isLeaf} = templateData.widget[name];
|
||||
const sectionMap = templateData.sections;
|
||||
const {actions, conditions} = transitionRules;
|
||||
const [error, setError] = useState();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const dataToBeValidated = useSelector(
|
||||
(state: RootState) => state.case.caseForm?.[caseId]?.[journey]?.[name],
|
||||
const dataToBeValidated = useAppSelector(
|
||||
state => state.case.caseForm?.[caseId]?.[journey],
|
||||
);
|
||||
|
||||
console.log(dataToBeValidated);
|
||||
|
||||
const journeyData = useSelector(
|
||||
(state: RootState) => state.case.caseForm?.[caseId]?.[journey],
|
||||
);
|
||||
|
||||
console.log(journeyData);
|
||||
|
||||
const {control, handleSubmit} = useForm({
|
||||
defaultValues: dataToBeValidated,
|
||||
@@ -58,7 +58,11 @@ const Widget: React.FC<IWidget> = props => {
|
||||
const evaluateLeaf = (leaf: ILeaf, data: any): boolean => {
|
||||
switch (leaf.operator) {
|
||||
case 'MATCHES':
|
||||
return leaf.right === data[leaf.section][leaf.left];
|
||||
return (
|
||||
leaf.right ===
|
||||
data?.widgetContext?.[name]?.sectionContext?.[leaf.section]
|
||||
?.questionContext?.[leaf.left]?.answer
|
||||
);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -69,7 +73,9 @@ const Widget: React.FC<IWidget> = props => {
|
||||
case 'MATCHES':
|
||||
return (
|
||||
leaf.right ===
|
||||
journeyData[leaf.widgetId][leaf.section][leaf.left]
|
||||
journeyData.widgetContext[leaf.widgetId]?.sectionContext?.[
|
||||
leaf.section
|
||||
]?.questionContext?.[leaf.left]
|
||||
);
|
||||
default:
|
||||
return false;
|
||||
@@ -99,7 +105,7 @@ const Widget: React.FC<IWidget> = props => {
|
||||
|
||||
const handleValidation = (rules: any, data: any) => {
|
||||
let nextScreenName = '';
|
||||
if (!isNoBrainer) {
|
||||
if (rules !== null) {
|
||||
if (rules.conditionType === 'LEAF_NODE') {
|
||||
const answer = String(evaluateLeaf(rules, data));
|
||||
nextScreenName = actions[answer as keyof typeof actions];
|
||||
@@ -117,6 +123,7 @@ const Widget: React.FC<IWidget> = props => {
|
||||
};
|
||||
|
||||
const onSubmit = (data: any) => {
|
||||
console.log(data, 'submit');
|
||||
dispatch(
|
||||
updateInteraction({
|
||||
caseId,
|
||||
@@ -141,16 +148,31 @@ const Widget: React.FC<IWidget> = props => {
|
||||
answer: data,
|
||||
}),
|
||||
);
|
||||
const rules = Realjson.journey[journey].transitionRules.conditions;
|
||||
const screeenAction = Realjson.journey[journey].transitionRules.actions;
|
||||
let nextScreenName = '';
|
||||
const rules =
|
||||
templateData.journey[journey as keyof typeof templateData.journey]
|
||||
.transitionRules.conditions;
|
||||
const screeenAction =
|
||||
templateData.journey[journey as keyof typeof templateData.journey]
|
||||
.transitionRules.actions;
|
||||
let nextActions = '';
|
||||
if (rules.condition_type === 'LEAF_NODE') {
|
||||
nextScreenName = screeenAction[evaluateLeafJourney(rules)];
|
||||
nextActions = screeenAction[String(evaluateLeafJourney(rules as ILeaf))];
|
||||
} else {
|
||||
const answer = String(evaluateComposite(rules));
|
||||
nextScreenName = screeenAction[answer];
|
||||
const answer = String(evaluateComposite(rules as IDecision, data));
|
||||
nextActions = screeenAction[answer];
|
||||
}
|
||||
|
||||
console.log(nextActions);
|
||||
// dispatch some actions to redux store
|
||||
dispatch(updateCaseDetail({
|
||||
caseId,
|
||||
journeyId: journey,
|
||||
widgetId: name,
|
||||
answer: data,
|
||||
caseData: caseData,
|
||||
nextActions
|
||||
}))
|
||||
|
||||
navigateToScreen('Home', {
|
||||
journey: journey,
|
||||
caseId,
|
||||
@@ -187,7 +209,7 @@ const Widget: React.FC<IWidget> = props => {
|
||||
GenericStyles.p16,
|
||||
GenericStyles.whiteBackground,
|
||||
]}>
|
||||
{sections.map((section, index: number) => (
|
||||
{sections.map((section: any, index: number) => (
|
||||
<View
|
||||
key={section + index}
|
||||
style={[
|
||||
@@ -226,7 +248,17 @@ const Widget: React.FC<IWidget> = props => {
|
||||
variant={'secondary'}
|
||||
style={styles.fb45}
|
||||
title={'Back'}
|
||||
onPress={goBack}
|
||||
onPress={() => {
|
||||
dispatch(
|
||||
deleteInteraction({
|
||||
caseId,
|
||||
journeyId: journey,
|
||||
widgetId: name,
|
||||
}),
|
||||
);
|
||||
goBack();
|
||||
}}
|
||||
leftIcon={<BackArrowIcon size={10} />}
|
||||
/>
|
||||
<Button
|
||||
style={styles.fb45}
|
||||
|
||||
@@ -50,3 +50,17 @@ export interface ILeaf {
|
||||
section: string;
|
||||
widgetId: string;
|
||||
}
|
||||
|
||||
|
||||
export enum AnswerType {
|
||||
text = 'text',
|
||||
option = 'text',
|
||||
number = 'text',
|
||||
array = 'option'
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
text: string;
|
||||
associatedQuestions: Array<string>;
|
||||
metadata: any;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@ export enum ApiKeys {
|
||||
GENERATE_OTP,
|
||||
VERIFY_OTP,
|
||||
ALL_CASES,
|
||||
CASE_DETAIL
|
||||
CASE_DETAIL,
|
||||
PINNED_CASES,
|
||||
LOGOUT,
|
||||
FEEDBACK
|
||||
}
|
||||
|
||||
const API_URLS: Record<ApiKeys, string> = {} as Record<ApiKeys, string>;
|
||||
@@ -25,6 +28,9 @@ API_URLS[ApiKeys.GENERATE_OTP] = '/auth/otp/generate';
|
||||
API_URLS[ApiKeys.VERIFY_OTP] = '/auth/otp/verify';
|
||||
API_URLS[ApiKeys.ALL_CASES] = '/cases/all-cases';
|
||||
API_URLS[ApiKeys.CASE_DETAIL] = '/cases/get-cases';
|
||||
API_URLS[ApiKeys.PINNED_CASES] = '/cases/pin';
|
||||
API_URLS[ApiKeys.LOGOUT] = '/auth/logout';
|
||||
API_URLS[ApiKeys.FEEDBACK] = '/cases/feedback';
|
||||
|
||||
const MOCK_API_URLS: Record<ApiKeys, string> = {} as Record<ApiKeys, string>;
|
||||
|
||||
@@ -74,7 +80,6 @@ const errorsToRetry = [];
|
||||
const axiosInstance = axios.create();
|
||||
|
||||
axiosInstance.interceptors.request.use(request => {
|
||||
console.log(request)
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
request.retry = request?.retry < 4 ? request.retry : 3;
|
||||
|
||||
@@ -5,6 +5,9 @@ export const navigationRef: RefObject<any> = React.createRef();
|
||||
|
||||
// if screen already exists then navigate to it otherwise push screen
|
||||
export const navigateToScreen = (name: string, params: object = {}) => {
|
||||
if(navigationRef.current?.getCurrentRoute()?.name === name) {
|
||||
return;
|
||||
}
|
||||
navigationRef.current?.navigate(name, params);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,8 +39,14 @@
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"true": "verified",
|
||||
"false": "not verified"
|
||||
"true": {
|
||||
"status": "VERIFIED_SUCCESS",
|
||||
"nextJourney": ""
|
||||
},
|
||||
"false":{
|
||||
"status": "VERIFICATION_FAILED",
|
||||
"nextJourney": "PERMANENT_ADDRESS_VERIFICATION_TASK"
|
||||
}
|
||||
}
|
||||
},
|
||||
"isLeaf": false
|
||||
@@ -105,9 +111,8 @@
|
||||
"isLeaf": true
|
||||
},
|
||||
"w4": {
|
||||
"isNoBrainer": true,
|
||||
"transitionRules": {
|
||||
"conditions":{},
|
||||
"conditions":null,
|
||||
"actions": {
|
||||
"true": "w6",
|
||||
"false": "w6"
|
||||
@@ -122,9 +127,8 @@
|
||||
"isLeaf": false
|
||||
},
|
||||
"w5": {
|
||||
"isNoBrainer": true,
|
||||
"transitionRules": {
|
||||
"conditions":{},
|
||||
"conditions":null,
|
||||
"actions": {
|
||||
"true": "w4",
|
||||
"false": "w4"
|
||||
@@ -136,9 +140,8 @@
|
||||
"isLeaf": false
|
||||
},
|
||||
"w6":{
|
||||
"isNoBrainer": true,
|
||||
"transitionRules": {
|
||||
"conditions":{},
|
||||
"conditions":null,
|
||||
"actions": {
|
||||
"true": "w6",
|
||||
"false": "w6"
|
||||
|
||||
@@ -15,6 +15,8 @@ interface IAllCasesSlice {
|
||||
casesListMap: ICasesMap;
|
||||
intermediateTodoList: ICaseItem[];
|
||||
intermediateTodoListMap: ICasesMap;
|
||||
selectedTodoListMap: ICasesMap;
|
||||
selectedTodoListCount: number;
|
||||
initialPinnedRankCount: number;
|
||||
pinnedRankCount: number;
|
||||
loading: boolean;
|
||||
@@ -32,6 +34,8 @@ const initialState: IAllCasesSlice = {
|
||||
casesListMap: {},
|
||||
intermediateTodoList: [],
|
||||
intermediateTodoListMap: {},
|
||||
selectedTodoListCount: 0,
|
||||
selectedTodoListMap: {},
|
||||
initialPinnedRankCount: 0,
|
||||
pinnedRankCount: 0,
|
||||
loading: false,
|
||||
@@ -134,13 +138,13 @@ const getPinnedListDetails = (casesList: ICaseItem[]) => {
|
||||
let maxPinnedRank = 0;
|
||||
const pinnedList: ICaseItem[] = [];
|
||||
casesList.forEach(caseItem => {
|
||||
const {pinnedRank} = caseItem;
|
||||
if (!pinnedRank) {
|
||||
const {pinRank} = caseItem;
|
||||
if (pinRank === null || pinRank === undefined) {
|
||||
return;
|
||||
}
|
||||
pinnedList.push(caseItem);
|
||||
if (pinnedRank > maxPinnedRank) {
|
||||
maxPinnedRank = pinnedRank;
|
||||
if (pinRank > maxPinnedRank) {
|
||||
maxPinnedRank = pinRank;
|
||||
}
|
||||
});
|
||||
return {pinnedList, maxPinnedRank};
|
||||
@@ -150,12 +154,19 @@ const allCasesSlice = createSlice({
|
||||
name: 'cases',
|
||||
initialState,
|
||||
reducers: {
|
||||
setLoading: (state, action) => {
|
||||
state.loading = action.payload;
|
||||
},
|
||||
setCasesListData: (state, action) => {
|
||||
const {allCases, details} = action.payload;
|
||||
if (details?.length) {
|
||||
const initialValue = {...state.caseDetails};
|
||||
const detailsData = details.reduce((prev: any, item: any) => {
|
||||
prev[item.id] = item;
|
||||
prev[item.id] = {
|
||||
...item,
|
||||
isSynced: true,
|
||||
|
||||
};
|
||||
return prev;
|
||||
}, initialValue);
|
||||
state.caseDetails = detailsData;
|
||||
@@ -164,7 +175,60 @@ const allCasesSlice = createSlice({
|
||||
const {pinnedList, maxPinnedRank} = getPinnedListDetails(allCases);
|
||||
state.pinnedList = pinnedList;
|
||||
state.pinnedRankCount = maxPinnedRank;
|
||||
state.loading = false;
|
||||
},
|
||||
|
||||
updateCaseDetail: (state, action) => {
|
||||
const {caseId, journeyId, answer, caseData, nextActions} =
|
||||
action.payload;
|
||||
console.log(action.payload);
|
||||
const updatedValue = {...caseData};
|
||||
updatedValue.isSynced = false;
|
||||
if (!updatedValue.context) {
|
||||
updatedValue.context = {
|
||||
taskSequence: updatedValue.tasks.map(task => task.taskType),
|
||||
currentTask: nextActions.nextJourney,
|
||||
taskContext: {
|
||||
[journeyId]: [
|
||||
{
|
||||
taskStatus: nextActions.status,
|
||||
...answer,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (updatedValue.context.taskContext?.[journeyId]) {
|
||||
const journey = [
|
||||
...updatedValue.context.taskContext?.[journeyId],
|
||||
{
|
||||
taskStatus: nextActions.status,
|
||||
...answer,
|
||||
},
|
||||
];
|
||||
updatedValue.context = {
|
||||
currentTask: nextActions.nextJourney,
|
||||
taskContext: {
|
||||
[journeyId]: journey,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
const taskContext = updatedValue.taskContext;
|
||||
(taskContext[journeyId] = [
|
||||
{
|
||||
taskStatus: nextActions.status,
|
||||
...answer,
|
||||
},
|
||||
]),
|
||||
(updatedValue.context = {
|
||||
currentTask: nextActions.nextJourney,
|
||||
taskContext,
|
||||
});
|
||||
}
|
||||
state.caseDetails[caseId] = updatedValue;
|
||||
},
|
||||
|
||||
setPinnedRank: (state, action) => {
|
||||
const caseId = action.payload.caseReferenceId;
|
||||
const isCasePresent = state.intermediateTodoListMap[caseId];
|
||||
@@ -175,14 +239,14 @@ const allCasesSlice = createSlice({
|
||||
state.pinnedRankCount++;
|
||||
state.newlyPinnedCases++;
|
||||
const selectedCase = {...action.payload};
|
||||
selectedCase.pinnedRank = state.pinnedRankCount;
|
||||
selectedCase.pinRank = state.pinnedRankCount;
|
||||
state.intermediateTodoListMap[caseId] = selectedCase;
|
||||
}
|
||||
},
|
||||
proceedToTodoList: state => {
|
||||
state.intermediateTodoList = Object.values(
|
||||
state.intermediateTodoListMap,
|
||||
).sort((caseA, caseB) => caseA.pinnedRank - caseB.pinnedRank);
|
||||
).sort((caseA, caseB) => caseA.pinRank - caseB.pinRank);
|
||||
navigateToScreen('TodoList');
|
||||
},
|
||||
deleteIntermediateTodoListItem: (state, action) => {
|
||||
@@ -208,23 +272,28 @@ const allCasesSlice = createSlice({
|
||||
state.newlyPinnedCases = 0;
|
||||
state.pinnedRankCount = state.initialPinnedRankCount;
|
||||
},
|
||||
setTodoList: state => {
|
||||
state.newlyPinnedCases = 0;
|
||||
const list = state.casesList.map(caseItem => {
|
||||
const pinnedItem =
|
||||
state.intermediateTodoListMap[caseItem.caseReferenceId];
|
||||
return {
|
||||
...caseItem,
|
||||
pinnedRank: pinnedItem
|
||||
? pinnedItem.pinnedRank
|
||||
: caseItem.pinnedRank,
|
||||
};
|
||||
});
|
||||
state.casesList = list;
|
||||
setTodoListOffline: (state, action) => {
|
||||
state.casesList = action.payload;
|
||||
state.intermediateTodoListMap = {};
|
||||
state.newlyPinnedCases = 0;
|
||||
navigateToScreen('Home');
|
||||
},
|
||||
setSelectedTodoListMap: (state, action) => {
|
||||
const caseId = action.payload.caseReferenceId;
|
||||
const isCasePresent = state.selectedTodoListMap[caseId];
|
||||
if (isCasePresent) {
|
||||
delete state.selectedTodoListMap[caseId];
|
||||
state.selectedTodoListCount--;
|
||||
} else {
|
||||
state.selectedTodoListCount++;
|
||||
const selectedCase = {...action.payload};
|
||||
state.selectedTodoListMap[caseId] = selectedCase;
|
||||
}
|
||||
},
|
||||
resetSelectedTodoList: (state) => {
|
||||
state.selectedTodoListCount = 0;
|
||||
state.selectedTodoListMap = {};
|
||||
},
|
||||
setFilters: (state , action) => {
|
||||
state.filters = {...state.filters , ...action.payload}
|
||||
},
|
||||
@@ -242,9 +311,10 @@ const allCasesSlice = createSlice({
|
||||
});
|
||||
|
||||
export const {
|
||||
setLoading,
|
||||
setCasesListData,
|
||||
setPinnedRank,
|
||||
setTodoList,
|
||||
setTodoListOffline,
|
||||
resetTodoList,
|
||||
filterData,
|
||||
proceedToTodoList,
|
||||
@@ -252,7 +322,10 @@ export const {
|
||||
setSelectedFilters,
|
||||
setFilterList,
|
||||
clearSelectedFilters,
|
||||
setFilters
|
||||
setFilters,
|
||||
setSelectedTodoListMap,
|
||||
resetSelectedTodoList,
|
||||
updateCaseDetail,
|
||||
} = allCasesSlice.actions;
|
||||
|
||||
export default allCasesSlice.reducer;
|
||||
|
||||
@@ -7,26 +7,23 @@ interface ICaseReducer {
|
||||
caseForm: {
|
||||
[caseId: string]: {
|
||||
[journeyId: string]: {
|
||||
[sectionId: string]: {
|
||||
"widgetContext":{
|
||||
[widgetId: string]: {
|
||||
[questionId: string]: string;
|
||||
"sectionContext":{
|
||||
[sectionId: string]: {
|
||||
"questionContext":{
|
||||
[questionId: string]: string;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
toBeSynced: {
|
||||
[caseId: string]: {
|
||||
[journeyId: string]: {
|
||||
[sectionId: string]: {
|
||||
[widgetId: string]: {
|
||||
[questionId: string]: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
||||
toBeSynced: any;
|
||||
allCases: Array<Data>;
|
||||
templateData: any;
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
@@ -148,7 +145,8 @@ const initialState = {
|
||||
GEOLOCATION: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
templateData: {}
|
||||
} as ICaseReducer;
|
||||
|
||||
export const caseSlice = createSlice({
|
||||
name: 'case',
|
||||
@@ -167,14 +165,24 @@ export const caseSlice = createSlice({
|
||||
data[caseId] = {};
|
||||
}
|
||||
if (!data[caseId][journeyId]) {
|
||||
// @ts-ignore
|
||||
data[caseId][journeyId] = {};
|
||||
}
|
||||
if (!data[caseId][journeyId][widgetId]) {
|
||||
data[caseId][journeyId][widgetId] = {};
|
||||
}
|
||||
data[caseId][journeyId][widgetId] = answer;
|
||||
|
||||
data[caseId][journeyId] = answer;
|
||||
state.caseForm = data;
|
||||
},
|
||||
deleteInteraction: (state, action) => {
|
||||
const {caseId, journeyId, widgetId, answer} = action.payload;
|
||||
console.log({caseId, journeyId, widgetId, answer})
|
||||
const data = state.caseForm;
|
||||
delete data[caseId][journeyId].widgetContext[widgetId];
|
||||
state.caseForm = data;
|
||||
},
|
||||
|
||||
updateTemplateData: (state, action) => {
|
||||
state.templateData = action.payload;
|
||||
},
|
||||
setAllCases: (state, action) => {
|
||||
state.allCases = action.payload;
|
||||
},
|
||||
@@ -185,7 +193,7 @@ export const caseSlice = createSlice({
|
||||
},
|
||||
});
|
||||
|
||||
export const {increaseByOne, decreaseByOne, updateInteraction, setAllCases} =
|
||||
export const {increaseByOne, decreaseByOne, updateInteraction, setAllCases, deleteInteraction, updateTemplateData} =
|
||||
caseSlice.actions;
|
||||
|
||||
export default caseSlice.reducer;
|
||||
|
||||
@@ -37,6 +37,9 @@ const loginSlice = createSlice({
|
||||
setFormLoading: (state, action) => {
|
||||
state.isLoading = action.payload;
|
||||
},
|
||||
resetLoginForm: state => {
|
||||
state = {...initialState}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -46,6 +49,7 @@ export const {
|
||||
setVerifyOTPSuccess,
|
||||
setShowOTPScreen,
|
||||
setFormLoading,
|
||||
resetLoginForm
|
||||
} = loginSlice.actions;
|
||||
|
||||
export default loginSlice.reducer;
|
||||
|
||||
44
src/screens/Profile/AccountDetails.tsx
Normal file
44
src/screens/Profile/AccountDetails.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import {StyleSheet, View} from 'react-native';
|
||||
import React from 'react';
|
||||
import {GenericStyles} from '../../../RN-UI-LIB/src/styles';
|
||||
import Avatar from '../../../RN-UI-LIB/src/components/Avatar';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import {COLORS} from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import Heading from '../../../RN-UI-LIB/src/components/Heading';
|
||||
import {useSelector} from 'react-redux';
|
||||
import {RootState} from '../../store/store';
|
||||
|
||||
const AccountDetails = () => {
|
||||
const {phoneNumber, name} = useSelector(
|
||||
(state: RootState) => state.user.user!!,
|
||||
);
|
||||
return (
|
||||
<View style={[GenericStyles.row, styles.accountDetails]}>
|
||||
{/* Need URI for the profile pic */}
|
||||
<Avatar name={'Profile'} dataURI={'uri'} />
|
||||
<View style={styles.detailsContainer}>
|
||||
<Heading type="h5" dark bold>
|
||||
Account Details
|
||||
</Heading>
|
||||
<Text>{name}</Text>
|
||||
<Text light small>
|
||||
Logged in via {phoneNumber}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountDetails;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
accountDetails: {
|
||||
borderBottomColor: COLORS.BORDER.PRIMARY,
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
detailsContainer: {
|
||||
marginLeft: 12,
|
||||
marginBottom: 20,
|
||||
alignSelf: 'flex-start',
|
||||
},
|
||||
});
|
||||
42
src/screens/Profile/ProfileHeader.tsx
Normal file
42
src/screens/Profile/ProfileHeader.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import {Pressable, StyleSheet, View} from 'react-native';
|
||||
import React from 'react';
|
||||
import Heading from '../../../RN-UI-LIB/src/components/Heading';
|
||||
import {GenericStyles} from '../../../RN-UI-LIB/src/styles';
|
||||
import {COLORS} from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import {navigateToScreen} from '../../components/utlis/navigationUtlis';
|
||||
import ArrowBackSmallIcon from '../../../RN-UI-LIB/src/Icons/ArrowBackSmallIcon';
|
||||
|
||||
const ProfileHeader = () => {
|
||||
const handleBackIconPress = () => {
|
||||
navigateToScreen('Home');
|
||||
};
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
GenericStyles.row,
|
||||
GenericStyles.alignCenter,
|
||||
styles.header,
|
||||
]}>
|
||||
<Pressable onPress={handleBackIconPress}>
|
||||
<ArrowBackSmallIcon />
|
||||
</Pressable>
|
||||
<Heading type="h5" style={styles.headerLabel}>
|
||||
Profile
|
||||
</Heading>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfileHeader;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
header: {
|
||||
backgroundColor: COLORS.BACKGROUND.HEADER,
|
||||
height: 56,
|
||||
paddingLeft: 26,
|
||||
},
|
||||
headerLabel: {
|
||||
color: COLORS.BACKGROUND.PRIMARY,
|
||||
marginLeft: 16,
|
||||
},
|
||||
});
|
||||
61
src/screens/Profile/index.tsx
Normal file
61
src/screens/Profile/index.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import {Alert, Pressable, StyleSheet, View} from 'react-native';
|
||||
import React from 'react';
|
||||
import {GenericStyles} from '../../../RN-UI-LIB/src/styles';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import AccountDetails from './AccountDetails';
|
||||
import {useAppDispatch} from '../../hooks';
|
||||
import {logout} from '../../action/authActions';
|
||||
import ProfileHeader from './ProfileHeader';
|
||||
import LogoutIcon from '../../../RN-UI-LIB/src/Icons/LogoutIcon';
|
||||
|
||||
const Profile = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleLogout = () => {
|
||||
Alert.alert('Confirm', 'Are you sure you want to logout? ', [
|
||||
{
|
||||
text: 'Cancel',
|
||||
style: 'cancel',
|
||||
},
|
||||
{
|
||||
text: 'Logout',
|
||||
onPress: () => dispatch(logout()),
|
||||
style: 'destructive',
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={GenericStyles.fill}>
|
||||
<View>
|
||||
<ProfileHeader />
|
||||
</View>
|
||||
<View style={GenericStyles.p16}>
|
||||
<View style={GenericStyles.mb24}>
|
||||
<AccountDetails />
|
||||
</View>
|
||||
<Pressable
|
||||
onPress={handleLogout}
|
||||
style={[
|
||||
GenericStyles.row,
|
||||
GenericStyles.alignCenter,
|
||||
styles.logoutContainer,
|
||||
]}>
|
||||
<LogoutIcon />
|
||||
<Text style={styles.logoutText}>Logout</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default Profile;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
logoutContainer: {
|
||||
marginLeft: 10,
|
||||
},
|
||||
logoutText: {
|
||||
marginLeft: 6,
|
||||
},
|
||||
});
|
||||
@@ -12,13 +12,15 @@ import {CaseStatuses, ICaseItem, CaseTypes} from './interface';
|
||||
import {COMPLETED_STATUSES, ListHeaderItems} from './contants';
|
||||
import CaseItem from './CaseItem';
|
||||
import {Search} from "../../../RN-UI-LIB/src/utlis/search";
|
||||
import CasesActionButtons from './CasesActionButtons';
|
||||
import FloatingInfoText from '../../components/floatingInfoText';
|
||||
|
||||
export const Separator = () => <View style={styles.separator} />;
|
||||
|
||||
export const getItem = (item: Array<ICaseItem>, index: number) => item[index];
|
||||
|
||||
const AllCases = () => {
|
||||
const {casesList, newlyPinnedCases} = useSelector(
|
||||
const {casesList, newlyPinnedCases, selectedTodoListCount} = useSelector(
|
||||
(state: RootState) => state.allCases,
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
@@ -54,10 +56,13 @@ const AllCases = () => {
|
||||
|
||||
//extracting data for todo list and other cases
|
||||
filteredList.forEach(caseItem => {
|
||||
if (caseItem.pinnedRank) {
|
||||
pinnedList.push({...caseItem, type: CaseTypes.TODO});
|
||||
} else {
|
||||
if (
|
||||
caseItem.pinRank === null ||
|
||||
caseItem.pinRank === undefined
|
||||
) {
|
||||
otherList.push({...caseItem, type: CaseTypes.CASE});
|
||||
} else {
|
||||
pinnedList.push({...caseItem, type: CaseTypes.TODO});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -73,11 +78,6 @@ const AllCases = () => {
|
||||
compiledList.push(...otherList);
|
||||
}
|
||||
|
||||
pinnedList.sort(
|
||||
(caseItemA, caseItemB) =>
|
||||
caseItemA.pinnedRank - caseItemB.pinnedRank,
|
||||
);
|
||||
|
||||
let completedPinnedCasesCount = 0;
|
||||
pinnedList.forEach(todo => {
|
||||
if (todo.caseStatus === CaseStatuses.CLOSED) {
|
||||
@@ -95,14 +95,6 @@ const AllCases = () => {
|
||||
};
|
||||
}, [filteredList]);
|
||||
|
||||
const handleTodoProceedClick = () => {
|
||||
dispatch(proceedToTodoList());
|
||||
};
|
||||
|
||||
const handleCancelTodoList = () => {
|
||||
dispatch(resetTodoList());
|
||||
};
|
||||
|
||||
const handleSearchChange = (query: string) => {
|
||||
const filterList = query.length > 0 ? Search(query , filteredList || [] , { keys: ['customerInfo.name']}).map(filteredListItem => filteredListItem.obj) : filteredList;
|
||||
setFilteredList(filterList);
|
||||
@@ -133,27 +125,14 @@ const AllCases = () => {
|
||||
) : (
|
||||
<Text>Nothing to show</Text>
|
||||
)}
|
||||
{newlyPinnedCases ? (
|
||||
<View
|
||||
style={[
|
||||
GenericStyles.row,
|
||||
GenericStyles.justifyContentSpaceBetween,
|
||||
GenericStyles.p16,
|
||||
styles.actionBtns,
|
||||
]}>
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
style={styles.fb45}
|
||||
title={'Cancel'}
|
||||
onPress={handleCancelTodoList}
|
||||
/>
|
||||
<Button
|
||||
style={styles.fb45}
|
||||
title={'Proceed'}
|
||||
onPress={handleTodoProceedClick}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
{newlyPinnedCases || selectedTodoListCount ? (
|
||||
<CasesActionButtons />
|
||||
) : (
|
||||
<FloatingInfoText
|
||||
bottom={24}
|
||||
message="Press on customer image to select cases"
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -168,9 +147,6 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: COLORS.BACKGROUND.PRIMARY,
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
fb45: {
|
||||
flexBasis: '45%',
|
||||
},
|
||||
});
|
||||
|
||||
export default AllCases;
|
||||
|
||||
109
src/screens/allCases/CasesActionButtons.tsx
Normal file
109
src/screens/allCases/CasesActionButtons.tsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import {StyleSheet, View} from 'react-native';
|
||||
import React from 'react';
|
||||
import {GenericStyles} from '../../../RN-UI-LIB/src/styles';
|
||||
import {COLORS} from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import Button from '../../../RN-UI-LIB/src/components/Button';
|
||||
import {useSelector} from 'react-redux';
|
||||
import {
|
||||
proceedToTodoList,
|
||||
resetSelectedTodoList,
|
||||
resetTodoList,
|
||||
} from '../../reducer/allCasesSlice';
|
||||
import {RootState} from '../../store/store';
|
||||
import {CaseTypes, ICaseItem} from './interface';
|
||||
import {useAppDispatch} from '../../hooks';
|
||||
import {postPinnedList} from '../../action/dataActions';
|
||||
|
||||
export const CasesActionButtons = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const {
|
||||
newlyPinnedCases,
|
||||
selectedTodoListCount,
|
||||
selectedTodoListMap,
|
||||
casesList,
|
||||
} = useSelector((state: RootState) => state.allCases);
|
||||
const handleTodoProceedClick = () => {
|
||||
dispatch(proceedToTodoList());
|
||||
};
|
||||
|
||||
const handleCancelTodoList = () => {
|
||||
dispatch(resetTodoList());
|
||||
};
|
||||
|
||||
const handleRemovePinnedList = () => {
|
||||
const updatedPinnedList: ICaseItem[] = [];
|
||||
const updatedCaseList: ICaseItem[] = casesList.map(caseItem => {
|
||||
const {caseReferenceId, pinRank} = caseItem;
|
||||
if (selectedTodoListMap[caseReferenceId]) {
|
||||
caseItem.pinRank = null;
|
||||
caseItem.type = CaseTypes.CASE;
|
||||
} else if (pinRank !== null && pinRank !== undefined) {
|
||||
updatedPinnedList.push(caseItem);
|
||||
}
|
||||
return caseItem;
|
||||
});
|
||||
dispatch(resetSelectedTodoList());
|
||||
dispatch(postPinnedList(updatedPinnedList, updatedCaseList));
|
||||
};
|
||||
|
||||
if (!newlyPinnedCases && !selectedTodoListCount) {
|
||||
return null;
|
||||
}
|
||||
const renderActions = () => {
|
||||
if (newlyPinnedCases) {
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
variant={'secondary'}
|
||||
style={styles.fb45}
|
||||
title={'Cancel'}
|
||||
onPress={handleCancelTodoList}
|
||||
/>
|
||||
<Button
|
||||
style={styles.fb45}
|
||||
title={'Proceed'}
|
||||
onPress={handleTodoProceedClick}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (selectedTodoListCount) {
|
||||
return (
|
||||
<Button
|
||||
style={GenericStyles.fill}
|
||||
title={'Remove from list'}
|
||||
onPress={handleRemovePinnedList}
|
||||
buttonStyle={styles.removeBtn}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
GenericStyles.row,
|
||||
GenericStyles.justifyContentSpaceBetween,
|
||||
GenericStyles.p16,
|
||||
styles.actionBtns,
|
||||
]}>
|
||||
{renderActions()}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
actionBtns: {
|
||||
borderTopColor: COLORS.BORDER.PRIMARY,
|
||||
backgroundColor: COLORS.BACKGROUND.PRIMARY,
|
||||
borderTopWidth: 1,
|
||||
},
|
||||
fb45: {
|
||||
flexBasis: '45%',
|
||||
},
|
||||
removeBtn: {
|
||||
backgroundColor: COLORS.TEXT.RED,
|
||||
},
|
||||
});
|
||||
|
||||
export default CasesActionButtons;
|
||||
@@ -1,43 +1,62 @@
|
||||
import {Pressable, StyleSheet, View} from 'react-native';
|
||||
import React from 'react';
|
||||
import {CaseStatuses, ICaseItem, TaskTitleUIMapping, CaseTypes} from './interface';
|
||||
import {
|
||||
CaseStatuses,
|
||||
ICaseItem,
|
||||
TaskTitleUIMapping,
|
||||
CaseTypes,
|
||||
} from './interface';
|
||||
import Avatar from '../../../RN-UI-LIB/src/components/Avatar';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import Heading from '../../../RN-UI-LIB/src/components/Heading';
|
||||
import {GenericStyles} from '../../../RN-UI-LIB/src/styles';
|
||||
import {useDispatch, useSelector} from 'react-redux';
|
||||
import {setPinnedRank} from '../../reducer/allCasesSlice';
|
||||
import {
|
||||
setPinnedRank,
|
||||
setSelectedTodoListMap,
|
||||
} from '../../reducer/allCasesSlice';
|
||||
import {RootState} from '../../store/store';
|
||||
import RoundCheckIcon from '../../icons/RoundCheckIcon';
|
||||
import {navigateToScreen} from '../../components/utlis/navigationUtlis';
|
||||
|
||||
interface IListItem {
|
||||
caseData: ICaseItem;
|
||||
// True if it's from the inside todo screen
|
||||
isTodoItem?: boolean;
|
||||
compleatedList?: boolean;
|
||||
}
|
||||
|
||||
const ListItem: React.FC<IListItem> = props => {
|
||||
const {caseData, compleatedList, isTodoItem} = props;
|
||||
const {type, caseReferenceId: caseId, customerInfo} = caseData;
|
||||
const {type, caseReferenceId: caseId} = caseData;
|
||||
const dispatch = useDispatch();
|
||||
|
||||
if (!compleatedList && caseData.caseStatus === CaseStatuses.CLOSED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const {intermediateTodoListMap} = useSelector(
|
||||
(state: RootState) => state.allCases,
|
||||
);
|
||||
const {
|
||||
intermediateTodoListMap,
|
||||
selectedTodoListMap,
|
||||
newlyPinnedCases,
|
||||
selectedTodoListCount,
|
||||
} = useSelector((state: RootState) => state.allCases);
|
||||
|
||||
const handleAvatarClick = () => {
|
||||
if (isTodoItem || caseData.caseStatus === CaseStatuses.CLOSED) {
|
||||
return;
|
||||
}
|
||||
if (type === CaseTypes.CASE && selectedTodoListCount > 0) {
|
||||
return;
|
||||
}
|
||||
if (type === CaseTypes.TODO && newlyPinnedCases > 0) {
|
||||
return;
|
||||
}
|
||||
if (type === CaseTypes.CASE) {
|
||||
dispatch(setPinnedRank(caseData));
|
||||
return;
|
||||
} else if (type === CaseTypes.TODO) {
|
||||
dispatch(setSelectedTodoListMap(caseData));
|
||||
// select todo item
|
||||
}
|
||||
};
|
||||
@@ -46,7 +65,9 @@ const ListItem: React.FC<IListItem> = props => {
|
||||
navigateToScreen('caseDetail', {caseId});
|
||||
};
|
||||
|
||||
const caseSelected = !isTodoItem && intermediateTodoListMap?.[caseId];
|
||||
const caseSelected =
|
||||
!isTodoItem &&
|
||||
(intermediateTodoListMap?.[caseId] || selectedTodoListMap?.[caseId]);
|
||||
|
||||
const address = caseData.currentTask.metadata?.address;
|
||||
const poneNumber = caseData.currentTask.metadata?.primaryPhoneNumber;
|
||||
@@ -73,7 +94,9 @@ const ListItem: React.FC<IListItem> = props => {
|
||||
GenericStyles.ph16,
|
||||
styles.pv12,
|
||||
GenericStyles.row,
|
||||
GenericStyles.whiteBackground,
|
||||
caseSelected
|
||||
? GenericStyles.silverBackground
|
||||
: GenericStyles.whiteBackground,
|
||||
]}>
|
||||
<Pressable
|
||||
style={[styles.avatarContainer, styles.alignSelf]}
|
||||
@@ -93,9 +116,7 @@ const ListItem: React.FC<IListItem> = props => {
|
||||
</Heading>
|
||||
<Text dark ellipsizeMode="tail" numberOfLines={2}>
|
||||
{TaskTitleUIMapping[caseData.currentTask.title]}:{' '}
|
||||
<Text>
|
||||
{displayAddress}
|
||||
</Text>
|
||||
<Text>{displayAddress}</Text>
|
||||
</Text>
|
||||
{/* TODO write color coding logic with tag component */}
|
||||
{/* {caseData.caseVerdict !== caseVerdict.NEW && (
|
||||
|
||||
@@ -1,19 +1,58 @@
|
||||
import React, {useEffect} from 'react';
|
||||
import {StyleSheet, View} from 'react-native';
|
||||
import {Pressable, StyleSheet, View} from 'react-native';
|
||||
import Heading from '../../../RN-UI-LIB/src/components/Heading';
|
||||
import Tabs from '../../../RN-UI-LIB/src/components/tabs/Tabs';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import ArrowBackSmallIcon from '../../../RN-UI-LIB/src/Icons/ArrowBackSmallIcon';
|
||||
import AvatarIcon from '../../../RN-UI-LIB/src/Icons/AvatarIcon';
|
||||
import NaviLogoIcon from '../../../RN-UI-LIB/src/Icons/NaviLogoIcon';
|
||||
import {GenericStyles} from '../../../RN-UI-LIB/src/styles';
|
||||
import {COLORS} from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import {getAllCases} from '../../action/dataActions';
|
||||
import {navigateToScreen} from '../../components/utlis/navigationUtlis';
|
||||
import {useAppDispatch, useAppSelector} from '../../hooks';
|
||||
import {
|
||||
resetSelectedTodoList,
|
||||
resetTodoList,
|
||||
} from '../../reducer/allCasesSlice';
|
||||
import AllCases from './AllCases';
|
||||
import ComplatedCase from './ComplatedCase';
|
||||
import {CaseStatuses} from './interface';
|
||||
import RealJson from '../../data/RealTemplateData.json';
|
||||
import { updateTemplateData } from '../../reducer/caseReducre';
|
||||
|
||||
const LogoActions = () => {
|
||||
const {newlyPinnedCases, selectedTodoListCount} = useAppSelector(
|
||||
state => state.allCases,
|
||||
);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
if (!newlyPinnedCases && !selectedTodoListCount) {
|
||||
return <NaviLogoIcon />;
|
||||
}
|
||||
const handleBackPressIfTodoSelected = () => {
|
||||
dispatch(newlyPinnedCases ? resetTodoList() : resetSelectedTodoList());
|
||||
};
|
||||
const count = newlyPinnedCases || selectedTodoListCount;
|
||||
return (
|
||||
<View style={GenericStyles.centerAlignedRow}>
|
||||
<Pressable onPress={handleBackPressIfTodoSelected}>
|
||||
<ArrowBackSmallIcon />
|
||||
</Pressable>
|
||||
<Text style={[styles.text, styles.selectedText]} bold light>
|
||||
{count} selected
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
const AllCasesMain = () => {
|
||||
const data = useAppSelector(state => state.allCases.casesList);
|
||||
const completed = data.filter(
|
||||
const {casesList, newlyPinnedCases, selectedTodoListCount} = useAppSelector(
|
||||
state => state.allCases,
|
||||
);
|
||||
const completed = casesList.filter(
|
||||
caseData =>
|
||||
caseData.caseStatus === CaseStatuses.CLOSED ||
|
||||
caseData.caseStatus === CaseStatuses.EXPIRED ||
|
||||
@@ -23,7 +62,7 @@ const AllCasesMain = () => {
|
||||
const tabItems = [
|
||||
{
|
||||
key: 'first',
|
||||
title: `Pending (${data.length - completed.length})`,
|
||||
title: `Pending (${casesList.length - completed.length})`,
|
||||
content: AllCases,
|
||||
},
|
||||
{
|
||||
@@ -37,20 +76,31 @@ const AllCasesMain = () => {
|
||||
dispatch(getAllCases());
|
||||
}, []);
|
||||
|
||||
const handleProfileIconPress = () => {
|
||||
navigateToScreen('Profile');
|
||||
};
|
||||
useEffect(() => {
|
||||
dispatch(updateTemplateData(RealJson));
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={GenericStyles.fill}>
|
||||
<View
|
||||
style={[
|
||||
styles.headerTop,
|
||||
GenericStyles.p16,
|
||||
GenericStyles.row,
|
||||
GenericStyles.centerAlignedRow,
|
||||
GenericStyles.justifyContentSpaceBetween,
|
||||
]}>
|
||||
<NaviLogoIcon />
|
||||
<Heading type={'h5'} style={styles.text} bold light>
|
||||
My allocations
|
||||
</Heading>
|
||||
<View style={styles.iconSkeliton} />
|
||||
<LogoActions />
|
||||
{!newlyPinnedCases && !selectedTodoListCount && (
|
||||
<Heading type={'h5'} style={styles.text} bold light>
|
||||
My allocations
|
||||
</Heading>
|
||||
)}
|
||||
<Pressable onPress={handleProfileIconPress}>
|
||||
<AvatarIcon />
|
||||
</Pressable>
|
||||
</View>
|
||||
<Tabs
|
||||
selectedTab="first"
|
||||
@@ -74,6 +124,10 @@ const styles = StyleSheet.create({
|
||||
height: 64,
|
||||
backgroundColor: COLORS.BACKGROUND.HEADER,
|
||||
},
|
||||
selectedText: {
|
||||
marginLeft: 18,
|
||||
fontSize: 16,
|
||||
},
|
||||
});
|
||||
|
||||
export default AllCasesMain;
|
||||
|
||||
@@ -79,7 +79,7 @@ export const caseVerdictAndColor = {
|
||||
|
||||
export interface ICaseItem {
|
||||
type?: CaseTypes; // this is for maintaing frontend
|
||||
pinnedRank: number;
|
||||
pinRank: number | null;
|
||||
updatedAt: any;
|
||||
allocatedAt: any;
|
||||
caseReferenceId: string;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { SafeAreaView, StyleSheet, View } from 'react-native';
|
||||
import { Alert, SafeAreaView, StyleSheet, View } from 'react-native';
|
||||
import Button from '../../../RN-UI-LIB/src/components/Button';
|
||||
import BackArrowIcon from '../../../RN-UI-LIB/src/Icons/BackArrowIcon';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
@@ -20,8 +20,7 @@ interface ICaseDetails {
|
||||
const CaseDetails: React.FC<ICaseDetails> = (props) => {
|
||||
const {route : { params : {caseId}}} = props;
|
||||
|
||||
const detailObject = useAppSelector(state => state.allCases.caseDetails[caseId])
|
||||
console.log(detailObject);
|
||||
const detailObject = useAppSelector(state => state.allCases.caseDetails[caseId]);
|
||||
|
||||
return (
|
||||
<SafeAreaView style={[GenericStyles.fill, GenericStyles.whiteBackground]}>
|
||||
@@ -31,12 +30,23 @@ const CaseDetails: React.FC<ICaseDetails> = (props) => {
|
||||
<View style={GenericStyles.p16}>
|
||||
<UserDetailsSection caseDetail={detailObject} />
|
||||
<TaskStepper caseDetail={detailObject} />
|
||||
<Button
|
||||
{/* <Button
|
||||
style={{}}
|
||||
title="Trigger journey"
|
||||
variant="secondary"
|
||||
onPress={() => navigateToScreen('w1', {caseId: 'labkjisbldfyuk', journey: 'COMMUNICATION_ADDRESS_VERIFICATION_TASK'})}
|
||||
/>
|
||||
onPress={() => Alert.alert("Confirm" , 'Are you sure you want to logout?', [
|
||||
{
|
||||
text: 'Cancle',
|
||||
onPress: (value?: string) => console.log(value),
|
||||
style: 'default'
|
||||
},
|
||||
{
|
||||
text: 'Logout',
|
||||
onPress: (value?: string) => console.log(value),
|
||||
style: 'cancel'
|
||||
},
|
||||
])}
|
||||
/> */}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
|
||||
@@ -1,66 +1,108 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { useSelector } from 'react-redux';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import {
|
||||
Image, Modal,
|
||||
Pressable,
|
||||
SafeAreaView,
|
||||
StyleSheet,
|
||||
View
|
||||
} from 'react-native';
|
||||
import Avatar from '../../../RN-UI-LIB/src/components/Avatar';
|
||||
import Heading from '../../../RN-UI-LIB/src/components/Heading';
|
||||
import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import CloseIcon from '../../../RN-UI-LIB/src/Icons/CloseIcon';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import { dateFormat } from '../../../RN-UI-LIB/src/utlis/dates';
|
||||
import CalenderIcon from '../../assets/icons/CalenderIcon';
|
||||
import DocumentIcon from '../../assets/icons/DocumentIcon';
|
||||
import IconLabel from '../../common/IconLabel';
|
||||
import { RootState } from '../../store/store';
|
||||
import { CaseDetail, LoanAccountStatusUIMapping, LoanTypeUIMapping } from './interface';
|
||||
|
||||
interface IUserDetailsSection{
|
||||
caseDetail : any;
|
||||
interface IUserDetailsSection {
|
||||
caseDetail: CaseDetail;
|
||||
}
|
||||
|
||||
const UserDetailsSection: React.FC<IUserDetailsSection> = (props) => {
|
||||
const UserDetailsSection: React.FC<IUserDetailsSection> = props => {
|
||||
const {caseDetail} = props;
|
||||
const {customerInfo, loanDetails} = caseDetail;
|
||||
const disbursalDate = loanDetails.disbursalDate;
|
||||
const allocationDate = loanDetails.allocationDate;
|
||||
const disbursalDate = dateFormat(new Date(loanDetails.disbursalDate), "DD MMM, YYYY");
|
||||
const allocationDate = dateFormat(new Date(caseDetail.allocatedAt), "DD MMM, YYYY");
|
||||
|
||||
const [openImage, setOpenImage] = useState<boolean>(false);
|
||||
|
||||
const handleOpenClose = useCallback(() => {
|
||||
setOpenImage(prev => !prev);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View style={[GenericStyles.row, GenericStyles.pb16, styles.container]}>
|
||||
<View style={[styles.avatarContainer]}>
|
||||
<Avatar
|
||||
name={customerInfo.customerName}
|
||||
dataURI={customerInfo.imageURL}
|
||||
/>
|
||||
<Pressable onPress={handleOpenClose}>
|
||||
<Avatar
|
||||
size={60}
|
||||
name={customerInfo.customerName}
|
||||
dataURI={customerInfo.imageURL}
|
||||
/>
|
||||
</Pressable>
|
||||
</View>
|
||||
<View style={[styles.infoContainer]}>
|
||||
<Heading dark type="h4">
|
||||
{customerInfo.customerName}
|
||||
</Heading>
|
||||
<View style={[GenericStyles.row]}>
|
||||
<View style={[GenericStyles.row, GenericStyles.mb8]}>
|
||||
<IconLabel
|
||||
containerStyle={{flex: 0.5}}
|
||||
icon={<DocumentIcon />}
|
||||
text={loanDetails.loanType}
|
||||
text={LoanTypeUIMapping[loanDetails.loanType]}
|
||||
/>
|
||||
<IconLabel
|
||||
text={loanDetails.loanAccountStatus}
|
||||
containerStyle={{flex: 0.5}}
|
||||
containerStyle={GenericStyles.ml10}
|
||||
text={LoanAccountStatusUIMapping[loanDetails.loanAccountStatus]}
|
||||
/>
|
||||
</View>
|
||||
<View style={[GenericStyles.row]}>
|
||||
<View style={[GenericStyles.row, GenericStyles.mb8]}>
|
||||
<IconLabel
|
||||
icon={<CalenderIcon />}
|
||||
text={disbursalDate}
|
||||
containerStyle={{flex: 0.5}}
|
||||
/>
|
||||
<IconLabel
|
||||
text={`${loanDetails.tenureMonths} months`}
|
||||
containerStyle={{flex: 0.5}}
|
||||
text={`${loanDetails.tenureMonths} ${loanDetails.tenureMonths > 1 ? "Months" : "Month"}`}
|
||||
containerStyle={GenericStyles.ml10}
|
||||
/>
|
||||
</View>
|
||||
<View style={[GenericStyles.pt16]}>
|
||||
<Text style={[GenericStyles.fontSize15]}>
|
||||
<Text light style={[GenericStyles.fontSize15]}>
|
||||
Allocated on {allocationDate}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Modal animationType={'slide'} visible={openImage} onRequestClose={handleOpenClose}>
|
||||
<SafeAreaView
|
||||
style={[
|
||||
GenericStyles.fill,
|
||||
{backgroundColor: COLORS.BACKGROUND.HEADER},
|
||||
]}>
|
||||
<View style={GenericStyles.p16}>
|
||||
<Pressable onPress={handleOpenClose}>
|
||||
<CloseIcon />
|
||||
</Pressable>
|
||||
</View>
|
||||
<View
|
||||
style={[
|
||||
GenericStyles.fill,
|
||||
GenericStyles.alignCenter,
|
||||
GenericStyles.row
|
||||
]}>
|
||||
<Image
|
||||
style={[
|
||||
GenericStyles.fill,
|
||||
styles.imageStyle,
|
||||
]}
|
||||
source={{uri: customerInfo.imageURL}}
|
||||
resizeMode={'contain'}
|
||||
/>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -78,6 +120,12 @@ const styles = StyleSheet.create({
|
||||
infoContainer: {
|
||||
flex: 0.6,
|
||||
},
|
||||
imageStyle:{
|
||||
height: 300
|
||||
},
|
||||
backgroundColor:{
|
||||
backgroundColor: COLORS.BACKGROUND.HEADER
|
||||
}
|
||||
});
|
||||
|
||||
export default UserDetailsSection;
|
||||
|
||||
28
src/screens/caseDetails/interactionsHandler.tsx
Normal file
28
src/screens/caseDetails/interactionsHandler.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { StyleSheet, Text, View } from 'react-native'
|
||||
import React, { useEffect } from 'react'
|
||||
import { useAppDispatch, useAppSelector } from '../../hooks'
|
||||
import { _map } from '../../../RN-UI-LIB/src/utlis/common';
|
||||
import { syncCaseDetail } from '../../action/dataActions';
|
||||
|
||||
const interactionsHandler = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const allCasesDetails = useAppSelector(state => state.allCases.caseDetails);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const notSyncedCases: Array<any> = [];
|
||||
_map(allCasesDetails, (el)=> {
|
||||
if(!allCasesDetails[el].isSynced){
|
||||
const caseId = allCasesDetails[el].id
|
||||
notSyncedCases.push({...allCasesDetails[el], caseId})
|
||||
}
|
||||
})
|
||||
console.log(notSyncedCases.length, "not synced")
|
||||
notSyncedCases.map((caseItem)=> dispatch(syncCaseDetail(caseItem)))
|
||||
}, [allCasesDetails])
|
||||
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export default interactionsHandler
|
||||
121
src/screens/caseDetails/interface.ts
Normal file
121
src/screens/caseDetails/interface.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
export enum LoanType {
|
||||
PERSONAL_LOAN = "PERSONAL_LOAN",
|
||||
HOUSE_LOAN = "HOUSE_LOAN"
|
||||
}
|
||||
|
||||
export enum LoanAccountStatus {
|
||||
ACTIVE = "ACTIVE",
|
||||
CLOSE = "CLOSE"
|
||||
}
|
||||
|
||||
export enum LoanAccountStatusUIMapping {
|
||||
ACTIVE = "Active",
|
||||
CLOSE = "Close"
|
||||
}
|
||||
|
||||
export enum LoanTypeUIMapping {
|
||||
PERSONAL_LOAN = 'Personal loan',
|
||||
HOUSE_LOAN = 'House loan'
|
||||
}
|
||||
|
||||
export interface LoanDetails {
|
||||
loanAccountNumber: string;
|
||||
disbursalDate: string;
|
||||
disbursementAmount: number;
|
||||
firstDueDate: string;
|
||||
tenureMonths: number;
|
||||
loanType: LoanType;
|
||||
loanAccountStatus: LoanAccountStatus;
|
||||
productCode: string;
|
||||
}
|
||||
|
||||
export interface CustomerInfo {
|
||||
customerReferenceId: string;
|
||||
customerName: string;
|
||||
primaryPhoneNumber: string;
|
||||
imageURL: string;
|
||||
geoLocation: string;
|
||||
}
|
||||
|
||||
export interface Address {
|
||||
referenceId: string;
|
||||
houseNumber: string;
|
||||
lineOne: string;
|
||||
lineTwo: string;
|
||||
locality: string;
|
||||
street: string;
|
||||
city: string;
|
||||
state: string;
|
||||
pinCode: string;
|
||||
type: string;
|
||||
source: string;
|
||||
current: boolean;
|
||||
permanent: boolean;
|
||||
zipCode?: any;
|
||||
addressQualityStatus?: any;
|
||||
}
|
||||
|
||||
export interface Metadata {
|
||||
'@class': string;
|
||||
address: Address;
|
||||
geoLocation: string;
|
||||
primaryPhoneNumber: string;
|
||||
}
|
||||
|
||||
export interface Task {
|
||||
taskId: number;
|
||||
taskType: string;
|
||||
metadata: Metadata;
|
||||
}
|
||||
|
||||
export interface Q1 {
|
||||
optionId: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface QuestionContext {
|
||||
q1: Q1[];
|
||||
}
|
||||
|
||||
export interface S1 {
|
||||
questionContext: QuestionContext;
|
||||
}
|
||||
|
||||
export interface SectionContext {
|
||||
s1: S1;
|
||||
}
|
||||
|
||||
export interface W1 {
|
||||
sectionContext: SectionContext;
|
||||
}
|
||||
|
||||
export interface WidgetContext {
|
||||
w1: W1;
|
||||
}
|
||||
|
||||
export interface COMMUNICATIONADDRESSVERIFICATIONTASK {
|
||||
taskStatus: string;
|
||||
widgetContext: WidgetContext;
|
||||
}
|
||||
|
||||
export interface TaskContext {
|
||||
COMMUNICATION_ADDRESS_VERIFICATION_TASK: COMMUNICATIONADDRESSVERIFICATIONTASK[];
|
||||
}
|
||||
|
||||
export interface Context {
|
||||
taskSequence: string[];
|
||||
currentTask: string;
|
||||
taskContext: TaskContext;
|
||||
}
|
||||
|
||||
export interface CaseDetail {
|
||||
id: string;
|
||||
caseStatus: string;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
allocatedAt: number;
|
||||
loanDetails: LoanDetails;
|
||||
customerInfo: CustomerInfo;
|
||||
tasks: Task[];
|
||||
context: Context;
|
||||
}
|
||||
@@ -10,10 +10,7 @@ import TextInput from '../../../RN-UI-LIB/src/components/TextInput';
|
||||
import BackArrowIcon from '../../../RN-UI-LIB/src/Icons/BackArrowIcon';
|
||||
import {GenericStyles} from '../../../RN-UI-LIB/src/styles';
|
||||
import {COLORS} from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import {
|
||||
verifyOTP,
|
||||
VerifyOTPPayload,
|
||||
} from '../../action/authActions';
|
||||
import {verifyOTP, VerifyOTPPayload} from '../../action/authActions';
|
||||
import {useAppDispatch} from '../../hooks';
|
||||
import {RootState} from '../../store/store';
|
||||
import {navigateToScreen} from '../../components/utlis/navigationUtlis';
|
||||
@@ -72,7 +69,7 @@ const OtpInput = () => {
|
||||
render={({field: {onChange, onBlur, value}}) => (
|
||||
<TextInput
|
||||
keyboardType="phone-pad"
|
||||
placeholder="Enter OTP"
|
||||
placeholder="Enter 4 digits OTP"
|
||||
onBlur={onBlur}
|
||||
onChangeText={value => onChange(value)}
|
||||
value={value}
|
||||
|
||||
@@ -20,22 +20,40 @@ import Button from '../../../RN-UI-LIB/src/components/Button';
|
||||
import {
|
||||
deleteIntermediateTodoListItem,
|
||||
resetTodoList,
|
||||
setPinnedRank,
|
||||
setTodoList,
|
||||
} from '../../reducer/allCasesSlice';
|
||||
import {navigateToScreen} from '../../components/utlis/navigationUtlis';
|
||||
import SwipeableContainer from '../../components/SwipeableContainer';
|
||||
import {postPinnedList} from '../../action/dataActions';
|
||||
import {useAppDispatch} from '../../hooks';
|
||||
|
||||
const TodoList = () => {
|
||||
const {
|
||||
pinnedList = [],
|
||||
intermediateTodoList = [],
|
||||
casesList,
|
||||
intermediateTodoListMap,
|
||||
loading,
|
||||
} = useSelector((state: RootState) => state.allCases);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleCreateTodoList = () => {
|
||||
dispatch(setTodoList());
|
||||
const updatedPinnedList: ICaseItem[] = [];
|
||||
const updatedCaseList = casesList.map(caseItem => {
|
||||
const pinnedItem =
|
||||
intermediateTodoListMap[caseItem.caseReferenceId];
|
||||
if (caseItem.pinRank !== null && caseItem.pinRank !== undefined) {
|
||||
updatedPinnedList.push(caseItem);
|
||||
}
|
||||
if (pinnedItem) {
|
||||
updatedPinnedList.push(pinnedItem);
|
||||
}
|
||||
return pinnedItem ? pinnedItem : caseItem;
|
||||
});
|
||||
const sortedPinnedList: ICaseItem[] = updatedPinnedList.sort(
|
||||
(caseA, caseB) => caseA.pinRank - caseB.pinRank,
|
||||
);
|
||||
dispatch(postPinnedList(sortedPinnedList, updatedCaseList));
|
||||
};
|
||||
|
||||
const handleCancelTodoList = () => {
|
||||
|
||||
Reference in New Issue
Block a user