@djb25/digit-ui-module-ekyc 1.0.2 → 1.0.4

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