@djb25/digit-ui-module-ekyc 1.0.8 → 1.0.9

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,773 +1,548 @@
1
- import React, { useState, useRef, Fragment, useEffect } from "react";
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
- Dropdown,
18
- Loader,
19
- UploadFile,
20
- Toast,
21
- } from "@djb25/digit-ui-react-components";
1
+ // import React, { useState, useRef, Fragment, useEffect } from "react";
2
+ // import {
3
+ // Card,
4
+ // CardLabel,
5
+ // TextInput,
6
+ // SubmitBar,
7
+ // CardHeader,
8
+ // RadioButtons,
9
+ // ActionBar,
10
+ // Dropdown,
11
+ // Loader,
12
+ // UploadFile,
13
+ // Toast,
14
+ // FormStep,
15
+ // } from "@djb25/digit-ui-react-components";
16
+ // import { useTranslation } from "react-i18next";
17
+ // import { useHistory, useLocation } from "react-router-dom";
18
+ // import { getSavedData } from "../../utils";
19
+
20
+ // const AddressDetails = ({ config, onSelect, formData, t: tProps }) => {
21
+ // const { t } = useTranslation();
22
+ // const history = useHistory();
23
+ // const location = useLocation();
24
+
25
+ // const flowState = location.state || {};
26
+ // const { isEditing, kNumber } = flowState;
27
+
28
+ // // Robust data extraction from formData (which includes reviewData and edits from EKYCForm)
29
+ // const activeEdits = formData || {};
30
+ // const rawReviewData = formData?.reviewData || formData?.connectionDetails || {};
31
+ // const reviewWrapper = rawReviewData?.applicationReview || rawReviewData;
32
+ // const applicationData = (Array.isArray(reviewWrapper) ? reviewWrapper[0] : reviewWrapper) || {};
33
+ // const apiData = applicationData?.newData || applicationData;
34
+ // const apiAddr = apiData?.addressDetails || apiData || {};
35
+
36
+ // const addrData = activeEdits?.addressDetails || {};
37
+
38
+ // const [addressType, setAddressType] = useState(addrData.addressType || { code: "AADHAAR", name: "EKYC_AADHAAR_ADDRESS" });
39
+ // const [correctAddress, setCorrectAddress] = useState(addrData.correctAddress || { code: "NO", name: "CORE_COMMON_NO" });
40
+ // const [fullAddress, setFullAddress] = useState(addrData.fullAddress || apiAddr.addressRaw || apiAddr.fullAddress || "");
41
+ // const [flatHouseNumber, setFlatHouseNumber] = useState(addrData.flatHouseNumber || addrData.flatNo || apiAddr.flatHouseNumber || apiAddr.flatNo || "");
42
+ // const [buildingTower, setBuildingTower] = useState(addrData.buildingTower || addrData.building || apiAddr.buildingTower || apiAddr.building || "");
43
+ // const [landmark, setLandmark] = useState(addrData.landmark || apiAddr.landmark || "");
44
+ // const [pinCode, setPinCode] = useState(addrData.pinCode || addrData.pincode || apiAddr.pinCode || apiAddr.pincode || "");
45
+ // const [doorPhoto, setDoorPhoto] = useState(addrData.doorPhoto || null);
46
+ // const [doorPhotoFileStoreId, setDoorPhotoFileStoreId] = useState(addrData.doorPhotoFilestoreId || addrData.doorPhotoFileStoreId || apiAddr.doorPhotoFilestoreId || null);
47
+
48
+ // const [gpsValid, setGpsValid] = useState(addrData.gpsValid !== undefined ? addrData.gpsValid : (apiAddr.gpsValid !== undefined ? apiAddr.gpsValid : true));
49
+ // const [latitude, setLatitude] = useState(addrData.latitude || apiAddr.latitude || "");
50
+ // const [longitude, setLongitude] = useState(addrData.longitude || apiAddr.longitude || "");
51
+ // const [mobileNo, setMobileNo] = useState(addrData.mobileNo || apiAddr.mobileNo || "");
52
+ // const [whatsappNo, setWhatsappNo] = useState(addrData.whatsappNo || apiAddr.whatsappNo || "");
53
+ // const [email, setEmail] = useState(addrData.email || apiAddr.email || "");
54
+ // const [noOfPerson, setNoOfPerson] = useState(addrData.noOfPerson || apiAddr.noOfPerson || apiAddr.noOfPersons || "");
55
+ // const [knumber, setKnumber] = useState(addrData.knumber || apiAddr.knumber || apiAddr.kno || kNumber || "");
56
+
57
+ // const [toast, setToast] = useState(null);
58
+
59
+ // const tenantId = Digit.ULBService.getCurrentTenantId();
60
+ // const { data: mdmsData, isLoading: isMdmsLoading } = Digit.Hooks.useCommonMDMS(tenantId, "egov-location", ["TenantBoundary"]);
61
+ // const assemblies = mdmsData?.MdmsRes?.["egov-location"]?.TenantBoundary?.[0]?.boundary?.children || [];
62
+ // const [assembly, setAssembly] = useState(addrData.assemblyData || (apiAddr.assembly ? { name: apiAddr.assembly } : null));
63
+ // const [ward, setWard] = useState(addrData.wardData || (apiAddr.ward ? { name: apiAddr.ward } : null));
64
+
65
+ // const getUpdatedData = () => ({
66
+ // addressType,
67
+ // correctAddress,
68
+ // fullAddress,
69
+ // flatHouseNumber,
70
+ // buildingTower,
71
+ // landmark,
72
+ // pinCode,
73
+ // doorPhoto,
74
+ // doorPhotoFilestoreId: doorPhotoFileStoreId,
75
+ // assembly: assembly?.name,
76
+ // ward: ward?.name,
77
+ // assemblyData: assembly,
78
+ // wardData: ward,
79
+ // gpsValid,
80
+ // latitude,
81
+ // longitude,
82
+ // mobileNo,
83
+ // whatsappNo,
84
+ // email,
85
+ // noOfPerson,
86
+ // knumber
87
+ // });
88
+
89
+ // const selectphoto = async (e) => {
90
+ // const file = e.target.files[0];
91
+ // if (file) {
92
+ // if (file.size >= 2000000) {
93
+ // setToast({ type: "error", message: t("EKYC_MAXIMUM_UPLOAD_SIZE_EXCEEDED") });
94
+ // return;
95
+ // }
96
+ // try {
97
+ // const res = await Digit.UploadServices.Filestorage("EKYC", file, tenantId);
98
+ // if (res?.data?.files?.[0]?.fileStoreId) {
99
+ // const fileStoreId = res.data.files[0].fileStoreId;
100
+ // setDoorPhotoFileStoreId(fileStoreId);
101
+ // const reader = new FileReader();
102
+ // reader.onloadend = () => {
103
+ // setDoorPhoto(reader.result);
104
+ // if (onSelect) {
105
+ // onSelect(config.key, { ...getUpdatedData(), doorPhoto: reader.result, doorPhotoFilestoreId: fileStoreId });
106
+ // }
107
+ // };
108
+ // reader.readAsDataURL(file);
109
+ // setToast({ type: "success", message: t("EKYC_UPLOAD_SUCCESS") });
110
+ // }
111
+ // } catch (err) {
112
+ // setToast({ type: "error", message: t("EKYC_FILE_UPLOAD_ERROR") });
113
+ // }
114
+ // }
115
+ // };
116
+
117
+ // const removePhoto = () => {
118
+ // setDoorPhoto(null);
119
+ // setDoorPhotoFileStoreId(null);
120
+ // if (onSelect) {
121
+ // onSelect(config.key, { ...getUpdatedData(), doorPhoto: null, doorPhotoFilestoreId: null });
122
+ // }
123
+ // };
124
+
125
+ // const onStepSelect = () => {
126
+ // const updatedData = getUpdatedData();
127
+ // if (onSelect) {
128
+ // onSelect(config.key, updatedData);
129
+ // } else {
130
+ // if (isEditing) {
131
+ // history.push("/digit-ui/employee/ekyc/review", { ...location.state, edits: { ...edits, addressDetails: updatedData } });
132
+ // } else {
133
+ // history.push("/digit-ui/employee/ekyc/property-info", {
134
+ // ...location.state,
135
+ // edits: { ...edits, addressDetails: updatedData }
136
+ // });
137
+ // }
138
+ // }
139
+ // };
140
+
141
+ // const handleUpdateAndReturn = () => {
142
+ // history.push("/digit-ui/employee/ekyc/review", { ...location.state, edits: { ...edits, addressDetails: getUpdatedData() } });
143
+ // };
144
+
145
+ // const addressOptions = [
146
+ // { code: "AADHAAR", name: "EKYC_AADHAAR_ADDRESS" },
147
+ // { code: "CURRENT", name: "EKYC_CURRENT_ADDRESS" },
148
+ // ];
149
+
150
+ // const yesNoOptions = [
151
+ // { code: "YES", name: "CORE_COMMON_YES" },
152
+ // { code: "NO", name: "CORE_COMMON_NO" },
153
+ // ];
154
+
155
+ // if (isMdmsLoading) return <Loader />;
156
+
157
+ // return (
158
+ // <Fragment>
159
+ // <FormStep t={t} onSelect={onStepSelect} config={config || {}} label={t(config?.texts?.submitBarLabel) || (isEditing ? t("EKYC_UPDATE_AND_RETURN") : t("ES_COMMON_CONTINUE"))}>
160
+ // <CardLabel>{t("EKYC_ADDRESS_TYPE")}</CardLabel>
161
+ // <RadioButtons
162
+ // options={addressOptions}
163
+ // optionsKey="name"
164
+ // selectedOption={addressType}
165
+ // onSelect={setAddressType}
166
+ // />
167
+
168
+ // <CardLabel>{t("EKYC_IS_ADDRESS_CORRECT")}</CardLabel>
169
+ // <RadioButtons
170
+ // options={yesNoOptions}
171
+ // optionsKey="name"
172
+ // selectedOption={correctAddress}
173
+ // onSelect={setCorrectAddress}
174
+ // />
175
+
176
+ // {correctAddress?.code === "NO" && (
177
+ // <Fragment>
178
+ // <CardLabel>{t("EKYC_FULL_ADDRESS")}</CardLabel>
179
+ // <TextInput
180
+ // id="fullAddress"
181
+ // name="fullAddress"
182
+ // value={fullAddress}
183
+ // onChange={(e) => setFullAddress(e.target.value)}
184
+ // placeholder={t("EKYC_ENTER_FULL_ADDRESS")}
185
+ // />
186
+
187
+ // <CardLabel>{t("EKYC_FLAT_HOUSE_NO")}</CardLabel>
188
+ // <TextInput
189
+ // id="flatHouseNumber"
190
+ // name="flatHouseNumber"
191
+ // value={flatHouseNumber}
192
+ // onChange={(e) => setFlatHouseNumber(e.target.value)}
193
+ // placeholder={t("EKYC_ENTER_FLAT_HOUSE_NO")}
194
+ // />
195
+
196
+ // <CardLabel>{t("EKYC_BUILDING_TOWER")}</CardLabel>
197
+ // <TextInput
198
+ // id="buildingTower"
199
+ // name="buildingTower"
200
+ // value={buildingTower}
201
+ // onChange={(e) => setBuildingTower(e.target.value)}
202
+ // placeholder={t("EKYC_ENTER_BUILDING_TOWER")}
203
+ // />
204
+
205
+ // <CardLabel>{t("EKYC_LANDMARK")}</CardLabel>
206
+ // <TextInput
207
+ // id="landmark"
208
+ // name="landmark"
209
+ // value={landmark}
210
+ // onChange={(e) => setLandmark(e.target.value)}
211
+ // placeholder={t("EKYC_ENTER_LANDMARK")}
212
+ // />
213
+
214
+ // <CardLabel>{t("EKYC_PINCODE")}</CardLabel>
215
+ // <TextInput
216
+ // id="pinCode"
217
+ // name="pinCode"
218
+ // value={pinCode}
219
+ // onChange={(e) => setPinCode(e.target.value)}
220
+ // placeholder={t("EKYC_ENTER_PINCODE")}
221
+ // />
222
+ // </Fragment>
223
+ // )}
224
+
225
+ // <CardLabel>{t("EKYC_ASSEMBLY_WARD")}</CardLabel>
226
+ // <Dropdown
227
+ // option={assemblies}
228
+ // optionKey="name"
229
+ // selected={assembly}
230
+ // select={setAssembly}
231
+ // t={t}
232
+ // />
233
+
234
+ // {assembly && (
235
+ // <Fragment>
236
+ // <CardLabel>{t("EKYC_WARD")}</CardLabel>
237
+ // <Dropdown
238
+ // option={assembly.children || []}
239
+ // optionKey="name"
240
+ // selected={ward}
241
+ // select={setWard}
242
+ // t={t}
243
+ // />
244
+ // </Fragment>
245
+ // )}
246
+
247
+ // <CardLabel>{t("EKYC_GPS_VALID")}</CardLabel>
248
+ // <RadioButtons
249
+ // options={[
250
+ // { code: true, name: "CORE_COMMON_YES" },
251
+ // { code: false, name: "CORE_COMMON_NO" },
252
+ // ]}
253
+ // optionsKey="name"
254
+ // selectedOption={gpsValid ? { code: true, name: "CORE_COMMON_YES" } : { code: false, name: "CORE_COMMON_NO" }}
255
+ // onSelect={(val) => setGpsValid(val.code)}
256
+ // />
257
+
258
+ // <CardLabel>{t("EKYC_LATITUDE")}</CardLabel>
259
+ // <TextInput
260
+ // id="latitude"
261
+ // name="latitude"
262
+ // value={latitude}
263
+ // onChange={(e) => setLatitude(e.target.value)}
264
+ // placeholder={t("EKYC_ENTER_LATITUDE")}
265
+ // />
266
+
267
+ // <CardLabel>{t("EKYC_LONGITUDE")}</CardLabel>
268
+ // <TextInput
269
+ // id="longitude"
270
+ // name="longitude"
271
+ // value={longitude}
272
+ // onChange={(e) => setLongitude(e.target.value)}
273
+ // placeholder={t("EKYC_ENTER_LONGITUDE")}
274
+ // />
275
+
276
+ // <CardLabel>{t("EKYC_MOBILE_NO")}</CardLabel>
277
+ // <TextInput
278
+ // id="mobileNo"
279
+ // name="mobileNo"
280
+ // value={mobileNo}
281
+ // onChange={(e) => setMobileNo(e.target.value)}
282
+ // placeholder={t("EKYC_ENTER_MOBILE_NO")}
283
+ // />
284
+
285
+ // <CardLabel>{t("EKYC_WHATSAPP_NO")}</CardLabel>
286
+ // <TextInput
287
+ // id="whatsappNo"
288
+ // name="whatsappNo"
289
+ // value={whatsappNo}
290
+ // onChange={(e) => setWhatsappNo(e.target.value)}
291
+ // placeholder={t("EKYC_ENTER_WHATSAPP_NO")}
292
+ // />
293
+
294
+ // <CardLabel>{t("EKYC_EMAIL")}</CardLabel>
295
+ // <TextInput
296
+ // id="email"
297
+ // name="email"
298
+ // value={email}
299
+ // onChange={(e) => setEmail(e.target.value)}
300
+ // placeholder={t("EKYC_ENTER_EMAIL")}
301
+ // />
302
+
303
+ // <CardLabel>{t("EKYC_NO_OF_PERSONS")}</CardLabel>
304
+ // <TextInput
305
+ // id="noOfPerson"
306
+ // name="noOfPerson"
307
+ // value={noOfPerson}
308
+ // onChange={(e) => setNoOfPerson(e.target.value)}
309
+ // placeholder={t("EKYC_ENTER_NO_OF_PERSONS")}
310
+ // />
311
+
312
+ // <CardLabel>{t("EKYC_K_NUMBER")}</CardLabel>
313
+ // <TextInput
314
+ // id="knumber"
315
+ // name="knumber"
316
+ // value={knumber}
317
+ // onChange={(e) => setKnumber(e.target.value)}
318
+ // placeholder={t("EKYC_ENTER_K_NUMBER")}
319
+ // />
320
+
321
+ // <CardLabel>{t("EKYC_DOOR_PHOTO")}</CardLabel>
322
+ // <UploadFile
323
+ // onUpload={selectphoto}
324
+ // onDelete={removePhoto}
325
+ // message={doorPhotoFileStoreId ? t("EKYC_FILE_UPLOADED") : t("EKYC_NO_FILE_SELECTED")}
326
+ // />
327
+ // {doorPhoto && <img src={doorPhoto} style={{ width: "100%", marginTop: "10px", borderRadius: "8px" }} />}
328
+
329
+ // {toast && <Toast label={toast.message} error={toast.type === "error"} onClose={() => setToast(null)} />}
330
+ // </FormStep>
331
+ // {isEditing && !onSelect && (
332
+ // // <ActionBar style={{ position: "static", marginTop: "20px" }}>
333
+ // <SubmitBar label={t("EKYC_UPDATE_AND_RETURN")} onSubmit={handleUpdateAndReturn} />
334
+ // // </ActionBar>
335
+ // )}
336
+ // </Fragment>
337
+ // );
338
+ // };
339
+
340
+ // export default AddressDetails;
341
+
342
+ import React, { useState, useEffect, Fragment } from "react";
343
+ import { CardLabel, TextInput, Dropdown, UploadFile, Toast, FormStep, Loader } from "@djb25/digit-ui-react-components";
22
344
  import { useTranslation } from "react-i18next";
