@TP-12803 case details

This commit is contained in:
kunalsharma
2022-12-12 17:07:29 +05:30
parent 43e7811ba4
commit f7ea54f976
19 changed files with 899 additions and 17 deletions

View File

@@ -21,7 +21,7 @@ import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import Widget from './src/components/form';
import {navigationRef} from './src/components/utlis/navigationUtlis';
import {GenericStyles} from './RN-UI-LIB/src/styles';
import CaseDetails from './src/components/caseDetails/CaseDetails';
function HomeScreen() {
return (
@@ -44,7 +44,11 @@ const App = () => {
persistor={persistor}>
<NavigationContainer ref={navigationRef}>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
{/*<Stack.Screen name="Home" component={HomeScreen} />*/}
<Stack.Screen
name="Case Details"
component={CaseDetails}
/>
{Object.keys(data.widgets).map(key => (
<Stack.Screen
key={key}

View File

@@ -0,0 +1,10 @@
import * as React from 'react';
import Svg, {Circle} from 'react-native-svg';
const BulletIcon = () => (
<Svg width={8} height={8} fill="none">
<Circle cx={4} cy={4} r={4} fill="#E8E8E8" />
</Svg>
);
export default BulletIcon;

View File

@@ -0,0 +1,22 @@
import * as React from 'react';
import Svg, {Mask, Rect, G, Path} from 'react-native-svg';
const CallViaSimIcon = () => (
<Svg width={16} height={16} viewBox="0 0 16 16" fill="none">
<Mask
id="mask0_744_23679"
maskUnits="userSpaceOnUse"
x={0}
y={0}
width={16}
height={16}>
<Rect width={16} height={16} fill="#D9D9D9" />
</Mask>
<G mask="url(#mask0_744_23679)">
<Path
d="M4.66683 15.3332C4.30016 15.3332 3.98638 15.2027 3.7255 14.9418C3.46416 14.6805 3.3335 14.3665 3.3335 13.9998V1.99984C3.3335 1.63317 3.46416 1.31917 3.7255 1.05784C3.98638 0.796948 4.30016 0.666504 4.66683 0.666504H11.3335C11.7002 0.666504 12.0142 0.796948 12.2755 1.05784C12.5364 1.31917 12.6668 1.63317 12.6668 1.99984V13.9998C12.6668 14.3665 12.5364 14.6805 12.2755 14.9418C12.0142 15.2027 11.7002 15.3332 11.3335 15.3332H4.66683ZM4.66683 11.9998H11.3335V3.99984H4.66683V11.9998Z"
fill="#0276FE"
/>
</G>
</Svg>
);
export default CallViaSimIcon;

View File

@@ -0,0 +1,22 @@
import * as React from 'react';
import Svg, {Mask, Rect, G, Path} from 'react-native-svg';
const SVGComponent = () => (
<Svg width={16} height={16} viewBox="0 0 16 16" fill="none">
<Mask
id="mask0_591_26105"
maskUnits="userSpaceOnUse"
x={0}
y={0}
width={16}
height={16}>
<Rect width={16} height={16} fill="#D9D9D9" />
</Mask>
<G mask="url(#mask0_591_26105)">
<Path
d="M3.33333 14.6668C2.96667 14.6668 2.65267 14.5364 2.39133 14.2755C2.13044 14.0142 2 13.7002 2 13.3335V4.00016C2 3.6335 2.13044 3.31972 2.39133 3.05883C2.65267 2.7975 2.96667 2.66683 3.33333 2.66683H4V1.3335H5.33333V2.66683H10.6667V1.3335H12V2.66683H12.6667C13.0333 2.66683 13.3473 2.7975 13.6087 3.05883C13.8696 3.31972 14 3.6335 14 4.00016V13.3335C14 13.7002 13.8696 14.0142 13.6087 14.2755C13.3473 14.5364 13.0333 14.6668 12.6667 14.6668H3.33333ZM3.33333 13.3335H12.6667V6.66683H3.33333V13.3335Z"
fill="#29A1A3"
/>
</G>
</Svg>
);
export default SVGComponent;

View File

@@ -0,0 +1,13 @@
import * as React from 'react';
import Svg, {Path} from 'react-native-svg';
const DocumentIcon = () => (
<Svg width={12} height={14} fill="none">
<Path
d="M4 11h4a.646.646 0 0 0 .475-.192.645.645 0 0 0 .192-.474.645.645 0 0 0-.192-.475A.646.646 0 0 0 8 9.667H4a.643.643 0 0 0-.475.192.643.643 0 0 0-.192.475c0 .188.064.347.192.474A.643.643 0 0 0 4 11Zm0-2.666h4a.646.646 0 0 0 .475-.192.645.645 0 0 0 .192-.475.647.647 0 0 0-.192-.476.647.647 0 0 0-.475-.19H4a.645.645 0 0 0-.475.19.646.646 0 0 0-.192.476c0 .189.064.347.192.475A.643.643 0 0 0 4 8.334Zm-2 5.333c-.367 0-.68-.13-.941-.392a1.284 1.284 0 0 1-.392-.941V1.667c0-.367.13-.68.392-.942.26-.261.574-.392.941-.392h4.783a1.319 1.319 0 0 1 .934.384L10.95 3.95a1.318 1.318 0 0 1 .383.933v7.45c0 .367-.13.681-.391.942-.261.261-.575.392-.942.392H2Zm4.667-9.334c0 .19.064.348.192.475A.643.643 0 0 0 7.333 5H10L6.667 1.667v2.667Z"
fill="#FACC15"
/>
</Svg>
);
export default DocumentIcon;

View File

@@ -0,0 +1,22 @@
import * as React from 'react';
import Svg, {Mask, Rect, G, Path} from 'react-native-svg';
const LocationIcon = () => (
<Svg width={24} height={24} viewBox="0 0 24 24" fill="none">
<Mask
id="mask0_744_23798"
maskUnits="userSpaceOnUse"
x={0}
y={0}
width={24}
height={24}>
<Rect width={24} height={24} fill="#D9D9D9" />
</Mask>
<G mask="url(#mask0_744_23798)">
<Path
d="M12 12C12.55 12 13.021 11.804 13.413 11.412C13.8043 11.0207 14 10.55 14 10C14 9.45 13.8043 8.979 13.413 8.587C13.021 8.19567 12.55 8 12 8C11.45 8 10.9793 8.19567 10.588 8.587C10.196 8.979 10 9.45 10 10C10 10.55 10.196 11.0207 10.588 11.412C10.9793 11.804 11.45 12 12 12ZM12 21.625C11.8667 21.625 11.7333 21.6 11.6 21.55C11.4667 21.5 11.35 21.4333 11.25 21.35C8.81667 19.2 7 17.2043 5.8 15.363C4.6 13.521 4 11.8 4 10.2C4 7.7 4.80433 5.70833 6.413 4.225C8.021 2.74167 9.88333 2 12 2C14.1167 2 15.979 2.74167 17.587 4.225C19.1957 5.70833 20 7.7 20 10.2C20 11.8 19.4 13.521 18.2 15.363C17 17.2043 15.1833 19.2 12.75 21.35C12.65 21.4333 12.5333 21.5 12.4 21.55C12.2667 21.6 12.1333 21.625 12 21.625Z"
fill="#969696"
/>
</G>
</Svg>
);
export default LocationIcon;

View File

@@ -0,0 +1,18 @@
import * as React from 'react';
import Svg, {Path} from 'react-native-svg';
interface TickIconProps {
color: string;
}
const TickIcon = ({color}: TickIconProps) => (
<Svg width={15} height={11} viewBox="0 0 15 11" fill="none">
<Path
fillRule="evenodd"
clipRule="evenodd"
d="M4.49999 8.4751L1.60833 5.58343C1.28333 5.25843 0.758325 5.25843 0.433325 5.58343C0.108325 5.90843 0.108325 6.43343 0.433325 6.75843L3.91666 10.2418C4.24166 10.5668 4.76666 10.5668 5.09166 10.2418L13.9083 1.4251C14.2333 1.1001 14.2333 0.575098 13.9083 0.250098C13.5833 -0.0749023 13.0583 -0.0749023 12.7333 0.250098L4.49999 8.4751Z"
fill={color}
/>
</Svg>
);
export default TickIcon;

View File

@@ -0,0 +1,22 @@
import * as React from 'react';
import Svg, {Mask, Rect, G, Path} from 'react-native-svg';
const UnsyncedIcon = () => (
<Svg width={20} height={20} viewBox="0 0 20 20" fill="none">
<Mask
id="mask0_417_40812"
maskUnits="userSpaceOnUse"
x={0}
y={0}
width={20}
height={20}>
<Rect width={20} height={20} fill="#D9D9D9" />
</Mask>
<G mask="url(#mask0_417_40812)">
<Path
d="M10.812 9.646L12.833 11.688C12.9997 11.8547 13.083 12.056 13.083 12.292C13.083 12.528 12.9997 12.7293 12.833 12.896C12.6663 13.0627 12.4617 13.146 12.219 13.146C11.9757 13.146 11.7707 13.0627 11.604 12.896L9.312 10.583C9.22933 10.4997 9.167 10.406 9.125 10.302C9.083 10.198 9.062 10.0903 9.062 9.979V6.708C9.062 6.472 9.149 6.26733 9.323 6.094C9.49633 5.92 9.70133 5.833 9.938 5.833C10.174 5.833 10.3787 5.92 10.552 6.094C10.7253 6.26733 10.812 6.472 10.812 6.708V9.646ZM10.021 17.5C8.34033 17.5 6.82633 17.0033 5.479 16.01C4.13167 15.0173 3.236 13.7153 2.792 12.104C2.72267 11.854 2.75033 11.618 2.875 11.396C2.99967 11.1733 3.18733 11.0343 3.438 10.979C3.68733 10.9237 3.906 10.9863 4.094 11.167C4.28133 11.3477 4.41667 11.5627 4.5 11.812C4.87467 13.0067 5.57267 13.9617 6.594 14.677C7.61467 15.3923 8.757 15.75 10.021 15.75C11.6183 15.75 12.9723 15.191 14.083 14.073C15.1943 12.955 15.75 11.5973 15.75 10C15.75 8.40267 15.1943 7.045 14.083 5.927C12.9723 4.809 11.6183 4.25 10.021 4.25C9.06233 4.25 8.15933 4.47233 7.312 4.917C6.46533 5.361 5.778 5.979 5.25 6.771H6.562C6.79867 6.771 7.00367 6.85767 7.177 7.031C7.351 7.205 7.438 7.41 7.438 7.646C7.438 7.882 7.351 8.08667 7.177 8.26C7.00367 8.434 6.79867 8.521 6.562 8.521H3.375C3.139 8.521 2.934 8.434 2.76 8.26C2.58667 8.08667 2.5 7.882 2.5 7.646V4.271C2.5 4.035 2.58667 3.83 2.76 3.656C2.934 3.48267 3.139 3.396 3.375 3.396C3.611 3.396 3.816 3.48267 3.99 3.656C4.16333 3.83 4.25 4.035 4.25 4.271V5.188C4.94467 4.29867 5.79867 3.62833 6.812 3.177C7.826 2.72567 8.89567 2.5 10.021 2.5C11.0483 2.5 12.017 2.69433 12.927 3.083C13.837 3.47233 14.632 4.00733 15.312 4.688C15.9927 5.368 16.5277 6.163 16.917 7.073C17.3057 7.983 17.5 8.95167 17.5 9.979C17.5 11.021 17.3057 11.9967 16.917 12.906C16.5277 13.816 15.9927 14.6113 15.312 15.292C14.632 15.972 13.8407 16.51 12.938 16.906C12.0347 17.302 11.0623 17.5 10.021 17.5Z"
fill="#969696"
/>
</G>
</Svg>
);
export default UnsyncedIcon;

View File

@@ -0,0 +1,15 @@
import * as React from 'react';
import Svg, {Path} from 'react-native-svg';
const WhatsAppIcon = () => (
<Svg width={16} height={16} viewBox="0 0 16 16" fill="none">
<Path
d="M4.2137 13.8382L4.47514 13.9679C5.54114 14.5972 6.75985 14.9261 8.00016 14.9192C11.8184 14.9106 14.9557 11.7897 14.9557 8.00036C14.9557 6.16902 14.2228 4.41033 12.9195 3.1139C11.618 1.80408 9.83982 1.06592 7.98666 1.06592C4.18581 1.06592 1.05859 4.1699 1.05859 7.94155C1.05859 7.97139 1.05859 8.00079 1.05903 8.03063C1.07048 9.31297 1.43187 10.5683 2.10478 11.663L2.27906 11.9225L1.58191 14.4738L4.2137 13.8382V13.8382Z"
fill="#69E382"
/>
<Path
d="M13.6949 2.33523C12.2113 0.832962 10.176 -0.00982963 8.05659 8.65243e-05H8.04308C3.67842 0.000100071 0.0867182 3.56463 0.0867182 7.89627C0.0867182 7.91659 0.087155 7.93649 0.087155 7.95682C0.103595 9.33401 0.462835 10.6858 1.13291 11.8919L0 16L4.22221 14.9189C5.38859 15.5544 6.69989 15.882 8.03045 15.8703C12.4113 15.8465 16.0025 12.2617 15.9999 7.91357C16.0104 5.8245 15.1803 3.81543 13.6949 2.33523ZM8.05659 14.5297C6.87715 14.5358 5.71847 14.2218 4.70585 13.6216L4.44441 13.4919L1.93027 14.1406L2.58386 11.6757L2.40957 11.4162C1.76217 10.3788 1.41918 9.18272 1.41916 7.96243C1.41916 4.36376 4.40303 1.40246 8.02915 1.40246C11.6553 1.40246 14.6391 4.36376 14.6391 7.96243C14.6391 10.2284 13.4561 12.3395 11.5163 13.5351C10.4903 14.1874 9.2968 14.5327 8.07839 14.5297M11.9084 9.72977L11.4291 9.51356C11.4291 9.51356 10.732 9.21085 10.2962 8.99465C10.2527 8.99465 10.2091 8.9514 10.1655 8.9514C10.0581 8.95403 9.95311 8.9838 9.8605 9.03789C9.7677 9.09194 9.81693 9.08113 9.20691 9.77301C9.16553 9.85388 9.08056 9.90448 8.98906 9.90275H8.94548C8.87997 9.89186 8.81927 9.86174 8.77119 9.81626L8.55333 9.72977C8.08586 9.53336 7.65783 9.25506 7.28971 8.90816C7.20257 8.82167 7.07185 8.73517 6.9847 8.64869C6.66213 8.34203 6.38357 7.99282 6.15683 7.61087L6.11325 7.52439C6.0754 7.47152 6.046 7.41318 6.0261 7.35141C6.01471 7.2765 6.03013 7.2 6.06967 7.1352C6.10933 7.07033 6.24397 6.91897 6.37468 6.78925C6.50541 6.65953 6.50541 6.57305 6.59255 6.48655C6.63734 6.42482 6.66829 6.35429 6.68332 6.2797C6.69835 6.20511 6.69711 6.12819 6.67969 6.05411C6.47663 5.49457 6.24392 4.94606 5.98253 4.41089C5.91247 4.30275 5.80332 4.22538 5.67752 4.19467H5.19822C5.11108 4.19467 5.02394 4.23791 4.93678 4.23791L4.89321 4.28115C4.80607 4.3244 4.71893 4.41089 4.63177 4.45413C4.54463 4.49737 4.50106 4.62711 4.41392 4.71359C4.10931 5.09561 3.94077 5.56699 3.93462 6.05411C3.93944 6.39677 4.01352 6.73498 4.15247 7.04871L4.19605 7.17843C4.5873 8.00859 5.13447 8.75709 5.80825 9.38383L5.98253 9.5568C6.10936 9.66105 6.22607 9.77688 6.33111 9.90275C7.23393 10.6824 8.30626 11.2446 9.464 11.546C9.59471 11.5892 9.76901 11.5892 9.89972 11.6325H10.3355C10.5632 11.6213 10.786 11.5624 10.989 11.4595C11.0958 11.4115 11.1977 11.3536 11.294 11.2865L11.3812 11.2C11.4683 11.1135 11.5555 11.0703 11.6426 10.9838C11.7278 10.9085 11.8012 10.8211 11.8605 10.7244C11.9442 10.5306 12.003 10.3274 12.0348 10.119V9.81626C11.9956 9.78134 11.9516 9.75221 11.9041 9.72977"
fill="white"
/>
</Svg>
);
export default WhatsAppIcon;

44
src/common/IconLabel.tsx Normal file
View File

@@ -0,0 +1,44 @@
import React from 'react';
import {
StyleProp,
StyleSheet,
TextStyle,
View,
ViewStyle as RNViewStyle,
} from 'react-native';
import Text from '../../RN-UI-LIB/src/components/Text';
import BulletIcon from '../assets/icons/BulletIcon';
interface IconLabelProps {
icon?: React.ReactNode;
text: string;
iconStyle?: StyleProp<TextStyle>;
textStyle?: StyleProp<TextStyle>;
containerStyle?: StyleProp<RNViewStyle>;
}
const IconLabel: React.FC<IconLabelProps> = props => {
const {icon, text, iconStyle, textStyle, containerStyle} = props;
return (
<View style={[styles.container, containerStyle]}>
<View style={[styles.icon, iconStyle]}>
{icon ? icon : <BulletIcon />}
</View>
<Text style={textStyle}>{text}</Text>
</View>
);
};
export default IconLabel;
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
},
icon: {
marginRight: 10,
lineHeight: 23,
width: 10,
},
});

View File

@@ -1,19 +1,16 @@
import React from 'react';
import {StyleSheet, View} from 'react-native';
import {SafeAreaView} from 'react-native';
import UserDetailsSection from './UserDetailsSection';
import {GenericStyles} from '../../../RN-UI-LIB/src/styles';
import TaskStepper from './journeyStepper/TaskStepper';
const CaseDetails: React.FC<any> = props => {
const CaseDetails: React.FC = () => {
return (
<View style={styles.caseDetailscontainer}>
<SafeAreaView style={[GenericStyles.fill, GenericStyles.p16]}>
<UserDetailsSection />
</View>
<TaskStepper />
</SafeAreaView>
);
};
const styles = StyleSheet.create({
caseDetailscontainer: {
paddingHorizontal: 16,
},
});
export default CaseDetails;

View File

@@ -1,8 +1,81 @@
import React from 'react';
import {View} from 'react-native';
import {StyleSheet, View} from 'react-native';
import {useSelector} from 'react-redux';
import {RootState} from '../../store/store';
import Avatar from '../../../RN-UI-LIB/src/components/Avatar';
import Heading from '../../../RN-UI-LIB/src/components/Heading';
import {GenericStyles} from '../../../RN-UI-LIB/src/styles';
import DocumentIcon from '../../assets/icons/DocumentIcon';
import IconLabel from '../../common/IconLabel';
import CalenderIcon from '../../assets/icons/CalenderIcon';
import Text from '../../../RN-UI-LIB/src/components/Text';
import {COLORS} from '../../../RN-UI-LIB/src/styles/colors';
const UserDetailsSection: React.FC<any> = props => {
return <View />;
const UserDetailsSection: React.FC = () => {
const {loanDetails, customerDetails} = useSelector((state: RootState) => ({
loanDetails: state.case.loanDetails,
customerDetails: state.case.customerInfo,
}));
const disbursalDate = loanDetails.disbursalDate;
const allocationDate = loanDetails.allocationDate;
return (
<View style={[GenericStyles.row, GenericStyles.pb16, styles.container]}>
<View style={[styles.avatarContainer]}>
<Avatar
name={customerDetails.customerName}
dataURI={customerDetails.imageURL}
/>
</View>
<View style={[styles.infoContainer]}>
<Heading dark type="h4">
{customerDetails.customerName}
</Heading>
<View style={[GenericStyles.row]}>
<IconLabel
containerStyle={{flex: 0.5}}
icon={<DocumentIcon />}
text={loanDetails.loanType}
/>
<IconLabel
text={loanDetails.loanAccountStatus}
containerStyle={{flex: 0.5}}
/>
</View>
<View style={[GenericStyles.row]}>
<IconLabel
icon={<CalenderIcon />}
text={disbursalDate}
containerStyle={{flex: 0.5}}
/>
<IconLabel
text={`${loanDetails.tenureMonths} months`}
containerStyle={{flex: 0.5}}
/>
</View>
<View style={[GenericStyles.pt16]}>
<Text style={[GenericStyles.fontSize15]}>
Allocated on {allocationDate}
</Text>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
avatarContainer: {
height: 60,
width: 60,
flex: 0.2,
},
container: {
borderBottomWidth: 1,
borderBottomColor: COLORS.BORDER.PRIMARY,
},
infoContainer: {
flex: 0.6,
},
});
export default UserDetailsSection;

View File

@@ -0,0 +1,73 @@
import {Linking, TouchableOpacity, View} from 'react-native';
import BottomSheet from '../../../../RN-UI-LIB/src/components/bottom_sheet/BottomSheet';
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
import Heading from '../../../../RN-UI-LIB/src/components/Heading';
import CloseIcon from '../../../../RN-UI-LIB/src/Icons/CloseIcon';
import {COLORS} from '../../../../RN-UI-LIB/src/styles/colors';
import IconLabel from '../../../common/IconLabel';
import CallViaSimIcon from '../../../assets/icons/CalViaSimIcon';
import WhatsAppIcon from '../../../assets/icons/WhatsAppIcon';
import React from 'react';
import {styles} from './TaskStepper';
interface CallingBottomSheetProps {
selectedPhoneNumber: string;
showCallingBottomSheet: boolean;
setShowCallingBottomSheet: React.Dispatch<React.SetStateAction<boolean>>;
}
const CallingBottomSheet: React.FC<CallingBottomSheetProps> = props => {
const {
selectedPhoneNumber,
showCallingBottomSheet,
setShowCallingBottomSheet,
} = props;
const callViaSim = () => {
Linking.openURL(`tel:${selectedPhoneNumber}`);
};
const callViaWhatsapp = () => {
Linking.openURL(`whatsapp://send?phone=${selectedPhoneNumber}`);
};
return (
<BottomSheet
heightPercentage={25}
visible={showCallingBottomSheet}
setVisible={() => setShowCallingBottomSheet(prev => !prev)}>
<View style={[GenericStyles.p16]}>
<View
style={[
GenericStyles.row,
GenericStyles.spaceBetween,
GenericStyles.alignCenter,
GenericStyles.mb24,
styles.bottomSheetHeader,
]}>
<Heading dark type="h5">
Call {selectedPhoneNumber} Via
</Heading>
<TouchableOpacity
activeOpacity={0.7}
onPress={() =>
setShowCallingBottomSheet(prev => !prev)
}>
<CloseIcon color={COLORS.TEXT.LIGHT} />
</TouchableOpacity>
</View>
<TouchableOpacity
style={[GenericStyles.row, GenericStyles.pb16]}
activeOpacity={0.7}
onPress={callViaSim}>
<IconLabel text="Sim Card" icon={<CallViaSimIcon />} />
</TouchableOpacity>
<TouchableOpacity
style={[GenericStyles.row]}
activeOpacity={0.7}
onPress={callViaWhatsapp}>
<IconLabel text="Whats App" icon={<WhatsAppIcon />} />
</TouchableOpacity>
</View>
</BottomSheet>
);
};
export default CallingBottomSheet;

View File

@@ -0,0 +1,90 @@
import {ScrollView, TouchableOpacity, View} from 'react-native';
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
import Heading from '../../../../RN-UI-LIB/src/components/Heading';
import CloseIcon from '../../../../RN-UI-LIB/src/Icons/CloseIcon';
import {COLORS} from '../../../../RN-UI-LIB/src/styles/colors';
import Options from '../../../../RN-UI-LIB/src/components/dropdown/Options';
import Button from '../../../../RN-UI-LIB/src/components/Button';
import BottomSheet from '../../../../RN-UI-LIB/src/components/bottom_sheet/BottomSheet';
import React from 'react';
import {styles} from './TaskStepper';
interface PhoneNumberSelectionBottomSheetProps {
showPhoneNumberBottomSheet: boolean;
setShowPhoneNumberBottomSheet: React.Dispatch<
React.SetStateAction<boolean>
>;
mobileNumbers: string[];
setShowCallingBottomSheet: React.Dispatch<React.SetStateAction<boolean>>;
selectedPhoneNumber: string;
setSelectedPhoneNumber: React.Dispatch<React.SetStateAction<string>>;
}
const PhoneNumberSelectionBottomSheet: React.FC<
PhoneNumberSelectionBottomSheetProps
> = props => {
const {
setShowPhoneNumberBottomSheet,
showPhoneNumberBottomSheet,
mobileNumbers,
setShowCallingBottomSheet,
selectedPhoneNumber,
setSelectedPhoneNumber,
} = props;
return (
<BottomSheet
heightPercentage={40}
visible={showPhoneNumberBottomSheet}
setVisible={() => setShowPhoneNumberBottomSheet(prev => !prev)}>
<View>
<View style={[GenericStyles.p16]}>
<>
<View
style={[
GenericStyles.row,
GenericStyles.spaceBetween,
GenericStyles.alignCenter,
styles.bottomSheetHeader,
]}>
<Heading dark type="h5">
Customer's Number
</Heading>
<TouchableOpacity
activeOpacity={0.7}
onPress={() =>
setShowPhoneNumberBottomSheet(prev => !prev)
}>
<CloseIcon color={COLORS.TEXT.LIGHT} />
</TouchableOpacity>
</View>
<ScrollView
style={[styles.phoneNumberSelectionSection]}>
{mobileNumbers.map(number => (
<Options
key={number}
id={number}
label={number}
selectedValue={selectedPhoneNumber}
handleSelection={id => {
setSelectedPhoneNumber(id);
// selectedPhoneNumber.current = id;
}}
/>
))}
</ScrollView>
<Button
style={{width: '100%', marginVertical: 10}}
title="Proceed"
onPress={() => {
setShowPhoneNumberBottomSheet(prev => !prev);
setShowCallingBottomSheet(prev => !prev);
}}
/>
</>
</View>
</View>
</BottomSheet>
);
};
export default PhoneNumberSelectionBottomSheet;

View File

@@ -0,0 +1,94 @@
import React from 'react';
import {View} from 'react-native';
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
import Heading from '../../../../RN-UI-LIB/src/components/Heading';
import {styles} from './TaskStepper';
import TickIcon from '../../../assets/icons/TickIcon';
import {COLORS} from '../../../../RN-UI-LIB/src/styles/colors';
import UnsyncedIcon from '../../../assets/icons/UnsyncedIcon';
import Tag from '../../../../RN-UI-LIB/src/components/Tag';
export const enum STEPPER_STATE {
DEFAULT = 'DEFAULT',
SYNCED = 'SYNCED',
UNSYNCED = 'UNSYNCED',
CURRENT = 'CURRENT',
}
interface IStepperHeader {
stepNumber: number;
header: string;
currentState: STEPPER_STATE;
verdict: any;
}
const StepperHeader: React.FC<IStepperHeader> = props => {
const {stepNumber, header, verdict, currentState} = props;
switch (currentState) {
case STEPPER_STATE.CURRENT:
return (
<View style={[GenericStyles.row, GenericStyles.alignCenter]}>
<View style={[GenericStyles.row, styles.stepperCurrent]}>
<Heading style={[GenericStyles.whiteText]} type="h3">
{stepNumber}
</Heading>
</View>
<View>
<Heading dark type="h3">
{header}
</Heading>
</View>
</View>
);
case STEPPER_STATE.DEFAULT:
return (
<View style={[GenericStyles.row, GenericStyles.alignCenter]}>
<View style={[GenericStyles.row, styles.stepperDefault]}>
<Heading type="h3">{stepNumber}</Heading>
</View>
<View>
<Heading dark type="h3">
{header}
</Heading>
</View>
</View>
);
case STEPPER_STATE.UNSYNCED:
return (
<View style={[GenericStyles.row, GenericStyles.alignCenter]}>
<View style={[GenericStyles.row, styles.stepperDefault]}>
<UnsyncedIcon />
</View>
<View>
<Heading dark type="h3">
{header}
</Heading>
</View>
</View>
);
case STEPPER_STATE.SYNCED:
return (
<View style={[GenericStyles.row, GenericStyles.alignCenter]}>
<View style={[GenericStyles.row, styles.stepperSynced]}>
{/*<Heading type="h3">{stepNumber}</Heading>*/}
<TickIcon color={COLORS.TEXT.BLUE} />
</View>
<View>
<Heading dark type="h3">
{header}
</Heading>
</View>
{verdict && (
<View style={[GenericStyles.ml8]}>
<Tag variant="success" text={verdict} />
</View>
)}
</View>
);
default:
return <></>;
}
};
export default StepperHeader;

View File

@@ -0,0 +1,39 @@
import {Linking, View} from 'react-native';
import Text from '../../../../RN-UI-LIB/src/components/Text';
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
import Button from '../../../../RN-UI-LIB/src/components/Button';
import React from 'react';
const TaskContent = ({
address,
geolocationUrl,
}: {
address?: any;
geolocationUrl: string | null;
}) => {
const openGeolocation = () => {
geolocationUrl && Linking.openURL(geolocationUrl);
};
return (
<View>
{address && (
<Text>
{`${address.houseNumber}, ${address.lineOne} , ${address.lineTwo} , ${address.locality} , ${address.street} , ${address.city} , ${address.state} - ${address.pincode}`}
</Text>
)}
<View style={[GenericStyles.row]}>
{geolocationUrl && (
<Button
style={{marginRight: 10}}
variant="secondary"
onPress={openGeolocation}
title="Open in maps"
/>
)}
<Button title="Add Feedback" />
</View>
</View>
);
};
export default TaskContent;

View File

@@ -0,0 +1,186 @@
import React from 'react';
import {PixelRatio, StyleSheet, View} from 'react-native';
import {COLORS} from '../../../../RN-UI-LIB/src/styles/colors';
import {GenericStyles} from '../../../../RN-UI-LIB/src/styles';
import Button from '../../../../RN-UI-LIB/src/components/Button';
import {useSelector} from 'react-redux';
import {RootState} from '../../../store/store';
import CallingBottomSheet from './CallingBottomSheet';
import PhoneNumberSelectionBottomSheet from './PhoneNumberSelectionBottomSheet';
import TaskContent from './TaskContent';
import StepperHeader, {STEPPER_STATE} from './StepperHeader';
interface IStepperContent {
content?: React.ReactNode;
}
const StepperContent: React.FC<IStepperContent> = props => {
const {content} = props;
if (content) {
return <View style={[styles.stepperContent]}>{content}</View>;
}
return <View style={[styles.emptyContent]} />;
};
const TaskStepper: React.FC = () => {
const [showPhoneNumberBottomSheet, setShowPhoneNumberBottomSheet] =
React.useState(false);
const [showCallingBottomSheet, setShowCallingBottomSheet] =
React.useState(false);
const {tasks, context, mobileNumbers} = useSelector((state: RootState) => ({
mobileNumbers: state.case.customerInfo.mobileNumbers,
tasks: state.case.tasks,
context: state.case.context,
}));
const [selectedPhoneNumber, setSelectedPhoneNumber] = React.useState('');
return (
<>
<View style={[GenericStyles.p16]}>
{tasks.map((task, index) => {
const verdict =
// @ts-ignore
context.tasks[task.taskTypeId] &&
// @ts-ignore
context.tasks[task.taskTypeId].length > 0 ? context.tasks[task.taskTypeId][context.tasks[task.taskTypeId].length - 1].verdict
: null;
const currentState =
context.currentTask === task.taskTypeId
? STEPPER_STATE.CURRENT
: task.isSynced && verdict
? STEPPER_STATE.SYNCED
: task.isSynced
? STEPPER_STATE.DEFAULT
: STEPPER_STATE.UNSYNCED;
if (context.currentTask === task.taskTypeId) {
return (
<>
<StepperHeader
verdict={verdict}
currentState={currentState}
stepNumber={index + 1}
header={task.taskTypeId}
/>
<StepperContent
content={
<TaskContent
address={task.metadata.address}
geolocationUrl={
task.metadata.geoLocation
}
/>
}
/>
</>
);
}
return (
<>
<StepperHeader
verdict={verdict}
stepNumber={index + 1}
header={task.taskTypeId}
currentState={currentState}
/>
<StepperContent />
</>
);
})}
</View>
<View style={[GenericStyles.row, styles.journeyContainer]}>
<Button
style={[styles.callCustomerButton]}
title="Call Customer"
variant="secondary"
onPress={() => setShowPhoneNumberBottomSheet(true)}
/>
</View>
<PhoneNumberSelectionBottomSheet
showPhoneNumberBottomSheet={showPhoneNumberBottomSheet}
selectedPhoneNumber={selectedPhoneNumber}
mobileNumbers={mobileNumbers}
setShowPhoneNumberBottomSheet={setShowPhoneNumberBottomSheet}
setShowCallingBottomSheet={setShowCallingBottomSheet}
setSelectedPhoneNumber={setSelectedPhoneNumber}
/>
<CallingBottomSheet
setShowCallingBottomSheet={setShowCallingBottomSheet}
showCallingBottomSheet={showCallingBottomSheet}
selectedPhoneNumber={selectedPhoneNumber}
/>
</>
);
};
export const styles = StyleSheet.create({
journeyContainer: {
borderTopWidth: 1,
borderTopColor: COLORS.BORDER.PRIMARY,
},
stepperCurrent: {
height: PixelRatio.roundToNearestPixel(32),
width: PixelRatio.roundToNearestPixel(32),
borderRadius: 20,
alignSelf: 'flex-start',
backgroundColor: COLORS.TEXT.BLUE,
marginRight: 11,
justifyContent: 'center',
alignItems: 'center',
},
stepperDefault: {
height: PixelRatio.roundToNearestPixel(32),
width: PixelRatio.roundToNearestPixel(32),
borderRadius: 20,
alignSelf: 'flex-start',
backgroundColor: COLORS.BACKGROUND.PRIMARY,
borderColor: COLORS.BORDER.PRIMARY,
borderWidth: 1,
marginRight: 11,
justifyContent: 'center',
alignItems: 'center',
},
stepperSynced: {
height: PixelRatio.roundToNearestPixel(32),
width: PixelRatio.roundToNearestPixel(32),
borderRadius: 20,
alignSelf: 'flex-start',
backgroundColor: COLORS.BACKGROUND.BLUE,
borderColor: COLORS.BORDER.BLUE,
borderWidth: 1,
marginRight: 11,
justifyContent: 'center',
alignItems: 'center',
},
callCustomerButton: {width: '100%', marginVertical: 10},
emptyContent: {
marginVertical: 8,
marginLeft: 16,
borderLeftWidth: 1,
borderLeftColor: COLORS.BORDER.PRIMARY,
height: 8,
},
stepperContent: {
marginVertical: 8,
marginLeft: 16,
borderLeftWidth: 1,
borderLeftColor: COLORS.BORDER.PRIMARY,
paddingLeft: 28.5,
},
bottomSheetHeader: {
borderBottomWidth: 1,
borderBottomColor: COLORS.BORDER.PRIMARY,
paddingBottom: 20,
},
phoneNumberSelectionSection: {
paddingBottom: 30,
height: 175,
},
bottomSheetButton: {
position: 'absolute',
bottom: 0,
},
});
export default TaskStepper;

View File

@@ -4,6 +4,139 @@ import {createSlice} from '@reduxjs/toolkit';
export const counterSlice = createSlice({
name: 'case',
initialState: {
loanDetails: {
loanAccountNumber: '100',
disbursalDate: '2022-12-06',
allocationDate: '2022-12-06',
disbursementAmount: 100,
firstDueDate: '2022-12-06',
tenureMonths: 10,
loanType: 'PERSONAL',
loanAccountStatus: 'ACTIVE',
productCode: 'PL-003',
},
// customerInfo: {
// name: 'Abhinav bindra upadhyay',
// age: 25,
// imageUrl:
// 'https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/Elon_Musk_Royal_Society_%28crop2%29.jpg/1200px-Elon_Musk_Royal_Society_%28crop2%29.jpg',
// mobileNumbers: [
// '999991245',
// '7821234573',
// '1231943281',
// '9585437411',
// '9811873334',
// ],
// },
customerInfo: {
customerReferenceId: '3d808ea0-cd17-4877-8e49-c3e310c58ad2',
customerName: 'Likhith',
primaryPhoneNumber: '8436942857',
imageURL:
'https://upload.wikimedia.org/wikipedia/commons/thumb/3/34/Elon_Musk_Royal_Society_%28crop2%29.jpg/1200px-Elon_Musk_Royal_Society_%28crop2%29.jpg',
geoLocation: 'vdvvfbfbfb',
mobileNumbers: [
'999991245',
'7821234573',
'1231943281',
'9585437411',
'9811873334',
],
},
tasks: [
{
taskId: 'asdaxcvxcvsd',
taskTypeId: 'COMMUNICATION',
isSynced: true,
metadata: {
address: {
referenceId: 'asdasd',
houseNumber: '301',
lineOne: 'Tranquility Appartment',
lineTwo: 'ST Bed Layout',
locality: 'Kormangla',
street: '8th Cross Road',
city: 'Bengaluru',
state: 'Karnataka',
pincode: '110085',
type: 'COMMUNICATION',
source: 'Pata nahi',
current: true,
permanent: true,
zipcode: '110085',
addressQualityStatus: 'asdsad',
},
geoLocation: null,
},
},
{
taskId: 'asdasdasdasdasdas',
taskTypeId: 'PERMANENT',
isSynced: true,
metadata: {
address: {
referenceId: 'asdasd',
houseNumber: '301',
lineOne: 'Tranquility Appartment',
lineTwo: 'ST Bed Layout',
locality: 'Kormangla',
street: '8th Cross Road',
city: 'Bengaluru',
state: 'Karnataka',
pincode: '110085',
type: 'COMMUNICATION',
source: 'Pata nahi',
current: true,
permanent: true,
zipcode: '110085',
addressQualityStatus: 'asdsad',
},
geoLocation: null,
},
},
{
taskId: 'asdasdasdasdasdas',
taskTypeId: 'GEOLOCATION',
isSynced: true,
metadata: {
address: {
referenceId: 'asdasd',
houseNumber: '301',
lineOne: 'Tranquility Appartment',
lineTwo: 'ST Bed Layout',
locality: 'Kormangla',
street: '8th Cross Road',
city: 'Bengaluru',
state: 'Karnataka',
pincode: '110085',
type: 'COMMUNICATION',
source: 'Pata nahi',
current: true,
permanent: true,
zipcode: '110085',
addressQualityStatus: 'asdsad',
},
geoLocation: 'vdvvfbfbfb',
},
},
],
context: {
taskSequence: ['COMMUNICATION', 'PERMANENT', 'GEOLOCATION'],
currentTask: 'GEOLOCATION',
tasks: {
COMMUNICATION: [
{
verdict: 'Verified',
},
],
PERMANENT: [
{
verdict: 'Verified',
},
],
GEOLOCATION: [],
},
},
value: 0,
caseForm: {},
},
@@ -29,10 +162,14 @@ export const counterSlice = createSlice({
data[caseId][journeyId][widgetId] = answer;
state.caseForm = data;
},
updateDate: (state, action) => {
const {date} = action.payload;
state.loanInfo.allocationDate = date;
},
},
});
export const {increaseByOne, decreaseByOne, updateInteraction} =
export const {increaseByOne, decreaseByOne, updateInteraction, updateDate} =
counterSlice.actions;
export default counterSlice.reducer;

View File

@@ -22,7 +22,8 @@ const persistConfig = {
key: 'root',
version: 1,
storage: AsyncStorage,
whitelist: ['case'],
// whitelist: ['case'],
blacklist: ['case'],
};
const persistedReducer = persistReducer(persistConfig, rootReducer);