@djb25/digit-ui-module-ekyc 1.0.30 → 1.0.32

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.
Files changed (63) hide show
  1. package/dist/index.js +8911 -1
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.modern.js +3295 -2039
  4. package/dist/index.modern.js.map +1 -1
  5. package/package.json +4 -1
  6. package/dist/index.css +0 -54
  7. package/src/Module.js +0 -78
  8. package/src/components/AadhaarVerification.js +0 -315
  9. package/src/components/AssignEkyc.js +0 -236
  10. package/src/components/AssignEkycModal.js +0 -446
  11. package/src/components/CeoDashboard.js +0 -264
  12. package/src/components/CeoDashboard.jsx +0 -334
  13. package/src/components/ConnectionDetailsView.js +0 -241
  14. package/src/components/Dashboard.js +0 -43
  15. package/src/components/DesktopInbox.js +0 -176
  16. package/src/components/EKYCCard.js +0 -53
  17. package/src/components/Filter.js +0 -55
  18. package/src/components/MeterDetails.js +0 -336
  19. package/src/components/MobileInbox.js +0 -73
  20. package/src/components/PropertyInfo.js +0 -264
  21. package/src/components/Review.js +0 -696
  22. package/src/components/SearchConsumer.js +0 -142
  23. package/src/components/SearchFormFieldsComponent.js +0 -67
  24. package/src/components/SelectEkycZones.js +0 -71
  25. package/src/components/StatusCards.js +0 -148
  26. package/src/components/SurveyorDetailsCard.js +0 -512
  27. package/src/components/VendorDetails.jsx +0 -230
  28. package/src/components/analytics/charts/ClusterHeatmap.js +0 -88
  29. package/src/components/analytics/charts/ExecutiveBarChart.jsx +0 -30
  30. package/src/components/analytics/charts/ExecutiveLineChart.jsx +0 -159
  31. package/src/components/analytics/charts/ExecutivePieChart.jsx +0 -24
  32. package/src/components/analytics/charts/TaskStatusChart.js +0 -90
  33. package/src/components/analytics/components/AnalyticsTable.js +0 -106
  34. package/src/components/analytics/components/DashboardLayout.js +0 -52
  35. package/src/components/analytics/components/EmptyState.js +0 -27
  36. package/src/components/analytics/components/ErrorBoundary.js +0 -27
  37. package/src/components/analytics/components/FilterBar.js +0 -73
  38. package/src/components/analytics/components/NotificationPanel.js +0 -77
  39. package/src/components/analytics/components/SLAWidget.js +0 -56
  40. package/src/components/analytics/components/SkeletonLoader.js +0 -53
  41. package/src/components/analytics/components/SummaryCard.js +0 -74
  42. package/src/components/analytics/components/WorkflowTimeline.js +0 -55
  43. package/src/components/analytics/utils/exportUtils.js +0 -64
  44. package/src/components/analytics/utils/filterSerializer.js +0 -50
  45. package/src/components/mockData.js +0 -772
  46. package/src/config/AadhaarVerificationConfig.js +0 -367
  47. package/src/config/MeterDetailsConfig.js +0 -297
  48. package/src/config/PropertyInfoConfig.js +0 -145
  49. package/src/config/config.js +0 -70
  50. package/src/hook/SupervisorInboxTableConfig.js +0 -80
  51. package/src/hook/useInboxTableConfig.js +0 -131
  52. package/src/pages/citizen/Home.js +0 -54
  53. package/src/pages/citizen/Inbox.js +0 -265
  54. package/src/pages/citizen/index.js +0 -199
  55. package/src/pages/employee/ConsumerDetails.js +0 -299
  56. package/src/pages/employee/Create.js +0 -94
  57. package/src/pages/employee/EKYCForm.js +0 -118
  58. package/src/pages/employee/Inbox.js +0 -266
  59. package/src/pages/employee/Mapping.js +0 -358
  60. package/src/pages/employee/Update.js +0 -9
  61. package/src/pages/employee/index.js +0 -184
  62. package/src/utils/index.js +0 -46
  63. package/src/utils/reportDownloader.js +0 -90