23
- import { useHistory, useLocation } from "react-router-dom";
24
- import { getPayloadDiff, getSavedData } from "../../utils";
25
-
26
- // ─── Icons ────────────────────────────────────────────────────────────────────
27
-
28
- const FlagIcon = ({ size = 20 }) => (
29
- <svg width={size} height={size} viewBox="0 0 24 24" fill="none">
30
- <path d="M14.4 6L13.6 4H5V21H7V14H12.6L13.4 16H20V6H14.4Z" fill="#0F6E56" />
31
- </svg>
32
- );
33
-
34
- const IdCardIcon = ({ size = 20 }) => (
35
- <svg width={size} height={size} viewBox="0 0 24 24" fill="none">
36
- <path
37
- 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"
38
- fill="#185FA5"
39
- />
40
- </svg>
41
- );
42
-
43
- const CameraIcon = ({ size = 28 }) => (
44
- <svg width={size} height={size} viewBox="0 0 24 24" fill="none">
45
- <path
46
- 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"
47
- fill="#185FA5"
48
- />
49
- </svg>
50
- );
51
-
52
- const TargetIcon = ({ size = 20 }) => (
53
- <svg width={size} height={size} viewBox="0 0 24 24" fill="none">
54
- <path
55
- 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"
56
- fill="#185FA5"
57
- />
58
- </svg>
59
- );
60
-
61
- const PincodeIcon = ({ size = 18 }) => (
62
- <svg width={size} height={size} viewBox="0 0 24 24" fill="none">
63
- <path
64
- 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"
65
- fill="currentColor"
66
- />
67
- </svg>
68
- );
69
-
70
- const TrashIcon = ({ size = 16 }) => (
71
- <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="#D92D20" strokeWidth="2" strokeLinecap="round">
72
- <polyline points="3 6 5 6 21 6" />
73
- <path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
74
- <path d="M10 11v6M14 11v6" />
75
- <path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2" />
76
- </svg>
77
- );
78
-
79
- const CheckIcon = ({ size = 11, color = "#fff" }) => (
80
- <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="3" strokeLinecap="round">
81
- <polyline points="20 6 9 17 4 12" />
82
- </svg>
83
- );
84
-
85
- // ─── Reusable: Icon-prefixed input ────────────────────────────────────────────
86
-
87
- const IconInput = ({ icon, topAligned = false, inputStyle = {}, ...props }) => (
88
- <div style={{ position: "relative", width: "100%" }}>
89
- <div style={{
90
- position: "absolute",
91
- left: "10px",
92
- ...(topAligned ? { top: "14px" } : { top: "50%", transform: "translateY(-50%)" }),
93
- zIndex: 1,
94
- opacity: 0.45,
95
- display: "flex",
96
- pointerEvents: "none",
97
- }}>
98
- {icon}
99
- </div>
100
- <TextInput
101
- textInputStyle={{ paddingLeft: "36px", paddingRight: "12px", ...inputStyle }}
102
- {...props}
103
- />
104
- </div>
105
- );
106
-
107
- // ─── Reusable: Section heading with inline rule ───────────────────────────────
108
-
109
- const SectionHead = ({ icon, label }) => (
110
- <div style={{
111
- display: "flex", alignItems: "center", gap: "8px",
112
- marginBottom: "16px", marginTop: "4px",
113
- }}>
114
- <div style={{ opacity: 0.5, display: "flex" }}>{icon}</div>
115
- <span style={{ fontSize: "15px", fontWeight: "600", color: "#0B0C0C", whiteSpace: "nowrap" }}>
116
- {label}
117
- </span>
118
- <div style={{ flex: 1, height: "1px", background: "#EAECF0" }} />
119
- </div>
120
- );
121
-
122
- // ─── Reusable: Admin info card ────────────────────────────────────────────────
123
-
124
- const AdminCard = ({ bgColor, iconBg, icon, labelColor, label, value }) => (
125
- <div style={{
126
- backgroundColor: bgColor,
127
- padding: "14px 16px",
128
- borderRadius: "8px",
129
- display: "flex",
130
- alignItems: "center",
131
- gap: "14px",
132
- border: "0.5px solid #EAECF0",
133
- }}>
134
- <div style={{ backgroundColor: iconBg, padding: "8px", borderRadius: "8px", display: "flex", flexShrink: 0 }}>
135
- {icon}
136
- </div>
137
- <div>
138
- <div style={{ color: labelColor, fontSize: "10px", fontWeight: "600", textTransform: "uppercase", letterSpacing: "0.05em", marginBottom: "3px" }}>
139
- {label}
140
- </div>
141
- <div style={{ fontSize: "14px", fontWeight: "600", color: "#101828" }}>{value}</div>
142
- </div>
143
- </div>
144
- );
145
-
146
- // ─── Main Component ───────────────────────────────────────────────────────────
147
-
148
- const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
345
+
346
+ const AddressDetails = ({ config, onSelect }) => {
149
347
  const { t } = useTranslation();
150
- const history = useHistory();
151
- const location = useLocation();
152
-
153
- const flowState = parentState || location.state || {
154
- kNumber: "EKYC-1234567890",
155
- selectedOption: { code: "SELF", name: "EKYC_SELF" },
156
- connectionDetails: null,
157
- initialData: {},
158
- };
159
348
 
160
- const initialData = flowState.initialData || {};
161
-
162
- const addrDetails = flowState.connectionDetails?.addressDetails || {};
163
-
164
- const [addressType, setAddressType] = useState(() => getSavedData("EKYC_ADDRESS_TYPE", { code: "AADHAAR", name: "EKYC_AADHAAR_ADDRESS" }));
165
- const [correctAddress, setCorrectAddress] = useState(() => getSavedData("EKYC_ADDRESS_CORRECT", { code: "NO", name: "CORE_COMMON_NO" }));
166
- const [fullAddress, setFullAddress] = useState(() => sessionStorage.getItem("EKYC_FULL_ADDRESS") || initialData.fullAddress || "");
167
- const [flatNo, setFlatNo] = useState(() => sessionStorage.getItem("EKYC_FLAT_NO") || initialData.flatNo || "");
168
- const [building, setBuilding] = useState(() => sessionStorage.getItem("EKYC_BUILDING") || initialData.building || "");
169
- const [landmark, setLandmark] = useState(() => sessionStorage.getItem("EKYC_LANDMARK") || initialData.landmark || "");
170
- const [pincode, setPincode] = useState(() => sessionStorage.getItem("EKYC_PINCODE") || initialData.pincode || "");
171
- const [doorPhoto, setDoorPhoto] = useState(() => sessionStorage.getItem("EKYC_DOOR_PHOTO") || null);
172
- const [doorPhotoFileStoreId, setDoorPhotoFileStoreId] = useState(() => sessionStorage.getItem("EKYC_DOOR_PHOTO_FILESTORE_ID") || null);
173
-
174
- const [filephoto, setFilephoto] = useState(null);
175
- const [error, setError] = useState(null);
349
+ const tenantId = Digit.ULBService.getCurrentTenantId();
350
+
351
+ // 🔹 STATES
352
+ const [houseNo, setHouseNo] = useState("");
353
+ const [street, setStreet] = useState("");
354
+ const [locality, setLocality] = useState("");
355
+ const [landmark, setLandmark] = useState("");
356
+ const [subLocality, setSubLocality] = useState(null);
357
+
358
+ const [pinCode, setPinCode] = useState("");
359
+ const [assembly, setAssembly] = useState(null);
360
+ const [ward, setWard] = useState(null);
361
+ const [zone, setZone] = useState(null);
362
+
363
+ const [latitude, setLatitude] = useState("");
364
+ const [longitude, setLongitude] = useState("");
365
+
366
+ const [addressType, setAddressType] = useState(null);
367
+
368
+ const [doorPhoto, setDoorPhoto] = useState(null);
369
+ const [doorPhotoFileStoreId, setDoorPhotoFileStoreId] = useState(null);
370
+
176
371
  const [toast, setToast] = useState(null);
177
372
 
178
- // Sync address state to sessionStorage
179
- useEffect(() => {
180
- sessionStorage.setItem("EKYC_ADDRESS_TYPE", JSON.stringify(addressType));
181
- sessionStorage.setItem("EKYC_ADDRESS_CORRECT", JSON.stringify(correctAddress));
182
- sessionStorage.setItem("EKYC_FULL_ADDRESS", fullAddress);
183
- sessionStorage.setItem("EKYC_FLAT_NO", flatNo);
184
- sessionStorage.setItem("EKYC_BUILDING", building);
185
- sessionStorage.setItem("EKYC_LANDMARK", landmark);
186
- sessionStorage.setItem("EKYC_PINCODE", pincode);
187
- if (doorPhoto) sessionStorage.setItem("EKYC_DOOR_PHOTO", doorPhoto);
188
- if (doorPhotoFileStoreId) sessionStorage.setItem("EKYC_DOOR_PHOTO_FILESTORE_ID", doorPhotoFileStoreId);
189
- sessionStorage.setItem("EKYC_CURRENT_STEP", "ADDRESS");
190
- }, [addressType, correctAddress, fullAddress, flatNo, building, landmark, pincode, doorPhoto, doorPhotoFileStoreId]);
191
-
192
- const uploadFile = async (file, tenantId) => {
193
- if (!file) return null;
194
- const res = await Digit.UploadServices.Filestorage("EKYC", file, tenantId);
195
- return res?.data?.files?.[0]?.fileStoreId || null;
196
- };
373
+ // 🔹 MDMS DATA
374
+ const { data: mdmsData, isLoading } = Digit.Hooks.useCommonMDMS(tenantId, "egov-location", ["TenantBoundary"]);
375
+
376
+ const assemblies = mdmsData?.MdmsRes?.["egov-location"]?.TenantBoundary?.[0]?.boundary?.children || [];
197
377
 
378
+ // 🔹 AUTO GPS
198
379
  useEffect(() => {
199
- (async () => {
200
- setError(null);
201
- if (filephoto) {
202
- if (filephoto.size >= 2000000) {
203
- setError(t("EKYC_MAXIMUM_UPLOAD_SIZE_EXCEEDED"));
204
- setToast({ type: "error", message: t("EKYC_MAXIMUM_UPLOAD_SIZE_EXCEEDED") });
205
- } else {
206
- try {
207
- setToast({ type: "info", message: t("EKYC_UPLOADING") });
208
- const fsId = await uploadFile(filephoto, tenantId);
209
- if (fsId) {
210
- setDoorPhotoFileStoreId(fsId);
211
- const reader = new FileReader();
212
- reader.onloadend = () => setDoorPhoto(reader.result);
213
- reader.readAsDataURL(filephoto);
214
- setToast({ type: "success", message: t("EKYC_UPLOAD_SUCCESS") });
215
- } else {
216
- setError(t("EKYC_FILE_UPLOAD_ERROR"));
217
- setToast({ type: "error", message: t("EKYC_FILE_UPLOAD_ERROR") });
218
- }
219
- } catch (err) {
220
- setError(t("EKYC_FILE_UPLOAD_ERROR"));
221
- setToast({ type: "error", message: t("EKYC_FILE_UPLOAD_ERROR") });
222
- }
380
+ let isMounted = true;
381
+
382
+ if (navigator.geolocation) {
383
+ navigator.geolocation.getCurrentPosition(
384
+ (pos) => {
385
+ if (!isMounted) return;
386
+ setLatitude(pos.coords.latitude);
387
+ setLongitude(pos.coords.longitude);
388
+ },
389
+ () => {
390
+ if (!isMounted) return;
391
+ setToast({ type: "error", message: "GPS access denied" });
223
392
  }
224
- }
225
- })();
226
- }, [filephoto]);
227
- const [isLocationFetching, setIsLocationFetching] = useState(false);
228
- const fileInputRef = useRef(null);
229
-
230
- const tenantId = Digit.ULBService.getCurrentTenantId();
231
- const { data: mdmsData, isLoading: isMdmsLoading } = Digit.Hooks.useCommonMDMS(
232
- tenantId,
233
- "egov-location",
234
- ["TenantBoundary"]
235
- );
393
+ );
394
+ }
236
395
 
237
- const mdmsRes = mdmsData?.MdmsRes || mdmsData;
238
- const adminHierarchy = mdmsRes?.["egov-location"]?.TenantBoundary?.find(h => h.hierarchyType.code === "ADMIN")
239
- || mdmsRes?.["egov-location"]?.TenantBoundary?.[0];
396
+ return () => {
397
+ isMounted = false;
398
+ };
399
+ }, []);
240
400
 
