Skip to content

Commit 2bec47d

Browse files
author
caneppelevitor
committed
fix: Aligment on verification request dashboard itens and pie chart with one source
1 parent 4e2d58c commit 2bec47d

File tree

3 files changed

+169
-150
lines changed

3 files changed

+169
-150
lines changed

src/components/VerificationRequest/Dashboard/SourceChannelDistribution.tsx

Lines changed: 83 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -6,94 +6,101 @@ import { useTranslation } from "next-i18next";
66
import { StatsSourceChannelsProps } from "../../../types/VerificationRequest";
77

88
const SourceChannelDistribution = ({
9-
statsSourceChannels,
9+
statsSourceChannels,
1010
}: StatsSourceChannelsProps) => {
11-
const { t } = useTranslation("verificationRequest");
11+
const { t } = useTranslation("verificationRequest");
1212

13-
const sourceColors = {
14-
[VerificationRequestSourceChannel.Whatsapp]: colors.lightPrimary,
15-
[VerificationRequestSourceChannel.Instagram]: colors.secondary,
16-
[VerificationRequestSourceChannel.Website]: colors.tertiary,
17-
[VerificationRequestSourceChannel.AutomatedMonitoring]:
18-
colors.lightSecondary,
19-
};
13+
const sourceColors = {
14+
[VerificationRequestSourceChannel.Whatsapp]: colors.lightPrimary,
15+
[VerificationRequestSourceChannel.Instagram]: colors.secondary,
16+
[VerificationRequestSourceChannel.Website]: colors.tertiary,
17+
[VerificationRequestSourceChannel.AutomatedMonitoring]:
18+
colors.lightSecondary,
19+
};
2020

21-
const calculatePieSegments = () => {
22-
let currentAngle = 0;
23-
return statsSourceChannels.map((channel) => {
24-
const percentage = channel.percentage;
25-
const angle = (percentage / 100) * 360;
26-
const segment = {
27-
startAngle: currentAngle,
28-
endAngle: currentAngle + angle,
29-
percentage,
30-
color: sourceColors[channel.label],
31-
label: channel.label,
32-
};
33-
currentAngle += angle;
34-
return segment;
35-
});
36-
};
21+
const calculatePieSegments = () => {
22+
let currentAngle = 0;
23+
return statsSourceChannels.map((channel) => {
24+
const percentage = channel.percentage;
25+
const angle = (percentage / 100) * 360;
26+
const segment = {
27+
startAngle: currentAngle,
28+
endAngle: currentAngle + angle,
29+
percentage,
30+
color: sourceColors[channel.label],
31+
label: channel.label,
32+
};
33+
currentAngle += angle;
34+
return segment;
35+
});
36+
};
3737

38-
const createPiePath = (startAngle: number, endAngle: number) => {
39-
const radius = 80;
40-
const centerX = 100;
41-
const centerY = 100;
38+
const createPiePath = (startAngle: number, endAngle: number) => {
39+
const radius = 80;
40+
const centerX = 100;
41+
const centerY = 100;
4242

43-
const startRad = (startAngle * Math.PI) / 180;
44-
const endRad = (endAngle * Math.PI) / 180;
43+
const clampedEnd =
44+
endAngle - startAngle >= 360 ? startAngle + 359.99 : endAngle;
45+
const startRad = (startAngle * Math.PI) / 180;
46+
const endRad = (clampedEnd * Math.PI) / 180;
4547

46-
const x1 = centerX + radius * Math.cos(startRad);
47-
const y1 = centerY + radius * Math.sin(startRad);
48-
const x2 = centerX + radius * Math.cos(endRad);
49-
const y2 = centerY + radius * Math.sin(endRad);
48+
const x1 = centerX + radius * Math.cos(startRad);
49+
const y1 = centerY + radius * Math.sin(startRad);
50+
const x2 = centerX + radius * Math.cos(endRad);
51+
const y2 = centerY + radius * Math.sin(endRad);
5052

51-
const largeArc = endAngle - startAngle > 180 ? 1 : 0;
53+
const largeArc = clampedEnd - startAngle > 180 ? 1 : 0;
5254

53-
return `M ${centerX} ${centerY} L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2} Z`;
54-
};
55+
return `M ${centerX} ${centerY} L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArc} 1 ${x2} ${y2} Z`;
56+
};
5557

56-
const pieSegments = calculatePieSegments();
58+
const pieSegments = calculatePieSegments();
5759

58-
return (
59-
<>
60-
<Typography className="title">{t("dashboard.sourcesTitle")}</Typography>
61-
<Typography className="subtitle">
62-
{t("dashboard.sourcesSubtitle")}
63-
</Typography>
64-
<Box className="PieChart-container">
65-
<PieChartSVG width="200" height="200" viewBox="0 0 200 200">
66-
{pieSegments.map((segment) => (
67-
<path
68-
key={segment.label}
69-
d={createPiePath(segment.startAngle, segment.endAngle)}
70-
fill={segment.color}
71-
stroke={colors.white}
72-
strokeWidth="2"
73-
/>
74-
))}
75-
</PieChartSVG>
76-
</Box>
77-
78-
<Box className="legend">
79-
{statsSourceChannels.map((channel) => (
80-
<Box className="legend-item" key={channel.label}>
81-
<LegendColor color={sourceColors[channel.label]} />
82-
<Typography className="legend-label">
83-
{t(`verificationRequest:${channel.label}`, {
84-
defaultValue:
85-
channel.label.charAt(0).toUpperCase() +
86-
channel.label.slice(1),
87-
})}
60+
return (
61+
<>
62+
<Typography className="title">
63+
{t("dashboard.sourcesTitle")}
8864
</Typography>
89-
<Typography className="legend-percentage">
90-
{channel.percentage.toFixed(1)}%
65+
<Typography className="subtitle">
66+
{t("dashboard.sourcesSubtitle")}
9167
</Typography>
92-
</Box>
93-
))}
94-
</Box>
95-
</>
96-
);
68+
<Box className="PieChart-container">
69+
<PieChartSVG width="200" height="200" viewBox="0 0 200 200">
70+
{pieSegments.map((segment) => (
71+
<path
72+
key={segment.label}
73+
d={createPiePath(
74+
segment.startAngle,
75+
segment.endAngle
76+
)}
77+
fill={segment.color}
78+
stroke={colors.white}
79+
strokeWidth="2"
80+
/>
81+
))}
82+
</PieChartSVG>
83+
</Box>
84+
85+
<Box className="legend">
86+
{statsSourceChannels.map((channel) => (
87+
<Box className="legend-item" key={channel.label}>
88+
<LegendColor color={sourceColors[channel.label]} />
89+
<Typography className="legend-label">
90+
{t(`verificationRequest:${channel.label}`, {
91+
defaultValue:
92+
channel.label.charAt(0).toUpperCase() +
93+
channel.label.slice(1),
94+
})}
95+
</Typography>
96+
<Typography className="legend-percentage">
97+
{channel.percentage.toFixed(1)}%
98+
</Typography>
99+
</Box>
100+
))}
101+
</Box>
102+
</>
103+
);
97104
};
98105

