@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.
- package/dist/index.css +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +2884 -682
- package/dist/index.modern.js.map +1 -1
- package/package.json +1 -1
- package/src/Module.js +28 -7
- package/src/components/AadhaarVerification.js +415 -0
- package/src/components/AddressDetails.js +207 -0
- package/src/components/CeoDashboard.js +201 -0
- package/src/components/DesktopInbox.js +1 -1
- package/src/components/EKYCCard.js +4 -0
- package/src/components/MeterDetails.js +372 -0
- package/src/components/PropertyInfo.js +303 -0
- package/src/components/Review.js +572 -0
- package/src/components/analytics/charts/ClusterHeatmap.js +88 -0
- package/src/components/analytics/charts/TaskStatusChart.js +92 -0
- package/src/components/analytics/components/AnalyticsTable.js +106 -0
- package/src/components/analytics/components/DashboardLayout.js +72 -0
- package/src/components/analytics/components/EmptyState.js +27 -0
- package/src/components/analytics/components/ErrorBoundary.js +27 -0
- package/src/components/analytics/components/FilterBar.js +73 -0
- package/src/components/analytics/components/NotificationPanel.js +77 -0
- package/src/components/analytics/components/SLAWidget.js +56 -0
- package/src/components/analytics/components/SkeletonLoader.js +53 -0
- package/src/components/analytics/components/SummaryCard.js +74 -0
- package/src/components/analytics/components/WorkflowTimeline.js +55 -0
- package/src/components/analytics/styles/Dashboard.css +54 -0
- package/src/components/analytics/utils/exportUtils.js +64 -0
- package/src/components/analytics/utils/filterSerializer.js +50 -0
- package/src/config/config.js +1 -1
- package/src/pages/citizen/index.js +74 -18
- package/src/pages/employee/ConsumerDetails.js +10 -281
- package/src/pages/employee/Inbox.js +6 -4
- package/src/pages/employee/index.js +55 -8
- package/src/pages/employee/AadhaarVerification.js +0 -512
- package/src/pages/employee/AddressDetails.js +0 -548
- package/src/pages/employee/MeterDetails.js +0 -496
- package/src/pages/employee/PropertyInfo.js +0 -489
- package/src/pages/employee/Review.js +0 -314
package/package.json
CHANGED
package/src/Module.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useEffect } from "react";
|
|
2
2
|
import { useTranslation } from "react-i18next";
|
|
3
3
|
import { useRouteMatch } from "react-router-dom";
|
|
4
|
-
import { CitizenHomeCard, DocumentIcon } from "@djb25/digit-ui-react-components";
|
|
4
|
+
import { CitizenHomeCard, DocumentIcon, Loader } from "@djb25/digit-ui-react-components";
|
|
5
5
|
import EKYCCard from "./components/EKYCCard";
|
|
6
6
|
import Inbox from "./components/Dashboard";
|
|
7
7
|
import DesktopInbox from "./components/DesktopInbox";
|
|
@@ -9,15 +9,34 @@ import MobileInbox from "./components/MobileInbox";
|
|
|
9
9
|
import Filter from "./components/Filter";
|
|
10
10
|
import EmployeeApp from "./pages/employee";
|
|
11
11
|
import CitizenApp from "./pages/citizen";
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
|
|
12
|
+
import PropertyInfo from "./components/PropertyInfo";
|
|
13
|
+
import MeterDetails from "./components/MeterDetails";
|
|
14
|
+
import AadhaarVerification from "./components/AadhaarVerification";
|
|
15
|
+
import AddressDetails from "./components/AddressDetails";
|
|
16
|
+
import CeoDashboard from "./components/CeoDashboard";
|
|
17
|
+
export const EkycModule = ({ stateCode, userType, tenants }) => {
|
|
18
|
+
|
|
17
19
|
const { path, url } = useRouteMatch();
|
|
20
|
+
const moduleCode = "EKYC";
|
|
21
|
+
const language = Digit.StoreData.getCurrentLanguage();
|
|
22
|
+
const { isLoading, data: store } = Digit.Services.useStore({ stateCode, moduleCode, language });
|
|
18
23
|
|
|
19
24
|
Digit.SessionStorage.set("EKYC_TENANTS", tenants);
|
|
20
25
|
|
|
26
|
+
useEffect(
|
|
27
|
+
() =>
|
|
28
|
+
Digit.LocalizationService.getLocale({
|
|
29
|
+
modules: [`rainmaker-ekyc`, `rainmaker-${Digit.ULBService.getCurrentTenantId()}`],
|
|
30
|
+
locale: Digit.StoreData.getCurrentLanguage(),
|
|
31
|
+
tenantId: Digit.ULBService.getCurrentTenantId(),
|
|
32
|
+
}),
|
|
33
|
+
[]
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
if (isLoading) {
|
|
37
|
+
return <Loader page={true} />;
|
|
38
|
+
}
|
|
39
|
+
|
|
21
40
|
if (userType === "employee") {
|
|
22
41
|
return <EmployeeApp path={path} url={url} userType={userType} tenants={tenants} />;
|
|
23
42
|
} else return <CitizenApp />;
|
|
@@ -51,6 +70,8 @@ const componentsToRegister = {
|
|
|
51
70
|
AddressDetails,
|
|
52
71
|
PropertyInfo,
|
|
53
72
|
MeterDetails,
|
|
73
|
+
CeoDashboard,
|
|
74
|
+
|
|
54
75
|
};
|
|
55
76
|
|
|
56
77
|
export const initEkycComponents = () => {
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
|
|
2
|
+
import React, { useState, Fragment, useEffect } from "react";
|
|
3
|
+
import { useLocation } from "react-router-dom";
|
|
4
|
+
import {
|
|
5
|
+
CardLabel,
|
|
6
|
+
TextInput,
|
|
7
|
+
Dropdown,
|
|
8
|
+
UploadFile,
|
|
9
|
+
RadioButtons,
|
|
10
|
+
Toast,
|
|
11
|
+
FormStep,
|
|
12
|
+
Loader,
|
|
13
|
+
CheckBox
|
|
14
|
+
} from "@djb25/digit-ui-react-components";
|
|
15
|
+
const AadhaarVerification = ({ config, onSelect, formData }) => {
|
|
16
|
+
const location = useLocation();
|
|
17
|
+
const flowState = location.state || {};
|
|
18
|
+
|
|
19
|
+
const tenantId = Digit.ULBService.getCurrentTenantId();
|
|
20
|
+
const searchKno = flowState?.kNumber || flowState?.kno || formData?.kNumber || formData?.kno || sessionStorage.getItem("EKYC_K_NUMBER");
|
|
21
|
+
|
|
22
|
+
const { isLoading, data: searchData } = Digit.Hooks.ekyc.useSearchConnection(
|
|
23
|
+
{ tenantId, details: { kno: searchKno } },
|
|
24
|
+
{ enabled: !!searchKno, cacheTime: 0 }
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const updateMutation = Digit.Hooks.ekyc.useEkycUpdate(tenantId);
|
|
28
|
+
|
|
29
|
+
const savedData = formData?.aadhaarVerification || {};
|
|
30
|
+
|
|
31
|
+
// 🔹 STATES
|
|
32
|
+
const [kno, setKno] = useState(savedData.kno || searchKno || "");
|
|
33
|
+
const [consumerType, setConsumerType] = useState(savedData.consumerType ? { name: savedData.consumerType } : null);
|
|
34
|
+
const [occupantType, setOccupantType] = useState(savedData.occupantType ? { name: savedData.occupantType } : null);
|
|
35
|
+
const [categoryType, setCategoryType] = useState(savedData.categoryType ? { name: savedData.categoryType } : null);
|
|
36
|
+
|
|
37
|
+
const [consumerName, setConsumerName] = useState(savedData.consumerName || "");
|
|
38
|
+
const [firstName, setFirstName] = useState(savedData.firstName || "");
|
|
39
|
+
const [middleName, setMiddleName] = useState(savedData.middleName || "");
|
|
40
|
+
const [lastName, setLastName] = useState(savedData.lastName || "");
|
|
41
|
+
|
|
42
|
+
const [gender, setGender] = useState(savedData.gender ? { name: savedData.gender } : null);
|
|
43
|
+
const [parentSpouseName, setParentSpouseName] = useState(savedData.parentSpouseName || "");
|
|
44
|
+
const [relation, setRelation] = useState(savedData.relation || "");
|
|
45
|
+
|
|
46
|
+
const [mobile, setMobile] = useState(savedData.mobile || "");
|
|
47
|
+
const [whatsapp, setWhatsapp] = useState(savedData.whatsapp || "");
|
|
48
|
+
const [email, setEmail] = useState(savedData.email || "");
|
|
49
|
+
const [residents, setResidents] = useState(savedData.residents || "");
|
|
50
|
+
|
|
51
|
+
// Tenant
|
|
52
|
+
const [documentProof, setDocumentProof] = useState(savedData.documentProof || null);
|
|
53
|
+
const [documentId, setDocumentId] = useState(savedData.documentId || null);
|
|
54
|
+
const [ownerMobile, setOwnerMobile] = useState(savedData.ownerMobile || "");
|
|
55
|
+
const [tenantVerification, setTenantVerification] = useState(savedData.tenantVerification || "");
|
|
56
|
+
|
|
57
|
+
// Govt
|
|
58
|
+
const [designation, setDesignation] = useState(savedData.designation || "");
|
|
59
|
+
const [department, setDepartment] = useState(savedData.department || "");
|
|
60
|
+
const [employeeId, setEmployeeId] = useState(savedData.employeeId || "");
|
|
61
|
+
const [landline, setLandline] = useState(savedData.landline || "");
|
|
62
|
+
|
|
63
|
+
// Other Entity
|
|
64
|
+
const [entityRelation, setEntityRelation] = useState(savedData.entityRelation || "");
|
|
65
|
+
const [contactPerson, setContactPerson] = useState(savedData.contactPerson || "");
|
|
66
|
+
const [entityName, setEntityName] = useState(savedData.entityName || "");
|
|
67
|
+
|
|
68
|
+
// Identity
|
|
69
|
+
const [idProof, setIdProof] = useState(savedData.idProof ? { name: savedData.idProof } : null);
|
|
70
|
+
const [idNumber, setIdNumber] = useState(savedData.idNumber || "");
|
|
71
|
+
const [documentNumber, setDocumentNumber] = useState(savedData.documentNumber || "");
|
|
72
|
+
const [identityType, setIdentityType] = useState(savedData.identityType ? { name: savedData.identityType } : null);
|
|
73
|
+
const [idFile, setIdFile] = useState(savedData.idFile || null);
|
|
74
|
+
|
|
75
|
+
// Consent
|
|
76
|
+
const [consent, setConsent] = useState(savedData.consent || false);
|
|
77
|
+
const [informantIsConsumer, setInformantIsConsumer] = useState(savedData.informantIsConsumer ?? true);
|
|
78
|
+
const [informantName, setInformantName] = useState(savedData.informantName || "");
|
|
79
|
+
const [informantRelation, setInformantRelation] = useState(savedData.informantRelation || "");
|
|
80
|
+
|
|
81
|
+
const [toast, setToast] = useState(null);
|
|
82
|
+
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
const rawData = searchData || formData?.connectionDetails;
|
|
85
|
+
const details = rawData?.connectionDetails || rawData || {};
|
|
86
|
+
const addrDetails = rawData?.addressDetails || {};
|
|
87
|
+
|
|
88
|
+
if (details && Object.keys(details).length > 0 && !savedData.firstName) {
|
|
89
|
+
if (!kno && searchKno) setKno(searchKno);
|
|
90
|
+
|
|
91
|
+
if (details.firstName) {
|
|
92
|
+
setFirstName(details.firstName);
|
|
93
|
+
if (details.middleName) setMiddleName(details.middleName);
|
|
94
|
+
if (details.lastName) setLastName(details.lastName);
|
|
95
|
+
} else if (details.consumerName) {
|
|
96
|
+
setConsumerName(details.consumerName);
|
|
97
|
+
const parts = details.consumerName.trim().split(/\s+/);
|
|
98
|
+
setFirstName(parts[0] || "");
|
|
99
|
+
if (parts.length === 2) setLastName(parts[1]);
|
|
100
|
+
if (parts.length > 2) {
|
|
101
|
+
setMiddleName(parts.slice(1, -1).join(" "));
|
|
102
|
+
setLastName(parts[parts.length - 1]);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (details.phoneNumber || addrDetails.mobileNo) setMobile(details.phoneNumber || addrDetails.mobileNo);
|
|
107
|
+
if (details.email || addrDetails.email) setEmail(details.email || addrDetails.email);
|
|
108
|
+
if (addrDetails.whatsappNo) setWhatsapp(addrDetails.whatsappNo);
|
|
109
|
+
if (addrDetails.noOfPerson) setResidents(String(addrDetails.noOfPerson));
|
|
110
|
+
|
|
111
|
+
if (details.consumerType) setConsumerType({ name: details.consumerType });
|
|
112
|
+
if (details.occupantType) setOccupantType({ name: details.occupantType });
|
|
113
|
+
if (details.gender) setGender({ name: details.gender });
|
|
114
|
+
if (details.parentSpouse) setParentSpouseName(details.parentSpouse);
|
|
115
|
+
if (details.documentNumber) {
|
|
116
|
+
setDocumentId(details.documentNumber);
|
|
117
|
+
setIdNumber(details.documentNumber);
|
|
118
|
+
}
|
|
119
|
+
if (details.informantName) setInformantName(details.informantName);
|
|
120
|
+
if (details.informantRelation) setInformantRelation(details.informantRelation);
|
|
121
|
+
}
|
|
122
|
+
}, [searchData, formData?.connectionDetails, searchKno]);
|
|
123
|
+
|
|
124
|
+
// 🔹 OPTIONS
|
|
125
|
+
const consumerTypeOptions = [
|
|
126
|
+
{ name: "Individual" },
|
|
127
|
+
{ name: "Govt" },
|
|
128
|
+
{ name: "Company_Society_Org" },
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
const occupantOptions = [
|
|
132
|
+
{ name: "Self" },
|
|
133
|
+
{ name: "Tenanted" },
|
|
134
|
+
];
|
|
135
|
+
|
|
136
|
+
const genderOptions = [
|
|
137
|
+
{ name: "Male" },
|
|
138
|
+
{ name: "Female" },
|
|
139
|
+
{ name: "Others" },
|
|
140
|
+
{ name: "Not prefer to say" },
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
const identityTypeOptions = [
|
|
144
|
+
{ name: "Aadhaar Card" },
|
|
145
|
+
{ name: "Driving License" },
|
|
146
|
+
{ name: "Passport" },
|
|
147
|
+
{ name: "Voter ID" },
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
const yesNo = [{ name: "Yes" }, { name: "No" }];
|
|
151
|
+
|
|
152
|
+
// 🔹 FILE UPLOAD
|
|
153
|
+
const uploadFile = async (e, setter, idSetter) => {
|
|
154
|
+
const file = e.target.files[0];
|
|
155
|
+
if (!file) return;
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const res = await Digit.UploadServices.Filestorage("EKYC", file);
|
|
159
|
+
const id = res?.data?.files?.[0]?.fileStoreId;
|
|
160
|
+
if (id) {
|
|
161
|
+
setter(file.name);
|
|
162
|
+
idSetter(id);
|
|
163
|
+
}
|
|
164
|
+
} catch {
|
|
165
|
+
setToast({ type: "error", message: "Upload failed" });
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// 🔹 VALIDATION
|
|
170
|
+
const isValid = () => {
|
|
171
|
+
if (!kno) return false;
|
|
172
|
+
if (!consumerType) return false;
|
|
173
|
+
if (!occupantType) return false;
|
|
174
|
+
if (!categoryType) return false;
|
|
175
|
+
if (!firstName) return false;
|
|
176
|
+
if (!mobile) return false;
|
|
177
|
+
if (!residents || Number(residents) <= 0) return false;
|
|
178
|
+
|
|
179
|
+
if (occupantType?.name === "Tenanted" && !documentId && !ownerMobile)
|
|
180
|
+
return false;
|
|
181
|
+
|
|
182
|
+
return consent; // consent must be true
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// 🔹 SUBMIT
|
|
186
|
+
const onStepSelect = async () => {
|
|
187
|
+
// If not valid, just show a warning (or uncomment below to enforce)
|
|
188
|
+
/*
|
|
189
|
+
if (!isValid()) {
|
|
190
|
+
setToast({ type: "error", message: "Fill required fields" });
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
const data = {
|
|
196
|
+
kno,
|
|
197
|
+
consumerType: consumerType?.name,
|
|
198
|
+
occupantType: occupantType?.name,
|
|
199
|
+
categoryType: categoryType?.name,
|
|
200
|
+
consumerName,
|
|
201
|
+
firstName,
|
|
202
|
+
middleName,
|
|
203
|
+
lastName,
|
|
204
|
+
gender: gender?.name,
|
|
205
|
+
parentSpouseName,
|
|
206
|
+
relation,
|
|
207
|
+
mobile,
|
|
208
|
+
whatsapp,
|
|
209
|
+
email,
|
|
210
|
+
residents,
|
|
211
|
+
documentId,
|
|
212
|
+
ownerMobile,
|
|
213
|
+
tenantVerification,
|
|
214
|
+
designation,
|
|
215
|
+
department,
|
|
216
|
+
employeeId,
|
|
217
|
+
landline,
|
|
218
|
+
entityRelation,
|
|
219
|
+
contactPerson,
|
|
220
|
+
entityName,
|
|
221
|
+
idProof: idProof?.name,
|
|
222
|
+
idNumber,
|
|
223
|
+
consent,
|
|
224
|
+
informantIsConsumer,
|
|
225
|
+
informantName,
|
|
226
|
+
informantRelation,
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
await updateMutation.mutateAsync({
|
|
231
|
+
RequestInfo: {},
|
|
232
|
+
updateType: "CONSUMER",
|
|
233
|
+
...data
|
|
234
|
+
});
|
|
235
|
+
setToast({ type: "success", message: "Data updated successfully!" });
|
|
236
|
+
onSelect(config.key, data);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
setToast({ type: "error", message: "Failed to update consumer details" });
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
if (isLoading) {
|
|
243
|
+
return <Loader />;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return (
|
|
247
|
+
<Fragment>
|
|
248
|
+
<FormStep onSelect={onStepSelect} config={config} isDisabled={!isValid()}>
|
|
249
|
+
|
|
250
|
+
<div>
|
|
251
|
+
<CardLabel>Consumer Type *</CardLabel>
|
|
252
|
+
<Dropdown option={consumerTypeOptions} selected={consumerType} select={setConsumerType} />
|
|
253
|
+
</div>
|
|
254
|
+
|
|
255
|
+
<div>
|
|
256
|
+
<CardLabel>Occupant Type *</CardLabel>
|
|
257
|
+
<Dropdown option={occupantOptions} selected={occupantType} select={setOccupantType} />
|
|
258
|
+
</div>
|
|
259
|
+
|
|
260
|
+
<div>
|
|
261
|
+
<CardLabel>Category Type *</CardLabel>
|
|
262
|
+
<Dropdown option={[]} selected={categoryType} select={setCategoryType} />
|
|
263
|
+
</div>
|
|
264
|
+
|
|
265
|
+
<div>
|
|
266
|
+
<CardLabel>First Name *</CardLabel>
|
|
267
|
+
<TextInput value={firstName} onChange={(e) => setFirstName(e.target.value)} />
|
|
268
|
+
</div>
|
|
269
|
+
|
|
270
|
+
<div>
|
|
271
|
+
<CardLabel>Middle Name</CardLabel>
|
|
272
|
+
<TextInput value={middleName} onChange={(e) => setMiddleName(e.target.value)} />
|
|
273
|
+
</div>
|
|
274
|
+
|
|
275
|
+
<div>
|
|
276
|
+
<CardLabel>Last Name</CardLabel>
|
|
277
|
+
<TextInput value={lastName} onChange={(e) => setLastName(e.target.value)} />
|
|
278
|
+
</div>
|
|
279
|
+
|
|
280
|
+
<div>
|
|
281
|
+
<CardLabel>Gender</CardLabel>
|
|
282
|
+
<Dropdown option={genderOptions} selected={gender} select={setGender} />
|
|
283
|
+
</div>
|
|
284
|
+
|
|
285
|
+
<div>
|
|
286
|
+
<CardLabel>Parent/Spouse Name </CardLabel>
|
|
287
|
+
<TextInput value={parentSpouseName} onChange={(e) => setParentSpouseName(e.target.value)} />
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
<div>
|
|
291
|
+
<CardLabel>Mobile *</CardLabel>
|
|
292
|
+
<TextInput value={mobile} onChange={(e) => setMobile(e.target.value)} />
|
|
293
|
+
</div>
|
|
294
|
+
|
|
295
|
+
<div>
|
|
296
|
+
<CardLabel>WhatsApp</CardLabel>
|
|
297
|
+
<TextInput value={whatsapp} onChange={(e) => setWhatsapp(e.target.value)} />
|
|
298
|
+
</div>
|
|
299
|
+
|
|
300
|
+
<div>
|
|
301
|
+
<CardLabel>Email</CardLabel>
|
|
302
|
+
<TextInput value={email} onChange={(e) => setEmail(e.target.value)} />
|
|
303
|
+
</div>
|
|
304
|
+
|
|
305
|
+
<div>
|
|
306
|
+
<CardLabel>No. of Residents *</CardLabel>
|
|
307
|
+
<TextInput value={residents} onChange={(e) => setResidents(e.target.value)} />
|
|
308
|
+
</div>
|
|
309
|
+
<div>
|
|
310
|
+
{console.log("identityType",identityType)}
|
|
311
|
+
<CardLabel>Type of Identity *</CardLabel>
|
|
312
|
+
<Dropdown option={identityTypeOptions} selected={identityType} select={setIdentityType} />
|
|
313
|
+
</div>
|
|
314
|
+
<div>
|
|
315
|
+
<CardLabel>Proof of Identity</CardLabel>
|
|
316
|
+
<UploadFile onUpload={(e) => uploadFile(e, setDocumentProof, setDocumentId)} />
|
|
317
|
+
</div>
|
|
318
|
+
<div>
|
|
319
|
+
<CardLabel>Document Number</CardLabel>
|
|
320
|
+
<TextInput value={documentNumber} onChange={(e) => setDocumentNumber(e.target.value)} />
|
|
321
|
+
</div>
|
|
322
|
+
|
|
323
|
+
<div>
|
|
324
|
+
<CardLabel>Informant Is Consumer</CardLabel>
|
|
325
|
+
<CheckBox
|
|
326
|
+
label="Yes, the informant is the consumer"
|
|
327
|
+
checked={informantIsConsumer}
|
|
328
|
+
onChange={(e) => setInformantIsConsumer(e.target.checked)}
|
|
329
|
+
/>
|
|
330
|
+
</div>
|
|
331
|
+
|
|
332
|
+
{!informantIsConsumer && (
|
|
333
|
+
<Fragment>
|
|
334
|
+
<div>
|
|
335
|
+
<CardLabel>Informant Name</CardLabel>
|
|
336
|
+
<TextInput value={informantName} onChange={(e) => setInformantName(e.target.value)} />
|
|
337
|
+
</div>
|
|
338
|
+
<div>
|
|
339
|
+
<CardLabel>Informant Relation</CardLabel>
|
|
340
|
+
<TextInput value={informantRelation} onChange={(e) => setInformantRelation(e.target.value)} />
|
|
341
|
+
</div>
|
|
342
|
+
</Fragment>
|
|
343
|
+
)}
|
|
344
|
+
|
|
345
|
+
{/* TENANT LOGIC */}
|
|
346
|
+
{occupantType?.name === "Tenanted" && (
|
|
347
|
+
<Fragment>
|
|
348
|
+
<div>
|
|
349
|
+
<CardLabel>Document Proof</CardLabel>
|
|
350
|
+
<UploadFile onUpload={(e) => uploadFile(e, setDocumentProof, setDocumentId)} />
|
|
351
|
+
</div>
|
|
352
|
+
|
|
353
|
+
{!documentId && (
|
|
354
|
+
<Fragment>
|
|
355
|
+
<div>
|
|
356
|
+
<CardLabel>Owner Mobile *</CardLabel>
|
|
357
|
+
<TextInput value={ownerMobile} onChange={(e) => setOwnerMobile(e.target.value)} />
|
|
358
|
+
</div>
|
|
359
|
+
|
|
360
|
+
<div>
|
|
361
|
+
<CardLabel>Tenant Verification</CardLabel>
|
|
362
|
+
<TextInput value={tenantVerification} onChange={(e) => setTenantVerification(e.target.value)} />
|
|
363
|
+
</div>
|
|
364
|
+
</Fragment>
|
|
365
|
+
)}
|
|
366
|
+
</Fragment>
|
|
367
|
+
)}
|
|
368
|
+
|
|
369
|
+
{/* GOVT */}
|
|
370
|
+
{consumerType?.name === "Govt" && (
|
|
371
|
+
<Fragment>
|
|
372
|
+
<div>
|
|
373
|
+
<CardLabel>Designation</CardLabel>
|
|
374
|
+
<TextInput value={designation} onChange={(e) => setDesignation(e.target.value)} />
|
|
375
|
+
</div>
|
|
376
|
+
|
|
377
|
+
<div>
|
|
378
|
+
<CardLabel>Department</CardLabel>
|
|
379
|
+
<TextInput value={department} onChange={(e) => setDepartment(e.target.value)} />
|
|
380
|
+
</div>
|
|
381
|
+
|
|
382
|
+
<div>
|
|
383
|
+
<CardLabel>Employee ID</CardLabel>
|
|
384
|
+
<TextInput value={employeeId} onChange={(e) => setEmployeeId(e.target.value)} />
|
|
385
|
+
</div>
|
|
386
|
+
</Fragment>
|
|
387
|
+
)}
|
|
388
|
+
|
|
389
|
+
{/* OTHER ENTITY */}
|
|
390
|
+
{consumerType?.name === "Company_Society_Org" && (
|
|
391
|
+
<Fragment>
|
|
392
|
+
<div>
|
|
393
|
+
<CardLabel>Entity Name</CardLabel>
|
|
394
|
+
<TextInput value={entityName} onChange={(e) => setEntityName(e.target.value)} />
|
|
395
|
+
</div>
|
|
396
|
+
|
|
397
|
+
<div>
|
|
398
|
+
<CardLabel>Contact Person</CardLabel>
|
|
399
|
+
<TextInput value={contactPerson} onChange={(e) => setContactPerson(e.target.value)} />
|
|
400
|
+
</div>
|
|
401
|
+
</Fragment>
|
|
402
|
+
)}
|
|
403
|
+
</FormStep>
|
|
404
|
+
{toast && (
|
|
405
|
+
<Toast
|
|
406
|
+
error={toast.type === "error"}
|
|
407
|
+
label={toast.message}
|
|
408
|
+
onClose={() => setToast(null)}
|
|
409
|
+
/>
|
|
410
|
+
)}
|
|
411
|
+
</Fragment>
|
|
412
|
+
);
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
export default AadhaarVerification;
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import React, { useState, useEffect, Fragment } from "react";
|
|
2
|
+
import { CardLabel, TextInput, Dropdown, UploadFile, Toast, FormStep, Loader } from "@djb25/digit-ui-react-components";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
|
|
5
|
+
const AddressDetails = ({ config, onSelect }) => {
|
|
6
|
+
const { t } = useTranslation();
|
|
7
|
+
|
|
8
|
+
const tenantId = Digit.ULBService.getCurrentTenantId();
|
|
9
|
+
|
|
10
|
+
// 🔹 STATES
|
|
11
|
+
const [houseNo, setHouseNo] = useState("");
|
|
12
|
+
const [street, setStreet] = useState("");
|
|
13
|
+
const [locality, setLocality] = useState("");
|
|
14
|
+
const [landmark, setLandmark] = useState("");
|
|
15
|
+
const [subLocality, setSubLocality] = useState(null);
|
|
16
|
+
|
|
17
|
+
const [pinCode, setPinCode] = useState("");
|
|
18
|
+
const [assembly, setAssembly] = useState(null);
|
|
19
|
+
const [ward, setWard] = useState(null);
|
|
20
|
+
const [zone, setZone] = useState(null);
|
|
21
|
+
|
|
22
|
+
const [latitude, setLatitude] = useState("");
|
|
23
|
+
const [longitude, setLongitude] = useState("");
|
|
24
|
+
|
|
25
|
+
const [addressType, setAddressType] = useState(null);
|
|
26
|
+
|
|
27
|
+
const [doorPhoto, setDoorPhoto] = useState(null);
|
|
28
|
+
const [doorPhotoFileStoreId, setDoorPhotoFileStoreId] = useState(null);
|
|
29
|
+
|
|
30
|
+
const [toast, setToast] = useState(null);
|
|
31
|
+
|
|
32
|
+
// 🔹 MDMS DATA
|
|
33
|
+
const { data: mdmsData, isLoading } = Digit.Hooks.useCommonMDMS(tenantId, "egov-location", ["TenantBoundary"]);
|
|
34
|
+
|
|
35
|
+
const assemblies = mdmsData?.MdmsRes?.["egov-location"]?.TenantBoundary?.[0]?.boundary?.children || [];
|
|
36
|
+
|
|
37
|
+
// 🔹 AUTO GPS
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
let isMounted = true;
|
|
40
|
+
|
|
41
|
+
if (navigator.geolocation) {
|
|
42
|
+
navigator.geolocation.getCurrentPosition(
|
|
43
|
+
(pos) => {
|
|
44
|
+
if (!isMounted) return;
|
|
45
|
+
setLatitude(pos.coords.latitude);
|
|
46
|
+
setLongitude(pos.coords.longitude);
|
|
47
|
+
},
|
|
48
|
+
() => {
|
|
49
|
+
if (!isMounted) return;
|
|
50
|
+
setToast({ type: "error", message: "GPS access denied" });
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return () => {
|
|
56
|
+
isMounted = false;
|
|
57
|
+
};
|
|
58
|
+
}, []);
|
|
59
|
+
|
|
60
|
+
// 🔹 PIN CODE HANDLER
|
|
61
|
+
const handlePincodeChange = (e) => {
|
|
62
|
+
const value = e.target.value;
|
|
63
|
+
if (/^\d{0,6}$/.test(value)) {
|
|
64
|
+
setPinCode(value);
|
|
65
|
+
|
|
66
|
+
if (value.length === 6) {
|
|
67
|
+
fetchLocationByPincode(value);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
// 🔹 MOCK PIN API (Replace with real API)
|
|
73
|
+
const fetchLocationByPincode = (pin) => {
|
|
74
|
+
// 🔥 Replace this with backend API
|
|
75
|
+
console.log("Fetching location for PIN:", pin);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// 🔹 FILE UPLOAD
|
|
79
|
+
const selectphoto = async (e) => {
|
|
80
|
+
let isMounted = true;
|
|
81
|
+
|
|
82
|
+
const file = e.target.files[0];
|
|
83
|
+
if (!file) return;
|
|
84
|
+
|
|
85
|
+
if (file.size >= 2000000) {
|
|
86
|
+
setToast({ type: "error", message: "Max size 2MB exceeded" });
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
const res = await Digit.UploadServices.Filestorage("EKYC", file, tenantId);
|
|
92
|
+
|
|
93
|
+
if (!isMounted) return;
|
|
94
|
+
|
|
95
|
+
const fileStoreId = res?.data?.files?.[0]?.fileStoreId;
|
|
96
|
+
|
|
97
|
+
if (fileStoreId) {
|
|
98
|
+
setDoorPhotoFileStoreId(fileStoreId);
|
|
99
|
+
|
|
100
|
+
const reader = new FileReader();
|
|
101
|
+
reader.onloadend = () => {
|
|
102
|
+
if (!isMounted) return;
|
|
103
|
+
setDoorPhoto(reader.result);
|
|
104
|
+
};
|
|
105
|
+
reader.readAsDataURL(file);
|
|
106
|
+
|
|
107
|
+
setToast({ type: "success", message: "Upload successful" });
|
|
108
|
+
}
|
|
109
|
+
} catch {
|
|
110
|
+
if (!isMounted) return;
|
|
111
|
+
setToast({ type: "error", message: "Upload failed" });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return () => {
|
|
115
|
+
isMounted = false;
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const removePhoto = () => {
|
|
120
|
+
setDoorPhoto(null);
|
|
121
|
+
setDoorPhotoFileStoreId(null);
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// 🔹 VALIDATION
|
|
125
|
+
const isValid = () => {
|
|
126
|
+
return houseNo && street && pinCode.length === 6 && assembly && ward && zone && latitude && longitude && doorPhotoFileStoreId;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// 🔹 SUBMIT
|
|
130
|
+
const onStepSelect = () => {
|
|
131
|
+
if (!isValid()) {
|
|
132
|
+
setToast({ type: "error", message: "Please fill all mandatory fields" });
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const data = {
|
|
137
|
+
houseNo,
|
|
138
|
+
street,
|
|
139
|
+
locality,
|
|
140
|
+
landmark,
|
|
141
|
+
subLocality,
|
|
142
|
+
pinCode,
|
|
143
|
+
assembly: assembly?.name,
|
|
144
|
+
ward: ward?.name,
|
|
145
|
+
zone: zone?.name,
|
|
146
|
+
latitude,
|
|
147
|
+
longitude,
|
|
148
|
+
addressType: addressType?.name,
|
|
149
|
+
doorPhotoFilestoreId: doorPhotoFileStoreId,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
onSelect(config.key, data);
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
if (isLoading) return <Loader />;
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<Fragment>
|
|
159
|
+
<FormStep t={t} onSelect={onStepSelect} config={config} label={t("ES_COMMON_CONTINUE")}>
|
|
160
|
+
<CardLabel>House No / Flat No *</CardLabel>
|
|
161
|
+
<TextInput value={houseNo} onChange={(e) => setHouseNo(e.target.value)} />
|
|
162
|
+
|
|
163
|
+
<CardLabel>Street / Address Line *</CardLabel>
|
|
164
|
+
<TextInput value={street} onChange={(e) => setStreet(e.target.value)} />
|
|
165
|
+
|
|
166
|
+
<CardLabel>Locality</CardLabel>
|
|
167
|
+
<TextInput value={locality} onChange={(e) => setLocality(e.target.value)} />
|
|
168
|
+
|
|
169
|
+
<CardLabel>Landmark</CardLabel>
|
|
170
|
+
<TextInput value={landmark} onChange={(e) => setLandmark(e.target.value)} />
|
|
171
|
+
|
|
172
|
+
<CardLabel>Sub Locality</CardLabel>
|
|
173
|
+
<Dropdown option={[]} selected={subLocality} select={setSubLocality} />
|
|
174
|
+
|
|
175
|
+
<CardLabel>PIN Code *</CardLabel>
|
|
176
|
+
<TextInput value={pinCode} onChange={handlePincodeChange} maxLength={6} />
|
|
177
|
+
|
|
178
|
+
<CardLabel>Assembly *</CardLabel>
|
|
179
|
+
<Dropdown option={assemblies} selected={assembly} select={setAssembly} />
|
|
180
|
+
|
|
181
|
+
<CardLabel>Ward *</CardLabel>
|
|
182
|
+
<Dropdown option={assembly?.children || []} selected={ward} select={setWard} />
|
|
183
|
+
|
|
184
|
+
<CardLabel>Zone *</CardLabel>
|
|
185
|
+
<Dropdown option={ward?.children || []} selected={zone} select={setZone} />
|
|
186
|
+
|
|
187
|
+
<CardLabel>Latitude</CardLabel>
|
|
188
|
+
<TextInput value={latitude} disabled />
|
|
189
|
+
|
|
190
|
+
<CardLabel>Longitude</CardLabel>
|
|
191
|
+
<TextInput value={longitude} disabled />
|
|
192
|
+
|
|
193
|
+
<CardLabel>Address Type</CardLabel>
|
|
194
|
+
<Dropdown option={[{ name: "Permanent" }, { name: "Correspondence" }, { name: "Other" }]} selected={addressType} select={setAddressType} />
|
|
195
|
+
|
|
196
|
+
<CardLabel>Door Image *</CardLabel>
|
|
197
|
+
<UploadFile onUpload={selectphoto} onDelete={removePhoto} message={doorPhotoFileStoreId ? "Uploaded" : "No file selected"} />
|
|
198
|
+
|
|
199
|
+
{doorPhoto && <img src={doorPhoto} alt="preview" style={{ width: "100%", marginTop: "10px" }} />}
|
|
200
|
+
|
|
201
|
+
{toast && <Toast label={toast.message} error={toast.type === "error"} onClose={() => setToast(null)} />}
|
|
202
|
+
</FormStep>
|
|
203
|
+
</Fragment>
|
|
204
|
+
);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export default AddressDetails;
|