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

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,579 +1,489 @@
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
+ // RadioButtons,
14
+ // } from "@djb25/digit-ui-react-components";
15
+ // import { useTranslation } from "react-i18next";
16
+ // import { useHistory, useLocation } from "react-router-dom";
17
+ // import { getSavedData } from "../../utils";
18
+
19
+ // const PropertyInfo = ({ config, onSelect, formData, t: tProps }) => {
20
+ // const { t } = useTranslation();
21
+ // const history = useHistory();
22
+ // const location = useLocation();
23
+
24
+ // const flowState = location.state || {};
25
+ // const { isEditing } = flowState;
26
+
27
+ // // Robust data extraction from formData
28
+ // const activeEdits = formData || {};
29
+ // const rawReviewData = formData?.reviewData || formData?.connectionDetails || {};
30
+ // const reviewWrapper = rawReviewData?.applicationReview || rawReviewData;
31
+ // const applicationData = (Array.isArray(reviewWrapper) ? reviewWrapper[0] : reviewWrapper) || {};
32
+ // const apiData = applicationData?.newData || applicationData;
33
+ // const apiProp = apiData?.propertyInfo || apiData || {};
34
+
35
+ // const tenantId = Digit.ULBService.getCurrentTenantId();
36
+
37
+ // const { data: dataV1 } = Digit.Hooks.ekyc.useGetUserType(tenantId);
38
+ // const { data: dataV2 } = Digit.Hooks.ekyc.useGetFloorCount(tenantId);
39
+ // const { data: dataV3 } = Digit.Hooks.ekyc.useGetPropertyType(tenantId);
40
+ // const { data: dataConn } = Digit.Hooks.ekyc.useGetConnectionTypeV2(tenantId);
41
+
42
+ // const userTypeOptions = dataV1?.["ws-services-calculation"]?.userTypeV2?.map((item) => ({
43
+ // label: t(item.code), value: item.code,
44
+ // })) || [];
45
+
46
+ // const floorOptions = dataV2?.["ws-services-calculation"]?.floorCount?.map((item) => ({
47
+ // label: t(item.code), value: item.code,
48
+ // })) || [];
49
+
50
+ // const connectionCategoryOptions = dataV3?.["ws-services-calculation"]?.propertyTypeV2?.map((item) => ({
51
+ // label: t(item.code), value: item.code,
52
+ // })) || [];
53
+
54
+ // const connectionTypeOptions = dataConn?.["ws-services-calculation"]?.connectionTypeV2?.map((item) => ({
55
+ // label: t(item.code), value: item.code,
56
+ // })) || [];
57
+
58
+ // const propData = activeEdits?.propertyDetails || {};
59
+
60
+ // const [ownerType, setOwnerType] = useState(propData.ownerType || (apiProp.tenantName ? "TENANT" : "OWNER"));
61
+ // const [pidNumber, setPidNumber] = useState(propData.pidNumber || apiProp.pidNumber || "");
62
+ // const [userType, setUserType] = useState(propData.userTypeData || null);
63
+ // const [noOfFloors, setNoOfFloors] = useState(propData.noOfFloorsData || null);
64
+ // const [connectionCategory, setConnectionCategory] = useState(propData.connectionCategoryData || null);
65
+ // const [typeOfConnection, setTypeOfConnection] = useState(propData.typeOfConnectionData || null);
66
+
67
+ // const [propertyDocument, setPropertyDocument] = useState(propData.propertyDocument || null);
68
+ // const [propertyDocumentFileStoreId, setPropertyDocumentFileStoreId] = useState(propData.propertyDocumentFileStoreId || apiProp.propertyDocumentFileStoreId || null);
69
+
70
+ // const [toast, setToast] = useState(null);
71
+
72
+ // // Pre-fill dropdowns from API
73
+ // useEffect(() => {
74
+ // if (!userType && userTypeOptions.length > 0) {
75
+ // const val = apiProp.userType;
76
+ // const found = userTypeOptions.find(o => o.value === val || o.label === val);
77
+ // if (found) setUserType(found);
78
+ // }
79
+ // }, [userTypeOptions, apiProp.userType]);
80
+
81
+ // useEffect(() => {
82
+ // if (!noOfFloors && floorOptions.length > 0) {
83
+ // const val = apiProp.numberOfFloors || apiProp.noOfFloor;
84
+ // const found = floorOptions.find(o => o.value === String(val) || o.label === String(val));
85
+ // if (found) setNoOfFloors(found);
86
+ // }
87
+ // }, [floorOptions, apiProp.numberOfFloors]);
88
+
89
+ // useEffect(() => {
90
+ // if (!connectionCategory && connectionCategoryOptions.length > 0) {
91
+ // const val = apiProp.connectionCategory;
92
+ // const found = connectionCategoryOptions.find(o => o.value === val || o.label === val);
93
+ // if (found) setConnectionCategory(found);
94
+ // }
95
+ // }, [connectionCategoryOptions, apiProp.connectionCategory]);
96
+
97
+ // useEffect(() => {
98
+ // if (!typeOfConnection && connectionTypeOptions.length > 0) {
99
+ // const val = apiProp.typeOfConnection;
100
+ // const found = connectionTypeOptions.find(o => o.value === val || o.label === val);
101
+ // if (found) setTypeOfConnection(found);
102
+ // }
103
+ // }, [connectionTypeOptions, apiProp.typeOfConnection]);
104
+
105
+ // const getUpdatedData = () => ({
106
+ // ownerType,
107
+ // pidNumber,
108
+ // userTypeData: userType,
109
+ // noOfFloorsData: noOfFloors,
110
+ // connectionCategoryData: connectionCategory,
111
+ // typeOfConnectionData: typeOfConnection,
112
+ // propertyDocument,
113
+ // propertyDocumentFileStoreId,
114
+ // kno: apiProp.kno || flowState.kno
115
+ // });
116
+
117
+ // const selectpdf = async (e) => {
118
+ // const file = e.target.files[0];
119
+ // if (file) {
120
+ // if (file.size >= 5000000) {
121
+ // setToast({ type: "error", message: t("EKYC_MAXIMUM_UPLOAD_SIZE_EXCEEDED") });
122
+ // return;
123
+ // }
124
+ // try {
125
+ // const res = await Digit.UploadServices.Filestorage("EKYC", file, tenantId);
126
+ // if (res?.data?.files?.[0]?.fileStoreId) {
127
+ // const fileStoreId = res.data.files[0].fileStoreId;
128
+ // setPropertyDocumentFileStoreId(fileStoreId);
129
+ // setPropertyDocument(file.name);
130
+ // if (onSelect) {
131
+ // onSelect(config.key, { ...getUpdatedData(), propertyDocument: file.name, propertyDocumentFileStoreId: fileStoreId });
132
+ // }
133
+ // setToast({ type: "success", message: t("EKYC_UPLOAD_SUCCESS") });
134
+ // }
135
+ // } catch (err) {
136
+ // setToast({ type: "error", message: t("EKYC_FILE_UPLOAD_ERROR") });
137
+ // }
138
+ // }
139
+ // };
140
+
141
+ // const onStepSelect = () => {
142
+ // const updatedData = getUpdatedData();
143
+ // if (onSelect) {
144
+ // onSelect(config.key, updatedData);
145
+ // } else {
146
+ // if (isEditing) {
147
+ // history.push("/digit-ui/employee/ekyc/review", { ...location.state, edits: { ...edits, propertyDetails: updatedData } });
148
+ // } else {
149
+ // history.push("/digit-ui/employee/ekyc/meter-details", {
150
+ // ...location.state,
151
+ // edits: { ...edits, propertyDetails: updatedData }
152
+ // });
153
+ // }
154
+ // }
155
+ // };
156
+
157
+ // const handleUpdateAndReturn = () => {
158
+ // history.push("/digit-ui/employee/ekyc/review", { ...location.state, edits: { ...edits, propertyDetails: getUpdatedData() } });
159
+ // };
160
+
161
+ // const ownerOptions = [
162
+ // { code: "OWNER", name: "EKYC_OWNER" },
163
+ // { code: "TENANT", name: "EKYC_TENANT" },
164
+ // ];
165
+
166
+ // return (
167
+ // <Fragment>
168
+ // <FormStep t={t} onSelect={onStepSelect} config={config || {}} label={t(config?.texts?.submitBarLabel) || (isEditing ? t("EKYC_UPDATE_AND_RETURN") : t("ES_COMMON_CONTINUE"))}>
169
+ // <CardLabel>{t("EKYC_OWNER_TENANT")}</CardLabel>
170
+ // <RadioButtons
171
+ // options={ownerOptions}
172
+ // optionsKey="name"
173
+ // selectedOption={ownerOptions.find(o => o.code === ownerType)}
174
+ // onSelect={(val) => setOwnerType(val.code)}
175
+ // />
176
+
177
+ // <CardLabel>{t("EKYC_PID_NUMBER")}</CardLabel>
178
+ // <TextInput
179
+ // id="pidNumber"
180
+ // name="pidNumber"
181
+ // value={pidNumber}
182
+ // onChange={(e) => setPidNumber(e.target.value)}
183
+ // placeholder={t("EKYC_ENTER_PID_NUMBER")}
184
+ // />
185
+
186
+ // <CardLabel>{t("EKYC_USER_TYPE")}</CardLabel>
187
+ // <Dropdown
188
+ // option={userTypeOptions}
189
+ // optionKey="label"
190
+ // selected={userType}
191
+ // select={setUserType}
192
+ // t={t}
193
+ // />
194
+
195
+ // <CardLabel>{t("EKYC_NO_OF_FLOORS")}</CardLabel>
196
+ // <Dropdown
197
+ // option={floorOptions}
198
+ // optionKey="label"
199
+ // selected={noOfFloors}
200
+ // select={setNoOfFloors}
201
+ // t={t}
202
+ // />
203
+
204
+ // <CardLabel>{t("EKYC_TYPE_OF_CONNECTION")}</CardLabel>
205
+ // <Dropdown
206
+ // option={connectionTypeOptions}
207
+ // optionKey="label"
208
+ // selected={typeOfConnection}
209
+ // select={setTypeOfConnection}
210
+ // t={t}
211
+ // />
212
+
213
+ // <CardLabel>{t("EKYC_CONNECTION_CATEGORY")}</CardLabel>
214
+ // <Dropdown
215
+ // option={connectionCategoryOptions}
216
+ // optionKey="label"
217
+ // selected={connectionCategory}
218
+ // select={setConnectionCategory}
219
+ // t={t}
220
+ // />
221
+
222
+ // <CardLabel>{t("EKYC_UPLOAD_PROPERTY_DOC")}</CardLabel>
223
+ // <UploadFile
224
+ // onUpload={selectpdf}
225
+ // onDelete={() => {
226
+ // setPropertyDocument(null);
227
+ // setPropertyDocumentFileStoreId(null);
228
+ // if (onSelect) {
229
+ // onSelect(config.key, { ...getUpdatedData(), propertyDocument: null, propertyDocumentFileStoreId: null });
230
+ // }
231
+ // }}
232
+ // message={propertyDocumentFileStoreId ? t("EKYC_FILE_UPLOADED") : t("EKYC_NO_FILE_SELECTED")}
233
+ // />
234
+
235
+ // {toast && <Toast label={toast.message} error={toast.type === "error"} onClose={() => setToast(null)} />}
236
+ // </FormStep>
237
+ // {isEditing && !onSelect && (
238
+ // <ActionBar style={{ position: "static", marginTop: "20px" }}>
239
+ // <SubmitBar label={t("EKYC_UPDATE_AND_RETURN")} onSubmit={handleUpdateAndReturn} />
240
+ // </ActionBar>
241
+ // )}
242
+ // </Fragment>
243
+ // );
244
+ // };
245
+
246
+ // export default PropertyInfo;
247
+
248
+
249
+
250
+ import React, { useState, Fragment } from "react";
2
251
  import {
3
- Card,
4
- CardLabel,
5
- TextInput,
6
- SubmitBar,
7
- CardHeader,
8
- ActionBar,
9
- Dropdown,
10
- InfoBannerIcon,
11
- HomeIcon,
12
- UploadFile,
13
- Toast,
252
+ CardLabel,
253
+ TextInput,
254
+ Dropdown,
255
+ UploadFile,
256
+ Toast,
257
+ FormStep,
14
258
  } from "@djb25/digit-ui-react-components";