99106
export { SourceChannelDistribution };

src/components/VerificationRequest/Dashboard/VerificationRequestDashboard.tsx

Lines changed: 71 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import React, { useEffect, useState } from "react";
22
import { Grid, Typography } from "@mui/material";
33
import verificationRequestApi from "../../../api/verificationRequestApi";
44
import {
5-
StatsCount,
6-
StatsRecentActivity,
7-
StatsSourceChannels,
5+
StatsCount,
6+
StatsRecentActivity,
7+
StatsSourceChannels,
88
} from "../../../types/VerificationRequest";
99
import { Dashboard } from "./VerificationRequestDashboard.style";
1010
import VerificationRequestCounts from "./VerificationRequestCounts";
@@ -14,72 +14,82 @@ import { useTranslation } from "next-i18next";
1414
import Loading from "../../Loading";
1515

1616
const VerificationRequestDashboard: React.FC = () => {
17-
const { t } = useTranslation("verificationRequest");
18-
const [stats, setStats] = useState<{
19-
statsCount: StatsCount;
20-
statsSourceChannels: StatsSourceChannels[];
21-
statsRecentActivity: StatsRecentActivity[];
22-
} | null>(null);
23-
const [loading, setLoading] = useState(true);
24-
const [error, setError] = useState(false);
17+
const { t } = useTranslation("verificationRequest");
18+
const [stats, setStats] = useState<{
19+
statsCount: StatsCount;
20+
statsSourceChannels: StatsSourceChannels[];
21+
statsRecentActivity: StatsRecentActivity[];
22+
} | null>(null);
23+
const [loading, setLoading] = useState(true);
24+
const [error, setError] = useState(false);
2525

26-
useEffect(() => {
27-
fetchStats();
28-
}, []);
26+
useEffect(() => {
27+
fetchStats();
28+
}, []);
2929

30-
const fetchStats = async () => {
31-
try {
32-
setLoading(true);
33-
setError(false);
34-
const data = await verificationRequestApi.getVerificationRequestStats();
35-
if (!data) {
36-
throw new Error("Empty data");
37-
}
38-
setStats(data);
39-
} catch (err) {
40-
console.error("Error fetching stats:", err);
41-
setError(true);
42-
} finally {
43-
setLoading(false);
30+
const fetchStats = async () => {
31+
try {
32+
setLoading(true);
33+
setError(false);
34+
const data =
35+
await verificationRequestApi.getVerificationRequestStats();
36+
if (!data) {
37+
throw new Error("Empty data");
38+
}
39+
setStats(data);
40+
} catch (err) {
41+
console.error("Error fetching stats:", err);
42+
setError(true);
43+
} finally {
44+
setLoading(false);
45+
}
46+
};
47+
48+
if (loading) {
49+
return <Loading />;
4450
}
45-
};
4651

47-
if (loading) {
48-
return <Loading />;
49-
}
52+
if (error || !stats) {
53+
return (
54+
<Dashboard style={{ justifyContent: "center" }}>
55+
<Typography>{t("dashboard.errorLoading")}</Typography>
56+
</Dashboard>
57+
);
58+
}
5059

51-
if (error || !stats) {
5260
return (
53-
<Dashboard style={{ justifyContent: "center" }}>
54-
<Typography>{t("dashboard.errorLoading")}</Typography>
55-
</Dashboard>
56-
);
57-
}
61+
<Dashboard>
62+
<Grid container spacing={2}>
63+
<Grid item xs={12}>
64+
<Typography className="title">
65+
{t("dashboard.title")}
66+
</Typography>
67+
<Typography className="subtitle">
68+
{t("dashboard.subtitle")}
69+
</Typography>
70+
</Grid>
5871

59-
return (
60-
<Dashboard>
61-
<Grid container spacing={2}>
62-
<Grid item xs={12}>
63-
<Typography className="title">{t("dashboard.title")}</Typography>
64-
<Typography className="subtitle">{t("dashboard.subtitle")}</Typography>
65-
</Grid>
72+
<Grid
73+
item
74+
xs={12}
75+
lg={7}
76+
style={{ display: "flex", flexDirection: "column" }}
77+
>
78+
<VerificationRequestCounts {...stats.statsCount} />
79+
<VerificationRequestOverview
80+
statsCounts={stats.statsCount}
81+
statsSourceChannels={stats.statsSourceChannels}
82+
/>
83+
</Grid>
6684

67-
<Grid item xs={12} lg={7}>
68-
<VerificationRequestCounts {...stats.statsCount} />
69-
<VerificationRequestOverview
70-
statsCounts={stats.statsCount}
71-
statsSourceChannels={stats.statsSourceChannels}
72-
/>
73-
</Grid>
74-
75-
<Grid item xs={12} lg={5}>
76-
<VerificationRequestActivity
77-
statsRecentActivity={stats.statsRecentActivity}
78-
/>
79-
</Grid>
80-
</Grid>
81-
</Dashboard>
82-
);
85+
<Grid item xs={12} lg={5}>
86+
<VerificationRequestActivity
87+
statsRecentActivity={stats.statsRecentActivity}
88+
/>
89+
</Grid>
90+
</Grid>
91+
</Dashboard>
92+
);
8393
};
8494

