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

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,4 +1,4 @@
1
- import React, { Fragment, useState } from "react";
1
+ import React, { Fragment, useState, useEffect } from "react";
2
2
  import {
3
3
  Card,
4
4
  CardHeader,
@@ -9,6 +9,7 @@ import {
9
9
  } from "@djb25/digit-ui-react-components";
10
10
  import { useTranslation } from "react-i18next";
11
11
  import { useHistory, useLocation } from "react-router-dom";
12
+ import { getPayloadDiff, getSavedData } from "../../utils";
12
13
 
13
14
  // ─── Icons ────────────────────────────────────────────────────────────────────
14
15
 
@@ -60,7 +61,7 @@ const SectionHead = ({ icon, label }) => (
60
61
 
61
62
  // ─── Reusable: Review section card ───────────────────────────────────────────
62
63
 
63
- const ReviewCard = ({ icon, title, onEdit, editLabel, rows }) => (
64
+ const ReviewCard = ({ icon, title, onEdit, editLabel, rows, t }) => (
64
65
  <div style={{
65
66
  border: "0.5px solid #EAECF0",
66
67
  borderRadius: "10px",
@@ -110,8 +111,22 @@ const ReviewCard = ({ icon, title, onEdit, editLabel, rows }) => (
110
111
  }}>
111
112
  {row.label}
112
113
  </div>
113
- <div style={{ flex: 1, fontSize: "14px", color: "#101828", fontWeight: "500", wordBreak: "break-word" }}>
114
+ <div style={{ flex: 1, fontSize: "14px", color: "#101828", fontWeight: "500", wordBreak: "break-word", display: "flex", alignItems: "center", gap: "8px" }}>
114
115
  {row.value}
116
+ {row.isModified && (
117
+ <span style={{
118
+ fontSize: "10px",
119
+ background: "#FFF4ED",
120
+ color: "#B45309",
121
+ border: "0.5px solid #FDE68A",
122
+ borderRadius: "4px",
123
+ padding: "2px 6px",
124
+ fontWeight: "600",
125
+ textTransform: "uppercase"
126
+ }}>
127
+ {t("EKYC_MODIFIED") || "Modified"}
128
+ </span>
129
+ )}
115
130
  </div>
116
131
  </div>
117
132
  ) : null
@@ -127,15 +142,60 @@ const Review = () => {
127
142
  const history = useHistory();
128
143
  const location = useLocation();
129
144
 
130
- const {
131
- kNumber = "EKYC-1234567890",
132
- aadhaarDetails = {},
133
- addressDetails = {},
134
- propertyDetails = {},
135
- } = location.state || {};
145
+ // ── Restore State Logic ──
146
+ const state = location.state || {};
147
+ const initialData = state.initialData || getSavedData("EKYC_INITIAL_DATA", {});
148
+ const kNumber = state.kNumber || sessionStorage.getItem("EKYC_K_NUMBER") || "EKYC-1234567890";
149
+
150
+ // Reconstruct nested objects if state is lost on refresh
151
+ const aadhaarDetails = state.aadhaarDetails || {
152
+ userName: sessionStorage.getItem("EKYC_USER_NAME"),
153
+ mobileNumber: sessionStorage.getItem("EKYC_MOBILE_NUMBER"),
154
+ whatsappNumber: sessionStorage.getItem("EKYC_WHATSAPP_NUMBER"),
155
+ email: sessionStorage.getItem("EKYC_EMAIL"),
156
+ noOfPersons: sessionStorage.getItem("EKYC_NO_OF_PERSONS"),
157
+ };
158
+
159
+ const addressDetails = state.addressDetails || {
160
+ fullAddress: sessionStorage.getItem("EKYC_FULL_ADDRESS"),
161
+ flatNo: sessionStorage.getItem("EKYC_FLAT_NO"),
162
+ building: sessionStorage.getItem("EKYC_BUILDING"),
163
+ landmark: sessionStorage.getItem("EKYC_LANDMARK"),
164
+ pincode: sessionStorage.getItem("EKYC_PINCODE"),
165
+ assembly: getSavedData("EKYC_ASSEMBLY_DATA")?.name,
166
+ ward: getSavedData("EKYC_WARD_DATA")?.name,
167
+ doorPhoto: sessionStorage.getItem("EKYC_DOOR_PHOTO"),
168
+ doorPhotoFileStoreId: sessionStorage.getItem("EKYC_DOOR_PHOTO_FILESTORE_ID"),
169
+ };
170
+
171
+ const propertyDetails = state.propertyDetails || {
172
+ ownerType: sessionStorage.getItem("EKYC_OWNER_TYPE"),
173
+ pidNumber: sessionStorage.getItem("EKYC_PID_NUMBER"),
174
+ connectionCategory: getSavedData("EKYC_TYPE_OF_CONNECTION_DATA"),
175
+ connectionType: getSavedData("EKYC_CONNECTION_CATEGORY_DATA"),
176
+ userType: getSavedData("EKYC_USER_TYPE_DATA"),
177
+ noOfFloors: getSavedData("EKYC_NO_OF_FLOORS_DATA"),
178
+ propertyDocument: sessionStorage.getItem("EKYC_PROPERTY_DOC"),
179
+ propertyDocumentFileStoreId: sessionStorage.getItem("EKYC_PROPERTY_DOC_FILESTORE_ID"),
180
+ buildingPhoto: sessionStorage.getItem("EKYC_BUILDING_PHOTO"),
181
+ buildingPhotoFileStoreId: sessionStorage.getItem("EKYC_BUILDING_PHOTO_FILESTORE_ID"),
182
+ };
183
+
184
+ useEffect(() => {
185
+ sessionStorage.setItem("EKYC_CURRENT_STEP", "REVIEW");
186
+ }, []);
187
+
188
+ // Helper to check if a field is modified
189
+ const isFieldModified = (key, currentVal) => {
190
+ const initialVal = initialData[key];
191
+ if (initialVal === undefined) return false;
192
+ return JSON.stringify(initialVal) !== JSON.stringify(currentVal);
193
+ };
136
194
 
137
- const [isSubmitting, setIsSubmitting] = useState(false);
138
195
  const [toast, setToast] = useState(null);
196
+ const tenantId = Digit.ULBService.getCurrentTenantId() || "dl";
197
+ const { mutate, isLoading: isMutationLoading } = Digit.Hooks.ekyc.useEkycApplicationUpdate(tenantId);
198
+ const isSubmitting = isMutationLoading;
139
199
 
140
200
  // ── Helper: upload a File object to Filestore ──────────────────────────────
141
201
  const uploadFile = async (file, tenantId) => {
@@ -156,32 +216,34 @@ const Review = () => {
156
216
  };
157
217
 
158
218
  const handleSubmit = async () => {
159
- setIsSubmitting(true);
160
219
  setToast(null);
161
220
  try {
162
- const tenantId = Digit.ULBService.getCurrentTenantId() || "dl.djb";
163
221
  const userInfo = Digit.UserService.getUser()?.info || {};
164
222
 
165
- // ── 1. Upload property document (PDF File object) ──────────────────────
166
- const propertyDocFile = propertyDetails.propertyDocument || null; // File object from <input>
167
- const propertyDocFileStoreId = await uploadFile(propertyDocFile, tenantId);
223
+ // ── 1. Upload property document ──────────────────────────────────────
224
+ let propertyDocFileStoreId = propertyDetails.propertyDocumentFileStoreId || null;
225
+ if (!propertyDocFileStoreId && propertyDetails.propertyDocument instanceof File) {
226
+ propertyDocFileStoreId = await uploadFile(propertyDetails.propertyDocument, tenantId);
227
+ }
168
228
 
169
- // ── 2. Upload building photo (data-URL string from camera capture) ─────
170
- let buildingImageFileStoreId = null;
171
- if (propertyDetails.buildingPhoto) {
229
+ // ── 2. Upload building photo ──────────────────────────────────────────
230
+ let buildingImageFileStoreId = propertyDetails.buildingPhotoFileStoreId || null;
231
+ if (!buildingImageFileStoreId && propertyDetails.buildingPhoto) {
232
+ // Fallback if we only have the dataURL
172
233
  const photoFile = dataUrlToFile(propertyDetails.buildingPhoto, "building_photo.jpg");
173
234
  buildingImageFileStoreId = await uploadFile(photoFile, tenantId);
174
235
  }
175
236
 
176
- // ── 3. Build request payload ───────────────────────────────────────────
237
+ // ── 3. Upload door photo ──────────────────────────────────────────────
238
+ let doorPhotoFileStoreId = addressDetails.doorPhotoFileStoreId || null;
239
+ if (!doorPhotoFileStoreId && addressDetails.doorPhoto) {
240
+ const doorFile = dataUrlToFile(addressDetails.doorPhoto, "door_photo.jpg");
241
+ doorPhotoFileStoreId = await uploadFile(doorFile, tenantId);
242
+ }
243
+
244
+ // ── 4. Build optimized request payload ────────────────────────────────
245
+ // Note: RequestInfo is added automatically by the Digit Request utility
177
246
  const requestBody = {
178
- RequestInfo: {
179
- apiId: "Rainmaker",
180
- ver: "1.0",
181
- msgId: `${Date.now()}|${navigator.language || "en_IN"}`,
182
- tenantId,
183
- authToken: userInfo.access_token || Digit.UserService.getUser()?.access_token || "",
184
- },
185
247
  updateType: "PROPERTY",
186
248
  kno: kNumber,
187
249
  pidNumber: propertyDetails.pidNumber || null,
@@ -192,30 +254,50 @@ const Review = () => {
192
254
  typeOfConnection: propertyDetails.connectionCategory?.value || null,
193
255
  connectionCategory: propertyDetails.connectionType?.value || null,
194
256
  modifiedBy: userInfo.name || userInfo.userName || null,
257
+ mobileNumber: aadhaarDetails.mobileNumber || null,
258
+ email: aadhaarDetails.email || null,
259
+ userName: aadhaarDetails.userName || null,
260
+ noOfPersons: aadhaarDetails.noOfPersons || null,
261
+ doorPhotoFileStoreId: doorPhotoFileStoreId,
262
+ fullAddress: addressDetails.fullAddress || null,
263
+ flatNo: addressDetails.flatNo || null,
264
+ building: addressDetails.building || null,
265
+ landmark: addressDetails.landmark || null,
266
+ pincode: addressDetails.pincode || null,
267
+ assembly: addressDetails.assembly || null,
268
+ ward: addressDetails.ward || null,
195
269
  };
196
270
 
197
- // ── 4. Call the update API ─────────────────────────────────────────────
198
- await Digit.CustomService.getResponse({
199
- url: "/ekyc-service/user/application/_update",
200
- params: { tenantId },
201
- body: requestBody,
202
- useCache: false,
203
- method: "POST",
271
+ // ── 4. Call the update API using the new Hook ──────────────────────────
272
+ mutate(requestBody, {
273
+ onSuccess: (res) => {
274
+ setToast({ type: "success", message: t("EKYC_SUBMIT_SUCCESS") || "Application submitted successfully!" });
275
+
276
+ // Cleanup sessionStorage on success
277
+ Object.keys(sessionStorage).forEach(key => {
278
+ if (key.startsWith("EKYC_")) sessionStorage.removeItem(key);
279
+ });
280
+
281
+ setTimeout(() => {
282
+ history.push("/digit-ui/employee/ekyc/dashboard");
283
+ }, 1800);
284
+ },
285
+ onError: (err) => {
286
+ console.error("eKYC Submit Error:", err);
287
+ setToast({
288
+ type: "error",
289
+ message: err?.response?.data?.Errors?.[0]?.message ||
290
+ t("EKYC_SUBMIT_ERROR") || "Submission failed. Please try again.",
291
+ });
292
+ }
204
293
  });
205
294
 
206
- setToast({ type: "success", message: t("EKYC_SUBMIT_SUCCESS") || "Application submitted successfully!" });
207
- setTimeout(() => {
208
- history.push("/digit-ui/employee/ekyc/dashboard");
209
- }, 1800);
210
295
  } catch (err) {
211
- console.error("eKYC Submit Error:", err);
296
+ console.error("eKYC Frontend Error:", err);
212
297
  setToast({
213
298
  type: "error",
214
- message: err?.response?.data?.Errors?.[0]?.message ||
215
- t("EKYC_SUBMIT_ERROR") || "Submission failed. Please try again.",
299
+ message: t("EKYC_SUBMIT_ERROR") || "An error occurred during submission.",
216
300
  });
217
- } finally {
218
- setIsSubmitting(false);
219
301
  }
220
302
  };
221
303
 
@@ -232,210 +314,216 @@ const Review = () => {
232
314
  };
233
315
 
234
316
  return (
235
- <Fragment>
236
- <div className="inbox-container">
237
- <style>{`
317
+ <div className="ground-container employee-app-container form-container">
318
+
319
+ <Fragment>
320
+ <div className="inbox-container">
321
+ <style>{`
238
322
  @keyframes fadeSlideIn {
239
323
  from { opacity: 0; transform: translateY(8px); }
240
324
  to { opacity: 1; transform: translateY(0); }
241
325
  }
242
326
  `}</style>
243
327
 
244
- {/* ── Sidebar ── */}
245
- <div className="filters-container">
246
- <Card style={{ display: "flex", alignItems: "center", padding: "12px 16px", marginBottom: "12px", borderRadius: "8px" }}>
247
- <div style={{ color: "#185FA5", marginRight: "10px", display: "flex" }}>
248
- <HomeIcon style={{ width: "20px", height: "20px" }} />
249
- </div>
250
- <div style={{ fontWeight: "600", fontSize: "15px", color: "#0B0C0C" }}>
251
- {t("EKYC_PROCESS") || "eKYC Process"}
328
+ {/* ── Sidebar ── */}
329
+ <div className="filters-container">
330
+ <Card style={{ display: "flex", alignItems: "center", padding: "12px 16px", marginBottom: "12px", borderRadius: "8px" }}>
331
+ <div style={{ color: "#185FA5", marginRight: "10px", display: "flex" }}>
332
+ <HomeIcon style={{ width: "20px", height: "20px" }} />
333
+ </div>
334
+ <div style={{ fontWeight: "600", fontSize: "15px", color: "#0B0C0C" }}>
335
+ {t("EKYC_PROCESS") || "eKYC Process"}
336
+ </div>
337
+ </Card>
338
+
339
+ <div style={{ background: "#fff", padding: "16px 14px", borderRadius: "8px", border: "1px solid #EAECF0" }}>
340
+ {[
341
+ { label: t("EKYC_STEP_AADHAAR") || "Aadhaar", done: true, active: false },
342
+ { label: t("EKYC_STEP_ADDRESS") || "Address", done: true, active: false },
343
+ { label: t("EKYC_STEP_PROPERTY") || "Property", done: true, active: false },
344
+ { label: t("EKYC_STEP_REVIEW") || "Review", done: false, active: true },
345
+ ].map((step, i) => (
346
+ <div key={i} style={{
347
+ display: "flex", gap: "10px", alignItems: "flex-start",
348
+ position: "relative", paddingBottom: i < 3 ? "18px" : 0,
349
+ }}>
350
+ {i < 3 && (
351
+ <div style={{
352
+ position: "absolute", left: "10px", top: "22px",
353
+ width: "1px", height: "calc(100% - 10px)", background: "#EAECF0",
354
+ }} />
355
+ )}
356
+ <div style={{
357
+ width: "20px", height: "20px", borderRadius: "50%", flexShrink: 0, marginTop: "1px",
358
+ border: step.done ? "none" : step.active ? "1.5px solid #185FA5" : "1.5px solid #D0D5DD",
359
+ background: step.done ? "#0F6E56" : step.active ? "#E6F1FB" : "#fff",
360
+ display: "flex", alignItems: "center", justifyContent: "center",
361
+ fontSize: "10px", fontWeight: "500",
362
+ color: step.done ? "#fff" : step.active ? "#185FA5" : "#98A2B3",
363
+ }}>
364
+ {step.done ? <CheckIcon size={11} color="#fff" /> : i + 1}
365
+ </div>
366
+ <div style={{
367
+ fontSize: "12px", paddingTop: "2px",
368
+ color: step.done ? "#0F6E56" : step.active ? "#0B0C0C" : "#667085",
369
+ fontWeight: step.done || step.active ? "600" : "400",
370
+ }}>
371
+ {step.label}
372
+ </div>
373
+ </div>
374
+ ))}
375
+ </div>
252
376
  </div>
253
- </Card>
254
-
255
- <div style={{ background: "#fff", padding: "16px 14px", borderRadius: "8px", border: "1px solid #EAECF0" }}>
256
- {[
257
- { label: t("EKYC_STEP_AADHAAR") || "Aadhaar", done: true, active: false },
258
- { label: t("EKYC_STEP_ADDRESS") || "Address", done: true, active: false },
259
- { label: t("EKYC_STEP_PROPERTY") || "Property", done: true, active: false },
260
- { label: t("EKYC_STEP_REVIEW") || "Review", done: false, active: true },
261
- ].map((step, i) => (
262
- <div key={i} style={{
263
- display: "flex", gap: "10px", alignItems: "flex-start",
264
- position: "relative", paddingBottom: i < 3 ? "18px" : 0,
265
- }}>
266
- {i < 3 && (
377
+
378
+ {/* ── Main Content ── */}
379
+ <div style={{ flex: 1, marginLeft: "16px" }}>
380
+ <Card>
381
+
382
+ {/* Page header */}
383
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }}>
384
+ <CardHeader style={{ margin: 0, fontSize: "18px" }}>
385
+ {t("EKYC_REVIEW_DETAILS") || "Review Details"}
386
+ </CardHeader>
267
387
  <div style={{
268
- position: "absolute", left: "10px", top: "22px",
269
- width: "1px", height: "calc(100% - 10px)", background: "#EAECF0",
270
- }} />
271
- )}
272
- <div style={{
273
- width: "20px", height: "20px", borderRadius: "50%", flexShrink: 0, marginTop: "1px",
274
- border: step.done ? "none" : step.active ? "1.5px solid #185FA5" : "1.5px solid #D0D5DD",
275
- background: step.done ? "#0F6E56" : step.active ? "#E6F1FB" : "#fff",
276
- display: "flex", alignItems: "center", justifyContent: "center",
277
- fontSize: "10px", fontWeight: "500",
278
- color: step.done ? "#fff" : step.active ? "#185FA5" : "#98A2B3",
279
- }}>
280
- {step.done ? <CheckIcon size={11} color="#fff" /> : i + 1}
388
+ background: "#F9FAFB", border: "0.5px solid #EAECF0",
389
+ borderRadius: "20px", padding: "4px 14px",
390
+ fontSize: "12px", color: "#667085",
391
+ }}>
392
+ {t("EKYC_K_NUMBER") || "K Number"}:{" "}
393
+ <span style={{ color: "#0B0C0C", fontWeight: "600" }}>{kNumber}</span>
394
+ </div>
281
395
  </div>
396
+
397
+ {/* Confirmation banner */}
282
398
  <div style={{
283
- fontSize: "12px", paddingTop: "2px",
284
- color: step.done ? "#0F6E56" : step.active ? "#0B0C0C" : "#667085",
285
- fontWeight: step.done || step.active ? "600" : "400",
399
+ backgroundColor: "#E1F5EE", border: "0.5px solid #5DCAA5",
400
+ borderRadius: "8px", padding: "12px 16px",
401
+ display: "flex", alignItems: "center", gap: "10px",
402
+ marginBottom: "24px",
286
403
  }}>
287
- {step.label}
404
+ <div style={{ backgroundColor: "#9FE1CB", padding: "5px", borderRadius: "6px", display: "flex", flexShrink: 0 }}>
405
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#085041" strokeWidth="3" strokeLinecap="round">
406
+ <polyline points="20 6 9 17 4 12" />
407
+ </svg>
408
+ </div>
409
+ <div style={{ fontSize: "13px", color: "#04342C", fontWeight: "500" }}>
410
+ {t("EKYC_REVIEW_NOTICE") || "Please review all details carefully before submitting. You can edit any section by clicking Edit."}
411
+ </div>
288
412
  </div>
289
- </div>
290
- ))}
291
- </div>
292
- </div>
293
-
294
- {/* ── Main Content ── */}
295
- <div style={{ flex: 1, marginLeft: "16px" }}>
296
- <Card>
297
413
 
298
- {/* Page header */}
299
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }}>
300
- <CardHeader style={{ margin: 0, fontSize: "18px" }}>
301
- {t("EKYC_REVIEW_DETAILS") || "Review Details"}
302
- </CardHeader>
303
- <div style={{
304
- background: "#F9FAFB", border: "0.5px solid #EAECF0",
305
- borderRadius: "20px", padding: "4px 14px",
306
- fontSize: "12px", color: "#667085",
307
- }}>
308
- {t("EKYC_K_NUMBER") || "K Number"}:{" "}
309
- <span style={{ color: "#0B0C0C", fontWeight: "600" }}>{kNumber}</span>
310
- </div>
311
- </div>
414
+ <div style={{ animation: "fadeSlideIn 0.3s ease" }}>
415
+
416
+ {/* ── Aadhaar section head ── */}
417
+ <SectionHead
418
+ icon={<PersonIcon size={16} />}
419
+ label={t("EKYC_AADHAAR_VERIFICATION_HEADER") || "Aadhaar details"}
420
+ />
421
+
422
+ <ReviewCard
423
+ icon={<PersonIcon size={16} />}
424
+ title={t("EKYC_AADHAAR_VERIFICATION_HEADER") || "Aadhaar details"}
425
+ onEdit={handleEditAadhaar}
426
+ editLabel={t("CS_COMMON_EDIT") || "Edit"}
427
+ t={t}
428
+ rows={[
429
+ { label: t("EKYC_NAME") || "Name", value: aadhaarDetails.userName || "Rajesh Kumar Singh", isModified: isFieldModified("userName", aadhaarDetails.userName) },
430
+ { label: t("EKYC_AADHAAR") || "Aadhaar no.", value: aadhaarDetails.aadhaarLastFour ? `${aadhaarDetails.aadhaarLastFour}` : "XXXX XXXX 1234" },
431
+ { label: t("EKYC_MOBILE_NO") || "Mobile no.", value: aadhaarDetails.mobileNumber || "XXXXXXXXXX", isModified: isFieldModified("mobileNumber", aadhaarDetails.mobileNumber) },
432
+ { label: t("EKYC_EMAIL_ADDRESS") || "Email", value: aadhaarDetails.email || null, isModified: isFieldModified("email", aadhaarDetails.email) },
433
+ ]}
434
+ />
435
+
436
+ <hr style={{ margin: "20px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
437
+
438
+ {/* ── Address section head ── */}
439
+ <SectionHead
440
+ icon={<LocationIcon2 size={16} />}
441
+ label={t("EKYC_ADDRESS_DETAILS_HEADER") || "Address details"}
442
+ />
443
+
444
+ <ReviewCard
445
+ icon={<LocationIcon2 size={16} />}
446
+ title={t("EKYC_ADDRESS_DETAILS_HEADER") || "Address details"}
447
+ onEdit={handleEditAddress}
448
+ editLabel={t("CS_COMMON_EDIT") || "Edit"}
449
+ t={t}
450
+ rows={[
451
+ { label: t("EKYC_FULL_ADDRESS") || "Full address", value: addressDetails.fullAddress || "H.No. 123, Sector 15, Rohini, Delhi – 110085", isModified: isFieldModified("fullAddress", addressDetails.fullAddress) },
452
+ { label: t("EKYC_FLAT_HOUSE_NUMBER") || "Flat / House no.", value: addressDetails.flatNo || null, isModified: isFieldModified("flatNo", addressDetails.flatNo) },
453
+ { label: t("EKYC_BUILDING_TOWER") || "Building", value: addressDetails.building || null, isModified: isFieldModified("building", addressDetails.building) },
454
+ { label: t("EKYC_LANDMARK") || "Landmark", value: addressDetails.landmark || null, isModified: isFieldModified("landmark", addressDetails.landmark) },
455
+ { label: t("EKYC_PINCODE") || "Pincode", value: addressDetails.pincode || "110085", isModified: isFieldModified("pincode", addressDetails.pincode) },
456
+ { label: t("EKYC_ASSEMBLY") || "Assembly", value: addressDetails.assembly || "AC-12 Chandni Chowk", isModified: isFieldModified("assembly", addressDetails.assembly) },
457
+ { label: t("EKYC_WARD") || "Ward", value: addressDetails.ward || "WARD-45 Civil Lines", isModified: isFieldModified("ward", addressDetails.ward) },
458
+ ]}
459
+ />
460
+
461
+ <hr style={{ margin: "20px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
462
+
463
+ {/* ── Property section head ── */}
464
+ <SectionHead
465
+ icon={<BuildingIcon size={16} />}
466
+ label={t("EKYC_PROPERTY_INFO") || "Property details"}
467
+ />
468
+
469
+ <ReviewCard
470
+ icon={<BuildingIcon size={16} />}
471
+ title={t("EKYC_PROPERTY_INFO") || "Property details"}
472
+ onEdit={handleEditProperty}
473
+ editLabel={t("CS_COMMON_EDIT") || "Edit"}
474
+ t={t}
475
+ rows={[
476
+ { label: t("EKYC_PROPERTY_OWNER") || "Property owner", value: propertyDetails.ownerType || "Owner" },
477
+ { label: t("EKYC_PID_NUMBER") || "PID number", value: propertyDetails.pidNumber || null, isModified: isFieldModified("pidNumber", propertyDetails.pidNumber) },
478
+ { label: t("EKYC_TYPE_OF_CONNECTION") || "Type of connection", value: propertyDetails.connectionCategory?.label || null, isModified: isFieldModified("typeOfConnection", propertyDetails.connectionCategory?.value) },
479
+ { label: t("EKYC_CONNECTION_CATEGORY") || "Connection category", value: propertyDetails.connectionType?.label || null, isModified: isFieldModified("connectionCategory", propertyDetails.connectionType?.value) },
480
+ { label: t("EKYC_USER_TYPE") || "User type", value: propertyDetails.userType?.label || null, isModified: isFieldModified("userType", propertyDetails.userType?.value) },
481
+ { label: t("EKYC_NO_OF_FLOORS") || "No. of floors", value: propertyDetails.noOfFloors?.label || null, isModified: isFieldModified("noOfFloor", propertyDetails.noOfFloors?.value) },
482
+ ]}
483
+ />
312
484
 
313
- {/* Confirmation banner */}
314
- <div style={{
315
- backgroundColor: "#E1F5EE", border: "0.5px solid #5DCAA5",
316
- borderRadius: "8px", padding: "12px 16px",
317
- display: "flex", alignItems: "center", gap: "10px",
318
- marginBottom: "24px",
319
- }}>
320
- <div style={{ backgroundColor: "#9FE1CB", padding: "5px", borderRadius: "6px", display: "flex", flexShrink: 0 }}>
321
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#085041" strokeWidth="3" strokeLinecap="round">
322
- <polyline points="20 6 9 17 4 12" />
323
- </svg>
324
- </div>
325
- <div style={{ fontSize: "13px", color: "#04342C", fontWeight: "500" }}>
326
- {t("EKYC_REVIEW_NOTICE") || "Please review all details carefully before submitting. You can edit any section by clicking Edit."}
327
- </div>
328
- </div>
329
-
330
- <div style={{ animation: "fadeSlideIn 0.3s ease" }}>
331
-
332
- {/* ── Aadhaar section head ── */}
333
- <SectionHead
334
- icon={<PersonIcon size={16} />}
335
- label={t("EKYC_AADHAAR_VERIFICATION_HEADER") || "Aadhaar details"}
336
- />
337
-
338
- <ReviewCard
339
- icon={<PersonIcon size={16} />}
340
- title={t("EKYC_AADHAAR_VERIFICATION_HEADER") || "Aadhaar details"}
341
- onEdit={handleEditAadhaar}
342
- editLabel={t("CS_COMMON_EDIT") || "Edit"}
343
- rows={[
344
- { label: t("EKYC_NAME") || "Name", value: aadhaarDetails.userName || "Rajesh Kumar Singh" },
345
- { label: t("EKYC_AADHAAR") || "Aadhaar no.", value: aadhaarDetails.aadhaarLastFour ? `${aadhaarDetails.aadhaarLastFour}` : "XXXX XXXX 1234" },
346
- { label: t("EKYC_MOBILE_NO") || "Mobile no.", value: aadhaarDetails.mobileNumber || "XXXXXXXXXX" },
347
- { label: t("EKYC_EMAIL_ADDRESS") || "Email", value: aadhaarDetails.email || null },
348
- ]}
349
- />
350
-
351
- <hr style={{ margin: "20px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
352
-
353
- {/* ── Address section head ── */}
354
- <SectionHead
355
- icon={<LocationIcon2 size={16} />}
356
- label={t("EKYC_ADDRESS_DETAILS_HEADER") || "Address details"}
357
- />
358
-
359
- <ReviewCard
360
- icon={<LocationIcon2 size={16} />}
361
- title={t("EKYC_ADDRESS_DETAILS_HEADER") || "Address details"}
362
- onEdit={handleEditAddress}
363
- editLabel={t("CS_COMMON_EDIT") || "Edit"}
364
- rows={[
365
- { label: t("EKYC_FULL_ADDRESS") || "Full address", value: addressDetails.fullAddress || "H.No. 123, Sector 15, Rohini, Delhi – 110085" },
366
- { label: t("EKYC_FLAT_HOUSE_NUMBER") || "Flat / House no.", value: addressDetails.flatNo || null },
367
- { label: t("EKYC_BUILDING_TOWER") || "Building", value: addressDetails.building || null },
368
- { label: t("EKYC_LANDMARK") || "Landmark", value: addressDetails.landmark || null },
369
- { label: t("EKYC_PINCODE") || "Pincode", value: addressDetails.pincode || "110085" },
370
- { label: t("EKYC_ASSEMBLY") || "Assembly", value: addressDetails.assembly || "AC-12 Chandni Chowk" },
371
- { label: t("EKYC_WARD") || "Ward", value: addressDetails.ward || "WARD-45 Civil Lines" },
372
- ]}
373
- />
374
-
375
- <hr style={{ margin: "20px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
376
-
377
- {/* ── Property section head ── */}
378
- <SectionHead
379
- icon={<BuildingIcon size={16} />}
380
- label={t("EKYC_PROPERTY_INFO") || "Property details"}
381
- />
382
-
383
- <ReviewCard
384
- icon={<BuildingIcon size={16} />}
385
- title={t("EKYC_PROPERTY_INFO") || "Property details"}
386
- onEdit={handleEditProperty}
387
- editLabel={t("CS_COMMON_EDIT") || "Edit"}
388
- rows={[
389
- { label: t("EKYC_PROPERTY_OWNER") || "Property owner", value: propertyDetails.ownerType || "Owner" },
390
- { label: t("EKYC_PID_NUMBER") || "PID number", value: propertyDetails.pidNumber || null },
391
- { label: t("EKYC_TYPE_OF_CONNECTION") || "Type of connection", value: propertyDetails.connectionCategory?.label || null },
392
- { label: t("EKYC_CONNECTION_CATEGORY") || "Connection category", value: propertyDetails.connectionType?.label || null },
393
- { label: t("EKYC_USER_TYPE") || "User type", value: propertyDetails.userType?.label || null },
394
- { label: t("EKYC_NO_OF_FLOORS") || "No. of floors", value: propertyDetails.noOfFloors?.label || null },
395
- ]}
396
- />
485
+ </div>
397
486
 
398
- </div>
487
+ {/* Submit (Non-sticky, at form end) */}
488
+ <div style={{ marginTop: "24px" }}>
489
+ <SubmitBar
490
+ label={isSubmitting
491
+ ? (t("EKYC_SUBMITTING") || "Submitting...")
492
+ : (t("ES_COMMON_SUBMIT") || "Submit")
493
+ }
494
+ onSubmit={handleSubmit}
495
+ disabled={isSubmitting}
496
+ />
497
+ </div>
399
498
 
400
- {/* Submit (Non-sticky, at form end) */}
401
- <div style={{ marginTop: "24px" }}>
402
- <SubmitBar
403
- label={isSubmitting
404
- ? (t("EKYC_SUBMITTING") || "Submitting...")
405
- : (t("ES_COMMON_SUBMIT") || "Submit")
406
- }
407
- onSubmit={handleSubmit}
408
- disabled={isSubmitting}
409
- />
410
- </div>
499
+ {/* Secure notice */}
500
+ <div style={{
501
+ display: "flex", alignItems: "center", justifyContent: "center",
502
+ gap: "5px", marginTop: "16px",
503
+ fontSize: "11px", color: "#98A2B3",
504
+ }}>
505
+ <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
506
+ <rect x="3" y="11" width="18" height="11" rx="2" />
507
+ <path d="M7 11V7a5 5 0 0 1 10 0v4" />
508
+ </svg>
509
+ {t("EKYC_SECURE_DATA_NOTICE") || "Your data is encrypted and secure"}
510
+ </div>
411
511
 
412
- {/* Secure notice */}
413
- <div style={{
414
- display: "flex", alignItems: "center", justifyContent: "center",
415
- gap: "5px", marginTop: "16px",
416
- fontSize: "11px", color: "#98A2B3",
417
- }}>
418
- <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
419
- <rect x="3" y="11" width="18" height="11" rx="2" />
420
- <path d="M7 11V7a5 5 0 0 1 10 0v4" />
421
- </svg>
422
- {t("EKYC_SECURE_DATA_NOTICE") || "Your data is encrypted and secure"}
512
+ </Card>
423
513
  </div>
514
+ </div>
424
515
 
425
- </Card>
426
- </div>
516
+ {/* Toast notification */}
517
+ {toast && (
518
+ <Toast
519
+ label={toast.message}
520
+ error={toast.type === "error"}
521
+ success={toast.type === "success"}
522
+ onClose={() => setToast(null)}
523
+ />
524
+ )}
525
+ </Fragment>
427
526
  </div>
428
-
429
- {/* Toast notification */}
430
- {toast && (
431
- <Toast
432
- label={toast.message}
433
- error={toast.type === "error"}
434
- success={toast.type === "success"}
435
- onClose={() => setToast(null)}
436
- />
437
- )}
438
- </Fragment>
439
527
  );
440
528
  };
441
529