@djb25/digit-ui-module-ekyc 1.0.8 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,486 +1,496 @@
1
- import React, { useState, useRef, Fragment, useEffect } from "react";
1
+ // import React, { useState, Fragment, useEffect } from "react";
2
+ // import {
3
+ // Card,
4
+ // CardLabel,
5
+ // TextInput,
6
+ // SubmitBar,
7
+ // CardHeader,
8
+ // ActionBar,
9
+ // Dropdown,
10
+ // UploadFile,
11
+ // Toast,
12
+ // FormStep,
13
+ // } from "@djb25/digit-ui-react-components";
14
+ // import { useTranslation } from "react-i18next";
15
+ // import { useHistory, useLocation } from "react-router-dom";
16
+ // import { getSavedData } from "../../utils";
17
+
18
+ // const MeterDetails = ({ config, onSelect, formData, t: tProps }) => {
19
+ // const { t } = useTranslation();
20
+ // const history = useHistory();
21
+ // const location = useLocation();
22
+
23
+ // const flowState = location.state || {};
24
+ // const { isEditing, kNumber } = flowState;
25
+
26
+ // // Robust data extraction from formData
27
+ // const activeEdits = formData || {};
28
+ // const rawReviewData = formData?.reviewData || formData?.connectionDetails || {};
29
+ // const reviewWrapper = rawReviewData?.applicationReview || rawReviewData;
30
+ // const applicationData = (Array.isArray(reviewWrapper) ? reviewWrapper[0] : reviewWrapper) || {};
31
+ // const apiData = applicationData?.newData || applicationData;
32
+ // const apiMeter = apiData?.meterDetails || apiData || {};
33
+
34
+ // const tenantId = Digit.ULBService.getCurrentTenantId();
35
+
36
+ // const { data: dataV0 } = Digit.Hooks.ekyc.useGetPropertyType(tenantId);
37
+ // const { data: dataConn } = Digit.Hooks.ekyc.useGetConnectionTypeV2(tenantId);
38
+
39
+ // const mtrData = activeEdits?.meterDetails || {};
40
+
41
+ // const [meterStatus, setMeterStatus] = useState(mtrData.meterStatusData || (apiMeter.metered !== undefined ? { label: apiMeter.metered ? t("EKYC_METER_METERED") : t("EKYC_METER_UNMETERED"), value: apiMeter.metered ? "Metered" : "Unmetered" } : (apiMeter.meterStatus ? { label: t(`EKYC_METER_${apiMeter.meterStatus}`), value: apiMeter.meterStatus } : null)));
42
+ // const [meterPhoto, setMeterStatusPhoto] = useState(mtrData.meterPhoto || null);
43
+ // const [meterPhotoFileStoreId, setMeterStatusPhotoFileStoreId] = useState(mtrData.meterPhotoFileStoreId || apiMeter.meterPhotoFileStoreId || null);
44
+ // const [workingStatus, setWorkingStatus] = useState(mtrData.workingStatusData || (apiMeter.workingStatus !== undefined ? { label: apiMeter.workingStatus ? t("EKYC_METER_WORKING") : t("EKYC_METER_NOT_WORKING"), value: apiMeter.workingStatus ? "Working" : "Not Working" } : (apiMeter.workingStatus ? { label: t(`EKYC_METER_${apiMeter.workingStatus}`), value: apiMeter.workingStatus } : null)));
45
+ // const [meterLocation, setMeterLocation] = useState(mtrData.meterLocation || apiMeter.meterLocationAddress || apiMeter.meterLocation || "");
46
+ // const [lastBillRaised, setLastBillRaised] = useState(mtrData.lastBillRaisedData || (apiMeter.lastBillRaised !== undefined ? { label: apiMeter.lastBillRaised ? t("CORE_COMMON_YES") : t("CORE_COMMON_NO"), value: apiMeter.lastBillRaised ? "Yes" : "No" } : (apiMeter.lastBillRaised ? { label: t(`EKYC_${apiMeter.lastBillRaised}`), value: apiMeter.lastBillRaised } : null)));
47
+ // const [sewerConnection, setSewerConnection] = useState(mtrData.sewerConnectionData || (apiMeter.sewerConnection ? { label: t(`EKYC_${apiMeter.sewerConnection}`), value: apiMeter.sewerConnection } : null));
48
+ // const [connectionCategory, setConnectionCategory] = useState(mtrData.connectionCategoryData || (apiMeter.connectionCategory ? { label: t(apiMeter.connectionCategory), value: apiMeter.connectionCategory } : (apiMeter.typeOfConnection ? { label: t(apiMeter.typeOfConnection), value: apiMeter.typeOfConnection } : null)));
49
+ // const [connectionType, setConnectionType] = useState(mtrData.connectionTypeData || (apiMeter.connectionType ? { label: t(apiMeter.connectionType), value: apiMeter.connectionType } : (apiMeter.connectionCategory ? { label: t(apiMeter.connectionCategory), value: apiMeter.connectionCategory } : null)));
50
+
51
+ // const [toast, setToast] = useState(null);
52
+
53
+ // const getUpdatedData = () => ({
54
+ // meterStatusData: meterStatus,
55
+ // meterPhoto,
56
+ // meterPhotoFileStoreId,
57
+ // workingStatusData: workingStatus,
58
+ // meterLocation,
59
+ // lastBillRaisedData: lastBillRaised,
60
+ // sewerConnectionData: sewerConnection,
61
+ // connectionCategoryData: connectionCategory,
62
+ // connectionTypeData: connectionType,
63
+ // });
64
+
65
+ // const selectphoto = async (e) => {
66
+ // const file = e.target.files[0];
67
+ // if (file) {
68
+ // if (file.size >= 2000000) {
69
+ // setToast({ type: "error", message: t("EKYC_MAXIMUM_UPLOAD_SIZE_EXCEEDED") });
70
+ // return;
71
+ // }
72
+ // try {
73
+ // const res = await Digit.UploadServices.Filestorage("EKYC", file, tenantId);
74
+ // if (res?.data?.files?.[0]?.fileStoreId) {
75
+ // const fileStoreId = res.data.files[0].fileStoreId;
76
+ // setMeterStatusPhotoFileStoreId(fileStoreId);
77
+ // const reader = new FileReader();
78
+ // reader.onloadend = () => {
79
+ // setMeterStatusPhoto(reader.result);
80
+ // if (onSelect) {
81
+ // onSelect(config.key, { ...getUpdatedData(), meterPhoto: reader.result, meterPhotoFileStoreId: fileStoreId });
82
+ // }
83
+ // };
84
+ // reader.readAsDataURL(file);
85
+ // setToast({ type: "success", message: t("EKYC_UPLOAD_SUCCESS") });
86
+ // }
87
+ // } catch (err) {
88
+ // setToast({ type: "error", message: t("EKYC_FILE_UPLOAD_ERROR") });
89
+ // }
90
+ // }
91
+ // };
92
+
93
+ // const onStepSelect = () => {
94
+ // const updatedData = getUpdatedData();
95
+ // if (onSelect) {
96
+ // onSelect(config.key, updatedData);
97
+ // } else {
98
+ // if (isEditing) {
99
+ // history.push("/digit-ui/employee/ekyc/review", { ...location.state, edits: { ...edits, meterDetails: updatedData } });
100
+ // } else {
101
+ // history.push("/digit-ui/employee/ekyc/review", {
102
+ // ...location.state,
103
+ // edits: { ...edits, meterDetails: updatedData }
104
+ // });
105
+ // }
106
+ // }
107
+ // };
108
+
109
+ // const handleUpdateAndReturn = () => {
110
+ // history.push("/digit-ui/employee/ekyc/review", { ...location.state, edits: { ...edits, meterDetails: getUpdatedData() } });
111
+ // };
112
+
113
+ // const meterStatusOptions = [
114
+ // { label: t("EKYC_METER_METERED"), value: "Metered" },
115
+ // { label: t("EKYC_METER_UNMETERED"), value: "Unmetered" },
116
+ // ];
117
+
118
+ // const workingStatusOptions = [
119
+ // { label: t("EKYC_METER_WORKING"), value: "Working" },
120
+ // { label: t("EKYC_METER_NOT_WORKING"), value: "Not Working" },
121
+ // ];
122
+
123
+ // const yesNoOptions = [
124
+ // { label: t("CORE_COMMON_YES"), value: "Yes" },
125
+ // { label: t("CORE_COMMON_NO"), value: "No" },
126
+ // ];
127
+
128
+ // const connectionCategoryOptions = dataV0?.["ws-services-calculation"]?.propertyTypeV2?.map((item) => ({
129
+ // label: t(item.code), value: item.code,
130
+ // })) || [];
131
+
132
+ // const connectionTypeOptions = dataConn?.["ws-services-calculation"]?.connectionTypeV2?.map((item) => ({
133
+ // label: t(item.code), value: item.code,
134
+ // })) || [];
135
+
136
+ // return (
137
+ // <Fragment>
138
+ // <FormStep t={t} onSelect={onStepSelect} config={config || {}} label={t(config?.texts?.submitBarLabel) || (isEditing ? t("EKYC_UPDATE_AND_RETURN") : t("ES_COMMON_CONTINUE"))}>
139
+ // <CardLabel>{t("EKYC_METER_STATUS")}</CardLabel>
140
+ // <Dropdown
141
+ // option={meterStatusOptions}
142
+ // optionKey="label"
143
+ // selected={meterStatus}
144
+ // select={setMeterStatus}
145
+ // t={t}
146
+ // />
147
+
148
+ // {meterStatus?.value === "Metered" && (
149
+ // <Fragment>
150
+ // <CardLabel>{t("EKYC_METER_WORKING_STATUS")}</CardLabel>
151
+ // <Dropdown
152
+ // option={workingStatusOptions}
153
+ // optionKey="label"
154
+ // selected={workingStatus}
155
+ // select={setWorkingStatus}
156
+ // t={t}
157
+ // />
158
+
159
+ // <CardLabel>{t("EKYC_CAPTURE_METER_IMAGE")}</CardLabel>
160
+ // <UploadFile
161
+ // onUpload={selectphoto}
162
+ // onDelete={() => {
163
+ // setMeterStatusPhoto(null);
164
+ // setMeterStatusPhotoFileStoreId(null);
165
+ // if (onSelect) {
166
+ // onSelect(config.key, { ...getUpdatedData(), meterPhoto: null, meterPhotoFileStoreId: null });
167
+ // }
168
+ // }}
169
+ // message={meterPhotoFileStoreId ? t("EKYC_FILE_UPLOADED") : t("EKYC_NO_FILE_SELECTED")}
170
+ // />
171
+ // {meterPhoto && <img src={meterPhoto} style={{ width: "100%", marginTop: "10px", borderRadius: "8px" }} />}
172
+
173
+ // <CardLabel>{t("EKYC_METER_LOCATION")}</CardLabel>
174
+ // <TextInput
175
+ // id="meterLocation"
176
+ // name="meterLocation"
177
+ // value={meterLocation}
178
+ // onChange={(e) => setMeterLocation(e.target.value)}
179
+ // placeholder={t("EKYC_ENTER_METER_LOCATION")}
180
+ // />
181
+
182
+ // <CardLabel>{t("EKYC_LAST_BILL_RAISED")}</CardLabel>
183
+ // <Dropdown
184
+ // option={yesNoOptions}
185
+ // optionKey="label"
186
+ // selected={lastBillRaised}
187
+ // select={setLastBillRaised}
188
+ // t={t}
189
+ // />
190
+ // </Fragment>
191
+ // )}
192
+
193
+ // <CardLabel>{t("EKYC_SEWER_CONNECTION")}</CardLabel>
194
+ // <Dropdown
195
+ // option={yesNoOptions}
196
+ // optionKey="label"
197
+ // selected={sewerConnection}
198
+ // select={setSewerConnection}
199
+ // t={t}
200
+ // />
201
+
202
+ // <CardLabel>{t("EKYC_TYPE_OF_CONNECTION")}</CardLabel>
203
+ // <Dropdown
204
+ // option={connectionCategoryOptions}
205
+ // optionKey="label"
206
+ // selected={connectionCategory}
207
+ // select={setConnectionCategory}
208
+ // t={t}
209
+ // />
210
+
211
+ // <CardLabel>{t("EKYC_CONNECTION_CATEGORY")}</CardLabel>
212
+ // <Dropdown
213
+ // option={connectionTypeOptions}
214
+ // optionKey="label"
215
+ // selected={connectionType}
216
+ // select={setConnectionType}
217
+ // t={t}
218
+ // />
219
+
220
+ // {toast && <Toast label={toast.message} error={toast.type === "error"} onClose={() => setToast(null)} />}
221
+ // </FormStep>
222
+ // {isEditing && !onSelect && (
223
+ // <ActionBar style={{ position: "static", marginTop: "20px" }}>
224
+ // <SubmitBar label={t("EKYC_UPDATE_AND_RETURN")} onSubmit={handleUpdateAndReturn} />
225
+ // </ActionBar>
226
+ // )}
227
+ // </Fragment>
228
+ // );
229
+ // };
230
+
231
+ // export default MeterDetails;
232
+
233
+
234
+
235
+
236
+ import React, { useState, Fragment } from "react";
2
237
  import {
3
- Card,
4
- CardLabel,
5
- TextInput,
6
- SubmitBar,
7
- CardHeader,
8
- ActionBar,
9
- Dropdown,
10
- InfoBannerIcon,
11
- HomeIcon,
12
- UploadFile,
13
- Toast,
238
+ CardLabel,
239
+ TextInput,
240
+ Dropdown,
241
+ UploadFile,
242
+ Toast,
243
+ FormStep,
14
244
  } from "@djb25/digit-ui-react-components";