15
259
  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 BuildingIcon = ({ size = 16 }) => (
28
- <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
29
- <path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8V9h8v10zm-2-8h-4v2h4v-2zm0 4h-4v2h4v-2z" />
30
- </svg>
31
- );
32
-
33
- const BriefcaseIcon = ({ size = 16 }) => (
34
- <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
35
- <path d="M20 6H16V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-2 .89-2 2v13c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6-2v2h-4V4h4z" />
36
- </svg>
37
- );
38
-
39
- const DocumentIcon = ({ size = 16 }) => (
40
- <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
41
- <path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13z" />
42
- </svg>
43
- );
44
-
45
- const CameraIcon = ({ size = 24 }) => (
46
- <svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
47
- <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" />
48
- </svg>
49
- );
50
-
51
- const TrashIcon = ({ size = 14 }) => (
52
- <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="#D92D20" strokeWidth="2" strokeLinecap="round">
53
- <polyline points="3 6 5 6 21 6" />
54
- <path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
55
- <path d="M10 11v6M14 11v6" />
56
- <path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2" />
57
- </svg>
58
- );
59
-
60
- const PidIcon = ({ size = 16 }) => (
61
- <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
62
- <rect x="3" y="4" width="18" height="16" rx="2" />
63
- <path d="M7 8h5M7 12h8M7 16h4" />
64
- </svg>
65
- );
66
-
67
- // ─── Reusable: Section heading with inline rule ───────────────────────────────
68
-
69
- const SectionHead = ({ icon, label }) => (
70
- <div style={{
71
- display: "flex", alignItems: "center", gap: "8px",
72
- marginBottom: "16px", marginTop: "4px",
73
- }}>
74
- <div style={{ opacity: 0.5, display: "flex" }}>{icon}</div>
75
- <span style={{ fontSize: "15px", fontWeight: "600", color: "#0B0C0C", whiteSpace: "nowrap" }}>
76
- {label}
77
- </span>
78
- <div style={{ flex: 1, height: "1px", background: "#EAECF0" }} />
79
- </div>
80
- );
81
-
82
- // ─── Reusable: Icon-prefixed input ────────────────────────────────────────────
83
-
84
- const IconInput = ({ icon, ...props }) => (
85
- <div style={{ position: "relative", width: "100%" }}>
86
- <div style={{
87
- position: "absolute", left: "10px",
88
- top: "50%", transform: "translateY(-50%)",
89
- zIndex: 1, opacity: 0.45, display: "flex", pointerEvents: "none",
90
- }}>
91
- {icon}
92
- </div>
93
- <TextInput textInputStyle={{ paddingLeft: "36px", paddingRight: "12px" }} {...props} />
94
- </div>
95
- );
96
260
 
