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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djb25/digit-ui-module-ekyc",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "Digit UI Module for Ekyc",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.modern.js",
@@ -44,17 +44,17 @@ const DesktopInbox = ({ tableConfig, filterComponent, ...props }) => {
44
44
  accessor: "citizenName",
45
45
  Cell: ({ row }) => <span>{row.original?.citizenName || "NA"}</span>,
46
46
  },
47
- {
48
- Header: t("EKYC_MOBILE_NO"),
49
- accessor: "mobileNumber",
50
- Cell: ({ row }) => <span>{row.original?.mobileNumber || "NA"}</span>,
51
- },
47
+ // {
48
+ // Header: t("EKYC_MOBILE_NO"),
49
+ // accessor: "mobileNumber",
50
+ // Cell: ({ row }) => <span>{row.original?.mobileNumber || "NA"}</span>,
51
+ // },
52
52
  {
53
53
  Header: t("EKYC_STATUS"),
54
54
  accessor: "status",
55
55
  Cell: ({ row }) => {
56
56
  const status = row.original?.status || "DEFAULT";
57
- return <span className={`ekyc-status-tag ${status}`}>{t(`EKYC_STATUS_${status}`)}</span>;
57
+ return <span className={`ekyc-status-tag ${status}`}>{t(`${status}`)}</span>;
58
58
  },
59
59
  },
60
60
  ],
@@ -66,7 +66,7 @@ const DesktopInbox = ({ tableConfig, filterComponent, ...props }) => {
66
66
  }, [data]);
67
67
 
