@djb25/digit-ui-module-ekyc 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +2164 -1535
- package/dist/index.modern.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ConnectionDetailsView.js +8 -8
- package/src/components/DesktopInbox.js +5 -5
- package/src/components/SearchConsumer.js +11 -2
- package/src/pages/employee/AadhaarVerification.js +367 -251
- package/src/pages/employee/AddressDetails.js +530 -373
- package/src/pages/employee/Create.js +5 -19
- package/src/pages/employee/Inbox.js +40 -34
- package/src/pages/employee/PropertyInfo.js +409 -316
- package/src/pages/employee/Review.js +290 -89
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import React, { useState, useRef, Fragment } from "react";
|
|
1
|
+
import React, { useState, useRef, Fragment, useEffect } from "react";
|
|
2
2
|
import {
|
|
3
|
-
Header,
|
|
4
3
|
Card,
|
|
5
4
|
LabelFieldPair,
|
|
6
5
|
CardLabel,
|
|
@@ -12,38 +11,226 @@ import {
|
|
|
12
11
|
InfoBannerIcon,
|
|
13
12
|
PropertyHouse,
|
|
14
13
|
LocationIcon,
|
|
15
|
-
RemoveableTag,
|
|
16
14
|
HomeIcon,
|
|
17
15
|
ConnectingCheckPoints,
|
|
18
16
|
CheckPoint,
|
|
17
|
+
Dropdown,
|
|
18
|
+
Loader,
|
|
19
19
|
} from "@djb25/digit-ui-react-components";
|
|
20
20
|
import { useTranslation } from "react-i18next";
|
|
21
21
|
import { useHistory, useLocation } from "react-router-dom";
|
|
22
22
|
|
|
23
|
+
// ─── Icons ────────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
const FlagIcon = ({ size = 20 }) => (
|
|
26
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
27
|
+
<path d="M14.4 6L13.6 4H5V21H7V14H12.6L13.4 16H20V6H14.4Z" fill="#0F6E56" />
|
|
28
|
+
</svg>
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const IdCardIcon = ({ size = 20 }) => (
|
|
32
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
33
|
+
<path
|
|
34
|
+
d="M2 7V17C2 18.1 2.9 19 4 19H20C21.1 19 22 18.1 22 17V7C22 5.9 21.1 5 20 5H4C2.9 5 2 5.9 2 7ZM12 11H14V13H12V11ZM12 7H14V9H12V7ZM16 11H20V13H16V11ZM16 7H20V9H16V7ZM4 7H10V15H4V7ZM20 17H4V16H20V17Z"
|
|
35
|
+
fill="#185FA5"
|
|
36
|
+
/>
|
|
37
|
+
</svg>
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const CameraIcon = ({ size = 28 }) => (
|
|
41
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
42
|
+
<path
|
|
43
|
+
d="M9 2L7.17 4H4C2.9 4 2 4.9 2 6V18C2 19.1 2.9 20 4 20H20C21.1 20 22 19.1 22 18V6C22 4.9 21.1 4 20 4H16.83L15 2H9ZM12 17C9.24 17 7 14.76 7 12C7 9.24 9.24 7 12 7C14.76 7 17 9.24 17 12C17 14.76 14.76 17 12 17ZM12 9C10.34 9 9 10.34 9 12C9 13.66 10.34 15 12 15C13.66 15 15 13.66 15 12C15 10.34 13.66 9 12 9Z"
|
|
44
|
+
fill="#185FA5"
|
|
45
|
+
/>
|
|
46
|
+
</svg>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const TargetIcon = ({ size = 20 }) => (
|
|
50
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
51
|
+
<path
|
|
52
|
+
d="M12 8C9.79 8 8 9.79 8 12C8 14.21 9.79 16 12 16C14.21 16 16 14.21 16 12C16 9.79 14.21 8 12 8ZM20.94 11C20.48 6.83 17.17 3.52 13 3.06V1H11V3.06C6.83 3.52 3.52 6.83 3.06 11H1V13H3.06C3.52 17.17 6.83 20.48 11 20.94V23H13V20.94C17.17 20.48 20.48 17.17 20.94 13H23V11H20.94ZM12 19C8.13 19 5 15.87 5 12C5 8.13 8.13 5 12 5C15.87 5 19 8.13 19 12C19 15.87 15.87 19 12 19Z"
|
|
53
|
+
fill="#185FA5"
|
|
54
|
+
/>
|
|
55
|
+
</svg>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const PincodeIcon = ({ size = 18 }) => (
|
|
59
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
|
60
|
+
<path
|
|
61
|
+
d="M13 13V11H15V13H13ZM13 9V7H15V9H13ZM17 13V11H19V13H17ZM17 9V7H19V9H17ZM11 13V11H9V13H11ZM11 9V7H9V9H11ZM7 13V11H5V13H7ZM7 9V7H5V9H7ZM21 3H3C1.9 3 1 3.9 1 5V19C1 20.1 1.9 21 3 21H21C22.1 21 23 20.1 23 19V5C23 3.9 22.1 3 21 3ZM21 19H3V5H21V19Z"
|
|
62
|
+
fill="currentColor"
|
|
63
|
+
/>
|
|
64
|
+
</svg>
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const TrashIcon = ({ size = 16 }) => (
|
|
68
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="#D92D20" strokeWidth="2" strokeLinecap="round">
|
|
69
|
+
<polyline points="3 6 5 6 21 6" />
|
|
70
|
+
<path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
|
|
71
|
+
<path d="M10 11v6M14 11v6" />
|
|
72
|
+
<path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2" />
|
|
73
|
+
</svg>
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const CheckIcon = ({ size = 11, color = "#fff" }) => (
|
|
77
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="3" strokeLinecap="round">
|
|
78
|
+
<polyline points="20 6 9 17 4 12" />
|
|
79
|
+
</svg>
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// ─── Reusable: Icon-prefixed input ────────────────────────────────────────────
|
|
83
|
+
|
|
84
|
+
const IconInput = ({ icon, topAligned = false, inputStyle = {}, ...props }) => (
|
|
85
|
+
<div style={{ position: "relative", width: "100%" }}>
|
|
86
|
+
<div style={{
|
|
87
|
+
position: "absolute",
|
|
88
|
+
left: "10px",
|
|
89
|
+
...(topAligned ? { top: "14px" } : { top: "50%", transform: "translateY(-50%)" }),
|
|
90
|
+
zIndex: 1,
|
|
91
|
+
opacity: 0.45,
|
|
92
|
+
display: "flex",
|
|
93
|
+
pointerEvents: "none",
|
|
94
|
+
}}>
|
|
95
|
+
{icon}
|
|
96
|
+
</div>
|
|
97
|
+
<TextInput
|
|
98
|
+
textInputStyle={{ paddingLeft: "36px", paddingRight: "12px", ...inputStyle }}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
</div>
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
// ─── Reusable: Section heading with inline rule ───────────────────────────────
|
|
105
|
+
|
|
106
|
+
const SectionHead = ({ icon, label }) => (
|
|
107
|
+
<div style={{
|
|
108
|
+
display: "flex", alignItems: "center", gap: "8px",
|
|
109
|
+
marginBottom: "16px", marginTop: "4px",
|
|
110
|
+
}}>
|
|
111
|
+
<div style={{ opacity: 0.5, display: "flex" }}>{icon}</div>
|
|
112
|
+
<span style={{ fontSize: "15px", fontWeight: "600", color: "#0B0C0C", whiteSpace: "nowrap" }}>
|
|
113
|
+
{label}
|
|
114
|
+
</span>
|
|
115
|
+
<div style={{ flex: 1, height: "1px", background: "#EAECF0" }} />
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// ─── Reusable: Admin info card ────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
const AdminCard = ({ bgColor, iconBg, icon, labelColor, label, value }) => (
|
|
122
|
+
<div style={{
|
|
123
|
+
backgroundColor: bgColor,
|
|
124
|
+
padding: "14px 16px",
|
|
125
|
+
borderRadius: "8px",
|
|
126
|
+
display: "flex",
|
|
127
|
+
alignItems: "center",
|
|
128
|
+
gap: "14px",
|
|
129
|
+
border: "0.5px solid #EAECF0",
|
|
130
|
+
}}>
|
|
131
|
+
<div style={{ backgroundColor: iconBg, padding: "8px", borderRadius: "8px", display: "flex", flexShrink: 0 }}>
|
|
132
|
+
{icon}
|
|
133
|
+
</div>
|
|
134
|
+
<div>
|
|
135
|
+
<div style={{ color: labelColor, fontSize: "10px", fontWeight: "600", textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: "3px" }}>
|
|
136
|
+
{label}
|
|
137
|
+
</div>
|
|
138
|
+
<div style={{ fontSize: "14px", fontWeight: "600", color: "#101828" }}>{value}</div>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// ─── Main Component ───────────────────────────────────────────────────────────
|
|
144
|
+
|
|
23
145
|
const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
|
|
24
146
|
const { t } = useTranslation();
|
|
25
147
|
const history = useHistory();
|
|
26
148
|
const location = useLocation();
|
|
27
149
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
150
|
+
const flowState = parentState || location.state || {
|
|
151
|
+
kNumber: "EKYC-1234567890",
|
|
152
|
+
selectedOption: { code: "SELF", name: "EKYC_SELF" },
|
|
153
|
+
connectionDetails: null,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const addrDetails = flowState.connectionDetails?.addressDetails || {};
|
|
35
157
|
|
|
36
158
|
const [addressType, setAddressType] = useState({ code: "AADHAAR", name: "EKYC_AADHAAR_ADDRESS" });
|
|
37
159
|
const [correctAddress, setCorrectAddress] = useState({ code: "NO", name: "CORE_COMMON_NO" });
|
|
38
|
-
const [fullAddress, setFullAddress] = useState("");
|
|
39
|
-
const [flatNo, setFlatNo] = useState("");
|
|
40
|
-
const [building, setBuilding] = useState("");
|
|
41
|
-
const [landmark, setLandmark] = useState("");
|
|
42
|
-
const [pincode, setPincode] = useState("");
|
|
160
|
+
const [fullAddress, setFullAddress] = useState(addrDetails.fullAddress || "");
|
|
161
|
+
const [flatNo, setFlatNo] = useState(addrDetails.flatHouseNumber || "");
|
|
162
|
+
const [building, setBuilding] = useState(addrDetails.buildingTower || "");
|
|
163
|
+
const [landmark, setLandmark] = useState(addrDetails.landmark || "");
|
|
164
|
+
const [pincode, setPincode] = useState(addrDetails.pinCode || "");
|
|
43
165
|
const [doorPhoto, setDoorPhoto] = useState(null);
|
|
44
166
|
const [isLocationFetching, setIsLocationFetching] = useState(false);
|
|
45
167
|
const fileInputRef = useRef(null);
|
|
46
168
|
|
|
169
|
+
const tenantId = Digit.ULBService.getCurrentTenantId();
|
|
170
|
+
const { data: mdmsData, isLoading: isMdmsLoading } = Digit.Hooks.useCommonMDMS(
|
|
171
|
+
tenantId,
|
|
172
|
+
"egov-location",
|
|
173
|
+
["TenantBoundary"]
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const mdmsRes = mdmsData?.MdmsRes || mdmsData;
|
|
177
|
+
const adminHierarchy = mdmsRes?.["egov-location"]?.TenantBoundary?.find(h => h.hierarchyType.code === "ADMIN")
|
|
178
|
+
|| mdmsRes?.["egov-location"]?.TenantBoundary?.[0];
|
|
179
|
+
|
|
180
|
+
const rootBoundary = adminHierarchy?.boundary;
|
|
181
|
+
|
|
182
|
+
const getAssemblies = (boundaries) => {
|
|
183
|
+
if (!boundaries) return [];
|
|
184
|
+
let assemblies = [];
|
|
185
|
+
const targetLabel = "assembly constituency";
|
|
186
|
+
for (const boundary of boundaries) {
|
|
187
|
+
const label = (boundary.label || boundary.name || "").toLowerCase().replace(/_/g, " ");
|
|
188
|
+
if (label === targetLabel || label === "assemblyconstituency") {
|
|
189
|
+
assemblies.push({ code: boundary.code, name: boundary.name, children: boundary.children });
|
|
190
|
+
}
|
|
191
|
+
if (boundary.children?.length) {
|
|
192
|
+
assemblies.push(...getAssemblies(boundary.children));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return assemblies;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const getBlocks = (children) => {
|
|
199
|
+
if (!children) return [];
|
|
200
|
+
let blocks = [];
|
|
201
|
+
const targetLabel = "block";
|
|
202
|
+
for (const child of children) {
|
|
203
|
+
const label = (child.label || child.name || "").toLowerCase().replace(/_/g, " ");
|
|
204
|
+
if (label === targetLabel) {
|
|
205
|
+
blocks.push({ code: child.code, name: child.name });
|
|
206
|
+
}
|
|
207
|
+
if (child.children?.length) {
|
|
208
|
+
blocks.push(...getBlocks(child.children));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return blocks;
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const assemblies = getAssemblies(Array.isArray(rootBoundary) ? rootBoundary : rootBoundary ? [rootBoundary] : []);
|
|
215
|
+
|
|
216
|
+
const [assembly, setAssembly] = useState(addrDetails.assembly ? { name: addrDetails.assembly } : null);
|
|
217
|
+
const [ward, setWard] = useState(addrDetails.ward ? { name: addrDetails.ward } : null);
|
|
218
|
+
|
|
219
|
+
useEffect(() => {
|
|
220
|
+
if (mdmsRes && addrDetails.assembly && !assembly?.code) {
|
|
221
|
+
const foundAssembly = assemblies.find((a) => a.name === addrDetails.assembly || a.code === addrDetails.assembly);
|
|
222
|
+
if (foundAssembly) setAssembly(foundAssembly);
|
|
223
|
+
}
|
|
224
|
+
}, [mdmsRes, assemblies]);
|
|
225
|
+
|
|
226
|
+
const blocks = assembly ? getBlocks(assembly.children) : [];
|
|
227
|
+
|
|
228
|
+
useEffect(() => {
|
|
229
|
+
if (assembly && ward && !blocks.find((b) => b.name === ward.name)) {
|
|
230
|
+
setWard(null);
|
|
231
|
+
}
|
|
232
|
+
}, [assembly]);
|
|
233
|
+
|
|
47
234
|
const addressOptions = [
|
|
48
235
|
{ code: "AADHAAR", name: "EKYC_AADHAAR_ADDRESS" },
|
|
49
236
|
{ code: "OLD", name: "EKYC_OLD_ADDRESS" },
|
|
@@ -55,32 +242,33 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
|
|
|
55
242
|
];
|
|
56
243
|
|
|
57
244
|
const handleCompleteVerification = () => {
|
|
245
|
+
const payload = {
|
|
246
|
+
addressType,
|
|
247
|
+
fullAddress,
|
|
248
|
+
flatNo,
|
|
249
|
+
building,
|
|
250
|
+
landmark,
|
|
251
|
+
pincode,
|
|
252
|
+
doorPhoto,
|
|
253
|
+
assembly: assembly?.name,
|
|
254
|
+
ward: ward?.name
|
|
255
|
+
};
|
|
58
256
|
if (onComplete) {
|
|
59
|
-
onComplete(
|
|
257
|
+
onComplete(payload);
|
|
60
258
|
} else {
|
|
61
259
|
const { kNumber, selectedOption, connectionDetails } = flowState;
|
|
62
260
|
history.push("/digit-ui/employee/ekyc/property-info", {
|
|
63
|
-
kNumber,
|
|
64
|
-
selectedOption,
|
|
65
|
-
connectionDetails,
|
|
66
|
-
addressDetails: { addressType, fullAddress, flatNo, building, landmark, pincode, doorPhoto },
|
|
261
|
+
kNumber, selectedOption, connectionDetails, addressDetails: payload,
|
|
67
262
|
});
|
|
68
263
|
}
|
|
69
264
|
};
|
|
70
265
|
|
|
71
266
|
const handleCapture = (e) => {
|
|
72
267
|
const file = e.target.files[0];
|
|
73
|
-
if (file)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
};
|
|
78
|
-
reader.readAsDataURL(file);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const openGallery = () => {
|
|
83
|
-
fileInputRef.current.click();
|
|
268
|
+
if (!file) return;
|
|
269
|
+
const reader = new FileReader();
|
|
270
|
+
reader.onloadend = () => setDoorPhoto(reader.result);
|
|
271
|
+
reader.readAsDataURL(file);
|
|
84
272
|
};
|
|
85
273
|
|
|
86
274
|
const removePhoto = () => {
|
|
@@ -93,98 +281,47 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
|
|
|
93
281
|
alert(t("GEOLOCATION_NOT_SUPPORTED") || "Geolocation is not supported by your browser");
|
|
94
282
|
return;
|
|
95
283
|
}
|
|
96
|
-
|
|
97
284
|
setIsLocationFetching(true);
|
|
98
285
|
navigator.geolocation.getCurrentPosition(
|
|
99
|
-
async (
|
|
100
|
-
const { latitude, longitude } = position.coords;
|
|
286
|
+
async ({ coords: { latitude, longitude } }) => {
|
|
101
287
|
try {
|
|
102
|
-
const
|
|
288
|
+
const res = await fetch(
|
|
103
289
|
`https://nominatim.openstreetmap.org/reverse?format=json&lat=${latitude}&lon=${longitude}&zoom=18&addressdetails=1`
|
|
104
290
|
);
|
|
105
|
-
if (!
|
|
106
|
-
const data = await
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
data.address?.suburb,
|
|
114
|
-
data.address?.city,
|
|
115
|
-
data.address?.state,
|
|
116
|
-
data.address?.postcode,
|
|
117
|
-
]
|
|
118
|
-
.filter(Boolean)
|
|
119
|
-
.join(", ");
|
|
120
|
-
|
|
121
|
-
setFullAddress(addr || "");
|
|
122
|
-
setPincode(data.address?.postcode || "");
|
|
123
|
-
setLandmark(data.address?.suburb || data.address?.neighbourhood || "");
|
|
124
|
-
setFlatNo(data.address?.amenity || "");
|
|
291
|
+
if (!res.ok) throw new Error("Geocode failed");
|
|
292
|
+
const data = await res.json();
|
|
293
|
+
if (data?.address) {
|
|
294
|
+
const a = data.address;
|
|
295
|
+
setFullAddress([a.amenity, a.road, a.neighbourhood, a.suburb, a.city, a.state, a.postcode].filter(Boolean).join(", "));
|
|
296
|
+
setPincode(a.postcode || "");
|
|
297
|
+
setLandmark(a.suburb || a.neighbourhood || "");
|
|
298
|
+
setFlatNo(a.amenity || "");
|
|
125
299
|
}
|
|
126
|
-
} catch (
|
|
127
|
-
console.error("
|
|
300
|
+
} catch (err) {
|
|
301
|
+
console.error("Reverse geocode error:", err);
|
|
128
302
|
} finally {
|
|
129
303
|
setIsLocationFetching(false);
|
|
130
304
|
}
|
|
131
305
|
},
|
|
132
|
-
(
|
|
133
|
-
console.error("
|
|
306
|
+
(err) => {
|
|
307
|
+
console.error("Geolocation error:", err);
|
|
134
308
|
setIsLocationFetching(false);
|
|
135
|
-
alert(t("LOCATION_FETCH_FAILED") || "Failed to fetch
|
|
309
|
+
alert(t("LOCATION_FETCH_FAILED") || "Failed to fetch location. Please grant location permissions.");
|
|
136
310
|
},
|
|
137
311
|
{ enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }
|
|
138
312
|
);
|
|
139
313
|
};
|
|
140
314
|
|
|
141
|
-
const
|
|
142
|
-
<
|
|
143
|
-
<path d="M14.4 6L13.6 4H5V21H7V14H12.6L13.4 16H20V6H14.4Z" fill="#2E9E8F" />
|
|
144
|
-
</svg>
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
const IdCardIcon = () => (
|
|
148
|
-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
149
|
-
<path
|
|
150
|
-
d="M2 7V17C2 18.1 2.9 19 4 19H20C21.1 19 22 18.1 22 17V7C22 5.9 21.1 5 20 5H4C2.9 5 2 5.9 2 7ZM12 11H14V13H12V11ZM12 7H14V9H12V7ZM16 11H20V13H16V11ZM16 7H20V9H16V7ZM4 7H10V15H4V7ZM20 17H4V16H20V17Z"
|
|
151
|
-
fill="#3D51B0"
|
|
152
|
-
/>
|
|
153
|
-
</svg>
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
const CameraIcon = () => (
|
|
157
|
-
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
158
|
-
<path
|
|
159
|
-
d="M9 2L7.17 4H4C2.9 4 2 4.9 2 6V18C2 19.1 2.9 20 4 20H20C21.1 20 22 19.1 22 18V6C22 4.9 21.1 4 20 4H16.83L15 2H9ZM12 17C9.24 17 7 14.76 7 12C7 9.24 9.24 7 12 7C14.76 7 17 9.24 17 12C17 14.76 14.76 17 12 17ZM12 9C10.34 9 9 10.34 9 12C9 13.66 10.34 15 12 15C13.66 15 15 13.66 15 12C15 10.34 13.66 9 12 9Z"
|
|
160
|
-
fill="#0068faff"
|
|
161
|
-
/>
|
|
162
|
-
</svg>
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
const TargetIcon = () => (
|
|
166
|
-
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
167
|
-
<path
|
|
168
|
-
d="M12 8C9.79 8 8 9.79 8 12C8 14.21 9.79 16 12 16C14.21 16 16 14.21 16 12C16 9.79 14.21 8 12 8ZM20.94 11C20.48 6.83 17.17 3.52 13 3.06V1H11V3.06C6.83 3.52 3.52 6.83 3.06 11H1V13H3.06C3.52 17.17 6.83 20.48 11 20.94V23H13V20.94C17.17 20.48 20.48 17.17 20.94 13H23V11H20.94ZM12 19C8.13 19 5 15.87 5 12C5 8.13 8.13 5 12 5C15.87 5 19 8.13 19 12C19 15.87 15.87 19 12 19Z"
|
|
169
|
-
fill="#0068faff"
|
|
170
|
-
/>
|
|
171
|
-
</svg>
|
|
172
|
-
);
|
|
315
|
+
const renderContent = () => (
|
|
316
|
+
<div style={{ animation: "fadeSlideIn 0.3s ease" }}>
|
|
173
317
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
fill="#0068faff"
|
|
318
|
+
{/* ── Address Type Toggle ── */}
|
|
319
|
+
<SectionHead
|
|
320
|
+
icon={<LocationIcon className="icon" styles={{ fill: "#0B0C0C", width: "16px", height: "16px" }} />}
|
|
321
|
+
label={t("EKYC_ADDRESS_DETAILS_HEADER") || "Address Details"}
|
|
179
322
|
/>
|
|
180
|
-
</svg>
|
|
181
|
-
);
|
|
182
323
|
|
|
183
|
-
|
|
184
|
-
<div style={{ animation: "fadeSlideIn 0.3s ease" }}>
|
|
185
|
-
{isSection && <hr style={{ margin: "40px 0", border: "0", borderTop: "2px solid #EAECF0" }} />}
|
|
186
|
-
<Header style={{ marginBottom: "24px" }}>{t("EKYC_ADDRESS_DETAILS_HEADER") || "Address Details"}</Header>
|
|
187
|
-
<div style={{ marginBottom: "32px" }}>
|
|
324
|
+
<div style={{ marginBottom: "20px" }}>
|
|
188
325
|
<RadioButtons
|
|
189
326
|
options={addressOptions}
|
|
190
327
|
optionsKey="name"
|
|
@@ -192,40 +329,40 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
|
|
|
192
329
|
onSelect={setAddressType}
|
|
193
330
|
t={t}
|
|
194
331
|
innerStyles={{ display: "flex", alignItems: "center" }}
|
|
195
|
-
style={{ display: "flex", gap: "
|
|
332
|
+
style={{ display: "flex", gap: "40px" }}
|
|
196
333
|
/>
|
|
197
334
|
</div>
|
|
198
335
|
|
|
336
|
+
{/* ── Aadhaar Address display ── */}
|
|
199
337
|
{addressType.code === "AADHAAR" && (
|
|
200
|
-
<div
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}}
|
|
212
|
-
|
|
213
|
-
<div style={{ backgroundColor: "#E7F4EE", padding: "8px", borderRadius: "8px" }}>
|
|
214
|
-
<LocationIcon className="icon" styles={{ fill: "#2E9E8F", width: "20px", height: "20px" }} />
|
|
338
|
+
<div style={{
|
|
339
|
+
backgroundColor: "#E1F5EE",
|
|
340
|
+
border: "0.5px solid #5DCAA5",
|
|
341
|
+
borderRadius: "8px",
|
|
342
|
+
padding: "14px 16px",
|
|
343
|
+
display: "flex",
|
|
344
|
+
alignItems: "flex-start",
|
|
345
|
+
gap: "12px",
|
|
346
|
+
marginBottom: "20px",
|
|
347
|
+
animation: "fadeSlideIn 0.3s ease",
|
|
348
|
+
}}>
|
|
349
|
+
<div style={{ backgroundColor: "#9FE1CB", padding: "6px", borderRadius: "6px", display: "flex", flexShrink: 0 }}>
|
|
350
|
+
<LocationIcon className="icon" styles={{ fill: "#085041", width: "16px", height: "16px" }} />
|
|
215
351
|
</div>
|
|
216
|
-
<div style={{ fontSize: "
|
|
217
|
-
H.No. 123, Sector 15, Rohini
|
|
218
|
-
<br />
|
|
219
|
-
Delhi - 110085
|
|
352
|
+
<div style={{ fontSize: "14px", lineHeight: "1.6", color: "#04342C", fontWeight: "500" }}>
|
|
353
|
+
{addrDetails.fullAddress || "H.No. 123, Sector 15, Rohini, Delhi – 110085"}
|
|
220
354
|
</div>
|
|
221
355
|
</div>
|
|
222
356
|
)}
|
|
223
357
|
|
|
358
|
+
{/* ── Old / Custom Address ── */}
|
|
224
359
|
{addressType.code === "OLD" && (
|
|
225
360
|
<div style={{ animation: "fadeSlideIn 0.3s ease" }}>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
361
|
+
|
|
362
|
+
{/* Correction toggle */}
|
|
363
|
+
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: "14px" }}>
|
|
364
|
+
<CardLabel style={{ fontWeight: "500", marginBottom: 0, fontSize: "13px", color: "#505A5F" }}>
|
|
365
|
+
{t("EKYC_ADDRESS_CORRECTION_PROMPT") || "Correct the address?"}
|
|
229
366
|
</CardLabel>
|
|
230
367
|
<RadioButtons
|
|
231
368
|
options={yesNoOptions}
|
|
@@ -233,352 +370,372 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
|
|
|
233
370
|
selectedOption={correctAddress}
|
|
234
371
|
onSelect={setCorrectAddress}
|
|
235
372
|
t={t}
|
|
236
|
-
innerStyles={{ display: "flex",
|
|
237
|
-
style={{
|
|
373
|
+
innerStyles={{ display: "flex", gap: "20px" }}
|
|
374
|
+
style={{ marginBottom: 0 }}
|
|
238
375
|
/>
|
|
239
376
|
</div>
|
|
240
377
|
|
|
378
|
+
{/* Use Current Location */}
|
|
241
379
|
<div
|
|
380
|
+
onClick={!isLocationFetching ? handleUseCurrentLocation : undefined}
|
|
242
381
|
style={{
|
|
243
|
-
border: "
|
|
244
|
-
borderRadius: "
|
|
245
|
-
padding: "
|
|
382
|
+
border: "0.5px solid #D0D5DD",
|
|
383
|
+
borderRadius: "8px",
|
|
384
|
+
padding: "12px 16px",
|
|
246
385
|
display: "flex",
|
|
247
386
|
alignItems: "center",
|
|
248
387
|
justifyContent: "space-between",
|
|
249
|
-
marginBottom: "
|
|
388
|
+
marginBottom: "20px",
|
|
250
389
|
cursor: isLocationFetching ? "not-allowed" : "pointer",
|
|
251
|
-
backgroundColor: isLocationFetching ? "#
|
|
252
|
-
transition: "
|
|
390
|
+
backgroundColor: isLocationFetching ? "#F9FAFB" : "#fff",
|
|
391
|
+
transition: "background 0.15s",
|
|
253
392
|
opacity: isLocationFetching ? 0.7 : 1,
|
|
254
|
-
boxShadow: "0px 1px 2px rgba(16, 24, 40, 0.05)",
|
|
255
393
|
}}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
onMouseOut={(e) => (!isLocationFetching ? (e.currentTarget.style.backgroundColor = "#FFFFFF") : null)}
|
|
394
|
+
onMouseOver={(e) => { if (!isLocationFetching) e.currentTarget.style.background = "#F9FAFB"; }}
|
|
395
|
+
onMouseOut={(e) => { if (!isLocationFetching) e.currentTarget.style.background = "#fff"; }}
|
|
259
396
|
>
|
|
260
397
|
<div style={{ display: "flex", alignItems: "center", gap: "12px" }}>
|
|
261
|
-
<div style={{ backgroundColor: "#
|
|
398
|
+
<div style={{ backgroundColor: "#E6F1FB", padding: "7px", borderRadius: "7px", display: "flex" }}>
|
|
262
399
|
{isLocationFetching ? (
|
|
263
|
-
<div
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
border: "2px solid #0068faff",
|
|
269
|
-
borderTopColor: "transparent",
|
|
270
|
-
borderRadius: "50%",
|
|
271
|
-
animation: "spin 1s linear infinite",
|
|
272
|
-
}}
|
|
273
|
-
></div>
|
|
400
|
+
<div style={{
|
|
401
|
+
width: "18px", height: "18px", border: "2px solid #185FA5",
|
|
402
|
+
borderTopColor: "transparent", borderRadius: "50%",
|
|
403
|
+
animation: "spin 1s linear infinite",
|
|
404
|
+
}} />
|
|
274
405
|
) : (
|
|
275
|
-
<TargetIcon />
|
|
406
|
+
<TargetIcon size={18} />
|
|
276
407
|
)}
|
|
277
408
|
</div>
|
|
278
|
-
<span style={{ fontWeight: "
|
|
409
|
+
<span style={{ fontWeight: "500", fontSize: "14px", color: "#344054" }}>
|
|
279
410
|
{isLocationFetching
|
|
280
|
-
? t("EKYC_FETCHING_LOCATION") || "Fetching
|
|
281
|
-
: t("EKYC_USE_CURRENT_LOCATION") || "Use
|
|
411
|
+
? t("EKYC_FETCHING_LOCATION") || "Fetching location..."
|
|
412
|
+
: t("EKYC_USE_CURRENT_LOCATION") || "Use current location"}
|
|
282
413
|
</span>
|
|
283
414
|
</div>
|
|
284
|
-
{!isLocationFetching &&
|
|
415
|
+
{!isLocationFetching && (
|
|
416
|
+
<span style={{ fontSize: "18px", color: "#98A2B3", lineHeight: 1 }}>›</span>
|
|
417
|
+
)}
|
|
285
418
|
</div>
|
|
286
419
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
<div
|
|
290
|
-
|
|
291
|
-
|
|
420
|
+
{/* Full Address (textarea-style) */}
|
|
421
|
+
<div style={{ marginBottom: "14px" }}>
|
|
422
|
+
<div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
|
|
423
|
+
{t("EKYC_FULL_ADDRESS") || "Full address"}
|
|
424
|
+
</div>
|
|
425
|
+
<IconInput
|
|
426
|
+
icon={<PropertyHouse styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
|
|
427
|
+
topAligned
|
|
428
|
+
value={fullAddress}
|
|
429
|
+
onChange={(e) => setFullAddress(e.target.value)}
|
|
430
|
+
placeholder={t("EKYC_ENTER_FULL_ADDRESS") || "Enter full address"}
|
|
431
|
+
inputStyle={{ minHeight: "72px" }}
|
|
432
|
+
/>
|
|
433
|
+
</div>
|
|
434
|
+
|
|
435
|
+
{/* Flat + Building */}
|
|
436
|
+
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "14px" }}>
|
|
437
|
+
<div>
|
|
438
|
+
<div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
|
|
439
|
+
{t("EKYC_FLAT_HOUSE_NUMBER") || "Flat / House no."}
|
|
292
440
|
</div>
|
|
293
|
-
<
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
441
|
+
<IconInput
|
|
442
|
+
icon={<PropertyHouse styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
|
|
443
|
+
value={flatNo}
|
|
444
|
+
onChange={(e) => setFlatNo(e.target.value)}
|
|
445
|
+
placeholder={t("EKYC_ENTER_FLAT_NO") || "e.g. 45-B"}
|
|
298
446
|
/>
|
|
299
447
|
</div>
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
<LabelFieldPair>
|
|
304
|
-
<CardLabel style={{ fontWeight: "600" }}>{t("EKYC_FLAT_HOUSE_NUMBER") || "Flat/House Number"}</CardLabel>
|
|
305
|
-
<div className="field" style={{ position: "relative" }}>
|
|
306
|
-
<div style={{ position: "absolute", left: "12px", top: "50%", transform: "translateY(-50%)", zIndex: 1, opacity: 0.6 }}>
|
|
307
|
-
<PropertyHouse styles={{ fill: "#0068faff", width: "20px", height: "20px" }} />
|
|
308
|
-
</div>
|
|
309
|
-
<TextInput
|
|
310
|
-
value={flatNo}
|
|
311
|
-
onChange={(e) => setFlatNo(e.target.value)}
|
|
312
|
-
placeholder={t("EKYC_ENTER_FLAT_NO") || "e.g. 45-B"}
|
|
313
|
-
textInputStyle={{ paddingLeft: "40px" }}
|
|
314
|
-
/>
|
|
315
|
-
</div>
|
|
316
|
-
</LabelFieldPair>
|
|
317
|
-
<LabelFieldPair>
|
|
318
|
-
<CardLabel style={{ fontWeight: "600" }}>{t("EKYC_BUILDING_TOWER") || "Building/Tower"}</CardLabel>
|
|
319
|
-
<div className="field" style={{ position: "relative" }}>
|
|
320
|
-
<div style={{ position: "absolute", left: "12px", top: "50%", transform: "translateY(-50%)", zIndex: 1, opacity: 0.6 }}>
|
|
321
|
-
<PropertyHouse styles={{ fill: "#0068faff", width: "20px", height: "20px" }} />
|
|
322
|
-
</div>
|
|
323
|
-
<TextInput
|
|
324
|
-
value={building}
|
|
325
|
-
onChange={(e) => setBuilding(e.target.value)}
|
|
326
|
-
placeholder={t("EKYC_ENTER_BUILDING") || "e.g. Tower 4"}
|
|
327
|
-
textInputStyle={{ paddingLeft: "40px" }}
|
|
328
|
-
/>
|
|
448
|
+
<div>
|
|
449
|
+
<div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
|
|
450
|
+
{t("EKYC_BUILDING_TOWER") || "Building / Tower"}
|
|
329
451
|
</div>
|
|
330
|
-
|
|
452
|
+
<IconInput
|
|
453
|
+
icon={<PropertyHouse styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
|
|
454
|
+
value={building}
|
|
455
|
+
onChange={(e) => setBuilding(e.target.value)}
|
|
456
|
+
placeholder={t("EKYC_ENTER_BUILDING") || "e.g. Tower 4"}
|
|
457
|
+
/>
|
|
458
|
+
</div>
|
|
331
459
|
</div>
|
|
332
460
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
<div
|
|
336
|
-
<div style={{
|
|
337
|
-
|
|
461
|
+
{/* Landmark + Pincode */}
|
|
462
|
+
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "4px" }}>
|
|
463
|
+
<div>
|
|
464
|
+
<div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
|
|
465
|
+
{t("EKYC_LANDMARK") || "Landmark"}
|
|
338
466
|
</div>
|
|
339
|
-
<
|
|
467
|
+
<IconInput
|
|
468
|
+
icon={<LocationIcon className="icon" styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
|
|
340
469
|
value={landmark}
|
|
341
470
|
onChange={(e) => setLandmark(e.target.value)}
|
|
342
471
|
placeholder={t("EKYC_ENTER_LANDMARK") || "Near Central Park"}
|
|
343
|
-
textInputStyle={{ paddingLeft: "40px" }}
|
|
344
472
|
/>
|
|
345
473
|
</div>
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
<CardLabel style={{ fontWeight: "600" }}>{t("EKYC_PINCODE") || "Pincode"}</CardLabel>
|
|
350
|
-
<div className="field" style={{ position: "relative" }}>
|
|
351
|
-
<div style={{ position: "absolute", left: "12px", top: "50%", transform: "translateY(-50%)", zIndex: 1, opacity: 0.6 }}>
|
|
352
|
-
<PincodeIcon />
|
|
474
|
+
<div>
|
|
475
|
+
<div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
|
|
476
|
+
{t("EKYC_PINCODE") || "Pincode"}
|
|
353
477
|
</div>
|
|
354
|
-
<
|
|
478
|
+
<IconInput
|
|
479
|
+
icon={<PincodeIcon size={15} />}
|
|
355
480
|
value={pincode}
|
|
356
|
-
onChange={(e) => setPincode(e.target.value)}
|
|
481
|
+
onChange={(e) => { if (/^\d*$/.test(e.target.value)) setPincode(e.target.value); }}
|
|
357
482
|
placeholder={t("EKYC_ENTER_PINCODE") || "6-digit pincode"}
|
|
358
|
-
textInputStyle={{ paddingLeft: "40px" }}
|
|
359
483
|
maxLength={6}
|
|
360
484
|
/>
|
|
361
485
|
</div>
|
|
362
|
-
</
|
|
486
|
+
</div>
|
|
363
487
|
</div>
|
|
364
488
|
)}
|
|
365
489
|
|
|
366
|
-
<hr style={{ margin: "
|
|
490
|
+
<hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
|
|
367
491
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
</div>
|
|
492
|
+
{/* ── Administrative Division ── */}
|
|
493
|
+
<SectionHead
|
|
494
|
+
icon={<PropertyHouse styles={{ fill: "#0B0C0C", width: "16px", height: "16px" }} />}
|
|
495
|
+
label={t("EKYC_ADMINISTRATIVE_DIVISION") || "Administrative Division"}
|
|
496
|
+
/>
|
|
374
497
|
|
|
375
|
-
|
|
376
|
-
<div
|
|
377
|
-
style={{
|
|
378
|
-
backgroundColor: "#F9FAFB",
|
|
379
|
-
padding: "16px",
|
|
380
|
-
borderRadius: "12px",
|
|
381
|
-
display: "flex",
|
|
382
|
-
alignItems: "center",
|
|
383
|
-
gap: "16px",
|
|
384
|
-
border: "1px solid #EAECF0",
|
|
385
|
-
}}
|
|
386
|
-
>
|
|
387
|
-
<div style={{ backgroundColor: "#E7F4EE", padding: "10px", borderRadius: "10px", display: "flex" }}>
|
|
388
|
-
<FlagIcon />
|
|
389
|
-
</div>
|
|
498
|
+
{isMdmsLoading ? <Loader /> : (
|
|
499
|
+
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "24px" }}>
|
|
390
500
|
<div>
|
|
391
|
-
<div style={{
|
|
392
|
-
{t("EKYC_ASSEMBLY") || "
|
|
501
|
+
<div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
|
|
502
|
+
{t("EKYC_ASSEMBLY") || "Assembly Constituency"}
|
|
393
503
|
</div>
|
|
394
|
-
<
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
borderRadius: "12px",
|
|
402
|
-
display: "flex",
|
|
403
|
-
alignItems: "center",
|
|
404
|
-
gap: "16px",
|
|
405
|
-
border: "1px solid #EAECF0",
|
|
406
|
-
}}
|
|
407
|
-
>
|
|
408
|
-
<div style={{ backgroundColor: "#EEF4FF", padding: "10px", borderRadius: "10px", display: "flex" }}>
|
|
409
|
-
<IdCardIcon />
|
|
504
|
+
<Dropdown
|
|
505
|
+
option={assemblies}
|
|
506
|
+
optionKey="name"
|
|
507
|
+
selected={assembly}
|
|
508
|
+
select={(val) => { setAssembly(val); setWard(null); }}
|
|
509
|
+
t={t}
|
|
510
|
+
/>
|
|
410
511
|
</div>
|
|
411
512
|
<div>
|
|
412
|
-
<div style={{
|
|
413
|
-
{t("EKYC_WARD") || "
|
|
513
|
+
<div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
|
|
514
|
+
{t("EKYC_WARD") || "Block"}
|
|
414
515
|
</div>
|
|
415
|
-
<
|
|
516
|
+
<Dropdown
|
|
517
|
+
option={blocks}
|
|
518
|
+
optionKey="name"
|
|
519
|
+
selected={ward}
|
|
520
|
+
select={setWard}
|
|
521
|
+
disabled={!assembly}
|
|
522
|
+
t={t}
|
|
523
|
+
/>
|
|
416
524
|
</div>
|
|
417
525
|
</div>
|
|
418
|
-
|
|
526
|
+
)}
|
|
527
|
+
|
|
528
|
+
<hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
|
|
529
|
+
|
|
530
|
+
{/* ── Door Photo ── */}
|
|
531
|
+
<SectionHead
|
|
532
|
+
icon={<CameraIcon size={16} />}
|
|
533
|
+
label={t("EKYC_DOOR_PHOTO_HEADER") || "Door photo with GPS stamp"}
|
|
534
|
+
/>
|
|
419
535
|
|
|
420
|
-
<
|
|
421
|
-
{t("EKYC_DOOR_PHOTO_HEADER") || "Door Photo with GPS Stamp"}
|
|
422
|
-
</CardHeader>
|
|
423
|
-
<div style={{ color: "#667085", fontSize: "14px", marginBottom: "16px" }}>
|
|
536
|
+
<div style={{ fontSize: "12px", color: "#667085", marginBottom: "12px" }}>
|
|
424
537
|
{t("EKYC_REQUIRED_FOR_VERIFICATION") || "Required for verification"}
|
|
425
538
|
</div>
|
|
426
539
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
540
|
+
{/* Warning banner */}
|
|
541
|
+
<div style={{
|
|
542
|
+
backgroundColor: "#FFFAEB",
|
|
543
|
+
border: "0.5px solid #FEDF89",
|
|
544
|
+
borderRadius: "8px",
|
|
545
|
+
padding: "12px 14px",
|
|
546
|
+
display: "flex",
|
|
547
|
+
alignItems: "flex-start",
|
|
548
|
+
gap: "10px",
|
|
549
|
+
marginBottom: "16px",
|
|
550
|
+
}}>
|
|
551
|
+
<div style={{ flexShrink: 0, marginTop: "1px" }}>
|
|
552
|
+
<InfoBannerIcon fill="#B54708" />
|
|
553
|
+
</div>
|
|
440
554
|
<div>
|
|
441
|
-
<div style={{ fontWeight: "
|
|
442
|
-
|
|
555
|
+
<div style={{ fontWeight: "600", color: "#B54708", fontSize: "13px", marginBottom: "2px" }}>
|
|
556
|
+
{t("EKYC_IMPORTANT") || "Important"}
|
|
557
|
+
</div>
|
|
558
|
+
<div style={{ fontSize: "12px", color: "#92400E" }}>
|
|
443
559
|
{t("EKYC_CAPTURE_LIVE_CAMERA") || "Capture with live camera for GPS metadata"}
|
|
444
560
|
</div>
|
|
445
561
|
</div>
|
|
446
562
|
</div>
|
|
447
563
|
|
|
564
|
+
{/* Drop zone */}
|
|
565
|
+
<input
|
|
566
|
+
type="file"
|
|
567
|
+
ref={fileInputRef}
|
|
568
|
+
onChange={handleCapture}
|
|
569
|
+
accept="image/*"
|
|
570
|
+
style={{ display: "none" }}
|
|
571
|
+
/>
|
|
448
572
|
<div
|
|
573
|
+
onClick={!doorPhoto ? () => fileInputRef.current.click() : undefined}
|
|
574
|
+
onMouseOver={(e) => { if (!doorPhoto) e.currentTarget.style.borderColor = "#185FA5"; }}
|
|
575
|
+
onMouseOut={(e) => { if (!doorPhoto) e.currentTarget.style.borderColor = "#D0D5DD"; }}
|
|
449
576
|
style={{
|
|
450
|
-
border: "
|
|
451
|
-
borderRadius: "
|
|
452
|
-
|
|
453
|
-
textAlign: "center",
|
|
454
|
-
cursor: "pointer",
|
|
455
|
-
position: "relative",
|
|
456
|
-
overflow: "hidden",
|
|
457
|
-
minHeight: "180px",
|
|
577
|
+
border: "1.5px dashed #D0D5DD",
|
|
578
|
+
borderRadius: "10px",
|
|
579
|
+
minHeight: "160px",
|
|
458
580
|
display: "flex",
|
|
459
581
|
flexDirection: "column",
|
|
460
582
|
alignItems: "center",
|
|
461
583
|
justifyContent: "center",
|
|
462
584
|
backgroundColor: "#F9FAFB",
|
|
463
|
-
|
|
464
|
-
|
|
585
|
+
cursor: doorPhoto ? "default" : "pointer",
|
|
586
|
+
overflow: "hidden",
|
|
587
|
+
transition: "border-color 0.15s",
|
|
588
|
+
position: "relative",
|
|
589
|
+
padding: doorPhoto ? "0" : "32px 24px",
|
|
465
590
|
}}
|
|
466
|
-
onClick={!doorPhoto ? openGallery : undefined}
|
|
467
|
-
onMouseOver={(e) => (!doorPhoto ? (e.currentTarget.style.borderColor = "#0068faff") : null)}
|
|
468
|
-
onMouseOut={(e) => (!doorPhoto ? (e.currentTarget.style.borderColor = "#D0D5DD") : null)}
|
|
469
591
|
>
|
|
470
|
-
<input type="file" ref={fileInputRef} onChange={handleCapture} accept="image/*" style={{ display: "none" }} />
|
|
471
592
|
{!doorPhoto ? (
|
|
472
593
|
<>
|
|
473
|
-
<div
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
margin: "0 auto 16px",
|
|
483
|
-
boxShadow: "0px 1px 3px rgba(16, 24, 40, 0.1)",
|
|
484
|
-
}}
|
|
485
|
-
>
|
|
486
|
-
<CameraIcon />
|
|
594
|
+
<div style={{
|
|
595
|
+
width: "52px", height: "52px", borderRadius: "50%",
|
|
596
|
+
background: "#E6F1FB", display: "flex",
|
|
597
|
+
alignItems: "center", justifyContent: "center", marginBottom: "12px",
|
|
598
|
+
}}>
|
|
599
|
+
<CameraIcon size={26} />
|
|
600
|
+
</div>
|
|
601
|
+
<div style={{ fontWeight: "600", fontSize: "14px", color: "#101828", marginBottom: "4px" }}>
|
|
602
|
+
{t("EKYC_TAP_TO_CAPTURE") || "Tap to capture"}
|
|
487
603
|
</div>
|
|
488
|
-
<div style={{
|
|
489
|
-
{t("
|
|
604
|
+
<div style={{ fontSize: "12px", color: "#667085" }}>
|
|
605
|
+
{t("EKYC_CAPTURE_DOOR_IMAGE") || "Capture door image"}
|
|
490
606
|
</div>
|
|
491
|
-
<div style={{ color: "#667085", fontSize: "14px" }}>{t("EKYC_CAPTURE_DOOR_IMAGE") || "Capture Door Image"}</div>
|
|
492
607
|
</>
|
|
493
608
|
) : (
|
|
494
|
-
|
|
609
|
+
<>
|
|
495
610
|
<img
|
|
496
611
|
src={doorPhoto}
|
|
497
612
|
alt="Door"
|
|
498
|
-
style={{ width: "100%", maxHeight: "
|
|
613
|
+
style={{ width: "100%", maxHeight: "280px", objectFit: "cover", display: "block" }}
|
|
499
614
|
/>
|
|
500
|
-
<
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
cursor: "pointer",
|
|
514
|
-
}}
|
|
515
|
-
>
|
|
516
|
-
<RemoveableTag text="" onClick={() => {}} extraStyles={{ tagStyles: { margin: 0, padding: 0 } }} />
|
|
517
|
-
</button>
|
|
518
|
-
</div>
|
|
519
|
-
</div>
|
|
615
|
+
<button
|
|
616
|
+
onClick={(e) => { e.stopPropagation(); removePhoto(); }}
|
|
617
|
+
style={{
|
|
618
|
+
position: "absolute", top: "10px", right: "10px",
|
|
619
|
+
background: "#fff", border: "0.5px solid #EAECF0",
|
|
620
|
+
borderRadius: "7px", padding: "6px 10px",
|
|
621
|
+
display: "flex", alignItems: "center", gap: "5px",
|
|
622
|
+
cursor: "pointer", fontSize: "12px", color: "#D92D20", fontWeight: "500",
|
|
623
|
+
}}
|
|
624
|
+
>
|
|
625
|
+
<TrashIcon size={13} /> {t("EKYC_REMOVE") || "Remove"}
|
|
626
|
+
</button>
|
|
627
|
+
</>
|
|
520
628
|
)}
|
|
521
629
|
</div>
|
|
522
630
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
631
|
+
{/* Submit */}
|
|
632
|
+
{isSection ? (
|
|
633
|
+
<div style={{ marginTop: "24px" }}>
|
|
634
|
+
<SubmitBar
|
|
635
|
+
label={t("EKYC_COMPLETE_VERIFICATION_AND_PROCEED") || "Complete & Proceed"}
|
|
636
|
+
onSubmit={handleCompleteVerification}
|
|
637
|
+
/>
|
|
638
|
+
</div>
|
|
639
|
+
) : (
|
|
640
|
+
<ActionBar>
|
|
641
|
+
<SubmitBar
|
|
642
|
+
label={t("EKYC_COMPLETE_VERIFICATION") || "Complete Verification"}
|
|
643
|
+
onSubmit={handleCompleteVerification}
|
|
644
|
+
/>
|
|
645
|
+
</ActionBar>
|
|
646
|
+
)}
|
|
647
|
+
|
|
648
|
+
{/* Secure notice */}
|
|
649
|
+
<div style={{
|
|
650
|
+
display: "flex", alignItems: "center", justifyContent: "center",
|
|
651
|
+
gap: "5px", marginTop: "16px",
|
|
652
|
+
fontSize: "11px", color: "#98A2B3",
|
|
653
|
+
}}>
|
|
654
|
+
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
655
|
+
<rect x="3" y="11" width="18" height="11" rx="2" />
|
|
656
|
+
<path d="M7 11V7a5 5 0 0 1 10 0v4" />
|
|
657
|
+
</svg>
|
|
658
|
+
{t("EKYC_SECURE_DATA_NOTICE") || "Your data is encrypted and secure"}
|
|
659
|
+
</div>
|
|
533
660
|
</div>
|
|
534
661
|
);
|
|
535
662
|
|
|
536
|
-
|
|
663
|
+
// ── When rendered as inline section inside AadhaarVerification ──
|
|
664
|
+
if (isSection) {
|
|
665
|
+
return (
|
|
666
|
+
<Fragment>
|
|
667
|
+
<hr style={{ margin: "32px 0", border: 0, borderTop: "2px solid #EAECF0" }} />
|
|
668
|
+
{renderContent()}
|
|
669
|
+
</Fragment>
|
|
670
|
+
);
|
|
671
|
+
}
|
|
537
672
|
|
|
673
|
+
// ── When rendered as a standalone page ──
|
|
538
674
|
return (
|
|
539
675
|
<div className="inbox-container">
|
|
540
676
|
<style>{`
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
677
|
+
@keyframes spin { to { transform: rotate(360deg); } }
|
|
678
|
+
@keyframes fadeSlideIn { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:translateY(0); } }
|
|
679
|
+
`}</style>
|
|
544
680
|
|
|
681
|
+
{/* Sidebar */}
|
|
545
682
|
<div className="filters-container">
|
|
546
|
-
{
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
<HomeIcon style={{ width: "24px", height: "24px" }} />
|
|
683
|
+
<Card style={{ display: "flex", alignItems: "center", padding: "12px 16px", marginBottom: "12px", borderRadius: "8px" }}>
|
|
684
|
+
<div style={{ color: "#185FA5", marginRight: "10px", display: "flex" }}>
|
|
685
|
+
<HomeIcon style={{ width: "20px", height: "20px" }} />
|
|
686
|
+
</div>
|
|
687
|
+
<div style={{ fontWeight: "600", fontSize: "15px", color: "#0B0C0C" }}>
|
|
688
|
+
{t("EKYC_PROCESS") || "eKYC Process"}
|
|
553
689
|
</div>
|
|
554
|
-
<div style={{ fontWeight: "700", fontSize: "18px", color: "#0B0C0C" }}>{t("EKYC_PROCESS")}</div>
|
|
555
690
|
</Card>
|
|
556
691
|
|
|
557
|
-
{
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
692
|
+
<div style={{ background: "#fff", padding: "16px 14px", borderRadius: "8px", border: "1px solid #EAECF0" }}>
|
|
693
|
+
{[
|
|
694
|
+
{ label: t("EKYC_STEP_AADHAAR") || "Aadhaar", done: true, active: false },
|
|
695
|
+
{ label: t("EKYC_STEP_ADDRESS") || "Address", done: false, active: true },
|
|
696
|
+
{ label: t("EKYC_STEP_PROPERTY") || "Property", done: false, active: false },
|
|
697
|
+
{ label: t("EKYC_STEP_REVIEW") || "Review", done: false, active: false },
|
|
698
|
+
].map((step, i) => (
|
|
699
|
+
<div key={i} style={{ display: "flex", gap: "10px", alignItems: "flex-start", position: "relative", paddingBottom: i < 3 ? "18px" : 0 }}>
|
|
700
|
+
{i < 3 && (
|
|
701
|
+
<div style={{ position: "absolute", left: "10px", top: "22px", width: "1px", height: "calc(100% - 10px)", background: "#EAECF0" }} />
|
|
702
|
+
)}
|
|
703
|
+
<div style={{
|
|
704
|
+
width: "20px", height: "20px", borderRadius: "50%", flexShrink: 0, marginTop: "1px",
|
|
705
|
+
border: step.done ? "none" : step.active ? "1.5px solid #185FA5" : "1.5px solid #D0D5DD",
|
|
706
|
+
background: step.done ? "#0F6E56" : step.active ? "#E6F1FB" : "#fff",
|
|
707
|
+
display: "flex", alignItems: "center", justifyContent: "center",
|
|
708
|
+
fontSize: "10px", fontWeight: "500",
|
|
709
|
+
color: step.done ? "#fff" : step.active ? "#185FA5" : "#98A2B3",
|
|
710
|
+
}}>
|
|
711
|
+
{step.done ? <CheckIcon size={11} color="#fff" /> : i + 1}
|
|
712
|
+
</div>
|
|
713
|
+
<div style={{
|
|
714
|
+
fontSize: "12px", paddingTop: "2px",
|
|
715
|
+
color: step.done ? "#0F6E56" : step.active ? "#0B0C0C" : "#667085",
|
|
716
|
+
fontWeight: step.done || step.active ? "600" : "400",
|
|
717
|
+
}}>
|
|
718
|
+
{step.label}
|
|
719
|
+
</div>
|
|
720
|
+
</div>
|
|
721
|
+
))}
|
|
573
722
|
</div>
|
|
574
723
|
</div>
|
|
575
724
|
|
|
725
|
+
{/* Main */}
|
|
576
726
|
<div style={{ flex: 1, marginLeft: "16px" }}>
|
|
577
727
|
<Card>
|
|
578
|
-
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "
|
|
579
|
-
<
|
|
580
|
-
|
|
581
|
-
|
|
728
|
+
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }}>
|
|
729
|
+
<CardHeader style={{ margin: 0, fontSize: "18px" }}>
|
|
730
|
+
{t("EKYC_ADDRESS_DETAILS_HEADER") || "Address Details"}
|
|
731
|
+
</CardHeader>
|
|
732
|
+
<div style={{
|
|
733
|
+
background: "#F9FAFB", border: "0.5px solid #EAECF0",
|
|
734
|
+
borderRadius: "20px", padding: "4px 14px",
|
|
735
|
+
fontSize: "12px", color: "#667085",
|
|
736
|
+
}}>
|
|
737
|
+
{t("EKYC_K_NUMBER") || "K Number"}:{" "}
|
|
738
|
+
<span style={{ color: "#0B0C0C", fontWeight: "600" }}>{flowState?.kNumber}</span>
|
|
582
739
|
</div>
|
|
583
740
|
</div>
|
|
584
741
|
{renderContent()}
|
|
@@ -588,4 +745,4 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
|
|
|
588
745
|
);
|
|
589
746
|
};
|
|
590
747
|
|
|
591
|
-
export default AddressDetails;
|
|
748
|
+
export default AddressDetails;
|