15
- import { useTranslation } from "react-i18next";
16
- import { useHistory, useLocation } from "react-router-dom";
17
- import { getPayloadDiff, getSavedData } from "../../utils";
18
-
19
- // ─── Icons ────────────────────────────────────────────────────────────────────
20
-
21
- const CheckIcon = ({ size = 11, color = "#fff" }) => (
22
- <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="3" strokeLinecap="round">
23
- <polyline points="20 6 9 17 4 12" />
24
- </svg>
25
- );
26
-
27
- const MeterIcon = ({ size = 16 }) => (
28
- <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
29
- <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67V7z" />
30
- </svg>
31
- );
32
-
33
- const ConnectionIcon = ({ size = 16 }) => (
34
- <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
35
- <path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z" />
36
- </svg>
37
- );
38
-
39
- const CameraIcon = ({ size = 24 }) => (
40
- <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
41
- <path d="M9 2L7.17 4H4C2.9 4 2 4.9 2 6v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-3.17L13 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z" />
42
- </svg>
43
- );
44
-
45
- // ─── Reusable: Section heading with inline rule ───────────────────────────────
46
-
47
- const SectionHead = ({ icon, label }) => (
48
- <div style={{
49
- display: "flex", alignItems: "center", gap: "8px",
50
- marginBottom: "16px", marginTop: "4px",
51
- }}>
52
- <div style={{ opacity: 0.5, display: "flex" }}>{icon}</div>
53
- <span style={{ fontSize: "15px", fontWeight: "600", color: "#0B0C0C", whiteSpace: "nowrap" }}>
54
- {label}
55
- </span>
56
- <div style={{ flex: 1, height: "1px", background: "#EAECF0" }} />
57
- </div>
58
- );
59
-
60
- // ─── Reusable: Icon-prefixed input ────────────────────────────────────────────
61
-
62
- const IconInput = ({ icon, ...props }) => (
63
- <div style={{ position: "relative", width: "100%" }}>
64
- <div style={{
65
- position: "absolute", left: "10px",
66
- top: "50%", transform: "translateY(-50%)",
67
- zIndex: 1, opacity: 0.45, display: "flex", pointerEvents: "none",
68
- }}>
69
- {icon}
70
- </div>
71
- <TextInput textInputStyle={{ paddingLeft: "36px", paddingRight: "12px" }} {...props} />
72
- </div>
73
- );
74
245
 