@@ -1,696 +0,0 @@
1
- import React, { Fragment, useState } from "react";
2
- import {
3
- Card,
4
- CardSubHeader,
5
- StatusTable,
6
- Row,
7
- SubmitBar,
8
- Loader,
9
- ActionBar,
10
- CheckBox,
11
- LinkButton,
12
- EditIcon,
13
- GenericFileIcon,
14
- Menu,
15
- Toast,
16
- } from "@djb25/digit-ui-react-components";
17
- import { useTranslation } from "react-i18next";
18
- import { useHistory, useLocation, useParams } from "react-router-dom";
19
-
20
- // ─── Constants ───────────────────────────────────────────────────────────────
21
-
22
- const ActionButton = ({ jumpTo, state }) => {
23
- const history = useHistory();
24
- function routeTo() {
25
- history.push(jumpTo, { ...state, isEditing: true });
26
- }
27
- return (
28
- <LinkButton label={<EditIcon style={{ width: "20px", height: "20px", fill: "#F47738" }} />} style={{ margin: 0, padding: 0 }} onClick={routeTo} />
29
- );
30
- };
31
-
32
- const checkForNA = (value) => (value !== null && value !== undefined && value !== "" ? value : "N/A");
33
-
34
- const boolToYesNo = (value, t) => {
35
- if (value === true || value === "true" || String(value).toLowerCase() === "yes") return t("CORE_COMMON_YES");
36
- if (value === false || value === "false" || String(value).toLowerCase() === "no") return t("CORE_COMMON_NO");
37
- if (value === "true") return t("CORE_COMMON_YES");
38
- if (value === "false") return t("CORE_COMMON_NO");
39
- };
40
- /**
41
- * Robust data extraction for comparison.
42
- * The API returns { applicationReviewInfo: { newData: { ... }, oldData: { ... } } }
43
- */
44
- const extractReviewData = (searchData, flowState) => {
45
- const rawData = searchData && Object.keys(searchData).length > 0 ? searchData : flowState?.reviewData || {};
46
-
47
- // Navigate through applicationReviewInfo -> newData/oldData
48
- const reviewWrapper = rawData?.applicationReviewInfo || rawData?.applicationReview || rawData;
49
- const applicationData = (Array.isArray(reviewWrapper) ? reviewWrapper[0] : reviewWrapper) || {};
50
-
51
- return {
52
- newData: applicationData?.newData || applicationData,
53
- oldData: applicationData?.oldData || null,
54
- };
55
- };
56
-
57
- const ReviewSection = ({ title, fields, newData, oldData, t, jumpTo, state }) => {
58
- return (
59
- <div
60
- className="review-section-wrapper"
61
- style={{ marginBottom: "48px", background: "#fff", borderRadius: "12px", border: "1px solid #EAECF0", overflow: "hidden" }}
62
- >
63
- <div
64
- style={{
65
- padding: "20px 24px",
66
- background: "#F9FAFB",
67
- borderBottom: "1px solid #EAECF0",
68
- display: "flex",
69
- justifyContent: "space-between",
70
- alignItems: "center",
71
- }}
72
- >
73
- <CardSubHeader style={{ margin: 0, fontSize: "18px", color: "#101828", fontWeight: "700" }}>{title}</CardSubHeader>
74
- {jumpTo && <ActionButton jumpTo={jumpTo} state={state} />}
75
- </div>
76
-
77
- <div style={{ padding: "0 24px" }}>
78
- <table style={{ width: "100%", borderCollapse: "collapse", tableLayout: "fixed" }}>
79
- <thead>
80
- <tr>
81
- <th
82
- style={{
83
- padding: "16px 0",
84
- textAlign: "left",
85
- color: "#667085",
86
- fontSize: "12px",
87
- fontWeight: "600",
88
- textTransform: "uppercase",
89
- width: "30%",
90
- }}
91
- >
92
- {t("EKYC_FIELD_NAME")}
93
- </th>
94
- <th
95
- style={{
96
- padding: "16px 0",
97
- textAlign: "left",
98
- color: "#667085",
99
- fontSize: "12px",
100
- fontWeight: "600",
101
- textTransform: "uppercase",
102
- width: "35%",
103
- }}
104
- >
105
- {t("EKYC_EXISTING_INFORMATION")}
106
- </th>
107
- <th
108
- style={{
109
- padding: "16px 0",
110
- textAlign: "left",
111
- color: "#667085",
112
- fontSize: "12px",
113
- fontWeight: "600",
114
- textTransform: "uppercase",
115
- width: "35%",
116
- }}
117
- >
118
- {t("EKYC_PROPOSED_UPDATES")}
119
- </th>
120
- </tr>
121
- </thead>
122
- <tbody>
123
- {fields.map((field, idx) => {
124
- const valNew = newData?.[field.key];
125
- const valOld = oldData?.[field.key];
126
- const isChanged = oldData && String(valNew) !== String(valOld) && valOld !== undefined && valOld !== null;
127
-
128
- return (
129
- <tr key={idx} style={{ borderTop: "1px solid #F2F4F7" }}>
130
- <td style={{ padding: "16px 0", fontSize: "14px", color: "#344054", fontWeight: "500" }}>{t(field.label)}</td>
131
- <td style={{ padding: "16px 0", fontSize: "14px", color: "#667085" }}>
132
- {field.isBool ? boolToYesNo(valOld, t) : checkForNA(valOld)}
133
- </td>
134
- <td
135
- style={{ padding: "16px 0", fontSize: "14px", color: isChanged ? "#1B8B32" : "#101828", fontWeight: isChanged ? "700" : "400" }}
136
- >
137
- <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
138
- {field.isBool ? boolToYesNo(valNew, t) : checkForNA(valNew)}
139
- {isChanged && (
140
- <span
141
- style={{
142
- background: "#ECFDF3",
143
- color: "#067647",
144
- padding: "2px 8px",
145
- borderRadius: "12px",
146
- fontSize: "10px",
147
- fontWeight: "600",
148
- }}
149
- >
150
- {t("EKYC_CHANGED")}
151
- </span>
152
- )}
153
- </div>
154
- </td>
155
- </tr>
156
- );
157
- })}
158
- </tbody>
159
- </table>
160
- </div>
161
- </div>
162
- );
163
- };
164
-
165
- const Review = () => {
166
- const { t } = useTranslation();
167
- const history = useHistory();
168
- const location = useLocation();
169
- let { kno } = useParams();
170
-
171
- const [agree, setAgree] = useState(false);
172
- const [isSubmitting, setIsSubmitting] = useState(false);
173
- const [showPreview, setShowPreview] = useState(false);
174
- const [previewUrl, setPreviewUrl] = useState("");
175
- const [showOptions, setShowOptions] = useState(false);
176
- const [showToast, setShowToast] = useState(false);
177
- const [toastData, setToastData] = useState({ error: false, label: "" });
178
-
179
- const options = [
180
- { action: t("APPROVE") },
181
- { action: t("REJECT") }
182
- ];
183
-
184
- const flowState = location.state || {};
185
- const { edits = {} } = flowState;
186
- const activeKno = kno;
187
-
188
- const { aadhaarData = {}, addressDetails: editedAddress = {}, propertyDetails: editedProperty = {}, meterDetails: editedMeter = {} } = edits;
189
-
190
- const tenantId = Digit.ULBService.getCurrentTenantId();
191
- const workflowMutation = Digit.Hooks.ekyc.useEkycWorkflow(tenantId);
192
- const updateMutation = Digit.Hooks.ekyc.useEkycUpdate(tenantId);
193
-
194
- const { data: searchData, isLoading: isSearchLoading } = Digit.Hooks.ekyc.useEkycSearchReview({ kno: activeKno, fetchType: "REVIEW" }, tenantId, {
195
- enabled: !!activeKno,
196
- });
197
-
198
- // ── Data Consolidation ──────────────────────────────────────────────────
199
- const { newData: apiNewData, oldData: apiOldData } = extractReviewData(searchData, flowState);
200
-
201
- const prepareConsolidatedData = (data) => {
202
- if (!data) return null;
203
- const apiConn = data?.connectionDetails || data || {};
204
- const apiAddr = data?.addressDetails || data || {};
205
- const apiProp = data?.propertyInfo || data || {};
206
- const apiMeter = data?.meterDetails || data || {};
207
-
208
- return {
209
- connection: {
210
- consumerName:
211
- apiConn?.consumerName || (apiConn?.firstName ? [apiConn.firstName, apiConn.middleName, apiConn.lastName].filter(Boolean).join(" ") : null),
212
- address: apiConn?.address || apiConn?.addressRaw,
213
- connectionType: apiConn?.connectionType || apiConn?.connectionCategory,
214
- meterNumber: apiConn?.meterNumber || apiConn?.meterNo,
215
- phoneNumber: apiConn?.phoneNumber || apiConn?.mobileNo || apiConn?.mobileNumber,
216
- email: apiConn?.email,
217
- statusflag: apiConn?.statusflag || apiConn?.statusFlag,
218
- ekycStatus: apiConn?.ekycStatus,
219
- knumber: apiConn?.knumber || apiConn?.kno,
220
- },
221
- address: {
222
- fullAddress: apiAddr?.fullAddress || apiAddr?.addressRaw,
223
- flatHouseNumber: apiAddr?.flatHouseNumber || apiAddr?.flatNo,
224
- buildingTower: apiAddr?.buildingTower || apiAddr?.building,
225
- landmark: apiAddr?.landmark,
226
- pinCode: apiAddr?.pinCode || apiAddr?.pincode,
227
- ward: apiAddr?.ward || apiAddr?.locality,
228
- assembly: apiAddr?.assembly,
229
- gpsValid: apiAddr?.gpsValid,
230
- latitude: apiAddr?.latitude,
231
- longitude: apiAddr?.longitude,
232
- mobileNo: apiAddr?.mobileNo || apiAddr?.mobileNumber,
233
- whatsappNo: apiAddr?.whatsappNo,
234
- email: apiAddr?.email,
235
- noOfPerson: apiAddr?.noOfPerson || apiAddr?.noOfPersons,
236
- knumber: apiAddr?.knumber || apiAddr?.kno,
237
- doorPhotoFilestoreId: apiAddr?.doorPhotoFilestoreId,
238
- },
239
- property: {
240
- kno: apiProp?.kno,
241
- pidNumber: apiProp?.pidNumber,
242
- typeOfConnection: apiProp?.typeOfConnection,
243
- connectionCategory: apiProp?.connectionCategory,
244
- userType: apiProp?.userType,
245
- numberOfFloors: apiProp?.numberOfFloors || apiProp?.noOfFloor,
246
- tenantName: apiProp?.tenantName,
247
- tenantMobile: apiProp?.tenantMobile,
248
- ekycStatus: apiProp?.ekycStatus,
249
- propertyDocumentFileStoreId: apiProp?.propertyDocumentFileStoreId,
250
- buildingImageFileStoreId: apiProp?.buildingImageFileStoreId,
251
- },
252
- meter: {
253
- kno: apiMeter?.kno,
254
- metered: apiMeter?.meterStatus === "METERED" || apiMeter?.metered,
255
- meterNumber: apiMeter?.meterNumber || apiMeter?.meterNo,
256
- meterMake: apiMeter?.meterMake,
257
- meterLocationAddress: apiMeter?.meterLocationAddress,
258
- meterLatitude: apiMeter?.meterLatitude,
259
- meterLongitude: apiMeter?.meterLongitude,
260
- workingStatus: apiMeter?.workingStatus,
261
- lastBillRaised: apiMeter?.lastBillRaised,
262
- systemMeterId: apiMeter?.systemMeterId,
263
- meterPhotoFileStoreId: apiMeter?.meterPhotoFileStoreId,
264
- },
265
- };
266
- };
267
-
268
- const newDataRaw = prepareConsolidatedData(apiNewData);
269
- const oldDataRaw = prepareConsolidatedData(apiOldData);
270
-
271
- // Apply edits to newData if present
272
- const connectionData = {
273
- ...newDataRaw?.connection,
274
- consumerName: aadhaarData?.name || newDataRaw?.connection?.consumerName,
275
- phoneNumber: aadhaarData?.mobileNumber || newDataRaw?.connection?.phoneNumber,
276
- knumber: newDataRaw?.connection?.knumber || activeKno,
277
- };
278
-
279
- const addressData = {
280
- ...newDataRaw?.address,
281
- fullAddress: editedAddress?.fullAddress || newDataRaw?.address?.fullAddress,
282
- flatHouseNumber: editedAddress?.flatHouseNumber || editedAddress?.flatNo || newDataRaw?.address?.flatHouseNumber,
283
- buildingTower: editedAddress?.buildingTower || editedAddress?.building || newDataRaw?.address?.buildingTower,
284
- landmark: editedAddress?.landmark || newDataRaw?.address?.landmark,
285
- pinCode: editedAddress?.pinCode || editedAddress?.pincode || newDataRaw?.address?.pinCode,
286
- ward: editedAddress?.ward || newDataRaw?.address?.ward,
287
- assembly: editedAddress?.assembly || newDataRaw?.address?.assembly,
288
- gpsValid: editedAddress?.gpsValid !== undefined ? editedAddress.gpsValid : newDataRaw?.address?.gpsValid,
289
- latitude: editedAddress?.latitude || newDataRaw?.address?.latitude,
290
- longitude: editedAddress?.longitude || newDataRaw?.address?.longitude,
291
- mobileNo: editedAddress?.mobileNo || aadhaarData?.mobileNumber || newDataRaw?.address?.mobileNo,
292
- whatsappNo: editedAddress?.whatsappNo || aadhaarData?.whatsappNumber || newDataRaw?.address?.whatsappNo,
293
- email: editedAddress?.email || newDataRaw?.address?.email,
294
- noOfPerson: editedAddress?.noOfPerson || aadhaarData?.noOfPersons || newDataRaw?.address?.noOfPerson,
295
- knumber: editedAddress?.knumber || newDataRaw?.address?.knumber || activeKno,
296
- doorPhotoFilestoreId: editedAddress?.doorPhotoFileStoreId || newDataRaw?.address?.doorPhotoFilestoreId,
297
- };
298
-
299
- const propertyData = {
300
- ...newDataRaw?.property,
301
- kno: newDataRaw?.property?.kno || activeKno,
302
- pidNumber: editedProperty?.pidNumber || newDataRaw?.property?.pidNumber,
303
- typeOfConnection: editedProperty?.connectionTypeData?.label || newDataRaw?.property?.typeOfConnection,
304
- connectionCategory: editedProperty?.connectionCategoryData?.label || newDataRaw?.property?.connectionCategory,
305
- userType: editedProperty?.userTypeData?.label || newDataRaw?.property?.userType,
306
- numberOfFloors: editedProperty?.noOfFloorsData?.label || newDataRaw?.property?.numberOfFloors,
307
- propertyDocumentFileStoreId: editedProperty?.propertyDocumentFileStoreId || newDataRaw?.property?.propertyDocumentFileStoreId,
308
- };
309
-
310
- const meterData = {
311
- ...newDataRaw?.meter,
312
- kno: editedMeter?.kno || newDataRaw?.meter?.kno || activeKno,
313
- metered: editedMeter?.meterStatusData?.value === "Metered" || newDataRaw?.meter?.metered,
314
- meterNumber: newDataRaw?.meter?.meterNumber,
315
- meterMake: editedMeter?.meterMake || newDataRaw?.meter?.meterMake,
316
- meterLocationAddress: editedMeter?.meterLocation || newDataRaw?.meter?.meterLocationAddress,
317
- workingStatus: editedMeter?.workingStatusData?.value === "Working" || newDataRaw?.meter?.workingStatus,
318
- lastBillRaised: editedMeter?.lastBillRaisedData?.value === "Yes" || newDataRaw?.meter?.lastBillRaised,
319
- meterPhotoFileStoreId: editedMeter?.meterPhotoFileStoreId || newDataRaw?.meter?.meterPhotoFileStoreId,
320
- };
321
-
322
- // ── Section Fields Configuration ─────────────────────────────────────
323
- const connectionFields = [
324
- { label: "EKYC_K_NUMBER", key: "knumber" },
325
- { label: "EKYC_CONSUMER_NAME", key: "consumerName" },
326
- { label: "EKYC_ADDRESS", key: "address" },
327
- { label: "EKYC_CONNECTION_TYPE", key: "connectionType" },
328
- { label: "EKYC_METER_NO", key: "meterNumber" },
329
- { label: "EKYC_MOBILE_NO", key: "phoneNumber" },
330
- { label: "EKYC_EMAIL", key: "email" },
331
- { label: "EKYC_STATUS_FLAG", key: "statusflag" },
332
- { label: "EKYC_STATUS", key: "ekycStatus" },
333
- ];
334
-
335
- const addressFields = [
336
- { label: "EKYC_FULL_ADDRESS", key: "fullAddress" },
337
- { label: "EKYC_FLAT_HOUSE_NO", key: "flatHouseNumber" },
338
- { label: "EKYC_BUILDING_TOWER", key: "buildingTower" },
339
- { label: "EKYC_LANDMARK", key: "landmark" },
340
- { label: "EKYC_PINCODE", key: "pinCode" },
341
- { label: "EKYC_LOCALITY", key: "ward" },
342
- { label: "EKYC_ASSEMBLY", key: "assembly" },
343
- { label: "EKYC_GPS_VALID", key: "gpsValid", isBool: true },
344
- { label: "EKYC_LATITUDE", key: "latitude" },
345
- { label: "EKYC_LONGITUDE", key: "longitude" },
346
- { label: "EKYC_MOBILE_NO", key: "mobileNo" },
347
- { label: "EKYC_WHATSAPP_NO", key: "whatsappNo" },
348
- { label: "EKYC_EMAIL", key: "email" },
349
- { label: "EKYC_NO_OF_PERSONS", key: "noOfPerson" },
350
- { label: "EKYC_K_NUMBER", key: "knumber" },
351
- ];
352
-
353
- const propertyFields = [
354
- { label: "EKYC_CONNECTION_CATEGORY", key: "connectionCategory" },
355
- { label: "EKYC_PID_NUMBER", key: "pidNumber" },
356
- { label: "EKYC_TYPE_OF_CONNECTION", key: "typeOfConnection" },
357
- { label: "EKYC_USER_TYPE", key: "userType" },
358
- { label: "EKYC_FLOOR_COUNT", key: "numberOfFloors" },
359
- { label: "EKYC_TENANT_NAME", key: "tenantName" },
360
- { label: "EKYC_TENANT_MOBILE", key: "tenantMobile" },
361
- { label: "EKYC_STATUS", key: "ekycStatus" },
362
- ];
363
-
364
- const meterFields = [
365
- { label: "EKYC_METERED", key: "metered", isBool: true },
366
- { label: "EKYC_METER_NO", key: "meterNumber" },
367
- { label: "EKYC_METER_MAKE", key: "meterMake" },
368
- { label: "EKYC_METER_LOCATION_ADDRESS", key: "meterLocationAddress" },
369
- { label: "EKYC_METER_LATITUDE", key: "meterLatitude" },
370
- { label: "EKYC_METER_LONGITUDE", key: "meterLongitude" },
371
- { label: "EKYC_WORKING_STATUS", key: "workingStatus", isBool: true },
372
- { label: "EKYC_LAST_BILL_RAISED", key: "lastBillRaised", isBool: true },
373
- { label: "EKYC_SYSTEM_METER_ID", key: "systemMeterId" },
374
- ];
375
-
376
- const handleDeclaration = () => setAgree(!agree);
377
-
378
- const handleReject = async () => {
379
- const payload = {
380
- RequestInfo: {
381
- apiId: "Rainmaker",
382
- ver: "1.0",
383
- msgId: "message-id",
384
- tenantId: tenantId,
385
- authToken: Digit.UserService.getUser()?.access_token,
386
- },
387
- kno: activeKno,
388
- action: "REJECTED",
389
- remarks: "Application rejected by reviewer",
390
- reviewedBy: Digit.UserService.getUser()?.info?.userName,
391
- role: "ZRO",
392
- };
393
- try {
394
- const result = await workflowMutation.mutateAsync(payload);
395
- if (result) {
396
- history.push("/digit-ui/employee/ekyc/response", { success: true, result });
397
- }
398
- } catch (err) {
399
- console.error("Reject Error:", err);
400
- }
401
- };
402
-
403
- const handleApprove = async () => {
404
- const payload = {
405
- RequestInfo: {
406
- apiId: "Rainmaker",
407
- ver: "1.0",
408
- msgId: "message-id",
409
- tenantId: tenantId,
410
- authToken: Digit.UserService.getUser()?.access_token,
411
- },
412
- kno: activeKno,
413
- action: "APPROVED",
414
- remarks: "All documents verified",
415
- reviewedBy: Digit.UserService.getUser()?.info?.userName,
416
- role: "ZRO",
417
- };
418
- try {
419
- const result = await workflowMutation.mutateAsync(payload);
420
- if (result) {
421
- setToastData({
422
- error: false,
423
- label: t("EKYC_APPLICATION_APPROVE_SUCCESSFUL") || "Application Approved Successfully",
424
- });
425
- setShowToast(true);
426
- setTimeout(() => {
427
- history.push("/digit-ui/employee/ekyc/inbox");
428
- }, 2000);
429
- }
430
- } catch (err) {
431
- console.error("Approve Error:", err);
432
- setToastData({
433
- error: true,
434
- label: err?.message || err?.response?.data?.message || "Approve Error",
435
- });
436
- setShowToast(true);
437
- }
438
- };
439
-
440
- const handleFinalSubmit = async () => {
441
- setIsSubmitting(true);
442
- try {
443
- const payload = {
444
- kno: activeKno,
445
- tenantId: tenantId,
446
- newData: {
447
- connectionDetails: connectionData,
448
- addressDetails: addressData,
449
- propertyInfo: propertyData,
450
- meterDetails: meterData,
451
- },
452
- };
453
-
454
- const result = await updateMutation.mutateAsync(payload);
455
- if (result) {
456
- history.push("/digit-ui/employee/ekyc/response", { success: true, result });
457
- }
458
- } catch (err) {
459
- console.error("Submit Error:", err);
460
- } finally {
461
- setIsSubmitting(false);
462
- }
463
- };
464
-
465
- const handleViewDocument = (fileStoreId) => {
466
- if (!fileStoreId) return;
467
- const documentUrl = `https://dev-djberp.nitcon.in/filestore/v1/files/id?tenantId=dl.djb&fileStoreId=${fileStoreId}`;
468
- setPreviewUrl(documentUrl);
469
- setShowPreview(true);
470
- };
471
-
472
- const handleMenuSelect = (option) => {
473
- setShowOptions(false); // close menu
474
- if (option.action === t("Approve")) {
475
- handleApprove();
476
- } else if (option.action === t("Reject")) {
477
- handleReject();
478
- }
479
- };
480
-
481
- if (isSearchLoading || isSubmitting) return <Loader />;
482
-
483
- const baseUrl = "/digit-ui/employee/ekyc";
484
-
485
- return (
486
- <Fragment>
487
- <Card className="overflow-y-scroll">
488
- {/* ── 1. Connection Details ────────────────────────────────────── */}
489
- <ReviewSection
490
- title={t("EKYC_CONNECTION_DETAILS")}
491
- fields={connectionFields}
492
- newData={connectionData}
493
- oldData={oldDataRaw?.connection}
494
- t={t}
495
- jumpTo={`${baseUrl}/consumer-details?kno=${kno}`}
496
- state={{ ...flowState, kNumber: kno, kno, reviewData: searchData, edits }}
497
- />
498
-
499
- {/* ── 2. Address Details ──────────────────────────────────────── */}
500
- <ReviewSection
501
- title={t("EKYC_ADDRESS_DETAILS")}
502
- fields={addressFields}
503
- newData={addressData}
504
- oldData={oldDataRaw?.address}
505
- t={t}
506
- jumpTo={`${baseUrl}/address-details?kno=${kno}`}
507
- state={{ ...flowState, kNumber: kno, kno, reviewData: searchData, edits }}
508
- />
509
-
510
- {/* ── 3. Property Info ────────────────────────────────────────── */}
511
- <ReviewSection
512
- title={t("EKYC_PROPERTY_INFO")}
513
- fields={propertyFields}
514
- newData={propertyData}
515
- oldData={oldDataRaw?.property}
516
- t={t}
517
- jumpTo={`${baseUrl}/property-info?kno=${kno}`}
518
- state={{ ...flowState, kNumber: kno, kno, reviewData: searchData, edits }}
519
- />
520
-
521
- {/* ── 4. Meter Details ────────────────────────────────────────── */}
522
- <ReviewSection
523
- title={t("EKYC_METER_DETAILS")}
524
- fields={meterFields}
525
- newData={meterData}
526
- oldData={oldDataRaw?.meter}
527
- t={t}
528
- jumpTo={`${baseUrl}/meter-details?kno=${kno}`}
529
- state={{ ...flowState, kNumber: kno, kno, reviewData: searchData, edits }}
530
- />
531
-
532
- {/* ── 5. Documents ────────────────────────────────────────────── */}
533
- <div style={{ marginTop: "40px" }}>
534
- <CardSubHeader style={{ marginBottom: "20px" }}>{t("EKYC_DOCUMENTS")}</CardSubHeader>
535
- <StatusTable style={{ maxWidth: "600px" }}>
536
- <Row
537
- label={t("EKYC_DOOR_PHOTO")}
538
- text={addressData.doorPhotoFilestoreId ? t("EKYC_PHOTO_AVAILABLE") : t("CS_NA")}
539
- actionButton={
540
- addressData.doorPhotoFilestoreId && (
541
- <div onClick={() => handleViewDocument(addressData.doorPhotoFilestoreId)}>
542
- <GenericFileIcon style={{ cursor: "pointer", fill: "#F47738" }} />
543
- </div>
544
- )
545
- }
546
- />
547
- <Row
548
- label={t("EKYC_METER_PHOTO")}
549
- text={meterData.meterPhotoFileStoreId ? t("EKYC_PHOTO_AVAILABLE") : t("CS_NA")}
550
- actionButton={
551
- meterData.meterPhotoFileStoreId && (
552
- <div onClick={() => handleViewDocument(meterData.meterPhotoFileStoreId)}>
553
- <GenericFileIcon style={{ cursor: "pointer", fill: "#F47738" }} />
554
- </div>
555
- )
556
- }
557
- />
558
- <Row
559
- label={t("EKYC_BUILDING_IMAGE")}
560
- text={propertyData.buildingImageFileStoreId ? t("EKYC_PHOTO_AVAILABLE") : t("CS_NA")}
561
- actionButton={
562
- propertyData.buildingImageFileStoreId && (
563
- <div onClick={() => handleViewDocument(propertyData.buildingImageFileStoreId)}>
564
- <GenericFileIcon style={{ cursor: "pointer", fill: "#F47738" }} />
565
- </div>
566
- )
567
- }
568
- />
569
- <Row
570
- label={t("EKYC_PROPERTY_DOCUMENTS")}
571
- text={propertyData.propertyDocumentFileStoreId ? t("EKYC_DOCS_AVAILABLE") : t("CS_NA")}
572
- actionButton={
573
- propertyData.propertyDocumentFileStoreId && (
574
- <div onClick={() => handleViewDocument(propertyData.propertyDocumentFileStoreId)}>
575
- <GenericFileIcon style={{ cursor: "pointer", fill: "#F47738" }} />
576
- </div>
577
- )
578
- }
579
- />
580
- </StatusTable>
581
- </div>
582
-
583
- <div style={{ marginTop: "40px", paddingTop: "30px", borderTop: "1px solid #EAECF0" }}>
584
- <CheckBox
585
- id="agreeDeclaration"
586
- name="agreeDeclaration"
587
- label={<span style={{ fontSize: "16px", color: "#344054" }}>{t("EKYC_FINAL_DECLARATION")}</span>}
588
- onChange={handleDeclaration}
589
- checked={agree}
590
- />
591
- </div>
592
-
593
- {/* <ActionBar>
594
- <SubmitBar label={t("EKYC_REJECT")} onSubmit={handleReject} disabled={!agree} />
595
- <SubmitBar label={t("EKYC_APPROVE")} onSubmit={handleApprove} disabled={!agree} />
596
- <SubmitBar label={t("EKYC_SUBMIT_APPLICATION")} onSubmit={handleFinalSubmit} disabled={!agree} />
597
- </ActionBar> */}
598
- <ActionBar>
599
- <SubmitBar
600
- label={t("TAKE_ACTION_FOR_APPROVE_REJECT")}
601
- onSubmit={() => setShowOptions((prev) => !prev)}
602
- disabled={!agree}
603
- />
604
- {showOptions && (
605
- <Menu
606
- options={options}
607
- optionKey={"action"}
608
- t={t}
609
- onSelect={handleMenuSelect}
610
- style={{
611
- color: "#FFFFFF",
612
- fontSize: "18px",
613
- }}
614
- />
615
- )}
616
- </ActionBar>
617
- </Card>
618
-
619
- {/* ── Document Preview Modal ────────────────────────────────────── */}
620
- {showPreview && (
621
- <div
622
- style={{
623
- position: "fixed",
624
- top: 0,
625
- left: 0,
626
- width: "100%",
627
- height: "100%",
628
- backgroundColor: "rgba(0,0,0,0.7)",
629
- display: "flex",
630
- justifyContent: "center",
631
- alignItems: "center",
632
- zIndex: 10000,
633
- }}
634
- >
635
- <div
636
- style={{
637
- position: "relative",
638
- backgroundColor: "#fff",
639
- padding: "30px",
640
- borderRadius: "12px",
641
- maxWidth: "600px",
642
- width: "100%",
643
- maxHeight: "70vh",
644
- overflow: "auto",
645
- boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
646
- }}
647
- >
648
- <div
649
- onClick={() => setShowPreview(false)}
650
- style={{
651
- position: "absolute",
652
- top: "10px",
653
- right: "10px",
654
- cursor: "pointer",
655
- fontWeight: "bold",
656
- fontSize: "20px",
657
- color: "#333",
658
- background: "#eee",
659
- width: "30px",
660
- height: "30px",
661
- display: "flex",
662
- justifyContent: "center",
663
- alignItems: "center",
664
- borderRadius: "50%",
665
- }}
666
- >
667
- ×
668
- </div>
669
- <img
670
- src={previewUrl}
671
- alt="Document Preview"
672
- style={{ maxWidth: "100%", height: "auto", display: "block" }}
673
- onError={(e) => {
674
- e.target.style.display = "none";
675
- e.target.nextSibling.style.display = "block";
676
- }}
677
- />
678
- <div style={{ display: "none", padding: "40px", textAlign: "center" }}>
679
- <p>{t("EKYC_DOCUMENT_PREVIEW_NOT_AVAILABLE")}</p>
680
- <LinkButton label={t("EKYC_OPEN_IN_NEW_TAB")} onClick={() => window.open(previewUrl, "_blank")} />
681
- </div>
682
- </div>
683
- </div>
684
- )}
685
- {showToast && (
686
- <Toast
687
- error={toastData.error}
688
- label={toastData.label}
689
- onClose={() => setShowToast(false)}
690
- />
691
- )}
692
- </Fragment>
693
- );
694
- };
695
-
696
- export default Review;