Tp 21873 sethi (#165)
* intermediate screen text fix TP-21873 * image bug fix TP-21873 * intermediate screen text issue fix TP-21873 * otp screen fix TP-21873 * remove commented code TP-21873 * success image changes TP-21873 * submodule update TP-21873 * fix images issue TP-21873
This commit is contained in:
committed by
GitHub Enterprise
parent
669c3d41c4
commit
6791014fff
Submodule RN-UI-LIB updated: 9b83ba94da...82e33fdb8f
@@ -1,12 +1,13 @@
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import RNFetchBlob from "rn-fetch-blob";
|
||||
import { getPrefixBase64Image, MimeType } from "../../common/Constants";
|
||||
import { getPrefixBase64Image, LocalStorageKeys, MimeType } from "../../common/Constants";
|
||||
import { Address, PhoneNumber } from "../../screens/caseDetails/interface";
|
||||
import NetInfo from "@react-native-community/netinfo";
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import { stringify } from './stringifyUtils';
|
||||
import address from "../form/components/Address";
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
import { GlobalImageMap } from '../../../App';
|
||||
import { GenericType } from '../../common/GenericTypes';
|
||||
|
||||
|
||||
@@ -124,7 +125,14 @@ export const getDynamicBottomSheetHeightPercentageFn = (headerOffset = 100, rowH
|
||||
})
|
||||
}
|
||||
|
||||
export const saveToGlobalImageMap = async (caseId: string, image: string) => {
|
||||
GlobalImageMap[caseId] = image;
|
||||
await setAsyncStorageItem(
|
||||
LocalStorageKeys.GLOBAL_IMAGE_MAP,
|
||||
GlobalImageMap,
|
||||
);
|
||||
};
|
||||
export const allSettled = (promises: Promise<GenericType>[]) =>
|
||||
Promise.all(
|
||||
promises.map(p => p.then(value => ({ status: 'fulfilled', value})).catch(value => ({ status: 'rejected', value}))),
|
||||
);
|
||||
);
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { setAsyncStorageItem } from './../components/utlis/commonFunctions';
|
||||
import {
|
||||
setAsyncStorageItem,
|
||||
} from './../components/utlis/commonFunctions';
|
||||
import { CaseDetail } from '../screens/caseDetails/interface';
|
||||
import { CaseAllocationType } from '../screens/allCases/interface';
|
||||
import { LocalStorageKeys } from '../common/Constants';
|
||||
import { getSignedApi, ISignedRequest } from '../action/dataActions';
|
||||
import { getBase64FromUrl } from '../components/utlis/commonFunctions';
|
||||
import { GlobalImageMap } from '../../App';
|
||||
import { LocalStorageKeys } from '../common/Constants';
|
||||
import { useAppSelector } from '.';
|
||||
|
||||
const useCustomerImage = (caseDetails: CaseDetail) => {
|
||||
const [imageUrl, setImageUrl] = useState(
|
||||
@@ -13,6 +16,7 @@ const useCustomerImage = (caseDetails: CaseDetail) => {
|
||||
caseDetails?.customerInfo?.imageURL ||
|
||||
caseDetails?.imageUrl,
|
||||
);
|
||||
const pinnedList = useAppSelector(state => state.allCases.pinnedList);
|
||||
const [error, setError] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
@@ -45,11 +49,17 @@ const useCustomerImage = (caseDetails: CaseDetail) => {
|
||||
const responseImage64 = await getBase64FromUrl(url);
|
||||
if (responseImage64) {
|
||||
setImageUrl(responseImage64);
|
||||
GlobalImageMap[caseId] = responseImage64;
|
||||
await setAsyncStorageItem(
|
||||
LocalStorageKeys.GLOBAL_IMAGE_MAP,
|
||||
GlobalImageMap,
|
||||
);
|
||||
if (
|
||||
pinnedList.find(
|
||||
item => item.caseReferenceId === caseId,
|
||||
)
|
||||
) {
|
||||
GlobalImageMap[caseId] = responseImage64;
|
||||
await setAsyncStorageItem(
|
||||
LocalStorageKeys.GLOBAL_IMAGE_MAP,
|
||||
GlobalImageMap,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setImageUrl('');
|
||||
|
||||
@@ -34,6 +34,9 @@ const loginSlice = createSlice({
|
||||
state.verifyOTPError = action.payload;
|
||||
state.isLoading = false;
|
||||
},
|
||||
resetVerifyOTPError: state => {
|
||||
state.verifyOTPError = '';
|
||||
},
|
||||
setFormLoading: (state, action) => {
|
||||
state.isLoading = action.payload;
|
||||
},
|
||||
@@ -55,6 +58,7 @@ export const {
|
||||
setShowOTPScreen,
|
||||
setFormLoading,
|
||||
resetLoginForm,
|
||||
resetVerifyOTPError,
|
||||
} = loginSlice.actions;
|
||||
|
||||
export default loginSlice.reducer;
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import React from 'react';
|
||||
import { StyleSheet, View } from 'react-native';
|
||||
import { GlobalImageMap } from '../../../App';
|
||||
import Avatar from '../../../RN-UI-LIB/src/components/Avatar';
|
||||
import UnsyncedIcon from '../../../RN-UI-LIB/src/Icons/UnsyncedIcon';
|
||||
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import { useAppDispatch, useAppSelector } from '../../hooks';
|
||||
import {
|
||||
getBase64FromUrl,
|
||||
saveToGlobalImageMap,
|
||||
} from '../../components/utlis/commonFunctions';
|
||||
import { useAppSelector } from '../../hooks';
|
||||
import useCustomerImage from '../../hooks/useCustomerImage';
|
||||
import { CaseDetail } from '../caseDetails/interface';
|
||||
import { ICaseItem } from './interface';
|
||||
@@ -12,6 +17,7 @@ interface ICaseItemAvatar {
|
||||
caseData: ICaseItem;
|
||||
size?: number;
|
||||
showBorder?: boolean;
|
||||
shouldHandleError?: boolean;
|
||||
}
|
||||
|
||||
const RELATIVE_ASYNC_ICON_RIGHT_POSITION = -5;
|
||||
@@ -21,19 +27,33 @@ const CaseItemAvatar: React.FC<ICaseItemAvatar> = ({
|
||||
caseData,
|
||||
size = 40,
|
||||
showBorder = false,
|
||||
shouldHandleError,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const refrenceId = caseData?.caseReferenceId || caseData?.id;
|
||||
const caseDetails: CaseDetail = useAppSelector(
|
||||
state => state.allCases.caseDetails?.[refrenceId]!!,
|
||||
);
|
||||
const [apiErrorCount, setApiErrorCount] = React.useState(0);
|
||||
|
||||
const isSynced = caseDetails?.isSynced;
|
||||
const { imageUrl, setError, loading } = useCustomerImage(caseDetails);
|
||||
const { imageUrl, setImageUrl, setError, loading } =
|
||||
useCustomerImage(caseDetails);
|
||||
|
||||
const onError = async () => {
|
||||
setError(true);
|
||||
if (shouldHandleError) {
|
||||
setError(true);
|
||||
} else {
|
||||
setImageUrl('');
|
||||
}
|
||||
};
|
||||
|
||||
const onImageLoadSuccess = async () => {
|
||||
if (!GlobalImageMap[caseDetails?.id]) {
|
||||
const responseImage64 = await getBase64FromUrl(imageUrl);
|
||||
if (responseImage64) {
|
||||
const caseId = caseDetails?.id;
|
||||
await saveToGlobalImageMap(caseId, responseImage64);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const customerName =
|
||||
@@ -51,6 +71,7 @@ const CaseItemAvatar: React.FC<ICaseItemAvatar> = ({
|
||||
onErrorFallback={onError}
|
||||
style={[showBorder && styles.border]}
|
||||
loading={loading}
|
||||
onSuccess={onImageLoadSuccess}
|
||||
/>
|
||||
{!isSynced ? (
|
||||
<View style={styles.unsyncedIcon}>
|
||||
|
||||
@@ -46,7 +46,7 @@ const ListItem: React.FC<IListItem> = props => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { intermediateTodoListMap, selectedTodoListMap, caseDetails } =
|
||||
const { intermediateTodoListMap, selectedTodoListMap, caseDetails, pinnedList } =
|
||||
useAppSelector(state => state.allCases);
|
||||
|
||||
const detail = caseDetails[caseId]!!;
|
||||
@@ -128,7 +128,7 @@ const ListItem: React.FC<IListItem> = props => {
|
||||
: COLORS.BACKGROUND.PRIMARY,
|
||||
},
|
||||
]}>
|
||||
<CaseItemAvatar caseData={caseData} />
|
||||
<CaseItemAvatar shouldHandleError={pinnedList?.find(item => item?.caseReferenceId === caseId) ? true: false} caseData={caseData} />
|
||||
{!isTodoItem && !isCompleted ? (
|
||||
<Pressable
|
||||
onPress={handleAvatarClick}
|
||||
|
||||
@@ -45,7 +45,9 @@ const UserDetailsSection: React.FC<IUserDetailsSection> = props => {
|
||||
);
|
||||
const ANIMATION_DURATION = 500;
|
||||
const [openImage, setOpenImage] = useState<boolean>(false);
|
||||
const { imageUrl, setError, loading } = useCustomerImage(caseDetail);
|
||||
const { imageUrl, setError } = useCustomerImage(caseDetail);
|
||||
const [errorModalImage, setErrorModalImage] = useState<boolean>(false);
|
||||
|
||||
|
||||
const handleOpenClose = useCallback(() => {
|
||||
setOpenImage(prev => !prev);
|
||||
@@ -86,6 +88,7 @@ const UserDetailsSection: React.FC<IUserDetailsSection> = props => {
|
||||
showBorder
|
||||
size={64}
|
||||
caseData={caseDetail}
|
||||
shouldHandleError
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<View style={[styles.infoContainer]}>
|
||||
@@ -155,7 +158,7 @@ const UserDetailsSection: React.FC<IUserDetailsSection> = props => {
|
||||
''
|
||||
)}
|
||||
|
||||
{ GlobalImageMap[caseDetail?.id] ? <Modal
|
||||
{ (GlobalImageMap[caseDetail?.id] || imageUrl) ? <Modal
|
||||
animationType={'slide'}
|
||||
visible={openImage}
|
||||
onRequestClose={handleOpenClose}>
|
||||
@@ -174,13 +177,31 @@ const UserDetailsSection: React.FC<IUserDetailsSection> = props => {
|
||||
GenericStyles.fill,
|
||||
GenericStyles.alignCenter,
|
||||
GenericStyles.row,
|
||||
{
|
||||
position: 'relative',
|
||||
},
|
||||
]}>
|
||||
<RNFastImage
|
||||
style={[GenericStyles.fill, styles.imageStyle]}
|
||||
source={{ uri: imageUrl }}
|
||||
source={{ uri: GlobalImageMap[caseDetail?.id] ?? imageUrl }}
|
||||
resizeMode={'stretch'}
|
||||
onError={() => setError(true)}
|
||||
onError={() => {
|
||||
setError(true)
|
||||
setErrorModalImage(true)
|
||||
}}
|
||||
onLoad={()=>{
|
||||
setErrorModalImage(false)
|
||||
}}
|
||||
/>
|
||||
{
|
||||
errorModalImage ?
|
||||
<Text style={[GenericStyles.whiteText, {
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '35%',
|
||||
}]}>Image not available</Text>
|
||||
: null
|
||||
}
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</Modal> : null}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { addClickstreamEvent } from '../../services/clickstreamEventService';
|
||||
import { CLICKSTREAM_EVENT_NAMES } from '../../common/Constants';
|
||||
import Layout from '../layout/Layout';
|
||||
import otpText from "./OtpText";
|
||||
import { resetVerifyOTPError } from '../../reducer/loginSlice';
|
||||
|
||||
interface IOtpForm {
|
||||
otp: string;
|
||||
@@ -97,7 +98,12 @@ const OtpInput = () => {
|
||||
style={[styles.otpText]}
|
||||
keyboardType="phone-pad"
|
||||
onBlur={onBlur}
|
||||
onChangeText={value => onChange(value)}
|
||||
onChangeText={value => {
|
||||
onChange(value)
|
||||
if(verifyOTPError) {
|
||||
dispatch(resetVerifyOTPError());
|
||||
}
|
||||
}}
|
||||
value={value}
|
||||
maxLength={4}
|
||||
testID={'test_enter_otp'}
|
||||
|
||||
@@ -7,9 +7,11 @@ import Text from '../../../RN-UI-LIB/src/components/Text';
|
||||
import {Countdown} from '../../components/countdown';
|
||||
import {StyleSheet} from 'react-native';
|
||||
import {COLORS} from '../../../RN-UI-LIB/src/styles/colors';
|
||||
import { GenericStyles } from '../../../RN-UI-LIB/src/styles';
|
||||
|
||||
const OtpText = () => {
|
||||
const [countDownComplete, setCountDownComplete] = useState<boolean>(false);
|
||||
const [countDownTimeLeft, setCountDownTimeLeft] = useState<number>(30);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const {phoneNumber, verifyOTPError} = useSelector(
|
||||
@@ -24,35 +26,34 @@ const OtpText = () => {
|
||||
setCountDownComplete(true)
|
||||
};
|
||||
|
||||
if (verifyOTPError) {
|
||||
return (
|
||||
<Text style={styles.errorText}>
|
||||
{verifyOTPError}{' '}
|
||||
<Text style={styles.clickableText} onPress={handleResendOTP} testID='resend-otp-text'>
|
||||
Resend OTP
|
||||
</Text>
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
if (countDownComplete) {
|
||||
return (
|
||||
<Text light>
|
||||
Enter 4 digits OTP or{' '}
|
||||
<Text style={styles.clickableText} onPress={handleResendOTP} testID='resend-otp-text'>
|
||||
Resend OTP
|
||||
</Text>
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Text light>
|
||||
<>
|
||||
{!countDownComplete && <Text light>
|
||||
Resend OTP in{' '}
|
||||
<Countdown
|
||||
onComplete={handleCountdownComplete}
|
||||
startFrom={30}
|
||||
startFrom={countDownTimeLeft}
|
||||
step={(timeLeft) => setCountDownTimeLeft(timeLeft)}
|
||||
/>{' '}
|
||||
second(s)
|
||||
second{ countDownTimeLeft > 1 && 's' }
|
||||
</Text>
|
||||
}
|
||||
<Text style={GenericStyles.alignCenter} >
|
||||
{verifyOTPError && (
|
||||
<Text style={styles.errorText}>
|
||||
{verifyOTPError}{' '}
|
||||
</Text>
|
||||
)}
|
||||
{
|
||||
countDownComplete && (
|
||||
<Text style={styles.clickableText} onPress={handleResendOTP} testID='resend-otp-text'>
|
||||
Resend OTP
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
</Text>
|
||||
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -119,6 +119,12 @@ const TodoList = () => {
|
||||
|
||||
const intermediateTodoListLength = intermediateTodoList.length;
|
||||
|
||||
const avCases = intermediateTodoList.filter((item) => {
|
||||
if(caseDetails[item.caseReferenceId]?.caseType === CaseAllocationType.ADDRESS_VERIFICATION_CASE) {
|
||||
return item;
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<View style={[GenericStyles.fill, styles.todoListContainer]}>
|
||||
@@ -128,22 +134,27 @@ const TodoList = () => {
|
||||
} selected`}
|
||||
onBack={handleBack}
|
||||
/>
|
||||
<Banner hideClose style={GenericStyles.m12}>
|
||||
{ avCases?.length > 0 && <Banner hideClose style={GenericStyles.m12}>
|
||||
<View style={[GenericStyles.row]}>
|
||||
<View style={styles.infoIcon}>
|
||||
<InfoIcon color={COLORS.BACKGROUND.INDIGO_DARK} />
|
||||
</View>
|
||||
<View style={{flexBasis: '95%'}}>
|
||||
<Heading dark type="h5" style={styles.headingText}>
|
||||
Sharing a message of your visit
|
||||
<Heading dark type="h5" style={styles.headingText} >
|
||||
Sharing a message to only onboarding
|
||||
</Heading>
|
||||
<Text>
|
||||
The selected customer{intermediateTodoListLength > 1 ? 's' : ''} will recieve a message
|
||||
about your visit. Are you sure you want to proceed?
|
||||
<Heading dark type="h5" style={styles.headingText} >
|
||||
customers
|
||||
</Heading>
|
||||
<Text style={styles.descriptionText} >
|
||||
The selected onboarding customer{avCases?.length > 1 ? 's' : ''} will
|
||||
</Text>
|
||||
<Text style={styles.descriptionText} >
|
||||
receive a message about your visit
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</Banner>
|
||||
</Banner>}
|
||||
<VirtualizedList
|
||||
style={{ height: 500 }}
|
||||
data={intermediateTodoList as Array<ICaseItem>}
|
||||
@@ -213,6 +224,9 @@ const styles = StyleSheet.create({
|
||||
opacity: 0.6,
|
||||
bottom: 77,
|
||||
height: '100%',
|
||||
},
|
||||
descriptionText: {
|
||||
color: '#6770C4'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user