feat: added changes for qa release on feedback flow (#114)

This commit is contained in:
Ishan Srivastava
2023-02-28 14:29:38 +05:30
committed by GitHub Enterprise
parent 81457d12ec
commit 4f636e60bb
10 changed files with 43 additions and 40 deletions

View File

@@ -1,4 +1,5 @@
import React from 'react';
import { LogBox } from 'react-native';
import {Provider} from 'react-redux';
import store, {persistor} from './src/store/store';
import {PersistGate} from 'redux-persist/integration/react';
@@ -25,6 +26,8 @@ if (ENV !== 'prod') {
mockApiServer();
}
LogBox.ignoreAllLogs();
const App = () => {
useNativeButtons();
return (

View File

@@ -21,6 +21,7 @@ import { AppDispatch } from '../store/store';
import { addClickstreamEvent } from '../services/clickstreamEventService';
import { CLICKSTREAM_EVENT_NAMES } from '../common/Constants';
import { logError } from '../components/utlis/errorUtils';
import { toast } from "../../RN-UI-LIB/src/components/toast";
export const getAllCases = () => (dispatch: AppDispatch) => {
const url = getApiUrl(ApiKeys.ALL_CASES);
@@ -104,6 +105,7 @@ export const syncCaseDetail = (data: any) => (dispatch: AppDispatch) => {
.then(res => {
dispatch(updateSingleCase({ data: res.data, id: data.id }));
OfflineImageDAO.deleteImages(offlineImageIdList);
toast({ type: 'success', text1: 'Feedback recorded successfully!' })
});
};

View File

@@ -14,14 +14,14 @@ const ErrorMessage: React.FC<IError> = props => {
}
return (
<View style={GenericStyles.mt12}>
<Text style={GenericStyles.alignCenter}>
<InfoIcon color={'red'} />{' '}
<Text style={[GenericStyles.ml10, GenericStyles.redText]}>
<View style={[GenericStyles.flexRow, GenericStyles.alignCenter, GenericStyles.justifyStart]}>
<InfoIcon color={'red'}/>
<Text style={[GenericStyles.ml8, GenericStyles.redText]}>
{show?.message || 'This is mandatory field'}
</Text>
</Text>
</View>
);
</View>
);
};
export default ErrorMessage;

View File

@@ -20,7 +20,7 @@ import withObservables from '@nozbe/with-observables';
import OfflineImageDAO from '../../../wmDB/dao/OfflineImageDAO';
import { CLICKSTREAM_EVENT_NAMES, PrefixJpegBase64Image } from '../../../common/Constants';
import { addClickstreamEvent } from '../../../services/clickstreamEventService';
import { isQuestionMandatory } from "../services/validation.service";
import { isQuestionMandatory, validateInput } from "../services/validation.service";
import { CaseAllocationType } from "../../../screens/allCases/interface";
interface IOfflineImage {
@@ -90,7 +90,7 @@ const ImageUpload: React.FC<IImageUpload> = props => {
{!imageId ? (
<Controller
control={props.control}
// rules={question.metadata.validators}
rules={{validate: (data) => validateInput(data, question.metadata.validators)}}
render={({field: {onChange}}) => (
<CameraClickPicture
onPictureClickSuccess={clickedImage => handleChange(clickedImage, onChange)}

View File

@@ -55,7 +55,7 @@ const Rating: React.FC<IRating> = props => {
</Text>
<Controller
control={props.control}
// rules={{validate: (data) => validateInput(data, question.metadata.validators)}}
rules={{validate: (data) => validateInput(data, question.metadata.validators)}}
render={({field: {onChange, value}}) => (
<StarRating
minText={"Unhappy"}

View File

@@ -57,6 +57,7 @@ const TextInput: React.FC<ITextInput> = props => {
rules={{validate: (data) => validateInput(data, question.metadata.validators)}}
render={({field: {onChange, value}}) => (
<RNTextInput
keyboardType={question.metadata.keyboardType || "default"}
onChangeText={(text) => handleChange(text, onChange)}
value={value?.answer}
containerStyle={[GenericStyles.mt12]}

View File

@@ -29,8 +29,6 @@ import { getNextJourneyActions, getNextWidget } from "./services/forms.service";
import { FormTemplateV1 } from "../../types/template.types";
import { CaseAllocationType } from "../../screens/allCases/interface";
const CASE_DETAIL_SCREEN_NAME = 'caseDetail';
interface IWidget {
route: {
name: string;
@@ -42,12 +40,8 @@ interface IWidget {
}
const Widget: React.FC<IWidget> = props => {
const navigationRoutes = useNavigationState(state => state.routes);
const previousScreenRoute = navigationRoutes[navigationRoutes.length - 2];
const [isJourneyFirstScreen] = useState(
previousScreenRoute.name === CASE_DETAIL_SCREEN_NAME,
);
const [isJourneyFirstScreen, setIsJourneyFirstScreen] = useState(true);
const { params } = props.route;
@@ -62,19 +56,36 @@ const Widget: React.FC<IWidget> = props => {
const sectionMap = templateData.sections;
const [error, setError] = useState();
const dispatch = useDispatch();
useEffect(()=>{
let isFirst = false
for(const journey of Object.values(templateData.journey)){
if(journey.startWidget === name){
isFirst = true;
break;
}
}
setIsJourneyFirstScreen(isFirst)
},[templateData, name])
const dataToBeValidated = useAppSelector(
state => state.case.caseForm?.[caseId]?.[journey],
);
const { control, handleSubmit } = useForm({
const { control, handleSubmit, trigger, watch, clearErrors, formState: {errors} } = useForm({
defaultValues: {
...dataToBeValidated,
allocationReferenceId: caseData?.currentAllocationReferenceId || 'asdfasd',
allocationReferenceId: caseData?.currentAllocationReferenceId || Date.now(),
},
});
React.useEffect(() => {
const subscription = watch((value, { name }) => {
clearErrors(name);
trigger(name)
});
return () => subscription.unsubscribe();
}, [watch]);
const onSubmit = (data: any) => {
addClickstreamEvent(
CLICKSTREAM_EVENT_NAMES.AV_FORM_NEXT_BUTTON_CLICKED,
@@ -88,7 +99,7 @@ const Widget: React.FC<IWidget> = props => {
answer: data,
}),
);
navigateToScreen(getTemplateRoute(`${getNextWidget(widgetConditionActions, data, name)}`,caseType), {
navigateToScreen(getTemplateRoute(`${getNextWidget(widgetConditionActions, data)}`,caseType), {
journey: journey,
caseId,
});
@@ -260,24 +271,11 @@ const Widget: React.FC<IWidget> = props => {
<>
{sections?.map((section: any, index: number) => {
return (
<>
{sectionMap[section]?.label && (
<Heading
style={
index > 0
? GenericStyles.mt16
: null
}
key={index}
type={'h3'}
dark>
{sectionMap[section]?.label}
</Heading>
)}
<View
key={section + index}
style={[
GenericStyles.p16,
GenericStyles.pt12,
GenericStyles.whiteBackground,
getShadowStyle(5),
styles.br8,
@@ -296,7 +294,6 @@ const Widget: React.FC<IWidget> = props => {
name={name}
/>
</View>
</>
);
})}
</>

View File

@@ -10,16 +10,16 @@ import {
// TODO : technically widgetId should also be inside context, will do it when time allows.
export function evaluateCondition(condition: Condition, context: any): boolean {
if (condition.conditionType === ConditionTypes.LEAF) {
return evaluateLeaf(condition as unknown as LeafCondition, context , widgetId)
} else return evaluateComposite(condition as unknown as CompositeCondition, context, widgetId)
return evaluateLeaf(condition as unknown as LeafCondition, context )
} else return evaluateComposite(condition as unknown as CompositeCondition, context)
}
function evaluateLeaf (leaf: LeafCondition, context: any, widgetId: string):boolean {
function evaluateLeaf (leaf: LeafCondition, context: any):boolean {
switch (leaf.operator) {
case LeafOperator.VALUE_EQUAL_TO:
return (
leaf.right ===
context?.widgetContext?.[widgetId]?.sectionContext?.[leaf.section]
context?.widgetContext?.[leaf.widgetId]?.sectionContext?.[leaf.section]
?.questionContext?.[leaf.left]?.answer
);
default:

View File

@@ -1,7 +1,7 @@
import { evaluateCondition } from "./conditionEvaluation.service";
import { Action, ActionType, ConditionAction } from "../../../types/template.types";
export const getNextWidget = (conditionActions: ConditionAction[], context: any, currentWidgetId: string): string => {
export const getNextWidget = (conditionActions: ConditionAction[], context: any): string => {
let nextScreenName = '';
for (const conditionAction of conditionActions) {
if (conditionAction.isDefault || (conditionAction.condition && evaluateCondition(conditionAction.condition, context))) {

View File

@@ -10,7 +10,7 @@ export function validateInput(data: { answer: any, type: string }, allRules: any
for (const ruleName of Object.keys(allRules)) {
const rule = allRules[ruleName];
if (ruleName === 'required' && rule.value) {
if (!data?.answer?.length) {
if (data?.answer=== null || data?.answer===undefined || !`${data?.answer}`.trim().length) {
result = rule.message || 'This is required field';
break;
}