@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.
@@ -16,9 +16,12 @@ import {
16
16
  CheckPoint,
17
17
  Dropdown,
18
18
  Loader,
19
+ UploadFile,
20
+ Toast,
19
21
  } from "@djb25/digit-ui-react-components";
20
22
  import { useTranslation } from "react-i18next";
21
23
  import { useHistory, useLocation } from "react-router-dom";
24
+ import { getPayloadDiff, getSavedData } from "../../utils";
22
25
 
23
26
  // ─── Icons ────────────────────────────────────────────────────────────────────
24
27
 
@@ -151,18 +154,76 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
151
154
  kNumber: "EKYC-1234567890",
152
155
  selectedOption: { code: "SELF", name: "EKYC_SELF" },
153
156
  connectionDetails: null,
157
+ initialData: {},
154
158
  };
155
159
 
160
+ const initialData = flowState.initialData || {};
161
+
156
162
  const addrDetails = flowState.connectionDetails?.addressDetails || {};
157
163
 
158
- const [addressType, setAddressType] = useState({ code: "AADHAAR", name: "EKYC_AADHAAR_ADDRESS" });
159
- const [correctAddress, setCorrectAddress] = useState({ code: "NO", name: "CORE_COMMON_NO" });
160
- const [fullAddress, setFullAddress] = useState(addrDetails.fullAddress || "");
161
- const [flatNo, setFlatNo] = useState(addrDetails.flatHouseNumber || "");
162
- const [building, setBuilding] = useState(addrDetails.buildingTower || "");
163
- const [landmark, setLandmark] = useState(addrDetails.landmark || "");
164
- const [pincode, setPincode] = useState(addrDetails.pinCode || "");
165
- const [doorPhoto, setDoorPhoto] = useState(null);
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);
176
+ const [toast, setToast] = useState(null);
177
+
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
+ };
197
+
198
+ 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
+ }
223
+ }
224
+ }
225
+ })();
226
+ }, [filephoto]);
166
227
  const [isLocationFetching, setIsLocationFetching] = useState(false);
167
228
  const fileInputRef = useRef(null);
168
229
 
@@ -174,11 +235,11 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
174
235
  );
175
236
 
176
237
  const mdmsRes = mdmsData?.MdmsRes || mdmsData;
177
- const adminHierarchy = mdmsRes?.["egov-location"]?.TenantBoundary?.find(h => h.hierarchyType.code === "ADMIN")
238
+ const adminHierarchy = mdmsRes?.["egov-location"]?.TenantBoundary?.find(h => h.hierarchyType.code === "ADMIN")
178
239
  || mdmsRes?.["egov-location"]?.TenantBoundary?.[0];
179
-
240
+
180
241
  const rootBoundary = adminHierarchy?.boundary;
181
-
242
+
182
243
  const getAssemblies = (boundaries) => {
183
244
  if (!boundaries) return [];
184
245
  let assemblies = [];
@@ -213,8 +274,14 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
213
274
 
214
275
  const assemblies = getAssemblies(Array.isArray(rootBoundary) ? rootBoundary : rootBoundary ? [rootBoundary] : []);
215
276
 
216
- const [assembly, setAssembly] = useState(addrDetails.assembly ? { name: addrDetails.assembly } : null);
217
- const [ward, setWard] = useState(addrDetails.ward ? { name: addrDetails.ward } : null);
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]);
218
285
 
