diff --git a/RN-UI-LIB b/RN-UI-LIB
index 69b6c0b7..d19cd8f5 160000
--- a/RN-UI-LIB
+++ b/RN-UI-LIB
@@ -1 +1 @@
-Subproject commit 69b6c0b76feb0d1e48456b25377aee2faa166a5d
+Subproject commit d19cd8f56bf491b2eeee12eca853c119742c0535
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 84518593..78d77126 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -113,8 +113,8 @@ def jscFlavor = 'org.webkit:android-jsc:+'
def enableHermes = project.ext.react.get("enableHermes", false);
-def VERSION_CODE = 250
-def VERSION_NAME = "2.18.7"
+def VERSION_CODE = 251
+def VERSION_NAME = "2.18.8"
android {
namespace "com.avapp"
diff --git a/buildFlavor/field/buildNumber.txt b/buildFlavor/field/buildNumber.txt
index 8a32cf78..f123c4f4 100644
--- a/buildFlavor/field/buildNumber.txt
+++ b/buildFlavor/field/buildNumber.txt
@@ -1 +1 @@
-250
\ No newline at end of file
+251
\ No newline at end of file
diff --git a/buildFlavor/field/buildVersion.txt b/buildFlavor/field/buildVersion.txt
index 394c48dd..caa23986 100644
--- a/buildFlavor/field/buildVersion.txt
+++ b/buildFlavor/field/buildVersion.txt
@@ -1 +1 @@
-2.18.7
\ No newline at end of file
+2.18.8
\ No newline at end of file
diff --git a/buildFlavor/tele/buildNumber.txt b/buildFlavor/tele/buildNumber.txt
index e0da8ae0..3bac779c 100644
--- a/buildFlavor/tele/buildNumber.txt
+++ b/buildFlavor/tele/buildNumber.txt
@@ -1 +1 @@
-309
\ No newline at end of file
+310
\ No newline at end of file
diff --git a/buildFlavor/tele/buildVersion.txt b/buildFlavor/tele/buildVersion.txt
index 065ed156..9f7b5569 100644
--- a/buildFlavor/tele/buildVersion.txt
+++ b/buildFlavor/tele/buildVersion.txt
@@ -1 +1 @@
-100.2.5
\ No newline at end of file
+100.2.6
\ No newline at end of file
diff --git a/package.json b/package.json
index ce474575..cf4798d9 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "AV_APP",
- "version": "2.18.7",
- "buildNumber": "250",
+ "version": "2.18.8",
+ "buildNumber": "251",
"private": true,
"scripts": {
"android:dev": "yarn move:dev && react-native run-android",
diff --git a/src/action/filterActions.ts b/src/action/filterActions.ts
index cf76c004..65440a23 100644
--- a/src/action/filterActions.ts
+++ b/src/action/filterActions.ts
@@ -12,6 +12,7 @@ dayjs.extend(timezone);
export const CoachMarkFeatures = {
CASE_STATUS_FILTERS: 'caseStatusFilters',
+ TOP_5_ADDRESSES: 'top5Addresses'
};
export const showCoachMark = async (
diff --git a/src/assets/icons/AddFeedbackIcon.tsx b/src/assets/icons/AddFeedbackIcon.tsx
new file mode 100644
index 00000000..d6afbabc
--- /dev/null
+++ b/src/assets/icons/AddFeedbackIcon.tsx
@@ -0,0 +1,56 @@
+import * as React from 'react';
+import Svg, { Path } from 'react-native-svg';
+const AddFeedbackIcon = () => (
+
+);
+export default AddFeedbackIcon;
diff --git a/src/assets/icons/CopyOutlineIcon.tsx b/src/assets/icons/CopyOutlineIcon.tsx
new file mode 100644
index 00000000..e07d00ef
--- /dev/null
+++ b/src/assets/icons/CopyOutlineIcon.tsx
@@ -0,0 +1,17 @@
+import * as React from 'react';
+import Svg, { Mask, Rect, G, Path } from 'react-native-svg';
+
+const CopyOutlineIcon = () => (
+
+);
+export default CopyOutlineIcon;
diff --git a/src/assets/icons/GoogleMapIcon.tsx b/src/assets/icons/GoogleMapIcon.tsx
new file mode 100644
index 00000000..0dd1df1c
--- /dev/null
+++ b/src/assets/icons/GoogleMapIcon.tsx
@@ -0,0 +1,27 @@
+import * as React from 'react';
+import Svg, { Path } from 'react-native-svg';
+const GoogleMapIcon = () => (
+
+);
+export default GoogleMapIcon;
diff --git a/src/assets/icons/LocationOnMap3DIcon.tsx b/src/assets/icons/LocationOnMap3DIcon.tsx
new file mode 100644
index 00000000..9043a421
--- /dev/null
+++ b/src/assets/icons/LocationOnMap3DIcon.tsx
@@ -0,0 +1,45 @@
+import * as React from 'react';
+import Svg, { Path, Ellipse } from 'react-native-svg';
+const LocationOnMap3DIcon = () => (
+
+);
+export default LocationOnMap3DIcon;
diff --git a/src/assets/icons/LocationOnMapIcon.tsx b/src/assets/icons/LocationOnMapIcon.tsx
new file mode 100644
index 00000000..6daf679a
--- /dev/null
+++ b/src/assets/icons/LocationOnMapIcon.tsx
@@ -0,0 +1,48 @@
+import * as React from 'react';
+import Svg, { Path } from 'react-native-svg';
+const LocationOnMapIcon = () => (
+
+);
+export default LocationOnMapIcon;
diff --git a/src/assets/icons/LollipopIcon.tsx b/src/assets/icons/LollipopIcon.tsx
new file mode 100644
index 00000000..6dc51b85
--- /dev/null
+++ b/src/assets/icons/LollipopIcon.tsx
@@ -0,0 +1,23 @@
+import * as React from 'react';
+import Svg, { Path } from 'react-native-svg';
+
+const LollipopIcon = () => (
+
+);
+export default LollipopIcon;
diff --git a/src/assets/icons/MapDirectionFilledIcon.tsx b/src/assets/icons/MapDirectionFilledIcon.tsx
new file mode 100644
index 00000000..e1cde36f
--- /dev/null
+++ b/src/assets/icons/MapDirectionFilledIcon.tsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import { G, Mask, Path, Rect, Svg } from 'react-native-svg';
+
+const MapDirectionFilledIcon = () => {
+ return (
+
+ );
+};
+
+export default MapDirectionFilledIcon;
diff --git a/src/assets/icons/MapDirectionIcon.tsx b/src/assets/icons/MapDirectionIcon.tsx
new file mode 100644
index 00000000..1387326e
--- /dev/null
+++ b/src/assets/icons/MapDirectionIcon.tsx
@@ -0,0 +1,17 @@
+import * as React from 'react';
+import Svg, { Mask, Rect, G, Path } from 'react-native-svg';
+
+const MapDirectionIcon = () => (
+
+);
+export default MapDirectionIcon;
diff --git a/src/assets/icons/OldFeedbacksIcon.tsx b/src/assets/icons/OldFeedbacksIcon.tsx
new file mode 100644
index 00000000..a4eaaf83
--- /dev/null
+++ b/src/assets/icons/OldFeedbacksIcon.tsx
@@ -0,0 +1,56 @@
+import * as React from 'react';
+import Svg, { Path } from 'react-native-svg';
+const OldFeedbacksIcon = () => (
+
+);
+export default OldFeedbacksIcon;
diff --git a/src/assets/icons/RankTagIcon.tsx b/src/assets/icons/RankTagIcon.tsx
new file mode 100644
index 00000000..33d1d29a
--- /dev/null
+++ b/src/assets/icons/RankTagIcon.tsx
@@ -0,0 +1,16 @@
+import * as React from 'react';
+import Svg, { Path, Rect } from 'react-native-svg';
+
+const RankTagIcon = () => (
+
+);
+
+export default RankTagIcon;
diff --git a/src/assets/icons/TickSmallIcon.tsx b/src/assets/icons/TickSmallIcon.tsx
new file mode 100644
index 00000000..929922fe
--- /dev/null
+++ b/src/assets/icons/TickSmallIcon.tsx
@@ -0,0 +1,15 @@
+import * as React from 'react';
+import Svg, { Path } from 'react-native-svg';
+
+const TickSmallIcon = () => (
+
+);
+export default TickSmallIcon;
diff --git a/src/assets/icons/TickSmallSolidIcon.tsx b/src/assets/icons/TickSmallSolidIcon.tsx
new file mode 100644
index 00000000..16549c02
--- /dev/null
+++ b/src/assets/icons/TickSmallSolidIcon.tsx
@@ -0,0 +1,18 @@
+import * as React from 'react';
+import Svg, { G, Mask, Path, Rect } from 'react-native-svg';
+
+const TickSmallSolidIcon = () => (
+
+);
+export default TickSmallSolidIcon;
diff --git a/src/assets/icons/VisitedTagIcon.tsx b/src/assets/icons/VisitedTagIcon.tsx
new file mode 100644
index 00000000..154e6c44
--- /dev/null
+++ b/src/assets/icons/VisitedTagIcon.tsx
@@ -0,0 +1,30 @@
+import * as React from 'react';
+import Svg, { Path } from 'react-native-svg';
+
+const VisitedTagIcon = () => (
+
+);
+export default VisitedTagIcon;
diff --git a/src/assets/lottie/SwipeAnimation.json b/src/assets/lottie/SwipeAnimation.json
new file mode 100644
index 00000000..0abab25a
--- /dev/null
+++ b/src/assets/lottie/SwipeAnimation.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":25,"ip":0,"op":70,"w":125,"h":125,"nm":"Swipe icon for animation 1x","ddd":0,"assets":[{"id":"comp_0","nm":"Swipe icon for animation 5x","fr":25,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Finger outline","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.735],"y":[1]},"o":{"x":[0.447],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.628],"y":[0]},"t":8.19,"s":[18]},{"i":{"x":[0.782],"y":[1]},"o":{"x":[0.484],"y":[0]},"t":11.515,"s":[18]},{"i":{"x":[0.479],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":31.026,"s":[-20]},{"t":41,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.738,"y":1},"o":{"x":0.447,"y":0},"t":0,"s":[254.895,395.88,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.628,"y":0.628},"t":8.19,"s":[284.895,395.88,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.782,"y":1},"o":{"x":0.484,"y":0},"t":11.515,"s":[284.895,395.88,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.479,"y":1},"o":{"x":0.333,"y":0},"t":31.026,"s":[210.895,395.88,0],"to":[0,0,0],"ti":[0,0,0]},{"t":41,"s":[254.895,395.88,0]}],"ix":2,"l":2},"a":{"a":0,"k":[112.203,273.98,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.704,"y":1},"o":{"x":0.634,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[7.999,-5.792],[-4.873,-7.86],[0,0],[-20.501,0.092],[0,0],[-16.502,24.179],[-1.057,4.827],[-0.874,36.819],[0.166,9.493],[4.332,3.554],[3.664,0.488],[0,0],[18.156,2.712],[0,0],[18.111,2.483],[2.62,-21.559],[0,0],[8.044,0],[0,-8.045],[0,0]],"o":[[0,0],[-5.7,-8.044],[-7.492,5.424],[0,0],[11.951,19.26],[0,0],[0,0],[2.804,-4.091],[2.253,-10.572],[0,0],[-0.098,-5.603],[-2.223,-1.823],[-11.4,-1.517],[0,0],[-18.157,-2.712],[0,0],[0,0],[0,0],[0,-8.091],[-8.09,0],[0,0],[0,0]],"v":[[-32.299,27.832],[-61.947,-14.089],[-86.77,-18.18],[-91.366,5.401],[-32.023,101.057],[23.78,131.44],[24.608,131.44],[82.294,109.836],[87.902,96.138],[95.717,22.914],[96.072,-4.672],[89.27,-19.233],[80.503,-23.052],[62.392,-9.4],[48.97,-35.463],[29.617,-19.559],[15.965,-45.622],[-3.018,-26.775],[-3.018,-107.397],[-17.635,-122.015],[-32.253,-107.397],[-32.253,27.787]],"c":true}]},{"i":{"x":0.851,"y":1},"o":{"x":0.628,"y":0},"t":8.021,"s":[{"i":[[0,0],[0,0],[7.999,-5.792],[-4.873,-7.86],[0,0],[-20.501,0.092],[0,0],[-16.502,24.179],[-1.057,4.827],[-0.874,36.819],[0.166,9.493],[4.332,3.554],[3.664,0.488],[0,0],[18.156,2.712],[0,0],[18.111,2.483],[2.62,-21.559],[0,0],[8.044,0],[0,-8.045],[0,0]],"o":[[0,0],[-5.7,-8.044],[-7.492,5.424],[0,0],[11.951,19.26],[0,0],[0,0],[2.804,-4.091],[2.253,-10.572],[0,0],[-0.098,-5.603],[-2.223,-1.823],[-11.4,-1.517],[0,0],[-18.157,-2.712],[0,0],[0,0],[0,0],[0,-8.091],[-8.09,0],[0,0],[0,0]],"v":[[-32.299,27.832],[-61.947,-14.089],[-86.77,-18.18],[-91.366,5.401],[-32.023,101.057],[23.78,131.44],[24.608,131.44],[82.294,109.836],[87.902,96.138],[95.717,22.914],[96.072,-4.672],[89.27,-19.233],[80.503,-23.052],[62.392,-9.4],[48.97,-35.463],[29.617,-19.559],[15.965,-45.622],[-3.018,-26.775],[-1.047,-87.445],[-15.664,-102.063],[-30.282,-87.445],[-32.253,27.787]],"c":true}]},{"i":{"x":0.577,"y":1},"o":{"x":0.628,"y":0},"t":11.587,"s":[{"i":[[0,0],[0,0],[7.999,-5.792],[-4.873,-7.86],[0,0],[-20.501,0.092],[0,0],[-16.502,24.179],[-1.057,4.827],[-0.874,36.819],[0.166,9.493],[4.332,3.554],[3.664,0.488],[0,0],[18.156,2.712],[0,0],[18.111,2.483],[2.62,-21.559],[0,0],[8.044,0],[0,-8.045],[0,0]],"o":[[0,0],[-5.7,-8.044],[-7.492,5.424],[0,0],[11.951,19.26],[0,0],[0,0],[2.804,-4.091],[2.253,-10.572],[0,0],[-0.098,-5.603],[-2.223,-1.823],[-11.4,-1.517],[0,0],[-18.157,-2.712],[0,0],[0,0],[0,0],[0,-8.091],[-8.09,0],[0,0],[0,0]],"v":[[-32.299,27.832],[-61.947,-14.089],[-86.77,-18.18],[-91.366,5.401],[-32.023,101.057],[23.78,131.44],[24.608,131.44],[82.294,109.836],[87.902,96.138],[95.717,22.914],[96.072,-4.672],[89.27,-19.233],[80.503,-23.052],[62.392,-9.4],[48.97,-35.463],[29.617,-19.559],[15.965,-45.622],[-3.018,-26.775],[-1.047,-87.445],[-15.664,-102.063],[-30.282,-87.445],[-32.253,27.787]],"c":true}]},{"i":{"x":0.699,"y":1},"o":{"x":0.467,"y":0},"t":31,"s":[{"i":[[0,0],[0,0],[7.999,-5.792],[-4.873,-7.86],[0,0],[-20.501,0.092],[0,0],[-16.502,24.179],[-1.057,4.827],[-0.874,36.819],[0.166,9.493],[4.332,3.554],[3.664,0.488],[0,0],[18.156,2.712],[0,0],[18.111,2.483],[2.62,-21.559],[0,0],[8.044,0],[0,-8.045],[0,0]],"o":[[0,0],[-5.7,-8.044],[-7.492,5.424],[0,0],[11.951,19.26],[0,0],[0,0],[2.804,-4.091],[2.253,-10.572],[0,0],[-0.098,-5.603],[-2.223,-1.823],[-11.4,-1.517],[0,0],[-18.157,-2.712],[0,0],[0,0],[0,0],[-1.359,-7.89],[-8.09,0],[0,0],[0,0]],"v":[[-32.299,27.832],[-61.947,-14.089],[-86.77,-18.18],[-91.366,5.401],[-32.023,101.057],[23.78,131.44],[24.608,131.44],[82.294,109.836],[87.902,96.138],[95.717,22.914],[96.072,-4.672],[89.27,-19.233],[80.503,-23.052],[62.392,-9.4],[48.97,-35.463],[29.617,-19.559],[15.965,-45.622],[-3.018,-26.775],[-24.047,-97.843],[-38.664,-112.461],[-53.282,-97.843],[-32.253,27.787]],"c":true}]},{"t":41,"s":[{"i":[[0,0],[0,0],[7.999,-5.792],[-4.873,-7.86],[0,0],[-20.501,0.092],[0,0],[-16.502,24.179],[-1.057,4.827],[-0.874,36.819],[0.166,9.493],[4.332,3.554],[3.664,0.488],[0,0],[18.156,2.712],[0,0],[18.111,2.483],[2.62,-21.559],[0,0],[8.044,0],[0,-8.045],[0,0]],"o":[[0,0],[-5.7,-8.044],[-7.492,5.424],[0,0],[11.951,19.26],[0,0],[0,0],[2.804,-4.091],[2.253,-10.572],[0,0],[-0.098,-5.603],[-2.223,-1.823],[-11.4,-1.517],[0,0],[-18.157,-2.712],[0,0],[0,0],[0,0],[0,-8.091],[-8.09,0],[0,0],[0,0]],"v":[[-32.299,27.832],[-61.947,-14.089],[-86.77,-18.18],[-91.366,5.401],[-32.023,101.057],[23.78,131.44],[24.608,131.44],[82.294,109.836],[87.902,96.138],[95.717,22.914],[96.072,-4.672],[89.27,-19.233],[80.503,-23.052],[62.392,-9.4],[48.97,-35.463],[29.617,-19.559],[15.965,-45.622],[-3.018,-26.775],[-3.018,-107.397],[-17.635,-122.015],[-32.253,-107.397],[-32.253,27.787]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":9.965,"ix":5},"lc":1,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[106.203,143.98],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Arrow pointer","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":28,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":31,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":49,"s":[100]},{"t":52,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100.5,95,0],"ix":2,"l":2},"a":{"a":0,"k":[24.965,37.465,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[15,-27.5],[-15,-2.5],[15,27.5]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":28,"s":[100]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":31,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":49,"s":[0]},{"t":52,"s":[100]}],"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":9.965,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[24.965,37.465],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Arrow line","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.825,"y":1},"o":{"x":0.423,"y":0},"t":12,"s":[272,92.5,0],"to":[0,0,0],"ti":[0,0,0]},{"t":37,"s":[248,92.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[139.982,4.982,0],"ix":1,"l":2},"s":{"a":0,"k":[107.593,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[274.982,4.982],[-6.171,4.982]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.46],"y":[1]},"o":{"x":[0.103],"y":[0]},"t":37,"s":[0]},{"t":52,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.71],"y":[1]},"o":{"x":[0.658],"y":[0]},"t":11,"s":[0]},{"t":28.5947265625,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":9.965,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":11,"op":150,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Swipe icon for animation 5x","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[62.5,62.5,0],"ix":2,"l":2},"a":{"a":0,"k":[250,250,0],"ix":1,"l":2},"s":{"a":0,"k":[25,25,100],"ix":6,"l":2}},"ao":0,"w":500,"h":500,"ip":0,"op":150,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/src/common/Constants.ts b/src/common/Constants.ts
index ad328041..4e9fe847 100644
--- a/src/common/Constants.ts
+++ b/src/common/Constants.ts
@@ -1346,27 +1346,27 @@ export const CLICKSTREAM_EVENT_NAMES = {
},
FA_UNSYNC_FEEDBACK_CAPTURED: {
name: 'FA_UNSYNC_FEEDBACK_CAPTURED',
- description: 'Unsync feedback captured'
+ description: 'Unsync feedback captured',
},
FA_UNSYNC_FEEDBACK_CAPTURING: {
name: 'FA_UNSYNC_FEEDBACK_CAPTURING',
- description: 'Feedback capturing'
+ description: 'Feedback capturing',
},
FA_UNSYNC_FEEDBACK_CAPTURE_SUCCESS: {
name: 'FA_UNSYNC_FEEDBACK_CAPTURE_SUCCESS',
- description: 'Feedback capture success'
+ description: 'Feedback capture success',
},
FA_FEEDBACK_SUCCESS: {
name: 'FA_FEEDBACK_SUCCESS',
- description: 'Feedback capture success'
+ description: 'Feedback capture success',
},
FA_ORIGINAL_IMAGE_UPLOADING: {
name: 'FA_ORIGINAL_IMAGE_UPLOADING',
- description: 'Original image uploading'
+ description: 'Original image uploading',
},
FA_WRONG_QUESTION_KEY: {
name: 'FA_WRONG_QUESTION_KEY',
- description: 'Wrong question key'
+ description: 'Wrong question key',
},
FA_API_FAILED: {
name: 'FA_API_FAILED',
@@ -1495,7 +1495,45 @@ export const CLICKSTREAM_EVENT_NAMES = {
FA_COSMOS_CONNECTED_CALL_EVENTS: {
name: 'FA_COSMOS_CONNECTED_CALL_EVENTS',
description: 'Cosmos connected call events',
- }
+ },
+
+ // Top Addresses
+ FA_VIEW_TOP_ADDRESSES_CLICKED: {
+ name: 'FA_VIEW_TOP_ADDRESSES_CLICKED',
+ description: 'View top addresses clicked',
+ },
+ FA_TOP_ADDRESSES_SCREEN_LOADED: {
+ name: 'FA_TOP_ADDRESSES_SCREEN_LOADED',
+ description: 'Top addresses screen loaded',
+ },
+ FA_DIRECTIONS_BUTTON_CLICKED: {
+ name: 'FA_DIRECTIONS_BUTTON_CLICKED',
+ description: 'Directions button clicked',
+ },
+ FA_OPEN_MAP_BUTTON_CLICKED: {
+ name: 'FA_OPEN_MAP_BUTTON_CLICKED',
+ description: 'Open map button clicked',
+ },
+ FA_VIEW_SIMILAR_ADDRESSES_BUTTON_CLICKED: {
+ name: 'FA_VIEW_SIMILAR_ADDRESSES_BUTTON_CLICKED',
+ description: 'View similar addresses button clicked',
+ },
+ FA_VIEW_OTHER_ADDRESSES_CLICKED: {
+ name: 'FA_VIEW_OTHER_ADDRESSES_CLICKED',
+ description: 'View other addresses clicked',
+ },
+ FA_OTHER_ADDRESSES_SCREEN_LOADED: {
+ name: 'FA_OTHER_ADDRESSES_SCREEN_LOADED',
+ description: 'Top addresses screen loaded',
+ },
+ FA_CAROUSEL_ADDRESS_PAGINATION_CLICKED: {
+ name: 'FA_CAROUSEL_ADDRESS_PAGINATION_CLICKED',
+ description: 'Carousel address pagination clicked',
+ },
+ FA_CAROUSEL_ADDRESS_SWIPE_GESTURE: {
+ name: 'FA_CAROUSEL_ADDRESS_SWIPE_GESTURE',
+ description: 'Carousel address swipe gesture',
+ },
} as const;
export enum MimeType {
@@ -1635,7 +1673,6 @@ export const HIT_SLOP = {
right: 8,
};
-
export const SELF_CALL_SHARED_PREFERENCE_KEY = 'selfCallSharedPreference';
export const LITMUS_URL = 'https://longhorn.navi.com/litmus';
diff --git a/src/common/ModalWrapperForAlfredV2.tsx b/src/common/ModalWrapperForAlfredV2.tsx
index 6e85cc3c..ce40973e 100644
--- a/src/common/ModalWrapperForAlfredV2.tsx
+++ b/src/common/ModalWrapperForAlfredV2.tsx
@@ -1,11 +1,7 @@
-import React, { useEffect } from 'react';
+import React from 'react';
import { Modal, NativeSyntheticEvent, View, findNodeHandle } from 'react-native';
import { IModalWrapper } from '../../RN-UI-LIB/src/components/modalWrapper/ModalWrapper';
-import {
- clearBottomSheet,
- sendBottomSheetOpenSignal,
- setBottomSheetView,
-} from '../components/utlis/DeviceUtils';
+import { clearBottomSheet, setBottomSheetView } from '../components/utlis/DeviceUtils';
import { GenericStyles } from '@rn-ui-lib/styles';
const ModalWrapperForAlfredV2: React.FC = ({ children, ...props }) => {
diff --git a/src/common/ShadowLine.tsx b/src/common/ShadowLine.tsx
new file mode 100644
index 00000000..0d0a1c06
--- /dev/null
+++ b/src/common/ShadowLine.tsx
@@ -0,0 +1,41 @@
+import { StyleSheet, Text, View } from 'react-native';
+import React from 'react';
+
+const ShadowLine = () => {
+ return (
+ <>
+
+
+
+ >
+ );
+};
+
+const styles = StyleSheet.create({
+ line1: {
+ position: 'absolute',
+ top: -1,
+ left: 0,
+ right: 0,
+ height: 1,
+ backgroundColor: 'rgba(0,0,0,0.05)',
+ },
+ line2: {
+ position: 'absolute',
+ top: -2,
+ left: 0,
+ right: 0,
+ height: 1,
+ backgroundColor: 'rgba(0,0,0,0.025)',
+ },
+ line3: {
+ position: 'absolute',
+ top: -3,
+ left: 0,
+ right: 0,
+ height: 1,
+ backgroundColor: 'rgba(0,0,0,0.0125)',
+ },
+});
+
+export default ShadowLine;
diff --git a/src/components/Tour/components/CopilotStep.tsx b/src/components/Tour/components/CopilotStep.tsx
index c9e8276a..4c2206e9 100644
--- a/src/components/Tour/components/CopilotStep.tsx
+++ b/src/components/Tour/components/CopilotStep.tsx
@@ -8,6 +8,7 @@ export const CopilotStep = ({
name,
order,
text,
+ subText,
children,
active = true,
width,
@@ -63,6 +64,7 @@ export const CopilotStep = ({
registerStep({
name,
text,
+ subText,
order,
measure,
wrapperRef,
diff --git a/src/components/Tour/components/Tooltip.tsx b/src/components/Tour/components/Tooltip.tsx
index 41d77c42..921e82ef 100644
--- a/src/components/Tour/components/Tooltip.tsx
+++ b/src/components/Tour/components/Tooltip.tsx
@@ -54,6 +54,11 @@ export const Tooltip: React.FC = ({ labels }) => {
{currentStep?.text}
+ {currentStep?.subText ? (
+
+ {currentStep?.subText}
+
+ ) : null}
;
measure: () => Promise;
text: ReactNode;
+ subText?: ReactNode;
isCircularHighlight?: boolean;
noHighlightArea?: boolean;
}
@@ -105,6 +106,7 @@ export interface CopilotStepProps {
name: string;
order: number;
text: ReactNode;
+ subText?: ReactNode;
children: React.ReactElement;
active?: boolean;
width?: number;
diff --git a/src/components/carousel/Carousel.tsx b/src/components/carousel/Carousel.tsx
new file mode 100644
index 00000000..db14d2f5
--- /dev/null
+++ b/src/components/carousel/Carousel.tsx
@@ -0,0 +1,93 @@
+import React from 'react';
+import { FlatList, View } from 'react-native';
+import CarouselItem from './CarouselItem';
+import Animated, { useAnimatedScrollHandler, useSharedValue } from 'react-native-reanimated';
+import { GenericStyles, SCREEN_WIDTH } from '@rn-ui-lib/styles';
+import Pagination from './Pagination';
+import { ICarousel } from './interfaces';
+import { GenericType } from '@common/GenericTypes';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+
+const Carousel: React.FC = ({
+ data,
+ gapBetweenItems,
+ sideItemScale,
+ horizontalPadding,
+ renderItem,
+ isLoading,
+}) => {
+ const scrollX = useSharedValue(0);
+ const canMomentum = React.useRef(false);
+ const [activePageNumber, setActivePageNumber] = React.useState(1);
+ const flatListRef = React.useRef>(null);
+
+ const onScrollHandler = useAnimatedScrollHandler({
+ onScroll: (event) => {
+ scrollX.value = event.contentOffset.x;
+ },
+ });
+
+ const scrollTo = (index: number) => {
+ flatListRef.current?.scrollToOffset({
+ offset: index * SCREEN_WIDTH,
+ animated: true,
+ });
+ setActivePageNumber(index + 1);
+ };
+
+ const handleMomentumScrollBegin = () => {
+ canMomentum.current = true;
+ };
+
+ const handleMomentumScrollEnd = () => {
+ if (canMomentum.current) {
+ const index = Math.round(scrollX.value / SCREEN_WIDTH);
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_CAROUSEL_ADDRESS_SWIPE_GESTURE, {
+ page: index,
+ });
+ setActivePageNumber(index + 1);
+ }
+
+ canMomentum.current = false;
+ };
+
+ return (
+
+ (
+
+ )}
+ horizontal
+ scrollEnabled={!isLoading}
+ pagingEnabled
+ showsHorizontalScrollIndicator={false}
+ onScroll={onScrollHandler}
+ removeClippedSubviews={false}
+ onMomentumScrollBegin={handleMomentumScrollBegin}
+ onMomentumScrollEnd={handleMomentumScrollEnd}
+ />
+
+
+
+
+ );
+};
+
+export default Carousel;
diff --git a/src/components/carousel/CarouselItem.tsx b/src/components/carousel/CarouselItem.tsx
new file mode 100644
index 00000000..38ad2714
--- /dev/null
+++ b/src/components/carousel/CarouselItem.tsx
@@ -0,0 +1,62 @@
+import { StyleSheet, View } from 'react-native';
+import React from 'react';
+import { SCREEN_WIDTH } from '@rn-ui-lib/styles';
+import Animated, { Extrapolation, interpolate, useAnimatedStyle } from 'react-native-reanimated';
+import { COLORS } from '@rn-ui-lib/colors';
+import { GAP_BETWEEN_ITEMS, HORIZONTAL_PADDING, SIDE_ITEM_SCALE } from './constants';
+import { ICarouselItem } from './interfaces';
+
+const CarouselItem: React.FC = ({
+ item,
+ scrollX,
+ index,
+ horizontalPadding = HORIZONTAL_PADDING,
+ gapBetweenItems = GAP_BETWEEN_ITEMS,
+ sideItemScale = SIDE_ITEM_SCALE,
+ renderItem,
+}) => {
+ const TRANSLATE_X = horizontalPadding + gapBetweenItems + ((1 - 0.8) / 2) * SCREEN_WIDTH;
+ const animatedStyle = useAnimatedStyle(() => {
+ return {
+ transform: [
+ {
+ translateX: interpolate(
+ scrollX.value,
+ [(index - 1) * SCREEN_WIDTH, index * SCREEN_WIDTH, (index + 1) * SCREEN_WIDTH],
+ [-TRANSLATE_X, 0, TRANSLATE_X],
+ Extrapolation.CLAMP
+ ),
+ },
+ {
+ scale: interpolate(
+ scrollX.value,
+ [(index - 1) * SCREEN_WIDTH, index * SCREEN_WIDTH, (index + 1) * SCREEN_WIDTH],
+ [sideItemScale, 1, sideItemScale],
+ Extrapolation.CLAMP
+ ),
+ },
+ ],
+ };
+ });
+
+ return (
+
+ {renderItem({ item, index })}
+
+ );
+};
+const styles = StyleSheet.create({
+ container: {
+ paddingVertical: 16,
+ paddingHorizontal: HORIZONTAL_PADDING,
+ width: SCREEN_WIDTH,
+ },
+ listItem: {
+ height: '100%',
+ borderRadius: 20,
+ elevation: 6,
+ backgroundColor: COLORS.BACKGROUND.PRIMARY,
+ },
+});
+
+export default CarouselItem;
diff --git a/src/components/carousel/Pagination.tsx b/src/components/carousel/Pagination.tsx
new file mode 100644
index 00000000..9971da44
--- /dev/null
+++ b/src/components/carousel/Pagination.tsx
@@ -0,0 +1,37 @@
+import { StyleSheet, View } from 'react-native';
+import { IPagination } from './interfaces';
+import PaginationItem from './PaginationItem';
+import { CopilotStep } from '@components/Tour/components/CopilotStep';
+
+const Pagination: React.FC = ({ data, activePageNumber, scrollTo, isLoading }) => {
+ if (!data?.length) return null;
+ return (
+
+
+ {data?.map((_, index) => (
+
+ ))}
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ pagination: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ borderRadius: 20,
+ padding: 8,
+ backgroundColor: 'rgba(50, 70, 91, 0.40)',
+ },
+});
+
+export default Pagination;
diff --git a/src/components/carousel/PaginationItem.tsx b/src/components/carousel/PaginationItem.tsx
new file mode 100644
index 00000000..8f7fdefe
--- /dev/null
+++ b/src/components/carousel/PaginationItem.tsx
@@ -0,0 +1,83 @@
+import React from 'react';
+import { Pressable, StyleSheet, View } from 'react-native';
+import { IPaginationItem } from './interfaces';
+import { COLORS } from '@rn-ui-lib/colors';
+import Text from '@rn-ui-lib/components/Text';
+import TickSmallSolidIcon from '@assets/icons/TickSmallSolidIcon';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+
+const PaginationItem: React.FC = ({
+ index,
+ activePageNumber,
+ isLastItem,
+ scrollTo,
+ isVisited,
+ isLoading,
+}) => {
+ const pageNumber = index + 1;
+ const isActivePage = activePageNumber === pageNumber;
+
+ return (
+ {
+ if (isLoading) return;
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_CAROUSEL_ADDRESS_PAGINATION_CLICKED, {
+ page: index,
+ });
+ scrollTo(index);
+ }}
+ style={isLoading && styles.opacity70}
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
+ >
+
+
+ {isLastItem ? 'Others' : pageNumber}
+
+ {isVisited ? (
+
+
+
+ ) : null}
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ numberCTA: {
+ justifyContent: 'center',
+ alignItems: 'center',
+ marginRight: 12,
+ },
+ paginationContainer: {
+ position: 'absolute',
+ top: 14,
+ left: 10,
+ },
+ activeNumberText: {
+ backgroundColor: COLORS.BACKGROUND.PRIMARY,
+ color: COLORS.TEXT.DARK,
+ borderColor: COLORS.BORDER.PRIMARY,
+ },
+ numberText: {
+ fontSize: 13,
+ color: COLORS.TEXT.WHITE,
+ paddingHorizontal: 5,
+ height: 20,
+ textAlign: 'center',
+ textAlignVertical: 'center',
+ lineHeight: 16,
+ borderRadius: 10,
+ borderWidth: 1,
+ borderColor: 'transparent',
+ },
+ mr0: {
+ marginRight: 0,
+ },
+ opacity70: {
+ opacity: 0.7,
+ },
+});
+
+export default PaginationItem;
diff --git a/src/components/carousel/constants.ts b/src/components/carousel/constants.ts
new file mode 100644
index 00000000..241ce99a
--- /dev/null
+++ b/src/components/carousel/constants.ts
@@ -0,0 +1,3 @@
+export const HORIZONTAL_PADDING = 30;
+export const SIDE_ITEM_SCALE = 0.8;
+export const GAP_BETWEEN_ITEMS = 12;
diff --git a/src/components/carousel/interfaces.ts b/src/components/carousel/interfaces.ts
new file mode 100644
index 00000000..f4385187
--- /dev/null
+++ b/src/components/carousel/interfaces.ts
@@ -0,0 +1,40 @@
+import { GenericType } from '@common/GenericTypes';
+import { SharedValue } from 'react-native-reanimated';
+
+type RenderItem = (data: { item: GenericType; index: number }) => React.ReactNode;
+
+export interface ICarouselItem {
+ item: GenericType;
+ scrollX: SharedValue;
+ index: number;
+ renderItem: RenderItem;
+ horizontalPadding?: number;
+ sideItemScale?: number;
+ gapBetweenItems?: number;
+}
+
+export interface ICarousel {
+ data: GenericType[];
+ horizontalPadding?: number;
+ gapBetweenItems?: number;
+ sideItemScale?: number;
+ renderItem: RenderItem;
+ isLoading: boolean;
+}
+
+export interface IPagination {
+ data: GenericType[];
+ scrollX: SharedValue;
+ activePageNumber: number;
+ scrollTo: (index: number) => void;
+ isLoading: boolean;
+}
+
+export interface IPaginationItem {
+ index: number;
+ activePageNumber: number;
+ isLastItem: boolean;
+ scrollTo: (index: number) => void;
+ isVisited: boolean;
+ isLoading: boolean;
+}
diff --git a/src/components/form/AnswerRender.tsx b/src/components/form/AnswerRender.tsx
index 8a7f9f0e..d042df7d 100644
--- a/src/components/form/AnswerRender.tsx
+++ b/src/components/form/AnswerRender.tsx
@@ -7,13 +7,12 @@ import { GenericStyles, SCREEN_WIDTH } from '../../../RN-UI-LIB/src/styles';
import { GenericObject, GenericType } from '../../common/GenericTypes';
import StarRating from '../../../RN-UI-LIB/src/components/star_rating/StarRating';
import { getPhoneNumberString, memoize } from '../utlis/commonFunctions';
-import {
- getImageHeightWrtAspectRatio,
-} from '../../services/casePayload.transformer';
+import { getImageHeightWrtAspectRatio } from '../../services/casePayload.transformer';
import { formatAmount } from '../../../RN-UI-LIB/src/utlis/amount';
-import GeolocationAddressAnswer from './components/GeolocationAddressAnswer';
import dayjs from 'dayjs';
import { BUSINESS_DATE_FORMAT, CUSTOM_ISO_DATE_FORMAT } from '@rn-ui-lib/utils/dates';
+import AddressAnswer from './components/AddressAnswer';
+import { CaseAllocationType } from '@screens/allCases/interface';
const RATING_COMPONENT = 'Rating';
const MAX_RATING = 5;
@@ -51,7 +50,9 @@ const DarkBoldText = ({ text }: IDarkBoldText) => {
const AnswerRender: React.FC = (props) => {
const { answer, visited, section, caseId, journey, metaData, questionId } = props;
const data = useAppSelector((state) => state.case.caseForm?.[caseId]?.[journey]);
- const caseType = useAppSelector((state) => state.allCases.caseDetails[caseId]?.caseType);
+ const caseType = useAppSelector(
+ (state) => state.allCases.caseDetails[caseId]?.caseType || CaseAllocationType.COLLECTION_CASE
+ );
const templateData = useAppSelector((state) => state.case.templateData[caseType]);
const mobileNumbers =
useAppSelector((state) => state?.telephoneNumbers?.telephoneNumbers?.[caseId]) || [];
@@ -122,7 +123,7 @@ const AnswerRender: React.FC = (props) => {
}
return ;
case AnswerType.image:
- if(!imageDoc?.fileUri) return null;
+ if (!imageDoc?.fileUri) return null;
return (
= (props) => {
>
);
case AnswerType.address:
- return (
-
- );
+ return ;
case AnswerType.phoneNumber:
return ;
case AnswerType.date:
diff --git a/src/components/form/Submit.tsx b/src/components/form/Submit.tsx
index 10df3b0f..30c73171 100644
--- a/src/components/form/Submit.tsx
+++ b/src/components/form/Submit.tsx
@@ -35,7 +35,7 @@ const Submit: React.FC = (props) => {
const data = useAppSelector((state) => state.case.caseForm?.[caseId]?.[journey]);
const caseType = useAppSelector(
(state) =>
- state.allCases.caseDetails[caseId]?.caseType || CaseAllocationType.ADDRESS_VERIFICATION_CASE
+ state.allCases.caseDetails[caseId]?.caseType || CaseAllocationType.COLLECTION_CASE
);
const templateData = useAppSelector((state) => state.case.templateData[caseType]);
const sections = templateData?.sections;
diff --git a/src/components/form/components/AddressAnswer.tsx b/src/components/form/components/AddressAnswer.tsx
new file mode 100644
index 00000000..4e9e46d5
--- /dev/null
+++ b/src/components/form/components/AddressAnswer.tsx
@@ -0,0 +1,31 @@
+import React, { useMemo } from 'react';
+import { useAppSelector } from '../../../hooks';
+import Text from '../../../../RN-UI-LIB/src/components/Text';
+import { RootState } from '../../../store/store';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import { View } from 'react-native';
+
+interface IAddressAnswer {
+ caseId: string;
+ addressId: string;
+}
+
+const AddressAnswer: React.FC = ({ caseId, addressId }) => {
+ const feedbackAddresses = useAppSelector(
+ (state: RootState) => state.topAddresses?.[caseId]?.feedbackAddresses
+ );
+ const address = useMemo(() => {
+ return feedbackAddresses?.find((address) => address.referenceId === addressId);
+ }, [feedbackAddresses, addressId]);
+
+ return (
+
+
+ {[address?.pinCode, address?.city].filter(Boolean).join(', ') || '-'}
+
+ {address?.addressText?.trim()}
+
+ );
+};
+
+export default AddressAnswer;
diff --git a/src/components/form/components/AddressSelection/AddressSelectionBody.tsx b/src/components/form/components/AddressSelection/AddressSelectionBody.tsx
new file mode 100644
index 00000000..a2be127e
--- /dev/null
+++ b/src/components/form/components/AddressSelection/AddressSelectionBody.tsx
@@ -0,0 +1,123 @@
+import { getAddressString } from '@components/utlis/commonFunctions';
+import Text from '@rn-ui-lib/components/Text';
+import RadioGroup from '@rn-ui-lib/components/radio_button/RadioGroup';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import React from 'react';
+import RNRadioButton from '@rn-ui-lib/components/radio_button/RadioButton';
+import { TouchableOpacity, View } from 'react-native';
+import { useAppDispatch, useAppSelector } from '@hooks';
+import { RootState } from '@store';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+import { AnswerType } from '@components/form/interface';
+import LineLoader from '@rn-ui-lib/components/suspense_loader/LineLoader';
+import LoadingIcon from '@rn-ui-lib/icons/LoadingIcon';
+import { COLORS } from '@rn-ui-lib/colors';
+import NoLocationsIcon from '@rn-ui-lib/icons/NoLocationIcon';
+import { getFeedbackAddresses } from '@screens/addresses/actions';
+import { IAddressSelectionBody } from './interface';
+
+const AddressSelectionBody = (props: IAddressSelectionBody) => {
+ const { caseId, questionId, error, widgetId, sectionId, control, questionType, value, onChange } =
+ props;
+
+ const feedbackAddresses = useAppSelector(
+ (state: RootState) => state.topAddresses?.[caseId]?.feedbackAddresses
+ );
+ const isFeedbackAddressesLoading = useAppSelector(
+ (state: RootState) => state.topAddresses?.[caseId]?.isFeedbackAddressesLoading
+ );
+
+ const dispatch = useAppDispatch();
+
+ const handleChange = (change: string) => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_FORM_ELEMENT_CHANGED, {
+ caseId,
+ questionType,
+ value: change,
+ questionId,
+ error,
+ sectionId,
+ widgetId,
+ });
+ onChange({
+ answer: change,
+ type: AnswerType.address,
+ });
+ };
+
+ const getAddresses = () => {
+ dispatch(getFeedbackAddresses(caseId));
+ };
+
+ if (isFeedbackAddressesLoading) {
+ return (
+
+ {[...Array(7).keys()].map((_, index) => (
+
+ ))}
+
+ );
+ }
+
+ if (!feedbackAddresses?.length) {
+ return (
+
+
+
+
+ No addresses found
+
+
+
+
+
+
+ Retry
+
+
+ );
+ }
+
+ return (
+
+ {feedbackAddresses?.map((address) => {
+ return (
+
+
+ {[address.pinCode, address.city].filter(Boolean).join(', ') || '-'}
+
+ {address?.addressText?.trim()}
+
+ }
+ containerStyle={GenericStyles.containerStyle}
+ />
+ );
+ })}
+
+ );
+};
+
+export default AddressSelectionBody;
diff --git a/src/components/form/components/AddressSelection/AddressSelectionV2.tsx b/src/components/form/components/AddressSelection/AddressSelectionV2.tsx
new file mode 100644
index 00000000..1f34a13b
--- /dev/null
+++ b/src/components/form/components/AddressSelection/AddressSelectionV2.tsx
@@ -0,0 +1,47 @@
+import { View } from 'react-native';
+import React from 'react';
+import { useAppSelector } from '../../../../hooks';
+import { CaseAllocationType } from '../../../../screens/allCases/interface';
+import { isQuestionMandatory, validateInput } from '../../services/validation.service';
+import { Control, Controller } from 'react-hook-form';
+import ErrorMessage from '../ErrorMessage';
+import { GenericStyles } from '../../../../../RN-UI-LIB/src/styles';
+import Text from '@rn-ui-lib/components/Text';
+import AddressSelectionBody from './AddressSelectionBody';
+import { IAddressSelectionV2 } from './interface';
+
+const AddressSelectionV2: React.FC = (props) => {
+ const { questionId, error, widgetId, sectionId, control } = props;
+ const template = useAppSelector(
+ (state) => state.case.templateData[CaseAllocationType.COLLECTION_CASE]
+ );
+ const question = template?.questions?.[questionId];
+ const controllerName = `widgetContext.${widgetId}.sectionContext.${sectionId}.questionContext.${questionId}`;
+
+ return (
+
+
+ {question?.text || ' '}
+ {isQuestionMandatory(question) && *}
+
+
+ validateInput(data, question.metadata.validators) }}
+ render={({ field: { onChange, value } }) => (
+
+ )}
+ name={controllerName}
+ />
+
+ );
+};
+
+export default AddressSelectionV2;
diff --git a/src/components/form/components/AddressSelection/interface.ts b/src/components/form/components/AddressSelection/interface.ts
new file mode 100644
index 00000000..a15169b6
--- /dev/null
+++ b/src/components/form/components/AddressSelection/interface.ts
@@ -0,0 +1,18 @@
+import { GenericType } from '@common/GenericTypes';
+import { Control } from 'react-hook-form';
+
+export interface IAddressSelectionV2 {
+ questionType: string;
+ questionId: string;
+ widgetId: string;
+ journeyId: string;
+ caseId: string;
+ sectionId: string;
+ control: Control;
+ error: GenericType;
+}
+
+export interface IAddressSelectionBody extends IAddressSelectionV2 {
+ value: GenericType;
+ onChange: (...event: GenericType[]) => void;
+}
diff --git a/src/components/form/components/PhoneNumberSelection.tsx b/src/components/form/components/PhoneNumberSelection.tsx
index 92acde25..ceecb3fd 100644
--- a/src/components/form/components/PhoneNumberSelection.tsx
+++ b/src/components/form/components/PhoneNumberSelection.tsx
@@ -32,7 +32,7 @@ const PhoneNumberSelection: React.FC = (props) => {
const { caseId, questionId, error, widgetId, sectionId, control, questionType } = props;
const currentCase = useAppSelector((state) => state.allCases?.caseDetails?.[caseId]) || {};
const { mobileNumbers, loading } = useMobileNumbers(caseId);
- const caseType = currentCase?.caseType || CaseAllocationType.ADDRESS_VERIFICATION_CASE;
+ const caseType = currentCase?.caseType || CaseAllocationType.COLLECTION_CASE;
const template = useAppSelector((state) => state.case.templateData[caseType]);
const question = template.questions[questionId];
const handleChange = (change: string | null, onChange: (...event: any[]) => void) => {
diff --git a/src/components/form/services/formComponents.ts b/src/components/form/services/formComponents.ts
index 553c17f1..360216c0 100644
--- a/src/components/form/services/formComponents.ts
+++ b/src/components/form/services/formComponents.ts
@@ -6,10 +6,10 @@ import Rating from '../components/Rating';
import TextArea from '../components/TextArea';
import TextInput from '../components/TextInput';
import Dropdown from '../components/Dropdown';
-import AddressSelection from '../components/AddressSelection';
import PhoneNumberSelection from '../components/PhoneNumberSelection';
import DateInput from '../components/DateInput';
import TimeInput from '../components/TimeInput';
+import AddressSelectionV2 from '../components/AddressSelection/AddressSelectionV2';
export const FormComponentList = {
TextInput,
@@ -20,7 +20,7 @@ export const FormComponentList = {
Rating,
Dropdown,
CheckboxGroup,
- AddressSelection,
+ AddressSelection: AddressSelectionV2,
PhoneNumberSelection,
DateInput,
TimeInput,
diff --git a/src/components/utlis/addressGeolocationUtils.ts b/src/components/utlis/addressGeolocationUtils.ts
index a71adbcf..877c11d3 100644
--- a/src/components/utlis/addressGeolocationUtils.ts
+++ b/src/components/utlis/addressGeolocationUtils.ts
@@ -8,9 +8,7 @@ export const getCollectionFeedbackOnAddressPreDefinedJourney = (
isGeolocation?: boolean
) => {
try {
- const templateStr = isGeolocation
- ? JSON.stringify(templateJson.geolocationTemplate)
- : JSON.stringify(templateJson.addressTemplate);
+ const templateStr = JSON.stringify(templateJson.addressTemplate);
const updatedStr = templateStr.replace(key, value);
return JSON.parse(updatedStr);
} catch (err) {
diff --git a/src/components/utlis/apiHelper.ts b/src/components/utlis/apiHelper.ts
index 5b9f8764..4f6b0bce 100644
--- a/src/components/utlis/apiHelper.ts
+++ b/src/components/utlis/apiHelper.ts
@@ -113,6 +113,8 @@ export enum ApiKeys {
GET_REPAYMENTS = 'GET_REPAYMENTS',
GET_FEEDBACK_HISTORY = 'GET_FEEDBACK_HISTORY',
GET_PRIORTIY_FEEDBACK = 'GET_PRIORTIY_FEEDBACK',
+ GET_TOP_ADDRESSES = 'GET_TOP_ADDRESSES',
+ GET_FEEDBACK_ADDRESSES = 'GET_FEEDBACK_ADDRESSES',
GET_TRAINING_MATERIAL_LIST = 'GET_TRAINING_MATERIAL_LIST',
GET_TRAINING_MATERIAL_DETAILS = 'GET_TRAINING_MATERIAL_DETAILS',
SELF_CALL_ACK= '/api/v1/self-call'
@@ -204,7 +206,6 @@ API_URLS[ApiKeys.CALL_CUSTOMER] = '/call-recording/v2/call-request';
API_URLS[ApiKeys.SYNC_ACTIVE_CALL_DETAILS] = '/call-recording/call-status';
API_URLS[ApiKeys.GET_CALL_HISTORY] = '/call-recording/v3/call-history';
API_URLS[ApiKeys.SYNC_CALL_FEEDBACK_NUDGE_DETAILS] =
-
'/call-recording/acknowledge-feedback-nudge/{callId}';
API_URLS[ApiKeys.FETCH_CUSTOMER_DOCUMENTS] = '/documents/{loanAccountNumber}';
API_URLS[ApiKeys.FETCH_AGENT_DOCUMENTS] = '/documents/agent';
@@ -223,6 +224,8 @@ API_URLS[ApiKeys.GET_PRIORTIY_FEEDBACK] = '/feedback/case-status';
API_URLS[ApiKeys.GET_TRAINING_MATERIAL_LIST] = '/training-page/content-list';
API_URLS[ApiKeys.GET_TRAINING_MATERIAL_DETAILS] = '/training-page/{docRefId}';
API_URLS[ApiKeys.SELF_CALL_ACK] = '/sync-data/self-call-metadata';
+API_URLS[ApiKeys.GET_TOP_ADDRESSES] = '/collection-cases/unified-locations';
+API_URLS[ApiKeys.GET_FEEDBACK_ADDRESSES] = '/collection-cases/unified-locations/lite';
export const API_STATUS_CODE = {
OK: 200,
diff --git a/src/components/utlis/commonFunctions.ts b/src/components/utlis/commonFunctions.ts
index c41a5860..0636dacd 100644
--- a/src/components/utlis/commonFunctions.ts
+++ b/src/components/utlis/commonFunctions.ts
@@ -410,6 +410,11 @@ export const getGoogleMapUrl = (latitude: string | number, longitude: string | n
return `https://www.google.com/maps/search/${latitude},+${longitude}`;
};
+export const getGoogleMapUrlForAddressText = (address: string) => {
+ if (!address) return;
+ return `https://www.google.com/maps/search/?api=1&query=${address}`;
+};
+
export const isValidAmountEntered = (value: number) => {
return typeof value === 'number' && !isNaN(value);
};
diff --git a/src/reducer/topAddressesSlice.ts b/src/reducer/topAddressesSlice.ts
new file mode 100644
index 00000000..07ba5ca6
--- /dev/null
+++ b/src/reducer/topAddressesSlice.ts
@@ -0,0 +1,91 @@
+import { createSlice } from '@reduxjs/toolkit';
+import {
+ IFeedbackAddress,
+ IFeedbackAddressMap,
+ ILocationData,
+} from '@screens/addresses/interfaces';
+
+type ITopAddressesSlice = Record<
+ string,
+ {
+ addresses: ILocationData[];
+ totalLocationEntities: number;
+ otherAddresses: ILocationData[];
+ isTopAddressesLoading: boolean;
+ isOtherAddressesLoading: boolean;
+ feedbackAddresses: IFeedbackAddress[];
+ feedbackAddressesMap: Record;
+ isFeedbackAddressesLoading: boolean;
+ }
+>;
+
+const initialState: ITopAddressesSlice = {};
+
+const TopAddressesSlice = createSlice({
+ name: 'topAddresses',
+ initialState,
+ reducers: {
+ setTopAddresses: (state, action) => {
+ const { caseId, addresses = [], totalLocationEntities } = action.payload;
+ state[caseId] = {
+ ...(state?.[caseId] || {}),
+ addresses,
+ totalLocationEntities,
+ };
+ },
+ setTopAddressesLoading: (state, action) => {
+ const { caseId, isLoading } = action.payload;
+ state[caseId] = {
+ ...(state?.[caseId] || {}),
+ isTopAddressesLoading: isLoading,
+ };
+ },
+ setOtherAddresses: (state, action) => {
+ const { caseId, addresses = [] } = action.payload;
+ state[caseId] = {
+ ...(state?.[caseId] || {}),
+ otherAddresses: addresses,
+ };
+ },
+ setOtherAddressesLoading: (state, action) => {
+ const { caseId, isLoading } = action.payload;
+ state[caseId] = {
+ ...(state?.[caseId] || {}),
+ isOtherAddressesLoading: isLoading,
+ };
+ },
+ setFeedbackAddresses: (state, action) => {
+ const { caseId, addresses = [] } = action.payload;
+ const feedbackAddressesMap = addresses?.reduce(
+ (acc: Record, address: IFeedbackAddress) => {
+ acc[address.referenceId] = { locationType: address?.locationType };
+ return acc;
+ },
+ {}
+ );
+ state[caseId] = {
+ ...(state?.[caseId] || {}),
+ feedbackAddresses: addresses,
+ feedbackAddressesMap,
+ };
+ },
+ setFeedbackAddressesLoading: (state, action) => {
+ const { caseId, isLoading } = action.payload;
+ state[caseId] = {
+ ...(state?.[caseId] || {}),
+ isFeedbackAddressesLoading: isLoading,
+ };
+ },
+ },
+});
+
+export const {
+ setTopAddresses,
+ setTopAddressesLoading,
+ setOtherAddresses,
+ setOtherAddressesLoading,
+ setFeedbackAddresses,
+ setFeedbackAddressesLoading,
+} = TopAddressesSlice.actions;
+
+export default TopAddressesSlice.reducer;
diff --git a/src/screens/addresses/actions.ts b/src/screens/addresses/actions.ts
new file mode 100644
index 00000000..85e1b641
--- /dev/null
+++ b/src/screens/addresses/actions.ts
@@ -0,0 +1,87 @@
+import axiosInstance, { ApiKeys, getApiUrl } from '@components/utlis/apiHelper';
+import {
+ setFeedbackAddresses,
+ setFeedbackAddressesLoading,
+ setOtherAddresses,
+ setOtherAddressesLoading,
+ setTopAddresses,
+ setTopAddressesLoading,
+} from '@reducers/topAddressesSlice';
+import { AppDispatch } from '@store';
+import { PAGE_END } from './constants';
+
+export const getTopAddresses =
+ (caseId: string, start: number, end: number) => (dispatch: AppDispatch) => {
+ dispatch(setTopAddressesLoading({ caseId, isLoading: true }));
+ const url = getApiUrl(ApiKeys.GET_TOP_ADDRESSES);
+ axiosInstance
+ .get(url, {
+ params: { caseReferenceId: caseId, startingRank: start, endingRank: end },
+ })
+ .then((res) => {
+ if (res?.data) {
+ const { unifiedLocations = [], totalLocationEntities = 0 } = res?.data || {};
+ dispatch(
+ setTopAddresses({
+ caseId,
+ addresses: unifiedLocations,
+ totalLocationEntities: totalLocationEntities - 5,
+ })
+ );
+ }
+ })
+ .catch((error) => {})
+ .finally(() => {
+ dispatch(setTopAddressesLoading({ caseId, isLoading: false }));
+ });
+ };
+
+export const getOtherAddresses = (caseId: string) => (dispatch: AppDispatch) => {
+ dispatch(setOtherAddressesLoading({ caseId, isLoading: true }));
+ const url = getApiUrl(ApiKeys.GET_TOP_ADDRESSES);
+ axiosInstance
+ .get(url, {
+ params: {
+ caseReferenceId: caseId,
+ startingRank: PAGE_END + 1,
+ },
+ })
+ .then((res) => {
+ if (res?.data) {
+ const { unifiedLocations = [] } = res?.data || {};
+ dispatch(
+ setOtherAddresses({
+ caseId,
+ addresses: unifiedLocations,
+ })
+ );
+ }
+ })
+ .finally(() => {
+ dispatch(setOtherAddressesLoading({ caseId, isLoading: false }));
+ });
+};
+
+export const getFeedbackAddresses = (caseId: string) => (dispatch: AppDispatch) => {
+ dispatch(setFeedbackAddressesLoading({ caseId, isLoading: true }));
+ const url = getApiUrl(ApiKeys.GET_FEEDBACK_ADDRESSES);
+ axiosInstance
+ .get(url, {
+ params: {
+ caseReferenceId: caseId,
+ },
+ })
+ .then((res) => {
+ if (res?.data) {
+ dispatch(
+ setFeedbackAddresses({
+ caseId,
+ addresses: res.data || [],
+ })
+ );
+ }
+ })
+ .finally(() => {
+ dispatch(setFeedbackAddressesLoading({ caseId, isLoading: false }));
+ });
+};
diff --git a/src/screens/addresses/common/AddressItemAddressString.tsx b/src/screens/addresses/common/AddressItemAddressString.tsx
new file mode 100644
index 00000000..13f49287
--- /dev/null
+++ b/src/screens/addresses/common/AddressItemAddressString.tsx
@@ -0,0 +1,93 @@
+import { Linking, Pressable, StyleSheet, View } from 'react-native';
+import React from 'react';
+import Text from '@rn-ui-lib/components/Text';
+import { ITopAddressItemAddressString, LocationType } from '../interfaces';
+import LollipopIcon from '@assets/icons/LollipopIcon';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import { copyAddressToClipboard } from '@screens/addressGeolocation/utils/copyAddressText';
+import MapDirectionIcon from '@assets/icons/MapDirectionIcon';
+import { getGoogleMapUrl, getGoogleMapUrlForAddressText } from '@components/utlis/commonFunctions';
+import CopyOutlineIcon from '@assets/icons/CopyOutlineIcon';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+
+const AddressItemAddressString = (props: ITopAddressItemAddressString) => {
+ const { locationDetails, showMapIcon = true, caseId, actionContainerStyle } = props;
+ const { addressText, latitude, longitude, locationSubType } = locationDetails || {};
+
+ const handleCopyAddress = () => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_COPY_ADDRESS_CLICKED, {
+ caseId,
+ addressText,
+ });
+ copyAddressToClipboard(addressText);
+ };
+
+ const handleOpenLocation = () => {
+ const isGeoLocation =
+ locationSubType === LocationType.GEO_LOCATION ||
+ locationSubType === LocationType.SKIP_TRACE_ADDRESS;
+
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_OPEN_MAP_BUTTON_CLICKED, {
+ caseId,
+ ...(isGeoLocation ? { latitude, longitude } : { addressText }),
+ locationSubType,
+ });
+
+ const mapUrl = isGeoLocation
+ ? getGoogleMapUrl(latitude, longitude)
+ : getGoogleMapUrlForAddressText(addressText);
+
+ if (mapUrl) {
+ return Linking.openURL(mapUrl);
+ }
+ };
+
+ return (
+
+
+
+
+
+ {addressText}
+
+
+
+
+ {showMapIcon ? (
+
+
+
+ ) : null}
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'row',
+ marginHorizontal: 16,
+ paddingTop: 8,
+ },
+ p4: {
+ padding: 4,
+ },
+ fs1: {
+ flexShrink: 1,
+ },
+});
+
+export default AddressItemAddressString;
diff --git a/src/screens/addresses/common/AddressItemFeedback.tsx b/src/screens/addresses/common/AddressItemFeedback.tsx
new file mode 100644
index 00000000..3c915d88
--- /dev/null
+++ b/src/screens/addresses/common/AddressItemFeedback.tsx
@@ -0,0 +1,64 @@
+import { View } from 'react-native';
+import React from 'react';
+import { ITopAddressItemFeedback } from '../interfaces';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import Text from '@rn-ui-lib/components/Text';
+import dayjs from 'dayjs';
+import { BUSINESS_DATE_FORMAT } from '@rn-ui-lib/utils/dates';
+import { getFeedbackColors } from '../utils';
+
+const AddressItemFeedback = (props: ITopAddressItemFeedback) => {
+ const { latestFeedback } = props;
+ const {
+ latestFeedbackStatus,
+ latestFeedbackTimestamp,
+ feedbackColourCode,
+ feedbackBgColourCode,
+ promiseToPayDate,
+ } = latestFeedback || {};
+
+ const { feedbackColor, feedbackBgColor } = getFeedbackColors(
+ latestFeedbackStatus,
+ feedbackColourCode,
+ feedbackBgColourCode
+ );
+
+ return (
+
+
+ Last feedback{' '}
+ {latestFeedbackTimestamp ? (
+
+ ({dayjs(latestFeedbackTimestamp).format(BUSINESS_DATE_FORMAT)})
+
+ ) : null}
+
+
+ {latestFeedbackStatus
+ ? `${latestFeedbackStatus} ${
+ promiseToPayDate ? `on ${dayjs(promiseToPayDate).format(BUSINESS_DATE_FORMAT)}` : ''
+ }`
+ : 'Unvisited address'}
+
+
+ );
+};
+
+export default AddressItemFeedback;
diff --git a/src/screens/addresses/common/AddressItemHeader.tsx b/src/screens/addresses/common/AddressItemHeader.tsx
new file mode 100644
index 00000000..fa744485
--- /dev/null
+++ b/src/screens/addresses/common/AddressItemHeader.tsx
@@ -0,0 +1,92 @@
+import { StyleSheet, View } from 'react-native';
+import React, { useMemo } from 'react';
+import { ITopAddressItemHeader } from '../interfaces';
+import Text from '@rn-ui-lib/components/Text';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import { useAppSelector } from '@hooks';
+import { getDistanceFromLatLonInKm } from '@components/utlis/commonFunctions';
+import relativeDistanceFormatter from '@screens/addressGeolocation/utils/relativeDistanceFormatter';
+import TopAddressItemRankTag from '../topAddresses/TopAddressItemRankTag';
+import { COLORS } from '@rn-ui-lib/colors';
+import { CopilotStep } from '@components/Tour/components/CopilotStep';
+
+const AddressItemHeader = (props: ITopAddressItemHeader) => {
+ const { locationDetails, isOtherAddressView, containerStyle, isCoachMarkVisible } = props;
+ const { pinCode, city, latitude, longitude, rank, visited } = locationDetails || {};
+ const deviceGeolocationCoordinate = useAppSelector(
+ (state) => state.foregroundService?.deviceGeolocationCoordinate
+ );
+
+ const relativeDistanceBwLatLong = useMemo(() => {
+ const distance = getDistanceFromLatLonInKm(deviceGeolocationCoordinate, {
+ latitude,
+ longitude,
+ });
+ return `${relativeDistanceFormatter(distance)} km`;
+ }, [deviceGeolocationCoordinate]);
+
+ const addressString = useMemo(() => {
+ return [pinCode, city].filter(Boolean).join(', ');
+ }, [pinCode, city]);
+
+ return (
+
+ {isOtherAddressView ? (
+
+ {rank}
+
+ ) : isCoachMarkVisible ? (
+
+
+
+
+
+ ) : (
+
+ )}
+
+
+ {addressString ? addressString : '-'}
+
+ ({relativeDistanceBwLatLong})
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ marginLeft: -5,
+ flexDirection: 'row',
+ alignItems: 'center',
+ paddingVertical: 8,
+ },
+ rankCircle: {
+ marginLeft: 21,
+ width: 23,
+ height: 23,
+ borderRadius: 13,
+ backgroundColor: COLORS.BACKGROUND.SILVER,
+ borderWidth: 1,
+ borderColor: COLORS.BORDER.PRIMARY,
+ textAlignVertical: 'center',
+ textAlign: 'center',
+ lineHeight: 17,
+ fontSize: 10,
+ },
+ mw70: {
+ maxWidth: '70%',
+ },
+});
+
+export default AddressItemHeader;
diff --git a/src/screens/addresses/constants.ts b/src/screens/addresses/constants.ts
new file mode 100644
index 00000000..954b717a
--- /dev/null
+++ b/src/screens/addresses/constants.ts
@@ -0,0 +1,14 @@
+import { TagVariant } from '@rn-ui-lib/components/Tag';
+
+export enum LocationSourceMap {
+ VKYC = 'VKYC',
+ DATA_SUTRAM = 'Skip Tracing',
+ PRIMARY = 'Allocated address',
+}
+
+export const LocationSourceTagVariantMap: Record = {
+ 'ALLOCATED_ADDRESS': TagVariant.white,
+};
+
+export const PAGE_START = 1;
+export const PAGE_END = 5;
diff --git a/src/screens/addresses/interfaces.ts b/src/screens/addresses/interfaces.ts
new file mode 100644
index 00000000..4bb1ab0f
--- /dev/null
+++ b/src/screens/addresses/interfaces.ts
@@ -0,0 +1,166 @@
+import { IPredefinedAddressScreenTemplate } from '@interfaces/template.types';
+import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack';
+import { StyleProp, ViewStyle } from 'react-native';
+
+export interface ILabel {
+ label: string;
+ val: string;
+}
+
+export interface ILatestFeedback {
+ locationReferenceId: string;
+ latestFeedbackStatus: string;
+ latestFeedbackStatusTag: string;
+ latestFeedbackTimestamp: number;
+ feedbackColourCode: string;
+ feedbackBgColourCode: string;
+ isSuspicious: boolean;
+ feedbackPresent: boolean;
+ promiseToPayDate: string;
+}
+
+export interface ILocationData {
+ referenceId: string;
+ customerReferenceId: string;
+ addressText: string;
+ pinCode: string;
+ city: string;
+ latitude: number;
+ longitude: number;
+ visited: boolean;
+ rank: number;
+ timestamp: number;
+ similarLocationEntities: ISimilarAddressEntity[];
+ labels: ILabel[];
+ relatedLocationIds: string[];
+ latestFeedback: ILatestFeedback;
+ locationSubType: string;
+}
+
+export interface ILocationDetails {
+ locationDetails: ILocationData;
+}
+
+export interface ITopAddressItem extends ILocationDetails {
+ caseId: string;
+ isCoachMarkVisible: boolean;
+}
+
+export interface ITopAddressItemHeader {
+ locationDetails: ILocationData;
+ isCoachMarkVisible?: boolean;
+ isOtherAddressView?: boolean;
+ containerStyle?: StyleProp;
+}
+
+export interface ITopAddressItemFeedback {
+ latestFeedback: ILatestFeedback;
+}
+
+export interface ITopAddressItemTags {
+ clusterLabels: ILabel[];
+}
+
+export interface ITopAddressItemAddressString {
+ locationDetails: ILocationData;
+ showMapIcon?: boolean;
+ caseId: string;
+ actionContainerStyle?: StyleProp;
+}
+
+export interface ITopAddressItemBottomActions extends ILocationDetails {
+ caseId: string;
+}
+
+export interface ITopAddressItemRankTag {
+ rank: number;
+ visited: boolean;
+}
+
+export interface ITopAddressSimilarAddresses extends ILocationDetails {
+ caseId: string;
+}
+interface ISimilarAddressEntity {
+ id: string;
+ addressText: string;
+ pinCode: string;
+ city: string;
+ state: string;
+ source: string;
+ order: number;
+ capturedAt: number;
+}
+
+export interface ITopAddressSimilarAddressCard {
+ similarAddressDetails: ISimilarAddressEntity;
+ caseId: string;
+}
+
+export interface IOtherAddressItem extends ILocationDetails {
+ caseId: string;
+}
+
+export interface IFeedbackAddress {
+ referenceId: string;
+ addressText: string;
+ city: string;
+ pinCode: string;
+ rank: number;
+ source: string;
+ capturedAt: string;
+ locationType: string;
+}
+
+export interface IFeedbackAddressMap {
+ locationType: string;
+}
+
+export enum LocationType {
+ GEO_LOCATION = 'GEO_LOCATION',
+ SKIP_TRACE_ADDRESS = 'SKIP_TRACE_ADDRESS',
+}
+
+export interface IOtherAddressActions extends ILocationDetails {
+ caseId: string;
+}
+
+export interface IOtherAddresses {
+ route: {
+ params: {
+ loanAccountNumber: string;
+ caseId: string;
+ };
+ };
+}
+
+export interface IOtherAddressList {
+ caseId: string;
+}
+
+export interface ITopAddress {
+ route: {
+ params: {
+ loanAccountNumber: string;
+ caseId: string;
+ };
+ };
+}
+
+export interface ITopAddressOtherAddressesItem {
+ caseId: string;
+}
+
+export interface IOpenOldFeedbacks {
+ loanAccountNumber: string;
+ addressText: string;
+ relatedLocationIds: string[];
+ referenceId: string;
+ caseId: string;
+}
+
+export interface INavigateToAddFeedbackScreen {
+ prefilledAddressScreenTemplate: IPredefinedAddressScreenTemplate | undefined;
+ caseId: string;
+ referenceId: string;
+ screen: CaseDetailStackEnum;
+}
diff --git a/src/screens/addresses/otherAddresses/OtherAddressActions.tsx b/src/screens/addresses/otherAddresses/OtherAddressActions.tsx
new file mode 100644
index 00000000..ebeed1e3
--- /dev/null
+++ b/src/screens/addresses/otherAddresses/OtherAddressActions.tsx
@@ -0,0 +1,108 @@
+import { StyleSheet, View } from 'react-native';
+import React from 'react';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import OldFeedbacksIcon from '@assets/icons/OldFeedbacksIcon';
+import { COLORS } from '@rn-ui-lib/colors';
+import AddFeedbackIcon from '@assets/icons/AddFeedbackIcon';
+import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack';
+import { useAppDispatch, useAppSelector } from '@hooks';
+import Button from '@rn-ui-lib/components/Button';
+import { CaseAllocationType } from '@screens/allCases/interface';
+import { handlePostOperativeHourActivities } from '@screens/addressGeolocation/utils/operativeHourUtils';
+import { ToastMessages } from '@screens/allCases/constants';
+import { IOtherAddressActions } from '../interfaces';
+import { navigateToAddFeedbackScreen, openOldFeedbacks } from '../utils';
+
+const OtherAddressActions = (props: IOtherAddressActions) => {
+ const { locationDetails, caseId } = props;
+ const { addressText, relatedLocationIds, referenceId } = locationDetails || {};
+
+ const loanAccountNumber = useAppSelector(
+ (state) => state?.allCases?.caseDetails?.[caseId]?.loanAccountNumber
+ );
+ const addingNewFeedbackDisabled = useAppSelector(
+ (state) => state?.postOperationalHourRestrictionsSlice?.postOperationalHourRestrictions
+ );
+ const prefilledAddressScreenTemplate = useAppSelector(
+ (state) =>
+ state.case.templateData[CaseAllocationType.COLLECTION_CASE]?.prefilledAddressScreenTemplate
+ );
+ const dispatch = useAppDispatch();
+
+ const handleOpenOldFeedbacks = () => {
+ openOldFeedbacks({
+ loanAccountNumber,
+ addressText: addressText,
+ relatedLocationIds: relatedLocationIds,
+ referenceId: referenceId,
+ caseId,
+ });
+ };
+
+ const handleAddFeedback = () => {
+ dispatch(
+ navigateToAddFeedbackScreen({
+ prefilledAddressScreenTemplate,
+ caseId,
+ referenceId,
+ screen: CaseDetailStackEnum.OTHER_ADDRESSES,
+ })
+ );
+ };
+
+ const handleDisableAddFeedback = () => {
+ handlePostOperativeHourActivities(
+ ToastMessages.DISABLE_ADD_FEEDBACK_AFTER_POST_OPERATIVE_HOURS
+ );
+ };
+
+ return (
+
+ }
+ opacityChangeOnPress
+ underlayColor="transparent"
+ textStyle={[GenericStyles.fontSize13, GenericStyles.ml4]}
+ />
+
+ }
+ opacityChangeOnPress={!addingNewFeedbackDisabled}
+ underlayColor="transparent"
+ style={addingNewFeedbackDisabled && styles.disabledButton}
+ textStyle={[GenericStyles.fontSize13, GenericStyles.ml4]}
+ />
+
+ );
+};
+
+const styles = StyleSheet.create({
+ divider: {
+ height: 28,
+ width: 1,
+ backgroundColor: COLORS.BORDER.PRIMARY,
+ },
+ disabledButton: {
+ color: COLORS.TEXT.BLUE,
+ opacity: 0.5,
+ },
+});
+
+export default OtherAddressActions;
diff --git a/src/screens/addresses/otherAddresses/OtherAddressItem.tsx b/src/screens/addresses/otherAddresses/OtherAddressItem.tsx
new file mode 100644
index 00000000..1fc8dce1
--- /dev/null
+++ b/src/screens/addresses/otherAddresses/OtherAddressItem.tsx
@@ -0,0 +1,38 @@
+import { StyleSheet, View } from 'react-native';
+import React from 'react';
+import { COLORS } from '@rn-ui-lib/colors';
+import AddressItemHeader from '@screens/addresses/common/AddressItemHeader';
+import AddressItemFeedback from '@screens/addresses/common/AddressItemFeedback';
+import AddressItemAddressString from '@screens/addresses/common/AddressItemAddressString';
+import OtherAddressActions from './OtherAddressActions';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import TopAddressSimilarAddresses from '../similarAddresses/TopAddressSimilarAddresses';
+import { IOtherAddressItem } from '../interfaces';
+
+const OtherAddressItem = (props: IOtherAddressItem) => {
+ const { locationDetails, caseId } = props;
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ borderRadius: 20,
+ elevation: 2,
+ backgroundColor: COLORS.BACKGROUND.PRIMARY,
+ marginBottom: 16,
+ },
+});
+
+export default OtherAddressItem;
diff --git a/src/screens/addresses/otherAddresses/OtherAddressList.tsx b/src/screens/addresses/otherAddresses/OtherAddressList.tsx
new file mode 100644
index 00000000..a0230811
--- /dev/null
+++ b/src/screens/addresses/otherAddresses/OtherAddressList.tsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import { ActivityIndicator, FlatList, RefreshControl, View } from 'react-native';
+import OtherAddressItem from './OtherAddressItem';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import Text from '@rn-ui-lib/components/Text';
+import { useAppDispatch, useAppSelector } from '@hooks';
+import { COLORS } from '@rn-ui-lib/colors';
+import { getOtherAddresses } from '../actions';
+import { IOtherAddressList } from '../interfaces';
+
+const OtherAddressList = (props: IOtherAddressList) => {
+ const { caseId } = props;
+ const otherAddresses = useAppSelector(
+ (state) => state.topAddresses?.[caseId]?.otherAddresses || []
+ );
+ const isOtherAddressesLoading = useAppSelector(
+ (state) => state.topAddresses?.[caseId]?.isOtherAddressesLoading
+ );
+
+ const dispatch = useAppDispatch();
+
+ const onRefresh = React.useCallback(() => {
+ dispatch(getOtherAddresses(caseId));
+ }, []);
+
+ if (isOtherAddressesLoading) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+ {otherAddresses?.length > 0 ? (
+ }
+ contentContainerStyle={[GenericStyles.p16, GenericStyles.mb24]}
+ renderItem={({ item }) => }
+ />
+ ) : (
+
+
+ No addresses found
+
+
+ )}
+
+ );
+};
+
+export default OtherAddressList;
diff --git a/src/screens/addresses/otherAddresses/OtherAddresses.tsx b/src/screens/addresses/otherAddresses/OtherAddresses.tsx
new file mode 100644
index 00000000..9a6cb56b
--- /dev/null
+++ b/src/screens/addresses/otherAddresses/OtherAddresses.tsx
@@ -0,0 +1,45 @@
+import { View } from 'react-native';
+import React, { useEffect } from 'react';
+import Layout from '@screens/layout/Layout';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import NavigationHeader from '@rn-ui-lib/components/NavigationHeader';
+import { goBack } from '@components/utlis/navigationUtlis';
+import { useAppDispatch, useAppSelector } from '@hooks';
+import OtherAddressList from './OtherAddressList';
+import { getOtherAddresses } from '../actions';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+import { IOtherAddresses } from '../interfaces';
+
+const OtherAddresses = ({ route: routeParams }: IOtherAddresses) => {
+ const {
+ params: { caseId },
+ } = routeParams;
+ const otherAddresses = useAppSelector(
+ (state) => state.topAddresses?.[caseId]?.otherAddresses || []
+ );
+
+ const dispatch = useAppDispatch();
+
+ useEffect(() => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_OTHER_ADDRESSES_SCREEN_LOADED, {
+ caseId,
+ });
+ dispatch(getOtherAddresses(caseId));
+ }, []);
+
+ const totalAddresses = otherAddresses?.length;
+ return (
+
+
+
+
+
+
+ );
+};
+
+export default OtherAddresses;
diff --git a/src/screens/addresses/similarAddresses/TopAddressSimilarAddressCard.tsx b/src/screens/addresses/similarAddresses/TopAddressSimilarAddressCard.tsx
new file mode 100644
index 00000000..6cb4888b
--- /dev/null
+++ b/src/screens/addresses/similarAddresses/TopAddressSimilarAddressCard.tsx
@@ -0,0 +1,83 @@
+import React from 'react';
+import { Pressable, StyleSheet, View } from 'react-native';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import { COLORS } from '@rn-ui-lib/colors';
+import Text from '@rn-ui-lib/components/Text';
+import { sanitizeString } from '@components/utlis/commonFunctions';
+import { copyAddressToClipboard } from '@screens/addressGeolocation/utils/copyAddressText';
+import CopyOutlineIcon from '@assets/icons/CopyOutlineIcon';
+import { BUSINESS_DATE_FORMAT, dateFormat } from '@rn-ui-lib/utils/dates';
+import { PRIMARY_SOURCE_MAPPING } from '@screens/addressGeolocation/constant';
+import { ITopAddressSimilarAddressCard } from '../interfaces';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+
+const TopAddressSimilarAddressCard = (props: ITopAddressSimilarAddressCard) => {
+ const { similarAddressDetails, caseId } = props;
+
+ const handleCopyAddress = () => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_COPY_ADDRESS_CLICKED, {
+ caseId,
+ address: similarAddressDetails?.addressText,
+ });
+ copyAddressToClipboard(similarAddressDetails?.addressText);
+ };
+
+ return (
+
+
+ {sanitizeString(
+ [similarAddressDetails?.pinCode, similarAddressDetails?.city].filter(Boolean).join(', ')
+ )}
+
+ {similarAddressDetails?.addressText}
+
+
+
+ {similarAddressDetails?.capturedAt || similarAddressDetails?.source ? (
+
+ {similarAddressDetails?.capturedAt ? (
+
+ {sanitizeString(
+ `${dateFormat(new Date(similarAddressDetails?.capturedAt), BUSINESS_DATE_FORMAT)}`
+ )}
+
+ ) : null}
+ {similarAddressDetails?.capturedAt && similarAddressDetails?.source ? (
+
+ ) : null}
+ {similarAddressDetails.source ? (
+
+ {PRIMARY_SOURCE_MAPPING[
+ similarAddressDetails.source as keyof typeof PRIMARY_SOURCE_MAPPING
+ ] ?? similarAddressDetails?.source}
+
+ ) : null}
+
+ ) : null}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ backgroundColor: COLORS.BACKGROUND.SILVER,
+ marginHorizontal: 16,
+ marginVertical: 8,
+ borderRadius: 8,
+ padding: 16,
+ },
+ bullet: {
+ width: 4,
+ height: 4,
+ borderRadius: 4,
+ backgroundColor: COLORS.BACKGROUND.LIGHT,
+ marginHorizontal: 6,
+ },
+});
+
+export default TopAddressSimilarAddressCard;
diff --git a/src/screens/addresses/similarAddresses/TopAddressSimilarAddresses.tsx b/src/screens/addresses/similarAddresses/TopAddressSimilarAddresses.tsx
new file mode 100644
index 00000000..c7f200b7
--- /dev/null
+++ b/src/screens/addresses/similarAddresses/TopAddressSimilarAddresses.tsx
@@ -0,0 +1,94 @@
+import { ScrollView, StyleSheet, TouchableOpacity, View, useWindowDimensions } from 'react-native';
+import React, { useState } from 'react';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import { pluralise } from '@components/utlis/commonFunctions';
+import { COLORS } from '@rn-ui-lib/colors';
+import RightChevronIcon from '@assets/icons/RightChevronIcon';
+import BottomSheetWrapper from '@common/BottomSheetWrapper';
+import Text from '@rn-ui-lib/components/Text';
+import TopAddressSimilarAddressCard from './TopAddressSimilarAddressCard';
+import { ToastContainer, toastConfigs } from '@rn-ui-lib/components/toast';
+import { ITopAddressSimilarAddresses } from '../interfaces';
+import AddressItemHeader from '../common/AddressItemHeader';
+import AddressItemAddressString from '../common/AddressItemAddressString';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+
+const TopAddressSimilarAddresses = (props: ITopAddressSimilarAddresses) => {
+ const { locationDetails, caseId } = props;
+ const { similarLocationEntities = [] } = locationDetails || {};
+ const showSimilarAddresses = similarLocationEntities?.length;
+ const [showBottomSheet, setShowBottomSheet] = useState(false);
+
+ const handleOpenSimilarLocations = () => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VIEW_SIMILAR_ADDRESSES_BUTTON_CLICKED, {
+ caseId,
+ addressReferenceId: locationDetails?.referenceId,
+ });
+ setShowBottomSheet(true);
+ };
+
+ const handleClose = () => {
+ setShowBottomSheet(false);
+ };
+ const toastPosition = useWindowDimensions().height;
+
+ if (!showSimilarAddresses) return null;
+ return (
+
+
+
+ View similar {pluralise(similarLocationEntities?.length, 'address', 'addresses')} (
+ {similarLocationEntities?.length})
+
+
+
+
+
+ (
+
+ )}
+ allowBackdropClose={true}
+ setVisible={handleClose}
+ >
+
+
+ {similarLocationEntities?.map((entity, index) => (
+
+ ))}
+
+
+
+
+
+
+ );
+};
+
+export default TopAddressSimilarAddresses;
+
+const styles = StyleSheet.create({
+ container: {
+ marginLeft: 34,
+ },
+ bottomSheetHeader: {
+ marginTop: -4,
+ paddingBottom: 16,
+ },
+});
diff --git a/src/screens/addresses/topAddresses/TopAddressItem.tsx b/src/screens/addresses/topAddresses/TopAddressItem.tsx
new file mode 100644
index 00000000..d8b03bf5
--- /dev/null
+++ b/src/screens/addresses/topAddresses/TopAddressItem.tsx
@@ -0,0 +1,46 @@
+import { ScrollView, View } from 'react-native';
+import React from 'react';
+import { ITopAddressItem } from '../interfaces';
+import AddressItemHeader from '../common/AddressItemHeader';
+import AddressItemFeedback from '../common/AddressItemFeedback';
+import TopAddressItemTags from './TopAddressItemTags';
+import AddressItemAddressString from '../common/AddressItemAddressString';
+import TopAddressItemBottomActions from './TopAddressItemBottomActions';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import TopAddressSimilarAddresses from '../similarAddresses/TopAddressSimilarAddresses';
+import { useCopilot } from '@components/Tour/contexts/CopilotProvider';
+import { useAppSelector } from '@hooks';
+import { RootState } from '@store';
+import { CoachMarkFeatures, showCoachMark } from '@actions/filterActions';
+
+const TopAddressItem = (props: ITopAddressItem) => {
+ const { locationDetails, caseId, isCoachMarkVisible } = props;
+ const copilot = useCopilot();
+ const userId = useAppSelector((state: RootState) => state.user?.user?.referenceId);
+ const serverTimestamp = useAppSelector(
+ (state: RootState) => state.foregroundService.serverTimestamp
+ );
+ const startTour = () => {
+ if (userId && copilot.totalStepsNumber > 0) {
+ showCoachMark(CoachMarkFeatures.TOP_5_ADDRESSES, userId, serverTimestamp, copilot.start);
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default TopAddressItem;
diff --git a/src/screens/addresses/topAddresses/TopAddressItemBottomActions.tsx b/src/screens/addresses/topAddresses/TopAddressItemBottomActions.tsx
new file mode 100644
index 00000000..8ce4bf58
--- /dev/null
+++ b/src/screens/addresses/topAddresses/TopAddressItemBottomActions.tsx
@@ -0,0 +1,90 @@
+import { StyleSheet, View } from 'react-native';
+import React from 'react';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import Button from '@rn-ui-lib/components/Button';
+import { ITopAddressItemBottomActions } from '../interfaces';
+import ShadowLine from '@common/ShadowLine';
+import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack';
+import { useAppDispatch, useAppSelector } from '@hooks';
+import { handlePostOperativeHourActivities } from '@screens/addressGeolocation/utils/operativeHourUtils';
+import { ToastMessages } from '@screens/allCases/constants';
+import { CaseAllocationType } from '@screens/allCases/interface';
+import { COLORS } from '@rn-ui-lib/colors';
+import { navigateToAddFeedbackScreen, openOldFeedbacks } from '../utils';
+
+const TopAddressItemBottomActions = (props: ITopAddressItemBottomActions) => {
+ const { locationDetails, caseId } = props;
+ const { addressText, relatedLocationIds, referenceId } = locationDetails || {};
+ const addingNewFeedbackDisabled = useAppSelector(
+ (state) => state?.postOperationalHourRestrictionsSlice?.postOperationalHourRestrictions
+ );
+ const prefilledAddressScreenTemplate = useAppSelector(
+ (state) =>
+ state.case.templateData[CaseAllocationType.COLLECTION_CASE]?.prefilledAddressScreenTemplate
+ );
+ const loanAccountNumber = useAppSelector(
+ (state) => state?.allCases?.caseDetails?.[caseId]?.loanAccountNumber
+ );
+ const dispatch = useAppDispatch();
+
+ const handleOpenOldFeedbacks = () => {
+ openOldFeedbacks({
+ loanAccountNumber,
+ addressText: addressText,
+ relatedLocationIds: relatedLocationIds,
+ referenceId: referenceId,
+ caseId,
+ });
+ };
+
+ const handleDisableAddFeedback = () => {
+ handlePostOperativeHourActivities(
+ ToastMessages.DISABLE_ADD_FEEDBACK_AFTER_POST_OPERATIVE_HOURS
+ );
+ };
+
+ const handleAddFeedback = () => {
+ dispatch(
+ navigateToAddFeedbackScreen({
+ prefilledAddressScreenTemplate,
+ caseId,
+ referenceId,
+ screen: CaseDetailStackEnum.TOP_ADDRESSES,
+ })
+ );
+ };
+
+ return (
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ disabledButton: {
+ color: COLORS.TEXT.BLUE,
+ opacity: 0.5,
+ backgroundColor: COLORS.BACKGROUND.PRIMARY,
+ borderColor: COLORS.BORDER.PRIMARY,
+ },
+});
+
+export default TopAddressItemBottomActions;
diff --git a/src/screens/addresses/topAddresses/TopAddressItemRankTag.tsx b/src/screens/addresses/topAddresses/TopAddressItemRankTag.tsx
new file mode 100644
index 00000000..94348d9b
--- /dev/null
+++ b/src/screens/addresses/topAddresses/TopAddressItemRankTag.tsx
@@ -0,0 +1,42 @@
+import { StyleSheet, View } from 'react-native';
+import React from 'react';
+import { ITopAddressItemRankTag } from '../interfaces';
+import RankTagIcon from '@assets/icons/RankTagIcon';
+import Text from '@rn-ui-lib/components/Text';
+import VisitedTagIcon from '@assets/icons/VisitedTagIcon';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import { COLORS } from '@rn-ui-lib/colors';
+
+const TopAddressItemRankTag = (props: ITopAddressItemRankTag) => {
+ const { rank, visited } = props;
+ return (
+
+ {visited ? (
+
+ ) : (
+
+
+
+ {rank}
+
+
+ )}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ rankTagContainer: {
+ position: 'relative',
+ alignSelf: 'flex-start',
+ },
+ rankText: {
+ position: 'absolute',
+ top: -2,
+ right: 6,
+ fontWeight: 'bold',
+ color: COLORS.TEXT.BLUE_DARK,
+ },
+});
+
+export default TopAddressItemRankTag;
diff --git a/src/screens/addresses/topAddresses/TopAddressItemTags.tsx b/src/screens/addresses/topAddresses/TopAddressItemTags.tsx
new file mode 100644
index 00000000..b3a64fab
--- /dev/null
+++ b/src/screens/addresses/topAddresses/TopAddressItemTags.tsx
@@ -0,0 +1,36 @@
+import { StyleSheet, View } from 'react-native';
+import React from 'react';
+import { ILabel, ITopAddressItemTags } from '../interfaces';
+import { COLORS } from '@rn-ui-lib/colors';
+import Tag, { TagVariant } from '@rn-ui-lib/components/Tag';
+import { LocationSourceTagVariantMap } from '../constants';
+
+const TopAddressItemTags = (props: ITopAddressItemTags) => {
+ const { clusterLabels = [] } = props;
+ if (clusterLabels?.length === 0) {
+ return null;
+ }
+ return (
+
+ {clusterLabels?.map((clusterLabel: ILabel) => (
+
+ ))}
+
+ );
+};
+const styles = StyleSheet.create({
+ container: {
+ backgroundColor: COLORS.BACKGROUND.GREY_LIGHT_3,
+ paddingHorizontal: 16,
+ paddingVertical: 12,
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ gap: 8,
+ },
+});
+
+export default TopAddressItemTags;
diff --git a/src/screens/addresses/topAddresses/TopAddressOtherAddressesItem.tsx b/src/screens/addresses/topAddresses/TopAddressOtherAddressesItem.tsx
new file mode 100644
index 00000000..6e9e120b
--- /dev/null
+++ b/src/screens/addresses/topAddresses/TopAddressOtherAddressesItem.tsx
@@ -0,0 +1,71 @@
+import { StyleSheet, View } from 'react-native';
+import React from 'react';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import Text from '@rn-ui-lib/components/Text';
+import LocationOnMap3DIcon from '@assets/icons/LocationOnMap3DIcon';
+import Button from '@rn-ui-lib/components/Button';
+import { COLORS } from '@rn-ui-lib/colors';
+import Chevron from '@rn-ui-lib/icons/Chevron';
+import { navigateToScreen } from '@components/utlis/navigationUtlis';
+import { useAppSelector } from '@hooks';
+import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { ITopAddressOtherAddressesItem } from '../interfaces';
+
+const TopAddressOtherAddressesItem = (props: ITopAddressOtherAddressesItem) => {
+ const { caseId } = props;
+ const totalLocationEntities = useAppSelector(
+ (state) => state.topAddresses?.[caseId]?.totalLocationEntities || 0
+ );
+
+ const navigateToOtherAddresses = () => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VIEW_OTHER_ADDRESSES_CLICKED, {
+ caseId,
+ totalLocationEntities,
+ });
+ navigateToScreen(CaseDetailStackEnum.OTHER_ADDRESSES, { caseId });
+ };
+ return (
+
+
+
+ Other Addresses
+
+
+
+
+
+ {totalLocationEntities > 0 ? totalLocationEntities : 'No'} more addresses
+
+
+ }
+ disabled={totalLocationEntities <= 0}
+ style={[GenericStyles.alighSelfCenter, GenericStyles.mt16]}
+ buttonStyle={[styles.w100, styles.pv4, GenericStyles.centerAlignedRow]}
+ textStyle={GenericStyles.fontSize13}
+ pressableWidthChange={false}
+ onPress={navigateToOtherAddresses}
+ />
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ w100: {
+ width: 100,
+ },
+ pv4: {
+ paddingVertical: 8,
+ },
+});
+
+export default TopAddressOtherAddressesItem;
diff --git a/src/screens/addresses/topAddresses/TopAddresses.tsx b/src/screens/addresses/topAddresses/TopAddresses.tsx
new file mode 100644
index 00000000..bc486807
--- /dev/null
+++ b/src/screens/addresses/topAddresses/TopAddresses.tsx
@@ -0,0 +1,125 @@
+import { Pressable, StyleSheet, View } from 'react-native';
+import React, { useEffect } from 'react';
+import Layout from '@screens/layout/Layout';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import NavigationHeader from '@rn-ui-lib/components/NavigationHeader';
+import { goBack, navigateToScreen } from '@components/utlis/navigationUtlis';
+import Carousel from '@components/carousel/Carousel';
+import TopAddressItem from './TopAddressItem';
+import TopAddressOtherAddressesItem from './TopAddressOtherAddressesItem';
+import PlusIcon from '@rn-ui-lib/icons/PlusIcon';
+import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack';
+import { COLORS } from '@rn-ui-lib/colors';
+import Text from '@rn-ui-lib/components/Text';
+import { getTopAddresses } from '../actions';
+import { useAppDispatch, useAppSelector } from '@hooks';
+import LineLoader from '@rn-ui-lib/components/suspense_loader/LineLoader';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+import { ITopAddress } from '../interfaces';
+import { PAGE_END, PAGE_START } from '../constants';
+import { CopilotProvider } from '@components/Tour/contexts/CopilotProvider';
+import { CopilotStep } from '@components/Tour/components/CopilotStep';
+import Lottie from '@rn-ui-lib/components/lottie/Lottie';
+
+const TopAddresses = ({ route: routeParams }: ITopAddress) => {
+ const {
+ params: { caseId },
+ } = routeParams;
+ const isTopAddressesLoading = useAppSelector(
+ (state) => state.topAddresses?.[caseId]?.isTopAddressesLoading
+ );
+ const addresses = useAppSelector((state) => state.topAddresses?.[caseId]?.addresses || []);
+
+ const dispatch = useAppDispatch();
+
+ // Added empty object to show "Other Addresses" at the end
+ const updatedAddresses = [...addresses, {}];
+
+ const handleNewAddressCta = () => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ADD_NEW_ADDRESS_CLICKED, {
+ caseId,
+ });
+ navigateToScreen(CaseDetailStackEnum.NEW_ADDRESS);
+ };
+
+ useEffect(() => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_TOP_ADDRESSES_SCREEN_LOADED, {
+ caseId,
+ });
+ dispatch(getTopAddresses(caseId, PAGE_START, PAGE_END));
+ }, []);
+
+ return (
+
+
+
+
+ [styles.btnContainer, { opacity: pressed ? 0.7 : 1 }]}
+ >
+
+ New
+
+
+ }
+ />
+ {
+ if (isTopAddressesLoading) {
+ return (
+
+
+
+ );
+ }
+ const isLastItem = updatedAddresses?.length - 1 === index;
+ return !isLastItem ? (
+
+ ) : (
+
+ );
+ }}
+ />
+
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ btnContainer: {
+ flexDirection: 'row',
+ gap: 8,
+ alignItems: 'center',
+ color: COLORS.TEXT.WHITE,
+ borderWidth: 1,
+ height: 28,
+ borderColor: COLORS.BACKGROUND.PRIMARY,
+ borderRadius: 4,
+ marginVertical: 14,
+ marginHorizontal: 16,
+ paddingHorizontal: 14,
+ },
+ loader: { borderRadius: 20, backgroundColor: '#929090' },
+});
+export default TopAddresses;
diff --git a/src/screens/addresses/utils.ts b/src/screens/addresses/utils.ts
new file mode 100644
index 00000000..f7c8751f
--- /dev/null
+++ b/src/screens/addresses/utils.ts
@@ -0,0 +1,76 @@
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+import { getTemplateRoute, navigateToScreen } from '@components/utlis/navigationUtlis';
+import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import { INavigateToAddFeedbackScreen, IOpenOldFeedbacks } from './interfaces';
+import { CaseAllocationType, TaskTitleUIMapping } from '@screens/allCases/interface';
+import { getCollectionFeedbackOnAddressPreDefinedJourney } from '@components/utlis/addressGeolocationUtils';
+import { updatePreDefinedCaseFormJourney } from '@reducers/caseReducer';
+import { AppDispatch } from '@store';
+import { COLORS } from '@rn-ui-lib/colors';
+
+export const openOldFeedbacks = ({
+ loanAccountNumber,
+ addressText,
+ relatedLocationIds,
+ referenceId,
+ caseId,
+}: IOpenOldFeedbacks) => {
+ const commonParams = {
+ loanAccountNumber,
+ addressText: addressText,
+ addressReferenceIds: relatedLocationIds?.join(','),
+ };
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ADDRESS_OLD_FEEDBACK_CLICKED, {
+ caseId,
+ addressId: referenceId,
+ });
+ navigateToScreen(CaseDetailStackEnum.PAST_FEEDBACK_DETAIL, commonParams);
+};
+
+export const navigateToAddFeedbackScreen =
+ ({ prefilledAddressScreenTemplate, caseId, referenceId, screen }: INavigateToAddFeedbackScreen) =>
+ (dispatch: AppDispatch) => {
+ if (prefilledAddressScreenTemplate != null) {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_ADDRESS_ADD_FEEDBACK_CLICKED, {
+ caseId,
+ addressId: referenceId,
+ });
+ const addressKey = '{{addressReferenceId}}';
+ const { visitedWidgets, widgetContext } = getCollectionFeedbackOnAddressPreDefinedJourney(
+ prefilledAddressScreenTemplate,
+ addressKey,
+ referenceId
+ );
+
+ dispatch(
+ updatePreDefinedCaseFormJourney({
+ caseId,
+ journeyId: TaskTitleUIMapping.COLLECTION_FEEDBACK,
+ visitedWidgets,
+ widgetContext,
+ })
+ );
+ if (visitedWidgets?.length) {
+ const lastVisitedWidget = visitedWidgets[visitedWidgets.length - 1];
+ navigateToScreen(getTemplateRoute(lastVisitedWidget, CaseAllocationType.COLLECTION_CASE), {
+ caseId,
+ journey: TaskTitleUIMapping.COLLECTION_FEEDBACK,
+ handleCloseRouting: () => navigateToScreen(screen, { caseId }),
+ });
+ }
+ }
+ };
+
+export const getFeedbackColors = (
+ latestFeedbackStatus: string,
+ feedbackColourCode?: string,
+ feedbackBgColourCode?: string
+) => {
+ return {
+ feedbackColor: latestFeedbackStatus ? feedbackColourCode ?? COLORS.TEXT.BLACK : COLORS.TEXT.RED,
+ feedbackBgColor: latestFeedbackStatus
+ ? feedbackBgColourCode ?? COLORS.BACKGROUND.SILVER
+ : COLORS.BACKGROUND.LIGHT_RED_1,
+ };
+};
diff --git a/src/screens/caseDetails/AllocatedAddressDetails.tsx b/src/screens/caseDetails/AllocatedAddressDetails.tsx
new file mode 100644
index 00000000..aaf38b7f
--- /dev/null
+++ b/src/screens/caseDetails/AllocatedAddressDetails.tsx
@@ -0,0 +1,102 @@
+import MapDirectionFilledIcon from '@assets/icons/MapDirectionFilledIcon';
+import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants';
+import {
+ getDistanceFromLatLonInKm,
+ getGoogleMapUrlForAddressText,
+} from '@components/utlis/commonFunctions';
+import { useAppSelector } from '@hooks';
+import { IGeolocationCoordinate } from '@interfaces/addressGeolocation.types';
+import { COLORS } from '@rn-ui-lib/colors';
+import Button from '@rn-ui-lib/components/Button';
+import Text from '@rn-ui-lib/components/Text';
+import { toast } from '@rn-ui-lib/components/toast';
+import { GenericStyles } from '@rn-ui-lib/styles';
+import relativeDistanceFormatter from '@screens/addressGeolocation/utils/relativeDistanceFormatter';
+import { addClickstreamEvent } from '@services/clickstreamEventService';
+import React, { useMemo } from 'react';
+import { Linking, StyleSheet, View } from 'react-native';
+
+interface IAllocatedAddressDetails {
+ isCasePaused: boolean;
+ addressLocation: IGeolocationCoordinate;
+ caseId: string;
+ addressString?: string;
+}
+
+const AllocatedAddressDetails = (props: IAllocatedAddressDetails) => {
+ const { isCasePaused, addressLocation, addressString, caseId } = props;
+ const deviceGeolocationCoordinate = useAppSelector(
+ (state) => state.foregroundService?.deviceGeolocationCoordinate
+ );
+
+ const relativeDistanceBwLatLong = useMemo(() => {
+ const distance = getDistanceFromLatLonInKm(deviceGeolocationCoordinate, {
+ latitude: addressLocation?.latitude,
+ longitude: addressLocation?.longitude,
+ });
+ return `${relativeDistanceFormatter(distance)} km`;
+ }, [deviceGeolocationCoordinate]);
+
+ const openLocation = () => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_DIRECTIONS_BUTTON_CLICKED, {
+ caseId,
+ });
+ if (!addressString) {
+ toast({ type: 'error', text1: 'Address not available' });
+ return;
+ }
+ const mapUrl = getGoogleMapUrlForAddressText(addressString);
+ if (!mapUrl) return;
+ return Linking.openURL(mapUrl);
+ };
+ return (
+
+
+ Allocated Address
+
+ {relativeDistanceBwLatLong}
+
+
+ }
+ underlayColor="transparent"
+ pressableWidthChange={false}
+ opacityChangeOnPress={true}
+ disabled={isCasePaused}
+ />
+
+ );
+};
+
+export const styles = StyleSheet.create({
+ bullet: {
+ width: 5,
+ height: 5,
+ borderRadius: 4,
+ backgroundColor: COLORS.TEXT.GREY_5,
+ marginHorizontal: 6,
+ },
+ details: {
+ fontSize: 13,
+ color: COLORS.TEXT.GREY_5,
+ },
+ pv0: {
+ paddingVertical: 0,
+ },
+});
+
+export default AllocatedAddressDetails;
diff --git a/src/screens/caseDetails/CaseDetailStack.tsx b/src/screens/caseDetails/CaseDetailStack.tsx
index 6a330b3d..a1871169 100644
--- a/src/screens/caseDetails/CaseDetailStack.tsx
+++ b/src/screens/caseDetails/CaseDetailStack.tsx
@@ -28,6 +28,8 @@ import AdditionalGeolocations from '@screens/addressGeolocation/AdditionalGeoloc
import FeeWaiver from '@screens/emiSchedule/FeeWaiver';
import FeeWaiverHistory from '@screens/emiSchedule/FeeWaiverHistory';
import CallCustomer from './CallCustomer';
+import TopAddresses from '@screens/addresses/topAddresses/TopAddresses';
+import OtherAddresses from '@screens/addresses/otherAddresses/OtherAddresses';
import Escalations from '@screens/escalations/Escalations';
const Stack = createNativeStackNavigator();
@@ -54,6 +56,8 @@ export enum CaseDetailStackEnum {
FEE_WAIVER = 'FeeWaiver',
FEE_WAIVER_HISTORY = 'FeeWaiverHistory',
CALL_CUSTOMER = 'CallCustomer',
+ TOP_ADDRESSES = 'TopAddresses',
+ OTHER_ADDRESSES = 'OtherAddresses',
ESCALATIONS = 'Escalations',
}
@@ -118,6 +122,8 @@ const CaseDetailStack = () => {
component={Widget}
/>
))}
+
+
);
};
diff --git a/src/screens/caseDetails/CollectionCaseDetail.tsx b/src/screens/caseDetails/CollectionCaseDetail.tsx
index 99b696df..44c741f4 100644
--- a/src/screens/caseDetails/CollectionCaseDetail.tsx
+++ b/src/screens/caseDetails/CollectionCaseDetail.tsx
@@ -27,6 +27,8 @@ import { CaseStatuses } from '@screens/allCases/interface';
import { BUSINESS_DATE_FORMAT, dateFormat, ISO_DATE_FORMAT } from '@rn-ui-lib/utils/dates';
import dayjs from 'dayjs';
import CaseDetailPausedNudge from './CaseDetailPausedNudge';
+import { captureLatestDeviceLocation } from '@components/form/services/geoLocation.service';
+import { getFeedbackAddresses } from '@screens/addresses/actions';
import { getForeclosureAmount } from '@actions/feedbackActions';
interface ICaseDetails {
@@ -44,7 +46,8 @@ const CollectionCaseDetails: React.FC = (props) => {
params: { caseId, notificationId },
},
} = props;
- const caseDetail = useAppSelector((state: RootState) => state.allCases.caseDetails?.[caseId]) || {};
+ const caseDetail =
+ useAppSelector((state: RootState) => state.allCases.caseDetails?.[caseId]) || {};
const isCallActive = useAppSelector(
(state: RootState) => state?.activeCall?.activeCallDetails?.callActive
);
@@ -77,10 +80,11 @@ const CollectionCaseDetails: React.FC = (props) => {
const casePausedTillDate = dayjs(pausedTillDate, ISO_DATE_FORMAT).format(BUSINESS_DATE_FORMAT);
useFocusEffect(
React.useCallback(() => {
+ if (caseId) {
+ dispatch(captureLatestDeviceLocation(caseId));
+ dispatch(getFeedbackAddresses(caseId));
+ }
if (loanAccountNumber) {
- dispatch(getAddressesAndGeolocations(loanAccountNumber, caseId, caseBusinessVertical));
- dispatch(getUngroupedAddress(loanAccountNumber, caseId, caseBusinessVertical));
- dispatch(getSkipTracingAddress(loanAccountNumber, caseId, caseBusinessVertical));
dispatch(getFeedbackHistory(loanAccountNumber));
}
}, [loanAccountNumber])
diff --git a/src/screens/caseDetails/EmiDetailsSection.tsx b/src/screens/caseDetails/EmiDetailsSection.tsx
index 09d81510..cb705af6 100644
--- a/src/screens/caseDetails/EmiDetailsSection.tsx
+++ b/src/screens/caseDetails/EmiDetailsSection.tsx
@@ -163,7 +163,7 @@ export const styles = StyleSheet.create({
},
emiCardCtas: {
color: COLORS.TEXT.BLUE,
- fontSize: 12,
+ fontSize: 13,
lineHeight: 15,
marginRight: 10,
},
diff --git a/src/screens/caseDetails/ViewAddressSection.tsx b/src/screens/caseDetails/ViewAddressSection.tsx
index 4a437c07..bfc76c16 100644
--- a/src/screens/caseDetails/ViewAddressSection.tsx
+++ b/src/screens/caseDetails/ViewAddressSection.tsx
@@ -13,6 +13,8 @@ import { StyleSheet, View } from 'react-native';
import { CaseDetailStackEnum } from './CaseDetailStack';
import { AddressGeolocationTabEnum, AddressTabType } from '@screens/addressGeolocation/constant';
import { CaseStatuses } from '@screens/allCases/interface';
+import LollipopIcon from '@assets/icons/LollipopIcon';
+import AllocatedAddressDetails from './AllocatedAddressDetails';
interface IViewAddressSection {
caseId: string;
@@ -20,7 +22,13 @@ interface IViewAddressSection {
const ViewAddressSection = ({ caseId }: IViewAddressSection) => {
const caseDetail = useAppSelector((state: RootState) => state.allCases.caseDetails[caseId]) || {};
- const { addressString, loanAccountNumber, customerReferenceId, addressStringType } = caseDetail;
+ const {
+ addressString,
+ loanAccountNumber,
+ customerReferenceId,
+ addressStringType,
+ addressLocation,
+ } = caseDetail;
const getTabName = () => {
if (addressStringType === AddressTabType.GEO_LOCATION) {
@@ -31,7 +39,7 @@ const ViewAddressSection = ({ caseId }: IViewAddressSection) => {
const isCasePaused = caseDetail?.caseStatus === CaseStatuses.ON_HOLD;
const viewAllAddressHandler = () => {
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VIEW_ADDRESSES_CLICKED, {
- lan: getLoanAccountNumber(caseDetail),
+ lan: loanAccountNumber,
});
const commonParams = {
loanAccountNumber,
@@ -42,6 +50,17 @@ const ViewAddressSection = ({ caseId }: IViewAddressSection) => {
navigateToScreen(CaseDetailStackEnum.ADDRESS_GEO, commonParams);
};
+ const viewTopAddressHandler = () => {
+ addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.FA_VIEW_TOP_ADDRESSES_CLICKED, {
+ lan: loanAccountNumber,
+ caseId
+ });
+ navigateToScreen(CaseDetailStackEnum.TOP_ADDRESSES, {
+ caseId,
+ loanAccountNumber,
+ });
+ };
+
return (
{
GenericStyles.pr16,
]}
>
- {addressString}
-
- }
- underlayColor="transparent"
- pressableWidthChange={false}
- opacityChangeOnPress={true}
- disabled={isCasePaused}
+
+
+
+
+
+
+
+ {addressString}
+
+
+ }
+ underlayColor="transparent"
+ pressableWidthChange={false}
+ opacityChangeOnPress={true}
+ disabled={isCasePaused}
+ />
+
+
);
};
@@ -86,6 +120,12 @@ export const styles = StyleSheet.create({
mb5: {
marginBottom: 5,
},
+ container: {
+ flexDirection: 'row',
+ },
+ fs1: {
+ flexShrink: 1,
+ },
});
export default ViewAddressSection;
diff --git a/src/screens/caseDetails/interface.ts b/src/screens/caseDetails/interface.ts
index 73106994..ab0749f9 100644
--- a/src/screens/caseDetails/interface.ts
+++ b/src/screens/caseDetails/interface.ts
@@ -292,7 +292,7 @@ export interface CaseDetail {
dpdBucket: string;
dpdCycle: string;
addresses?: Address[];
- addressLocation?: IGeolocationCoordinate;
+ addressLocation: IGeolocationCoordinate;
currentAllocationReferenceId: string;
customerReferenceId: string;
caseViewCreatedAt?: number;
diff --git a/src/screens/layout/Layout.tsx b/src/screens/layout/Layout.tsx
index 578e06cb..cd8d7935 100644
--- a/src/screens/layout/Layout.tsx
+++ b/src/screens/layout/Layout.tsx
@@ -1,4 +1,3 @@
-import { StyleSheet, Text, View } from 'react-native';
import React, { PropsWithChildren } from 'react';
import Offline from './Offline';
import CallInfo from './CallInfo';
@@ -26,5 +25,3 @@ const Layout: React.FC = (props) => {
};
export default Layout;
-
-const styles = StyleSheet.create({});
diff --git a/src/screens/login/index.tsx b/src/screens/login/index.tsx
index 5db8d3f4..fd92a65b 100644
--- a/src/screens/login/index.tsx
+++ b/src/screens/login/index.tsx
@@ -23,7 +23,7 @@ import Layout from '../layout/Layout';
import { GOOGLE_SSO_CLIENT_ID, IS_SSO_ENABLED } from '../../constants/config';
import { COLORS } from '../../../RN-UI-LIB/src/styles/colors';
import { GoogleSignin, User as GoogleSigninUser } from '@react-native-google-signin/google-signin';
-import { GenericType} from '../../common/GenericTypes';
+import { GenericType } from '../../common/GenericTypes';
import { logError } from '../../components/utlis/errorUtils';
import GoogleIcon from '../../assets/icons/GoogleIcon';
import { toast } from '../../../RN-UI-LIB/src/components/toast';
@@ -52,13 +52,15 @@ function Login() {
formState: { isValid },
} = useForm();
const dispatch = useAppDispatch();
- const { phoneNumber, OTPError, isLoading, otpToken, deviceId } = useSelector((state: RootState) => ({
- phoneNumber: state.loginInfo.phoneNumber,
- otpToken: state.loginInfo.otpToken,
- OTPError: state.loginInfo.OTPError,
- isLoading: state.loginInfo.isLoading,
- deviceId: state.user?.deviceId,
- }));
+ const { phoneNumber, OTPError, isLoading, otpToken, deviceId } = useSelector(
+ (state: RootState) => ({
+ phoneNumber: state.loginInfo.phoneNumber,
+ otpToken: state.loginInfo.otpToken,
+ OTPError: state.loginInfo.OTPError,
+ isLoading: state.loginInfo.isLoading,
+ deviceId: state.user?.deviceId,
+ })
+ );
useEffect(() => {
isValid &&
@@ -68,8 +70,8 @@ function Login() {
}, [isValid]);
useEffect(() => {
- if(deviceId){
- setGlobalUserData({deviceId});
+ if (deviceId) {
+ setGlobalUserData({ deviceId });
}
addClickstreamEvent(CLICKSTREAM_EVENT_NAMES.AV_LOGIN_SCREEN_LOAD);
}, []);
@@ -87,7 +89,7 @@ function Login() {
try {
await GoogleSignin.hasPlayServices();
const userInfo: GoogleSigninUser = await GoogleSignin.signIn();
- const serverAuthCode = userInfo?.data?.serverAuthCode || userInfo?.serverAuthCode
+ const serverAuthCode = userInfo?.data?.serverAuthCode || userInfo?.serverAuthCode;
if (serverAuthCode) {
toast({
text1: ToastMessages.FETCHING_USER_DATA,
diff --git a/src/services/casePayload.transformer.ts b/src/services/casePayload.transformer.ts
index fe9b5776..c9e6c0e9 100644
--- a/src/services/casePayload.transformer.ts
+++ b/src/services/casePayload.transformer.ts
@@ -46,6 +46,8 @@ export const extractQuestionContext = async (
let isBase64ImageAvailable = true;
const docsData =
store?.getState()?.feedbackImages?.intermediateDocsToBeUploaded?.[caseReferenceId]?.documents;
+ const feedbackAddressesMap =
+ store?.getState()?.topAddresses?.[caseReferenceId]?.feedbackAddressesMap;
const { widgetContext } = answer;
let newDocsData: GenericObject = {};
for (const widgetKey in widgetContext) {
@@ -63,10 +65,21 @@ export const extractQuestionContext = async (
if (answer.type === AnswerType.date) {
answer = { ...answer, answer: answer.answer.split('-').reverse().join('-') };
}
+
+ if (answer.type === AnswerType.address) {
+ const locationType = feedbackAddressesMap?.[answer.answer]?.locationType;
+ answer = {
+ ...answer,
+ metadata: {
+ locationType: locationType,
+ },
+ type: AnswerType.text,
+ };
+ }
+
if (
answer.type === AnswerType.date ||
answer.type === AnswerType.phoneNumber ||
- answer.type === AnswerType.address ||
answer.type === AnswerType.time
) {
answer = { ...answer, type: AnswerType.text };
diff --git a/src/store/store.ts b/src/store/store.ts
index 3bb3b1ea..0a540170 100644
--- a/src/store/store.ts
+++ b/src/store/store.ts
@@ -39,6 +39,7 @@ import postOperationalHourRestrictionsSlice from '@reducers/postOperationalHourR
import skipTracingAddressesSlice from '@reducers/skipTracingAddressesSlice';
import trainingMaterialSlice from '@reducers/trainingMaterialSlice';
import feedbackFormSlice from '@reducers/feedbackFormSlice';
+import topAddressesSlice from '@reducers/topAddressesSlice';
const rootReducer = combineReducers({
case: caseReducer,
@@ -78,6 +79,7 @@ const rootReducer = combineReducers({
postOperationalHourRestrictionsSlice: postOperationalHourRestrictionsSlice,
trainingMaterial: trainingMaterialSlice,
feedbackForm: feedbackFormSlice,
+ topAddresses: topAddressesSlice
});
const persistConfig = {