8595
export default VerificationRequestDashboard;

src/components/VerificationRequest/Dashboard/VerificationRequestOverview.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,24 @@ import { SourceChannelDistribution } from "./SourceChannelDistribution";
44
import { StatusDistribution } from "./StatusDistribution";
55

66
const VerificationRequestOverview = ({
7-
statsCounts,
8-
statsSourceChannels,
7+
statsCounts,
8+
statsSourceChannels,
99
}: StatsSourceChannelsProps) => (
10-
<Grid container spacing={3} mb={4}>
11-
<Grid item xs={12} md={6}>
12-
<Card className="card" style={{ minHeight: 400 }}>
13-
<SourceChannelDistribution statsSourceChannels={statsSourceChannels} />
14-
</Card>
15-
</Grid>
10+
<Grid container spacing={3} style={{ flex: 1 }}>
11+
<Grid item xs={12} md={6}>
12+
<Card className="card" style={{ height: "100%" }}>
13+
<SourceChannelDistribution
14+
statsSourceChannels={statsSourceChannels}
15+
/>
16+
</Card>
17+
</Grid>
1618

17-
<Grid item xs={12} md={6}>
18-
<Card className="card">
19-
<StatusDistribution {...statsCounts} />
20-
</Card>
19+
<Grid item xs={12} md={6}>
20+
<Card className="card" style={{ height: "100%" }}>
21+
<StatusDistribution {...statsCounts} />
22+
</Card>
23+
</Grid>
2124
</Grid>
22-
</Grid>
2325
);
2426

2527
export default VerificationRequestOverview;

0 commit comments

Comments
 (0)