219
286
  useEffect(() => {
220
287
  if (mdmsRes && addrDetails.assembly && !assembly?.code) {
@@ -242,38 +309,37 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
242
309
  ];
243
310
 
244
311
  const handleCompleteVerification = () => {
245
- const payload = {
246
- addressType,
247
- fullAddress,
248
- flatNo,
249
- building,
250
- landmark,
251
- pincode,
312
+ const payload = {
313
+ addressType,
314
+ fullAddress,
315
+ flatNo,
316
+ building,
317
+ landmark,
318
+ pincode,
252
319
  doorPhoto,
320
+ doorPhotoFileStoreId,
253
321
  assembly: assembly?.name,
254
322
  ward: ward?.name
255
323
  };
256
324
  if (onComplete) {
257
325
  onComplete(payload);
258
326
  } else {
259
- const { kNumber, selectedOption, connectionDetails } = flowState;
327
+ const { kNumber, selectedOption, connectionDetails, initialData } = flowState;
260
328
  history.push("/digit-ui/employee/ekyc/property-info", {
261
- kNumber, selectedOption, connectionDetails, addressDetails: payload,
329
+ kNumber, selectedOption, connectionDetails, addressDetails: payload, initialData
262
330
  });
263
331
  }
264
332
  };
265
333
 
266
- const handleCapture = (e) => {
267
- const file = e.target.files[0];
268
- if (!file) return;
269
- const reader = new FileReader();
270
- reader.onloadend = () => setDoorPhoto(reader.result);
271
- reader.readAsDataURL(file);
272
- };
334
+ function selectphoto(e) {
335
+ setDoorPhotoFileStoreId(null);
336
+ setFilephoto(e.target.files[0]);
337
+ }
273
338
 
274
339
  const removePhoto = () => {
275
340
  setDoorPhoto(null);
276
- if (fileInputRef.current) fileInputRef.current.value = "";
341
+ setDoorPhotoFileStoreId(null);
342
+ setFilephoto(null);
277
343
  };
278
344
 
279
345
  const handleUseCurrentLocation = () => {
@@ -530,14 +596,14 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
530
596
  {/* ── Door Photo ── */}
531
597
  <SectionHead
532
598
  icon={<CameraIcon size={16} />}
533
- label={t("EKYC_DOOR_PHOTO_HEADER")}
599
+ label={t("EKYC_CAPTURE_DOOR_IMAGE")}
534
600
  />
535
601
 
536
602
  <div style={{ fontSize: "12px", color: "#667085", marginBottom: "12px" }}>
537
603
  {t("EKYC_REQUIRED_FOR_VERIFICATION")}
538
604
  </div>
539
605
 
540
- {/* Warning banner */}
606
+ {/* Warning banner
541
607
  <div style={{
542
608
  backgroundColor: "#FFFAEB",
543
609
  border: "0.5px solid #FEDF89",
@@ -559,80 +625,29 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
559
625
  {t("EKYC_CAPTURE_LIVE_CAMERA")}
560
626
  </div>
561
627
  </div>
562
- </div>
563
-
564
- {/* Drop zone */}
565
- <input
566
- type="file"
567
- ref={fileInputRef}
568
- onChange={handleCapture}
569
- accept="image/*"
570
- style={{ display: "none" }}
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}
571
639
  />
572
- <div
573
- onClick={!doorPhoto ? () => fileInputRef.current.click() : undefined}
574
- onMouseOver={(e) => { if (!doorPhoto) e.currentTarget.style.borderColor = "#185FA5"; }}
575
- onMouseOut={(e) => { if (!doorPhoto) e.currentTarget.style.borderColor = "#D0D5DD"; }}
576
- style={{
577
- border: "1.5px dashed #D0D5DD",
578
- borderRadius: "10px",
579
- minHeight: "160px",
580
- display: "flex",
581
- flexDirection: "column",
582
- alignItems: "center",
583
- justifyContent: "center",
584
- backgroundColor: "#F9FAFB",
585
- cursor: doorPhoto ? "default" : "pointer",
586
- overflow: "hidden",
587
- transition: "border-color 0.15s",
588
- position: "relative",
589
- padding: doorPhoto ? "0" : "32px 24px",
590
- }}
591
- >
592
- {!doorPhoto ? (
593
- <>
594
- <div style={{
595
- width: "52px", height: "52px", borderRadius: "50%",
596
- background: "#E6F1FB", display: "flex",
597
- alignItems: "center", justifyContent: "center", marginBottom: "12px",
598
- }}>
599
- <CameraIcon size={26} />
600
- </div>
601
- <div style={{ fontWeight: "600", fontSize: "14px", color: "#101828", marginBottom: "4px" }}>
602
- {t("EKYC_TAP_TO_CAPTURE") || "Tap to capture"}
603
- </div>
604
- <div style={{ fontSize: "12px", color: "#667085" }}>
605
- {t("EKYC_CAPTURE_DOOR_IMAGE")}
606
- </div>
607
- </>
608
- ) : (
609
- <>
610
- <img
611
- src={doorPhoto}
612
- alt="Door"
613
- style={{ width: "100%", maxHeight: "280px", objectFit: "cover", display: "block" }}
614
- />
615
- <button
616
- onClick={(e) => { e.stopPropagation(); removePhoto(); }}
617
- style={{
618
- position: "absolute", top: "10px", right: "10px",
619
- background: "#fff", border: "0.5px solid #EAECF0",
620
- borderRadius: "7px", padding: "6px 10px",
621
- display: "flex", alignItems: "center", gap: "5px",
622
- cursor: "pointer", fontSize: "12px", color: "#D92D20", fontWeight: "500",
623
- }}
624
- >
625
- <TrashIcon size={13} /> {t("EKYC_REMOVE")}
626
- </button>
627
- </>
628
- )}
629
- </div>
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
+ )}
630
645
 
631
646
  {/* Submit */}
632
647
  {isSection ? (
633
648
  <div style={{ marginTop: "24px" }}>
634
649
  <SubmitBar
635
- label={t("EKYC_COMPLETE_VERIFICATION_AND_PROCEED")}
650
+ label={t("ES_COMMON_SAVE_CONTINUE")}
636
651
  onSubmit={handleCompleteVerification}
637
652
  />
638
653
  </div>
@@ -657,6 +672,15 @@ const AddressDetails = ({ isSection = false, onComplete, parentState }) => {
657
672
  </svg>
658
673
  {t("EKYC_SECURE_DATA_NOTICE")}
659
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
+ )}
660
684
  </div>
661
685
  );
662
686
 
@@ -45,8 +45,18 @@ const Create = () => {
45
45
  }
46
46
  setSearchParams(params);
47
47
  setSearchPerformed(true);
48
+
49
+ // Clear previous EKYC session data if K-number changes
50
+ const currentKno = sessionStorage.getItem("EKYC_K_NUMBER");
51
+ if (currentKno !== params.kNumber) {
52
+ Object.keys(sessionStorage).forEach(key => {
53
+ if (key.startsWith("EKYC_")) sessionStorage.removeItem(key);
54
+ });
55
+ }
56
+
48
57
  sessionStorage.setItem("EKYC_CREATE_SEARCH_PARAMS", JSON.stringify(params));
49
58
  sessionStorage.setItem("EKYC_CREATE_SEARCH_PERFORMED", "true");
59
+ sessionStorage.setItem("EKYC_K_NUMBER", params.kNumber);
50
60
  };