241
- const rootBoundary = adminHierarchy?.boundary;
401
+ // 🔹 PIN CODE HANDLER
402
+ const handlePincodeChange = (e) => {
403
+ const value = e.target.value;
404
+ if (/^\d{0,6}$/.test(value)) {
405
+ setPinCode(value);
242
406
 
243
- const getAssemblies = (boundaries) => {
244
- if (!boundaries) return [];
245
- let assemblies = [];
246
- const targetLabel = "assembly constituency";
247
- for (const boundary of boundaries) {
248
- const label = (boundary.label || boundary.name || "").toLowerCase().replace(/_/g, " ");
249
- if (label === targetLabel || label === "assemblyconstituency") {
250
- assemblies.push({ code: boundary.code, name: boundary.name, children: boundary.children });
251
- }
252
- if (boundary.children?.length) {
253
- assemblies.push(...getAssemblies(boundary.children));
407
+ if (value.length === 6) {
408
+ fetchLocationByPincode(value);
254
409
  }
255
410
  }
256
- return assemblies;
257
411
  };
258
412
 
259
- const getBlocks = (children) => {
260
- if (!children) return [];
261
- let blocks = [];
262
- const targetLabel = "block";
263
- for (const child of children) {
264
- const label = (child.label || child.name || "").toLowerCase().replace(/_/g, " ");
265
- if (label === targetLabel) {
266
- blocks.push({ code: child.code, name: child.name });
267
- }
268
- if (child.children?.length) {
269
- blocks.push(...getBlocks(child.children));
270
- }
271
- }
272
- return blocks;
413
+ // 🔹 MOCK PIN API (Replace with real API)
414
+ const fetchLocationByPincode = (pin) => {
415
+ // 🔥 Replace this with backend API
416
+ console.log("Fetching location for PIN:", pin);
273
417
  };
274
418
 
275
- const assemblies = getAssemblies(Array.isArray(rootBoundary) ? rootBoundary : rootBoundary ? [rootBoundary] : []);
419
+ // 🔹 FILE UPLOAD
420
+ const selectphoto = async (e) => {
421
+ let isMounted = true;
276
422
 
277
- const [assembly, setAssembly] = useState(() => getSavedData("EKYC_ASSEMBLY_DATA", initialData.assembly ? { name: initialData.assembly } : null));
278
- const [ward, setWard] = useState(() => getSavedData("EKYC_WARD_DATA", initialData.ward ? { name: initialData.ward } : null));
279
-
280
- // Sync MDMS selection
281
- useEffect(() => {
282
- sessionStorage.setItem("EKYC_ASSEMBLY_DATA", JSON.stringify(assembly));
283
- sessionStorage.setItem("EKYC_WARD_DATA", JSON.stringify(ward));
284
- }, [assembly, ward]);
423
+ const file = e.target.files[0];
424
+ if (!file) return;
285
425
 
286
- useEffect(() => {
287
- if (mdmsRes && addrDetails.assembly && !assembly?.code) {
288
- const foundAssembly = assemblies.find((a) => a.name === addrDetails.assembly || a.code === addrDetails.assembly);
289
- if (foundAssembly) setAssembly(foundAssembly);
426
+ if (file.size >= 2000000) {
427
+ setToast({ type: "error", message: "Max size 2MB exceeded" });
428
+ return;
290
429
  }
291
- }, [mdmsRes, assemblies]);
292
430
 
293
- const blocks = assembly ? getBlocks(assembly.children) : [];
431
+ try {
432
+ const res = await Digit.UploadServices.Filestorage("EKYC", file, tenantId);
294
433
 
295
- useEffect(() => {
296
- if (assembly && ward && !blocks.find((b) => b.name === ward.name)) {
297
- setWard(null);
434
+ if (!isMounted) return;
435
+
436
+ const fileStoreId = res?.data?.files?.[0]?.fileStoreId;
437
+
438
+ if (fileStoreId) {
439
+ setDoorPhotoFileStoreId(fileStoreId);
440
+
441
+ const reader = new FileReader();
442
+ reader.onloadend = () => {
443
+ if (!isMounted) return;
444
+ setDoorPhoto(reader.result);
445
+ };
446
+ reader.readAsDataURL(file);
447
+
448
+ setToast({ type: "success", message: "Upload successful" });
449
+ }
450
+ } catch {
451
+ if (!isMounted) return;
452
+ setToast({ type: "error", message: "Upload failed" });
298
453
  }
299
- }, [assembly]);
300
-
301
- const addressOptions = [
302
- { code: "AADHAAR", name: "EKYC_AADHAAR_ADDRESS" },
303
- { code: "OLD", name: "EKYC_OLD_ADDRESS" },
304
- ];
305
-
306
- const yesNoOptions = [
307
- { code: "YES", name: "CORE_COMMON_YES" },
308
- { code: "NO", name: "CORE_COMMON_NO" },
309
- ];
310
-
311
- const handleCompleteVerification = () => {
312
- const payload = {
313
- addressType,
314
- fullAddress,
315
- flatNo,
316
- building,
317
- landmark,
318
- pincode,
319
- doorPhoto,
320
- doorPhotoFileStoreId,
321
- assembly: assembly?.name,
322
- ward: ward?.name
454
+
455
+ return () => {
456
+ isMounted = false;
323
457
  };
324
- if (onComplete) {
325
- onComplete(payload);
326
- } else {
327
- const { kNumber, selectedOption, connectionDetails, initialData } = flowState;
328
- history.push("/digit-ui/employee/ekyc/property-info", {
329
- kNumber, selectedOption, connectionDetails, addressDetails: payload, initialData
330
- });
331
- }
332
458
  };
333
459
 
334
- function selectphoto(e) {
335
- setDoorPhotoFileStoreId(null);
336
- setFilephoto(e.target.files[0]);
337
- }
338
-
339
460
  const removePhoto = () => {
340
461
  setDoorPhoto(null);
341
462
  setDoorPhotoFileStoreId(null);
342
- setFilephoto(null);
343
463
  };
344
464
 
345
- const handleUseCurrentLocation = () => {
346
- if (!("geolocation" in navigator)) {
347
- alert(t("GEOLOCATION_NOT_SUPPORTED"));
465
+ // 🔹 VALIDATION
466
+ const isValid = () => {
467
+ return houseNo && street && pinCode.length === 6 && assembly && ward && zone && latitude && longitude && doorPhotoFileStoreId;
468
+ };
469
+
470
+ // 🔹 SUBMIT
471
+ const onStepSelect = () => {
472
+ if (!isValid()) {
473
+ setToast({ type: "error", message: "Please fill all mandatory fields" });
348
474
  return;
349
475
  }
350
- setIsLocationFetching(true);
351
- navigator.geolocation.getCurrentPosition(
352
- async ({ coords: { latitude, longitude } }) => {
353
- try {
354
- const res = await fetch(
355
- `https://nominatim.openstreetmap.org/reverse?format=json&lat=${latitude}&lon=${longitude}&zoom=18&addressdetails=1`
356
- );
357
- if (!res.ok) throw new Error("Geocode failed");
358
- const data = await res.json();
359
- if (data?.address) {
360
- const a = data.address;
361
- setFullAddress([a.amenity, a.road, a.neighbourhood, a.suburb, a.city, a.state, a.postcode].filter(Boolean).join(", "));
362
- setPincode(a.postcode || "");
363
- setLandmark(a.suburb || a.neighbourhood || "");
364
- setFlatNo(a.amenity || "");
365
- }
366
- } catch (err) {
367
- console.error("Reverse geocode error:", err);
368
- } finally {
369
- setIsLocationFetching(false);
370
- }
371
- },
372
- (err) => {
373
- console.error("Geolocation error:", err);
374
- setIsLocationFetching(false);
375
- alert(t("LOCATION_FETCH_FAILED"));
376
- },
377
- { enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }
378
- );
476
+
477
+ const data = {
478
+ houseNo,
479
+ street,
480
+ locality,
481
+ landmark,
482
+ subLocality,
483
+ pinCode,
484
+ assembly: assembly?.name,
485
+ ward: ward?.name,
486
+ zone: zone?.name,
487
+ latitude,
488
+ longitude,
489
+ addressType: addressType?.name,
490
+ doorPhotoFilestoreId: doorPhotoFileStoreId,
491
+ };
492
+
493
+ onSelect(config.key, data);
379
494
  };
380
495
 
381
- const renderContent = () => (
382
- <div style={{ animation: "fadeSlideIn 0.3s ease" }}>
383
-
384
- {/* ── Address Type Toggle ── */}
385
- <SectionHead
386
- icon={<LocationIcon className="icon" styles={{ fill: "#0B0C0C", width: "16px", height: "16px" }} />}
387
- label={t("EKYC_ADDRESS_DETAILS_HEADER")}
388
- />
389
-
390
- <div style={{ marginBottom: "20px" }}>
391
- <RadioButtons
392
- options={addressOptions}
393
- optionsKey="name"
394
- selectedOption={addressType}
395
- onSelect={setAddressType}
396
- t={t}
397
- innerStyles={{ display: "flex", alignItems: "center" }}
398
- style={{ display: "flex", gap: "40px" }}
399
- />
400
- </div>
401
-
402
- {/* ── Aadhaar Address display ── */}
403
- {addressType.code === "AADHAAR" && (
404
- <div style={{
405
- backgroundColor: "#E1F5EE",
406
- border: "0.5px solid #5DCAA5",
407
- borderRadius: "8px",
408
- padding: "14px 16px",
409
- display: "flex",
410
- alignItems: "flex-start",
411
- gap: "12px",
412
- marginBottom: "20px",
413
- animation: "fadeSlideIn 0.3s ease",
414
- }}>
415
- <div style={{ backgroundColor: "#9FE1CB", padding: "6px", borderRadius: "6px", display: "flex", flexShrink: 0 }}>
416
- <LocationIcon className="icon" styles={{ fill: "#085041", width: "16px", height: "16px" }} />
417
- </div>
418
- <div style={{ fontSize: "14px", lineHeight: "1.6", color: "#04342C", fontWeight: "500" }}>
419
- {addrDetails.fullAddress}
420
- </div>
421
- </div>
422
- )}
423
-
424
- {/* ── Old / Custom Address ── */}
425
- {addressType.code === "OLD" && (
426
- <div style={{ animation: "fadeSlideIn 0.3s ease" }}>
427
-
428
- {/* Correction toggle */}
429
- <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: "14px" }}>
430
- <CardLabel style={{ fontWeight: "500", marginBottom: 0, fontSize: "13px", color: "#505A5F" }}>
431
- {t("EKYC_ADDRESS_CORRECTION_PROMPT")}
432
- </CardLabel>
433
- <RadioButtons
434
- options={yesNoOptions}
435
- optionsKey="name"
436
- selectedOption={correctAddress}
437
- onSelect={setCorrectAddress}
438
- t={t}
439
- innerStyles={{ display: "flex", gap: "20px" }}
440
- style={{ marginBottom: 0 }}
441
- />
442
- </div>
443
-
444
- {/* Use Current Location */}
445
- <div
446
- onClick={!isLocationFetching ? handleUseCurrentLocation : undefined}
447
- style={{
448
- border: "0.5px solid #D0D5DD",
449
- borderRadius: "8px",
450
- padding: "12px 16px",
451
- display: "flex",
452
- alignItems: "center",
453
- justifyContent: "space-between",
454
- marginBottom: "20px",
455
- cursor: isLocationFetching ? "not-allowed" : "pointer",
456
- backgroundColor: isLocationFetching ? "#F9FAFB" : "#fff",
457
- transition: "background 0.15s",
458
- opacity: isLocationFetching ? 0.7 : 1,
459
- }}
460
- onMouseOver={(e) => { if (!isLocationFetching) e.currentTarget.style.background = "#F9FAFB"; }}
461
- onMouseOut={(e) => { if (!isLocationFetching) e.currentTarget.style.background = "#fff"; }}
462
- >
463
- <div style={{ display: "flex", alignItems: "center", gap: "12px" }}>
464
- <div style={{ backgroundColor: "#E6F1FB", padding: "7px", borderRadius: "7px", display: "flex" }}>
465
- {isLocationFetching ? (
466
- <div style={{
467
- width: "18px", height: "18px", border: "2px solid #185FA5",
468
- borderTopColor: "transparent", borderRadius: "50%",
469
- animation: "spin 1s linear infinite",
470
- }} />
471
- ) : (
472
- <TargetIcon size={18} />
473
- )}
474
- </div>
475
- <span style={{ fontWeight: "500", fontSize: "14px", color: "#344054" }}>
476
- {isLocationFetching
477
- ? t("EKYC_FETCHING_LOCATION")
478
- : t("EKYC_USE_CURRENT_LOCATION")}
479
- </span>
480
- </div>
481
- {!isLocationFetching && (
482
- <span style={{ fontSize: "18px", color: "#98A2B3", lineHeight: 1 }}>›</span>
483
- )}
484
- </div>
485
-
486
- {/* Full Address (textarea-style) */}
487
- <div style={{ marginBottom: "14px" }}>
488
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
489
- {t("EKYC_FULL_ADDRESS")}
490
- </div>
491
- <IconInput
492
- icon={<PropertyHouse styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
493
- topAligned
494
- value={fullAddress}
495
- onChange={(e) => setFullAddress(e.target.value)}
496
- placeholder={t("EKYC_ENTER_FULL_ADDRESS")}
497
- inputStyle={{ minHeight: "72px" }}
498
- />
499
- </div>
500
-
501
- {/* Flat + Building */}
502
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "14px" }}>
503
- <div>
504
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
505
- {t("EKYC_FLAT_HOUSE_NUMBER")}
506
- </div>
507
- <IconInput
508
- icon={<PropertyHouse styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
509
- value={flatNo}
510
- onChange={(e) => setFlatNo(e.target.value)}
511
- placeholder={t("EKYC_ENTER_FLAT_NO")}
512
- />
513
- </div>
514
- <div>
515
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
516
- {t("EKYC_BUILDING_TOWER")}
517
- </div>
518
- <IconInput
519
- icon={<PropertyHouse styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
520
- value={building}
521
- onChange={(e) => setBuilding(e.target.value)}
522
- placeholder={t("EKYC_ENTER_BUILDING")}
523
- />
524
- </div>
525
- </div>
526
-
527
- {/* Landmark + Pincode */}
528
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "4px" }}>
529
- <div>
530
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
531
- {t("EKYC_LANDMARK")}
532
- </div>
533
- <IconInput
534
- icon={<LocationIcon className="icon" styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
535
- value={landmark}
536
- onChange={(e) => setLandmark(e.target.value)}
537
- placeholder={t("EKYC_ENTER_LANDMARK")}
538
- />
539
- </div>
540
- <div>
541
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
542
- {t("EKYC_PINCODE")}
543
- </div>
544
- <IconInput
545
- icon={<PincodeIcon size={15} />}
546
- value={pincode}
547
- onChange={(e) => { if (/^\d*$/.test(e.target.value)) setPincode(e.target.value); }}
548
- placeholder={t("EKYC_ENTER_PINCODE")}
549
- maxLength={6}
550
- />
551
- </div>
552
- </div>
553
- </div>
554
- )}
555
-
556
- <hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
557
-
558
- {/* ── Administrative Division ── */}
559
- <SectionHead
560
- icon={<PropertyHouse styles={{ fill: "#0B0C0C", width: "16px", height: "16px" }} />}
561
- label={t("EKYC_ADMINISTRATIVE_DIVISION")}
562
- />
563
-
564
- {isMdmsLoading ? <Loader /> : (
565
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "24px" }}>
566
- <div>
567
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
568
- {t("EKYC_ASSEMBLY")}
569
- </div>
570
- <Dropdown
571
- option={assemblies}
572
- optionKey="name"
573
- selected={assembly}
574
- select={(val) => { setAssembly(val); setWard(null); }}
575
- t={t}
576
- />
577
- </div>
578
- <div>
579
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
580
- {t("EKYC_WARD") || "Block"}
581
- </div>
582
- <Dropdown
583
- option={blocks}
584
- optionKey="name"
585
- selected={ward}
586
- select={setWard}
587
- disabled={!assembly}
588
- t={t}
589
- />
590
- </div>
591
- </div>
592
- )}
593
-
594
- <hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
595
-
596
- {/* ── Door Photo ── */}
597
- <SectionHead
598
- icon={<CameraIcon size={16} />}
599
- label={t("EKYC_CAPTURE_DOOR_IMAGE")}
600
- />
601
-
602
- <div style={{ fontSize: "12px", color: "#667085", marginBottom: "12px" }}>
603
- {t("EKYC_REQUIRED_FOR_VERIFICATION")}
604
- </div>
605
-
606
- {/* Warning banner
607
- <div style={{
608
- backgroundColor: "#FFFAEB",
609
- border: "0.5px solid #FEDF89",
610
- borderRadius: "8px",
611
- padding: "12px 14px",
612
- display: "flex",
613
- alignItems: "flex-start",
614
- gap: "10px",
615
- marginBottom: "16px",
616
- }}>
617
- <div style={{ flexShrink: 0, marginTop: "1px" }}>
618
- <InfoBannerIcon fill="#B54708" />
619
- </div>
620
- <div>
621
- <div style={{ fontWeight: "600", color: "#B54708", fontSize: "13px", marginBottom: "2px" }}>
622
- {t("EKYC_IMPORTANT")}
623
- </div>
624
- <div style={{ fontSize: "12px", color: "#92400E" }}>
625
- {t("EKYC_CAPTURE_LIVE_CAMERA")}
626
- </div>
627
- </div>
628
- </div> */}
629
-
630
- {/* Building Photo Upload */}
631
- <UploadFile
632
- id={"ekyc-door-photo"}
633
- extraStyleName={"propertyCreate"}
634
- accept=".jpg,.png,.jpeg"
635
- onUpload={selectphoto}
636
- onDelete={removePhoto}
637
- message={doorPhotoFileStoreId ? `1 ${t(`EKYC_ACTION_FILEUPLOADED`)}` : t(`EKYC_ACTION_NO_FILEUPLOADED`)}
638
- error={error}
639
- />
640
- {doorPhoto && (
641
- <div style={{ marginTop: "10px", borderRadius: "8px", overflow: "hidden", border: "1px solid #EAECF0" }}>
642
- <img src={doorPhoto} alt="Door Preview" style={{ width: "100%", maxHeight: "250px", objectFit: "cover" }} />
643
- </div>
644
- )}
645
-
646
- {/* Submit */}
647
- {isSection ? (
648
- <div style={{ marginTop: "24px" }}>
649
- <SubmitBar
650
- label={t("ES_COMMON_SAVE_CONTINUE")}
651
- onSubmit={handleCompleteVerification}
652
- />
653
- </div>
654
- ) : (
655
- <ActionBar>
656
- <SubmitBar
657
- label={t("EKYC_COMPLETE_VERIFICATION")}
658
- onSubmit={handleCompleteVerification}
659
- />
660
- </ActionBar>
661
- )}
662
-
663
- {/* Secure notice */}
664
- <div style={{
665
- display: "flex", alignItems: "center", justifyContent: "center",
666
- gap: "5px", marginTop: "16px",
667
- fontSize: "11px", color: "#98A2B3",
668
- }}>
669
- <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
670
- <rect x="3" y="11" width="18" height="11" rx="2" />
671
- <path d="M7 11V7a5 5 0 0 1 10 0v4" />
672
- </svg>
673
- {t("EKYC_SECURE_DATA_NOTICE")}
674
- </div>
675
- {toast && (
676
- <Toast
677
- label={toast.message}
678
- error={toast.type === "error"}
679
- info={toast.type === "info"}
680
- success={toast.type === "success"}
681
- onClose={() => setToast(null)}
682
- />
683
- )}
684
- </div>
685
- );
496
+ if (isLoading) return <Loader />;
686
497
 
687
- // ── When rendered as inline section inside AadhaarVerification ──
688
- if (isSection) {
689
- return (
690
- <Fragment>
691
- <hr style={{ margin: "32px 0", border: 0, borderTop: "2px solid #EAECF0" }} />
692
- {renderContent()}
693
- </Fragment>
694
- );
695
- }
696
-
697
- // ── When rendered as a standalone page ──
698
498
  return (
699
- <div className="inbox-container">
700
- <style>{`
701
- @keyframes spin { to { transform: rotate(360deg); } }
702
- @keyframes fadeSlideIn { from { opacity:0; transform:translateY(8px); } to { opacity:1; transform:translateY(0); } }
703
- `}</style>
704
-
705
- {/* Sidebar */}
706
- <div className="filters-container">
707
- <Card style={{ display: "flex", alignItems: "center", padding: "12px 16px", marginBottom: "12px", borderRadius: "8px" }}>
708
- <div style={{ color: "#185FA5", marginRight: "10px", display: "flex" }}>
709
- <HomeIcon style={{ width: "20px", height: "20px" }} />
710
- </div>
711
- <div style={{ fontWeight: "600", fontSize: "15px", color: "#0B0C0C" }}>
712
- {t("EKYC_PROCESS") || "eKYC Process"}
713
- </div>
714
- </Card>
715
-
716
- <div style={{ background: "#fff", padding: "16px 14px", borderRadius: "8px", border: "1px solid #EAECF0" }}>
717
- {[
718
- { label: t("EKYC_STEP_AADHAAR") || "Aadhaar", done: true, active: false },
719
- { label: t("EKYC_STEP_ADDRESS") || "Address", done: false, active: true },
720
- { label: t("EKYC_STEP_PROPERTY") || "Property", done: false, active: false },
721
- { label: t("EKYC_STEP_METER") || "Meter", done: false, active: false },
722
- { label: t("EKYC_STEP_REVIEW") || "Review", done: false, active: false },
723
- ].map((step, i) => (
724
- <div key={i} style={{ display: "flex", gap: "10px", alignItems: "flex-start", position: "relative", paddingBottom: i < 4 ? "18px" : 0 }}>
725
- {i < 4 && (
726
- <div style={{ position: "absolute", left: "10px", top: "22px", width: "1px", height: "calc(100% - 10px)", background: "#EAECF0" }} />
727
- )}
728
- <div style={{
729
- width: "20px", height: "20px", borderRadius: "50%", flexShrink: 0, marginTop: "1px",
730
- border: step.done ? "none" : step.active ? "1.5px solid #185FA5" : "1.5px solid #D0D5DD",
731
- background: step.done ? "#0F6E56" : step.active ? "#E6F1FB" : "#fff",
732
- display: "flex", alignItems: "center", justifyContent: "center",
733
- fontSize: "10px", fontWeight: "500",
734
- color: step.done ? "#fff" : step.active ? "#185FA5" : "#98A2B3",
735
- }}>
736
- {step.done ? <CheckIcon size={11} color="#fff" /> : i + 1}
737
- </div>
738
- <div style={{
739
- fontSize: "12px", paddingTop: "2px",
740
- color: step.done ? "#0F6E56" : step.active ? "#0B0C0C" : "#667085",
741
- fontWeight: step.done || step.active ? "600" : "400",
742
- }}>
743
- {step.label}
744
- </div>
745
- </div>
746
- ))}
747
- </div>
748
- </div>
749
-
750
- {/* Main */}
751
- <div style={{ flex: 1, marginLeft: "16px" }}>
752
- <Card>
753
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }}>
754
- <CardHeader style={{ margin: 0, fontSize: "18px" }}>
755
- {t("EKYC_ADDRESS_DETAILS_HEADER") || "Address Details"}
756
- </CardHeader>
757
- <div style={{
758
- background: "#F9FAFB", border: "0.5px solid #EAECF0",
759
- borderRadius: "20px", padding: "4px 14px",
760
- fontSize: "12px", color: "#667085",
761
- }}>
762
- {t("EKYC_K_NUMBER") || "K Number"}:{" "}
763
- <span style={{ color: "#0B0C0C", fontWeight: "600" }}>{flowState?.kNumber}</span>
764
- </div>
765
- </div>
766
- {renderContent()}
767
- </Card>
768
- </div>
769
- </div>
499
+ <Fragment>
500
+ <FormStep t={t} onSelect={onStepSelect} config={config} label={t("ES_COMMON_CONTINUE")}>
501
+ <CardLabel>House No / Flat No *</CardLabel>
502
+ <TextInput value={houseNo} onChange={(e) => setHouseNo(e.target.value)} />
503
+
504
+ <CardLabel>Street / Address Line *</CardLabel>
505
+ <TextInput value={street} onChange={(e) => setStreet(e.target.value)} />
506
+
507
+ <CardLabel>Locality</CardLabel>
508
+ <TextInput value={locality} onChange={(e) => setLocality(e.target.value)} />
509
+
510
+ <CardLabel>Landmark</CardLabel>
511
+ <TextInput value={landmark} onChange={(e) => setLandmark(e.target.value)} />
512
+
513
+ <CardLabel>Sub Locality</CardLabel>
514
+ <Dropdown option={[]} selected={subLocality} select={setSubLocality} />
515
+
516
+ <CardLabel>PIN Code *</CardLabel>
517
+ <TextInput value={pinCode} onChange={handlePincodeChange} maxLength={6} />
518
+
519
+ <CardLabel>Assembly *</CardLabel>
520
+ <Dropdown option={assemblies} selected={assembly} select={setAssembly} />
521
+
522
+ <CardLabel>Ward *</CardLabel>
523
+ <Dropdown option={assembly?.children || []} selected={ward} select={setWard} />
524
+
525
+ <CardLabel>Zone *</CardLabel>
526
+ <Dropdown option={ward?.children || []} selected={zone} select={setZone} />
527
+
528
+ <CardLabel>Latitude</CardLabel>
529
+ <TextInput value={latitude} disabled />
530
+
531
+ <CardLabel>Longitude</CardLabel>
532
+ <TextInput value={longitude} disabled />
533
+
534
+ <CardLabel>Address Type</CardLabel>
535
+ <Dropdown option={[{ name: "Permanent" }, { name: "Correspondence" }, { name: "Other" }]} selected={addressType} select={setAddressType} />
536
+
537
+ <CardLabel>Door Image *</CardLabel>
538
+ <UploadFile onUpload={selectphoto} onDelete={removePhoto} message={doorPhotoFileStoreId ? "Uploaded" : "No file selected"} />
539
+
540
+ {doorPhoto && <img src={doorPhoto} alt="preview" style={{ width: "100%", marginTop: "10px" }} />}
541
+
542
+ {toast && <Toast label={toast.message} error={toast.type === "error"} onClose={() => setToast(null)} />}
543
+ </FormStep>
544
+ </Fragment>
770
545
  );
771
546
  };
772
547
 
773
- export default AddressDetails;
548
+ export default AddressDetails;