@djb25/digit-ui-module-ekyc 1.0.11 → 1.0.13

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 (40) hide show
  1. package/dist/index.css +1 -0
  2. package/dist/index.js +1 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.modern.js +2884 -682
  5. package/dist/index.modern.js.map +1 -1
  6. package/package.json +1 -1
  7. package/src/Module.js +28 -7
  8. package/src/components/AadhaarVerification.js +415 -0
  9. package/src/components/AddressDetails.js +207 -0
  10. package/src/components/CeoDashboard.js +201 -0
  11. package/src/components/DesktopInbox.js +1 -1
  12. package/src/components/EKYCCard.js +4 -0
  13. package/src/components/MeterDetails.js +372 -0
  14. package/src/components/PropertyInfo.js +303 -0
  15. package/src/components/Review.js +572 -0
  16. package/src/components/analytics/charts/ClusterHeatmap.js +88 -0
  17. package/src/components/analytics/charts/TaskStatusChart.js +92 -0
  18. package/src/components/analytics/components/AnalyticsTable.js +106 -0
  19. package/src/components/analytics/components/DashboardLayout.js +72 -0
  20. package/src/components/analytics/components/EmptyState.js +27 -0
  21. package/src/components/analytics/components/ErrorBoundary.js +27 -0
  22. package/src/components/analytics/components/FilterBar.js +73 -0
  23. package/src/components/analytics/components/NotificationPanel.js +77 -0
  24. package/src/components/analytics/components/SLAWidget.js +56 -0
  25. package/src/components/analytics/components/SkeletonLoader.js +53 -0
  26. package/src/components/analytics/components/SummaryCard.js +74 -0
  27. package/src/components/analytics/components/WorkflowTimeline.js +55 -0
  28. package/src/components/analytics/styles/Dashboard.css +54 -0
  29. package/src/components/analytics/utils/exportUtils.js +64 -0
  30. package/src/components/analytics/utils/filterSerializer.js +50 -0
  31. package/src/config/config.js +1 -1
  32. package/src/pages/citizen/index.js +74 -18
  33. package/src/pages/employee/ConsumerDetails.js +10 -281
  34. package/src/pages/employee/Inbox.js +6 -4
  35. package/src/pages/employee/index.js +55 -8
  36. package/src/pages/employee/AadhaarVerification.js +0 -512
  37. package/src/pages/employee/AddressDetails.js +0 -548
  38. package/src/pages/employee/MeterDetails.js +0 -496
  39. package/src/pages/employee/PropertyInfo.js +0 -489
  40. package/src/pages/employee/Review.js +0 -314
