@djb25/digit-ui-module-ekyc 1.0.30 → 1.0.32
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 +8911 -1
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +3295 -2039
- package/dist/index.modern.js.map +1 -1
- package/package.json +4 -1
- package/dist/index.css +0 -54
- package/src/Module.js +0 -78
- package/src/components/AadhaarVerification.js +0 -315
- package/src/components/AssignEkyc.js +0 -236
- package/src/components/AssignEkycModal.js +0 -446
- package/src/components/CeoDashboard.js +0 -264
- package/src/components/CeoDashboard.jsx +0 -334
- package/src/components/ConnectionDetailsView.js +0 -241
- package/src/components/Dashboard.js +0 -43
- package/src/components/DesktopInbox.js +0 -176
- package/src/components/EKYCCard.js +0 -53
- package/src/components/Filter.js +0 -55
- package/src/components/MeterDetails.js +0 -336
- package/src/components/MobileInbox.js +0 -73
- package/src/components/PropertyInfo.js +0 -264
- package/src/components/Review.js +0 -696
- package/src/components/SearchConsumer.js +0 -142
- package/src/components/SearchFormFieldsComponent.js +0 -67
- package/src/components/SelectEkycZones.js +0 -71
- package/src/components/StatusCards.js +0 -148
- package/src/components/SurveyorDetailsCard.js +0 -512
- package/src/components/VendorDetails.jsx +0 -230
- package/src/components/analytics/charts/ClusterHeatmap.js +0 -88
- package/src/components/analytics/charts/ExecutiveBarChart.jsx +0 -30
- package/src/components/analytics/charts/ExecutiveLineChart.jsx +0 -159
- package/src/components/analytics/charts/ExecutivePieChart.jsx +0 -24
- package/src/components/analytics/charts/TaskStatusChart.js +0 -90
- package/src/components/analytics/components/AnalyticsTable.js +0 -106
- package/src/components/analytics/components/DashboardLayout.js +0 -52
- package/src/components/analytics/components/EmptyState.js +0 -27
- package/src/components/analytics/components/ErrorBoundary.js +0 -27
- package/src/components/analytics/components/FilterBar.js +0 -73
- package/src/components/analytics/components/NotificationPanel.js +0 -77
- package/src/components/analytics/components/SLAWidget.js +0 -56
- package/src/components/analytics/components/SkeletonLoader.js +0 -53
- package/src/components/analytics/components/SummaryCard.js +0 -74
- package/src/components/analytics/components/WorkflowTimeline.js +0 -55
- package/src/components/analytics/utils/exportUtils.js +0 -64
- package/src/components/analytics/utils/filterSerializer.js +0 -50
- package/src/components/mockData.js +0 -772
- package/src/config/AadhaarVerificationConfig.js +0 -367
- package/src/config/MeterDetailsConfig.js +0 -297
- package/src/config/PropertyInfoConfig.js +0 -145
- package/src/config/config.js +0 -70
- package/src/hook/SupervisorInboxTableConfig.js +0 -80
- package/src/hook/useInboxTableConfig.js +0 -131
- package/src/pages/citizen/Home.js +0 -54
- package/src/pages/citizen/Inbox.js +0 -265
- package/src/pages/citizen/index.js +0 -199
- package/src/pages/employee/ConsumerDetails.js +0 -299
- package/src/pages/employee/Create.js +0 -94
- package/src/pages/employee/EKYCForm.js +0 -118
- package/src/pages/employee/Inbox.js +0 -266
- package/src/pages/employee/Mapping.js +0 -358
- package/src/pages/employee/Update.js +0 -9
- package/src/pages/employee/index.js +0 -184
- package/src/utils/index.js +0 -46
- package/src/utils/reportDownloader.js +0 -90
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import React, { useMemo } from "react";
|
|
2
|
-
import { useHistory, useParams } from "react-router-dom";
|
|
3
|
-
import { FaArrowLeft, FaUsers, FaCheckCircle, FaClock, FaExclamationTriangle, FaMapMarkedAlt } from "react-icons/fa";
|
|
4
|
-
import { ekycMockData } from "./mockData";
|
|
5
|
-
import ExecutiveLineChart from "./analytics/charts/ExecutiveLineChart";
|
|
6
|
-
import ExecutiveBarChart from "./analytics/charts/ExecutiveBarChart";
|
|
7
|
-
import ExecutivePieChart from "./analytics/charts/ExecutivePieChart";
|
|
8
|
-
import { Loader } from "@djb25/digit-ui-react-components";
|
|
9
|
-
|
|
10
|
-
const VendorDetails = () => {
|
|
11
|
-
const history = useHistory();
|
|
12
|
-
const { vendorId = 1 } = useParams();
|
|
13
|
-
const vendor = useMemo(() => ekycMockData.vendors.find((item) => item.id === Number(vendorId)), [vendorId]);
|
|
14
|
-
|
|
15
|
-
const tenantId = Digit.ULBService.getCurrentTenantId();
|
|
16
|
-
const { isLoading, data: dashboardData } = Digit.Hooks.ekyc.useEkycSurveyorDashboard(
|
|
17
|
-
{},
|
|
18
|
-
{
|
|
19
|
-
tenantId,
|
|
20
|
-
offset: 0,
|
|
21
|
-
limit: 10,
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
enabled: !!tenantId,
|
|
25
|
-
}
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
if (!vendor) {
|
|
29
|
-
return (
|
|
30
|
-
<div className="ekyc-dashboard-wrapper">
|
|
31
|
-
<div className="dashboard-shell">
|
|
32
|
-
<div className="detail-header">
|
|
33
|
-
<button className="back-button" onClick={() => history.goBack()}>
|
|
34
|
-
<FaArrowLeft /> Back
|
|
35
|
-
</button>
|
|
36
|
-
</div>
|
|
37
|
-
<div className="empty-state">
|
|
38
|
-
<h2>Vendor analytics not found</h2>
|
|
39
|
-
<p>The selected vendor does not exist in the current report. Please return to the dashboard.</p>
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const zoneRows = vendor.zones.slice(0, 8);
|
|
47
|
-
|
|
48
|
-
const performanceData = vendor.dailyPerformance.map((row) => ({
|
|
49
|
-
day: row.day,
|
|
50
|
-
completed: row.completed,
|
|
51
|
-
pending: row.pending,
|
|
52
|
-
rejected: row.rejected,
|
|
53
|
-
}));
|
|
54
|
-
|
|
55
|
-
if (isLoading) <Loader />;
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<div className="ekyc-dashboard-wrapper">
|
|
59
|
-
<div className="dashboard-shell detail-shell">
|
|
60
|
-
<section className="kpi-grid detail-kpi-grid">
|
|
61
|
-
{[
|
|
62
|
-
{
|
|
63
|
-
label: "Assigned Connections",
|
|
64
|
-
value: vendor.assignedConnections,
|
|
65
|
-
icon: <FaUsers />,
|
|
66
|
-
variant: "primary",
|
|
67
|
-
},
|
|
68
|
-
{
|
|
69
|
-
label: "Agency eKYC",
|
|
70
|
-
value: vendor.completedEkyc,
|
|
71
|
-
icon: <FaCheckCircle />,
|
|
72
|
-
variant: "success",
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
label: "Self eKYC",
|
|
76
|
-
value: vendor.selfEkyc,
|
|
77
|
-
icon: <FaUsers />,
|
|
78
|
-
variant: "info",
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
label: "Pending",
|
|
82
|
-
value: vendor.pending,
|
|
83
|
-
icon: <FaClock />,
|
|
84
|
-
variant: "warning",
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
label: "Rejected",
|
|
88
|
-
value: vendor.rejected,
|
|
89
|
-
icon: <FaExclamationTriangle />,
|
|
90
|
-
variant: "danger",
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
label: "Success Rate",
|
|
94
|
-
value: `${vendor.successRate}%`,
|
|
95
|
-
icon: <FaCheckCircle />,
|
|
96
|
-
variant: "success",
|
|
97
|
-
},
|
|
98
|
-
].map((item) => (
|
|
99
|
-
<article key={item.label} className={`kpi-card card-${item.variant}`}>
|
|
100
|
-
<div className="kpi-icon">{item.icon}</div>
|
|
101
|
-
<div>
|
|
102
|
-
<p className="kpi-title">{item.label}</p>
|
|
103
|
-
<h2>{item.value?.toLocaleString?.() ?? item.value}</h2>
|
|
104
|
-
</div>
|
|
105
|
-
</article>
|
|
106
|
-
))}
|
|
107
|
-
</section>
|
|
108
|
-
|
|
109
|
-
<section className="analytics-grid detail-analytics-grid">
|
|
110
|
-
<div className="analytics-panel glass-card">
|
|
111
|
-
<div className="section-header">
|
|
112
|
-
<h2>Daily Completion Trend</h2>
|
|
113
|
-
<span className="badge success">Performance</span>
|
|
114
|
-
</div>
|
|
115
|
-
<ExecutiveLineChart data={performanceData} dataKey="completed" name="Completed" />
|
|
116
|
-
</div>
|
|
117
|
-
|
|
118
|
-
<div className="analytics-panel glass-card">
|
|
119
|
-
<div className="section-header">
|
|
120
|
-
<h2>Pending vs Completed</h2>
|
|
121
|
-
<span className="badge warning">Workload</span>
|
|
122
|
-
</div>
|
|
123
|
-
<ExecutiveBarChart
|
|
124
|
-
data={performanceData}
|
|
125
|
-
categories={[
|
|
126
|
-
{ key: "completed", name: "Completed" },
|
|
127
|
-
{ key: "pending", name: "Pending" },
|
|
128
|
-
]}
|
|
129
|
-
xKey="day"
|
|
130
|
-
/>
|
|
131
|
-
</div>
|
|
132
|
-
|
|
133
|
-
<div className="analytics-panel glass-card">
|
|
134
|
-
<div className="section-header">
|
|
135
|
-
<h2>Self vs Agency Split</h2>
|
|
136
|
-
<span className="badge info">Adoption</span>
|
|
137
|
-
</div>
|
|
138
|
-
<ExecutivePieChart
|
|
139
|
-
data={[
|
|
140
|
-
{ label: "Agency eKYC", value: vendor.completedEkyc },
|
|
141
|
-
{ label: "Citizen Self eKYC", value: vendor.selfEkyc },
|
|
142
|
-
]}
|
|
143
|
-
dataKey="value"
|
|
144
|
-
labelKey="label"
|
|
145
|
-
/>
|
|
146
|
-
</div>
|
|
147
|
-
</section>
|
|
148
|
-
|
|
149
|
-
<section className="zone-section detail-zone-section">
|
|
150
|
-
<div className="section-header">
|
|
151
|
-
<div>
|
|
152
|
-
<h2>
|
|
153
|
-
<FaMapMarkedAlt /> Zone-wise Jurisdiction Analytics
|
|
154
|
-
</h2>
|
|
155
|
-
<p>Drill into the current operational load and heatmap intensity for this vendor.</p>
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
<div className="table-wrapper glass-card">
|
|
159
|
-
<table>
|
|
160
|
-
<thead>
|
|
161
|
-
<tr>
|
|
162
|
-
<th>Zone</th>
|
|
163
|
-
<th>Cluster</th>
|
|
164
|
-
<th>Assigned</th>
|
|
165
|
-
<th>Agency eKYC</th>
|
|
166
|
-
<th>Pending</th>
|
|
167
|
-
<th>Activity Score</th>
|
|
168
|
-
</tr>
|
|
169
|
-
</thead>
|
|
170
|
-
<tbody>
|
|
171
|
-
{zoneRows.map((row, index) => (
|
|
172
|
-
<tr key={`${row.location}-${index}`}>
|
|
173
|
-
<td>{row.location}</td>
|
|
174
|
-
<td>{row.cluster || row.district}</td>
|
|
175
|
-
<td>{row.activeDemand?.toLocaleString() ?? "—"}</td>
|
|
176
|
-
<td>{row.pppZones?.toLocaleString() ?? "—"}</td>
|
|
177
|
-
<td>{row.inactiveDemand?.toLocaleString() ?? "—"}</td>
|
|
178
|
-
<td>
|
|
179
|
-
<span className={`status-badge ${row.intensityScore > 65 ? "danger" : row.intensityScore > 45 ? "warning" : "success"}`}>
|
|
180
|
-
{row.intensityScore}%
|
|
181
|
-
</span>
|
|
182
|
-
</td>
|
|
183
|
-
</tr>
|
|
184
|
-
))}
|
|
185
|
-
</tbody>
|
|
186
|
-
</table>
|
|
187
|
-
</div>
|
|
188
|
-
</section>
|
|
189
|
-
|
|
190
|
-
<section className="bottom-grid detail-bottom-grid">
|
|
191
|
-
<div className="cards-summary glass-card">
|
|
192
|
-
<h2>Operational Efficiency</h2>
|
|
193
|
-
<div className="efficiency-grid">
|
|
194
|
-
<div className="efficiency-box">
|
|
195
|
-
<h3>{vendor.activeSurveyors}</h3>
|
|
196
|
-
<p>Active Surveyors</p>
|
|
197
|
-
</div>
|
|
198
|
-
<div className="efficiency-box">
|
|
199
|
-
<h3>{vendor.supervisors}</h3>
|
|
200
|
-
<p>Supervisors</p>
|
|
201
|
-
</div>
|
|
202
|
-
<div className="efficiency-box">
|
|
203
|
-
<h3>{vendor.progress}%</h3>
|
|
204
|
-
<p>Execution Rate</p>
|
|
205
|
-
</div>
|
|
206
|
-
<div className="efficiency-box">
|
|
207
|
-
<h3>{vendor.dailyPerformance.slice(-1)[0]?.completed?.toLocaleString()}</h3>
|
|
208
|
-
<p>Latest Day Completed</p>
|
|
209
|
-
</div>
|
|
210
|
-
</div>
|
|
211
|
-
</div>
|
|
212
|
-
|
|
213
|
-
<div className="cards-summary glass-card">
|
|
214
|
-
<h2>Supervisor Pulse</h2>
|
|
215
|
-
<div className="pulse-list">
|
|
216
|
-
{vendor.jurisdictions.map((zone) => (
|
|
217
|
-
<div key={zone} className="pulse-row">
|
|
218
|
-
<span>{zone}</span>
|
|
219
|
-
<span>{Math.max(12, Math.round(Math.random() * 38))} active</span>
|
|
220
|
-
</div>
|
|
221
|
-
))}
|
|
222
|
-
</div>
|
|
223
|
-
</div>
|
|
224
|
-
</section>
|
|
225
|
-
</div>
|
|
226
|
-
</div>
|
|
227
|
-
);
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
export default VendorDetails;
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { useTranslation } from "react-i18next";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Custom SVG-based Heatmap component for Cluster Workload monitoring.
|
|
6
|
-
*/
|
|
7
|
-
const ClusterHeatmap = ({ data, title, onDrillDown }) => {
|
|
8
|
-
const { t } = useTranslation();
|
|
9
|
-
|
|
10
|
-
if (!data || data.length === 0) return null;
|
|
11
|
-
|
|
12
|
-
const getIntensityColor = (score) => {
|
|
13
|
-
if (score > 80) return "#EF4444"; // High - Red
|
|
14
|
-
if (score > 50) return "#F59E0B"; // Medium - Amber
|
|
15
|
-
return "#10B981"; // Low - Emerald
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
return (
|
|
19
|
-
<div className="cluster-heatmap-container glass-card" style={{ padding: "28px" }}>
|
|
20
|
-
{title && <h3 className="chart-title" style={{ marginBottom: "28px", fontSize: "18px", fontWeight: "800", color: "#111827", letterSpacing: "-0.025em" }}>{t(title)}</h3>}
|
|
21
|
-
<div className="heatmap-grid" style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(240px, 1fr))", gap: "20px" }}>
|
|
22
|
-
{data.map((cluster) => (
|
|
23
|
-
<div
|
|
24
|
-
key={cluster.clusterId}
|
|
25
|
-
className="heatmap-card glass-card"
|
|
26
|
-
onClick={() => onDrillDown?.(cluster)}
|
|
27
|
-
style={{
|
|
28
|
-
padding: "20px",
|
|
29
|
-
background: "#FFFFFF",
|
|
30
|
-
border: `1px solid ${getIntensityColor(cluster.intensityScore)}40`,
|
|
31
|
-
cursor: "pointer",
|
|
32
|
-
position: "relative",
|
|
33
|
-
overflow: "hidden"
|
|
34
|
-
}}
|
|
35
|
-
>
|
|
36
|
-
<div className="intensity-bar" style={{
|
|
37
|
-
position: "absolute",
|
|
38
|
-
top: 0,
|
|
39
|
-
left: 0,
|
|
40
|
-
height: "4px",
|
|
41
|
-
width: "100%",
|
|
42
|
-
background: getIntensityColor(cluster.intensityScore)
|
|
43
|
-
}} />
|
|
44
|
-
|
|
45
|
-
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: "12px" }}>
|
|
46
|
-
<span style={{ fontWeight: "600", fontSize: "14px", color: "#374151" }}>{cluster.clusterName}</span>
|
|
47
|
-
<span style={{
|
|
48
|
-
fontSize: "12px",
|
|
49
|
-
fontWeight: "700",
|
|
50
|
-
padding: "2px 8px",
|
|
51
|
-
borderRadius: "12px",
|
|
52
|
-
background: `${getIntensityColor(cluster.intensityScore)}20`,
|
|
53
|
-
color: getIntensityColor(cluster.intensityScore)
|
|
54
|
-
}}>
|
|
55
|
-
{cluster.intensityScore}%
|
|
56
|
-
</span>
|
|
57
|
-
</div>
|
|
58
|
-
|
|
59
|
-
<div className="cluster-stats" style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
|
|
60
|
-
<div style={{ display: "flex", justifyContent: "space-between", fontSize: "12px" }}>
|
|
61
|
-
<span style={{ color: "#6B7280" }}>{t("EKYC_PENDING_WORKLOAD")}</span>
|
|
62
|
-
<span style={{ fontWeight: "600", color: "#1F2937" }}>{cluster.pendingWorkload}</span>
|
|
63
|
-
</div>
|
|
64
|
-
<div style={{ display: "flex", justifyContent: "space-between", fontSize: "12px" }}>
|
|
65
|
-
<span style={{ color: "#6B7280" }}>{t("EKYC_ACTIVE_AGENCIES")}</span>
|
|
66
|
-
<span style={{ fontWeight: "600", color: "#1F2937" }}>{cluster.activeAgencies}</span>
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
|
|
70
|
-
<div className="mini-spark" style={{ marginTop: "12px", display: "flex", gap: "2px", alignItems: "flex-end", height: "20px" }}>
|
|
71
|
-
{cluster.wards.map((ward, idx) => (
|
|
72
|
-
<div key={idx} style={{
|
|
73
|
-
flex: 1,
|
|
74
|
-
height: `${Math.min(100, (ward.pendingCount / cluster.pendingWorkload) * 100)}%`,
|
|
75
|
-
background: getIntensityColor(cluster.intensityScore),
|
|
76
|
-
opacity: 0.6,
|
|
77
|
-
borderRadius: "1px"
|
|
78
|
-
}} />
|
|
79
|
-
))}
|
|
80
|
-
</div>
|
|
81
|
-
</div>
|
|
82
|
-
))}
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
);
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
export default ClusterHeatmap;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { ResponsiveContainer, BarChart, Bar, XAxis, YAxis, Tooltip, CartesianGrid, Legend } from "recharts";
|
|
3
|
-
|
|
4
|
-
const ExecutiveBarChart = ({ data = [], categories = [], xKey = "label" }) => {
|
|
5
|
-
return (
|
|
6
|
-
<div className="chart-card" style={{ minHeight: 320 }}>
|
|
7
|
-
<ResponsiveContainer width="100%" height={320}>
|
|
8
|
-
<BarChart data={data} margin={{ top: 12, right: 16, left: 0, bottom: 0 }}>
|
|
9
|
-
<CartesianGrid stroke="rgba(148, 163, 184, 0.12)" strokeDasharray="4 4" />
|
|
10
|
-
<XAxis dataKey={xKey} axisLine={false} tickLine={false} tick={{ fill: "#cbd5e1" }} />
|
|
11
|
-
<YAxis axisLine={false} tickLine={false} tick={{ fill: "#cbd5e1" }} />
|
|
12
|
-
<Tooltip contentStyle={{ background: "#0f172a", border: "none", borderRadius: 14 }} itemStyle={{ color: "#f8fafc" }} />
|
|
13
|
-
<Legend verticalAlign="top" align="right" iconType="circle" wrapperStyle={{ color: "#cbd5e1" }} />
|
|
14
|
-
{categories.map((series, index) => (
|
|
15
|
-
<Bar
|
|
16
|
-
key={series.key}
|
|
17
|
-
dataKey={series.key}
|
|
18
|
-
name={series.name}
|
|
19
|
-
fill={index === 0 ? "#34d399" : "#60a5fa"}
|
|
20
|
-
radius={[12, 12, 0, 0]}
|
|
21
|
-
barSize={24}
|
|
22
|
-
/>
|
|
23
|
-
))}
|
|
24
|
-
</BarChart>
|
|
25
|
-
</ResponsiveContainer>
|
|
26
|
-
</div>
|
|
27
|
-
);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export default ExecutiveBarChart;
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
// import React from "react";
|
|
2
|
-
// import { ResponsiveContainer, LineChart, Line, XAxis, YAxis, Tooltip, CartesianGrid, Legend } from "recharts";
|
|
3
|
-
|
|
4
|
-
// const ExecutiveLineChart = ({ data = [], dataKey = "completed", name = "Value" }) => {
|
|
5
|
-
// return (
|
|
6
|
-
// <div className="chart-card" style={{ minHeight: 320 }}>
|
|
7
|
-
// <ResponsiveContainer width="100%" height={320}>
|
|
8
|
-
// <LineChart data={data} margin={{ top: 12, right: 16, left: 0, bottom: 0 }}>
|
|
9
|
-
// <CartesianGrid stroke="rgba(148, 163, 184, 0.12)" strokeDasharray="4 4" />
|
|
10
|
-
// <XAxis dataKey="label" axisLine={false} tickLine={false} tick={{ fill: "#cbd5e1" }} />
|
|
11
|
-
// <YAxis axisLine={false} tickLine={false} tick={{ fill: "#cbd5e1" }} />
|
|
12
|
-
// <Tooltip contentStyle={{ background: "#0f172a", border: "none", borderRadius: 14, color: "#f8fafc" }} itemStyle={{ color: "#f8fafc" }} />
|
|
13
|
-
// <Legend verticalAlign="top" align="right" iconType="circle" wrapperStyle={{ color: "#cbd5e1" }} />
|
|
14
|
-
// <Line
|
|
15
|
-
// type="monotone"
|
|
16
|
-
// dataKey={dataKey}
|
|
17
|
-
// name={name}
|
|
18
|
-
// stroke="#38bdf8"
|
|
19
|
-
// strokeWidth={3}
|
|
20
|
-
// dot={{ r: 4 }}
|
|
21
|
-
// activeDot={{ r: 6, strokeWidth: 2, fill: "#60a5fa" }}
|
|
22
|
-
// />
|
|
23
|
-
// </LineChart>
|
|
24
|
-
// </ResponsiveContainer>
|
|
25
|
-
// </div>
|
|
26
|
-
// );
|
|
27
|
-
// };
|
|
28
|
-
|
|
29
|
-
// export default ExecutiveLineChart;
|
|
30
|
-
|
|
31
|
-
import React from "react";
|
|
32
|
-
import { ResponsiveContainer, LineChart, Line, XAxis, YAxis, Tooltip, CartesianGrid, Legend } from "recharts";
|
|
33
|
-
|
|
34
|
-
const ExecutiveLineChart = ({ data = [] }) => {
|
|
35
|
-
const formattedData = data.map((item) => ({
|
|
36
|
-
...item,
|
|
37
|
-
|
|
38
|
-
agencyKyc: item.completed || 0,
|
|
39
|
-
|
|
40
|
-
selfKyc: Math.round((item.completed || 0) * 0.42),
|
|
41
|
-
|
|
42
|
-
totalKyc: (item.completed || 0) + Math.round((item.completed || 0) * 0.42),
|
|
43
|
-
}));
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<div className="chart-card executive-line-chart">
|
|
47
|
-
<ResponsiveContainer width="100%" height={340}>
|
|
48
|
-
<LineChart
|
|
49
|
-
data={formattedData}
|
|
50
|
-
margin={{
|
|
51
|
-
top: 20,
|
|
52
|
-
right: 12,
|
|
53
|
-
left: 0,
|
|
54
|
-
bottom: 0,
|
|
55
|
-
}}
|
|
56
|
-
>
|
|
57
|
-
<CartesianGrid stroke="#e2e8f0" strokeDasharray="3 3" vertical={false} />
|
|
58
|
-
|
|
59
|
-
<XAxis
|
|
60
|
-
dataKey="label"
|
|
61
|
-
axisLine={false}
|
|
62
|
-
tickLine={false}
|
|
63
|
-
tick={{
|
|
64
|
-
fill: "#64748b",
|
|
65
|
-
fontSize: 12,
|
|
66
|
-
fontWeight: 600,
|
|
67
|
-
}}
|
|
68
|
-
/>
|
|
69
|
-
|
|
70
|
-
<YAxis
|
|
71
|
-
axisLine={false}
|
|
72
|
-
tickLine={false}
|
|
73
|
-
tick={{
|
|
74
|
-
fill: "#64748b",
|
|
75
|
-
fontSize: 12,
|
|
76
|
-
}}
|
|
77
|
-
/>
|
|
78
|
-
|
|
79
|
-
<Tooltip
|
|
80
|
-
cursor={{
|
|
81
|
-
stroke: "#cbd5e1",
|
|
82
|
-
strokeWidth: 1,
|
|
83
|
-
}}
|
|
84
|
-
contentStyle={{
|
|
85
|
-
background: "#ffffff",
|
|
86
|
-
border: "1px solid #e2e8f0",
|
|
87
|
-
borderRadius: 18,
|
|
88
|
-
boxShadow: "0 10px 30px rgba(15,23,42,0.08)",
|
|
89
|
-
}}
|
|
90
|
-
labelStyle={{
|
|
91
|
-
color: "#0f172a",
|
|
92
|
-
fontWeight: 700,
|
|
93
|
-
marginBottom: 10,
|
|
94
|
-
}}
|
|
95
|
-
/>
|
|
96
|
-
|
|
97
|
-
<Legend
|
|
98
|
-
verticalAlign="top"
|
|
99
|
-
align="right"
|
|
100
|
-
iconType="circle"
|
|
101
|
-
wrapperStyle={{
|
|
102
|
-
paddingBottom: 18,
|
|
103
|
-
color: "#475569",
|
|
104
|
-
fontWeight: 600,
|
|
105
|
-
}}
|
|
106
|
-
/>
|
|
107
|
-
|
|
108
|
-
{/* TOTAL */}
|
|
109
|
-
|
|
110
|
-
<Line
|
|
111
|
-
type="monotone"
|
|
112
|
-
dataKey="totalKyc"
|
|
113
|
-
name="Total eKYC"
|
|
114
|
-
stroke="#0f172a"
|
|
115
|
-
strokeWidth={4}
|
|
116
|
-
dot={false}
|
|
117
|
-
activeDot={{
|
|
118
|
-
r: 6,
|
|
119
|
-
}}
|
|
120
|
-
/>
|
|
121
|
-
|
|
122
|
-
{/* AGENCY */}
|
|
123
|
-
|
|
124
|
-
<Line
|
|
125
|
-
type="monotone"
|
|
126
|
-
dataKey="agencyKyc"
|
|
127
|
-
name="Agency eKYC"
|
|
128
|
-
stroke="#3b82f6"
|
|
129
|
-
strokeWidth={3}
|
|
130
|
-
dot={{
|
|
131
|
-
r: 3,
|
|
132
|
-
}}
|
|
133
|
-
activeDot={{
|
|
134
|
-
r: 6,
|
|
135
|
-
}}
|
|
136
|
-
/>
|
|
137
|
-
|
|
138
|
-
{/* SELF */}
|
|
139
|
-
|
|
140
|
-
<Line
|
|
141
|
-
type="monotone"
|
|
142
|
-
dataKey="selfKyc"
|
|
143
|
-
name="Self eKYC"
|
|
144
|
-
stroke="#10b981"
|
|
145
|
-
strokeWidth={3}
|
|
146
|
-
dot={{
|
|
147
|
-
r: 3,
|
|
148
|
-
}}
|
|
149
|
-
activeDot={{
|
|
150
|
-
r: 6,
|
|
151
|
-
}}
|
|
152
|
-
/>
|
|
153
|
-
</LineChart>
|
|
154
|
-
</ResponsiveContainer>
|
|
155
|
-
</div>
|
|
156
|
-
);
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
export default ExecutiveLineChart;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { ResponsiveContainer, PieChart, Pie, Cell, Tooltip, Legend } from "recharts";
|
|
3
|
-
|
|
4
|
-
const colors = ["#22c55e", "#38bdf8", "#f97316", "#facc15", "#f43f5e"];
|
|
5
|
-
|
|
6
|
-
const ExecutivePieChart = ({ data = [], dataKey = "value", labelKey = "label" }) => {
|
|
7
|
-
return (
|
|
8
|
-
<div className="chart-card" style={{ minHeight: 320 }}>
|
|
9
|
-
<ResponsiveContainer width="100%" height={320}>
|
|
10
|
-
<PieChart>
|
|
11
|
-
<Pie data={data} dataKey={dataKey} nameKey={labelKey} cx="50%" cy="50%" outerRadius={110} innerRadius={60} paddingAngle={3} label={{ fill: "#f8fafc", fontSize: 12 }}>
|
|
12
|
-
{data.map((entry, index) => (
|
|
13
|
-
<Cell key={`cell-${index}`} fill={colors[index % colors.length]} />
|
|
14
|
-
))}
|
|
15
|
-
</Pie>
|
|
16
|
-
<Tooltip contentStyle={{ background: "#0f172a", border: "none", borderRadius: 14, color: "#f8fafc" }} />
|
|
17
|
-
<Legend verticalAlign="bottom" align="center" iconType="circle" wrapperStyle={{ color: "#cbd5e1", marginTop: 10 }} />
|
|
18
|
-
</PieChart>
|
|
19
|
-
</ResponsiveContainer>
|
|
20
|
-
</div>
|
|
21
|
-
);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export default ExecutivePieChart;
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import React, { useEffect, useRef } from "react";
|
|
2
|
-
import { useTranslation } from "react-i18next";
|
|
3
|
-
import Chart from "chart.js/auto";
|
|
4
|
-
|
|
5
|
-
const TaskStatusChart = ({ data, title }) => {
|
|
6
|
-
const { t } = useTranslation();
|
|
7
|
-
const chartRef = useRef(null);
|
|
8
|
-
const chartInstance = useRef(null);
|
|
9
|
-
|
|
10
|
-
useEffect(() => {
|
|
11
|
-
if (chartRef.current && data) {
|
|
12
|
-
if (chartInstance.current) chartInstance.current.destroy();
|
|
13
|
-
const ctx = chartRef.current.getContext("2d");
|
|
14
|
-
|
|
15
|
-
// Create vibrant gradients
|
|
16
|
-
const gradientBlue = ctx.createLinearGradient(0, 0, 0, 400);
|
|
17
|
-
gradientBlue.addColorStop(0, '#3B82F6');
|
|
18
|
-
gradientBlue.addColorStop(1, '#2563EB');
|
|
19
|
-
|
|
20
|
-
const gradientAmber = ctx.createLinearGradient(0, 0, 0, 400);
|
|
21
|
-
gradientAmber.addColorStop(0, '#F59E0B');
|
|
22
|
-
gradientAmber.addColorStop(1, '#D97706');
|
|
23
|
-
|
|
24
|
-
const gradientIndigo = ctx.createLinearGradient(0, 0, 0, 400);
|
|
25
|
-
gradientIndigo.addColorStop(0, '#6366F1');
|
|
26
|
-
gradientIndigo.addColorStop(1, '#4F46E5');
|
|
27
|
-
|
|
28
|
-
const gradientEmerald = ctx.createLinearGradient(0, 0, 0, 400);
|
|
29
|
-
gradientEmerald.addColorStop(0, '#10B981');
|
|
30
|
-
gradientEmerald.addColorStop(1, '#059669');
|
|
31
|
-
|
|
32
|
-
const colors = [gradientBlue, gradientAmber, gradientIndigo, gradientEmerald, '#EC4899', '#EF4444'];
|
|
33
|
-
|
|
34
|
-
const labels = data.map(item => t(item.stageName));
|
|
35
|
-
const values = data.map(item => item.count);
|
|
36
|
-
|
|
37
|
-
const ChartConstructor = Chart.Chart || Chart;
|
|
38
|
-
chartInstance.current = new ChartConstructor(ctx, {
|
|
39
|
-
type: "doughnut",
|
|
40
|
-
data: {
|
|
41
|
-
labels,
|
|
42
|
-
datasets: [
|
|
43
|
-
{
|
|
44
|
-
data: values,
|
|
45
|
-
backgroundColor: colors.slice(0, labels.length),
|
|
46
|
-
borderWidth: 2,
|
|
47
|
-
borderColor: "#ffffff",
|
|
48
|
-
hoverOffset: 10
|
|
49
|
-
}
|
|
50
|
-
]
|
|
51
|
-
},
|
|
52
|
-
options: {
|
|
53
|
-
responsive: true,
|
|
54
|
-
maintainAspectRatio: false,
|
|
55
|
-
cutout: '70%',
|
|
56
|
-
plugins: {
|
|
57
|
-
legend: {
|
|
58
|
-
position: 'right',
|
|
59
|
-
labels: {
|
|
60
|
-
usePointStyle: true,
|
|
61
|
-
padding: 15,
|
|
62
|
-
font: { size: 12 }
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
tooltip: {
|
|
66
|
-
backgroundColor: '#1F2937',
|
|
67
|
-
padding: 10,
|
|
68
|
-
bodyFont: { size: 13 }
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return () => {
|
|
76
|
-
if (chartInstance.current) chartInstance.current.destroy();
|
|
77
|
-
};
|
|
78
|
-
}, [data, t]);
|
|
79
|
-
|
|
80
|
-
return (
|
|
81
|
-
<div className="task-status-chart-container glass-card" style={{ height: "320px", width: "100%", padding: "24px" }}>
|
|
82
|
-
{title && <h3 className="chart-title" style={{ marginBottom: "24px", fontSize: "18px", fontWeight: "700", color: "#111827" }}>{t(title)}</h3>}
|
|
83
|
-
<div style={{ height: "220px" }}>
|
|
84
|
-
<canvas ref={chartRef} />
|
|
85
|
-
</div>
|
|
86
|
-
</div>
|
|
87
|
-
);
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
export default TaskStatusChart;
|