97
- // ─── Main Component ───────────────────────────────────────────────────────────
261
+ const PropertyInfo = ({ config, onSelect }) => {
262
+ const { t } = useTranslation();
263
+ const tenantId = Digit.ULBService.getCurrentTenantId();
98
264
 
99
- const PropertyInfo = () => {
100
- const { t } = useTranslation();
101
- const history = useHistory();
102
- const location = useLocation();
265
+ // 🔹 STATES
266
+ const [pidNumber, setPidNumber] = useState("");
267
+ const [propertyType, setPropertyType] = useState(null);
268
+ const [subPropertyCategory, setSubPropertyCategory] = useState(null);
103
269
 
104
- const flowState = location.state || {
105
- kNumber: sessionStorage.getItem("EKYC_K_NUMBER") || "EKYC-1234567890",
106
- initialData: getSavedData("EKYC_INITIAL_DATA", {})
107
- };
108
- const { kNumber } = flowState;
109
- const initialData = flowState.initialData || getSavedData("EKYC_INITIAL_DATA", {});
110
-
111
- const tenantId = Digit.ULBService.getCurrentTenantId();
112
- const { data: dataV0 } = Digit.Hooks.ekyc.useGetPropertyType(tenantId);
113
- const { data: dataConn } = Digit.Hooks.ekyc.useGetConnectionTypeV2(tenantId);
114
- const { data: dataV1 } = Digit.Hooks.ekyc.useGetUserType(tenantId);
115
- const { data: dataV2 } = Digit.Hooks.ekyc.useGetFloorCount(tenantId);
116
-
117
- const [ownerType, setOwnerType] = useState(() => sessionStorage.getItem("EKYC_OWNER_TYPE") || initialData.ownerType || "OWNER");
118
- const [pidNumber, setPidNumber] = useState(() => sessionStorage.getItem("EKYC_PID_NUMBER") || initialData.pidNumber || "");
119
- const [connectionCategory, setConnectionCategory] = useState(() =>
120
- getSavedData("EKYC_TYPE_OF_CONNECTION_DATA", initialData.typeOfConnection ? { label: t(initialData.typeOfConnection), value: initialData.typeOfConnection } : null)
121
- );
122
- const [connectionType, setConnectionType] = useState(() =>
123
- getSavedData("EKYC_CONNECTION_CATEGORY_DATA", initialData.connectionCategory ? { label: t(initialData.connectionCategory), value: initialData.connectionCategory } : null)
124
- );
125
- const [userType, setUserType] = useState(() =>
126
- getSavedData("EKYC_USER_TYPE_DATA", initialData.userType ? { label: t(initialData.userType), value: initialData.userType } : null)
127
- );
128
- const [noOfFloors, setNoOfFloors] = useState(() =>
129
- getSavedData("EKYC_NO_OF_FLOORS_DATA", initialData.noOfFloor ? { label: t(initialData.noOfFloor), value: initialData.noOfFloor } : null)
130
- );
131
- const [propertyDocument, setPropertyDocument] = useState(() => sessionStorage.getItem("EKYC_PROPERTY_DOC") || null);
132
- const [propertyDocumentFileStoreId, setPropertyDocumentFileStoreId] = useState(() => sessionStorage.getItem("EKYC_PROPERTY_DOC_FILESTORE_ID") || null);
133
- const [buildingPhoto, setBuildingPhoto] = useState(() => sessionStorage.getItem("EKYC_BUILDING_PHOTO") || null);
134
- const [buildingPhotoFileStoreId, setBuildingPhotoFileStoreId] = useState(() => sessionStorage.getItem("EKYC_BUILDING_PHOTO_FILESTORE_ID") || null);
135
-
136
- const [filepdf, setFilepdf] = useState(null);
137
- const [filephoto, setFilephoto] = useState(null);
138
- const [error, setError] = useState(null);
139
- const [toast, setToast] = useState(null);
140
-
141
- // Sync property state to sessionStorage
142
- useEffect(() => {
143
- sessionStorage.setItem("EKYC_OWNER_TYPE", ownerType);
144
- sessionStorage.setItem("EKYC_PID_NUMBER", pidNumber);
145
- sessionStorage.setItem("EKYC_TYPE_OF_CONNECTION_DATA", JSON.stringify(connectionCategory));
146
- sessionStorage.setItem("EKYC_CONNECTION_CATEGORY_DATA", JSON.stringify(connectionType));
147
- sessionStorage.setItem("EKYC_USER_TYPE_DATA", JSON.stringify(userType));
148
- sessionStorage.setItem("EKYC_NO_OF_FLOORS_DATA", JSON.stringify(noOfFloors));
149
- if (propertyDocument) sessionStorage.setItem("EKYC_PROPERTY_DOC", propertyDocument);
150
- if (propertyDocumentFileStoreId) sessionStorage.setItem("EKYC_PROPERTY_DOC_FILESTORE_ID", propertyDocumentFileStoreId);
151
- if (buildingPhoto) sessionStorage.setItem("EKYC_BUILDING_PHOTO", buildingPhoto);
152
- if (buildingPhotoFileStoreId) sessionStorage.setItem("EKYC_BUILDING_PHOTO_FILESTORE_ID", buildingPhotoFileStoreId);
153
- sessionStorage.setItem("EKYC_CURRENT_STEP", "PROPERTY");
154
- }, [ownerType, pidNumber, connectionCategory, connectionType, userType, noOfFloors, propertyDocument, propertyDocumentFileStoreId, buildingPhoto, buildingPhotoFileStoreId]);
155
-
156
- const uploadFile = async (file, tenantId) => {
157
- if (!file) return null;
158
- const res = await Digit.UploadServices.Filestorage("EKYC", file, tenantId);
159
- return res?.data?.files?.[0]?.fileStoreId || null;
160
- };
270
+ const [noOfFloors, setNoOfFloors] = useState("");
271
+ const [floorNo, setFloorNo] = useState("");
161
272
 
162
- const dataUrlToFile = (dataUrl, filename) => {
163
- const arr = dataUrl.split(",");
164
- const mime = arr[0].match(/:(.*?);/)[1];
165
- const bstr = atob(arr[1]);
166
- let n = bstr.length;
167
- const u8arr = new Uint8Array(n);
168
- while (n--) u8arr[n] = bstr.charCodeAt(n);
169
- return new File([u8arr], filename, { type: mime });
170
- };
273
+ const [noOfRooms, setNoOfRooms] = useState("");
274
+ const [noOfBeds, setNoOfBeds] = useState("");
275
+ const [dwellingUnits, setDwellingUnits] = useState("");
171
276
 
172
- // useEffect hooks for automatic upload (WT-style)
173
- useEffect(() => {
174
- (async () => {
175
- setError(null);
176
- if (filepdf) {
177
- if (filepdf.size >= 5000000) {
178
- setError(t("EKYC_MAXIMUM_UPLOAD_SIZE_EXCEEDED"));
179
- setToast({ type: "error", message: t("EKYC_MAXIMUM_UPLOAD_SIZE_EXCEEDED") });
180
- } else {
181
- try {
182
- setToast({ type: "info", message: t("EKYC_UPLOADING") });
183
- const fileStoreId = await uploadFile(filepdf, tenantId);
184
- if (fileStoreId) {
185
- setPropertyDocumentFileStoreId(fileStoreId);
186
- setPropertyDocument(filepdf.name);
187
- setToast({ type: "success", message: t("EKYC_UPLOAD_SUCCESS") });
188
- } else {
189
- setError(t("EKYC_FILE_UPLOAD_ERROR"));
190
- setToast({ type: "error", message: t("EKYC_FILE_UPLOAD_ERROR") });
191
- }
192
- } catch (err) {
193
- setError(t("EKYC_FILE_UPLOAD_ERROR"));
194
- setToast({ type: "error", message: t("EKYC_FILE_UPLOAD_ERROR") });
195
- }
196
- }
197
- }
198
- })();
199
- }, [filepdf]);
200
-
201
- useEffect(() => {
202
- (async () => {
203
- setError(null);
204
- if (filephoto) {
205
- if (filephoto.size >= 2000000) {
206
- setError(t("EKYC_MAXIMUM_UPLOAD_SIZE_EXCEEDED"));
207
- setToast({ type: "error", message: t("EKYC_MAXIMUM_UPLOAD_SIZE_EXCEEDED") });
208
- } else {
209
- try {
210
- setToast({ type: "info", message: t("EKYC_UPLOADING") });
211
- const fileStoreId = await uploadFile(filephoto, tenantId);
212
- if (fileStoreId) {
213
- setBuildingPhotoFileStoreId(fileStoreId);
214
- // Also store as dataURL for preview if needed, but for WT style we just need the fileStoreId
215
- const reader = new FileReader();
216
- reader.onloadend = () => setBuildingPhoto(reader.result);
217
- reader.readAsDataURL(filephoto);
218
- setToast({ type: "success", message: t("EKYC_UPLOAD_SUCCESS") });
219
- } else {
220
- setError(t("EKYC_FILE_UPLOAD_ERROR"));
221
- setToast({ type: "error", message: t("EKYC_FILE_UPLOAD_ERROR") });
222
- }
223
- } catch (err) {
224
- setError(t("EKYC_FILE_UPLOAD_ERROR"));
225
- setToast({ type: "error", message: t("EKYC_FILE_UPLOAD_ERROR") });
226
- }
227
- }
228
- }
229
- })();
230
- }, [filephoto]);
231
-
232
- const fileRef = useRef(null);
233
- const cameraRef = useRef(null);
234
-
235
- const handleSaveAndContinue = () => {
236
- history.push("/digit-ui/employee/ekyc/meter-details", {
237
- ...flowState,
238
- propertyDetails: {
239
- ownerType, pidNumber, connectionType,
240
- connectionCategory, userType, noOfFloors,
241
- propertyDocument, propertyDocumentFileStoreId,
242
- buildingPhoto, buildingPhotoFileStoreId,
243
- },
244
- initialData,
245
- });
246
- };
277
+ const [buildingImage, setBuildingImage] = useState(null);
278
+ const [buildingImageId, setBuildingImageId] = useState(null);
247
279
 
248
- function selectpdf(e) {
249
- setPropertyDocumentFileStoreId(null);
250
- setFilepdf(e.target.files[0]);
280
+ const [toast, setToast] = useState(null);
281
+
282
+ // 🔹 PROPERTY TYPE OPTIONS (you can replace with MDMS)
283
+ const propertyTypeOptions = [
284
+ { name: "Residential" },
285
+ { name: "Commercial" },
286
+ { name: "Hotel" },
287
+ { name: "Hospital" },
288
+ { name: "Nursing Home" },
289
+ ];
290
+
291
+ // 🔹 FILE UPLOAD
292
+ const handleUpload = async (e) => {
293
+ const file = e.target.files[0];
294
+ if (!file) return;
295
+
296
+ if (file.size > 2000000) {
297
+ setToast({ type: "error", message: "Max size 2MB exceeded" });
298
+ return;
251
299
  }
252
300
 
253
- function selectphoto(e) {
254
- setBuildingPhotoFileStoreId(null);
255
- setFilephoto(e.target.files[0]);
301
+ try {
302
+ const res = await Digit.UploadServices.Filestorage(
303
+ "EKYC",
304
+ file,
305
+ tenantId
306
+ );
307
+
308
+ const fileStoreId = res?.data?.files?.[0]?.fileStoreId;
309
+
310
+ if (fileStoreId) {
311
+ setBuildingImageId(fileStoreId);
312
+
313
+ const reader = new FileReader();
314
+ reader.onloadend = () => setBuildingImage(reader.result);
315
+ reader.readAsDataURL(file);
316
+
317
+ setToast({ type: "success", message: "Upload successful" });
318
+ }
319
+ } catch {
320
+ setToast({ type: "error", message: "Upload failed" });
321
+ }
322
+ };
323
+
324
+ // 🔹 VALIDATION
325
+ const isValid = () => {
326
+ if (!noOfFloors || Number(noOfFloors) < 1) return false;
327
+ if (!buildingImageId) return false;
328
+
329
+ if (propertyType?.name === "Hotel" && !noOfRooms) return false;
330
+ if (
331
+ (propertyType?.name === "Hospital" ||
332
+ propertyType?.name === "Nursing Home") &&
333
+ !noOfBeds
334
+ )
335
+ return false;
336
+
337
+ return true;
338
+ };
339
+
340
+ // 🔹 SUBMIT
341
+ const onStepSelect = () => {
342
+ if (!isValid()) {
343
+ setToast({ type: "error", message: "Fill all required fields" });
344
+ return;
256
345
  }
257
346
 
258
- const connectionCategoryOptions =
259
- dataV0?.["ws-services-calculation"]?.propertyTypeV2?.map((item) => ({
260
- label: t(item.code), value: item.code,
261
- })) || [];
262
-
263
- const connectionTypeOptions =
264
- dataConn?.["ws-services-calculation"]?.connectionTypeV2?.map((item) => ({
265
- label: t(item.code), value: item.code,
266
- })) || [];
267
-
268
- const userTypeOptions =
269
- dataV1?.["ws-services-calculation"]?.userTypeV2?.map((item) => ({
270
- label: t(item.code), value: item.code,
271
- })) || [];
272
-
273
- const floorOptions =
274
- dataV2?.["ws-services-calculation"]?.floorCount?.map((item) => ({
275
- label: t(item.code), value: item.code,
276
- })) || [];
277
-
278
- return (
279
- <>
280
- <div className="inbox-container">
281
- <style>{`
282
- @keyframes fadeSlideIn {
283
- from { opacity: 0; transform: translateY(8px); }
284
- to { opacity: 1; transform: translateY(0); }
285
- }
286
- `}</style>
287
-
288
- {/* ── Sidebar ── */}
289
- <div className="filters-container">
290
- <Card style={{ display: "flex", alignItems: "center", padding: "12px 16px", marginBottom: "12px", borderRadius: "8px" }}>
291
- <div style={{ color: "#185FA5", marginRight: "10px", display: "flex" }}>
292
- <HomeIcon style={{ width: "20px", height: "20px" }} />
293
- </div>
294
- <div style={{ fontWeight: "600", fontSize: "15px", color: "#0B0C0C" }}>
295
- {t("EKYC_PROCESS") || "eKYC Process"}
296
- </div>
297
- </Card>
298
-
299
- <div style={{ background: "#fff", padding: "16px 14px", borderRadius: "8px", border: "1px solid #EAECF0" }}>
300
- {[
301
- { label: t("EKYC_STEP_AADHAAR") || "Aadhaar", done: true, active: false },
302
- { label: t("EKYC_STEP_ADDRESS") || "Address", done: true, active: false },
303
- { label: t("EKYC_STEP_PROPERTY") || "Property", done: false, active: true },
304
- { label: t("EKYC_STEP_METER") || "Meter", done: false, active: false },
305
- { label: t("EKYC_STEP_REVIEW") || "Review", done: false, active: false },
306
- ].map((step, i) => (
307
- <div key={i} style={{ display: "flex", gap: "10px", alignItems: "flex-start", position: "relative", paddingBottom: i < 4 ? "18px" : 0 }}>
308
- {i < 4 && (
309
- <div style={{ position: "absolute", left: "10px", top: "22px", width: "1px", height: "calc(100% - 10px)", background: "#EAECF0" }} />
310
- )}
311
- <div style={{
312
- width: "20px", height: "20px", borderRadius: "50%", flexShrink: 0, marginTop: "1px",
313
- border: step.done ? "none" : step.active ? "1.5px solid #185FA5" : "1.5px solid #D0D5DD",
314
- background: step.done ? "#0F6E56" : step.active ? "#E6F1FB" : "#fff",
315
- display: "flex", alignItems: "center", justifyContent: "center",
316
- fontSize: "10px", fontWeight: "500",
317
- color: step.done ? "#fff" : step.active ? "#185FA5" : "#98A2B3",
318
- }}>
319
- {step.done ? <CheckIcon size={11} color="#fff" /> : i + 1}
320
- </div>
321
- <div style={{
322
- fontSize: "12px", paddingTop: "2px",
323
- color: step.done ? "#0F6E56" : step.active ? "#0B0C0C" : "#667085",
324
- fontWeight: step.done || step.active ? "600" : "400",
325
- }}>
326
- {step.label}
327
- </div>
328
- </div>
329
- ))}
330
- </div>
331
- </div>
332
-
333
- {/* ── Main Content ── */}
334
- <div style={{ flex: 1, marginLeft: "16px" }}>
335
- <Card>
336
- {/* Header */}
337
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }}>
338
- <CardHeader style={{ margin: 0, fontSize: "18px" }}>
339
- {t("EKYC_PROPERTY_DETAILS_HEADER") || "Property Details"}
340
- </CardHeader>
341
- <div style={{
342
- background: "#F9FAFB", border: "0.5px solid #EAECF0",
343
- borderRadius: "20px", padding: "4px 14px",
344
- fontSize: "12px", color: "#667085",
345
- }}>
346
- {t("EKYC_K_NUMBER") || "K Number"}:{" "}
347
- <span style={{ color: "#0B0C0C", fontWeight: "600" }}>{kNumber}</span>
348
- </div>
349
- </div>
350
-
351
- <div style={{ animation: "fadeSlideIn 0.3s ease" }}>
352
-
353
- {/* ── Property Details Section ── */}
354
- <SectionHead
355
- icon={<BriefcaseIcon size={16} />}
356
- label={t("EKYC_PROPERTY_DETAILS") || "Property details"}
357
- />
358
-
359
- {/* Owner / Tenant Toggle */}
360
- <div style={{ marginBottom: "20px" }}>
361
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "8px" }}>
362
- {t("EKYC_PROPERTY_OWNER") || "Property owner"}
363
- </div>
364
- <div style={{ display: "flex", backgroundColor: "#F2F4F7", padding: "4px", borderRadius: "10px", gap: "4px" }}>
365
- {["OWNER", "TENANT"].map((type) => (
366
- <button
367
- key={type}
368
- onClick={() => setOwnerType(type)}
369
- style={{
370
- flex: 1, padding: "9px 12px", borderRadius: "7px", border: "none", cursor: "pointer",
371
- fontSize: "13px", fontWeight: "600", transition: "all 0.15s",
372
- background: ownerType === type ? "#185FA5" : "transparent",
373
- color: ownerType === type ? "#fff" : "#667085",
374
- }}
375
- >
376
- {t(`EKYC_${type}`) || (type === "OWNER" ? "Owner" : "Tenant")}
377
- </button>
378
- ))}
379
- </div>
380
- </div>
381
-
382
- {/* PID Number */}
383
- <div style={{ marginBottom: "20px" }}>
384
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
385
- {t("EKYC_PID_NUMBER") || "PID number"}{" "}
386
- <span style={{ fontStyle: "italic", fontWeight: "400", textTransform: "none", color: "#98A2B3" }}>
387
- — {t("EKYC_OPTIONAL") || "optional"}
388
- </span>
389
- </div>
390
- <IconInput
391
- icon={<PidIcon size={15} />}
392
- value={pidNumber}
393
- onChange={(e) => setPidNumber(e.target.value)}
394
- placeholder={t("EKYC_ENTER_PID_NUMBER") || "Enter PID number"}
395
- />
396
- </div>
397
-
398
- <hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
399
-
400
- {/* ── Building Info Section ── */}
401
- <SectionHead
402
- icon={<BuildingIcon size={16} />}
403
- label={t("EKYC_BUILDING_INFO") || "Building info"}
404
- />
405
-
406
- {/* Dropdowns grid */}
407
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "14px" }}>
408
- {/* <div>
409
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
410
- {t("EKYC_TYPE_OF_CONNECTION") || "Type of connection"}
411
- </div>
412
- <Dropdown
413
- selected={connectionCategory}
414
- select={setConnectionCategory}
415
- option={connectionCategoryOptions}
416
- optionKey="label"
417
- t={t}
418
- placeholder={t("EKYC_SELECT") || "Select"}
419
- />
420
- </div> */}
421
- {/* <div>
422
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
423
- {t("EKYC_CONNECTION_CATEGORY") || "Connection category"}
424
- </div>
425
- <Dropdown
426
- selected={connectionType}
427
- select={setConnectionType}
428
- option={connectionTypeOptions}
429
- optionKey="label"
430
- t={t}
431
- placeholder={t("EKYC_SELECT") || "Select"}
432
- />
433
- </div> */}
434
- </div>
435
-
436
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "24px" }}>
437
- <div>
438
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
439
- {t("EKYC_USER_TYPE") || "User type"}
440
- </div>
441
- <Dropdown
442
- selected={userType}
443
- select={setUserType}
444
- option={userTypeOptions}
445
- optionKey="label"
446
- t={t}
447
- placeholder={t("EKYC_SELECT") || "Select"}
448
- />
449
- </div>
450
- <div>
451
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
452
- {t("EKYC_NO_OF_FLOORS") || "No. of floors"}
453
- </div>
454
- <Dropdown
455
- selected={noOfFloors}
456
- select={setNoOfFloors}
457
- option={floorOptions}
458
- optionKey="label"
459
- t={t}
460
- placeholder={t("EKYC_SELECT") || "Select"}
461
- />
462
- </div>
463
- </div>
464
-
465
- <hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
466
-
467
- {/* ── Documents & Photo Section ── */}
468
- <SectionHead
469
- icon={<DocumentIcon size={16} />}
470
- label={t("EKYC_DOCUMENTS_PHOTO") || "Documents & photo"}
471
- />
472
-
473
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "20px" }}>
474
-
475
- {/* PDF Upload */}
476
- <div>
477
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "8px" }}>
478
- {t("EKYC_UPLOAD_PROPERTY_DOC") || "Upload property document"}
479
- </div>
480
- <UploadFile
481
- id={"ekyc-property-doc"}
482
- extraStyleName={"propertyCreate"}
483
- accept=".pdf"
484
- onUpload={selectpdf}
485
- onDelete={() => {
486
- setPropertyDocumentFileStoreId(null);
487
- setPropertyDocument(null);
488
- setFilepdf(null);
489
- }}
490
- message={propertyDocumentFileStoreId ? `1 ${t(`EKYC_ACTION_FILEUPLOADED`)}` : t(`EKYC_ACTION_NO_FILEUPLOADED`)}
491
- error={error}
492
- disabled={!pidNumber}
493
- />
494
- {!pidNumber && (
495
- <div style={{ fontSize: "11px", color: "#D92D20", marginTop: "4px" }}>
496
- {t("EKYC_ENTER_PID_FIRST_CTA") || "Enter PID to upload"}
497
- </div>
498
- )}
499
- </div>
500
-
501
- {/* Building Photo Upload */}
502
- <div>
503
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "8px" }}>
504
- {t("EKYC_CAPTURE_BUILDING_IMAGE") || "Capture building image"}
505
- </div>
506
- <UploadFile
507
- id={"ekyc-building-photo"}
508
- extraStyleName={"propertyCreate"}
509
- accept=".jpg,.png,.jpeg"
510
- onUpload={selectphoto}
511
- onDelete={() => {
512
- setBuildingPhotoFileStoreId(null);
513
- setBuildingPhoto(null);
514
- setFilephoto(null);
515
- }}
516
- message={buildingPhotoFileStoreId ? `1 ${t(`EKYC_ACTION_FILEUPLOADED`)}` : t(`EKYC_ACTION_NO_FILEUPLOADED`)}
517
- error={error}
518
- />
519
- {buildingPhoto && (
520
- <div style={{ marginTop: "10px", borderRadius: "8px", overflow: "hidden", border: "1px solid #EAECF0" }}>
521
- <img src={buildingPhoto} alt="Building Preview" style={{ width: "100%", maxHeight: "150px", objectFit: "cover" }} />
522
- </div>
523
- )}
524
- </div>
525
- </div>
526
-
527
- {/* Info Banner */}
528
- <div style={{
529
- backgroundColor: "#E6F1FB", border: "0.5px solid #B5D4F4",
530
- borderRadius: "8px", padding: "12px 14px",
531
- display: "flex", alignItems: "flex-start", gap: "10px", marginBottom: "4px",
532
- }}>
533
- <div style={{ flexShrink: 0, marginTop: "1px" }}>
534
- <InfoBannerIcon fill="#185FA5" />
535
- </div>
536
- <div style={{ fontSize: "13px", color: "#185FA5", lineHeight: "1.5" }}>
537
- {t("EKYC_TENANT_INFO_NOTICE") || "This section is enabled only if the user is not the owner. Tenant details will be required if tenant is selected."}
538
- </div>
539
- </div>
540
-
541
- </div>
542
-
543
- {/* Submit (Non-sticky, at form end) */}
544
- <div style={{ marginTop: "24px" }}>
545
- <SubmitBar
546
- label={t("EKYC_SAVE_AND_CONTINUE") || "Save & Continue"}
547
- onSubmit={handleSaveAndContinue}
548
- />
549
- </div>
550
-
551
- {/* Secure notice */}
552
- <div style={{
553
- display: "flex", alignItems: "center", justifyContent: "center",
554
- gap: "5px", marginTop: "16px",
555
- fontSize: "11px", color: "#98A2B3",
556
- }}>
557
- <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
558
- <rect x="3" y="11" width="18" height="11" rx="2" />
559
- <path d="M7 11V7a5 5 0 0 1 10 0v4" />
560
- </svg>
561
- {t("EKYC_SECURE_DATA_NOTICE") || "Your data is encrypted and secure"}
562
- </div>
563
- </Card>
564
- </div>
347
+ const data = {
348
+ pidNumber,
349
+ propertyType: propertyType?.name,
350
+ subPropertyCategory: subPropertyCategory?.name,
351
+ noOfFloors,
352
+ floorNo,
353
+ noOfRooms,
354
+ noOfBeds,
355
+ dwellingUnits,
356
+ buildingImageId,
357
+ };
358
+
359
+ onSelect(config.key, data);
360
+ };
361
+
362
+ return (
363
+ <Fragment>
364
+ <FormStep
365
+ t={t}
366
+ onSelect={onStepSelect}
367
+ config={config}
368
+ label={t("ES_COMMON_CONTINUE")}
369
+ >
370
+ <div>
371
+ <CardLabel>PID Number</CardLabel>
372
+ <TextInput value={pidNumber} onChange={(e) => setPidNumber(e.target.value)} />
373
+ </div>
374
+
375
+ <div>
376
+ <CardLabel>Property Type</CardLabel>
377
+ <Dropdown
378
+ option={propertyTypeOptions}
379
+ selected={propertyType}
380
+ select={setPropertyType}
381
+ />
382
+ </div>
383
+
384
+ <div>
385
+ <CardLabel>Sub Property Category</CardLabel>
386
+ <Dropdown option={[]} selected={subPropertyCategory} select={setSubPropertyCategory} />
387
+ </div>
388
+
389
+ <div>
390
+ <CardLabel>No. of Floors *</CardLabel>
391
+ <TextInput
392
+ type="number"
393
+ value={noOfFloors}
394
+ onChange={(e) => setNoOfFloors(e.target.value)}
395
+ />
396
+ </div>
397
+
398
+ <div>
399
+ <CardLabel>Floor No. of this KNO</CardLabel>
400
+ <TextInput value={floorNo} onChange={(e) => setFloorNo(e.target.value)} />
401
+ </div>
402
+
403
+ <div>
404
+ <CardLabel>No of Beds</CardLabel>
405
+ <TextInput
406
+ type="number"
407
+ value={noOfBeds}
408
+ onChange={(e) => setNoOfBeds(e.target.value)}
409
+ />
410
+ </div>
411
+
412
+ <div>
413
+ <CardLabel>No. of Rooms</CardLabel>
414
+ <TextInput
415
+ type="number"
416
+ value={noOfRooms}
417
+ onChange={(e) => setNoOfRooms(e.target.value)}
418
+ />
419
+ </div>
420
+
421
+ {/* HOTEL CONDITION */}
422
+ {propertyType?.name === "Hotel" && (
423
+ <div>
424
+ <CardLabel>No. of Rooms *</CardLabel>
425
+ <TextInput
426
+ type="number"
427
+ value={noOfRooms}
428
+ onChange={(e) => setNoOfRooms(e.target.value)}
429
+ />
430
+ </div>
431
+ )}
432
+
433
+ {/* HOSPITAL CONDITION */}
434
+ {(propertyType?.name === "Hospital" ||
435
+ propertyType?.name === "Nursing Home") && (
436
+ <div>
437
+ <CardLabel>No. of Beds *</CardLabel>
438
+ <TextInput
439
+ type="number"
440
+ value={noOfBeds}
441
+ onChange={(e) => setNoOfBeds(e.target.value)}
442
+ />
565
443
  </div>
566
- {toast && (
567
- <Toast
568
- label={toast.message}
569
- error={toast.type === "error"}
570
- info={toast.type === "info"}
571
- success={toast.type === "success"}
572
- onClose={() => setToast(null)}
573
- />
574
- )}
575
- </>
576
- );
444
+ )}
445
+
446
+ <div>
447
+ <CardLabel>Number of Dwelling Units</CardLabel>
448
+ <TextInput
449
+ type="number"
450
+ value={dwellingUnits}
451
+ onChange={(e) => setDwellingUnits(e.target.value)}
452
+ />
453
+ </div>
454
+
455
+ <div>
456
+ <CardLabel>Building Image *</CardLabel>
457
+ <UploadFile
458
+ onUpload={handleUpload}
459
+ onDelete={() => {
460
+ setBuildingImage(null);
461
+ setBuildingImageId(null);
462
+ }}
463
+ message={buildingImageId ? "Uploaded" : "No file selected"}
464
+ />
465
+ </div>
466
+
467
+ {buildingImage && (
468
+ <div style={{ gridColumn: "span 2" }}>
469
+ <img
470
+ src={buildingImage}
471
+ alt="preview"
472
+ style={{ width: "100%", marginTop: "10px" }}
473
+ />
474
+ </div>
475
+ )}
476
+
477
+ {toast && (
478
+ <Toast
479
+ label={toast.message}
480
+ error={toast.type === "error"}
481
+ onClose={() => setToast(null)}
482
+ />
483
+ )}
484
+ </FormStep>
485
+ </Fragment>
486
+ );
577
487
  };
578
488
 
579
489
  export default PropertyInfo;