@djb25/digit-ui-module-ekyc 1.0.6 → 1.0.7

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,4 +1,4 @@
1
- import React, { useState, useRef, Fragment } from "react";
1
+ import React, { useState, useRef, Fragment, useEffect } from "react";
2
2
  import {
3
3
  Card,
4
4
  CardLabel,
@@ -9,9 +9,12 @@ import {
9
9
  Dropdown,
10
10
  InfoBannerIcon,
11
11
  HomeIcon,
12
+ UploadFile,
13
+ Toast,
12
14
  } from "@djb25/digit-ui-react-components";
13
15
  import { useTranslation } from "react-i18next";
14
16
  import { useHistory, useLocation } from "react-router-dom";
17
+ import { getPayloadDiff, getSavedData } from "../../utils";
15
18
 
16
19
  // ─── Icons ────────────────────────────────────────────────────────────────────
17
20
 
@@ -98,8 +101,12 @@ const PropertyInfo = () => {
98
101
  const history = useHistory();
99
102
  const location = useLocation();
100
103
 
101
- const flowState = location.state || { kNumber: "EKYC-1234567890" };
104
+ const flowState = location.state || {
105
+ kNumber: sessionStorage.getItem("EKYC_K_NUMBER") || "EKYC-1234567890",
106
+ initialData: getSavedData("EKYC_INITIAL_DATA", {})
107
+ };
102
108
  const { kNumber } = flowState;
109
+ const initialData = flowState.initialData || getSavedData("EKYC_INITIAL_DATA", {});
103
110
 
104
111
  const tenantId = Digit.ULBService.getCurrentTenantId();
105
112
  const { data: dataV0 } = Digit.Hooks.ekyc.useGetPropertyType(tenantId);
@@ -107,14 +114,120 @@ const PropertyInfo = () => {
107
114
  const { data: dataV1 } = Digit.Hooks.ekyc.useGetUserType(tenantId);
108
115
  const { data: dataV2 } = Digit.Hooks.ekyc.useGetFloorCount(tenantId);
109
116
 
110
- const [ownerType, setOwnerType] = useState("OWNER");
111
- const [pidNumber, setPidNumber] = useState("");
112
- const [connectionCategory, setConnectionCategory] = useState(null);
113
- const [connectionType, setConnectionType] = useState(null);
114
- const [userType, setUserType] = useState(null);
115
- const [noOfFloors, setNoOfFloors] = useState(null);
116
- const [propertyDocument, setPropertyDocument] = useState(null);
117
- const [buildingPhoto, setBuildingPhoto] = useState(null);
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
+ };
161
+
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
+ };
171
+
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]);
118
231
 
119
232
  const fileRef = useRef(null);
120
233
  const cameraRef = useRef(null);
@@ -125,24 +238,22 @@ const PropertyInfo = () => {
125
238
  propertyDetails: {
126
239
  ownerType, pidNumber, connectionType,
127
240
  connectionCategory, userType, noOfFloors,
128
- propertyDocument, buildingPhoto,
241
+ propertyDocument, propertyDocumentFileStoreId,
242
+ buildingPhoto, buildingPhotoFileStoreId,
129
243
  },
244
+ initialData,
130
245
  });
131
246
  };
132
247
 
133
- const handleFileUpload = (e) => {
134
- const file = e.target.files[0];
135
- if (!file) return;
136
- setPropertyDocument(file);
137
- };
248
+ function selectpdf(e) {
249
+ setPropertyDocumentFileStoreId(null);
250
+ setFilepdf(e.target.files[0]);
251
+ }
138
252
 
139
- const handlePhotoCapture = (e) => {
140
- const file = e.target.files[0];
141
- if (!file) return;
142
- const reader = new FileReader();
143
- reader.onloadend = () => setBuildingPhoto(reader.result);
144
- reader.readAsDataURL(file);
145
- };
253
+ function selectphoto(e) {
254
+ setBuildingPhotoFileStoreId(null);
255
+ setFilephoto(e.target.files[0]);
256
+ }
146
257
 