51
61
 
52
62
  const closeToast = () => {
@@ -54,26 +64,28 @@ const Create = () => {
54
64
  };
55
65
 
56
66
  return (
57
- <SearchConsumer
58
- onSearch={handleSearch}
59
- searchParams={searchParams}
60
- >
61
- {searchPerformed && (
62
- <ConnectionDetailsView
63
- kNumber={searchParams.kNumber}
64
- kName={searchParams.kName}
65
- connectionDetails={connectionDetails}
66
- isLoading={isSearching}
67
- />
68
- )}
67
+ <div class="ground-container employee-app-container form-container">
68
+ <SearchConsumer
69
+ onSearch={handleSearch}
70
+ searchParams={searchParams}
71
+ >
72
+ {searchPerformed && (
73
+ <ConnectionDetailsView
74
+ kNumber={searchParams.kNumber}
75
+ kName={searchParams.kName}
76
+ connectionDetails={connectionDetails}
77
+ isLoading={isSearching}
78
+ />
79
+ )}
69
80
 
70
- {!searchPerformed && !isSearching && (
71
- <Card style={{ textAlign: "center", padding: "40px" }}>
72
- <div style={{ color: "#667085" }}>{t("EKYC_SEARCH_TO_VIEW_DETAILS")}</div>
73
- </Card>
74
- )}
75
- {showToast && <Toast error={showToast.error} label={showToast.label} onClose={closeToast} isDsc={true} />}
76
- </SearchConsumer>
81
+ {!searchPerformed && !isSearching && (
82
+ <Card style={{ textAlign: "center", padding: "40px" }}>
83
+ <div style={{ color: "#667085" }}>{t("EKYC_SEARCH_TO_VIEW_DETAILS")}</div>
84
+ </Card>
85
+ )}
86
+ {showToast && <Toast error={showToast.error} label={showToast.label} onClose={closeToast} isDsc={true} />}
87
+ </SearchConsumer>
88
+ </div>
77
89
  );
78
90
  };
79
91
 
@@ -34,7 +34,6 @@ const Inbox = ({
34
34
  tenantId,
35
35
  offset: pageOffset,
36
36
  limit: pageSize,
37
- status: searchParams.status?.value || ""
38
37
  },
39
38
  {
40
39
  enabled: !!tenantId,
@@ -42,13 +41,20 @@ const Inbox = ({
42
41
  );
43
42
 
44
43
  const filteredData = useMemo(() => {
45
- const items = dashboardData?.dashboardInfo?.consumerList || [];
44
+ let items = dashboardData?.dashboardInfo?.consumerList || [];
45
+
46
+ // Frontend filtering since we no longer send status to API
47
+ const selectedStatus = searchParams.status?.value;
48
+ if (selectedStatus && selectedStatus !== "") {
49
+ items = items.filter(item => item.status === selectedStatus);
50
+ }
51
+
46
52
  return items.map(item => ({
47
53
  ...item,
48
54
  applicationNumber: item.kno || item.applicationNumber,
49
55
  citizenName: item.consumerName || item.citizenName,
50
56
  }));
51
- }, [dashboardData]);
57
+ }, [dashboardData, searchParams.status]);
52
58
 
53
59
  const countData = useMemo(() => {
54
60
  const info = dashboardData?.dashboardInfo || {};
@@ -56,7 +62,8 @@ const Inbox = ({
56
62
  total: info.total || 0,
57
63
  completed: info.completed || 0,
58
64
  pending: info.pending || 0,
59
- rejected: info.rejected || 0
65
+ rejected: info.rejected || 0,
66
+ active: info.active || 0,
60
67
  };
61
68
  }, [dashboardData]);
62
69