68
68
  return (
69
- <div className="inbox-container">
69
+ <div className="inbox-container" style={{ paddingBottom: "16px" }}>
70
70
  <div className="filters-container">
71
71
  {/* Sidebar Title Card */}
72
72
  <Card
@@ -25,7 +25,9 @@ const Filter = ({ searchParams, onFilterChange, defaultSearchParams, statusMap,
25
25
  };
26
26
 
27
27
  const onStatusChange = (value) => {
28
- localParamChange({ status: value });
28
+ const newParams = { ..._searchParams, status: value };
29
+ setSearchParams(newParams);
30
+ onFilterChange(newParams);
29
31
  };
30
32
 
31
33
  return (
@@ -43,9 +45,8 @@ const Filter = ({ searchParams, onFilterChange, defaultSearchParams, statusMap,
43
45
  <Dropdown
44
46
  option={[
45
47
  { label: t("EKYC_STATUS_ALL"), value: "" },
46
- { label: t("EKYC_STATUS_COMPLETED"), value: "COMPLETED" },
47
- { label: t("EKYC_STATUS_PENDING"), value: "PENDING" },
48
- { label: t("EKYC_STATUS_REJECTED"), value: "REJECTED" },
48
+ { label: t("EKYC_STATUS_ACTIVE"), value: "ACTIVE" },
49
+ { label: t("EKYC_STATUS_PENDING"), value: "PENDING START" },
49
50
  ]}
50
51
  optionKey="label"
51
52
  select={onStatusChange}
@@ -88,7 +88,8 @@ const SearchConsumer = ({ onSearch, searchParams, FilterComponent, children, ...
88
88
  />
89
89
  </div>
90
90
  </div>
91
-
91
+ </div>
92
+ <div style={{ display: "flex", justifyContent: "flex-end", marginTop: "20px" }}>
92
93
  <div style={{ display: "flex", gap: "12px", alignItems: "center" }}>
93
94
  <button
94
95
  type="button"
@@ -105,10 +106,18 @@ const SearchConsumer = ({ onSearch, searchParams, FilterComponent, children, ...
105
106
  >
106
107
  {t("ES_COMMON_CLEAR")}
107
108
  </button>
109
+
108
110
  <SubmitBar
109
111
  label={t("ES_COMMON_SEARCH")}
110
112
  onSubmit={onSubmit}
111
- style={{ margin: 0, borderRadius: "8px", height: "44px", padding: "0 32px", marginTop: "-55px" }}
113
+ style={{
114
+ margin: 0,
115
+ borderRadius: "8px",
116
+ height: "44px",
117
+ padding: "0 32px",
118
+ // ❌ remove this (it breaks alignment)
119
+ // marginTop: "-55px"
120
+ }}
112
121
  />
113
122
  </div>
114
123
  </div>
@@ -129,8 +129,8 @@ const RadioToggleRow = ({ label, selected, onSelect, t, options }) => (
129
129
  selectedOption={selected}
130
130
  onSelect={onSelect}
131
131
  t={t}
132
- innerStyles={{ display: "flex", gap: "20px" }}
133
- style={{ marginBottom: 0 }}
132
+ innerStyles={{ display: "flex", gap: "20px", alignItems: "center" }}
133
+ style={{ display: "flex", gap: "20px", marginBottom: 0 }}
134
134
  />
135
135
  </div>
136
136
  );
@@ -165,6 +165,9 @@ const AadhaarVerification = () => {
165
165
  const [aadhaarLastFour, setAadhaarLastFour] = useState("");
166
166
  const [isAadhaarVerified, setIsAadhaarVerified] = useState(false);
167
167
  const [isVerifying, setIsVerifying] = useState(false);
168
+ const [showOtpField, setShowOtpField] = useState(false);
169
+ const [otp, setOtp] = useState("");
170
+ const [otpError, setOtpError] = useState(false);
168
171
  const [nameCorrect, setNameCorrect] = useState({ code: "NO", name: "CORE_COMMON_NO" });
169
172
  const [userName, setUserName] = useState(details.consumerName || "");
170
173
 
@@ -186,17 +189,27 @@ const AadhaarVerification = () => {
186
189
 
187
190
  // ── Handlers ──
188
191
  const handleVerifyAadhaar = () => {
189
- if (aadhaarLastFour.length !== 4 || isVerifying) return;
192
+ if (aadhaarLastFour.length !== 12 || isVerifying) return;
190
193
  setIsVerifying(true);
191
194
  setTimeout(() => {
192
195
  setIsVerifying(false);
196
+ setShowOtpField(true);
197
+ }, 1200);
198
+ };
199
+
200
+ const handleVerifyOtp = () => {
201
+ if (otp === "123456") {
193
202
  setIsAadhaarVerified(true);
203
+ setShowOtpField(false);
204
+ setOtpError(false);
194
205
  // Auto-expand address section upon verification
195
206
  setShowAddressSection(true);
196
207
  setTimeout(() => {
197
208
  addressSectionRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
198
209
  }, 100);
199
- }, 1200);
210
+ } else {
211
+ setOtpError(true);
212
+ }
200
213
  };
201
214
 
202
215
  const handleSaveAndContinue = () => {
@@ -257,7 +270,7 @@ const AadhaarVerification = () => {
257
270
  display: "grid",
258
271
  gridTemplateColumns: "1fr 1fr",
259
272
  gap: "14px",
260
- marginBottom: "4px",
273
+ marginBottom: "20px",
261
274
  },
262
275
  optionalTag: {
263
276
  display: "inline-block",
@@ -364,24 +377,60 @@ const AadhaarVerification = () => {
364
377
  if (val.length <= 12 && /^\d*$/.test(val)) setAadhaarLastFour(val);
365
378
  }}
366
379
  placeholder={t("EKYC_ENTER_LAST_4_DIGIT") || "Enter 12 digits"}
367
- maxLength={4}
380
+ maxLength={12}
368
381
  disabled={isAadhaarVerified}
369
382
  inputStyle={isAadhaarVerified ? styles.verifiedInput : {}}
370
383
  />
371
384
  </div>
372
385
  </LabelFieldPair>
373
386
 
374
- {!isAadhaarVerified && (
387
+ {!isAadhaarVerified && !showOtpField && (
375
388
  <SubmitBar
376
389
  label={isVerifying
377
390
  ? t("EKYC_VERIFYING") || "Verifying..."
378
391
  : t("EKYC_VERIFY_AADHAAR_BTN") || "Verify Aadhaar"}
379
392
  onSubmit={handleVerifyAadhaar}
380
- disabled={aadhaarLastFour.length !== 4 || isVerifying}
393
+ disabled={aadhaarLastFour.length !== 12 || isVerifying}
381
394
  style={{ marginTop: "12px" }}
382
395
  />
383
396
  )}
384
397
 
398
+ {!isAadhaarVerified && showOtpField && (
399
+ <Fragment>
400
+ <div className="ekyc-field-label" style={{ marginTop: "16px" }}>
401
+ {t("EKYC_ENTER_OTP") || "Enter OTP"}
402
+ </div>
403
+ <LabelFieldPair>
404
+ <div className="field">
405
+ <IconInput
406
+ icon={<LockIcon size={15} />}
407
+ value={otp}
408
+ onChange={(e) => {
409
+ const val = e.target.value;
410
+ if (/^\d*$/.test(val)) {
411
+ setOtp(val);
412
+ if (otpError) setOtpError(false);
413
+ }
414
+ }}
415
+ placeholder={t("EKYC_ENTER_OTP_PLACEHOLDER") || "Enter 123456"}
416
+ maxLength={6}
417
+ />
418
+ </div>
419
+ </LabelFieldPair>
420
+ {otpError && (
421
+ <div style={{ color: "#D4351C", fontSize: "12px", marginTop: "4px" }}>
422
+ {t("EKYC_INVALID_OTP") || "Invalid OTP. Please enter 123456."}
423
+ </div>
424
+ )}
425
+ <SubmitBar
426
+ label={t("EKYC_VERIFY_OTP_BTN") || "Verify OTP"}
427
+ onSubmit={handleVerifyOtp}
428
+ disabled={otp.length !== 6}
429
+ style={{ marginTop: "12px" }}
430
+ />
431
+ </Fragment>
432
+ )}
433
+
385
434
  {isAadhaarVerified && (
386
435
  <div style={styles.verifiedCard}>
387
436
  <div style={{ display: "flex", alignItems: "center", gap: "8px", marginBottom: "14px" }}>
@@ -404,7 +453,7 @@ const AadhaarVerification = () => {
404
453
  </div>
405
454
  <div>
406
455
  <div style={styles.infoLabel}>{t("EKYC_AADHAAR") || "Aadhaar"}</div>
407
- <div style={styles.infoValue}>XXXX XXXX {aadhaarLastFour}</div>
456
+ <div style={styles.infoValue}>{aadhaarLastFour}</div>
408
457
  </div>
409
458
  <div style={{ gridColumn: "span 2" }}>
410
459
  <div style={styles.infoLabel}>{t("EKYC_ADDRESS") || "Address"}</div>
@@ -428,12 +477,14 @@ const AadhaarVerification = () => {
428
477
  selected={nameCorrect}
429
478
  onSelect={setNameCorrect}
430
479
  options={yesNoOptions}
480
+ sty
431
481
  t={t}
432
482
  />
433
483
  <LabelFieldPair>
434
484
  <div className="field">
435
485
  <IconInput
436
486
  icon={<UserIcon size={15} color={nameCorrect.code === "YES" ? "#64748b" : "#94a3b8"} />}
487
+ style={{ marginBottom: "12px" }}
437
488
  value={userName}
438
489
  onChange={(e) => setUserName(e.target.value)}
439
490
  placeholder={t("EKYC_ENTER_NAME_PLACEHOLDER") || "Enter full name"}
@@ -454,6 +505,7 @@ const AadhaarVerification = () => {
454
505
  <div className="field">
455
506
  <IconInput
456
507
  icon={<PhoneIcon size={15} color={mobileChange.code === "YES" ? "#64748b" : "#94a3b8"} />}
508
+ style={{ marginBottom: "12px" }}
457
509
  value={mobileNumber}
458
510
  onChange={(e) => setMobileNumber(e.target.value)}
459
511
  placeholder="+91 XXXXX XXXXX"
@@ -1,4 +1,4 @@
1
- import React, { useState, useRef, Fragment } from "react";
1
+ import React, { useState, useRef, Fragment, useEffect } from "react";
2
2
  import {
3
3
  Card,
4
4
  LabelFieldPair,
@@ -14,6 +14,8 @@ import {
14
14
  HomeIcon,
15
15
  ConnectingCheckPoints,
16
16
  CheckPoint,
17
+ Dropdown,
18
+ Loader,
17
19
  } from "@djb25/digit-ui-react-components";
18
20
  import { useTranslation } from "react-i18next";
19
21
  import { useHistory, useLocation } from "react-router-dom";
@@ -164,6 +166,71 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
164
166
  const [isLocationFetching, setIsLocationFetching] = useState(false);
165
167
  const fileInputRef = useRef(null);
166
168
 
169
+ const tenantId = Digit.ULBService.getCurrentTenantId();
170
+ const { data: mdmsData, isLoading: isMdmsLoading } = Digit.Hooks.useCommonMDMS(
171
+ tenantId,
172
+ "egov-location",
173
+ ["TenantBoundary"]
174
+ );
175
+
176
+ const mdmsRes = mdmsData?.MdmsRes || mdmsData;
177
+ const adminHierarchy = mdmsRes?.["egov-location"]?.TenantBoundary?.find(h => h.hierarchyType.code === "ADMIN")
178
+ || mdmsRes?.["egov-location"]?.TenantBoundary?.[0];
179
+
180
+ const rootBoundary = adminHierarchy?.boundary;
181
+
182
+ const getAssemblies = (boundaries) => {
183
+ if (!boundaries) return [];
184
+ let assemblies = [];
185
+ const targetLabel = "assembly constituency";
186
+ for (const boundary of boundaries) {
187
+ const label = (boundary.label || boundary.name || "").toLowerCase().replace(/_/g, " ");
188
+ if (label === targetLabel || label === "assemblyconstituency") {
189
+ assemblies.push({ code: boundary.code, name: boundary.name, children: boundary.children });
190
+ }
191
+ if (boundary.children?.length) {
192
+ assemblies.push(...getAssemblies(boundary.children));
193
+ }
194
+ }
195
+ return assemblies;
196
+ };
197
+
198
+ const getBlocks = (children) => {
199
+ if (!children) return [];
200
+ let blocks = [];
201
+ const targetLabel = "block";
202
+ for (const child of children) {
203
+ const label = (child.label || child.name || "").toLowerCase().replace(/_/g, " ");
204
+ if (label === targetLabel) {
205
+ blocks.push({ code: child.code, name: child.name });
206
+ }
207
+ if (child.children?.length) {
208
+ blocks.push(...getBlocks(child.children));
209
+ }
210
+ }
211
+ return blocks;
212
+ };
213
+
214
+ const assemblies = getAssemblies(Array.isArray(rootBoundary) ? rootBoundary : rootBoundary ? [rootBoundary] : []);
215
+
216
+ const [assembly, setAssembly] = useState(addrDetails.assembly ? { name: addrDetails.assembly } : null);
217
+ const [ward, setWard] = useState(addrDetails.ward ? { name: addrDetails.ward } : null);
218
+
219
+ useEffect(() => {
220
+ if (mdmsRes && addrDetails.assembly && !assembly?.code) {
221
+ const foundAssembly = assemblies.find((a) => a.name === addrDetails.assembly || a.code === addrDetails.assembly);
222
+ if (foundAssembly) setAssembly(foundAssembly);
223
+ }
224
+ }, [mdmsRes, assemblies]);
225
+
226
+ const blocks = assembly ? getBlocks(assembly.children) : [];
227
+
228
+ useEffect(() => {
229
+ if (assembly && ward && !blocks.find((b) => b.name === ward.name)) {
230
+ setWard(null);
231
+ }
232
+ }, [assembly]);
233
+
167
234
  const addressOptions = [
168
235
  { code: "AADHAAR", name: "EKYC_AADHAAR_ADDRESS" },
169
236
  { code: "OLD", name: "EKYC_OLD_ADDRESS" },
@@ -175,7 +242,17 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
175
242
  ];
176
243
 
177
244
  const handleCompleteVerification = () => {
178
- const payload = { addressType, fullAddress, flatNo, building, landmark, pincode, doorPhoto };
245
+ const payload = {
246
+ addressType,
247
+ fullAddress,
248
+ flatNo,
249
+ building,
250
+ landmark,
251
+ pincode,
252
+ doorPhoto,
253
+ assembly: assembly?.name,
254
+ ward: ward?.name
255
+ };
179
256
  if (onComplete) {
180
257
  onComplete(payload);
181
258
  } else {
@@ -201,7 +278,7 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
201
278
 
202
279
  const handleUseCurrentLocation = () => {
203
280
  if (!("geolocation" in navigator)) {
204
- alert(t("GEOLOCATION_NOT_SUPPORTED") || "Geolocation is not supported by your browser");
281
+ alert(t("GEOLOCATION_NOT_SUPPORTED"));
205
282
  return;
206
283
  }
207
284
  setIsLocationFetching(true);
@@ -229,7 +306,7 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
229
306
  (err) => {
230
307
  console.error("Geolocation error:", err);
231
308
  setIsLocationFetching(false);
232
- alert(t("LOCATION_FETCH_FAILED") || "Failed to fetch location. Please grant location permissions.");
309
+ alert(t("LOCATION_FETCH_FAILED"));
233
310
  },
234
311
  { enableHighAccuracy: true, timeout: 10000, maximumAge: 0 }
235
312
  );
@@ -241,7 +318,7 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
241
318
  {/* ── Address Type Toggle ── */}
242
319
  <SectionHead
243
320
  icon={<LocationIcon className="icon" styles={{ fill: "#0B0C0C", width: "16px", height: "16px" }} />}
244
- label={t("EKYC_ADDRESS_DETAILS_HEADER") || "Address Details"}
321
+ label={t("EKYC_ADDRESS_DETAILS_HEADER")}
245
322
  />
246
323
 
247
324
  <div style={{ marginBottom: "20px" }}>
@@ -273,7 +350,7 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
273
350
  <LocationIcon className="icon" styles={{ fill: "#085041", width: "16px", height: "16px" }} />
274
351
  </div>
275
352
  <div style={{ fontSize: "14px", lineHeight: "1.6", color: "#04342C", fontWeight: "500" }}>
276
- {addrDetails.fullAddress || "H.No. 123, Sector 15, Rohini, Delhi – 110085"}
353
+ {addrDetails.fullAddress}
277
354
  </div>
278
355
  </div>
279
356
  )}
@@ -285,7 +362,7 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
285
362
  {/* Correction toggle */}
286
363
  <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: "14px" }}>
287
364
  <CardLabel style={{ fontWeight: "500", marginBottom: 0, fontSize: "13px", color: "#505A5F" }}>
288
- {t("EKYC_ADDRESS_CORRECTION_PROMPT") || "Correct the address?"}
365
+ {t("EKYC_ADDRESS_CORRECTION_PROMPT")}
289
366
  </CardLabel>
290
367
  <RadioButtons
291
368
  options={yesNoOptions}
@@ -331,8 +408,8 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
331
408
  </div>
332
409
  <span style={{ fontWeight: "500", fontSize: "14px", color: "#344054" }}>
333
410
  {isLocationFetching
334
- ? t("EKYC_FETCHING_LOCATION") || "Fetching location..."
335
- : t("EKYC_USE_CURRENT_LOCATION") || "Use current location"}
411
+ ? t("EKYC_FETCHING_LOCATION")
412
+ : t("EKYC_USE_CURRENT_LOCATION")}
336
413
  </span>
337
414
  </div>
338
415
  {!isLocationFetching && (
@@ -343,14 +420,14 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
343
420
  {/* Full Address (textarea-style) */}
344
421
  <div style={{ marginBottom: "14px" }}>
345
422
  <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
346
- {t("EKYC_FULL_ADDRESS") || "Full address"}
423
+ {t("EKYC_FULL_ADDRESS")}
347
424
  </div>
348
425
  <IconInput
349
426
  icon={<PropertyHouse styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
350
427
  topAligned
351
428
  value={fullAddress}
352
429
  onChange={(e) => setFullAddress(e.target.value)}
353
- placeholder={t("EKYC_ENTER_FULL_ADDRESS") || "Enter full address"}
430
+ placeholder={t("EKYC_ENTER_FULL_ADDRESS")}
354
431
  inputStyle={{ minHeight: "72px" }}
355
432
  />
356
433
  </div>
@@ -359,24 +436,24 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
359
436
  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "14px" }}>
360
437
  <div>
361
438
  <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
362
- {t("EKYC_FLAT_HOUSE_NUMBER") || "Flat / House no."}
439
+ {t("EKYC_FLAT_HOUSE_NUMBER")}
363
440
  </div>
364
441
  <IconInput
365
442
  icon={<PropertyHouse styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
366
443
  value={flatNo}
367
444
  onChange={(e) => setFlatNo(e.target.value)}
368
- placeholder={t("EKYC_ENTER_FLAT_NO") || "e.g. 45-B"}
445
+ placeholder={t("EKYC_ENTER_FLAT_NO")}
369
446
  />
370
447
  </div>
371
448
  <div>
372
449
  <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
373
- {t("EKYC_BUILDING_TOWER") || "Building / Tower"}
450
+ {t("EKYC_BUILDING_TOWER")}
374
451
  </div>
375
452
  <IconInput
376
453
  icon={<PropertyHouse styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
377
454
  value={building}
378
455
  onChange={(e) => setBuilding(e.target.value)}
379
- placeholder={t("EKYC_ENTER_BUILDING") || "e.g. Tower 4"}
456
+ placeholder={t("EKYC_ENTER_BUILDING")}
380
457
  />
381
458
  </div>
382
459
  </div>
@@ -385,24 +462,24 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
385
462
  <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "4px" }}>
386
463
  <div>
387
464
  <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
388
- {t("EKYC_LANDMARK") || "Landmark"}
465
+ {t("EKYC_LANDMARK")}
389
466
  </div>
390
467
  <IconInput
391
468
  icon={<LocationIcon className="icon" styles={{ fill: "#0068fa", width: "15px", height: "15px" }} />}
392
469
  value={landmark}
393
470
  onChange={(e) => setLandmark(e.target.value)}
394
- placeholder={t("EKYC_ENTER_LANDMARK") || "Near Central Park"}
471
+ placeholder={t("EKYC_ENTER_LANDMARK")}
395
472
  />
396
473
  </div>
397
474
  <div>
398
475
  <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
399
- {t("EKYC_PINCODE") || "Pincode"}
476
+ {t("EKYC_PINCODE")}
400
477
  </div>
401
478
  <IconInput
402
479
  icon={<PincodeIcon size={15} />}
403
480
  value={pincode}
404
481
  onChange={(e) => { if (/^\d*$/.test(e.target.value)) setPincode(e.target.value); }}
405
- placeholder={t("EKYC_ENTER_PINCODE") || "6-digit pincode"}
482
+ placeholder={t("EKYC_ENTER_PINCODE")}
406
483
  maxLength={6}
407
484
  />
408
485
  </div>
@@ -415,38 +492,49 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
415
492
  {/* ── Administrative Division ── */}
416
493
  <SectionHead
417
494
  icon={<PropertyHouse styles={{ fill: "#0B0C0C", width: "16px", height: "16px" }} />}
418
- label={t("EKYC_ADMINISTRATIVE_DIVISION") || "Administrative Division"}
495
+ label={t("EKYC_ADMINISTRATIVE_DIVISION")}
419
496
  />
420
497
 
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>
498
+ {isMdmsLoading ? <Loader /> : (
499
+ <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "24px" }}>
500
+ <div>
501
+ <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
502
+ {t("EKYC_ASSEMBLY")}
503
+ </div>
504
+ <Dropdown
505
+ option={assemblies}
506
+ optionKey="name"
507
+ selected={assembly}
508
+ select={(val) => { setAssembly(val); setWard(null); }}
509
+ t={t}
510
+ />
511
+ </div>
512
+ <div>
513
+ <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
514
+ {t("EKYC_WARD") || "Block"}
515
+ </div>
516
+ <Dropdown
517
+ option={blocks}
518
+ optionKey="name"
519
+ selected={ward}
520
+ select={setWard}
521
+ disabled={!assembly}
522
+ t={t}
523
+ />
524
+ </div>
525
+ </div>
526
+ )}
439
527
 
440
528
  <hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
441
529
 
442
530
  {/* ── Door Photo ── */}
443
531
  <SectionHead
444
532
  icon={<CameraIcon size={16} />}
445
- label={t("EKYC_DOOR_PHOTO_HEADER") || "Door photo with GPS stamp"}
533
+ label={t("EKYC_DOOR_PHOTO_HEADER")}
446
534
  />
447
535
 
448
536
  <div style={{ fontSize: "12px", color: "#667085", marginBottom: "12px" }}>
449
- {t("EKYC_REQUIRED_FOR_VERIFICATION") || "Required for verification"}
537
+ {t("EKYC_REQUIRED_FOR_VERIFICATION")}
450
538
  </div>
451
539
 
452
540
  {/* Warning banner */}
@@ -465,10 +553,10 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
465
553
  </div>
466
554
  <div>
467
555
  <div style={{ fontWeight: "600", color: "#B54708", fontSize: "13px", marginBottom: "2px" }}>
468
- {t("EKYC_IMPORTANT") || "Important"}
556
+ {t("EKYC_IMPORTANT")}
469
557
  </div>
470
558
  <div style={{ fontSize: "12px", color: "#92400E" }}>
471
- {t("EKYC_CAPTURE_LIVE_CAMERA") || "Capture with live camera for GPS metadata"}
559
+ {t("EKYC_CAPTURE_LIVE_CAMERA")}
472
560
  </div>
473
561
  </div>
474
562
  </div>
@@ -514,7 +602,7 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
514
602
  {t("EKYC_TAP_TO_CAPTURE") || "Tap to capture"}
515
603
  </div>
516
604
  <div style={{ fontSize: "12px", color: "#667085" }}>
517
- {t("EKYC_CAPTURE_DOOR_IMAGE") || "Capture door image"}
605
+ {t("EKYC_CAPTURE_DOOR_IMAGE")}
518
606
  </div>
519
607
  </>
520
608
  ) : (
@@ -534,7 +622,7 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
534
622
  cursor: "pointer", fontSize: "12px", color: "#D92D20", fontWeight: "500",
535
623
  }}
536
624
  >
537
- <TrashIcon size={13} /> {t("EKYC_REMOVE") || "Remove"}
625
+ <TrashIcon size={13} /> {t("EKYC_REMOVE")}
538
626
  </button>
539
627
  </>
540
628
  )}
@@ -544,14 +632,14 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
544
632
  {isSection ? (
545
633
  <div style={{ marginTop: "24px" }}>
546
634
  <SubmitBar
547
- label={t("EKYC_COMPLETE_VERIFICATION_AND_PROCEED") || "Complete & Proceed"}
635
+ label={t("EKYC_COMPLETE_VERIFICATION_AND_PROCEED")}
548
636
  onSubmit={handleCompleteVerification}
549
637
  />
550
638
  </div>
551
639
  ) : (
552
640
  <ActionBar>
553
641
  <SubmitBar
554
- label={t("EKYC_COMPLETE_VERIFICATION") || "Complete Verification"}
642
+ label={t("EKYC_COMPLETE_VERIFICATION")}
555
643
  onSubmit={handleCompleteVerification}
556
644
  />
557
645
  </ActionBar>
@@ -567,7 +655,7 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
567
655
  <rect x="3" y="11" width="18" height="11" rx="2" />
568
656
  <path d="M7 11V7a5 5 0 0 1 10 0v4" />
569
657
  </svg>
570
- {t("EKYC_SECURE_DATA_NOTICE") || "Your data is encrypted and secure"}
658
+ {t("EKYC_SECURE_DATA_NOTICE")}
571
659
  </div>
572
660
  </div>
573
661
  );