75
- // ─── Main Component ───────────────────────────────────────────────────────────
246
+ const MeterDetails = ({ config, onSelect }) => {
247
+ const tenantId = Digit.ULBService.getCurrentTenantId();
76
248
 
77
- const MeterDetails = () => {
78
- const { t } = useTranslation();
79
- const history = useHistory();
80
- const location = useLocation();
249
+ // 🔹 STATES
250
+ const [connectionCategory, setConnectionCategory] = useState("");
251
+ const [saType, setSaType] = useState("");
252
+ const [status, setStatus] = useState("");
81
253
 
82
- const flowState = location.state || {
83
- kNumber: sessionStorage.getItem("EKYC_K_NUMBER") || "EKYC-1234567890",
84
- initialData: getSavedData("EKYC_INITIAL_DATA", {})
85
- };
86
- const { kNumber } = flowState;
87
- const initialData = flowState.initialData || getSavedData("EKYC_INITIAL_DATA", {});
88
-
89
- const tenantId = Digit.ULBService.getCurrentTenantId();
90
-
91
- // MDMS Hooks for Connection Details
92
- const { data: dataV0 } = Digit.Hooks.ekyc.useGetPropertyType(tenantId);
93
- const { data: dataConn } = Digit.Hooks.ekyc.useGetConnectionTypeV2(tenantId);
94
-
95
- // ── Meter State ──
96
- const [meterStatus, setMeterStatus] = useState(() =>
97
- getSavedData("EKYC_METER_STATUS_DATA", initialData.meterStatus ? { label: t(`EKYC_METER_${initialData.meterStatus}`), value: initialData.meterStatus } : null)
98
- );
99
- const [meterPhoto, setMeterStatusPhoto] = useState(() => sessionStorage.getItem("EKYC_METER_PHOTO") || null);
100
- const [meterPhotoFileStoreId, setMeterStatusPhotoFileStoreId] = useState(() => sessionStorage.getItem("EKYC_METER_PHOTO_FILESTORE_ID") || null);
101
- const [workingStatus, setWorkingStatus] = useState(() =>
102
- getSavedData("EKYC_METER_WORKING_STATUS_DATA", initialData.workingStatus ? { label: t(`EKYC_METER_${initialData.workingStatus}`), value: initialData.workingStatus } : null)
103
- );
104
- const [meterLocation, setMeterLocation] = useState(() => sessionStorage.getItem("EKYC_METER_LOCATION") || initialData.meterLocation || "");
105
- const [lastBillRaised, setLastBillRaised] = useState(() =>
106
- getSavedData("EKYC_LAST_BILL_RAISED_DATA", initialData.lastBillRaised ? { label: t(`EKYC_${initialData.lastBillRaised}`), value: initialData.lastBillRaised } : null)
107
- );
108
- const [noBillReason, setNoBillReason] = useState(() => sessionStorage.getItem("EKYC_REASON_FOR_NO_BILL") || initialData.noBillReason || "");
109
- const [sewerConnection, setSewerConnection] = useState(() =>
110
- getSavedData("EKYC_SEWER_CONNECTION_DATA", initialData.sewerConnection ? { label: t(`EKYC_${initialData.sewerConnection}`), value: initialData.sewerConnection } : null)
111
- );
112
-
113
- // ── Connection State (Moved from PropertyInfo) ──
114
- const [connectionCategory, setConnectionCategory] = useState(() =>
115
- getSavedData("EKYC_TYPE_OF_CONNECTION_DATA", initialData.typeOfConnection ? { label: t(initialData.typeOfConnection), value: initialData.typeOfConnection } : null)
116
- );
117
- const [connectionType, setConnectionType] = useState(() =>
118
- getSavedData("EKYC_CONNECTION_CATEGORY_DATA", initialData.connectionCategory ? { label: t(initialData.connectionCategory), value: initialData.connectionCategory } : null)
119
- );
120
-
121
- const [filephoto, setFilephoto] = useState(null);
122
- const [error, setError] = useState(null);
123
- const [toast, setToast] = useState(null);
124
-
125
- // Sync state to sessionStorage
126
- useEffect(() => {
127
- sessionStorage.setItem("EKYC_METER_STATUS_DATA", JSON.stringify(meterStatus));
128
- sessionStorage.setItem("EKYC_METER_WORKING_STATUS_DATA", JSON.stringify(workingStatus));
129
- sessionStorage.setItem("EKYC_METER_LOCATION", meterLocation);
130
- sessionStorage.setItem("EKYC_LAST_BILL_RAISED_DATA", JSON.stringify(lastBillRaised));
131
- sessionStorage.setItem("EKYC_REASON_FOR_NO_BILL", noBillReason);
132
- sessionStorage.setItem("EKYC_SEWER_CONNECTION_DATA", JSON.stringify(sewerConnection));
133
- sessionStorage.setItem("EKYC_TYPE_OF_CONNECTION_DATA", JSON.stringify(connectionCategory));
134
- sessionStorage.setItem("EKYC_CONNECTION_CATEGORY_DATA", JSON.stringify(connectionType));
135
- if (meterPhoto) sessionStorage.setItem("EKYC_METER_PHOTO", meterPhoto);
136
- if (meterPhotoFileStoreId) sessionStorage.setItem("EKYC_METER_PHOTO_FILESTORE_ID", meterPhotoFileStoreId);
137
- sessionStorage.setItem("EKYC_CURRENT_STEP", "METER");
138
- }, [meterStatus, workingStatus, meterLocation, lastBillRaised, noBillReason, sewerConnection, connectionCategory, connectionType, meterPhoto, meterPhotoFileStoreId]);
139
-
140
- const uploadFile = async (file, tenantId) => {
141
- if (!file) return null;
142
- const res = await Digit.UploadServices.Filestorage("EKYC", file, tenantId);
143
- return res?.data?.files?.[0]?.fileStoreId || null;
144
- };
254
+ const [mrCode, setMrCode] = useState("");
255
+ const [areaCode, setAreaCode] = useState("");
256
+ const [mrKey, setMrKey] = useState("");
145
257
 
146
- useEffect(() => {
147
- (async () => {
148
- setError(null);
149
- if (filephoto) {
150
- if (filephoto.size >= 2000000) {
151
- setError(t("EKYC_MAXIMUM_UPLOAD_SIZE_EXCEEDED"));
152
- setToast({ type: "error", message: t("EKYC_MAXIMUM_UPLOAD_SIZE_EXCEEDED") });
153
- } else {
154
- try {
155
- setToast({ type: "info", message: t("EKYC_UPLOADING") });
156
- const fileStoreId = await uploadFile(filephoto, tenantId);
157
- if (fileStoreId) {
158
- setMeterStatusPhotoFileStoreId(fileStoreId);
159
- const reader = new FileReader();
160
- reader.onloadend = () => setMeterStatusPhoto(reader.result);
161
- reader.readAsDataURL(filephoto);
162
- setToast({ type: "success", message: t("EKYC_UPLOAD_SUCCESS") });
163
- } else {
164
- setError(t("EKYC_FILE_UPLOAD_ERROR"));
165
- setToast({ type: "error", message: t("EKYC_FILE_UPLOAD_ERROR") });
166
- }
167
- } catch (err) {
168
- setError(t("EKYC_FILE_UPLOAD_ERROR"));
169
- setToast({ type: "error", message: t("EKYC_FILE_UPLOAD_ERROR") });
170
- }
171
- }
172
- }
173
- })();
174
- }, [filephoto]);
175
-
176
- const handleSaveAndContinue = () => {
177
- history.push("/digit-ui/employee/ekyc/review", {
178
- ...location.state,
179
- meterDetails: {
180
- meterStatus, meterPhoto, meterPhotoFileStoreId,
181
- workingStatus, meterLocation, lastBillRaised,
182
- noBillReason, sewerConnection,
183
- connectionType, connectionCategory
184
- }
185
- });
186
- };
258
+ const [meterNumber, setMeterNumber] = useState("");
259
+ const [meterMaker, setMeterMaker] = useState("");
260
+
261
+ const [meterStatus, setMeterStatus] = useState(null);
262
+ const [meterCondition, setMeterCondition] = useState(null);
263
+ const [meterLocation, setMeterLocation] = useState(null);
264
+
265
+ const [lastBillReceived, setLastBillReceived] = useState(null);
266
+ const [billMonthYear, setBillMonthYear] = useState(null);
267
+ const [reason, setReason] = useState("");
268
+
269
+ const [accessToMeter, setAccessToMeter] = useState(null);
270
+ const [sewerConnection, setSewerConnection] = useState(null);
271
+ const [septicTank, setSepticTank] = useState(null);
187
272
 
188
- function selectphoto(e) {
189
- setMeterStatusPhotoFileStoreId(null);
190
- setFilephoto(e.target.files[0]);
273
+ const [meterPhoto, setMeterPhoto] = useState(null);
274
+ const [meterPhotoId, setMeterPhotoId] = useState(null);
275
+
276
+ const [toast, setToast] = useState(null);
277
+
278
+ // 🔹 OPTIONS
279
+ const yesNo = [{ name: "Yes" }, { name: "No" }];
280
+
281
+ const meterStatusOptions = [
282
+ { name: "Metered" },
283
+ { name: "Unmetered" },
284
+ { name: "Can not be identified" },
285
+ ];
286
+
287
+ const meterConditionOptions = [
288
+ { name: "Damaged" },
289
+ { name: "Not-Damaged" },
290
+ ];
291
+
292
+ const meterLocationOptions = [
293
+ { name: "Inside" },
294
+ { name: "Outside" },
295
+ ];
296
+
297
+ // 🔹 MONTH-YEAR OPTIONS (1998–2026)
298
+ const monthYearOptions = [];
299
+ for (let y = 1998; y <= 2026; y++) {
300
+ for (let m = 1; m <= 12; m++) {
301
+ monthYearOptions.push({ name: `${m}/${y}` });
191
302
  }
303
+ }
192
304
 
193
- const meterStatusOptions = [
194
- { label: t("EKYC_METERED"), value: "Metered" },
195
- { label: t("EKYC_UNMETERED"), value: "Unmetered" },
196
- ];
197
-
198
- const workingStatusOptions = [
199
- { label: t("EKYC_WORKING"), value: "Working" },
200
- { label: t("EKYC_NOT_WORKING"), value: "Not Working" },
201
- ];
202
-
203
- const yesNoOptions = [
204
- { label: t("CORE_COMMON_YES"), value: "Yes" },
205
- { label: t("CORE_COMMON_NO"), value: "No" },
206
- ];
207
-
208
- const connectionCategoryOptions =
209
- dataV0?.["ws-services-calculation"]?.propertyTypeV2?.map((item) => ({
210
- label: t(item.code), value: item.code,
211
- })) || [];
212
-
213
- const connectionTypeOptions =
214
- dataConn?.["ws-services-calculation"]?.connectionTypeV2?.map((item) => ({
215
- label: t(item.code), value: item.code,
216
- })) || [];
217
-
218
- return (
219
- <div className="inbox-container">
220
- <style>{`
221
- @keyframes fadeSlideIn {
222
- from { opacity: 0; transform: translateY(8px); }
223
- to { opacity: 1; transform: translateY(0); }
224
- }
225
- `}</style>
226
-
227
- {/* ── Sidebar ── */}
228
- <div className="filters-container">
229
- <Card style={{ display: "flex", alignItems: "center", padding: "12px 16px", marginBottom: "12px", borderRadius: "8px" }}>
230
- <div style={{ color: "#185FA5", marginRight: "10px", display: "flex" }}>
231
- <HomeIcon style={{ width: "20px", height: "20px" }} />
232
- </div>
233
- <div style={{ fontWeight: "600", fontSize: "15px", color: "#0B0C0C" }}>
234
- {t("EKYC_PROCESS") || "eKYC Process"}
235
- </div>
236
- </Card>
237
-
238
- <div style={{ background: "#fff", padding: "16px 14px", borderRadius: "8px", border: "1px solid #EAECF0" }}>
239
- {[
240
- { label: t("EKYC_STEP_AADHAAR") || "Aadhaar", done: true, active: false },
241
- { label: t("EKYC_STEP_ADDRESS") || "Address", done: true, active: false },
242
- { label: t("EKYC_STEP_PROPERTY") || "Property", done: true, active: false },
243
- { label: t("EKYC_STEP_METER") || "Meter", done: false, active: true },
244
- { label: t("EKYC_STEP_REVIEW") || "Review", done: false, active: false },
245
- ].map((step, i) => (
246
- <div key={i} style={{ display: "flex", gap: "10px", alignItems: "flex-start", position: "relative", paddingBottom: i < 4 ? "18px" : 0 }}>
247
- {i < 4 && (
248
- <div style={{ position: "absolute", left: "10px", top: "22px", width: "1px", height: "calc(100% - 10px)", background: "#EAECF0" }} />
249
- )}
250
- <div style={{
251
- width: "20px", height: "20px", borderRadius: "50%", flexShrink: 0, marginTop: "1px",
252
- border: step.done ? "none" : step.active ? "1.5px solid #185FA5" : "1.5px solid #D0D5DD",
253
- background: step.done ? "#0F6E56" : step.active ? "#E6F1FB" : "#fff",
254
- display: "flex", alignItems: "center", justifyContent: "center",
255
- fontSize: "10px", fontWeight: "500",
256
- color: step.done ? "#fff" : step.active ? "#185FA5" : "#98A2B3",
257
- }}>
258
- {step.done ? <CheckIcon size={11} color="#fff" /> : i + 1}
259
- </div>
260
- <div style={{
261
- fontSize: "12px", paddingTop: "2px",
262
- color: step.done ? "#0F6E56" : step.active ? "#0B0C0C" : "#667085",
263
- fontWeight: step.done || step.active ? "600" : "400",
264
- }}>
265
- {step.label}
266
- </div>
267
- </div>
268
- ))}
269
- </div>
270
- </div>
305
+ // 🔹 FREEZE LOGIC
306
+ const isFrozen = meterStatus?.name === "Can not be identified";
271
307
 
272
- {/* ── Main Content ── */}
273
- <div style={{ flex: 1, marginLeft: "16px" }}>
274
- <Card>
275
- {/* Header */}
276
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }}>
277
- <CardHeader style={{ margin: 0, fontSize: "18px" }}>
278
- {t("EKYC_METER_DETAILS_HEADER") || "Meter Details"}
279
- </CardHeader>
280
- <div style={{
281
- background: "#F9FAFB", border: "0.5px solid #EAECF0",
282
- borderRadius: "20px", padding: "4px 14px",
283
- fontSize: "12px", color: "#667085",
284
- }}>
285
- {t("EKYC_K_NUMBER") || "K Number"}:{" "}
286
- <span style={{ color: "#0B0C0C", fontWeight: "600" }}>{kNumber}</span>
287
- </div>
288
- </div>
289
-
290
- <div style={{ animation: "fadeSlideIn 0.3s ease" }}>
291
-
292
- {/* ── Meter Details Section ── */}
293
- <SectionHead
294
- icon={<MeterIcon size={16} />}
295
- label={t("EKYC_METER_DETAILS") || "Meter details"}
296
- />
297
-
298
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "20px" }}>
299
- <div>
300
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
301
- {t("EKYC_METER_STATUS") || "Meter status"}
302
- </div>
303
- <Dropdown
304
- selected={meterStatus}
305
- select={setMeterStatus}
306
- option={meterStatusOptions}
307
- optionKey="label"
308
- t={t}
309
- placeholder={t("EKYC_SELECT") || "Select"}
310
- />
311
- </div>
312
- {meterStatus?.value === "Metered" && (
313
- <div>
314
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
315
- {t("EKYC_METER_WORKING_STATUS") || "Meter working status"}
316
- </div>
317
- <Dropdown
318
- selected={workingStatus}
319
- select={setWorkingStatus}
320
- option={workingStatusOptions}
321
- optionKey="label"
322
- t={t}
323
- placeholder={t("EKYC_SELECT") || "Select"}
324
- />
325
- </div>
326
- )}
327
- </div>
328
-
329
- {meterStatus?.value === "Metered" && (
330
- <Fragment>
331
- <div style={{ marginBottom: "20px" }}>
332
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "8px" }}>
333
- {t("EKYC_CAPTURE_METER_IMAGE") || "Capture meter image"}
334
- </div>
335
- <UploadFile
336
- id={"ekyc-meter-photo"}
337
- extraStyleName={"propertyCreate"}
338
- accept=".jpg,.png,.jpeg"
339
- onUpload={selectphoto}
340
- onDelete={() => {
341
- setMeterStatusPhotoFileStoreId(null);
342
- setMeterStatusPhoto(null);
343
- setFilephoto(null);
344
- }}
345
- message={meterPhotoFileStoreId ? `1 ${t(`EKYC_ACTION_FILEUPLOADED`)}` : t(`EKYC_ACTION_NO_FILEUPLOADED`)}
346
- error={error}
347
- />
348
- {meterPhoto && (
349
- <div style={{ marginTop: "10px", borderRadius: "8px", overflow: "hidden", border: "1px solid #EAECF0" }}>
350
- <img src={meterPhoto} alt="Meter Preview" style={{ width: "100%", maxHeight: "150px", objectFit: "cover" }} />
351
- </div>
352
- )}
353
- </div>
354
-
355
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "20px" }}>
356
- <div>
357
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
358
- {t("EKYC_METER_LOCATION") || "Meter location"}
359
- </div>
360
- <TextInput
361
- value={meterLocation}
362
- onChange={(e) => setMeterLocation(e.target.value)}
363
- placeholder={t("EKYC_ENTER_METER_LOCATION") || "Enter location"}
364
- />
365
- </div>
366
- <div>
367
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
368
- {t("EKYC_LAST_BILL_RAISED") || "Last bill raised"}
369
- </div>
370
- <Dropdown
371
- selected={lastBillRaised}
372
- select={setLastBillRaised}
373
- option={yesNoOptions}
374
- optionKey="label"
375
- t={t}
376
- placeholder={t("EKYC_SELECT") || "Select"}
377
- />
378
- </div>
379
- </div>
380
-
381
- {lastBillRaised?.value === "No" && (
382
- <div style={{ marginBottom: "20px" }}>
383
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
384
- {t("EKYC_REASON_FOR_NO_BILL") || "Reason for no bill"}
385
- </div>
386
- <TextInput
387
- value={noBillReason}
388
- onChange={(e) => setNoBillReason(e.target.value)}
389
- placeholder={t("EKYC_ENTER_REASON") || "Enter reason"}
390
- />
391
- </div>
392
- )}
393
- </Fragment>
394
- )}
395
-
396
- <div style={{ marginBottom: "20px" }}>
397
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
398
- {t("EKYC_SEWER_CONNECTION") || "Sewer connection"}
399
- </div>
400
- <div style={{ width: "calc(50% - 7px)" }}>
401
- <Dropdown
402
- selected={sewerConnection}
403
- select={setSewerConnection}
404
- option={yesNoOptions}
405
- optionKey="label"
406
- t={t}
407
- placeholder={t("EKYC_SELECT") || "Select"}
408
- />
409
- </div>
410
- </div>
411
-
412
- <hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
413
-
414
- {/* ── Property/Connection Details Section ── */}
415
- <SectionHead
416
- icon={<ConnectionIcon size={16} />}
417
- label={t("EKYC_PROPERTY_CONNECTION_DETAILS") || "Property Connection Details"}
418
- />
419
-
420
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "24px" }}>
421
- <div>
422
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
423
- {t("EKYC_TYPE_OF_CONNECTION") || "Type of connection"}
424
- </div>
425
- <Dropdown
426
- selected={connectionCategory}
427
- select={setConnectionCategory}
428
- option={connectionCategoryOptions}
429
- optionKey="label"
430
- t={t}
431
- placeholder={t("EKYC_SELECT") || "Select"}
432
- />
433
- </div>
434
- <div>
435
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
436
- {t("EKYC_CONNECTION_CATEGORY") || "Connection category"}
437
- </div>
438
- <Dropdown
439
- selected={connectionType}
440
- select={setConnectionType}
441
- option={connectionTypeOptions}
442
- optionKey="label"
443
- t={t}
444
- placeholder={t("EKYC_SELECT") || "Select"}
445
- />
446
- </div>
447
- </div>
448
-
449
- </div>
450
-
451
- {/* Submit */}
452
- <div style={{ marginTop: "24px" }}>
453
- <SubmitBar
454
- label={t("EKYC_SAVE_AND_CONTINUE") || "Save & Continue"}
455
- onSubmit={handleSaveAndContinue}
456
- />
457
- </div>
458
-
459
- {/* Secure notice */}
460
- <div style={{
461
- display: "flex", alignItems: "center", justifyContent: "center",
462
- gap: "5px", marginTop: "16px",
463
- fontSize: "11px", color: "#98A2B3",
464
- }}>
465
- <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
466
- <rect x="3" y="11" width="18" height="11" rx="2" />
467
- <path d="M7 11V7a5 5 0 0 1 10 0v4" />
468
- </svg>
469
- {t("EKYC_SECURE_DATA_NOTICE") || "Your data is encrypted and secure"}
470
- </div>
471
- </Card>
308
+ // 🔹 FILE UPLOAD
309
+ const uploadPhoto = async (e) => {
310
+ const file = e.target.files[0];
311
+ if (!file) return;
312
+
313
+ try {
314
+ const res = await Digit.UploadServices.Filestorage("EKYC", file, tenantId);
315
+ const id = res?.data?.files?.[0]?.fileStoreId;
316
+
317
+ if (id) {
318
+ setMeterPhotoId(id);
319
+
320
+ const reader = new FileReader();
321
+ reader.onloadend = () => setMeterPhoto(reader.result);
322
+ reader.readAsDataURL(file);
323
+ }
324
+ } catch {
325
+ setToast({ type: "error", message: "Upload failed" });
326
+ }
327
+ };
328
+
329
+ // 🔹 VALIDATION
330
+ const isValid = () => {
331
+ if (!connectionCategory) return false;
332
+ if (!meterStatus) return false;
333
+ if (!meterLocation) return false;
334
+ if (!lastBillReceived) return false;
335
+ if (!sewerConnection) return false;
336
+
337
+ if (meterStatus?.name === "Metered" && !meterPhotoId) return false;
338
+
339
+ if (lastBillReceived?.name === "No" && !reason) return false;
340
+
341
+ if (sewerConnection?.name === "No" && !septicTank) return false;
342
+
343
+ return true;
344
+ };
345
+
346
+ // 🔹 SUBMIT
347
+ const onStepSelect = () => {
348
+ if (!isValid()) {
349
+ setToast({ type: "error", message: "Fill all mandatory fields" });
350
+ return;
351
+ }
352
+
353
+ const data = {
354
+ connectionCategory,
355
+ saType,
356
+ status,
357
+ mrCode,
358
+ areaCode,
359
+ mrKey,
360
+ meterNumber,
361
+ meterMaker,
362
+ meterStatus: meterStatus?.name,
363
+ meterCondition: meterCondition?.name,
364
+ meterLocation: meterLocation?.name,
365
+ lastBillReceived: lastBillReceived?.name,
366
+ billMonthYear: billMonthYear?.name,
367
+ reason,
368
+ accessToMeter: accessToMeter?.name,
369
+ sewerConnection: sewerConnection?.name,
370
+ septicTank: septicTank?.name,
371
+ meterPhotoId,
372
+ };
373
+
374
+ onSelect(config.key, data);
375
+ };
376
+
377
+ return (
378
+ <Fragment>
379
+ <FormStep onSelect={onStepSelect} config={config}>
380
+ <div>
381
+ <CardLabel>Connection Category *</CardLabel>
382
+ <TextInput value={connectionCategory} onChange={(e) => setConnectionCategory(e.target.value)} />
383
+ </div>
384
+
385
+ <div>
386
+ <CardLabel>SA Type</CardLabel>
387
+ <TextInput value={saType} onChange={(e) => setSaType(e.target.value)} />
388
+ </div>
389
+
390
+ <div>
391
+ <CardLabel>Status</CardLabel>
392
+ <TextInput value={status} onChange={(e) => setStatus(e.target.value)} />
393
+ </div>
394
+
395
+ <div>
396
+ <CardLabel>MR Code</CardLabel>
397
+ <TextInput value={mrCode} onChange={(e) => setMrCode(e.target.value)} />
398
+ </div>
399
+
400
+ <div>
401
+ <CardLabel>Area Code</CardLabel>
402
+ <TextInput value={areaCode} onChange={(e) => setAreaCode(e.target.value)} />
403
+ </div>
404
+
405
+ <div>
406
+ <CardLabel>MR Key</CardLabel>
407
+ <TextInput value={mrKey} onChange={(e) => setMrKey(e.target.value)} />
408
+ </div>
409
+
410
+ {!isFrozen && (
411
+ <Fragment>
412
+ <div>
413
+ <CardLabel>Meter Number</CardLabel>
414
+ <TextInput value={meterNumber} onChange={(e) => setMeterNumber(e.target.value)} />
415
+ </div>
416
+
417
+ <div>
418
+ <CardLabel>Meter Maker</CardLabel>
419
+ <TextInput value={meterMaker} onChange={(e) => setMeterMaker(e.target.value)} />
420
+ </div>
421
+
422
+ <div>
423
+ <CardLabel>Meter Condition</CardLabel>
424
+ <Dropdown option={meterConditionOptions} selected={meterCondition} select={setMeterCondition} />
425
+ </div>
426
+
427
+ {meterStatus?.name === "Metered" && (
428
+ <Fragment>
429
+ <div>
430
+ <CardLabel>Meter Photo *</CardLabel>
431
+ <UploadFile onUpload={uploadPhoto} message={meterPhotoId ? "Uploaded" : "No file"} />
472
432
  </div>
473
- {toast && (
474
- <Toast
475
- label={toast.message}
476
- error={toast.type === "error"}
477
- info={toast.type === "info"}
478
- success={toast.type === "success"}
479
- onClose={() => setToast(null)}
480
- />
433
+ {meterPhoto && (
434
+ <div style={{ gridColumn: "span 2" }}>
435
+ <img src={meterPhoto} style={{ width: "100%" }} />
436
+ </div>
437
+ )}
438
+ </Fragment>
481
439
  )}
440
+ </Fragment>
441
+ )}
442
+
443
+ <div>
444
+ <CardLabel>Meter Status *</CardLabel>
445
+ <Dropdown option={meterStatusOptions} selected={meterStatus} select={setMeterStatus} />
446
+ </div>
447
+
448
+ <div>
449
+ <CardLabel>Meter Location *</CardLabel>
450
+ <Dropdown option={meterLocationOptions} selected={meterLocation} select={setMeterLocation} />
482
451
  </div>
483
- );
452
+
453
+ <div>
454
+ <CardLabel>Last Bill Received *</CardLabel>
455
+ <Dropdown option={yesNo} selected={lastBillReceived} select={setLastBillReceived} />
456
+ </div>
457
+
458
+ {lastBillReceived?.name === "Yes" && (
459
+ <div>
460
+ <CardLabel>When was the last bill received *</CardLabel>
461
+ <Dropdown option={monthYearOptions} selected={billMonthYear} select={setBillMonthYear} />
462
+ </div>
463
+ )}
464
+
465
+ {lastBillReceived?.name === "No" && (
466
+ <div>
467
+ <CardLabel>Reason *</CardLabel>
468
+ <TextInput value={reason} onChange={(e) => setReason(e.target.value)} />
469
+ </div>
470
+ )}
471
+
472
+ <div>
473
+ <CardLabel>Access to Meter</CardLabel>
474
+ <Dropdown option={yesNo} selected={accessToMeter} select={setAccessToMeter} />
475
+ </div>
476
+
477
+ <div>
478
+ <CardLabel>Sewer Connection *</CardLabel>
479
+ <Dropdown option={yesNo} selected={sewerConnection} select={setSewerConnection} />
480
+ </div>
481
+
482
+ {sewerConnection?.name === "No" && (
483
+ <div>
484
+ <CardLabel>Septic Tank *</CardLabel>
485
+ <Dropdown option={yesNo} selected={septicTank} select={setSepticTank} />
486
+ </div>
487
+ )}
488
+
489
+ {toast && <Toast label={toast.message} error={toast.type === "error"} onClose={() => setToast(null)} />}
490
+
491
+ </FormStep>
492
+ </Fragment>
493
+ );
484
494
  };
485
495
 
486
- export default MeterDetails;
496
+ export default MeterDetails;