@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.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +3281 -4272
- package/dist/index.modern.js.map +1 -1
- package/package.json +1 -1
- package/src/Module.js +42 -31
- package/src/components/ConnectionDetailsView.js +5 -3
- package/src/components/DesktopInbox.js +68 -184
- package/src/components/EKYCCard.js +35 -27
- package/src/components/Filter.js +48 -53
- package/src/components/SearchFormFieldsComponent.js +55 -0
- package/src/components/StatusCards.js +7 -3
- package/src/config/config.js +69 -0
- package/src/hook/useInboxTableConfig.js +134 -0
- package/src/pages/citizen/index.js +1 -1
- package/src/pages/employee/AadhaarVerification.js +473 -609
- package/src/pages/employee/AddressDetails.js +508 -733
- package/src/pages/employee/ConsumerDetails.js +512 -0
- package/src/pages/employee/Create.js +5 -1
- package/src/pages/employee/Dashboard.js +43 -0
- package/src/pages/employee/EKYCForm.js +117 -0
- package/src/pages/employee/Inbox.js +248 -140
- package/src/pages/employee/Mapping.js +640 -6
- package/src/pages/employee/MeterDetails.js +481 -471
- package/src/pages/employee/PropertyInfo.js +472 -562
- package/src/pages/employee/Review.js +268 -540
- package/src/pages/employee/Update.js +9 -0
- package/src/pages/employee/index.js +59 -94
|
@@ -1,11 +1,645 @@
|
|
|
1
|
-
import React from
|
|
1
|
+
import React, { useState, useMemo } from "react";
|
|
2
|
+
import { Card, Dropdown, Toast, Table } from "@djb25/digit-ui-react-components";
|
|
3
|
+
import { useTranslation } from "react-i18next";
|
|
4
|
+
|
|
5
|
+
// ─── Icons ────────────────────────────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
const UserIcon = ({ size = 18, color = "currentColor" }) => (
|
|
8
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
9
|
+
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
|
|
10
|
+
<circle cx="12" cy="7" r="4" />
|
|
11
|
+
</svg>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const DiaryIcon = ({ size = 18, color = "currentColor" }) => (
|
|
15
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
16
|
+
<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20" />
|
|
17
|
+
<path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z" />
|
|
18
|
+
</svg>
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const TrashIcon = ({ size = 14 }) => (
|
|
22
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
23
|
+
<polyline points="3 6 5 6 21 6" />
|
|
24
|
+
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
|
|
25
|
+
</svg>
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const EditIcon = ({ size = 14 }) => (
|
|
29
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
30
|
+
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
|
|
31
|
+
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
|
|
32
|
+
</svg>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
const MapPinIcon = ({ size = 12 }) => (
|
|
36
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
37
|
+
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" />
|
|
38
|
+
<circle cx="12" cy="10" r="3" />
|
|
39
|
+
</svg>
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const PlusIcon = ({ size = 16 }) => (
|
|
43
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
|
44
|
+
<line x1="12" y1="5" x2="12" y2="19" />
|
|
45
|
+
<line x1="5" y1="12" x2="19" y2="12" />
|
|
46
|
+
</svg>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const SaveIcon = ({ size = 16 }) => (
|
|
50
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
51
|
+
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z" />
|
|
52
|
+
<polyline points="17 21 17 13 7 13 7 21" />
|
|
53
|
+
<polyline points="7 3 7 8 15 8" />
|
|
54
|
+
</svg>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const CheckIcon = ({ size = 16 }) => (
|
|
58
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
|
59
|
+
<polyline points="20 6 9 17 4 12" />
|
|
60
|
+
</svg>
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
const XIcon = ({ size = 16 }) => (
|
|
64
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
|
|
65
|
+
<line x1="18" y1="6" x2="6" y2="18" />
|
|
66
|
+
<line x1="6" y1="6" x2="18" y2="18" />
|
|
67
|
+
</svg>
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// ─── Static Mock Data ─────────────────────────────────────────────────────────
|
|
71
|
+
|
|
72
|
+
const MOCK_SURVEYORS = [
|
|
73
|
+
{ name: "Amit Kumar", id: "SVR001", role: "Surveyor" },
|
|
74
|
+
{ name: "Sanjay Singh", id: "SVR002", role: "Surveyor" },
|
|
75
|
+
{ name: "Rahul Sharma", id: "SVR003", role: "Surveyor" },
|
|
76
|
+
{ name: "Priya Verma", id: "SVR004", role: "Surveyor" },
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
const MOCK_MRDS = [
|
|
80
|
+
{ name: "MRD - 01 (Central Zone)", code: "MRD01", zone: "Central" },
|
|
81
|
+
{ name: "MRD - 02 (North Zone)", code: "MRD02", zone: "North" },
|
|
82
|
+
{ name: "MRD - 03 (South Zone)", code: "MRD03", zone: "South" },
|
|
83
|
+
{ name: "MRD - 04 (West Zone)", code: "MRD04", zone: "West" },
|
|
84
|
+
{ name: "MRD - 05 (East Zone)", code: "MRD05", zone: "East" },
|
|
85
|
+
{ name: "MRD - 06 (Rohini)", code: "MRD06", zone: "Rohini" },
|
|
86
|
+
{ name: "MRD - 07 (Dwarka)", code: "MRD07", zone: "Dwarka" },
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
// ─── Confirm Delete Modal ─────────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
const ConfirmDeleteModal = ({ mapping, onConfirm, onCancel }) => (
|
|
92
|
+
<div style={{
|
|
93
|
+
position: "fixed", inset: 0, background: "rgba(0,0,0,0.35)",
|
|
94
|
+
display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1000,
|
|
95
|
+
}}>
|
|
96
|
+
<div style={{
|
|
97
|
+
background: "#fff", borderRadius: "12px", padding: "28px 28px 24px",
|
|
98
|
+
width: "400px", boxShadow: "0 20px 60px rgba(0,0,0,0.15)",
|
|
99
|
+
}}>
|
|
100
|
+
<div style={{ display: "flex", alignItems: "center", gap: "12px", marginBottom: "16px" }}>
|
|
101
|
+
<div style={{
|
|
102
|
+
width: "40px", height: "40px", borderRadius: "50%",
|
|
103
|
+
background: "#FEF3F2", display: "flex", alignItems: "center", justifyContent: "center",
|
|
104
|
+
}}>
|
|
105
|
+
<TrashIcon size={18} />
|
|
106
|
+
</div>
|
|
107
|
+
<div>
|
|
108
|
+
<div style={{ fontWeight: "700", fontSize: "16px", color: "#0D1B2A" }}>Remove Mapping</div>
|
|
109
|
+
<div style={{ fontSize: "12px", color: "#6B7B8E" }}>This action cannot be undone</div>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
<p style={{ fontSize: "13px", color: "#344054", marginBottom: "24px", lineHeight: "1.6" }}>
|
|
113
|
+
Are you sure you want to remove the mapping between{" "}
|
|
114
|
+
<strong>{mapping?.surveyorName}</strong> and <strong>{mapping?.mrdName}</strong>?
|
|
115
|
+
</p>
|
|
116
|
+
<div style={{ display: "flex", gap: "10px", justifyContent: "flex-end" }}>
|
|
117
|
+
<button onClick={onCancel} style={{
|
|
118
|
+
background: "none", border: "1px solid #D0D5DD", borderRadius: "8px",
|
|
119
|
+
padding: "8px 20px", fontWeight: "600", fontSize: "13px",
|
|
120
|
+
color: "#344054", cursor: "pointer",
|
|
121
|
+
}}>Cancel</button>
|
|
122
|
+
<button onClick={onConfirm} style={{
|
|
123
|
+
background: "#B42318", border: "none", borderRadius: "8px",
|
|
124
|
+
padding: "8px 20px", fontWeight: "600", fontSize: "13px",
|
|
125
|
+
color: "#fff", cursor: "pointer",
|
|
126
|
+
display: "flex", alignItems: "center", gap: "6px",
|
|
127
|
+
}}>
|
|
128
|
+
<TrashIcon size={13} /> Remove
|
|
129
|
+
</button>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// ─── Main Component ───────────────────────────────────────────────────────────
|
|
2
136
|
|
|
3
137
|
const Mapping = () => {
|
|
138
|
+
const { t } = useTranslation();
|
|
139
|
+
|
|
140
|
+
// Form state
|
|
141
|
+
const [selectedSurveyor, setSelectedSurveyor] = useState(null);
|
|
142
|
+
const [selectedMRD, setSelectedMRD] = useState(null);
|
|
143
|
+
|
|
144
|
+
// Mappings list
|
|
145
|
+
const [mappings, setMappings] = useState([]);
|
|
146
|
+
|
|
147
|
+
// Edit state: stores the id of the row being edited + its draft values
|
|
148
|
+
const [editingId, setEditingId] = useState(null);
|
|
149
|
+
const [editSurveyor, setEditSurveyor] = useState(null);
|
|
150
|
+
const [editMRD, setEditMRD] = useState(null);
|
|
151
|
+
|
|
152
|
+
// Delete confirm modal
|
|
153
|
+
const [deleteTarget, setDeleteTarget] = useState(null);
|
|
154
|
+
|
|
155
|
+
const [toast, setToast] = useState(null);
|
|
156
|
+
|
|
157
|
+
// ── Handlers ──────────────────────────────────────────────────────────────
|
|
158
|
+
|
|
159
|
+
const handleAddMapping = () => {
|
|
160
|
+
if (!selectedSurveyor || !selectedMRD) {
|
|
161
|
+
setToast({ type: "error", message: t("EKYC_SELECT_BOTH_ERROR") || "Please select both Surveyor and MRD" });
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const exists = mappings.some(
|
|
165
|
+
m => m.surveyorId === selectedSurveyor.id && m.mrdCode === selectedMRD.code
|
|
166
|
+
);
|
|
167
|
+
if (exists) {
|
|
168
|
+
setToast({ type: "warning", message: t("EKYC_MAPPING_EXISTS") || "This mapping already exists" });
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
setMappings(prev => [...prev, {
|
|
172
|
+
id: Date.now(),
|
|
173
|
+
surveyorName: selectedSurveyor.name,
|
|
174
|
+
surveyorId: selectedSurveyor.id,
|
|
175
|
+
mrdName: selectedMRD.name,
|
|
176
|
+
mrdCode: selectedMRD.code,
|
|
177
|
+
zone: selectedMRD.zone,
|
|
178
|
+
}]);
|
|
179
|
+
setSelectedMRD(null);
|
|
180
|
+
setToast({ type: "success", message: t("EKYC_MAPPING_ADDED") || "Mapping added successfully" });
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const handleEditStart = (row) => {
|
|
184
|
+
setEditingId(row.id);
|
|
185
|
+
setEditSurveyor(MOCK_SURVEYORS.find(s => s.id === row.surveyorId) || null);
|
|
186
|
+
setEditMRD(MOCK_MRDS.find(m => m.code === row.mrdCode) || null);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const handleEditSave = (id) => {
|
|
190
|
+
if (!editSurveyor || !editMRD) {
|
|
191
|
+
setToast({ type: "error", message: "Please select both Surveyor and MRD to save" });
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
// Check duplicate (excluding self)
|
|
195
|
+
const duplicate = mappings.some(
|
|
196
|
+
m => m.id !== id && m.surveyorId === editSurveyor.id && m.mrdCode === editMRD.code
|
|
197
|
+
);
|
|
198
|
+
if (duplicate) {
|
|
199
|
+
setToast({ type: "warning", message: "This mapping already exists" });
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
setMappings(prev => prev.map(m => m.id !== id ? m : {
|
|
203
|
+
...m,
|
|
204
|
+
surveyorName: editSurveyor.name,
|
|
205
|
+
surveyorId: editSurveyor.id,
|
|
206
|
+
mrdName: editMRD.name,
|
|
207
|
+
mrdCode: editMRD.code,
|
|
208
|
+
zone: editMRD.zone,
|
|
209
|
+
}));
|
|
210
|
+
setEditingId(null);
|
|
211
|
+
setToast({ type: "success", message: "Mapping updated successfully" });
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const handleEditCancel = () => {
|
|
215
|
+
setEditingId(null);
|
|
216
|
+
setEditSurveyor(null);
|
|
217
|
+
setEditMRD(null);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
const handleDeleteConfirm = () => {
|
|
221
|
+
setMappings(prev => prev.filter(m => m.id !== deleteTarget.id));
|
|
222
|
+
setDeleteTarget(null);
|
|
223
|
+
setToast({ type: "info", message: t("EKYC_MAPPING_REMOVED") || "Mapping removed" });
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const handleSaveMappings = () => {
|
|
227
|
+
if (mappings.length === 0) {
|
|
228
|
+
setToast({ type: "error", message: t("EKYC_NO_MAPPINGS_TO_SAVE") || "No mappings to save" });
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
// TODO: replace with real API call
|
|
232
|
+
setToast({ type: "success", message: t("EKYC_MAPPINGS_SAVED_SUCCESS") || "Surveyor mappings saved successfully!" });
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// ── Table columns ─────────────────────────────────────────────────────────
|
|
236
|
+
|
|
237
|
+
const columns = useMemo(() => [
|
|
238
|
+
{
|
|
239
|
+
Header: t("EKYC_SURVEYOR_NAME") || "Surveyor",
|
|
240
|
+
accessor: "surveyorName",
|
|
241
|
+
Cell: ({ row }) => {
|
|
242
|
+
const isEditing = editingId === row.original.id;
|
|
243
|
+
if (isEditing) {
|
|
244
|
+
return (
|
|
245
|
+
<div style={{ minWidth: "180px" }}>
|
|
246
|
+
<Dropdown
|
|
247
|
+
selected={editSurveyor}
|
|
248
|
+
select={setEditSurveyor}
|
|
249
|
+
option={MOCK_SURVEYORS}
|
|
250
|
+
optionKey="name"
|
|
251
|
+
t={t}
|
|
252
|
+
placeholder="Choose surveyor..."
|
|
253
|
+
/>
|
|
254
|
+
</div>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
return (
|
|
258
|
+
<div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
|
259
|
+
<div style={{
|
|
260
|
+
width: "32px", height: "32px", borderRadius: "50%",
|
|
261
|
+
background: "#EEF4FB", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
|
|
262
|
+
}}>
|
|
263
|
+
<UserIcon size={15} color="#3A7BD5" />
|
|
264
|
+
</div>
|
|
265
|
+
<div>
|
|
266
|
+
<div style={{ fontWeight: "600", fontSize: "13px", color: "#0D1B2A" }}>{row.original.surveyorName}</div>
|
|
267
|
+
<div style={{ fontSize: "11px", color: "#6B7B8E" }}>ID: {row.original.surveyorId}</div>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
);
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
Header: t("EKYC_MRD_ASSIGNED") || "MRD Assigned",
|
|
275
|
+
accessor: "mrdName",
|
|
276
|
+
Cell: ({ row }) => {
|
|
277
|
+
const isEditing = editingId === row.original.id;
|
|
278
|
+
if (isEditing) {
|
|
279
|
+
return (
|
|
280
|
+
<div style={{ minWidth: "200px" }}>
|
|
281
|
+
<Dropdown
|
|
282
|
+
selected={editMRD}
|
|
283
|
+
select={setEditMRD}
|
|
284
|
+
option={MOCK_MRDS}
|
|
285
|
+
optionKey="name"
|
|
286
|
+
t={t}
|
|
287
|
+
placeholder="Choose MRD..."
|
|
288
|
+
/>
|
|
289
|
+
</div>
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
return (
|
|
293
|
+
<div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
|
294
|
+
<div style={{
|
|
295
|
+
width: "32px", height: "32px", borderRadius: "50%",
|
|
296
|
+
background: "#EEF4FB", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
|
|
297
|
+
}}>
|
|
298
|
+
<DiaryIcon size={15} color="#3A7BD5" />
|
|
299
|
+
</div>
|
|
300
|
+
<div>
|
|
301
|
+
<div style={{ fontWeight: "600", fontSize: "13px", color: "#0D1B2A" }}>{row.original.mrdName}</div>
|
|
302
|
+
<div style={{ fontSize: "11px", color: "#3A7BD5", display: "flex", alignItems: "center", gap: "3px" }}>
|
|
303
|
+
<MapPinIcon size={10} /> {row.original.zone}
|
|
304
|
+
</div>
|
|
305
|
+
</div>
|
|
306
|
+
</div>
|
|
307
|
+
);
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
Header: t("ES_COMMON_ACTION") || "Actions",
|
|
312
|
+
Cell: ({ row }) => {
|
|
313
|
+
const isEditing = editingId === row.original.id;
|
|
314
|
+
if (isEditing) {
|
|
315
|
+
return (
|
|
316
|
+
<div style={{ display: "flex", gap: "8px" }}>
|
|
317
|
+
<button
|
|
318
|
+
onClick={() => handleEditSave(row.original.id)}
|
|
319
|
+
style={{
|
|
320
|
+
display: "flex", alignItems: "center", gap: "5px",
|
|
321
|
+
background: "#3A7BD5", color: "#fff",
|
|
322
|
+
border: "none", borderRadius: "6px",
|
|
323
|
+
padding: "6px 12px", fontWeight: "600",
|
|
324
|
+
fontSize: "12px", cursor: "pointer",
|
|
325
|
+
}}
|
|
326
|
+
>
|
|
327
|
+
<CheckIcon size={13} /> Save
|
|
328
|
+
</button>
|
|
329
|
+
<button
|
|
330
|
+
onClick={handleEditCancel}
|
|
331
|
+
style={{
|
|
332
|
+
display: "flex", alignItems: "center", gap: "5px",
|
|
333
|
+
background: "none", border: "1px solid #D0D5DD",
|
|
334
|
+
borderRadius: "6px", padding: "6px 12px",
|
|
335
|
+
fontWeight: "600", fontSize: "12px",
|
|
336
|
+
color: "#344054", cursor: "pointer",
|
|
337
|
+
}}
|
|
338
|
+
>
|
|
339
|
+
<XIcon size={13} /> Cancel
|
|
340
|
+
</button>
|
|
341
|
+
</div>
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
return (
|
|
345
|
+
<div style={{ display: "flex", gap: "8px" }}>
|
|
346
|
+
<button
|
|
347
|
+
onClick={() => handleEditStart(row.original)}
|
|
348
|
+
style={{
|
|
349
|
+
display: "flex", alignItems: "center", gap: "5px",
|
|
350
|
+
background: "none", border: "1px solid #D0D5DD",
|
|
351
|
+
borderRadius: "6px", padding: "6px 12px",
|
|
352
|
+
color: "#344054", fontSize: "12px",
|
|
353
|
+
fontWeight: "600", cursor: "pointer",
|
|
354
|
+
}}
|
|
355
|
+
>
|
|
356
|
+
<EditIcon size={13} /> Edit
|
|
357
|
+
</button>
|
|
358
|
+
<button
|
|
359
|
+
onClick={() => setDeleteTarget(row.original)}
|
|
360
|
+
style={{
|
|
361
|
+
display: "flex", alignItems: "center", gap: "5px",
|
|
362
|
+
background: "none", border: "1px solid #FECDCA",
|
|
363
|
+
borderRadius: "6px", padding: "6px 12px",
|
|
364
|
+
color: "#B42318", fontSize: "12px",
|
|
365
|
+
fontWeight: "600", cursor: "pointer",
|
|
366
|
+
}}
|
|
367
|
+
>
|
|
368
|
+
<TrashIcon size={13} /> Remove
|
|
369
|
+
</button>
|
|
370
|
+
</div>
|
|
371
|
+
);
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
], [editingId, editSurveyor, editMRD, mappings, t]);
|
|
375
|
+
|
|
376
|
+
// ── Render ────────────────────────────────────────────────────────────────
|
|
377
|
+
|
|
4
378
|
return (
|
|
5
|
-
<div style={{
|
|
6
|
-
|
|
379
|
+
<div style={{ background: "#F5F7FA", minHeight: "100vh", padding: "0" }}>
|
|
380
|
+
|
|
381
|
+
{/* Page Header Bar */}
|
|
382
|
+
<Card style={{
|
|
383
|
+
display: "flex", alignItems: "center", justifyContent: "space-between",
|
|
384
|
+
padding: "16px 24px", marginBottom: "0", borderRadius: "4px",
|
|
385
|
+
}}>
|
|
386
|
+
<div style={{ display: "flex", alignItems: "center", gap: "12px" }}>
|
|
387
|
+
<div style={{ color: "#3A8DCC" }}>
|
|
388
|
+
<DiaryIcon size={24} />
|
|
389
|
+
</div>
|
|
390
|
+
<div style={{ fontWeight: "700", fontSize: "18px", color: "#0B0C0C" }}>
|
|
391
|
+
{t("EKYC_SURVEYOR_MAPPING") || "Surveyor Mapping"}
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
394
|
+
<button
|
|
395
|
+
onClick={handleSaveMappings}
|
|
396
|
+
disabled={mappings.length === 0}
|
|
397
|
+
style={{
|
|
398
|
+
display: "flex", alignItems: "center", gap: "8px",
|
|
399
|
+
background: mappings.length === 0 ? "#D0D5DD" : "#0F3460",
|
|
400
|
+
color: "#fff", border: "none", borderRadius: "8px",
|
|
401
|
+
padding: "10px 20px", fontWeight: "600", fontSize: "14px",
|
|
402
|
+
cursor: mappings.length === 0 ? "not-allowed" : "pointer",
|
|
403
|
+
transition: "background 0.2s",
|
|
404
|
+
}}
|
|
405
|
+
>
|
|
406
|
+
<SaveIcon size={15} />
|
|
407
|
+
{t("EKYC_SAVE_MAPPINGS") || "Save Mappings"}
|
|
408
|
+
</button>
|
|
409
|
+
</Card>
|
|
410
|
+
|
|
411
|
+
{/* Content */}
|
|
412
|
+
<div style={{ padding: "24px 32px" }}>
|
|
413
|
+
<p style={{ fontSize: "13px", color: "#6B7B8E", marginBottom: "24px", marginTop: "0" }}>
|
|
414
|
+
{t("EKYC_MAPPING_SUBHEADER") || "Assign Meter Reading Dairies to surveyors to manage their data access."}
|
|
415
|
+
</p>
|
|
416
|
+
|
|
417
|
+
<div style={{ display: "grid", gridTemplateColumns: "360px 1fr", gap: "20px", alignItems: "start" }}>
|
|
418
|
+
|
|
419
|
+
{/* ── Left: New Mapping Panel ── */}
|
|
420
|
+
<div style={{
|
|
421
|
+
background: "#fff", borderRadius: "12px",
|
|
422
|
+
border: "1px solid #E5E9EF", overflow: "hidden",
|
|
423
|
+
}}>
|
|
424
|
+
{/* Header */}
|
|
425
|
+
<div style={{
|
|
426
|
+
display: "flex", alignItems: "center", gap: "10px",
|
|
427
|
+
padding: "16px 20px", borderBottom: "1px solid #F0F2F5", background: "#FAFBFC",
|
|
428
|
+
}}>
|
|
429
|
+
<div style={{
|
|
430
|
+
width: "32px", height: "32px", borderRadius: "8px",
|
|
431
|
+
background: "#EEF4FB", display: "flex", alignItems: "center", justifyContent: "center",
|
|
432
|
+
}}>
|
|
433
|
+
<DiaryIcon size={16} color="#3A7BD5" />
|
|
434
|
+
</div>
|
|
435
|
+
<span style={{ fontWeight: "700", fontSize: "15px", color: "#0D1B2A" }}>
|
|
436
|
+
{t("EKYC_NEW_MAPPING") || "New Mapping"}
|
|
437
|
+
</span>
|
|
438
|
+
</div>
|
|
439
|
+
|
|
440
|
+
{/* Body */}
|
|
441
|
+
<div style={{ padding: "20px" }}>
|
|
442
|
+
{/* Surveyor */}
|
|
443
|
+
<div style={{ marginBottom: "16px" }}>
|
|
444
|
+
<label style={{
|
|
445
|
+
display: "flex", alignItems: "center", gap: "6px",
|
|
446
|
+
fontSize: "11px", fontWeight: "700", letterSpacing: "0.06em",
|
|
447
|
+
color: "#3A7BD5", textTransform: "uppercase", marginBottom: "8px",
|
|
448
|
+
}}>
|
|
449
|
+
<UserIcon size={12} color="#3A7BD5" />
|
|
450
|
+
{t("EKYC_SELECT_SURVEYOR") || "Select Surveyor"}
|
|
451
|
+
</label>
|
|
452
|
+
<Dropdown
|
|
453
|
+
selected={selectedSurveyor}
|
|
454
|
+
select={setSelectedSurveyor}
|
|
455
|
+
option={MOCK_SURVEYORS}
|
|
456
|
+
optionKey="name"
|
|
457
|
+
t={t}
|
|
458
|
+
placeholder={t("EKYC_SELECT_SURVEYOR_PLACEHOLDER") || "Choose a surveyor..."}
|
|
459
|
+
/>
|
|
460
|
+
</div>
|
|
461
|
+
|
|
462
|
+
{/* MRD */}
|
|
463
|
+
<div style={{ marginBottom: "16px" }}>
|
|
464
|
+
<label style={{
|
|
465
|
+
display: "flex", alignItems: "center", gap: "6px",
|
|
466
|
+
fontSize: "11px", fontWeight: "700", letterSpacing: "0.06em",
|
|
467
|
+
color: "#3A7BD5", textTransform: "uppercase", marginBottom: "8px",
|
|
468
|
+
}}>
|
|
469
|
+
<DiaryIcon size={12} color="#3A7BD5" />
|
|
470
|
+
{t("EKYC_SELECT_MRD") || "Select MRD"}
|
|
471
|
+
</label>
|
|
472
|
+
<Dropdown
|
|
473
|
+
selected={selectedMRD}
|
|
474
|
+
select={setSelectedMRD}
|
|
475
|
+
option={MOCK_MRDS}
|
|
476
|
+
optionKey="name"
|
|
477
|
+
t={t}
|
|
478
|
+
placeholder={t("EKYC_SELECT_MRD_PLACEHOLDER") || "Choose an MRD..."}
|
|
479
|
+
/>
|
|
480
|
+
</div>
|
|
481
|
+
|
|
482
|
+
{/* MRD Info Preview */}
|
|
483
|
+
{selectedMRD && (
|
|
484
|
+
<div style={{
|
|
485
|
+
background: "#EEF4FB", borderLeft: "3px solid #3A7BD5",
|
|
486
|
+
borderRadius: "6px", padding: "10px 14px",
|
|
487
|
+
fontSize: "12px", color: "#0D1B2A", marginBottom: "16px",
|
|
488
|
+
display: "flex", alignItems: "center", gap: "8px",
|
|
489
|
+
}}>
|
|
490
|
+
<MapPinIcon size={13} />
|
|
491
|
+
<span><strong>{selectedMRD.name}</strong> — {selectedMRD.zone} Zone</span>
|
|
492
|
+
</div>
|
|
493
|
+
)}
|
|
494
|
+
|
|
495
|
+
{/* Surveyor Preview */}
|
|
496
|
+
{selectedSurveyor && (
|
|
497
|
+
<div style={{
|
|
498
|
+
background: "#F5F7FA", borderLeft: "3px solid #6B7B8E",
|
|
499
|
+
borderRadius: "6px", padding: "10px 14px",
|
|
500
|
+
fontSize: "12px", color: "#0D1B2A", marginBottom: "16px",
|
|
501
|
+
display: "flex", alignItems: "center", gap: "8px",
|
|
502
|
+
}}>
|
|
503
|
+
<UserIcon size={13} color="#6B7B8E" />
|
|
504
|
+
<span><strong>{selectedSurveyor.name}</strong> — {selectedSurveyor.id}</span>
|
|
505
|
+
</div>
|
|
506
|
+
)}
|
|
507
|
+
|
|
508
|
+
{/* Add Button */}
|
|
509
|
+
<button
|
|
510
|
+
onClick={handleAddMapping}
|
|
511
|
+
disabled={!selectedSurveyor || !selectedMRD}
|
|
512
|
+
style={{
|
|
513
|
+
width: "100%",
|
|
514
|
+
display: "flex", alignItems: "center", justifyContent: "center", gap: "8px",
|
|
515
|
+
background: (!selectedSurveyor || !selectedMRD) ? "#D0D5DD" : "#3A7BD5",
|
|
516
|
+
color: "#fff", border: "none", borderRadius: "8px",
|
|
517
|
+
padding: "12px", fontWeight: "600", fontSize: "14px",
|
|
518
|
+
cursor: (!selectedSurveyor || !selectedMRD) ? "not-allowed" : "pointer",
|
|
519
|
+
marginTop: "4px", transition: "background 0.2s",
|
|
520
|
+
}}
|
|
521
|
+
>
|
|
522
|
+
<PlusIcon size={16} />
|
|
523
|
+
{t("EKYC_ADD_TO_LIST") || "Add to Mapping List"}
|
|
524
|
+
</button>
|
|
525
|
+
</div>
|
|
526
|
+
|
|
527
|
+
{/* Stats Footer */}
|
|
528
|
+
{mappings.length > 0 && (
|
|
529
|
+
<div style={{
|
|
530
|
+
padding: "12px 20px", borderTop: "1px solid #F0F2F5",
|
|
531
|
+
background: "#FAFBFC", display: "flex", gap: "16px",
|
|
532
|
+
}}>
|
|
533
|
+
<div style={{ textAlign: "center", flex: 1 }}>
|
|
534
|
+
<div style={{ fontSize: "20px", fontWeight: "700", color: "#0F3460" }}>
|
|
535
|
+
{mappings.length}
|
|
536
|
+
</div>
|
|
537
|
+
<div style={{ fontSize: "11px", color: "#6B7B8E" }}>Total Mappings</div>
|
|
538
|
+
</div>
|
|
539
|
+
<div style={{ width: "1px", background: "#E5E9EF" }} />
|
|
540
|
+
<div style={{ textAlign: "center", flex: 1 }}>
|
|
541
|
+
<div style={{ fontSize: "20px", fontWeight: "700", color: "#0F3460" }}>
|
|
542
|
+
{[...new Set(mappings.map(m => m.surveyorId))].length}
|
|
543
|
+
</div>
|
|
544
|
+
<div style={{ fontSize: "11px", color: "#6B7B8E" }}>Surveyors</div>
|
|
545
|
+
</div>
|
|
546
|
+
<div style={{ width: "1px", background: "#E5E9EF" }} />
|
|
547
|
+
<div style={{ textAlign: "center", flex: 1 }}>
|
|
548
|
+
<div style={{ fontSize: "20px", fontWeight: "700", color: "#0F3460" }}>
|
|
549
|
+
{[...new Set(mappings.map(m => m.mrdCode))].length}
|
|
550
|
+
</div>
|
|
551
|
+
<div style={{ fontSize: "11px", color: "#6B7B8E" }}>MRDs</div>
|
|
552
|
+
</div>
|
|
553
|
+
</div>
|
|
554
|
+
)}
|
|
555
|
+
</div>
|
|
556
|
+
|
|
557
|
+
{/* ── Right: Summary Table Panel ── */}
|
|
558
|
+
<div style={{
|
|
559
|
+
background: "#fff", borderRadius: "12px",
|
|
560
|
+
border: "1px solid #E5E9EF", overflow: "hidden", minHeight: "420px",
|
|
561
|
+
}}>
|
|
562
|
+
{/* Header */}
|
|
563
|
+
<div style={{
|
|
564
|
+
display: "flex", alignItems: "center", justifyContent: "space-between",
|
|
565
|
+
padding: "16px 20px", borderBottom: "1px solid #F0F2F5", background: "#FAFBFC",
|
|
566
|
+
}}>
|
|
567
|
+
<div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
|
568
|
+
<div style={{
|
|
569
|
+
width: "32px", height: "32px", borderRadius: "8px",
|
|
570
|
+
background: "#EEF4FB", display: "flex", alignItems: "center", justifyContent: "center",
|
|
571
|
+
}}>
|
|
572
|
+
<UserIcon size={16} color="#3A7BD5" />
|
|
573
|
+
</div>
|
|
574
|
+
<span style={{ fontWeight: "700", fontSize: "15px", color: "#0D1B2A" }}>
|
|
575
|
+
{t("EKYC_MAPPING_SUMMARY") || "Mapping Summary"}
|
|
576
|
+
</span>
|
|
577
|
+
</div>
|
|
578
|
+
<span style={{
|
|
579
|
+
background: mappings.length > 0 ? "#0F3460" : "#E5E9EF",
|
|
580
|
+
color: mappings.length > 0 ? "#fff" : "#6B7B8E",
|
|
581
|
+
fontSize: "12px", fontWeight: "700",
|
|
582
|
+
padding: "3px 10px", borderRadius: "20px",
|
|
583
|
+
}}>
|
|
584
|
+
{mappings.length} {t("EKYC_ITEMS") || "items"}
|
|
585
|
+
</span>
|
|
586
|
+
</div>
|
|
587
|
+
|
|
588
|
+
{/* Body */}
|
|
589
|
+
<div style={{ padding: "20px" }}>
|
|
590
|
+
{mappings.length > 0 ? (
|
|
591
|
+
<div style={{ border: "1px solid #E5E9EF", borderRadius: "8px", overflow: "hidden" }}>
|
|
592
|
+
<Table
|
|
593
|
+
t={t}
|
|
594
|
+
data={mappings}
|
|
595
|
+
columns={columns}
|
|
596
|
+
getCellProps={() => ({})}
|
|
597
|
+
tableClassName="digit-table"
|
|
598
|
+
/>
|
|
599
|
+
</div>
|
|
600
|
+
) : (
|
|
601
|
+
<div style={{
|
|
602
|
+
display: "flex", flexDirection: "column",
|
|
603
|
+
alignItems: "center", justifyContent: "center",
|
|
604
|
+
minHeight: "320px", textAlign: "center",
|
|
605
|
+
}}>
|
|
606
|
+
<div style={{ marginBottom: "16px", opacity: 0.2 }}>
|
|
607
|
+
<DiaryIcon size={56} color="#0F3460" />
|
|
608
|
+
</div>
|
|
609
|
+
<div style={{ fontSize: "15px", fontWeight: "700", color: "#0D1B2A", marginBottom: "6px" }}>
|
|
610
|
+
{t("EKYC_NO_MAPPINGS") || "No Mappings Created Yet"}
|
|
611
|
+
</div>
|
|
612
|
+
<div style={{ fontSize: "13px", color: "#6B7B8E" }}>
|
|
613
|
+
{t("EKYC_NO_MAPPINGS_HINT") || "Select a surveyor and MRD on the left to get started."}
|
|
614
|
+
</div>
|
|
615
|
+
</div>
|
|
616
|
+
)}
|
|
617
|
+
</div>
|
|
618
|
+
</div>
|
|
619
|
+
</div>
|
|
620
|
+
</div>
|
|
621
|
+
|
|
622
|
+
{/* Delete Confirm Modal */}
|
|
623
|
+
{deleteTarget && (
|
|
624
|
+
<ConfirmDeleteModal
|
|
625
|
+
mapping={deleteTarget}
|
|
626
|
+
onConfirm={handleDeleteConfirm}
|
|
627
|
+
onCancel={() => setDeleteTarget(null)}
|
|
628
|
+
/>
|
|
629
|
+
)}
|
|
630
|
+
|
|
631
|
+
{/* Toast */}
|
|
632
|
+
{toast && (
|
|
633
|
+
<Toast
|
|
634
|
+
label={toast.message}
|
|
635
|
+
error={toast.type === "error"}
|
|
636
|
+
warning={toast.type === "warning"}
|
|
637
|
+
isDsc={true}
|
|
638
|
+
onClose={() => setToast(null)}
|
|
639
|
+
/>
|
|
640
|
+
)}
|
|
7
641
|
</div>
|
|
8
|
-
)
|
|
9
|
-
}
|
|
642
|
+
);
|
|
643
|
+
};
|
|
10
644
|
|
|
11
|
-
export default Mapping
|
|
645
|
+
export default Mapping;
|