147
258
  const connectionCategoryOptions =
148
259
  dataV0?.["ws-services-calculation"]?.propertyTypeV2?.map((item) => ({
@@ -165,349 +276,301 @@ const PropertyInfo = () => {
165
276
  })) || [];
166
277
 
167
278
  return (
168
- <div className="inbox-container">
169
- <style>{`
279
+ <div class="ground-container employee-app-container form-container">
280
+ <div className="inbox-container">
281
+ <style>{`
170
282
  @keyframes fadeSlideIn {
171
283
  from { opacity: 0; transform: translateY(8px); }
172
284
  to { opacity: 1; transform: translateY(0); }
173
285
  }
174
286
  `}</style>
175
287
 
176
- {/* ── Sidebar ── */}
177
- <div className="filters-container">
178
- <Card style={{ display: "flex", alignItems: "center", padding: "12px 16px", marginBottom: "12px", borderRadius: "8px" }}>
179
- <div style={{ color: "#185FA5", marginRight: "10px", display: "flex" }}>
180
- <HomeIcon style={{ width: "20px", height: "20px" }} />
181
- </div>
182
- <div style={{ fontWeight: "600", fontSize: "15px", color: "#0B0C0C" }}>
183
- {t("EKYC_PROCESS") || "eKYC Process"}
184
- </div>
185
- </Card>
186
-
187
- <div style={{ background: "#fff", padding: "16px 14px", borderRadius: "8px", border: "1px solid #EAECF0" }}>
188
- {[
189
- { label: t("EKYC_STEP_AADHAAR") || "Aadhaar", done: true, active: false },
190
- { label: t("EKYC_STEP_ADDRESS") || "Address", done: true, active: false },
191
- { label: t("EKYC_STEP_PROPERTY") || "Property", done: false, active: true },
192
- { label: t("EKYC_STEP_REVIEW") || "Review", done: false, active: false },
193
- ].map((step, i) => (
194
- <div key={i} style={{ display: "flex", gap: "10px", alignItems: "flex-start", position: "relative", paddingBottom: i < 3 ? "18px" : 0 }}>
195
- {i < 3 && (
196
- <div style={{ position: "absolute", left: "10px", top: "22px", width: "1px", height: "calc(100% - 10px)", background: "#EAECF0" }} />
197
- )}
198
- <div style={{
199
- width: "20px", height: "20px", borderRadius: "50%", flexShrink: 0, marginTop: "1px",
200
- border: step.done ? "none" : step.active ? "1.5px solid #185FA5" : "1.5px solid #D0D5DD",
201
- background: step.done ? "#0F6E56" : step.active ? "#E6F1FB" : "#fff",
202
- display: "flex", alignItems: "center", justifyContent: "center",
203
- fontSize: "10px", fontWeight: "500",
204
- color: step.done ? "#fff" : step.active ? "#185FA5" : "#98A2B3",
205
- }}>
206
- {step.done ? <CheckIcon size={11} color="#fff" /> : i + 1}
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_REVIEW") || "Review", done: false, active: false },
305
+ ].map((step, i) => (
306
+ <div key={i} style={{ display: "flex", gap: "10px", alignItems: "flex-start", position: "relative", paddingBottom: i < 3 ? "18px" : 0 }}>
307
+ {i < 3 && (
308
+ <div style={{ position: "absolute", left: "10px", top: "22px", width: "1px", height: "calc(100% - 10px)", background: "#EAECF0" }} />
309
+ )}
310
+ <div style={{
311
+ width: "20px", height: "20px", borderRadius: "50%", flexShrink: 0, marginTop: "1px",
312
+ border: step.done ? "none" : step.active ? "1.5px solid #185FA5" : "1.5px solid #D0D5DD",
313
+ background: step.done ? "#0F6E56" : step.active ? "#E6F1FB" : "#fff",
314
+ display: "flex", alignItems: "center", justifyContent: "center",
315
+ fontSize: "10px", fontWeight: "500",
316
+ color: step.done ? "#fff" : step.active ? "#185FA5" : "#98A2B3",
317
+ }}>
318
+ {step.done ? <CheckIcon size={11} color="#fff" /> : i + 1}
319
+ </div>
320
+ <div style={{
321
+ fontSize: "12px", paddingTop: "2px",
322
+ color: step.done ? "#0F6E56" : step.active ? "#0B0C0C" : "#667085",
323
+ fontWeight: step.done || step.active ? "600" : "400",
324
+ }}>
325
+ {step.label}
326
+ </div>
207
327
  </div>
328
+ ))}
329
+ </div>
330
+ </div>
331
+
332
+ {/* ── Main Content ── */}
333
+ <div style={{ flex: 1, marginLeft: "16px" }}>
334
+ <Card>
335
+ {/* Header */}
336
+ <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }}>
337
+ <CardHeader style={{ margin: 0, fontSize: "18px" }}>
338
+ {t("EKYC_PROPERTY_DETAILS_HEADER") || "Property Details"}
339
+ </CardHeader>
208
340
  <div style={{
209
- fontSize: "12px", paddingTop: "2px",
210
- color: step.done ? "#0F6E56" : step.active ? "#0B0C0C" : "#667085",
211
- fontWeight: step.done || step.active ? "600" : "400",
341
+ background: "#F9FAFB", border: "0.5px solid #EAECF0",
342
+ borderRadius: "20px", padding: "4px 14px",
343
+ fontSize: "12px", color: "#667085",
212
344
  }}>
213
- {step.label}
345
+ {t("EKYC_K_NUMBER") || "K Number"}:{" "}
346
+ <span style={{ color: "#0B0C0C", fontWeight: "600" }}>{kNumber}</span>
214
347
  </div>
215
348
  </div>
216
- ))}
217
- </div>
218
- </div>
219
349
 
220
- {/* ── Main Content ── */}
221
- <div style={{ flex: 1, marginLeft: "16px" }}>
222
- <Card>
223
- {/* Header */}
224
- <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: "20px" }}>
225
- <CardHeader style={{ margin: 0, fontSize: "18px" }}>
226
- {t("EKYC_PROPERTY_DETAILS_HEADER") || "Property Details"}
227
- </CardHeader>
228
- <div style={{
229
- background: "#F9FAFB", border: "0.5px solid #EAECF0",
230
- borderRadius: "20px", padding: "4px 14px",
231
- fontSize: "12px", color: "#667085",
232
- }}>
233
- {t("EKYC_K_NUMBER") || "K Number"}:{" "}
234
- <span style={{ color: "#0B0C0C", fontWeight: "600" }}>{kNumber}</span>
235
- </div>
236
- </div>
237
-
238
- <div style={{ animation: "fadeSlideIn 0.3s ease" }}>
350
+ <div style={{ animation: "fadeSlideIn 0.3s ease" }}>
239
351
 
240
- {/* ── Property Details Section ── */}
241
- <SectionHead
242
- icon={<BriefcaseIcon size={16} />}
243
- label={t("EKYC_PROPERTY_DETAILS") || "Property details"}
244
- />
352
+ {/* ── Property Details Section ── */}
353
+ <SectionHead
354
+ icon={<BriefcaseIcon size={16} />}
355
+ label={t("EKYC_PROPERTY_DETAILS") || "Property details"}
356
+ />
245
357
 
246
- {/* Owner / Tenant Toggle */}
247
- <div style={{ marginBottom: "20px" }}>
248
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "8px" }}>
249
- {t("EKYC_PROPERTY_OWNER") || "Property owner"}
250
- </div>
251
- <div style={{ display: "flex", backgroundColor: "#F2F4F7", padding: "4px", borderRadius: "10px", gap: "4px" }}>
252
- {["OWNER", "TENANT"].map((type) => (
253
- <button
254
- key={type}
255
- onClick={() => setOwnerType(type)}
256
- style={{
257
- flex: 1, padding: "9px 12px", borderRadius: "7px", border: "none", cursor: "pointer",
258
- fontSize: "13px", fontWeight: "600", transition: "all 0.15s",
259
- background: ownerType === type ? "#185FA5" : "transparent",
260
- color: ownerType === type ? "#fff" : "#667085",
261
- }}
262
- >
263
- {t(`EKYC_${type}`) || (type === "OWNER" ? "Owner" : "Tenant")}
264
- </button>
265
- ))}
358
+ {/* Owner / Tenant Toggle */}
359
+ <div style={{ marginBottom: "20px" }}>
360
+ <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "8px" }}>
361
+ {t("EKYC_PROPERTY_OWNER") || "Property owner"}
362
+ </div>
363
+ <div style={{ display: "flex", backgroundColor: "#F2F4F7", padding: "4px", borderRadius: "10px", gap: "4px" }}>
364
+ {["OWNER", "TENANT"].map((type) => (
365
+ <button
366
+ key={type}
367
+ onClick={() => setOwnerType(type)}
368
+ style={{
369
+ flex: 1, padding: "9px 12px", borderRadius: "7px", border: "none", cursor: "pointer",
370
+ fontSize: "13px", fontWeight: "600", transition: "all 0.15s",
371
+ background: ownerType === type ? "#185FA5" : "transparent",
372
+ color: ownerType === type ? "#fff" : "#667085",
373
+ }}
374
+ >
375
+ {t(`EKYC_${type}`) || (type === "OWNER" ? "Owner" : "Tenant")}
376
+ </button>
377
+ ))}
378
+ </div>
266
379
  </div>
267
- </div>
268
380
 
269
- {/* PID Number */}
270
- <div style={{ marginBottom: "20px" }}>
271
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
272
- {t("EKYC_PID_NUMBER") || "PID number"}{" "}
273
- <span style={{ fontStyle: "italic", fontWeight: "400", textTransform: "none", color: "#98A2B3" }}>
274
- — {t("EKYC_OPTIONAL") || "optional"}
275
- </span>
381
+ {/* PID Number */}
382
+ <div style={{ marginBottom: "20px" }}>
383
+ <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
384
+ {t("EKYC_PID_NUMBER") || "PID number"}{" "}
385
+ <span style={{ fontStyle: "italic", fontWeight: "400", textTransform: "none", color: "#98A2B3" }}>
386
+ — {t("EKYC_OPTIONAL") || "optional"}
387
+ </span>
388
+ </div>
389
+ <IconInput
390
+ icon={<PidIcon size={15} />}
391
+ value={pidNumber}
392
+ onChange={(e) => setPidNumber(e.target.value)}
393
+ placeholder={t("EKYC_ENTER_PID_NUMBER") || "Enter PID number"}
394
+ />
276
395
  </div>
277
- <IconInput
278
- icon={<PidIcon size={15} />}
279
- value={pidNumber}
280
- onChange={(e) => setPidNumber(e.target.value)}
281
- placeholder={t("EKYC_ENTER_PID_NUMBER") || "Enter PID number"}
282
- />
283
- </div>
284
396
 
285
- <hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
397
+ <hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
286
398
 
287
- {/* ── Building Info Section ── */}
288
- <SectionHead
289
- icon={<BuildingIcon size={16} />}
290
- label={t("EKYC_BUILDING_INFO") || "Building info"}
291
- />
399
+ {/* ── Building Info Section ── */}
400
+ <SectionHead
401
+ icon={<BuildingIcon size={16} />}
402
+ label={t("EKYC_BUILDING_INFO") || "Building info"}
403
+ />
292
404
 
293
- {/* Dropdowns grid */}
294
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "14px" }}>
295
- <div>
296
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
297
- {t("EKYC_TYPE_OF_CONNECTION") || "Type of connection"}
405
+ {/* Dropdowns grid */}
406
+ <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "14px" }}>
407
+ <div>
408
+ <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
409
+ {t("EKYC_TYPE_OF_CONNECTION") || "Type of connection"}
410
+ </div>
411
+ <Dropdown
412
+ selected={connectionCategory}
413
+ select={setConnectionCategory}
414
+ option={connectionCategoryOptions}
415
+ optionKey="label"
416
+ t={t}
417
+ placeholder={t("EKYC_SELECT") || "Select"}
418
+ />
298
419
  </div>
299
- <Dropdown
300
- selected={connectionCategory}
301
- select={setConnectionCategory}
302
- option={connectionCategoryOptions}
303
- optionKey="label"
304
- t={t}
305
- placeholder={t("EKYC_SELECT") || "Select"}
306
- />
307
- </div>
308
- <div>
309
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
310
- {t("EKYC_CONNECTION_CATEGORY") || "Connection category"}
420
+ <div>
421
+ <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
422
+ {t("EKYC_CONNECTION_CATEGORY") || "Connection category"}
423
+ </div>
424
+ <Dropdown
425
+ selected={connectionType}
426
+ select={setConnectionType}
427
+ option={connectionTypeOptions}
428
+ optionKey="label"
429
+ t={t}
430
+ placeholder={t("EKYC_SELECT") || "Select"}
431
+ />
311
432
  </div>
312
- <Dropdown
313
- selected={connectionType}
314
- select={setConnectionType}
315
- option={connectionTypeOptions}
316
- optionKey="label"
317
- t={t}
318
- placeholder={t("EKYC_SELECT") || "Select"}
319
- />
320
433
  </div>
321
- </div>
322
434
 
323
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "24px" }}>
324
- <div>
325
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
326
- {t("EKYC_USER_TYPE") || "User type"}
435
+ <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "24px" }}>
436
+ <div>
437
+ <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
438
+ {t("EKYC_USER_TYPE") || "User type"}
439
+ </div>
440
+ <Dropdown
441
+ selected={userType}
442
+ select={setUserType}
443
+ option={userTypeOptions}
444
+ optionKey="label"
445
+ t={t}
446
+ placeholder={t("EKYC_SELECT") || "Select"}
447
+ />
327
448
  </div>
328
- <Dropdown
329
- selected={userType}
330
- select={setUserType}
331
- option={userTypeOptions}
332
- optionKey="label"
333
- t={t}
334
- placeholder={t("EKYC_SELECT") || "Select"}
335
- />
336
- </div>
337
- <div>
338
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
339
- {t("EKYC_NO_OF_FLOORS") || "No. of floors"}
449
+ <div>
450
+ <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "6px" }}>
451
+ {t("EKYC_NO_OF_FLOORS") || "No. of floors"}
452
+ </div>
453
+ <Dropdown
454
+ selected={noOfFloors}
455
+ select={setNoOfFloors}
456
+ option={floorOptions}
457
+ optionKey="label"
458
+ t={t}
459
+ placeholder={t("EKYC_SELECT") || "Select"}
460
+ />
340
461
  </div>
341
- <Dropdown
342
- selected={noOfFloors}
343
- select={setNoOfFloors}
344
- option={floorOptions}
345
- optionKey="label"
346
- t={t}
347
- placeholder={t("EKYC_SELECT") || "Select"}
348
- />
349
462
  </div>
350
- </div>
351
463
 
352
- <hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
464
+ <hr style={{ margin: "24px 0", border: 0, borderTop: "1px solid #EAECF0" }} />
353
465
 
354
- {/* ── Documents & Photo Section ── */}
355
- <SectionHead
356
- icon={<DocumentIcon size={16} />}
357
- label={t("EKYC_DOCUMENTS_PHOTO") || "Documents & photo"}
358
- />
466
+ {/* ── Documents & Photo Section ── */}
467
+ <SectionHead
468
+ icon={<DocumentIcon size={16} />}
469
+ label={t("EKYC_DOCUMENTS_PHOTO") || "Documents & photo"}
470
+ />
359
471
 
360
- <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "20px" }}>
472
+ <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: "14px", marginBottom: "20px" }}>
361
473
 
362
- {/* PDF Upload */}
363
- <div>
364
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "8px" }}>
365
- {t("EKYC_UPLOAD_PROPERTY_DOC") || "Upload property document"}
474
+ {/* PDF Upload */}
475
+ <div>
476
+ <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "8px" }}>
477
+ {t("EKYC_UPLOAD_PROPERTY_DOC") || "Upload property document"}
478
+ </div>
479
+ <UploadFile
480
+ id={"ekyc-property-doc"}
481
+ extraStyleName={"propertyCreate"}
482
+ accept=".pdf"
483
+ onUpload={selectpdf}
484
+ onDelete={() => {
485
+ setPropertyDocumentFileStoreId(null);
486
+ setPropertyDocument(null);
487
+ setFilepdf(null);
488
+ }}
489
+ message={propertyDocumentFileStoreId ? `1 ${t(`EKYC_ACTION_FILEUPLOADED`)}` : t(`EKYC_ACTION_NO_FILEUPLOADED`)}
490
+ error={error}
491
+ disabled={!pidNumber}
492
+ />
493
+ {!pidNumber && (
494
+ <div style={{ fontSize: "11px", color: "#D92D20", marginTop: "4px" }}>
495
+ {t("EKYC_ENTER_PID_FIRST_CTA") || "Enter PID to upload"}
496
+ </div>
497
+ )}
366
498
  </div>
367
- <input type="file" ref={fileRef} accept=".pdf" style={{ display: "none" }} onChange={handleFileUpload} />
368
- <div
369
- onClick={() => pidNumber && fileRef.current.click()}
370
- onMouseOver={(e) => { if (pidNumber) e.currentTarget.style.borderColor = "#185FA5"; }}
371
- onMouseOut={(e) => { if (pidNumber) e.currentTarget.style.borderColor = "#B5D4F4"; }}
372
- style={{
373
- border: pidNumber ? "1.5px dashed #B5D4F4" : "1.5px dashed #D0D5DD",
374
- borderRadius: "10px",
375
- padding: "28px 20px",
376
- textAlign: "center",
377
- cursor: pidNumber ? "pointer" : "not-allowed",
378
- backgroundColor: pidNumber ? "#E6F1FB" : "#F9FAFB",
379
- minHeight: "160px",
380
- display: "flex",
381
- flexDirection: "column",
382
- alignItems: "center",
383
- justifyContent: "center",
384
- gap: "10px",
385
- transition: "all 0.15s",
386
- opacity: pidNumber ? 1 : 0.6,
387
- }}
388
- >
389
- <div style={{
390
- background: pidNumber ? "#fff" : "#EAECF0",
391
- padding: "10px",
392
- borderRadius: "10px",
393
- display: "flex",
394
- filter: pidNumber ? "none" : "grayscale(100%)"
395
- }}>
396
- <svg width="32" height="32" viewBox="0 0 24 24" fill={pidNumber ? "#185FA5" : "#98A2B3"}>
397
- <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" />
398
- <path d="M12 18v-4M12 14l-2 2M12 14l2 2" stroke="#fff" strokeWidth="1.5" strokeLinecap="round" />
399
- </svg>
499
+
500
+ {/* Building Photo Upload */}
501
+ <div>
502
+ <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "8px" }}>
503
+ {t("EKYC_CAPTURE_BUILDING_IMAGE") || "Capture building image"}
400
504
  </div>
401
- {propertyDocument ? (
402
- <div style={{ fontSize: "13px", fontWeight: "600", color: "#0F6E56" }}>
403
- {propertyDocument.name}
505
+ <UploadFile
506
+ id={"ekyc-building-photo"}
507
+ extraStyleName={"propertyCreate"}
508
+ accept=".jpg,.png,.jpeg"
509
+ onUpload={selectphoto}
510
+ onDelete={() => {
511
+ setBuildingPhotoFileStoreId(null);
512
+ setBuildingPhoto(null);
513
+ setFilephoto(null);
514
+ }}
515
+ message={buildingPhotoFileStoreId ? `1 ${t(`EKYC_ACTION_FILEUPLOADED`)}` : t(`EKYC_ACTION_NO_FILEUPLOADED`)}
516
+ error={error}
517
+ />
518
+ {buildingPhoto && (
519
+ <div style={{ marginTop: "10px", borderRadius: "8px", overflow: "hidden", border: "1px solid #EAECF0" }}>
520
+ <img src={buildingPhoto} alt="Building Preview" style={{ width: "100%", maxHeight: "150px", objectFit: "cover" }} />
404
521
  </div>
405
- ) : (
406
- <>
407
- <div style={{ fontSize: "13px", fontWeight: "600", color: pidNumber ? "#185FA5" : "#98A2B3" }}>
408
- {pidNumber ? (t("EKYC_UPLOAD_PROPERTY_DOC_CTA") || "Tap to upload") : (t("EKYC_ENTER_PID_FIRST_CTA") || "Enter PID to upload")}
409
- </div>
410
- <div style={{ fontSize: "12px", color: pidNumber ? "#378ADD" : "#98A2B3" }}>{pidNumber ? "PDF | Max 5MB" : "Requires PID"}</div>
411
- </>
412
522
  )}
413
523
  </div>
414
524
  </div>
415
525
 
416
- {/* Camera Capture */}
417
- <div>
418
- <div style={{ fontSize: "11px", fontWeight: "600", color: "#667085", textTransform: "uppercase", letterSpacing: "0.04em", marginBottom: "8px" }}>
419
- {t("EKYC_CAPTURE_BUILDING_IMAGE") || "Capture building image"}
526
+ {/* Info Banner */}
527
+ <div style={{
528
+ backgroundColor: "#E6F1FB", border: "0.5px solid #B5D4F4",
529
+ borderRadius: "8px", padding: "12px 14px",
530
+ display: "flex", alignItems: "flex-start", gap: "10px", marginBottom: "4px",
531
+ }}>
532
+ <div style={{ flexShrink: 0, marginTop: "1px" }}>
533
+ <InfoBannerIcon fill="#185FA5" />
420
534
  </div>
421
- <input type="file" ref={cameraRef} accept="image/*" capture="environment" style={{ display: "none" }} onChange={handlePhotoCapture} />
422
- <div
423
- onClick={!buildingPhoto ? () => cameraRef.current.click() : undefined}
424
- onMouseOver={(e) => { if (!buildingPhoto) e.currentTarget.style.borderColor = "#185FA5"; }}
425
- onMouseOut={(e) => { if (!buildingPhoto) e.currentTarget.style.borderColor = "#D0D5DD"; }}
426
- style={{
427
- border: "1.5px dashed #D0D5DD", borderRadius: "10px",
428
- minHeight: "160px", display: "flex", flexDirection: "column",
429
- alignItems: "center", justifyContent: "center",
430
- backgroundColor: "#F9FAFB",
431
- cursor: buildingPhoto ? "default" : "pointer",
432
- overflow: "hidden", transition: "border-color 0.15s",
433
- position: "relative",
434
- padding: buildingPhoto ? "0" : "28px 20px",
435
- }}
436
- >
437
- {!buildingPhoto ? (
438
- <>
439
- <div style={{ background: "#E6F1FB", width: "52px", height: "52px", borderRadius: "50%", display: "flex", alignItems: "center", justifyContent: "center", marginBottom: "10px" }}>
440
- <CameraIcon size={26} />
441
- </div>
442
- <div style={{ fontSize: "13px", fontWeight: "600", color: "#101828" }}>
443
- {t("EKYC_TAP_TO_CAPTURE") || "Tap to capture"}
444
- </div>
445
- <div style={{ fontSize: "12px", color: "#667085", marginTop: "2px" }}>
446
- {t("EKYC_BUILDING_PHOTO") || "Building photo with GPS"}
447
- </div>
448
- <div style={{ fontSize: "11px", color: "#98A2B3", marginTop: "2px" }}>
449
- JPG, PNG | Max 2MB
450
- </div>
451
- </>
452
- ) : (
453
- <>
454
- <img src={buildingPhoto} alt="Building" style={{ width: "100%", maxHeight: "200px", objectFit: "cover", display: "block" }} />
455
- <button
456
- onClick={(e) => { e.stopPropagation(); setBuildingPhoto(null); if (cameraRef.current) cameraRef.current.value = ""; }}
457
- style={{
458
- position: "absolute", top: "8px", right: "8px",
459
- background: "#fff", border: "0.5px solid #EAECF0",
460
- borderRadius: "7px", padding: "5px 10px",
461
- display: "flex", alignItems: "center", gap: "5px",
462
- cursor: "pointer", fontSize: "12px", color: "#D92D20", fontWeight: "500",
463
- }}
464
- >
465
- <TrashIcon size={13} /> {t("EKYC_REMOVE") || "Remove"}
466
- </button>
467
- </>
468
- )}
535
+ <div style={{ fontSize: "13px", color: "#185FA5", lineHeight: "1.5" }}>
536
+ {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."}
469
537
  </div>
470
538
  </div>
539
+
540
+ </div>
541
+
542
+ {/* Submit (Non-sticky, at form end) */}
543
+ <div style={{ marginTop: "24px" }}>
544
+ <SubmitBar
545
+ label={t("EKYC_SAVE_AND_CONTINUE") || "Save & Continue"}
546
+ onSubmit={handleSaveAndContinue}
547
+ />
471
548
  </div>
472
549
 
473
- {/* Info Banner */}
550
+ {/* Secure notice */}
474
551
  <div style={{
475
- backgroundColor: "#E6F1FB", border: "0.5px solid #B5D4F4",
476
- borderRadius: "8px", padding: "12px 14px",
477
- display: "flex", alignItems: "flex-start", gap: "10px", marginBottom: "4px",
552
+ display: "flex", alignItems: "center", justifyContent: "center",
553
+ gap: "5px", marginTop: "16px",
554
+ fontSize: "11px", color: "#98A2B3",
478
555
  }}>
479
- <div style={{ flexShrink: 0, marginTop: "1px" }}>
480
- <InfoBannerIcon fill="#185FA5" />
481
- </div>
482
- <div style={{ fontSize: "13px", color: "#185FA5", lineHeight: "1.5" }}>
483
- {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."}
484
- </div>
556
+ <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
557
+ <rect x="3" y="11" width="18" height="11" rx="2" />
558
+ <path d="M7 11V7a5 5 0 0 1 10 0v4" />
559
+ </svg>
560
+ {t("EKYC_SECURE_DATA_NOTICE") || "Your data is encrypted and secure"}
485
561
  </div>
486
-
487
- </div>
488
-
489
- {/* Submit (Non-sticky, at form end) */}
490
- <div style={{ marginTop: "24px" }}>
491
- <SubmitBar
492
- label={t("EKYC_SAVE_AND_CONTINUE") || "Save & Continue"}
493
- onSubmit={handleSaveAndContinue}
494
- />
495
- </div>
496
-
497
- {/* Secure notice */}
498
- <div style={{
499
- display: "flex", alignItems: "center", justifyContent: "center",
500
- gap: "5px", marginTop: "16px",
501
- fontSize: "11px", color: "#98A2B3",
502
- }}>
503
- <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
504
- <rect x="3" y="11" width="18" height="11" rx="2" />
505
- <path d="M7 11V7a5 5 0 0 1 10 0v4" />
506
- </svg>
507
- {t("EKYC_SECURE_DATA_NOTICE") || "Your data is encrypted and secure"}
508
- </div>
509
- </Card>
562
+ </Card>
563
+ </div>
510
564
  </div>
565
+ {toast && (
566
+ <Toast
567
+ label={toast.message}
568
+ error={toast.type === "error"}
569
+ info={toast.type === "info"}
570
+ success={toast.type === "success"}
571
+ onClose={() => setToast(null)}
572
+ />
573
+ )}
511
574
  </div>
512
575
  );
513
576
  };