@@ -1,314 +0,0 @@
1
- import React, { useState, Fragment, useEffect } from "react";
2
- import {
3
- Card,
4
- CardHeader,
5
- CardSubHeader,
6
- StatusTable,
7
- Row,
8
- SubmitBar,
9
- Loader,
10
- ActionBar,
11
- CheckBox,
12
- LinkButton,
13
- EditIcon,
14
- GenericFileIcon,
15
- } from "@djb25/digit-ui-react-components";
16
- import { useTranslation } from "react-i18next";
17
- import { useHistory, useLocation } from "react-router-dom";
18
-
19
- // ─── Constants ───────────────────────────────────────────────────────────────
20
-
21
- const ActionButton = ({ jumpTo, state }) => {
22
- const { t } = useTranslation();
23
- const history = useHistory();
24
- function routeTo() {
25
- history.push(jumpTo, { ...state, isEditing: true });
26
- }
27
- return (
28
- <LinkButton
29
- label={<EditIcon style={{ marginTop: "-30px", float: "right", position: "relative", bottom: "32px" }} />}
30
- className="check-page-link-button"
31
- onClick={routeTo}
32
- />
33
- );
34
- };
35
-
36
- const checkForNA = (value) => (value !== null && value !== undefined && value !== "") ? value : "N/A";
37
-
38
- const boolToYesNo = (value, t) => {
39
- if (value === true || value === "true" || String(value).toLowerCase() === "yes") return t("CORE_COMMON_YES");
40
- if (value === false || value === "false" || String(value).toLowerCase() === "no") return t("CORE_COMMON_NO");
41
- return "N/A";
42
- };
43
-
44
- /**
45
- * Robust data extraction based on the screenshot provided.
46
- * The API returns { applicationReview: { newData: { ...flatFields } } }
47
- */
48
- const extractActiveData = (searchData, flowState) => {
49
- const rawData = (searchData && Object.keys(searchData).length > 0) ? searchData : flowState?.reviewData || {};
50
-
51
- // Navigate through applicationReview -> newData
52
- const reviewWrapper = rawData?.applicationReview || rawData;
53
- const applicationData = (Array.isArray(reviewWrapper) ? reviewWrapper[0] : reviewWrapper) || {};
54
- return applicationData?.newData || applicationData;
55
- };
56
-
57
- const Review = () => {
58
- const { t } = useTranslation();
59
- const history = useHistory();
60
- const location = useLocation();
61
-
62
- const [agree, setAgree] = useState(false);
63
- const [isSubmitting, setIsSubmitting] = useState(false);
64
-
65
- const flowState = location.state || {};
66
- const { kNumber, kno, edits = {} } = flowState;
67
- const activeKno = kNumber || kno;
68
-
69
- const { aadhaarData = {}, addressDetails: editedAddress = {}, propertyDetails: editedProperty = {}, meterDetails: editedMeter = {} } = edits;
70
-
71
- const tenantId = Digit.ULBService.getCurrentTenantId();
72
-
73
- const { data: searchData, isLoading: isSearchLoading } = Digit.Hooks.ekyc.useEkycSearchReview(
74
- { kno: activeKno, fetchType: "REVIEW" },
75
- tenantId,
76
- { enabled: !!activeKno }
77
- );
78
-
79
- // ── Data Consolidation ──────────────────────────────────────────────────
80
- const activeData = extractActiveData(searchData, flowState);
81
-
82
- // Support both structured (connectionDetails.x) and flat (x) formats
83
- const apiConn = activeData?.connectionDetails || activeData || {};
84
- const apiAddr = activeData?.addressDetails || activeData || {};
85
- const apiProp = activeData?.propertyInfo || activeData || {};
86
- const apiMeter = activeData?.meterDetails || activeData || {};
87
-
88
- const connectionData = {
89
- consumerName: aadhaarData?.name || apiConn?.consumerName,
90
- address: apiConn?.address || apiConn?.addressRaw,
91
- connectionType: apiConn?.connectionType || apiConn?.connectionCategory,
92
- meterNumber: apiConn?.meterNumber || apiConn?.meterNo,
93
- phoneNumber: aadhaarData?.mobileNumber || apiConn?.phoneNumber || apiConn?.mobileNo,
94
- email: apiConn?.email,
95
- statusflag: apiConn?.statusflag || apiConn?.statusFlag,
96
- ekycStatus: apiConn?.ekycStatus,
97
- knumber: apiConn?.knumber || apiConn?.kno || activeKno,
98
- };
99
-
100
- const addressData = {
101
- fullAddress: editedAddress?.fullAddress || apiAddr?.fullAddress || apiAddr?.addressRaw,
102
- flatHouseNumber: editedAddress?.flatHouseNumber || editedAddress?.flatNo || apiAddr?.flatHouseNumber,
103
- buildingTower: editedAddress?.buildingTower || editedAddress?.building || apiAddr?.buildingTower,
104
- landmark: editedAddress?.landmark || apiAddr?.landmark,
105
- pinCode: editedAddress?.pinCode || editedAddress?.pincode || apiAddr?.pinCode || apiAddr?.pincode,
106
- ward: editedAddress?.ward || apiAddr?.ward || apiAddr?.locality,
107
- assembly: editedAddress?.assembly || apiAddr?.assembly,
108
- gpsValid: editedAddress?.gpsValid !== undefined ? editedAddress.gpsValid : apiAddr?.gpsValid,
109
- latitude: editedAddress?.latitude || apiAddr?.latitude,
110
- longitude: editedAddress?.longitude || apiAddr?.longitude,
111
- mobileNo: editedAddress?.mobileNo || aadhaarData?.mobileNumber || apiAddr?.mobileNo,
112
- whatsappNo: editedAddress?.whatsappNo || aadhaarData?.whatsappNumber || apiAddr?.whatsappNo,
113
- email: editedAddress?.email || apiAddr?.email,
114
- noOfPerson: editedAddress?.noOfPerson || aadhaarData?.noOfPersons || apiAddr?.noOfPerson,
115
- knumber: editedAddress?.knumber || apiAddr?.knumber || apiAddr?.kno || activeKno,
116
- doorPhotoFilestoreId: editedAddress?.doorPhotoFileStoreId || apiAddr?.doorPhotoFilestoreId,
117
- };
118
-
119
- const propertyData = {
120
- kno: apiProp?.kno || activeKno,
121
- pidNumber: editedProperty?.pidNumber || apiProp?.pidNumber,
122
- typeOfConnection: editedProperty?.connectionTypeData?.label || apiProp?.typeOfConnection,
123
- connectionCategory: editedProperty?.connectionCategoryData?.label || apiProp?.connectionCategory,
124
- userType: editedProperty?.userTypeData?.label || apiProp?.userType,
125
- numberOfFloors: editedProperty?.noOfFloorsData?.label || apiProp?.numberOfFloors,
126
- tenantName: apiProp?.tenantName,
127
- tenantMobile: apiProp?.tenantMobile,
128
- ekycStatus: apiProp?.ekycStatus,
129
- propertyDocumentFileStoreId: editedProperty?.propertyDocumentFileStoreId || apiProp?.propertyDocumentFileStoreId,
130
- buildingImageFileStoreId: apiProp?.buildingImageFileStoreId,
131
- };
132
-
133
- const meterData = {
134
- kno: editedMeter?.kno || apiMeter?.kno || activeKno,
135
- metered: editedMeter?.meterStatusData?.value === "Metered" || apiMeter?.metered,
136
- meterNumber: apiMeter?.meterNumber || apiMeter?.meterNo,
137
- meterMake: editedMeter?.meterMake || apiMeter?.meterMake,
138
- meterLocationAddress: editedMeter?.meterLocation || apiMeter?.meterLocationAddress,
139
- meterLatitude: apiMeter?.meterLatitude,
140
- meterLongitude: apiMeter?.meterLongitude,
141
- workingStatus: editedMeter?.workingStatusData?.value === "Working" || apiMeter?.workingStatus,
142
- lastBillRaised: editedMeter?.lastBillRaisedData?.value === "Yes" || apiMeter?.lastBillRaised,
143
- systemMeterId: apiMeter?.systemMeterId,
144
- meterPhotoFileStoreId: editedMeter?.meterPhotoFileStoreId || apiMeter?.meterPhotoFileStoreId,
145
- };
146
-
147
- const handleDeclaration = () => setAgree(!agree);
148
-
149
- const handleFinalSubmit = async () => {
150
- setIsSubmitting(true);
151
- try {
152
- const payload = {
153
- kno: activeKno,
154
- tenantId: tenantId,
155
- newData: {
156
- connectionDetails: connectionData,
157
- addressDetails: addressData,
158
- propertyInfo: propertyData,
159
- meterDetails: meterData,
160
- },
161
- };
162
-
163
- const result = await Digit.EkycService.application_update(payload, tenantId);
164
- if (result) {
165
- history.push("/digit-ui/employee/ekyc/response", { success: true, result });
166
- }
167
- } catch (err) {
168
- console.error("Submit Error:", err);
169
- } finally {
170
- setIsSubmitting(false);
171
- }
172
- };
173
-
174
- if (isSearchLoading || isSubmitting) return <Loader />;
175
-
176
- const baseUrl = "/digit-ui/employee/ekyc";
177
-
178
- return (
179
- <div className="review-container">
180
- <Card>
181
- {/* ── Header ───────────────────────────────────────────────────── */}
182
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }}>
183
- <CardHeader style={{ margin: 0 }}>{t("EKYC_REVIEW_APPLICATION")}</CardHeader>
184
- <div style={{
185
- background: "#F9FAFB", border: "0.5px solid #EAECF0",
186
- borderRadius: "20px", padding: "4px 14px",
187
- fontSize: "12px", color: "#667085",
188
- }}>
189
- {t("EKYC_K_NUMBER")}: <span style={{ color: "#0B0C0C", fontWeight: "600" }}>{activeKno}</span>
190
- </div>
191
- </div>
192
-
193
- {/* ── 1. Connection Details ────────────────────────────────────── */}
194
- <CardSubHeader>{t("EKYC_CONNECTION_DETAILS")}</CardSubHeader>
195
- <StatusTable style={{ marginTop: "20px", marginBottom: "30px" }}>
196
- <Row label={t("EKYC_K_NUMBER")} text={checkForNA(connectionData.knumber)} />
197
- <Row label={t("EKYC_CONSUMER_NAME")} text={checkForNA(connectionData.consumerName)} />
198
- <Row label={t("EKYC_ADDRESS")} text={checkForNA(connectionData.address)} />
199
- <Row label={t("EKYC_CONNECTION_TYPE")} text={checkForNA(connectionData.connectionType)} />
200
- <Row label={t("EKYC_METER_NO")} text={checkForNA(connectionData.meterNumber)} />
201
- <Row label={t("EKYC_MOBILE_NO")} text={checkForNA(connectionData.phoneNumber)} />
202
- <Row label={t("EKYC_EMAIL")} text={checkForNA(connectionData.email)} />
203
- <Row label={t("EKYC_STATUS_FLAG")} text={checkForNA(connectionData.statusflag)} />
204
- <Row label={t("EKYC_STATUS")} text={checkForNA(connectionData.ekycStatus)} />
205
- </StatusTable>
206
-
207
- {/* ── 2. Address Details ──────────────────────────────────────── */}
208
- <CardSubHeader>{t("EKYC_ADDRESS_DETAILS")}</CardSubHeader>
209
- <StatusTable style={{ marginTop: "20px", marginBottom: "30px" }}>
210
- <Row
211
- label={t("EKYC_FULL_ADDRESS")}
212
- text={checkForNA(addressData.fullAddress)}
213
- actionButton={<ActionButton jumpTo={`${baseUrl}/address-details`} state={{ ...flowState, reviewData: searchData, edits }} />}
214
- />
215
- <Row label={t("EKYC_FLAT_HOUSE_NO")} text={checkForNA(addressData.flatHouseNumber)} />
216
- <Row label={t("EKYC_BUILDING_TOWER")} text={checkForNA(addressData.buildingTower)} />
217
- <Row label={t("EKYC_LANDMARK")} text={checkForNA(addressData.landmark)} />
218
- <Row label={t("EKYC_PINCODE")} text={checkForNA(addressData.pinCode)} />
219
- <Row label={t("EKYC_LOCALITY")} text={checkForNA(addressData.ward)} />
220
- <Row label={t("EKYC_ASSEMBLY")} text={checkForNA(addressData.assembly)} />
221
- <Row label={t("EKYC_GPS_VALID")} text={boolToYesNo(addressData.gpsValid, t)} />
222
- <Row label={t("EKYC_LATITUDE")} text={checkForNA(addressData.latitude)} />
223
- <Row label={t("EKYC_LONGITUDE")} text={checkForNA(addressData.longitude)} />
224
- <Row label={t("EKYC_MOBILE_NO")} text={checkForNA(addressData.mobileNo)} />
225
- <Row label={t("EKYC_WHATSAPP_NO")} text={checkForNA(addressData.whatsappNo)} />
226
- <Row label={t("EKYC_EMAIL")} text={checkForNA(addressData.email)} />
227
- <Row label={t("EKYC_NO_OF_PERSONS")} text={checkForNA(addressData.noOfPerson)} />
228
- <Row label={t("EKYC_K_NUMBER")} text={checkForNA(addressData.knumber)} />
229
- </StatusTable>
230
-
231
- {/* ── 3. Property Info ────────────────────────────────────────── */}
232
- <CardSubHeader>{t("EKYC_PROPERTY_INFO")}</CardSubHeader>
233
- <StatusTable style={{ marginTop: "20px", marginBottom: "30px" }}>
234
- <Row
235
- label={t("EKYC_CONNECTION_CATEGORY")}
236
- text={checkForNA(propertyData.connectionCategory)}
237
- actionButton={<ActionButton jumpTo={`${baseUrl}/property-info`} state={{ ...flowState, reviewData: searchData, edits }} />}
238
- />
239
- {/* <Row label={t("EKYC_KNO")} text={checkForNA(propertyData.kno)} /> */}
240
- <Row label={t("EKYC_PID_NUMBER")} text={checkForNA(propertyData.pidNumber)} />
241
- <Row label={t("EKYC_TYPE_OF_CONNECTION")} text={checkForNA(propertyData.typeOfConnection)} />
242
- <Row label={t("EKYC_USER_TYPE")} text={checkForNA(propertyData.userType)} />
243
- <Row label={t("EKYC_FLOOR_COUNT")} text={checkForNA(propertyData.numberOfFloors)} />
244
- <Row label={t("EKYC_TENANT_NAME")} text={checkForNA(propertyData.tenantName)} />
245
- <Row label={t("EKYC_TENANT_MOBILE")} text={checkForNA(propertyData.tenantMobile)} />
246
- <Row label={t("EKYC_STATUS")} text={checkForNA(propertyData.ekycStatus)} />
247
- </StatusTable>
248
-
249
- {/* ── 4. Meter Details ────────────────────────────────────────── */}
250
- <CardSubHeader>{t("EKYC_METER_DETAILS")}</CardSubHeader>
251
- <StatusTable style={{ marginTop: "20px", marginBottom: "30px" }}>
252
- <Row
253
- label={t("EKYC_METERED")}
254
- text={boolToYesNo(meterData.metered, t)}
255
- actionButton={<ActionButton jumpTo={`${baseUrl}/meter-details`} state={{ ...flowState, reviewData: searchData, edits }} />}
256
- />
257
- {/* <Row label={t("EKYC_KNO")} text={checkForNA(meterData.kno)} /> */}
258
- <Row label={t("EKYC_METER_NO")} text={checkForNA(meterData.meterNumber)} />
259
- <Row label={t("EKYC_METER_MAKE")} text={checkForNA(meterData.meterMake)} />
260
- <Row label={t("EKYC_METER_LOCATION_ADDRESS")} text={checkForNA(meterData.meterLocationAddress)} />
261
- <Row label={t("EKYC_METER_LATITUDE")} text={checkForNA(meterData.meterLatitude)} />
262
- <Row label={t("EKYC_METER_LONGITUDE")} text={checkForNA(meterData.meterLongitude)} />
263
- <Row label={t("EKYC_WORKING_STATUS")} text={boolToYesNo(meterData.workingStatus, t)} />
264
- <Row label={t("EKYC_LAST_BILL_RAISED")} text={boolToYesNo(meterData.lastBillRaised, t)} />
265
- <Row label={t("EKYC_SYSTEM_METER_ID")} text={checkForNA(meterData.systemMeterId)} />
266
- </StatusTable>
267
-
268
- {/* ── 5. Documents ────────────────────────────────────────────── */}
269
- <CardSubHeader>{t("EKYC_DOCUMENTS")}</CardSubHeader>
270
- <StatusTable style={{ marginTop: "20px", marginBottom: "30px" }}>
271
- <Row
272
- label={t("EKYC_DOOR_PHOTO")}
273
- text={addressData.doorPhotoFilestoreId ? t("EKYC_PHOTO_AVAILABLE") : t("CS_NA")}
274
- actionButton={addressData.doorPhotoFilestoreId && <GenericFileIcon style={{ cursor: "pointer" }} />}
275
- />
276
- <Row
277
- label={t("EKYC_METER_PHOTO")}
278
- text={meterData.meterPhotoFileStoreId ? t("EKYC_PHOTO_AVAILABLE") : t("CS_NA")}
279
- actionButton={meterData.meterPhotoFileStoreId && <GenericFileIcon style={{ cursor: "pointer" }} />}
280
- />
281
- <Row
282
- label={t("EKYC_BUILDING_IMAGE")}
283
- text={propertyData.buildingImageFileStoreId ? t("EKYC_PHOTO_AVAILABLE") : t("CS_NA")}
284
- actionButton={propertyData.buildingImageFileStoreId && <GenericFileIcon style={{ cursor: "pointer" }} />}
285
- />
286
- <Row
287
- label={t("EKYC_PROPERTY_DOCUMENTS")}
288
- text={propertyData.propertyDocumentFileStoreId ? t("EKYC_DOCS_AVAILABLE") : t("CS_NA")}
289
- actionButton={propertyData.propertyDocumentFileStoreId && <GenericFileIcon style={{ cursor: "pointer" }} />}
290
- />
291
- </StatusTable>
292
-
293
- <CheckBox
294
- id="agreeDeclaration"
295
- name="agreeDeclaration"
296
- label={t("EKYC_FINAL_DECLARATION")}
297
- onChange={handleDeclaration}
298
- checked={agree}
299
- style={{ marginTop: "20px" }}
300
- />
301
- </Card>
302
-
303
- <ActionBar style={{ position: "static", marginTop: "24px" }}>
304
- <SubmitBar
305
- label={t("EKYC_SUBMIT_APPLICATION")}
306
- onSubmit={handleFinalSubmit}
307
- disabled={!agree}
308
- />
309
- </ActionBar>
310
- </div>
311
- );
312
- };
313
-
314
- export default Review;